houzhongjian
2024-11-27 fd13b0017518273406ee1a9906c07d079e4a9ac4
提交 | 用户 | 时间
820397 1 <template>
H 2   <Dialog v-model="dialogVisible" :title="dialogTitle">
3     <el-form
4       ref="formRef"
5       v-loading="formLoading"
6       :model="formData"
7       :rules="formRules"
8       label-width="80px"
9     >
10       <el-form-item label="套餐名" prop="name">
11         <el-input v-model="formData.name" placeholder="请输入套餐名" />
12       </el-form-item>
94d91d 13       <el-form-item label="套餐介绍" prop="description">
H 14         <el-input type="textarea" v-model="formData.description" placeholder="请输入套餐介绍" />
15       </el-form-item>
16       <el-form-item label="套餐图标">
17         <UploadImg v-model="formData.icon" :limit="1" />
18       </el-form-item>
820397 19       <el-form-item label="菜单权限">
H 20         <el-card class="cardHeight">
21           <template #header>
22             全选/全不选:
23             <el-switch
24               v-model="treeNodeAll"
25               active-text="是"
26               inactive-text="否"
27               inline-prompt
28               @change="handleCheckedTreeNodeAll"
29             />
30             全部展开/折叠:
31             <el-switch
32               v-model="menuExpand"
33               active-text="展开"
34               inactive-text="折叠"
35               inline-prompt
36               @change="handleCheckedTreeExpand"
37             />
38           </template>
39           <el-tree
40             ref="treeRef"
41             :data="menuOptions"
42             :props="defaultProps"
43             empty-text="加载中,请稍候"
44             node-key="id"
45             show-checkbox
46           />
47         </el-card>
94d91d 48       </el-form-item>
H 49       <el-form-item label="套餐标签" prop="labels">
50         <el-select
51           v-model="formData.labels"
52           filterable
53           multiple
54           allow-create
55           placeholder="请输入套餐标签"
56           style="width: 500px"
57         >
58           <el-option v-for="label in formData.labels" :key="label" :label="label" :value="label" />
59         </el-select>
820397 60       </el-form-item>
H 61       <el-form-item label="状态" prop="status">
62         <el-radio-group v-model="formData.status">
63           <el-radio
64             v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
65             :key="dict.value"
66             :label="dict.value"
67           >
68             {{ dict.label }}
69           </el-radio>
70         </el-radio-group>
71       </el-form-item>
72       <el-form-item label="备注" prop="remark">
73         <el-input v-model="formData.remark" placeholder="请输入备注" />
74       </el-form-item>
75     </el-form>
76     <template #footer>
77       <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
78       <el-button @click="dialogVisible = false">取 消</el-button>
79     </template>
80   </Dialog>
81 </template>
82 <script lang="ts" setup>
83 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
84 import { CommonStatusEnum } from '@/utils/constants'
85 import { defaultProps, handleTree } from '@/utils/tree'
86 import * as TenantPackageApi from '@/api/system/tenantPackage'
87 import * as MenuApi from '@/api/system/menu'
88 import { ElTree } from 'element-plus'
89
90 defineOptions({ name: 'SystemTenantPackageForm' })
91
92 const { t } = useI18n() // 国际化
93 const message = useMessage() // 消息弹窗
94
95 const dialogVisible = ref(false) // 弹窗的是否展示
96 const dialogTitle = ref('') // 弹窗的标题
97 const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
98 const formType = ref('') // 表单的类型:create - 新增;update - 修改
99 const formData = ref({
100   id: null,
101   name: null,
94d91d 102   icon: undefined,
H 103   labels: [],
104   description: null,
820397 105   remark: null,
H 106   menuIds: [],
107   status: CommonStatusEnum.ENABLE
108 })
109 const formRules = reactive({
110   name: [{ required: true, message: '套餐名不能为空', trigger: 'blur' }],
111   status: [{ required: true, message: '状态不能为空', trigger: 'blur' }],
112   menuIds: [{ required: true, message: '关联的菜单编号不能为空', trigger: 'blur' }]
113 })
114 const formRef = ref() // 表单 Ref
115 const menuOptions = ref<any[]>([]) // 树形结构数据
116 const menuExpand = ref(false) // 展开/折叠
117 const treeRef = ref<InstanceType<typeof ElTree>>() // 树组件 Ref
118 const treeNodeAll = ref(false) // 全选/全不选
119
120 /** 打开弹窗 */
121 const open = async (type: string, id?: number) => {
122   dialogVisible.value = true
123   dialogTitle.value = t('action.' + type)
124   formType.value = type
125   resetForm()
126   // 加载 Menu 列表。注意,必须放在前面,不然下面 setChecked 没数据节点
127   menuOptions.value = handleTree(await MenuApi.getSimpleMenusList())
128   // 修改时,设置数据
129   if (id) {
130     formLoading.value = true
131     try {
132       const res = await TenantPackageApi.getTenantPackage(id)
133       // 设置选中
134       formData.value = res
135       // 设置选中
136       res.menuIds.forEach((menuId: number) => {
137         treeRef.value!.setChecked(menuId, true, false)
138       })
139     } finally {
140       formLoading.value = false
141     }
142   }
143 }
144 defineExpose({ open }) // 提供 open 方法,用于打开弹窗
145
146 /** 提交表单 */
147 const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
148 const submitForm = async () => {
149   // 校验表单
150   if (!formRef) return
151   const valid = await formRef.value.validate()
152   if (!valid) return
153   // 提交请求
154   formLoading.value = true
155   try {
156     const data = formData.value as unknown as TenantPackageApi.TenantPackageVO
157     data.menuIds = [
158       ...(treeRef.value!.getCheckedKeys(false) as unknown as Array<number>), // 获得当前选中节点
159       ...(treeRef.value!.getHalfCheckedKeys() as unknown as Array<number>) // 获得半选中的父节点
160     ]
161     if (formType.value === 'create') {
162       await TenantPackageApi.createTenantPackage(data)
163       message.success(t('common.createSuccess'))
164     } else {
165       await TenantPackageApi.updateTenantPackage(data)
166       message.success(t('common.updateSuccess'))
167     }
168     dialogVisible.value = false
169     // 发送操作成功的事件
170     emit('success')
171   } finally {
172     formLoading.value = false
173   }
174 }
175
176 /** 重置表单 */
177 const resetForm = () => {
178   // 重置选项
179   treeNodeAll.value = false
180   menuExpand.value = false
181   // 重置表单
182   formData.value = {
183     id: null,
184     name: null,
4c081a 185     icon: undefined,
H 186     labels: [],
187     description: null,
820397 188     remark: null,
H 189     menuIds: [],
190     status: CommonStatusEnum.ENABLE
191   }
192   treeRef.value?.setCheckedNodes([])
193   formRef.value?.resetFields()
194 }
195
196 /** 全选/全不选 */
197 const handleCheckedTreeNodeAll = () => {
198   treeRef.value!.setCheckedNodes(treeNodeAll.value ? menuOptions.value : [])
199 }
200
201 /** 展开/折叠全部 */
202 const handleCheckedTreeExpand = () => {
203   const nodes = treeRef.value?.store.nodesMap
204   for (let node in nodes) {
205     if (nodes[node].expanded === menuExpand.value) {
206       continue
207     }
208     nodes[node].expanded = menuExpand.value
209   }
210 }
211 </script>
212 <style lang="scss" scoped>
213 .cardHeight {
214   width: 100%;
215   max-height: 400px;
216   overflow-y: scroll;
217 }
218 </style>