NoticeDialog.vue 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. <template>
  2. <Modal
  3. class="notice-dialog marker-modal"
  4. v-model="modalIsShow"
  5. title="消息"
  6. :mask-closable="false"
  7. footer-hide
  8. fullscreen
  9. @on-visible-change="visibleChange"
  10. >
  11. <div class="notice-container">
  12. <div v-if="IS_MARK_LEADER" class="notice-users">
  13. <div class="user-item user-all">
  14. <div>小组成员</div>
  15. <div
  16. :class="['user-selection', { 'is-active': userSelectAll }]"
  17. @click="selectAll"
  18. >
  19. <Icon v-if="userSelectAll" type="ios-checkmark-circle" />
  20. <Icon v-else type="md-radio-button-off" />
  21. </div>
  22. </div>
  23. <div
  24. v-for="user in markers"
  25. :key="user.id"
  26. class="user-item"
  27. @click="selectUser(user)"
  28. >
  29. <div class="user-avatar"><Icon type="md-contact" /></div>
  30. <div class="user-name" :title="user.name">{{ user.name }}</div>
  31. <div :class="['user-selection', { 'is-active': user.selected }]">
  32. <Icon v-if="user.selected" type="ios-checkmark-circle" />
  33. <Icon v-else type="md-radio-button-off" />
  34. </div>
  35. </div>
  36. </div>
  37. <div class="notice-body">
  38. <div ref="NoticeContent" class="notice-content">
  39. <div v-if="hasMore" class="notice-item notice-more" @click="nextPage">
  40. 获取更多
  41. </div>
  42. <div v-for="notice in notices" :key="notice.id" class="notice-item">
  43. <div class="notice-item-head">
  44. <span class="notice-head-users">
  45. {{ notice.relateUsers }}
  46. </span>
  47. <span class="notice-head-time">
  48. {{ notice.createTime }}
  49. </span>
  50. </div>
  51. <div class="notice-item-content" v-html="notice.content"></div>
  52. </div>
  53. </div>
  54. <div v-if="IS_MARK_LEADER" class="notice-send">
  55. <textarea placeholder="请输入" v-model="content"></textarea>
  56. <div class="notice-send-footer">
  57. <Button type="primary" :loading="loading" @click="toSend"
  58. >发送</Button
  59. >
  60. </div>
  61. </div>
  62. </div>
  63. </div>
  64. </Modal>
  65. </template>
  66. <script>
  67. import { mapState, mapMutations } from "vuex";
  68. import {
  69. userSendNoticeList,
  70. userReceiveNoticeList,
  71. fetchReleaseUnreadNotice,
  72. readNotice,
  73. sendNotice,
  74. leaderMarkUserList
  75. } from "@/api";
  76. import timeMixin from "@/plugins/timeMixin";
  77. export default {
  78. name: "ribbon-set-dialog",
  79. mixins: [timeMixin],
  80. data() {
  81. return {
  82. workId: "",
  83. subject: "",
  84. modalIsShow: false,
  85. curUserRoleType: this.$ls.get("user", { role: "" }).role,
  86. userSelectAll: false,
  87. markers: [],
  88. notices: [],
  89. current: 0,
  90. size: 10,
  91. content: "",
  92. hasMore: false,
  93. fetching: false,
  94. loading: false
  95. };
  96. },
  97. computed: {
  98. ...mapState("marker", ["curSubject"]),
  99. IS_MARKER() {
  100. return this.curUserRoleType === "MARKER";
  101. },
  102. IS_MARK_LEADER() {
  103. return this.curUserRoleType === "MARK_LEADER";
  104. }
  105. },
  106. mounted() {
  107. const [workId, subject] = this.$route.params.subjectId.split("-");
  108. this.workId = workId;
  109. this.subject = subject;
  110. this.initData();
  111. },
  112. beforeDestroy() {
  113. this.clearSetTs();
  114. },
  115. methods: {
  116. ...mapMutations("marker", ["setShortcut", "recoverShortcut"]),
  117. async initData() {
  118. if (this.IS_MARK_LEADER) {
  119. this.getLeaderMarkerList();
  120. this.getLeaderMarkerNoticeList();
  121. return;
  122. }
  123. if (this.IS_MARKER) {
  124. this.getMarkerNoticeList();
  125. this.addSetTime(() => {
  126. this.getNewNotice();
  127. }, 10 * 1000);
  128. }
  129. },
  130. visibleChange(visible) {
  131. if (visible) {
  132. if (this.IS_MARKER) {
  133. this.setNoticeRead();
  134. }
  135. this.goToBottom();
  136. this.setShortcut([]);
  137. } else {
  138. this.recoverShortcut();
  139. }
  140. },
  141. goToBottom() {
  142. this.$nextTick(() => {
  143. this.$refs.NoticeContent.scrollTop = this.$refs.NoticeContent.offsetHeight;
  144. });
  145. },
  146. async getLeaderMarkerList() {
  147. const markerId = this.$ls.get("user", { id: "" }).id;
  148. const data = await leaderMarkUserList({
  149. workId: this.workId,
  150. subject: this.subject,
  151. stage: this.curSubject.stage,
  152. markerId
  153. });
  154. const markers = data || [];
  155. this.markers = markers.map(item => {
  156. item.selected = false;
  157. return item;
  158. });
  159. },
  160. async nextPage() {
  161. if (this.fetching) return;
  162. this.fetching = true;
  163. this.current++;
  164. if (this.IS_MARKER) {
  165. await this.getMarkerNoticeList().catch(() => {});
  166. } else {
  167. await this.getLeaderMarkerNoticeList().catch(() => {});
  168. }
  169. this.fetching = false;
  170. },
  171. async getLeaderMarkerNoticeList() {
  172. const sendUserId = this.$ls.get("user", { id: "" }).id;
  173. const lastId = this.notices.length ? this.notices.slice(-1)[0].id : null;
  174. const data = await userSendNoticeList({
  175. subject: this.subject,
  176. stage: this.curSubject.stage,
  177. sendUserId,
  178. lastId,
  179. page: this.current,
  180. size: this.size
  181. });
  182. const notices = data.content.map(item => {
  183. item.receiveUser = JSON.parse(item.receiveUser);
  184. item.relateUsers = item.receiveUser.map(user => user.name).join(",");
  185. return item;
  186. });
  187. notices.reverse();
  188. this.hasMore = this.current + 1 < data.totalPages;
  189. this.notices = [...notices, ...this.notices];
  190. },
  191. parseMarkerNotice(info) {
  192. return {
  193. ...info.message,
  194. id: info.id,
  195. read: info.read,
  196. relateUsers: info.message.sendUserName
  197. };
  198. },
  199. async getMarkerNoticeList() {
  200. const receiveUserId = this.$ls.get("user", { id: "" }).id;
  201. const lastId = this.notices.length ? this.notices.slice(-1)[0].id : null;
  202. const data = await userReceiveNoticeList({
  203. subject: this.subject,
  204. stage: this.curSubject.stage,
  205. receiveUserId,
  206. lastId,
  207. page: this.current,
  208. size: this.size
  209. });
  210. const notices = data.content.map(item => {
  211. return this.parseMarkerNotice(item);
  212. });
  213. notices.reverse();
  214. this.hasMore = this.current + 1 < data.totalPages;
  215. this.notices = [...notices, ...this.notices];
  216. },
  217. async getNewNotice() {
  218. this.clearSetTs();
  219. const receiveUserId = this.$ls.get("user", { id: "" }).id;
  220. const resData = await fetchReleaseUnreadNotice({
  221. subject: this.subject,
  222. stage: this.curSubject.stage,
  223. receiveUserId
  224. }).catch(() => {});
  225. const data = resData || [];
  226. const noticeIds = this.notices.map(item => item.id);
  227. const validNotices = data
  228. .filter(item => !noticeIds.includes(item.id))
  229. .map(item => this.parseMarkerNotice(item));
  230. if (validNotices.length) {
  231. this.notices.push(...validNotices);
  232. this.open();
  233. this.goToBottom();
  234. this.$nextTick(() => {
  235. this.setNoticeRead();
  236. });
  237. }
  238. this.addSetTime(() => {
  239. this.getNewNotice();
  240. }, 10 * 1000);
  241. },
  242. setNoticeRead() {
  243. const noticeIds = this.notices
  244. .filter(item => !item.read)
  245. .map(item => item.id);
  246. if (!noticeIds.length) return;
  247. readNotice(noticeIds);
  248. },
  249. cancel() {
  250. this.modalIsShow = false;
  251. },
  252. open() {
  253. this.modalIsShow = true;
  254. },
  255. selectChange() {
  256. this.userSelectAll = !this.markers.some(item => !item.selected);
  257. },
  258. selectUser(user) {
  259. user.selected = !user.selected;
  260. this.selectChange();
  261. },
  262. selectAll() {
  263. this.userSelectAll = !this.userSelectAll;
  264. this.markers.forEach(user => {
  265. user.selected = this.userSelectAll;
  266. });
  267. },
  268. async toSend() {
  269. if (!this.content) {
  270. this.$Message.error("请输入内容");
  271. return;
  272. }
  273. const user = this.$ls.get("user", { id: "", name: "" });
  274. const markers = this.markers
  275. .filter(item => item.selected)
  276. .map(item => {
  277. return {
  278. id: item.id,
  279. name: item.name
  280. };
  281. });
  282. if (!markers.length) {
  283. this.$Message.error("请选择评卷员");
  284. return;
  285. }
  286. if (this.loading) return;
  287. this.loading = true;
  288. const data = {
  289. subject: this.subject,
  290. stage: this.curSubject.stage,
  291. sendUserId: user.id,
  292. sendUserName: user.name,
  293. content: this.content,
  294. markers
  295. };
  296. const res = await sendNotice(data).catch(() => {});
  297. this.loading = false;
  298. if (!res) return;
  299. this.content = "";
  300. res.receiveUser = JSON.parse(res.receiveUser);
  301. res.relateUsers = res.receiveUser.map(item => item.name).join(",");
  302. this.notices.push({ ...res });
  303. this.goToBottom();
  304. }
  305. }
  306. };
  307. </script>