Commit e8715703c1f35d156c26e851f9174e200ae787b1

Authored by 史婷婷
1 parent 7049339c

feat: 首页菜单权限

Showing 2 changed files with 302 additions and 227 deletions
@@ -39,4 +39,13 @@ export function selectorCityApi() { @@ -39,4 +39,13 @@ export function selectorCityApi() {
39 url: `/selector/city`, 39 url: `/selector/city`,
40 method: 'get' 40 method: 'get'
41 }) 41 })
  42 +}
  43 +/**
  44 + * 回去城市接口 省市区 一次性返回
  45 + */
  46 +export function getMenusApi() {
  47 + return request({
  48 + url: `/auth/menus`,
  49 + method: 'get'
  50 + })
42 } 51 }
@@ -3,7 +3,8 @@ @@ -3,7 +3,8 @@
3 <!-- 自定义头部 --> 3 <!-- 自定义头部 -->
4 <view class="custom-header"> 4 <view class="custom-header">
5 <view class="header-left" @click="navigateTo('/pages/message/index')"> 5 <view class="header-left" @click="navigateTo('/pages/message/index')">
6 - <view class="bell-wrap"> 6 + <!-- name:MsgCenter 消息中心权限-->
  7 + <view class="bell-wrap" v-if="hasMenu('MsgCenter')">
7 <image class="icon" src="/static/images/index/bell.png" mode="widthFix" /> 8 <image class="icon" src="/static/images/index/bell.png" mode="widthFix" />
8 <view class="badge">99+</view> 9 <view class="badge">99+</view>
9 </view> 10 </view>
@@ -13,7 +14,8 @@ @@ -13,7 +14,8 @@
13 </view> 14 </view>
14 15
15 <!-- 顶部统计卡片 --> 16 <!-- 顶部统计卡片 -->
16 - <view class="stats-row"> 17 + <!-- name:BpmManage 流程中心权限 -->
  18 + <view class="stats-row" v-if="hasMenu('BpmManage')">
17 <view class="stat-card" @click="navigateTo('/pages/flow/approval')"> 19 <view class="stat-card" @click="navigateTo('/pages/flow/approval')">
18 <image class="card-bg" src="/static/images/index/card_wait.png" mode="aspectFill" /> 20 <image class="card-bg" src="/static/images/index/card_wait.png" mode="aspectFill" />
19 <view class="card-content"> 21 <view class="card-content">
@@ -30,16 +32,17 @@ @@ -30,16 +32,17 @@
30 </view> 32 </view>
31 </view> 33 </view>
32 <!-- 分组入口 --> 34 <!-- 分组入口 -->
33 - <view class="section" v-for="(it, index) in sectionList" :key="index"> 35 + <view class="section" v-for="(it, index) in sectionList" :key="index" v-if="!it.hidden">
34 <text class="section-title">{{ it.title }}</text> 36 <text class="section-title">{{ it.title }}</text>
35 <view class="grid"> 37 <view class="grid">
36 - <view class="grid-item" v-for="(g, idx) in it.items" :key="idx" @click="navigateTo(g.link)"> 38 + <view class="grid-item" v-for="(g, idx) in it.items" :key="idx" v-if="!g.hidden"
  39 + @click="navigateTo(g.link)">
