@hbisty/qj-common 5.0.4 → 5.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/.babelrc +12 -12
  2. package/.eslintrc.js +25 -25
  3. package/.idea/common.iml +11 -11
  4. package/.idea/modules.xml +7 -7
  5. package/.idea/vcs.xml +5 -5
  6. package/.postcssrc.js +9 -9
  7. package/.prettierrc.js +7 -7
  8. package/.project +37 -37
  9. package/README.md +2 -2
  10. package/gulpfile.js +20 -20
  11. package/package.json +18 -18
  12. package/src/api/apimanage.js +146 -146
  13. package/src/api/common/index.js +192 -192
  14. package/src/api/login.js +160 -160
  15. package/src/api/shopFbu.js +515 -515
  16. package/src/api/siteMsg.js +36 -0
  17. package/src/api/upload.js +8 -8
  18. package/src/components/Bounced/index.vue +145 -145
  19. package/src/components/Breadcrumb/index.vue +71 -71
  20. package/src/components/Checkbox/index.vue +53 -53
  21. package/src/components/Hamburger/index.vue +48 -48
  22. package/src/components/Logistics/logic.vue +186 -186
  23. package/src/components/ScrollBar/index.vue +60 -60
  24. package/src/components/SiteMsg/img/readed-icon.png +0 -0
  25. package/src/components/SiteMsg/img/unread-icon.png +0 -0
  26. package/src/components/SiteMsg/index.vue +707 -0
  27. package/src/components/SiteMsg//347/253/231/345/206/205/344/277/241/346/266/210/346/201/257-/346/216/245/345/217/243/346/226/207/346/241/243.txt +191 -0
  28. package/src/components/Sticky/index.vue +76 -76
  29. package/src/components/SvgIcon/index.vue +42 -42
  30. package/src/components/ThemePicker/index.vue +243 -243
  31. package/src/components/Tinymce/components/editorImage.vue +94 -94
  32. package/src/components/Tinymce/index.vue +166 -166
  33. package/src/components/Tinymce/plugins.js +7 -7
  34. package/src/components/Tinymce/toolbar.js +6 -6
  35. package/src/components/TreeTable/customEval.js +44 -44
  36. package/src/components/TreeTable/eval.js +29 -29
  37. package/src/components/TreeTable/index.vue +124 -124
  38. package/src/components/TreeTable/readme.md +89 -89
  39. package/src/components/TreeTableApi/customEval.js +49 -49
  40. package/src/components/TreeTableApi/eval.js +29 -29
  41. package/src/components/TreeTableApi/index.vue +124 -124
  42. package/src/components/TreeTableApi/readme.md +89 -89
  43. package/src/components/Upload/singleImage.vue +123 -123
  44. package/src/components/Upload/singleImage2.vue +118 -118
  45. package/src/components/Upload/singleImage3.vue +138 -138
  46. package/src/components/Upload/upload.vue +295 -295
  47. package/src/components/workOrderList/index.vue +158 -158
  48. package/src/dependencies.js +119 -119
  49. package/src/iconShop/demo.css +539 -539
  50. package/src/iconShop/demo_index.html +8445 -8445
  51. package/src/iconShop/iconfont.css +1451 -1451
  52. package/src/iconShop/iconfont.json +2522 -2522
  53. package/src/iconShop/iconfont.svg +1070 -1070
  54. package/src/iconfont/demo.css +539 -539
  55. package/src/iconfont/demo_index.html +5276 -5276
  56. package/src/iconfont/iconfont.css +905 -905
  57. package/src/iconfont/iconfont.json +1563 -1563
  58. package/src/iconfont/iconfont.svg +692 -692
  59. package/src/icons/index.js +9 -9
  60. package/src/lang/e.js +48 -48
  61. package/src/lang/en.js +48 -48
  62. package/src/lang/zh.js +48 -48
  63. package/src/main.js +62 -62
  64. package/src/permission.js +283 -283
  65. package/src/permissionForMall.backup.js +375 -375
  66. package/src/permissionForMall.js +375 -375
  67. package/src/preset.js +67 -67
  68. package/src/router/_import_common.js +1 -1
  69. package/src/router/_import_development.js +1 -1
  70. package/src/router/_import_production.js +1 -1
  71. package/src/store/getters.js +39 -39
  72. package/src/store/index.js +18 -18
  73. package/src/store/modules/app.js +34 -34
  74. package/src/store/modules/menu.js +82 -82
  75. package/src/store/modules/user.js +234 -234
  76. package/src/styles/element-ui.scss +1368 -1368
  77. package/src/styles/index.scss +166 -166
  78. package/src/styles/mixin.scss +27 -27
  79. package/src/styles/pc-ui.scss +1031 -1031
  80. package/src/styles/scrollBar.scss +21 -21
  81. package/src/styles/sidebar.scss +123 -123
  82. package/src/styles/transition.scss +32 -32
  83. package/src/styles/variables.scss +44 -44
  84. package/src/styles/wf-ui.scss +86 -86
  85. package/src/utils/auth.js +84 -57
  86. package/src/utils/dom.js +12 -12
  87. package/src/utils/getQueryString.js +5 -5
  88. package/src/utils/import.js +5 -5
  89. package/src/utils/index.js +355 -355
  90. package/src/utils/interceptor.js +34 -34
  91. package/src/utils/menu.js +116 -116
  92. package/src/utils/proapp.js +35 -35
  93. package/src/utils/query.js +26 -26
  94. package/src/utils/request.js +374 -374
  95. package/src/utils/routeMapping.js +39 -39
  96. package/src/utils/routeMapping.json +310 -310
  97. package/src/utils/utils.js +84 -84
  98. package/src/utils/validate.js +102 -102
  99. package/src/views/404.vue +72 -72
  100. package/src/views/Layout.vue +106 -106
  101. package/src/views/imgSwiper/index.vue +34 -34
  102. package/src/views/layout/Layout.vue +181 -181
  103. package/src/views/layout/components/AppMain.vue +20 -20
  104. package/src/views/layout/components/Footer.vue +22 -22
  105. package/src/views/layout/components/LeftNavbar.vue +318 -318
  106. package/src/views/layout/components/NavMenu.vue +15 -15
  107. package/src/views/layout/components/Navbar.vue +765 -695
  108. package/src/views/layout/components/Sidebar/SidebarItem.vue +116 -116
  109. package/src/views/layout/components/Sidebar/index.vue +216 -216
  110. package/src/views/layout/components/index.js +19 -19
  111. package/src/views/layout/theme/darkBlue/Layout.vue +140 -140
  112. package/src/views/layout/theme/darkBlue/components/AppMain.vue +38 -38
  113. package/src/views/layout/theme/darkBlue/components/Footer.vue +147 -147
  114. package/src/views/layout/theme/darkBlue/components/LeftNavbar(/345/261/225/347/244/272/345/205/250/351/203/250/350/217/234/345/215/225).vue +448 -448
  115. package/src/views/layout/theme/darkBlue/components/LeftNavbar.3.vue +191 -191
  116. package/src/views/layout/theme/darkBlue/components/LeftNavbar.vue +466 -466
  117. package/src/views/layout/theme/darkBlue/components/Navbar.vue +200 -200
  118. package/src/views/layout/theme/darkBlue/components/Sidebar/SidebarItem.vue +71 -71
  119. package/src/views/layout/theme/darkBlue/components/Sidebar/index.vue +49 -49
  120. package/src/views/layout/theme/darkBlue/components/index.js +15 -15
  121. package/src/views/layout-default/Layout.vue +134 -134
  122. package/src/views/layout-default/components/AppMain.vue +19 -19
  123. package/src/views/layout-default/components/Footer.vue +22 -22
  124. package/src/views/layout-default/components/LeftNavbar.vue +164 -164
  125. package/src/views/layout-default/components/Navbar.vue +295 -295
  126. package/src/views/layout-default/components/Sidebar/SidebarItem.vue +67 -67
  127. package/src/views/layout-default/components/Sidebar/index.vue +59 -59
  128. package/src/views/layout-default/components/index.js +4 -4
  129. package/src/views/layout-default/theme/darkBlue/Layout.vue +140 -140
  130. package/src/views/layout-default/theme/darkBlue/components/AppMain.vue +38 -38
  131. package/src/views/layout-default/theme/darkBlue/components/Footer.vue +147 -147
  132. package/src/views/layout-default/theme/darkBlue/components/LeftNavbar.vue +465 -465
  133. package/src/views/layout-default/theme/darkBlue/components/Navbar.vue +200 -200
  134. package/src/views/layout-default/theme/darkBlue/components/Sidebar/SidebarItem.vue +69 -69
  135. package/src/views/layout-default/theme/darkBlue/components/Sidebar/index.vue +49 -49
  136. package/src/views/layout-default/theme/darkBlue/components/index.js +15 -15
  137. package/src/views/pc/Internationalization.vue +80 -80
  138. package/src/views/pc/default/Layout.vue +442 -442
  139. package/src/views/pc/default/LayoutCard.vue +424 -424
  140. package/src/views/pc/default/assets/flex.scss +99 -99
  141. package/src/views/pc/default/footer-modules/DgFooter/index.vue +179 -179
  142. package/src/views/pc/default/footer-modules/DgFooter/indexSDX.vue +187 -187
  143. package/src/views/pc/default/footer-modules/footer.vue +171 -171
  144. package/src/views/pc/default/footer-modules/footerAns.vue +167 -167
  145. package/src/views/pc/default/footer-modules/footerBulk.vue +169 -169
  146. package/src/views/pc/default/footer-modules/footerDM.vue +254 -254
  147. package/src/views/pc/default/footer-modules/footerDefault.vue +267 -267
  148. package/src/views/pc/default/footer-modules/footerDefaultA.vue +270 -270
  149. package/src/views/pc/default/footer-modules/footerDefaultNew.vue +201 -201
  150. package/src/views/pc/default/footer-modules/footerHDB.vue +153 -153
  151. package/src/views/pc/default/footer-modules/footerHy.vue +63 -63
  152. package/src/views/pc/default/footer-modules/footerKYW.vue +163 -163
  153. package/src/views/pc/default/footer-modules/footerMh.vue +30 -30
  154. package/src/views/pc/default/footer-modules/footerNew.vue +116 -116
  155. package/src/views/pc/default/footer-modules/footer_yzj.vue +169 -169
  156. package/src/views/pc/default/footer-modules/footerayd.vue +85 -85
  157. package/src/views/pc/default/footer-modules/ymFooter.vue +154 -154
  158. package/src/views/pc/default/footer-modules/zgl.vue +250 -250
  159. package/src/views/pc/default/header-modules/DgHeader/Logo.vue +57 -57
  160. package/src/views/pc/default/header-modules/DgHeader/Search.vue +135 -135
  161. package/src/views/pc/default/header-modules/DgHeader/Settleup.vue +46 -46
  162. package/src/views/pc/default/header-modules/DgHeader/index.vue +38 -38
  163. package/src/views/pc/default/header-modules/active.vue +177 -177
  164. package/src/views/pc/default/header-modules/header.vue +97 -97
  165. package/src/views/pc/default/header-modules/headerA.vue +142 -142
  166. package/src/views/pc/default/header-modules/headerFLPT.vue +157 -157
  167. package/src/views/pc/default/header-modules/headerMh.vue +187 -187
  168. package/src/views/pc/default/header-modules/headerNew.vue +121 -121
  169. package/src/views/pc/default/header-modules/headerSDX.vue +304 -304
  170. package/src/views/pc/default/header-modules/headerStyle2.vue +173 -173
  171. package/src/views/pc/default/header-modules/headerStyle3.vue +190 -190
  172. package/src/views/pc/default/header-modules/headerStyle4.vue +163 -163
  173. package/src/views/pc/default/header-modules/headerStyleAns.vue +400 -400
  174. package/src/views/pc/default/header-modules/headerStyleBulk.vue +427 -427
  175. package/src/views/pc/default/header-modules/headerStyleDefalut.vue +209 -209
  176. package/src/views/pc/default/header-modules/headerStyleKYW.vue +435 -435
  177. package/src/views/pc/default/header-modules/headerStyle_yzj.vue +427 -427
  178. package/src/views/pc/default/header-modules/headerayd.vue +187 -187
  179. package/src/views/pc/default/header-modules/index.vue +466 -466
  180. package/src/views/pc/default/header-modules/ymHeader.vue +292 -292
  181. package/src/views/pc/default/header-modules/ysHeader.vue +248 -248
  182. package/src/views/pc/default/header-modules/zgl.vue +855 -855
  183. package/src/views/pc/default/leftMenu-modules/leftMenu-logo.vue +194 -194
  184. package/src/views/pc/default/leftMenu-modules/leftMenu-style2.vue +206 -206
  185. package/src/views/pc/default/leftMenu-modules/leftMenu-style3.vue +207 -207
  186. package/src/views/pc/default/leftMenu-modules/leftMenu-style4.vue +192 -192
  187. package/src/views/pc/default/leftMenu-modules/leftMenu.vue +183 -183
  188. package/src/views/pc/default/leftMenu-modules/leftMenuDefault.vue +212 -212
  189. package/src/views/pc/default/leftMenu-modules/leftMenuDefaultEn.vue +214 -214
  190. package/src/views/pc/default/leftMenu-modules/leftMenuDefaultFLPT.vue +220 -220
  191. package/src/views/pc/default/leftMenu-modules/leftMenuDefaultayd.vue +220 -220
  192. package/src/views/pc/default/nav-modules/nav.vue +52 -52
  193. package/src/views/pc/default/nav-modules/navAns.vue +60 -60
  194. package/src/views/pc/default/nav-modules/navBulk.vue +60 -60
  195. package/src/views/pc/default/top-modules/DgTopShortcut/index.vue +177 -177
  196. package/src/views/pc/default/top-modules/Toplg.vue +280 -280
  197. package/src/views/pc/default/top-modules/topA.vue +136 -136
  198. package/src/views/pc/default/top-modules/topAns.vue +261 -261
  199. package/src/views/pc/default/top-modules/topAns_yzj.vue +282 -282
  200. package/src/views/pc/default/top-modules/topBar.vue +304 -304
  201. package/src/views/pc/default/top-modules/topBulk.vue +280 -280
  202. package/src/views/pc/default/top-modules/topDefault.vue +244 -244
  203. package/src/views/pc/default/top-modules/topDefaultDM.vue +197 -197
  204. package/src/views/pc/default/top-modules/topDefaultNew.vue +271 -271
  205. package/src/views/pc/default/top-modules/topFLPT.vue +197 -197
  206. package/src/views/pc/default/top-modules/topHDB.vue +479 -479
  207. package/src/views/pc/default/top-modules/topKYW.vue +258 -258
  208. package/src/views/pc/default/top-modules/topMh.vue +174 -174
  209. package/src/views/pc/default/top-modules/topNew.vue +97 -97
  210. package/src/views/pc/default/top-modules/topSDX.vue +298 -298
  211. package/src/views/pc/default/top-modules/topSimple.vue +247 -247
  212. package/src/views/pc/default/top-modules/topSimpleHy.vue +256 -256
  213. package/src/views/pc/default/top-modules/topUcc.vue +264 -264
  214. package/src/views/pc/default/top-modules/topayd.vue +170 -170
  215. package/src/views/pc/default/top-modules/ymTop.vue +299 -299
  216. package/src/views/pc/default/top-modules/zgltop.vue +499 -499
  217. package/src/views/routerView.vue +9 -9
  218. package/src/views/templates/components/temp-select.vue +80 -80
  219. package/src/views/templates/components/temp-upload.vue +233 -233
  220. package/src/views/templates/readme.md +2 -2
  221. package/src/views/templates/templateInput.vue +421 -421
  222. package/src/views/templates/templateReadme.html +588 -588
  223. package/src/views/templates/templateReadme.md +619 -619
  224. package/src/views/templates/templateTable.vue +2244 -2244
  225. package/src/views/templates/templateTableData.vue +1883 -1883
  226. package/src/views/templates/templateUi/templateTableContent.vue +187 -187
  227. package/src/views/treeTemplate/index.vue +559 -559
  228. package/src/views/treeTemplate/treeTemplate.md +274 -274
  229. package/src/views/uploadDialog/index copy.vue +352 -352
  230. package/src/views/uploadDialog/index.vue +558 -558
  231. package/src/views/uploadDialog/indexOlay.vue +582 -582
  232. package/src/views/uploadDialog/indexPM.vue +578 -578
  233. package/src/views/uploadDialog/indexUpload.vue +543 -543
  234. package/src/views/uploadDialog/readme.md +45 -45
