index.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. <template>
  2. <div id="userMessage-wrap" ref="userMessage">
  3. <el-drawer
  4. title="消息通知"
  5. :size="350"
  6. :visible.sync="drawerVisible"
  7. custom-class="el-drawer"
  8. :show-close="false"
  9. :append-to-body="true"
  10. >
  11. <div slot="title" class="drawer-head">
  12. <div class="tab-item" :class="tabSelected==='received'?'active':''" @click="tabClick('received')">
  13. <el-badge :value="viewData.unReadCount" class="custom-badge" :max="99" :hidden="viewData.unReadCount<1">收件箱</el-badge>
  14. </div>
  15. <div class="tab-item" :class="tabSelected==='sent'?'active':''" @click="tabClick('sent')">发件箱</div>
  16. <el-button size="small" type="primary" round @click="sendMessageHandle"> 发送消息</el-button>
  17. </div>
  18. <div class="message-content">
  19. <el-card
  20. v-for="(item,index) in viewData.msgList"
  21. :key="index"
  22. class="box-card"
  23. :body-style="{ padding: '10px 15px' }"
  24. >
  25. <div class="card-cont" @click="showMsgDetail(item)">
  26. <div class="top">
  27. <i v-if="tabSelected==='sent'" :class="item.msgCatId===1?'el-icon-chat-dot-round':'el-icon-message-solid'" />
  28. <el-badge v-else class="avatar-badge" is-dot :hidden="item.isRead!==0">
  29. <el-avatar class="avatar" size="small" :src="item.msgFrAvatar" />
  30. </el-badge>
  31. <div class="rt" :class="tabSelected">
  32. <h3 v-if="tabSelected==='received'" class="title">{{ item.msgFrName }}</h3>
  33. <h3 v-if="tabSelected==='sent'" class="title">{{ item.msgTo|formatMsgTo }}</h3>
  34. <p class="cont">{{ item.msgContent }}</p>
  35. <p class="flex-between">
  36. <span class="time">{{ item.msgTime|formatTime|niceDateFilter }}</span>
  37. <span v-if="item.isDetailed===1" class="more">详情</span>
  38. </p>
  39. </div>
  40. </div>
  41. <!-- <div class="desc">{{ item.msgContent }}</div> -->
  42. </div>
  43. </el-card>
  44. </div>
  45. <el-empty v-if="viewData.msgList&&viewData.msgList.length<1" :image-size="200" description="暂无信息" />
  46. </el-drawer>
  47. <el-dialog title="发送消息" :visible.sync="dialogVisible" width="40%" :close-on-click-modal="false" :fullscreen="formData.msgCatId===2">
  48. <el-form ref="sendForm" :model="formData" label-width="120px" :rules="rules">
  49. <el-form-item label="收件人" prop="msgTo">
  50. <template>
  51. <el-radio v-model="formData.msgCatId" :label="1">消息</el-radio>
  52. <el-radio v-model="formData.msgCatId" :label="2">通知</el-radio>
  53. </template>
  54. </el-form-item>
  55. <el-form-item label="收件人" prop="msgTo">
  56. <user-selector
  57. key="msgTo-selectUser"
  58. :default-val="viewData.msgTs"
  59. :multiple="true"
  60. @setUserInfo="handleMsgTo"
  61. />
  62. </el-form-item>
  63. <el-form-item label="抄送人" prop="msgCc">
  64. <user-selector
  65. :default-val="viewData.msgCs"
  66. :multiple="true"
  67. @setUserInfo="handleMsgCc"
  68. />
  69. </el-form-item>
  70. <el-form-item label="内容" prop="msgContent">
  71. <el-input v-model="formData.msgContent" />
  72. </el-form-item>
  73. <el-form-item v-if="formData.msgCatId===2" label="详情">
  74. <el-input v-model="formData.msgDetail" type="textarea" :rows="15" :maxlength="5000" show-word-limit />
  75. </el-form-item>
  76. </el-form>
  77. <div slot="footer" class="dialog-footer">
  78. <el-button @click="dialogVisible = false">取 消</el-button>
  79. <el-button type="primary" @click="sendMessage">确 定</el-button>
  80. </div>
  81. </el-dialog>
  82. <el-drawer
  83. :size="320"
  84. direction="rtl"
  85. :visible.sync="msgContentDrawer"
  86. :show-close="false"
  87. >
  88. <template slot="title"><i class="el-icon-arrow-left" @click="msgContentDrawer=false" />{{ viewData.msgDetail.msgCatTitle }}</template>
  89. <div class="msgContent">
  90. <h4 class="title">{{ viewData.msgDetail.msgContent }}</h4>
  91. <p>{{ viewData.msgDetail.msgDetail }}</p>
  92. </div>
  93. </el-drawer>
  94. </div>
  95. </template>
  96. <script>
  97. import { sendMsg, getMsgSentByPage, getMsgReceivedByPage, getUnReadCounter, putReadStatus, getMsgById } from '@/api/system/msgApi'
  98. import UserSelector from '@/components/UserSelector/index'
  99. import { isNotNull, parseTime } from '@/utils'
  100. import { mapGetters } from 'vuex'
  101. import commonMixins from '@/mixin/commonMethodMixin'
  102. export default {
  103. name: 'MsgList',
  104. components: {
  105. UserSelector
  106. },
  107. filters: {
  108. formatTime(val) {
  109. return parseTime(new Date(val))
  110. },
  111. formatMsgTo(val) {
  112. let result = ''
  113. if (isNotNull(val)) {
  114. const arr = val.split(',')
  115. for (const item of arr) {
  116. const arrItem = item.split('/')
  117. if (result === '') {
  118. result += arrItem[1]
  119. } else {
  120. result += ',' + arrItem[1]
  121. }
  122. }
  123. }
  124. return result
  125. }
  126. },
  127. mixins: [commonMixins],
  128. data() {
  129. return {
  130. title: '',
  131. drawerVisible: false,
  132. dialogVisible: false,
  133. msgContentDrawer: false,
  134. tabSelected: 'received',
  135. conditions: {
  136. page: 1,
  137. limit: 10,
  138. keywords: ''
  139. },
  140. viewData: {
  141. total: 0,
  142. msgList: [],
  143. msgTs: [],
  144. msgCs: [],
  145. msgDetail: '',
  146. unReadCount: 0
  147. },
  148. formData: {
  149. msgToGroup: undefined,
  150. msgCc: [],
  151. msgCatId: 1,
  152. msgTo: [],
  153. msgTitle: '',
  154. msgContent: ''
  155. },
  156. rules: {
  157. msgTo: [
  158. { required: true, trigger: 'blur', message: '请填写收件人' }
  159. ],
  160. msgCc: [
  161. { required: true, trigger: 'blur', message: '请填写抄送人' }
  162. ],
  163. msgContent: [
  164. { required: true, trigger: 'blur', message: '请填写发送内容' }
  165. ]
  166. }
  167. }
  168. },
  169. computed: {
  170. ...mapGetters([
  171. 'userData'
  172. ])
  173. },
  174. methods: {
  175. // 初始化
  176. init() {
  177. this.drawerVisible = true
  178. this.tabSelected = 'received'
  179. this.getReceivedMsg()
  180. this.getUnReadMsgCount()
  181. },
  182. // 获取未读数目
  183. getUnReadMsgCount() {
  184. getUnReadCounter().then((resp) => {
  185. this.viewData.unReadCount = resp.data
  186. })
  187. },
  188. // 获取已发送消息
  189. getSentMsg() {
  190. this.listLoading = true
  191. getMsgSentByPage(this.conditions).then((resp) => {
  192. const { data, total } = resp
  193. this.listLoading = false
  194. this.total = total
  195. this.viewData.msgList = data
  196. }).catch((error) => {
  197. console.log(error)
  198. })
  199. },
  200. // 获取接收到的消息
  201. getReceivedMsg() {
  202. this.listLoading = true
  203. getMsgReceivedByPage(this.conditions).then((resp) => {
  204. const { data, total } = resp
  205. this.listLoading = false
  206. this.conditions.total = total
  207. this.viewData.msgList = data
  208. }).catch((error) => {
  209. console.log(error)
  210. })
  211. },
  212. // 抄送人选择
  213. handleMsgCc(item, user) {
  214. this.formData.msgCc = user.map(item => `${item.accountId}/${item.accountName}`).join(',')
  215. },
  216. // 收件人选择
  217. handleMsgTo(item, user) {
  218. this.formData.msgTo = user.map(item => `${item.accountId}/${item.accountName}`).join(',')
  219. },
  220. //
  221. sendMessageHandle() {
  222. this.dialogVisible = true
  223. this.resetForm()
  224. this.viewData.msgTs = []
  225. this.viewData.msgCs = []
  226. },
  227. resetForm() {
  228. this.formData = {
  229. msgToGroup: '',
  230. msgCc: '',
  231. msgTo: '',
  232. msgDetail: '',
  233. msgCatId: 1,
  234. msgContent: ''
  235. }
  236. },
  237. sendMessage() {
  238. this.$refs['sendForm'].validate((valid) => {
  239. if (valid) {
  240. sendMsg(this.formData).then((res) => {
  241. this.$message.success(res.msg)
  242. this.dialogVisible = false
  243. this.tabSelected = 'received'
  244. this.getReceivedMsg()
  245. })
  246. } else {
  247. this.$message.error('请检查数据')
  248. return false
  249. }
  250. })
  251. },
  252. tabClick(type) {
  253. this.tabSelected = type
  254. this.msgList = []
  255. if (type === 'sent') {
  256. this.getSentMsg()
  257. } else if (type === 'received') {
  258. this.getReceivedMsg()
  259. }
  260. },
  261. showMsgDetail(item) {
  262. if (this.tabSelected === 'received' && item.isRead === 0) {
  263. putReadStatus(item.msgId).then(() => {
  264. this.getReceivedMsg()
  265. this.getUnReadMsg()
  266. })
  267. }
  268. if (item.isDetailed === 1) {
  269. this.viewData.msgDetail = ''
  270. this.msgContentDrawer = true
  271. getMsgById(item.msgId).then((res) => {
  272. this.viewData.msgDetail = res.data
  273. })
  274. }
  275. }
  276. }
  277. }
  278. </script>
  279. <style lang="scss" scoped>
  280. .el-drawer {
  281. .drawer-head {
  282. display: flex;
  283. justify-content: space-between;
  284. align-items: center;
  285. .tab-item {
  286. padding: 0 20px;
  287. height: 40px;
  288. -webkit-box-sizing: border-box;
  289. box-sizing: border-box;
  290. line-height: 40px;
  291. display: inline-block;
  292. list-style: none;
  293. font-size: 14px;
  294. font-weight: 500;
  295. position: relative;
  296. color: #fff;
  297. cursor: pointer;
  298. &::after {
  299. width: 100%;
  300. height: 2px;
  301. background-color: transparent;
  302. position: absolute;
  303. bottom: 0;
  304. left: 0;
  305. border-radius: 2px;
  306. display: block;
  307. content: "";
  308. transition: 0.3s;
  309. }
  310. &.active {
  311. &::after {
  312. background-color: #1890ff;
  313. }
  314. }
  315. }
  316. }
  317. .card-cont-box{
  318. width: 100%;
  319. }
  320. .card-cont {
  321. color: #FFFFFF;
  322. cursor: pointer;
  323. .top {
  324. display: flex;
  325. justify-content: flex-start;
  326. align-items: flex-start;
  327. i {
  328. font-size: 28px;
  329. color: #42c5bf;
  330. font-weight: normal;
  331. padding: 0 10px 0 0;
  332. margin: 0;
  333. }
  334. .avatar{
  335. margin-right: 10px;
  336. }
  337. h3 {
  338. font-weight: normal;
  339. font-size: 14px;
  340. line-height: 1.2;
  341. padding: 0;
  342. margin: 0;
  343. }
  344. p {
  345. line-height: 1.5;
  346. font-size: 10px;
  347. margin: 0;
  348. padding-top: 4px;
  349. }
  350. }
  351. .rt{
  352. width: 100%;
  353. .title{
  354. font-size: 14px;
  355. color: #c7c5c5;
  356. }
  357. p{
  358. font-size: 18px;
  359. color: #fff;
  360. }
  361. .time{
  362. font-size: 10px;
  363. color: #b5b5b5;
  364. }
  365. }
  366. .flex-between{
  367. width: 100%;
  368. display: flex;
  369. justify-content: space-between;
  370. align-items: center;
  371. }
  372. .more{
  373. color: #1890ff;
  374. font-size: 8px;
  375. }
  376. .desc {
  377. font-size: 14px;
  378. line-height: 1.4;
  379. padding-top: 8px;
  380. }
  381. }
  382. }
  383. .msgContent{
  384. padding: 10px;
  385. color: #fff;
  386. text-align: justify;
  387. h1,h2,h3,h4,h5{margin: 0;}
  388. .title{
  389. padding-bottom: 10px;
  390. }
  391. p{
  392. text-indent: 24px;
  393. margin: 0;
  394. line-height: 1.8;
  395. font-size: 14px;
  396. }
  397. }
  398. </style>
  399. <style lang="scss">
  400. .el-badge.custom-badge{
  401. .el-badge__content{
  402. height: 14px;
  403. line-height: 14px;
  404. font-size: 8px;
  405. border: 0;
  406. padding: 0 5px;
  407. &.is-fixed{
  408. top: 11px;
  409. right: 4px;
  410. }
  411. }
  412. }
  413. .avatar-badge{
  414. .el-badge__content{
  415. height: 6px;
  416. width: 6px;
  417. border: 0;
  418. &.is-fixed{
  419. right: 12px;
  420. }
  421. }
  422. }
  423. </style>