37 <image class="grid-icon" :src="g.icon" /> 40 <image class="grid-icon" :src="g.icon" />
38 <text class="grid-text omit1">{{ g.text }}</text> 41 <text class="grid-text omit1">{{ g.text }}</text>
39 </view> 42 </view>
40 </view> 43 </view>
41 </view> 44 </view>
42 - 45 + <!-- todo 后续删掉 -->
43 <view class="section"> 46 <view class="section">
44 <text class="section-title">附件上传</text> 47 <text class="section-title">附件上传</text>
45 <view class="upload-row"> 48 <view class="upload-row">
@@ -51,261 +54,324 @@ @@ -51,261 +54,324 @@
51 </template> 54 </template>
52 55
53 <script> 56 <script>
54 - import FileUpload from '@/components/file-upload/index.vue'  
55 - import {  
56 - statisticsCountApi  
57 - } from '@/api/flow.js'  
58 - export default {  
59 - components: { FileUpload },  
60 - data() {  
61 - return {  
62 - todoCount: '',  
63 - myCreateCount: '',  
64 - fileInfo: { id: '', name: '' },  
65 - sectionList: [{  
66 - title: '客户开发管理',  
67 - items: [{  
68 - text: '开发管理',  
69 - icon: '/static/images/index/dev_manage.png',  
70 - link: '/pages/dev_manage/index'  
71 - }]  
72 - },  
73 - {  
74 - title: '客户资信管理',  
75 - items: [{  
76 - text: '资信管理',  
77 - icon: '/static/images/index/credit_manage.png',  
78 - link: '/pages/credit_manage/index'  
79 - }]  
80 - },  
81 - {  
82 - title: '合同管理',  
83 - items: [{  
84 - text: '框架合同',  
85 - icon: '/static/images/index/contract_framework.png',  
86 - link: '/pages/contract_framework/index'  
87 - },  
88 - {  
89 - text: '经销标准合同',  
90 - icon: '/static/images/index/contract_retail.png',  
91 - link: '/pages/contract_retail/index'  
92 - },  
93 - {  
94 - text: '经销库存合同',  
95 - icon: '/static/images/index/contract_stock.png',  
96 - link: '/pages/contract_stock/index'  
97 - },  
98 - {  
99 - text: '经销未锁规合同',  
100 - icon: '/static/images/index/contract_unplan.png',  
101 - link: '/pages/contract_unplan/index'  
102 - },  
103 - {  
104 - text: '加工标准合同',  
105 - icon: '/static/images/index/contract_process.png',  
106 - link: '/pages/contract_process/index'  
107 - },  
108 - {  
109 - text: '外贸标准合同',  
110 - icon: '/static/images/index/contract_foreign_std.png',  
111 - link: '/pages/contract_foreign_std/index'  
112 - },  
113 - {  
114 - text: '外贸库存合同',  
115 - icon: '/static/images/index/contract_foreign_stock.png',  
116 - link: '/pages/contract_foreign_stock/index'  
117 - },  
118 - {  
119 - text: '外贸未锁规合同',  
120 - icon: '/static/images/index/contract_foreign_unplan.png',  
121 - link: '/pages/contract_foreign_unplan/index'  
122 - },  
123 - ],  
124 - }  
125 - ] 57 +import FileUpload from '@/components/file-upload/index.vue'
  58 +import {
  59 + statisticsCountApi
  60 +} from '@/api/flow.js'
  61 +import { getMenusApi } from '@/api/base.js'
  62 +export default {
  63 + components: { FileUpload },
  64 + data() {
  65 + return {
  66 + todoCount: '',
  67 + myCreateCount: '',
  68 + fileInfo: { id: '', name: '' },
  69 + sectionList: [{
  70 + title: '客户开发管理',
  71 + items: [{
  72 + text: '开发管理',
  73 + icon: '/static/images/index/dev_manage.png',
  74 + link: '/pages/dev_manage/index',
  75 + name: 'CustomerDevPlan'
  76 + }]
  77 + },
  78 + {
  79 + title: '客户资信管理',
  80 + items: [{
  81 + text: '资信管理',
  82 + icon: '/static/images/index/credit_manage.png',
  83 + link: '/pages/credit_manage/index',
  84 + name: 'CustomerCreditPlan'
  85 + }]
  86 + },
  87 + {
  88 + title: '合同管理',
  89 + items: [{
  90 + text: '框架合同',
  91 + icon: '/static/images/index/contract_framework.png',
  92 + link: '/pages/contract_framework/index',
  93 + name: 'ContractFramework'
  94 + },
  95 + {
  96 + text: '经销标准合同',
  97 + icon: '/static/images/index/contract_retail.png',
  98 + link: '/pages/contract_retail/index',
  99 + name: 'DistributionStandardContract'
  100 + },
  101 + {
  102 + text: '经销库存合同',
  103 + icon: '/static/images/index/contract_stock.png',
  104 + link: '/pages/contract_stock/index',
  105 + name: 'DistributionInventoryContract'
  106 + },
  107 + {
  108 + text: '经销未锁规合同',
  109 + icon: '/static/images/index/contract_unplan.png',
  110 + link: '/pages/contract_unplan/index',
  111 + name: 'DistributionUnlockedContract'
  112 + },
  113 + {
  114 + text: '加工标准合同',
  115 + icon: '/static/images/index/contract_process.png',
  116 + link: '/pages/contract_process/index',
  117 + name: 'ProcessedStandardContract'
  118 + },
  119 + {
  120 + text: '外贸标准合同',
  121 + icon: '/static/images/index/contract_foreign_std.png',
  122 + link: '/pages/contract_foreign_std/index',
  123 + name: 'ForeignTradeStandardContract'
  124 + },
  125 + {
  126 + text: '外贸库存合同',
  127 + icon: '/static/images/index/contract_foreign_stock.png',
  128 + link: '/pages/contract_foreign_stock/index',
  129 + name: 'ForeignTradeInventoryContract'
  130 + },
  131 + {
  132 + text: '外贸未锁规合同',
  133 + icon: '/static/images/index/contract_foreign_unplan.png',
  134 + link: '/pages/contract_foreign_unplan/index',
  135 + name: 'ForeignUnlockedContract'
  136 + },
  137 + {
  138 + text: '锁价无规格操作申请单',
  139 + icon: '/static/images/index/contract_foreign_unplan.png',
  140 + link: '/pages/contract_foreign_unplan/index',
  141 + name: 'UnlockedOperationApplication'
  142 + },
  143 + ],
  144 + },
  145 + {
  146 + title: '订货单管理',
  147 + items: [{
  148 + text: '订货单列表',
  149 + icon: '/static/images/index/credit_manage.png',
  150 + link: '/pages/credit_manage/index',
  151 + name: 'OrderList'
  152 + }]
126 } 153 }
  154 + ],
  155 + menuNames: []
  156 + }
  157 + },
  158 + created() {
  159 + this.getStatisticsFun()
  160 + this.loadMenusAndFilter()
  161 + },
  162 + methods: {
  163 + getStatisticsFun() {
  164 + statisticsCountApi().then((res) => {
  165 + this.todoCount = res.data.todoCount || '';
  166 + this.myCreateCount = res.data.myCreateCount || '';
  167 + });
127 }, 168 },
128 - created() {  
129 - this.getStatisticsFun()  
130 - },  
131 - methods: {  
132 - getStatisticsFun() {  
133 - statisticsCountApi().then((res) => {  
134 - this.todoCount = res.data.todoCount || '';  
135 - this.myCreateCount = res.data.myCreateCount || '';  
136 - });  
137 - },  
138 - // 普通页面  
139 - navigateTo(link) {  
140 - if (!link || link === '#') {  
141 - return; 169 + async loadMenusAndFilter() {
  170 + try {
  171 + const res = await getMenusApi()
  172 + const data = res && res.data ? res.data : []
  173 + const names = []
  174 + const walk = (n) => {
  175 + if (Array.isArray(n)) { n.forEach(walk); return }
  176 + if (!n || typeof n !== 'object') return
  177 + const nm = n.name != null ? String(n.name) : ''
  178 + if (nm) names.push(nm)
  179 + const cs = n.children
  180 + if (Array.isArray(cs)) cs.forEach(walk)
142 } 181 }
143 - // 规范化路径,确保以斜杠开头  
144 - const url = link.startsWith('/') ? link : `/${link}`;  
145 -  
146 - // 普通页面使用 navigateTo  
147 - uni.navigateTo({  
148 - url,  
149 - fail: () => {  
150 - uni.showToast({  
151 - title: '页面暂未开放',  
152 - icon: 'none'  
153 - });  
154 - }  
155 - }); 182 + walk(data)
  183 + this.menuNames = names
  184 + this.applyMenuFilter()
  185 + } catch (e) {
  186 + this.menuNames = []
  187 + this.applyMenuFilter()
156 } 188 }
  189 + },
  190 + applyMenuFilter() {
  191 + this.sectionList = (this.sectionList || []).map(sec => {
  192 + const items = Array.isArray(sec.items) ? sec.items : []
  193 + const nextItems = items.map(it => ({ ...it, hidden: !this.hasMenu(it && it.name) }))
  194 + const visibleCount = nextItems.filter(it => !it.hidden).length
  195 + const hidden = items.length === 0 || visibleCount === 0
  196 + return { ...sec, items: nextItems, hidden }
  197 + })
  198 + },
  199 + hasMenu(name) {
  200 + const names = Array.isArray(this.menuNames) ? this.menuNames : []
  201 + if (name == null) return false
  202 + return names.includes(String(name))
  203 + },
  204 + // 普通页面
  205 + navigateTo(link) {
  206 + if (!link || link === '#') {
  207 + return;
  208 + }
  209 + // 规范化路径,确保以斜杠开头
  210 + const url = link.startsWith('/') ? link : `/${link}`;
  211 +
  212 + // 普通页面使用 navigateTo
  213 + uni.navigateTo({
  214 + url,
  215 + fail: () => {
  216 + uni.showToast({
  217 + title: '页面暂未开放',
  218 + icon: 'none'
  219 + });
  220 + }
  221 + });
157 } 222 }
158 } 223 }
  224 +}