@@ -0,0 +1,707 @@
1
+ <template>
2
+ <div class="site-msg">
3
+ <el-drawer
4
+ :visible.sync="drawerVisible"
5
+ direction="rtl"
6
+ size="820px"
7
+ :with-header="false"
8
+ :before-close="handleClose"
9
+ custom-class="site-msg-drawer"
10
+ append-to-body
11
+ >
12
+ <div class="site-msg-container">
13
+ <!-- 顶部主消息类型Tab -->
14
+ <div class="msg-header">
15
+ <div class="msg-tabs">
16
+ <div
17
+ v-for="tab in messageTypes"
18
+ :key="tab.key"
19
+ class="msg-tab"
20
+ :class="{ active: activeType === tab.key }"
21
+ @click="switchType(tab.key)"
22
+ >
23
+ <span class="tab-name">{{ tab.name }}</span>
24
+ <el-badge
25
+ v-if="getTypeUnreadCount(tab.key) > 0"
26
+ :value="getTypeUnreadCount(tab.key)"
27
+ class="tab-badge"
28
+ />
29
+ </div>
30
+ </div>
31
+ <div class="msg-close" @click="closeDrawer">
32
+ <i class="el-icon-close"></i>
33
+ </div>
34
+ </div>
35
+
36
+ <div class="msg-body">
37
+ <!-- 左侧消息子类 -->
38
+ <div class="msg-sidebar">
39
+ <div
40
+ v-for="sub in currentSubCategories"
41
+ :key="sub.key"
42
+ class="sidebar-item"
43
+ :class="{ active: activeSub === sub.key }"
44
+ @click="switchSub(sub.key)"
45
+ >
46
+ <span class="sidebar-name">{{ sub.name }}</span>
47
+ <el-badge
48
+ v-if="getSubUnreadCount(sub.key) > 0"
49
+ :value="getSubUnreadCount(sub.key)"
50
+ class="sidebar-badge"
51
+ />
52
+ </div>
53
+ </div>
54
+
55
+ <!-- 右侧消息区 -->
56
+ <div class="msg-content">
57
+ <!-- 筛选Tab + 全部已读 -->
58
+ <div class="content-toolbar">
59
+ <div class="filter-tabs">
60
+ <div
61
+ v-for="f in filterTabs"
62
+ :key="f.key"
63
+ class="filter-tab"
64
+ :class="{ active: filterActive === f.key }"
65
+ @click="switchFilter(f.key)"
66
+ >
67
+ <span class="filter-name">{{ f.name }}</span>
68
+ <span class="filter-count" v-if="f.key === 'unread'">({{ getSubUnreadCount(activeSub) }})</span>
69
+ </div>
70
+ </div>
71
+ <el-checkbox
72
+ v-if="getCurrentFilteredMessages().length > 0"
73
+ v-model="markAllChecked"
74
+ @change="markAllRead"
75
+ class="mark-all"
76
+ >
77
+ 全部已读
78
+ </el-checkbox>
79
+ </div>
80
+
81
+ <!-- 搜索框 -->
82
+ <div class="search-bar">
83
+ <el-input
84
+ v-model="searchKeyword"
85
+ placeholder="搜索消息名称或内容"
86
+ clearable
87
+ size="small"
88
+ prefix-icon="el-icon-search"
89
+ @keyup.enter="handleSearch"
90
+ @clear="handleSearch"
91
+ />
92
+ <el-button
93
+ type="primary"
94
+ size="small"
95
+ icon="el-icon-search"
96
+ @click="handleSearch"
97
+ >搜索</el-button>
98
+ </div>
99
+
100
+ <!-- 消息列表 -->
101
+ <div class="message-list" v-loading="loading">
102
+ <div
103
+ v-for="msg in filteredMessages"
104
+ :key="msg.id"
105
+ class="message-card"
106
+ :class="{ unread: !msg.isRead }"
107
+ >
108
+ <div class="msg-card-header">
109
+ <span class="msg-title">{{ msg.title }}</span>
110
+ <span class="msg-time">{{ msg.time }}</span>
111
+ <el-tooltip
112
+ :content="msg.isRead ? '已读' : '标记为已读'"
113
+ placement="top"
114
+ :open-delay="300"
115
+ >
116
+ <img
117
+ v-if="!msg.isRead"
118
+ src="./img/unread-icon.png"
119
+ alt="未读"
120
+ class="msg-read-icon"
121
+ @click="!msg.isRead && markAsRead(msg.id)"
122
+ />
123
+ <img
124
+ v-else
125
+ src="./img/readed-icon.png"
126
+ alt="已读"
127
+ class="msg-read-icon"
128
+ />
129
+ </el-tooltip>
130
+ </div>
131
+ <div class="msg-content-text" v-html="renderContent(msg)"></div>
132
+ </div>
133
+
134
+ <el-empty
135
+ v-if="!loading && filteredMessages.length === 0"
136
+ description="暂无消息"
137
+ />
138
+ </div>
139
+
140
+ <!-- 分页 -->
141
+ <div class="msg-pagination">
142
+ <el-pagination
143
+ v-if="total > 0"
144
+ small
145
+ background
146
+ layout="prev, pager, next, jumper"
147
+ :current-page="currentPage"
148
+ :page-size="pageSize"
149
+ :total="total"
150
+ @current-change="handleCurrentChange"
151
+ />
152
+ </div>
153
+ </div>
154
+ </div>
155
+ </div>
156
+ </el-drawer>
157
+ </div>
158
+ </template>
159
+
160
+ <script>
161
+ import {
162
+ queryMailMnsblistPageTree,
163
+ queryMnsblistPage,
164
+ updateStateExtRead,
165
+ updateAllRead
166
+ } from '#/api/siteMsg';
167
+
168
+ export default {
169
+ name: 'SiteMsg',
170
+ props: {
171
+ visible: {
172
+ type: Boolean,
173
+ default: false
174
+ }
175
+ },
176
+ data() {
177
+ return {
178
+ drawerVisible: this.visible,
179
+ loading: false,
180
+ treeLoading: false,
181
+ treeLoaded: false,
182
+ activeType: '',
183
+ activeSub: '',
184
+ filterActive: 'all',
185
+ searchKeyword: '',
186
+ appliedKeyword: '',
187
+ markAllChecked: false,
188
+ currentPage: 1,
189
+ pageSize: 10,
190
+ total: 0,
191
+ totalUnread: 0,
192
+ messageTypes: [],
193
+ subCategoryMap: {},
194
+ filterTabs: [
195
+ { key: 'unread', name: '仅展示未读' },
196
+ { key: 'read', name: '仅展示已读' },
197
+ { key: 'all', name: '全部消息' }
198
+ ],
199
+ messages: []
200
+ }
201
+ },
202
+ computed: {
203
+ currentSubCategories() {
204
+ return this.subCategoryMap[this.activeType] || []
205
+ },
206
+ filteredMessages() {
207
+ return this.messages
208
+ }
209
+ },
210
+ watch: {
211
+ visible(val) {
212
+ this.drawerVisible = val
213
+ if (val && !this.treeLoaded) {
214
+ this.fetchTree()
215
+ }
216
+ },
217
+ drawerVisible(val) {
218
+ this.$emit('update:visible', val)
219
+ }
220
+ },
221
+ mounted() {
222
+ this.fetchTree()
223
+ },
224
+ methods: {
225
+ // 1.查询顶部tab消息类型和左侧tab状态类型
226
+ async fetchTree() {
227
+ this.treeLoading = true
228
+ try {
229
+ const res = await queryMailMnsblistPageTree({ mnslistBustype: 'smail', stateExt: '0' })
230
+ const list = (res && res.mnsTabTreeNodeList) || []
231
+ this.messageTypes = list.map(n => ({
232
+ key: n.code,
233
+ name: n.message,
234
+ badge: n.badge || 0,
235
+ children: (n.children || []).map(c => ({
236
+ key: c.code,
237
+ name: c.message,
238
+ badge: c.badge || 0
239
+ }))
240
+ }))
241
+ this.subCategoryMap = {}
242
+ this.messageTypes.forEach(t => {
243
+ this.subCategoryMap[t.key] = t.children
244
+ })
245
+ this.totalUnread = (res && res.badge) || 0
246
+ this.treeLoaded = true
247
+ // 设置默认选中项
248
+ if (this.messageTypes.length > 0) {
249
+ if (!this.messageTypes.find(t => t.key === this.activeType)) {
250
+ this.activeType = this.messageTypes[0].key
251
+ }
252
+ const subs = this.subCategoryMap[this.activeType] || []
253
+ if (subs.length > 0 && !subs.find(s => s.key === this.activeSub)) {
254
+ this.activeSub = subs[0].key
255
+ } else if (subs.length === 0) {
256
+ this.activeSub = ''
257
+ }
258
+ }
259
+ this.emitUnreadCount()
260
+ this.fetchMessageList()
261
+ } catch (e) {
262
+ console.error('queryMailMnsblistPageTree error:', e)
263
+ } finally {
264
+ this.treeLoading = false
265
+ }
266
+ },
267
+ // 2.根据1,2级选中的类型查询消息列表
268
+ async fetchMessageList() {
269
+ if (!this.activeType) {
270
+ this.messages = []
271
+ return
272
+ }
273
+ this.loading = true
274
+ this.markAllChecked = false
275
+ try {
276
+ const params = {
277
+ page: this.currentPage,
278
+ rows: this.pageSize,
279
+ mnslistBustype: 'smail',
280
+ mnslistBustnameExt: this.activeType, // 一级菜单code
281
+ // fuzzy: false
282
+ }
283
+ if (this.activeSub) {
284
+ params.mnslistBustypeExt = this.activeSub // 二级菜单code
285
+ }
286
+ if (this.appliedKeyword) {
287
+ params.mnslistContentLike = this.appliedKeyword // 模糊搜索关键词
288
+ }
289
+ // stateExt: 0未读 1已读 查全部不传
290
+ if (this.filterActive === 'unread') {
291
+ params.stateExt = '0'
292
+ } else if (this.filterActive === 'read') {
293
+ params.stateExt = '1'
294
+ }
295
+ const res = await queryMnsblistPage(params)
296
+ const rows = (res && res.rows) || []
297
+ this.messages = rows.map(r => this.mapMessage(r))
298
+ this.total = (res && res.total) || this.messages.length
299
+ } catch (e) {
300
+ console.error('queryMnsblistPage error:', e)
301
+ this.messages = []
302
+ this.total = 0
303
+ } finally {
304
+ this.loading = false
305
+ }
306
+ },
307
+ // 行数据映射为组件所需结构
308
+ mapMessage(row) {
309
+ return {
310
+ id: row.mnsblistId || row.id || '',
311
+ typeId: this.activeType,
312
+ subId: this.activeSub,
313
+ title: row.mnschannelName || row.mnslistName || '',
314
+ time: this.pickTime(row),
315
+ content: row.mnslistContent || '',
316
+ isRead: String(row.stateExt) === '1',
317
+ raw: row
318
+ }
319
+ },
320
+ // 兼容取消息时间字段
321
+ pickTime(row) {
322
+ const fields = ['gmtModified', 'gmtCreate', 'sendTime', 'createTime', 'mnsblistDate', 'mnsblistTime']
323
+ for (const f of fields) {
324
+ if (row[f]) return row[f]
325
+ }
326
+ return ''
327
+ },
328
+ emitUnreadCount() {
329
+ this.$emit('unread-count-change', this.totalUnread)
330
+ },
331
+ switchType(key) {
332
+ this.activeType = key
333
+ const subs = this.subCategoryMap[key] || []
334
+ this.activeSub = subs.length > 0 ? subs[0].key : ''
335
+ this.filterActive = 'all'
336
+ this.appliedKeyword = ''
337
+ this.searchKeyword = ''
338
+ this.markAllChecked = false
339
+ this.currentPage = 1
340
+ this.fetchMessageList()
341
+ },
342
+ switchSub(key) {
343
+ this.activeSub = key
344
+ this.filterActive = 'all'
345
+ this.appliedKeyword = ''
346
+ this.searchKeyword = ''
347
+ this.markAllChecked = false
348
+ this.currentPage = 1
349
+ this.fetchMessageList()
350
+ },
351
+ switchFilter(key) {
352
+ this.filterActive = key
353
+ this.currentPage = 1
354
+ this.fetchMessageList()
355
+ },
356
+ getTypeUnreadCount(typeKey) {
357
+ const node = this.messageTypes.find(t => t.key === typeKey)
358
+ return node ? node.badge : 0
359
+ },
360
+ getSubUnreadCount(subKey) {
361
+ const sub = this.currentSubCategories.find(c => c.key === subKey)
362
+ return sub ? sub.badge : 0
363
+ },
364
+ getCurrentFilteredMessages() {
365
+ return this.filteredMessages
366
+ },
367
+ handleCurrentChange(val) {
368
+ this.currentPage = val
369
+ this.fetchMessageList()
370
+ },
371
+ handleSearch() {
372
+ this.appliedKeyword = this.searchKeyword.trim()
373
+ this.currentPage = 1
374
+ this.fetchMessageList()
375
+ },
376
+ // 3.单个已读
377
+ async markAsRead(id) {
378
+ const msg = this.messages.find(m => m.id === id)
379
+ if (!msg || msg.isRead) return
380
+ try {
381
+ await updateStateExtRead({ mnsblistId: id })
382
+ msg.isRead = true
383
+ const subNode = this.currentSubCategories.find(c => c.key === this.activeSub)
384
+ const typeNode = this.messageTypes.find(t => t.key === this.activeType)
385
+ if (subNode && subNode.badge > 0) subNode.badge--
386
+ if (typeNode && typeNode.badge > 0) typeNode.badge--
387
+ if (this.totalUnread > 0) this.totalUnread--
388
+ this.emitUnreadCount()
389
+ } catch (e) {
390
+ console.error('updateStateExtRead error:', e)
391
+ this.$message.error('标记已读失败')
392
+ }
393
+ },
394
+ // 全部已读(当前二级菜单下的消息)
395
+ async markAllRead(val) {
396
+ if (!val) return
397
+ const unread = this.filteredMessages.filter(m => !m.isRead)
398
+ if (unread.length === 0) {
399
+ this.markAllChecked = false
400
+ return
401
+ }
402
+ const params = {
403
+ mnslistBustypeExt: this.activeSub, // 二级菜单code
404
+ }
405
+ const subNode = this.currentSubCategories.find(c => c.key === this.activeSub)
406
+ const typeNode = this.messageTypes.find(t => t.key === this.activeType)
407
+ const subUnread = subNode ? subNode.badge : 0
408
+ try {
409
+ const res = await updateAllRead(params)
410
+ if (res.success) {
411
+ // 接口标记的是当前二级菜单下全部消息(含分页外),按二级菜单未读数同步徽标
412
+ if (subNode) subNode.badge = 0
413
+ if (typeNode) typeNode.badge = Math.max(0, typeNode.badge - subUnread)
414
+ this.totalUnread = Math.max(0, this.totalUnread - subUnread)
415
+ this.emitUnreadCount()
416
+ this.fetchMessageList()
417
+ this.$message.success('已全部标记为已读')
418
+ } else {
419
+ this.$message.error(res.msg || '全部已读失败')
420
+ }
421
+ } catch (e) {
422
+ console.error('updateAllRead error:', e)
423
+ this.$message.error('全部已读失败')
424
+ } finally {
425
+ this.markAllChecked = false
426
+ }
427
+ },
428
+ renderContent(msg) {
429
+ return msg.content
430
+ },
431
+ jumpToProduct(code) {
432
+ this.$emit('jump-to-product', code)
433
+ this.$message.info(`跳转至商品中心 - 商品管理 - 待审核商品列表,商品编号:${code}`)
434
+ },
435
+ closeDrawer() {
436
+ this.drawerVisible = false
437
+ },
438
+ handleClose(done) {
439
+ done()
440
+ }
441
+ }
442
+ }
443
+ </script>
444
+
445
+ <style lang="scss">
446
+ .site-msg-drawer {
447
+ .el-drawer__body {
448
+ padding: 0;
449
+ overflow: hidden;
450
+ }
451
+
452
+ .site-msg-container {
453
+ display: flex;
454
+ flex-direction: column;
455
+ height: 100vh;
456
+ background: #f5f7fa;
457
+ }
458
+
459
+ .msg-header {
460
+ display: flex;
461
+ align-items: center;
462
+ justify-content: space-between;
463
+ background: #fff;
464
+ padding: 0 16px;
465
+ border-bottom: 1px solid #e4e7ed;
466
+ height: 50px;
467
+ flex-shrink: 0;
468
+
469
+ .msg-tabs {
470
+ display: flex;
471
+ align-items: center;
472
+ gap: 4px;
473
+ }
474
+
475
+ .msg-tab {
476
+ display: flex;
477
+ align-items: center;
478
+ padding: 0 14px;
479
+ height: 50px;
480
+ cursor: pointer;
481
+ font-size: 14px;
482
+ color: #606266;
483
+ position: relative;
484
+ white-space: nowrap;
485
+ transition: color 0.2s;
486
+
487
+ &:hover {
488
+ color: #409eff;
489
+ }
490
+
491
+ &.active {
492
+ color: #409eff;
493
+ font-weight: 600;
494
+
495
+ &::after {
496
+ content: '';
497
+ position: absolute;
498
+ bottom: 0;
499
+ left: 14px;
500
+ right: 14px;
501
+ height: 2px;
502
+ background: #409eff;
503
+ }
504
+ }
505
+
506
+ .tab-name {
507
+ line-height: 50px;
508
+ }
509
+
510
+ .tab-badge {
511
+ margin-left: 4px;
512
+ }
513
+ }
514
+
515
+ .msg-close {
516
+ cursor: pointer;
517
+ font-size: 18px;
518
+ color: #909399;
519
+ padding: 4px;
520
+
521
+ &:hover {
522
+ color: #409eff;
523
+ }
524
+ }
525
+ }
526
+
527
+ .msg-body {
528
+ display: flex;
529
+ flex: 1;
530
+ overflow: hidden;
531
+ }
532
+
533
+ .msg-sidebar {
534
+ width: 160px;
535
+ background: #fff;
536
+ border-right: 1px solid #e4e7ed;
537
+ padding: 12px 0;
538
+ flex-shrink: 0;
539
+ overflow-y: auto;
540
+
541
+ .sidebar-item {
542
+ display: flex;
543
+ align-items: center;
544
+ justify-content: space-between;
545
+ padding: 10px 16px;
546
+ cursor: pointer;
547
+ font-size: 13px;
548
+ color: #606266;
549
+ transition: all 0.2s;
550
+
551
+ &:hover {
552
+ background: #ecf5ff;
553
+ color: #409eff;
554
+ }
555
+
556
+ &.active {
557
+ background: #ecf5ff;
558
+ color: #409eff;
559
+ font-weight: 600;
560
+ border-right: 3px solid #409eff;
561
+ }
562
+
563
+ .sidebar-name {
564
+ flex: 1;
565
+ }
566
+ }
567
+ }
568
+
569
+ .msg-content {
570
+ flex: 1;
571
+ display: flex;
572
+ flex-direction: column;
573
+ overflow: hidden;
574
+ padding: 0 16px;
575
+ }
576
+
577
+ .content-toolbar {
578
+ display: flex;
579
+ align-items: center;
580
+ justify-content: space-between;
581
+ padding: 12px 0;
582
+ border-bottom: 1px solid #ebeef5;
583
+ flex-shrink: 0;
584
+
585
+ .filter-tabs {
586
+ display: flex;
587
+ align-items: center;
588
+ gap: 8px;
589
+ }
590
+
591
+ .filter-tab {
592
+ display: flex;
593
+ align-items: center;
594
+ padding: 6px 12px;
595
+ border-radius: 16px;
596
+ cursor: pointer;
597
+ font-size: 13px;
598
+ color: #606266;
599
+ border: 1px solid #dcdfe6;
600
+ background: #fff;
601
+ transition: all 0.2s;
602
+
603
+ &:hover {
604
+ color: #409eff;
605
+ border-color: #409eff;
606
+ }
607
+
608
+ &.active {
609
+ background: #409eff;
610
+ color: #fff;
611
+ border-color: #409eff;
612
+ font-weight: 600;
613
+ }
614
+
615
+ .filter-count {
616
+ margin-left: 2px;
617
+ }
618
+ }
619
+
620
+ .mark-all {
621
+ font-size: 13px;
622
+ }
623
+ }
624
+
625
+ .search-bar {
626
+ display: flex;
627
+ gap: 8px;
628
+ padding: 12px 0;
629
+ flex-shrink: 0;
630
+
631
+ .el-input {
632
+ flex: 1;
633
+ }
634
+ }
635
+
636
+ .message-list {
637
+ flex: 1;
638
+ overflow-y: auto;
639
+ padding-bottom: 16px;
640
+
641
+ .message-card {
642
+ background: #fff;
643
+ border-radius: 6px;
644
+ padding: 14px 16px;
645
+ margin-bottom: 10px;
646
+ border: 1px solid #ebeef5;
647
+ transition: box-shadow 0.2s;
648
+
649
+ &:hover {
650
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.08);
651
+ }
652
+
653
+ &.unread {
654
+ border-left: 3px solid #409eff;
655
+ background: #fafcff;
656
+ }
657
+
658
+ .msg-card-header {
659
+ display: flex;
660
+ align-items: center;
661
+ margin-bottom: 8px;
662
+
663
+ .msg-title {
664
+ font-size: 14px;
665
+ font-weight: 600;
666
+ color: #303133;
667
+ }
668
+
669
+ .msg-time {
670
+ font-size: 12px;
671
+ color: #909399;
672
+ margin-left: 12px;
673
+ }
674
+
675
+ .msg-read-icon {
676
+ margin-left: auto;
677
+ width: 24px;
678
+ height: 24px;
679
+ cursor: pointer;
680
+ }
681
+ }
682
+
683
+ .msg-content-text {
684
+ font-size: 13px;
685
+ color: #606266;
686
+ line-height: 1.6;
687
+
688
+ .highlight-link {
689
+ color: #409eff;
690
+ cursor: pointer;
691
+ text-decoration: none;
692
+
693
+ &:hover {
694
+ text-decoration: underline;
695
+ }
696
+ }
697
+ }
698
+ }
699
+ }
700
+
701
+ .msg-pagination {
702
+ flex-shrink: 0;
703
+ padding: 8px 0;
704
+ text-align: center;
705
+ }
706
+ }
707
+ </style>