inleft
2022-08-26 4adb0063ef324e235218cc73eea63e39a6e8e59f
commit | author | age
9bcb19 1 <template>
I 2
3   <a-modal
4     title="编辑菜单"
5     :width="1000"
6     :visible="visible"
7     :confirmLoading="confirmLoading"
8     @ok="handleSubmit"
9     @cancel="handleCancel"
10     :destroyOnClose="true"
11   >
12     <a-spin :spinning="formLoading">
13       <a-form :form="form" >
14
15         <a-form-item v-show="false" >
16           <a-input v-decorator="['id']" />
17         </a-form-item>
18
19         <a-row :gutter="24">
20           <a-col :md="12" :sm="24">
21             <a-form-item
22               label="菜单名称"
23               :labelCol="labelCol"
24               :wrapperCol="wrapperCol"
25               hasFeedback
26             >
27               <a-input placeholder="请输入菜单名称" v-decorator="['name',{rules: [{required: true, min: 1, message: '请输入菜单名称!'}]}]" />
28             </a-form-item>
29           </a-col>
30           <a-col :md="12" :sm="24">
31             <a-form-item
32               style="width: 100%"
33               :labelCol="labelCol"
34               :wrapperCol="wrapperCol"
35               label="菜单编号"
36               hasFeedback
37             >
38               <a-input placeholder="请输入菜单编号" v-decorator="['code', {rules: [{required: true, min: 1, message: '请输入菜单编号!'}]}]" />
39             </a-form-item>
40           </a-col>
41         </a-row>
42
43         <a-row :gutter="24">
44           <a-col :md="12" :sm="24">
45             <a-form-item
46               :labelCol="labelCol"
47               :wrapperCol="wrapperCol"
48               label="所属应用"
49               has-feedback
50             >
51               <a-select style="width: 100%" :disabled="appDisabled" placeholder="请选择应用分类" v-decorator="['application', {rules: [{ required: true, message: '请选择应用分类!' }]}]" >
52                 <a-select-option v-for="(item,index) in appData" :key="index" :value="item.code" @click="changeApplication(item.code)">{{ item.name }}</a-select-option>
53               </a-select>
54             </a-form-item>
55           </a-col>
56           <a-col :md="12" :sm="24">
57             <a-form-item
58               :labelCol="labelCol"
59               :wrapperCol="wrapperCol"
60               label="菜单层级"
61             >
62               <a-radio-group v-decorator="['type',{rules: [{ required: true, message: '请选择菜单层级!' }]}]" >
63                 <a-radio v-for="(item,index) in typeData" :key="index" :value="item.code" @click="meneTypeFunc(item.code)">{{ item.value }}</a-radio>
64               </a-radio-group>
65             </a-form-item>
66           </a-col>
67         </a-row>
68
69         <a-row :gutter="24">
70           <a-col :md="12" :sm="24">
71             <div v-show="pidShow">
72               <a-form-item
73                 :labelCol="labelCol"
74                 :wrapperCol="wrapperCol"
75                 label="父级菜单"
76                 has-feedback
77               >
78                 <a-tree-select
79                   v-decorator="['pid', {rules: [{ required: true, message: '请选择父级菜单!' }]}]"
80                   style="width: 100%"
81                   :dropdownStyle="{ maxHeight: '300px', overflow: 'auto' }"
82                   :treeData="menuTreeData"
83                   placeholder="请选择父级菜单"
84                   treeDefaultExpandAll
85                   @change="setPid"
86                 >
87                   <span slot="title" slot-scope="{ id }">{{ id }}
88                   </span>
89                 </a-tree-select>
90               </a-form-item>
91             </div>
92             <div v-show="redirectShow">
93               <a-form-item
94                 :labelCol="labelCol"
95                 :wrapperCol="wrapperCol"
96               >
97                 <span slot="label">
98                   <a-tooltip title="如需打开首页加载此目录下菜单,请填写加载菜单路由,设为首页后其他设置的主页将被替代">
99                     <a-icon type="question-circle-o" />
100                   </a-tooltip>&nbsp;
101                   重定向
102                 </span>
103                 <a-input prop="redirect" placeholder="请输入重定向地址" v-decorator="['redirect']" />
104               </a-form-item>
105             </div>
106           </a-col>
107           <a-col :md="12" :sm="24">
108             <a-form-item
109               :labelCol="labelCol"
110               :wrapperCol="wrapperCol"
111             >
112               <span slot="label">
113                 <a-tooltip title="按钮:无,菜单:内链、外链、组件">
114                   <a-icon type="question-circle-o" />
115                 </a-tooltip>&nbsp;
116                 打开方式
117               </span>
118               <a-radio-group :disabled="openTypeDisabled" v-decorator="['openType',{rules: [{ required: true, message: '请选择打开方式!' }]}]">
119                 <a-radio v-for="(item,index) in openTypeData" :key="index" :value="item.code" @click="meneOpenTypeFunc(item.code)">{{ item.value }}</a-radio>
120               </a-radio-group>
121             </a-form-item>
122
123           </a-col>
124         </a-row>
125
126         <a-divider />
127
128         <a-row :gutter="24" >
129           <a-col :md="12" :sm="24">
130             <div v-show="componentShow">
131               <a-form-item
132                 :labelCol="labelCol"
133                 :wrapperCol="wrapperCol"
134                 hasFeedback
135               >
136                 <span slot="label">
137                   <a-tooltip title="前端vue组件 views文件夹下路径,例:system/menu/index。注:目录级填写:RouteView(不带面包屑),PageView(带面包屑),菜单级内链打开http链接填写:Iframe">
138                     <a-icon type="question-circle-o" />
139                   </a-tooltip>&nbsp;
140                   前端组件
141                 </span>
142                 <a-input placeholder="请输入前端组件" :disabled="componentDisabled" prop="component" v-decorator="['component',{rules: [{required: componentRequired, message: '请输入前端组件'}]}]"/>
143               </a-form-item>
144             </div>
145           </a-col>
146           <a-col :md="12" :sm="24">
147             <div v-show="routerShow">
148               <a-form-item
149                 :labelCol="labelCol"
150                 :wrapperCol="wrapperCol"
151                 hasFeedback
152               >
153                 <span slot="label">
154                   <a-tooltip title="浏览器显示的URL,例:/menu,对应打开页面为菜单页面">
155                     <a-icon type="question-circle-o" />
156                   </a-tooltip>&nbsp;
157                   路由地址
158                 </span>
159                 <a-input placeholder="请输入路由" v-decorator="['router', {rules: [{required: routerRequired, message: '请输入路由!'}]}]" />
160               </a-form-item>
161             </div>
162             <div v-show="permissionShow">
163               <a-form-item
164                 :labelCol="labelCol"
165                 :wrapperCol="wrapperCol"
166                 label="权限标识"
167                 hasFeedback
168               >
169                 <a-input placeholder="请输入权限标识" v-decorator="['permission', {rules: [{required: permissionRequired, message: '请输入权限标识!'}]}]" />
170               </a-form-item>
171             </div>
172           </a-col>
173         </a-row>
174
175         <a-row :gutter="24">
176           <a-col :md="12" :sm="24">
177             <div v-show="linkShow" >
178               <a-form-item
179                 :labelCol="labelCol"
180                 :wrapperCol="wrapperCol"
181                 hasFeedback
182               >
183                 <span slot="label">
184                   <a-tooltip title="当选择了需要内链或外链打开的选项,此处输入要打开的链接地址,例:https://www.xiaonuo.vip">
185                     <a-icon type="question-circle-o" />
186                   </a-tooltip>&nbsp;
187                   内外链地址
188                 </span>
189                 <a-input placeholder="请输入内链打开地址" :disabled="linkDisabled" v-decorator="['link', {rules: [{required: linkRequired, message: '请输入权限标识!'}]}]" />
190               </a-form-item>
191             </div>
192           </a-col>
193           <a-col :md="12" :sm="24">
194             <div v-show="iconShow" >
195               <a-form-item
196                 :labelCol="labelCol"
197                 :wrapperCol="wrapperCol"
198                 label="图标"
199               >
200                 <a-input placeholder="请选择图标" disabled="disabled" v-decorator="['icon']" >
201                   <a-icon slot="addonAfter" @click="openIconSele()" type="setting" />
202                 </a-input>
203               </a-form-item>
204             </div>
205           </a-col>
206         </a-row>
207
208         <a-row :gutter="24">
209           <a-col :md="12" :sm="24">
210             <a-form-item
211               :labelCol="labelCol"
212               :wrapperCol="wrapperCol"
213             >
214               <span slot="label">
215                 <a-tooltip title="系统权重:菜单可分配给任何角色,业务权重:菜单对超级管理员不可见">
216                   <a-icon type="question-circle-o" />
217                 </a-tooltip>&nbsp;
218                 权重
219               </span>
220               <a-radio-group v-decorator="['weight']">
221                 <a-radio v-for="(item,index) in weightData" :key="index" :value="item.code" >{{ item.value }}</a-radio>
222               </a-radio-group>
223             </a-form-item>
224           </a-col>
225           <a-col :md="12" :sm="24">
226             <a-form-item
227               :labelCol="labelCol"
228               :wrapperCol="wrapperCol"
229               label="是否可见"
230             >
231               <a-switch id="visible" checkedChildren="是" unCheckedChildren="否" v-decorator="['visible', { valuePropName: 'checked' }]"/>
232             </a-form-item>
233           </a-col>
234         </a-row>
235
236         <a-row :gutter="24">
237           <a-col :md="12" :sm="24">
238             <a-form-item
239               :labelCol="labelCol"
240               :wrapperCol="wrapperCol"
241               label="排序"
242             >
243               <a-input-number style="width: 100%" v-decorator="['sort', { initialValue: 100 }]" :min="1" :max="1000" />
244             </a-form-item>
245           </a-col>
246           <a-col :md="12" :sm="24">
247             <a-form-item
248               :labelCol="labelCol"
249               :wrapperCol="wrapperCol"
250               label="备注"
251               hasFeedback
252             >
253               <a-input placeholder="请输入备注" v-decorator="['remark']"></a-input>
254             </a-form-item>
255           </a-col>
256         </a-row>
257
258       </a-form>
259     </a-spin>
260     <a-modal
261       :width="850"
262       :visible="visibleIcon"
263       @cancel="handleCancelIcon"
264       footer=""
265       :mask="false"
266       :closable="false"
267       :destroyOnClose="true"
268     >
269       <icon-selector v-model="currentSelectedIcon" @change="handleIconChange"/>
270     </a-modal>
271   </a-modal>
272 </template>
273
274 <script>
275   import { getAppList } from '@/api/modular/system/appManage'
276   import { getMenuTree, sysMenuEdit } from '@/api/modular/system/menuManage'
277   import IconSelector from '@/components/IconSelector'
278   import { sysDictTypeDropDown } from '@/api/modular/system/dictManage'
279   export default {
280     name: 'MenuEdit',
281     components: { IconSelector },
282
283     data () {
284       return {
285         labelCol: {
286           xs: { span: 24 },
287           sm: { span: 6 }
288         },
289         wrapperCol: {
290           xs: { span: 24 },
291           sm: { span: 16 }
292         },
293         visibleIcon: false,
294         visible: false,
295         confirmLoading: false,
296         appData: [],
297         menuTreeData: [],
298         redirectShow: true,
299         componentShow: true,
300         componentDisabled: false,
301         componentRequired: true,
302         routerRequired: true,
303         routerShow: true,
304         iconShow: true,
305         openTypeShow: true,
306         pidShow: true,
307         permissionShow: true,
308         permissionRequired: true,
309         // 图标组件
310         currentSelectedIcon: 'pause-circle',
311         typeData: [],
312         openTypeData: [],
313         weightData: [],
314         formLoading: true,
315         linkShow: true,
316         openTypeDisabled: false,
317         openTypeDefault: [],
318         openType: '',
319         linkRequired: true,
320         linkDisabled: false,
321         type: '',
322         pid: '',
323         appDisabled: false,
324         form: this.$form.createForm(this)
325       }
326     },
327
328     watch: {
329       pid (val) {
330         if (val === '0') {
331            // 再不能切换应用
332           this.appDisabled = false
333         } else {
334           this.appDisabled = true
335         }
336       }
337     },
338
339     methods: {
340       // 打开页面初始化
341       edit (record) {
342         this.visible = true
343         // 获取系统应用列表
344         this.getSysApplist()
345         this.sysDictTypeDropDown()
346
347         // 图标
348         this.currentSelectedIcon = record.icon
349         // 默认选中菜单项,并初始化
350         this.form.getFieldDecorator('type', { valuePropName: 'checked', initialValue: record.type.toString() })
351         this.meneTypeFunc(record.type.toString(), record.openType.toString())
352
353         // 默认选中的单选框
354         // eslint-disable-next-line no-unused-vars
355         const visibleDef = false
356         // eslint-disable-next-line eqeqeq
357         if (record.visible == 'Y') {
358           this.visibleDef = true
359         }
360         this.form.getFieldDecorator('weight', { valuePropName: 'checked', initialValue: record.weight.toString() })
361         this.form.getFieldDecorator('visible', { valuePropName: 'checked', initialValue: this.visibleDef })
362         this.form.getFieldDecorator('icon', { initialValue: record.icon })
363         setTimeout(() => {
364            this.setMenuItem(record)
365           this.changeApplication(record.application)
366         }, 100)
367       },
368
369       setMenuItem (record) {
370         this.form.setFieldsValue(
371           {
372             id: record.id,
373             name: record.name,
374             code: record.code,
375             application: record.application,
376             redirect: record.redirect,
377             component: record.component,
378             permission: record.permission,
379             link: record.link,
380             router: record.router,
381             sort: record.sort,
382             remark: record.remark
383           }
384         )
385         this.form.getFieldDecorator('pid', { initialValue: record.pid })
386         this.pid = record.pid
387       },
388
389       /**
390        * 获取字典数据
391        */
392       sysDictTypeDropDown () {
393         this.formLoading = true
394         // 菜单类型
395         sysDictTypeDropDown({ code: 'menu_type' }).then((res) => {
396           this.typeData = res.data
397         })
398         // 权重
399         sysDictTypeDropDown({ code: 'menu_weight' }).then((res) => {
400           this.weightData = res.data
401         })
402         // 内外链
403         sysDictTypeDropDown({ code: 'open_type' }).then((res) => {
404           this.openTypeData = res.data
405           this.formLoading = false
406         })
407       },
408
409       /**
410        * 选择父级
411        */
412       setPid (value) {
413         this.pid = value
414       },
415
416       getSysApplist () {
417         return getAppList().then((res) => {
418           if (res.success) {
419             this.appData = res.data
420           } else {
421             this.$message.warning(res.message)
422           }
423         })
424       },
425       changeApplication (value) {
426         getMenuTree({ 'application': value }).then((res) => {
427           if (res.success) {
428             this.form.resetFields(`pid`, [])
429             this.menuTreeData = [{
430               'id': '-1',
431               'parentId': '0',
432               'title': '顶级',
433               'value': '0',
434               'pid': '0',
435               'children': res.data
436             }]
437           } else {
438             this.$message.warning(res.message)
439           }
440         })
441       },
442
443       /**
444        * 选择菜单类型执行初始化表单变量
445        */
446       meneTypeFunc (type, openType) {
447         this.type = type
448         // eslint-disable-next-line eqeqeq
449         if (type == '0' || type == '1') {
450           // 内外链地址显示,给空值
451           this.linkShow = true
452           this.form.resetFields(`link`, [])
453           // 图标选择显示
454           this.iconShow = true
455           // 路由必填,设置空值,并显示
456           this.routerRequired = true
457           this.form.getFieldDecorator('router', { initialValue: '' })
458           this.routerShow = true
459           // 权限标识框隐藏,选填,给空值
460           this.permissionShow = false
461           this.permissionRequired = false
462           this.form.getFieldDecorator('permission', { initialValue: '' })
463           // 打开方式设置为组件 ,禁用选择方式
464           this.openType = openType
465           this.form.getFieldDecorator('openType', { initialValue: this.openType })
466           this.openTypeDisabled = false
467         }
468         // eslint-disable-next-line eqeqeq
469         if (type == '0') {
470           // 重定向展示,并给空
471           this.redirectShow = true
472           this.form.resetFields(`redirect`, [])
473           // 组件默认为显示,设置可输入,给默认组件 PageView,验证必填
474           this.componentShow = true
475           this.componentDisabled = false
476           this.form.getFieldDecorator('component', { initialValue: 'PageView' })
477           this.componentRequired = true
478           // 父级初始化顶级,并将其隐藏
479           this.form.getFieldDecorator('pid', { initialValue: '0' })
480           this.pid = '0'
481           this.pidShow = false
482         } else {
483           // eslint-disable-next-line eqeqeq
484           if (type == '1') {
485             // 组件可以手输,取消值
486             this.componentDisabled = false
487             this.form.getFieldDecorator('component', { initialValue: '' })
488           }
489           // 重定向输入隐藏,并给空值
490           this.redirectShow = false
491           this.form.getFieldDecorator('redirect', { initialValue: '' })
492           // 父级选择放开
493           this.pidShow = true
494         }
495         // eslint-disable-next-line eqeqeq
496         if (type == '2') {
497           // 组件设置不填,不可输入,并给空(手输的跟设置的)
498           this.componentRequired = false
499           this.componentDisabled = true
500           this.form.resetFields(`component`, [])
501           this.form.getFieldDecorator('component', { initialValue: '' })
502           // 路由选填,设置空值,并隐藏
503           this.routerRequired = true
504           this.form.getFieldDecorator('router', { initialValue: '' })
505           this.routerShow = false
506           // 内外链地址隐藏,给空值
507           this.linkShow = false
508           this.form.getFieldDecorator('link', { initialValue: '' })
509           // 权限标识框显示,必填,给空值
510           this.permissionShow = true
511           this.permissionRequired = true
512           this.form.getFieldDecorator('permission', { initialValue: '' })
513           // 图标选择隐藏,并给空
514           this.iconShow = false
515           this.form.getFieldDecorator('icon', { initialValue: '' })
516           // 打开方式设置为无 ,禁用选择方式
517           this.openType = '0'
518           this.form.getFieldDecorator('openType', { initialValue: this.openType })
519           this.openTypeDisabled = true
520           // 取消icon
521           this.form.getFieldDecorator('icon', { initialValue: '' })
522         }
523         this.meneOpenTypeFunc(this.openType)
524       },
525
526       /**
527        * 选择打开方式执行方法
528        */
529       meneOpenTypeFunc (openType) {
530         this.form.resetFields(`openType`, openType)
531         // eslint-disable-next-line eqeqeq
532         if (openType == '2' || openType == '3') {
533           // 点击内外链的时候保留原值,其他清空
534           if (this.linkDisabled === false) {
535             this.form.resetFields(`link`, [])
536           }
537           // 设置内外链可手输,加验证
538           this.linkDisabled = false
539           this.linkRequired = true
540         } else {
541           // 设置内外链不可手输,取消值,取消验证
542           this.linkDisabled = true
543           this.form.resetFields(`link`, [])
544           this.linkRequired = false
545         }
546         // 另起一个分支
547         // eslint-disable-next-line eqeqeq
548         if (openType == '3') {
549           this.componentRequired = false
550           this.componentDisabled = true
551           this.form.resetFields(`component`, [])
552           this.form.getFieldDecorator('component', { initialValue: '' })
553         } else {
554           this.componentRequired = true
555           // eslint-disable-next-line eqeqeq
556           if (this.type == '1' || this.type == '2') {
557             this.form.getFieldDecorator('component', { initialValue: '' })
558           } else {
559             this.form.resetFields(`component`, [])
560             this.form.getFieldDecorator('component', { initialValue: 'PageView' })
561           }
562           // eslint-disable-next-line eqeqeq
563           if (openType == '2') {
564             // 组件设置为 iframe
565             this.form.resetFields(`component`, [])
566             this.form.getFieldDecorator('component', { initialValue: 'Iframe' })
567           }
568         }
569         // eslint-disable-next-line eqeqeq
570         if (this.type == '2') {
571           // eslint-disable-next-line eqeqeq
572           if (openType == '0') {
573             this.componentRequired = false
574             this.routerRequired = false
575           }
576         }
577       },
578
579       openIconSele () {
580         this.visibleIcon = true
581       },
582       handleIconChange (icon) {
583         // console.log('新图标:'+icon)
584         this.form.getFieldDecorator('icon', { initialValue: icon })
585         // this.form.resetFields(`icon`,icon);
586
587         this.visibleIcon = false
588       },
589       handleCancelIcon () {
590         this.visibleIcon = false
591       },
592       handleSubmit () {
593         const { form: { validateFields } } = this
594         this.confirmLoading = true
595         validateFields((errors, values) => {
596           if (!errors) {
597             if (values.visible) {
598               values.visible = 'Y'
599             } else {
600               values.visible = 'N'
601             }
602             sysMenuEdit(values).then((res) => {
603               this.confirmLoading = false
604               if (res.success) {
605                 this.$message.success('编辑成功')
606                 this.$emit('ok', values)
607                 this.handleCancel()
608               } else {
609                 this.$message.error('编辑失败:' + res.message)
610               }
611             }).finally((res) => {
612               this.confirmLoading = false
613             })
614           } else {
615             this.confirmLoading = false
616           }
617         })
618       },
619       handleCancel () {
620         this.form.resetFields()
621         this.confirmLoading = false
622         this.visible = false
623       }
624     }
625
626   }
627 </script>