159 </script> 225 </script>
160 226
161 <style scoped lang="scss"> 227 <style scoped lang="scss">
162 - page {  
163 - background-color: #fff;  
164 - } 228 +page {
  229 + background-color: #fff;
  230 +}
165 231
166 - .home-page {  
167 - padding: 0 32rpx 32rpx;  
168 - padding-top: 96rpx;  
169 - } 232 +.home-page {
  233 + padding: 0 32rpx 32rpx;
  234 + padding-top: 96rpx;
  235 +}
170 236
171 - /* 自定义头部 */  
172 - .custom-header {  
173 - height: 96rpx; 237 +/* 自定义头部 */
  238 +.custom-header {
  239 + height: 96rpx;
  240 + display: flex;
  241 + align-items: center;
  242 + justify-content: space-between;
  243 + position: fixed;
  244 + top: 0;
  245 + left: 0;
  246 + right: 0;
  247 + z-index: 1000;
  248 + background-color: #fff;
  249 + padding: 0 32rpx;
  250 +
  251 + .header-left {
174 display: flex; 252 display: flex;
175 align-items: center; 253 align-items: center;
176 - justify-content: space-between;  
177 - position: fixed;  
178 - top: 0;  
179 - left: 0;  
180 - right: 0;  
181 - z-index: 1000;  
182 - background-color: #fff;  
183 - padding: 0 32rpx;  
184 -  
185 - .header-left {  
186 - display: flex;  
187 - align-items: center;  
188 - }  
189 -  
190 - .header-title {  
191 - font-size: 36rpx;  
192 - font-weight: 600;  
193 - color: rgba(0, 0, 0, 0.9);  
194 - }  
195 -  
196 - .icon {  
197 - width: 48rpx;  
198 - height: 48rpx;  
199 - } 254 + }
200 255
201 - .bell-wrap {  
202 - position: relative;  
203 - } 256 + .header-title {
  257 + font-size: 36rpx;
  258 + font-weight: 600;
  259 + color: rgba(0, 0, 0, 0.9);
  260 + }
204 261
205 - .header-right {  
206 - width: 48rpx;  
207 - } 262 + .icon {
  263 + width: 48rpx;
  264 + height: 48rpx;
  265 + }
208 266
209 - .badge {  
210 - position: absolute;  
211 - top: -8rpx;  
212 - left: 30rpx;  
213 - background-color: #ff3b30;  
214 - color: #fff;  
215 - font-size: 20rpx;  
216 - height: 32rpx;  
217 - min-width: 32rpx;  
218 - padding: 0 8rpx;  
219 - border-radius: 16rpx;  
220 - display: flex;  
221 - align-items: center;  
222 - justify-content: center;  
223 - } 267 + .bell-wrap {
  268 + position: relative;
224 } 269 }
225 270
  271 + .header-right {
  272 + width: 48rpx;
  273 + }
226 274
227 - /* 统计卡片 */  
228 - .stats-row { 275 + .badge {
  276 + position: absolute;
  277 + top: -8rpx;
  278 + left: 30rpx;
  279 + background-color: #ff3b30;
  280 + color: #fff;
  281 + font-size: 20rpx;
  282 + height: 32rpx;
  283 + min-width: 32rpx;
  284 + padding: 0 8rpx;
  285 + border-radius: 16rpx;
229 display: flex; 286 display: flex;
230 - gap: 26rpx;  
231 - padding-top: 20rpx; 287 + align-items: center;
  288 + justify-content: center;
  289 + }
  290 +}
232 291
233 - .stat-card {  
234 - flex: 1;  
235 - height: 168rpx;  
236 - position: relative;  
237 - overflow: hidden;  
238 - border-radius: 16rpx;  
239 - }  
240 292
241 - .card-bg {  
242 - position: absolute;  
243 - left: 0;  
244 - top: 0;  
245 - width: 100%;  
246 - height: 100%;  
247 - } 293 +/* 统计卡片 */
  294 +.stats-row {
  295 + display: flex;
  296 + gap: 26rpx;
  297 + padding-top: 20rpx;
248 298
249 - .card-content {  
250 - position: absolute;  
251 - left: 32rpx;  
252 - top: 36rpx;  
253 - display: flex;  
254 - flex-direction: column;  
255 - gap: 12rpx;  
256 - } 299 + .stat-card {
  300 + flex: 1;
  301 + height: 168rpx;
  302 + position: relative;
  303 + overflow: hidden;
  304 + border-radius: 16rpx;
  305 + }
257 306
258 - .card-title {  
259 - color: rgba(0, 0, 0, 0.9);  
260 - font-size: 32rpx;  
261 - line-height: 44rpx;  
262 - } 307 + .card-bg {
  308 + position: absolute;
  309 + left: 0;
  310 + top: 0;
  311 + width: 100%;
  312 + height: 100%;
  313 + }
263 314
264 - .card-num {  
265 - color: rgba(0, 0, 0, 0.4);  
266 - font-size: 32rpx;  
267 - font-weight: 600;  
268 - line-height: 44rpx;  
269 - } 315 + .card-content {
  316 + position: absolute;
  317 + left: 32rpx;
  318 + top: 36rpx;
  319 + display: flex;
  320 + flex-direction: column;
  321 + gap: 12rpx;
  322 + }
  323 +
  324 + .card-title {
  325 + color: rgba(0, 0, 0, 0.9);
  326 + font-size: 32rpx;
  327 + line-height: 44rpx;
270 } 328 }
271 329
  330 + .card-num {
  331 + color: rgba(0, 0, 0, 0.4);
  332 + font-size: 32rpx;
  333 + font-weight: 600;
  334 + line-height: 44rpx;
  335 + }
  336 +}
