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 39 url: `/selector/city`,
40 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 }
\ No newline at end of file
... ...
... ... @@ -3,7 +3,8 @@
3 3 <!-- 自定义头部 -->
4 4 <view class="custom-header">
5 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 8 <image class="icon" src="/static/images/index/bell.png" mode="widthFix" />
8 9 <view class="badge">99+</view>
9 10 </view>
... ... @@ -13,7 +14,8 @@
13 14 </view>
14 15
15 16 <!-- 顶部统计卡片 -->
16   - <view class="stats-row">
  17 + <!-- name:BpmManage 流程中心权限 -->
  18 + <view class="stats-row" v-if="hasMenu('BpmManage')">
17 19 <view class="stat-card" @click="navigateTo('/pages/flow/approval')">
18 20 <image class="card-bg" src="/static/images/index/card_wait.png" mode="aspectFill" />
19 21 <view class="card-content">
... ... @@ -30,16 +32,17 @@
30 32 </view>
31 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 36 <text class="section-title">{{ it.title }}</text>
35 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 40 <image class="grid-icon" :src="g.icon" />
38 41 <text class="grid-text omit1">{{ g.text }}</text>
39 42 </view>
40 43 </view>
41 44 </view>
42   -
  45 + <!-- todo 后续删掉 -->
43 46 <view class="section">
44 47 <text class="section-title">附件上传</text>
45 48 <view class="upload-row">
... ... @@ -51,261 +54,324 @@
51 54 </template>
52 55
53 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 225 </script>
160 226
161 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 252 display: flex;
175 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 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 377 </style>
\ No newline at end of file
... ...