272 337
273 - /* 分组入口 */  
274 - .section {  
275 - margin-top: 32rpx;  
276 338
277 - .section-title {  
278 - font-size: 32rpx;  
279 - font-weight: 600;  
280 - color: rgba(0, 0, 0, 0.9);  
281 - line-height: 44rpx;  
282 - } 339 +/* 分组入口 */
  340 +.section {
  341 + margin-top: 32rpx;
283 342
284 - .grid {  
285 - margin-top: 28rpx;  
286 - display: grid;  
287 - grid-template-columns: repeat(4, 1fr);  
288 - gap: 32rpx;  
289 - } 343 + .section-title {
  344 + font-size: 32rpx;
  345 + font-weight: 600;
  346 + color: rgba(0, 0, 0, 0.9);
  347 + line-height: 44rpx;
  348 + }
290 349
291 - .grid-item {  
292 - display: flex;  
293 - flex-direction: column;  
294 - align-items: center;  
295 - } 350 + .grid {
  351 + margin-top: 28rpx;
  352 + display: grid;
  353 + grid-template-columns: repeat(4, 1fr);
  354 + gap: 32rpx;
  355 + }
296 356
297 - .grid-icon {  
298 - width: 96rpx;  
299 - height: 96rpx;  
300 - border-radius: 24rpx;  
301 - } 357 + .grid-item {
  358 + display: flex;
  359 + flex-direction: column;
  360 + align-items: center;
  361 + }
302 362
303 - .grid-text {  
304 - margin-top: 16rpx;  
305 - font-size: 24rpx;  
306 - color: rgba(0, 0, 0, 0.6);  
307 - text-align: center;  
308 - } 363 + .grid-icon {
  364 + width: 96rpx;
  365 + height: 96rpx;
  366 + border-radius: 24rpx;
  367 + }
309 368
  369 + .grid-text {
  370 + margin-top: 16rpx;
  371 + font-size: 24rpx;
  372 + color: rgba(0, 0, 0, 0.6);
  373 + text-align: center;
310 } 374 }
  375 +
  376 +}
311 </style> 377 </style>