Showing
3 changed files
with
502 additions
and
479 deletions
... | ... | @@ -14,9 +14,10 @@ |
14 | 14 | </Button> |
15 | 15 | <BasicTree |
16 | 16 | v-if="organizationTreeData.length" |
17 | + :check-strictly="checkStrictly" | |
17 | 18 | v-model:value="model[field]" |
18 | 19 | :treeData="organizationTreeData" |
19 | - :checked-keys="checkGroup" | |
20 | + :checked-keys="checkedKeys" | |
20 | 21 | :expandedKeys="treeExpandData" |
21 | 22 | ref="basicTreeRef" |
22 | 23 | @check="handleCheckClick" |
... | ... | @@ -25,6 +26,7 @@ |
25 | 26 | checkable |
26 | 27 | toolbar |
27 | 28 | @change="handleTreeSelect" |
29 | + :replace-fields="{ children: 'children', title: 'name', key: 'id' }" | |
28 | 30 | /> |
29 | 31 | </template> |
30 | 32 | <template #roleSlot="{ model, field }"> |
... | ... | @@ -53,8 +55,8 @@ |
53 | 55 | </BasicModal> |
54 | 56 | <RoleDrawer @register="registerRoleDrawer" @success="handleSuccess" /> |
55 | 57 | </template> |
56 | -<script lang="ts"> | |
57 | - import { defineComponent, ref, computed, unref, reactive, onMounted } from 'vue'; | |
58 | +<script lang="ts" setup> | |
59 | + import { ref, computed, unref, reactive, onMounted, toRaw } from 'vue'; | |
58 | 60 | import { BasicModal, useModalInner } from '/@/components/Modal'; |
59 | 61 | import { BasicForm, useForm } from '/@/components/Form/index'; |
60 | 62 | import { accountFormSchema } from './account.data'; |
... | ... | @@ -64,262 +66,264 @@ |
64 | 66 | SaveOrUpdateUserInfo, |
65 | 67 | filterRoleList, |
66 | 68 | } from '/@/api/system/system'; |
67 | - import { BasicTree, TreeItem, CheckKeys, CheckEvent } from '/@/components/Tree'; | |
69 | + import { BasicTree, TreeItem, CheckKeys } from '/@/components/Tree'; | |
68 | 70 | import { findCurrentUserGroups } from '/@/api/system/group'; |
69 | 71 | import { RoleOrOrganizationParam } from '/@/api/system/model/systemModel'; |
70 | 72 | import { useMessage } from '/@/hooks/web/useMessage'; |
71 | - import { copyTransTreeFun } from '/@/utils/fnUtils'; | |
72 | 73 | import { TOption } from '/@/views/rule/linkedge/config/config.data'; |
73 | 74 | import { PlusOutlined } from '@ant-design/icons-vue'; |
74 | 75 | import { useDrawer } from '/@/components/Drawer'; |
75 | 76 | import RoleDrawer from '../../role/CustomRoleDrawer.vue'; |
76 | 77 | import OrganizationDrawer from '/@/views/system/organization/OrganizationDrawer.vue'; |
78 | + import { GroupListResultModel } from '/@/api/system/model/groupModel'; | |
79 | + import { isArray } from '/@/utils/is'; | |
77 | 80 | |
78 | - export default defineComponent({ | |
79 | - name: 'AccountModal', | |
80 | - components: { | |
81 | - BasicModal, | |
82 | - BasicForm, | |
83 | - Button, | |
84 | - BasicTree, | |
85 | - OrganizationDrawer, | |
86 | - PlusOutlined, | |
87 | - RoleDrawer, | |
88 | - VNodes: (_, { attrs }) => { | |
89 | - return attrs.vnodes; | |
90 | - }, | |
91 | - }, | |
92 | - emits: ['success', 'register'], | |
93 | - setup(_, { emit }) { | |
94 | - const roleOptions = ref<TOption[]>([]); | |
95 | - const isUpdate = ref(true); | |
96 | - const rowId = ref(''); | |
97 | - const organizationTreeData = ref<TreeItem[]>([]); | |
98 | - const basicTreeRef = ref(); | |
99 | - const checkGroup = ref<string[]>([]); | |
100 | - const treeExpandData = ref([]); | |
101 | - const olderPhoneNumber = ref(); | |
102 | - const postData = reactive({}); | |
103 | - const singleEditPostPhoneNumber = reactive({ | |
104 | - phoneNumber: '', | |
105 | - }); | |
106 | - const checkedKeysWithHalfChecked = ref<(string | number)[]>([]); | |
107 | - const getRoleList = async () => { | |
108 | - const res = await filterRoleList(); | |
109 | - roleOptions.value = res.map((m) => { | |
110 | - return { | |
111 | - label: m.name, | |
112 | - value: m.id, | |
113 | - }; | |
114 | - }); | |
115 | - }; | |
116 | - onMounted(async () => { | |
117 | - await getRoleList(); | |
118 | - }); | |
119 | - const [registerRoleDrawer, { openDrawer }] = useDrawer(); | |
81 | + const VNodes = (_, { attrs }) => { | |
82 | + return attrs.vnodes; | |
83 | + }; | |
120 | 84 | |
121 | - const handleOpenRole = () => { | |
122 | - openDrawer(true, { | |
123 | - isUpdate: false, | |
124 | - }); | |
125 | - }; | |
126 | - const clearValidateByField = (field: string) => { | |
127 | - clearValidate(field); | |
128 | - }; | |
129 | - const handleRoleSelect = (e) => { | |
130 | - if (e?.length > 0) clearValidateByField('roleIds'); | |
131 | - else validateFields(['roleIds']); | |
132 | - }; | |
133 | - const handleTreeSelect = (e) => { | |
134 | - if (e) clearValidateByField('organizationIds'); | |
135 | - }; | |
136 | - const handleSuccess = async () => { | |
137 | - await getRoleList(); | |
85 | + const emit = defineEmits(['register', 'success']); | |
86 | + | |
87 | + const checkStrictly = ref(true); | |
88 | + const roleOptions = ref<TOption[]>([]); | |
89 | + const isUpdate = ref(true); | |
90 | + const rowId = ref(''); | |
91 | + const organizationTreeData = ref<TreeItem[]>([]); | |
92 | + const basicTreeRef = ref(); | |
93 | + const checkedKeys = reactive<CheckKeys>({ checked: [], halfChecked: [] }); | |
94 | + const treeExpandData = ref([]); | |
95 | + const olderPhoneNumber = ref(); | |
96 | + const postData = reactive({}); | |
97 | + const singleEditPostPhoneNumber = reactive({ | |
98 | + phoneNumber: '', | |
99 | + }); | |
100 | + const checkedKeysWithHalfChecked = ref<(string | number)[]>([]); | |
101 | + const getRoleList = async () => { | |
102 | + const res = await filterRoleList(); | |
103 | + roleOptions.value = res.map((m) => { | |
104 | + return { | |
105 | + label: m.name, | |
106 | + value: m.id, | |
138 | 107 | }; |
139 | - const [ | |
140 | - registerForm, | |
141 | - { | |
142 | - setFieldsValue, | |
143 | - updateSchema, | |
144 | - resetFields, | |
145 | - validate, | |
146 | - getFieldsValue, | |
147 | - clearValidate, | |
148 | - validateFields, | |
149 | - }, | |
150 | - ] = useForm({ | |
151 | - labelWidth: 100, | |
152 | - schemas: accountFormSchema, | |
153 | - showActionButtonGroup: false, | |
154 | - actionColOptions: { | |
155 | - span: 18, | |
156 | - }, | |
108 | + }); | |
109 | + }; | |
110 | + onMounted(async () => { | |
111 | + await getRoleList(); | |
112 | + }); | |
113 | + const [registerRoleDrawer, { openDrawer }] = useDrawer(); | |
114 | + | |
115 | + const handleOpenRole = () => { | |
116 | + openDrawer(true, { | |
117 | + isUpdate: false, | |
118 | + }); | |
119 | + }; | |
120 | + const clearValidateByField = (field: string) => { | |
121 | + clearValidate(field); | |
122 | + }; | |
123 | + const handleRoleSelect = (e) => { | |
124 | + if (e?.length > 0) clearValidateByField('roleIds'); | |
125 | + else validateFields(['roleIds']); | |
126 | + }; | |
127 | + const handleTreeSelect = (e) => { | |
128 | + if (e) clearValidateByField('organizationIds'); | |
129 | + }; | |
130 | + const handleSuccess = async () => { | |
131 | + await getRoleList(); | |
132 | + }; | |
133 | + const [ | |
134 | + registerForm, | |
135 | + { | |
136 | + setFieldsValue, | |
137 | + updateSchema, | |
138 | + resetFields, | |
139 | + validate, | |
140 | + getFieldsValue, | |
141 | + clearValidate, | |
142 | + validateFields, | |
143 | + }, | |
144 | + ] = useForm({ | |
145 | + labelWidth: 100, | |
146 | + schemas: accountFormSchema, | |
147 | + showActionButtonGroup: false, | |
148 | + actionColOptions: { | |
149 | + span: 18, | |
150 | + }, | |
151 | + }); | |
152 | + //获取所有父级id | |
153 | + function findForAllId(data = [], arr = []) { | |
154 | + for (const item of data) { | |
155 | + arr.push(item.id); | |
156 | + } | |
157 | + return arr; | |
158 | + } | |
159 | + | |
160 | + const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => { | |
161 | + checkStrictly.value = true; | |
162 | + await resetFields(); | |
163 | + setModalProps({ confirmLoading: false }); | |
164 | + isUpdate.value = !!data?.isUpdate; | |
165 | + const groupListModel = await findCurrentUserGroups(); | |
166 | + if (!unref(organizationTreeData).length) { | |
167 | + organizationTreeData.value = groupListModel; | |
168 | + buildNodeMap(toRaw(unref(groupListModel))); | |
169 | + const getAllIds = findForAllId(organizationTreeData.value as any, []); | |
170 | + //设置要展开的id | |
171 | + treeExpandData.value = getAllIds; | |
172 | + } | |
173 | + if (unref(isUpdate)) { | |
174 | + rowId.value = data.record.id; | |
175 | + const roleParams = new RoleOrOrganizationParam(rowId.value, true, false); | |
176 | + olderPhoneNumber.value = data.record.phoneNumber; | |
177 | + singleEditPostPhoneNumber.phoneNumber = data.record.phoneNumber; | |
178 | + findCurrentUserRelation(roleParams).then((result) => { | |
179 | + Reflect.set(data.record, 'roleIds', result); | |
180 | + Reflect.set(data.record, 'password', '******'); | |
181 | + setFieldsValue(data.record); | |
157 | 182 | }); |
158 | - //获取所有父级id | |
159 | - function findForAllId(data = [], arr = []) { | |
160 | - for (const item of data) { | |
161 | - arr.push(item.id); | |
162 | - } | |
163 | - return arr; | |
183 | + const organizationParams = new RoleOrOrganizationParam(rowId.value, false, true); | |
184 | + const checked = await findCurrentUserRelation(organizationParams); | |
185 | + const halfChecked = getHalfCheckedNode(checked); | |
186 | + Object.assign(checkedKeys, { checked, halfChecked }); | |
187 | + setFieldsValue({ organizationIds: toRaw(checkedKeys) }); | |
188 | + } | |
189 | + await updateSchema([ | |
190 | + { | |
191 | + field: 'username', | |
192 | + dynamicDisabled: unref(isUpdate), | |
193 | + }, | |
194 | + { | |
195 | + field: 'password', | |
196 | + ifShow: !unref(isUpdate), | |
197 | + }, | |
198 | + ]); | |
199 | + }); | |
200 | + const getTitle = computed(() => (!unref(isUpdate) ? '新增客户账号' : '编辑客户账号')); | |
201 | + | |
202 | + const getFormatValues = (values: Recordable) => { | |
203 | + const organizationIds = values.organizationIds; | |
204 | + if (!organizationIds || isArray(organizationIds)) return values; | |
205 | + | |
206 | + values.organizationIds = values?.organizationIds?.checked; | |
207 | + | |
208 | + return values; | |
209 | + }; | |
210 | + | |
211 | + async function handleSubmit() { | |
212 | + setModalProps({ confirmLoading: true }); | |
213 | + try { | |
214 | + const { createMessage } = useMessage(); | |
215 | + if (unref(isUpdate)) { | |
216 | + Object.assign(postData, singleEditPostPhoneNumber); | |
164 | 217 | } |
218 | + const values = await validate([ | |
219 | + 'id', | |
220 | + 'username', | |
221 | + 'realName', | |
222 | + 'password', | |
223 | + 'roleIds', | |
224 | + 'email', | |
225 | + 'accountExpireTime', | |
226 | + 'enabled', | |
227 | + 'remark', | |
228 | + 'organizationIds', | |
229 | + olderPhoneNumber.value === getFieldsValue().phoneNumber ? '' : 'phoneNumber', | |
230 | + ]); | |
165 | 231 | |
166 | - const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => { | |
167 | - await resetFields(); | |
168 | - setModalProps({ confirmLoading: false }); | |
169 | - isUpdate.value = !!data?.isUpdate; | |
170 | - const groupListModel = await findCurrentUserGroups(); | |
171 | - if (!unref(organizationTreeData).length) { | |
172 | - copyTransTreeFun(groupListModel); | |
173 | - organizationTreeData.value = groupListModel; | |
174 | - const getAllIds = findForAllId(organizationTreeData.value as any, []); | |
175 | - //设置要展开的id | |
176 | - treeExpandData.value = getAllIds; | |
232 | + values.accountExpireTime = | |
233 | + typeof values.accountExpireTime != 'undefined' && values.accountExpireTime != null | |
234 | + ? values.accountExpireTime.format('YYYY-MM-DD HH:mm:ss') | |
235 | + : null; | |
236 | + | |
237 | + Object.assign(postData, getFormatValues(values)); | |
238 | + if (unref(isUpdate)) { | |
239 | + if (values.email == '') { | |
240 | + delete postData.email; | |
177 | 241 | } |
178 | - if (unref(isUpdate)) { | |
179 | - rowId.value = data.record.id; | |
180 | - const roleParams = new RoleOrOrganizationParam(rowId.value, true, false); | |
181 | - olderPhoneNumber.value = data.record.phoneNumber; | |
182 | - singleEditPostPhoneNumber.phoneNumber = data.record.phoneNumber; | |
183 | - findCurrentUserRelation(roleParams).then((result) => { | |
184 | - Reflect.set(data.record, 'roleIds', result); | |
185 | - Reflect.set(data.record, 'password', '******'); | |
186 | - setFieldsValue(data.record); | |
187 | - }); | |
188 | - const organizationParams = new RoleOrOrganizationParam(rowId.value, false, true); | |
189 | - checkGroup.value = await findCurrentUserRelation(organizationParams); | |
242 | + } else { | |
243 | + if (values.email == '') { | |
244 | + delete postData.email; | |
190 | 245 | } |
191 | - await updateSchema([ | |
192 | - { | |
193 | - field: 'username', | |
194 | - dynamicDisabled: unref(isUpdate), | |
195 | - }, | |
196 | - { | |
197 | - field: 'password', | |
198 | - ifShow: !unref(isUpdate), | |
199 | - }, | |
200 | - ]); | |
201 | - }); | |
202 | - const getTitle = computed(() => (!unref(isUpdate) ? '新增客户账号' : '编辑客户账号')); | |
246 | + } | |
247 | + if (!Reflect.get(values, 'accountExpireTime')) { | |
248 | + Reflect.deleteProperty(postData, 'accountExpireTime'); | |
249 | + } | |
250 | + await SaveOrUpdateUserInfo(postData as any, unref(isUpdate)); | |
251 | + closeModal(); | |
252 | + emit('success'); | |
253 | + createMessage.success(unref(isUpdate) ? '编辑成功' : '新增成功'); | |
254 | + } finally { | |
255 | + setTimeout(() => { | |
256 | + setModalProps({ confirmLoading: false }); | |
257 | + }, 300); | |
258 | + } | |
259 | + } | |
260 | + // 取消全部的时候清除回显时获取的 | |
261 | + const handleUnSelectAll = () => { | |
262 | + checkedKeysWithHalfChecked.value = []; | |
263 | + }; | |
264 | + | |
265 | + const strictlyStatus = ref(false); //层级关联或独立的状态 false为层级关联 true为层级独立 | |
203 | 266 | |
204 | - async function handleSubmit() { | |
205 | - setModalProps({ confirmLoading: true }); | |
206 | - try { | |
207 | - const { createMessage } = useMessage(); | |
208 | - if (unref(isUpdate)) { | |
209 | - Object.assign(postData, singleEditPostPhoneNumber); | |
210 | - } | |
211 | - const values = await validate([ | |
212 | - 'id', | |
213 | - 'username', | |
214 | - 'realName', | |
215 | - 'password', | |
216 | - 'roleIds', | |
217 | - 'email', | |
218 | - 'accountExpireTime', | |
219 | - 'enabled', | |
220 | - 'remark', | |
221 | - 'organizationIds', | |
222 | - olderPhoneNumber.value === getFieldsValue().phoneNumber ? '' : 'phoneNumber', | |
223 | - ]); | |
224 | - let treeCheckedKeys: string[] | CheckKeys = | |
225 | - (unref(basicTreeRef)?.getCheckedKeys() as string[] | CheckKeys) || []; | |
226 | - //fix 取消层级独立后(unref(treeRef)?.getCheckedKeys() as string[])的数据不是数组,是{checked:[],halfChecked:[]}对象,迭代报错 | |
227 | - if (!Array.isArray(treeCheckedKeys)) { | |
228 | - treeCheckedKeys = treeCheckedKeys?.checked; | |
229 | - } | |
230 | - const organizationIds = [ | |
231 | - ...new Set([...unref(checkedKeysWithHalfChecked), ...treeCheckedKeys]), | |
232 | - ]; | |
233 | - values.accountExpireTime = | |
234 | - typeof values.accountExpireTime != 'undefined' && values.accountExpireTime != null | |
235 | - ? values.accountExpireTime.format('YYYY-MM-DD HH:mm:ss') | |
236 | - : null; | |
237 | - values.organizationIds = organizationIds; | |
238 | - Object.assign(postData, values); | |
239 | - if (unref(isUpdate)) { | |
240 | - if (values.email == '') { | |
241 | - delete postData.email; | |
242 | - } | |
243 | - } else { | |
244 | - if (values.email == '') { | |
245 | - delete postData.email; | |
246 | - } | |
247 | - } | |
248 | - if (!Reflect.get(values, 'accountExpireTime')) { | |
249 | - Reflect.deleteProperty(postData, 'accountExpireTime'); | |
250 | - } | |
251 | - await SaveOrUpdateUserInfo(postData as any, unref(isUpdate)); | |
252 | - closeModal(); | |
253 | - emit('success'); | |
254 | - createMessage.success(unref(isUpdate) ? '编辑成功' : '新增成功'); | |
255 | - } finally { | |
256 | - setTimeout(() => { | |
257 | - setModalProps({ confirmLoading: false }); | |
258 | - }, 300); | |
267 | + const handleStrictlyStatus = (status) => (strictlyStatus.value = status); | |
268 | + | |
269 | + const handleCheckClick = () => { | |
270 | + if (unref(checkStrictly)) { | |
271 | + checkStrictly.value = false; | |
272 | + } | |
273 | + }; | |
274 | + | |
275 | + const [registerDrawer, { openDrawer: addOpenDrawer }] = useDrawer(); | |
276 | + | |
277 | + const handleOpenCreate = () => { | |
278 | + addOpenDrawer(true, { isUpdate: false }); | |
279 | + }; | |
280 | + const handleReload = async () => { | |
281 | + const groupListModel = await findCurrentUserGroups(); | |
282 | + organizationTreeData.value = groupListModel; | |
283 | + buildNodeMap(toRaw(unref(groupListModel))); | |
284 | + }; | |
285 | + | |
286 | + const treeNodeMap = ref<Record<string, { parentId?: string; children?: string[] }>>(); | |
287 | + | |
288 | + function buildNodeMap(tree: GroupListResultModel) { | |
289 | + const nodeMap: Record<string, { parentId?: string; children?: string[] }> = {}; | |
290 | + | |
291 | + function traverse(tree: GroupListResultModel) { | |
292 | + for (let node of tree) { | |
293 | + Reflect.set(nodeMap, node.id, { | |
294 | + parentId: node.parentId, | |
295 | + children: node.children?.map((item) => item.id), | |
296 | + }); | |
297 | + | |
298 | + if (node.children && node.children.length) { | |
299 | + traverse(node.children); | |
259 | 300 | } |
260 | 301 | } |
261 | - // 取消全部的时候清除回显时获取的 | |
262 | - const handleUnSelectAll = () => { | |
263 | - checkedKeysWithHalfChecked.value = []; | |
264 | - }; | |
302 | + } | |
303 | + traverse(tree); | |
265 | 304 | |
266 | - const strictlyStatus = ref(false); //层级关联或独立的状态 false为层级关联 true为层级独立 | |
305 | + treeNodeMap.value = nodeMap; | |
306 | + } | |
267 | 307 | |
268 | - const handleStrictlyStatus = (status) => (strictlyStatus.value = status); | |
308 | + function getHalfCheckedNode(keys: string[]) { | |
309 | + const relation = unref(treeNodeMap) || {}; | |
310 | + const halfChecked: string[] = []; | |
269 | 311 | |
270 | - const handleCheckClick = (selectedKeys: CheckKeys, event: CheckEvent) => { | |
271 | - //fix 取消层级独立后selectedKeys不是数组,是{checked:[],halfChecked:[]}对象 迭代报错 | |
272 | - // 层级独立 | |
273 | - if (strictlyStatus.value) { | |
274 | - if (!Array.isArray(selectedKeys)) { | |
275 | - selectedKeys = selectedKeys?.checked; | |
276 | - event.halfCheckedKeys = []; | |
277 | - } | |
278 | - } else { | |
279 | - // 层级关联 | |
280 | - event.halfCheckedKeys = []; | |
281 | - } | |
282 | - checkedKeysWithHalfChecked.value = [ | |
283 | - ...selectedKeys, | |
284 | - ...(event.halfCheckedKeys as string[]), | |
285 | - ]; | |
286 | - }; | |
312 | + for (const key of keys) { | |
313 | + let current = relation[key]; | |
287 | 314 | |
288 | - const [registerDrawer, { openDrawer: addOpenDrawer }] = useDrawer(); | |
315 | + while (current) { | |
316 | + if (keys.includes(current.parentId!) || !current.parentId) { | |
317 | + break; | |
318 | + } | |
289 | 319 | |
290 | - const handleOpenCreate = () => { | |
291 | - addOpenDrawer(true, { isUpdate: false }); | |
292 | - }; | |
293 | - const handleReload = async () => { | |
294 | - const groupListModel = await findCurrentUserGroups(); | |
295 | - copyTransTreeFun(groupListModel); | |
296 | - organizationTreeData.value = groupListModel; | |
297 | - }; | |
320 | + halfChecked.push(current.parentId!); | |
321 | + current = relation[current.parentId!]; | |
322 | + } | |
323 | + } | |
298 | 324 | |
299 | - return { | |
300 | - registerModal, | |
301 | - registerForm, | |
302 | - handleSubmit, | |
303 | - getTitle, | |
304 | - organizationTreeData, | |
305 | - checkGroup, | |
306 | - basicTreeRef, | |
307 | - treeExpandData, | |
308 | - roleOptions, | |
309 | - registerRoleDrawer, | |
310 | - handleOpenRole, | |
311 | - handleSuccess, | |
312 | - handleRoleSelect, | |
313 | - handleTreeSelect, | |
314 | - handleCheckClick, | |
315 | - handleUnSelectAll, | |
316 | - handleStrictlyStatus, | |
317 | - handleOpenCreate, | |
318 | - registerDrawer, | |
319 | - handleReload, | |
320 | - }; | |
321 | - }, | |
322 | - }); | |
325 | + return Array.from(new Set(halfChecked)); | |
326 | + } | |
323 | 327 | </script> |
324 | 328 | <style scoped lang="less"> |
325 | 329 | :deep(.vben-basic-tree) { | ... | ... |
... | ... | @@ -14,9 +14,10 @@ |
14 | 14 | </Button> |
15 | 15 | <BasicTree |
16 | 16 | v-if="organizationTreeData.length" |
17 | + :check-strictly="checkStrictly" | |
17 | 18 | v-model:value="model[field]" |
18 | 19 | :treeData="organizationTreeData" |
19 | - :checked-keys="checkGroup" | |
20 | + :checked-keys="checkedKeys" | |
20 | 21 | :expandedKeys="treeExpandData" |
21 | 22 | ref="basicTreeRef" |
22 | 23 | @check="handleCheckClick" |
... | ... | @@ -25,6 +26,7 @@ |
25 | 26 | checkable |
26 | 27 | toolbar |
27 | 28 | @change="handleTreeSelect" |
29 | + :replace-fields="{ children: 'children', title: 'name', key: 'id' }" | |
28 | 30 | /> |
29 | 31 | </template> |
30 | 32 | <template #roleSlot="{ model, field }"> |
... | ... | @@ -53,19 +55,18 @@ |
53 | 55 | </BasicModal> |
54 | 56 | <RoleDrawer @register="registerRoleDrawer" @success="handleSuccess" /> |
55 | 57 | </template> |
56 | -<script lang="ts"> | |
57 | - import { defineComponent, ref, computed, unref, reactive, onMounted } from 'vue'; | |
58 | +<script lang="ts" setup> | |
59 | + import { ref, computed, unref, reactive, onMounted } from 'vue'; | |
58 | 60 | import { BasicModal, useModalInner } from '/@/components/Modal'; |
59 | 61 | import { BasicForm, useForm } from '/@/components/Form/index'; |
60 | 62 | import { accountFormSchema } from './config'; |
61 | 63 | import { Button } from 'ant-design-vue'; |
62 | 64 | import { findCurrentUserRelation, filterRoleList } from '/@/api/system/system'; |
63 | 65 | import { addTenantList } from '/@/api/system/account'; |
64 | - import { BasicTree, TreeItem, CheckKeys, CheckEvent } from '/@/components/Tree'; | |
66 | + import { BasicTree, TreeItem, CheckKeys } from '/@/components/Tree'; | |
65 | 67 | import { findCurrentUserGroups } from '/@/api/system/group'; |
66 | 68 | import { RoleOrOrganizationParam } from '/@/api/system/model/systemModel'; |
67 | 69 | import { useMessage } from '/@/hooks/web/useMessage'; |
68 | - import { copyTransTreeFun } from '/@/utils/fnUtils'; | |
69 | 70 | import { TOption } from '/@/views/rule/linkedge/config/config.data'; |
70 | 71 | import { PlusOutlined } from '@ant-design/icons-vue'; |
71 | 72 | import { useDrawer } from '/@/components/Drawer'; |
... | ... | @@ -74,267 +75,285 @@ |
74 | 75 | import { useUserStore } from '/@/store/modules/user'; |
75 | 76 | import { IsPhoneExist } from '/@/api/system/system'; |
76 | 77 | import { phoneRegexp } from '/@/utils/rules'; |
78 | + import { GroupListResultModel } from '/@/api/system/model/groupModel'; | |
79 | + import { toRaw } from 'vue'; | |
80 | + import { isArray } from '/@/utils/is'; | |
77 | 81 | |
78 | - export default defineComponent({ | |
79 | - name: 'TenantModal', | |
80 | - components: { | |
81 | - BasicModal, | |
82 | - BasicForm, | |
83 | - Button, | |
84 | - BasicTree, | |
85 | - OrganizationDrawer, | |
86 | - PlusOutlined, | |
87 | - RoleDrawer, | |
88 | - VNodes: (_, { attrs }) => { | |
89 | - return attrs.vnodes; | |
90 | - }, | |
91 | - }, | |
92 | - emits: ['success', 'register'], | |
93 | - setup(_, { emit }) { | |
94 | - const [registerRoleDrawer, { openDrawer }] = useDrawer(); | |
95 | - const { createMessage } = useMessage(); | |
96 | - const userInfo = useUserStore(); | |
82 | + const VNodes = (_, { attrs }) => { | |
83 | + return attrs.vnodes; | |
84 | + }; | |
97 | 85 | |
98 | - const roleOptions = ref<TOption[]>([]); | |
99 | - const isAdd = ref(true); | |
100 | - const rowId = ref(''); | |
101 | - const organizationTreeData = ref<TreeItem[]>([]); | |
102 | - const basicTreeRef = ref(); | |
103 | - const checkGroup = ref<string[]>([]); | |
104 | - const treeExpandData = ref([]); | |
105 | - const olderPhoneNumber = ref(); | |
106 | - const singleEditPostPhoneNumber = reactive({ | |
107 | - phoneNumber: '', | |
108 | - }); | |
109 | - const checkedKeysWithHalfChecked = ref<(string | number)[]>([]); | |
110 | - const getRoleList = async () => { | |
111 | - const res = await filterRoleList({ roleType: 'TENANT_ADMIN' }); | |
112 | - roleOptions.value = res.map((m) => { | |
113 | - return { | |
114 | - label: m.name, | |
115 | - value: m.id, | |
116 | - }; | |
117 | - }); | |
118 | - }; | |
86 | + const emit = defineEmits(['register', 'success']); | |
119 | 87 | |
120 | - onMounted(async () => { | |
121 | - await getRoleList(); | |
122 | - }); | |
123 | - const handleOpenRole = () => { | |
124 | - openDrawer(true, { | |
125 | - isAdd: false, | |
126 | - }); | |
127 | - }; | |
128 | - const clearValidateByField = (field: string) => { | |
129 | - clearValidate(field); | |
130 | - }; | |
131 | - const handleRoleSelect = (e) => { | |
132 | - if (e?.length > 0) clearValidateByField('roleIds'); | |
133 | - else validateFields(['roleIds']); | |
134 | - }; | |
135 | - const handleTreeSelect = (e) => { | |
136 | - if (e) clearValidateByField('organizationIds'); | |
137 | - }; | |
138 | - const handleSuccess = async () => { | |
139 | - await getRoleList(); | |
88 | + const [registerRoleDrawer, { openDrawer }] = useDrawer(); | |
89 | + const { createMessage } = useMessage(); | |
90 | + const userInfo = useUserStore(); | |
91 | + | |
92 | + const checkStrictly = ref(true); | |
93 | + | |
94 | + const roleOptions = ref<TOption[]>([]); | |
95 | + const isAdd = ref(true); | |
96 | + const rowId = ref(''); | |
97 | + const organizationTreeData = ref<TreeItem[]>([]); | |
98 | + const basicTreeRef = ref(); | |
99 | + const checkedKeys = reactive<CheckKeys>({ checked: [], halfChecked: [] }); | |
100 | + const treeExpandData = ref([]); | |
101 | + const olderPhoneNumber = ref(); | |
102 | + const singleEditPostPhoneNumber = reactive({ | |
103 | + phoneNumber: '', | |
104 | + }); | |
105 | + const checkedKeysWithHalfChecked = ref<(string | number)[]>([]); | |
106 | + const getRoleList = async () => { | |
107 | + const res = await filterRoleList({ roleType: 'TENANT_ADMIN' }); | |
108 | + roleOptions.value = res.map((m) => { | |
109 | + return { | |
110 | + label: m.name, | |
111 | + value: m.id, | |
140 | 112 | }; |
141 | - const [ | |
142 | - registerForm, | |
143 | - { | |
144 | - setFieldsValue, | |
145 | - updateSchema, | |
146 | - resetFields, | |
147 | - validate, | |
148 | - getFieldsValue, | |
149 | - clearValidate, | |
150 | - validateFields, | |
151 | - }, | |
152 | - ] = useForm({ | |
153 | - labelWidth: 100, | |
154 | - schemas: accountFormSchema, | |
155 | - showActionButtonGroup: false, | |
156 | - actionColOptions: { | |
157 | - span: 18, | |
158 | - }, | |
159 | - }); | |
160 | - //获取所有父级id | |
161 | - function findForAllId(data = [], arr = []) { | |
162 | - for (const item of data) { | |
163 | - arr.push(item.id); | |
164 | - } | |
165 | - return arr; | |
166 | - } | |
113 | + }); | |
114 | + }; | |
167 | 115 | |
168 | - const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => { | |
169 | - await resetFields(); | |
170 | - setModalProps({ confirmLoading: false }); | |
171 | - isAdd.value = !!data?.isAdd; | |
172 | - const groupListModel = await findCurrentUserGroups(); | |
173 | - if (!unref(organizationTreeData).length) { | |
174 | - copyTransTreeFun(groupListModel); | |
175 | - organizationTreeData.value = groupListModel; | |
176 | - const getAllIds = findForAllId(organizationTreeData.value as any, []); | |
177 | - //设置要展开的id | |
178 | - treeExpandData.value = getAllIds; | |
179 | - } | |
116 | + onMounted(async () => { | |
117 | + await getRoleList(); | |
118 | + }); | |
119 | + const handleOpenRole = () => { | |
120 | + openDrawer(true, { | |
121 | + isAdd: false, | |
122 | + }); | |
123 | + }; | |
124 | + const clearValidateByField = (field: string) => { | |
125 | + clearValidate(field); | |
126 | + }; | |
127 | + const handleRoleSelect = (e) => { | |
128 | + if (e?.length > 0) clearValidateByField('roleIds'); | |
129 | + else validateFields(['roleIds']); | |
130 | + }; | |
131 | + const handleTreeSelect = (e) => { | |
132 | + if (e) clearValidateByField('organizationIds'); | |
133 | + }; | |
134 | + const handleSuccess = async () => { | |
135 | + await getRoleList(); | |
136 | + }; | |
137 | + const [ | |
138 | + registerForm, | |
139 | + { | |
140 | + setFieldsValue, | |
141 | + updateSchema, | |
142 | + resetFields, | |
143 | + validate, | |
144 | + getFieldsValue, | |
145 | + clearValidate, | |
146 | + validateFields, | |
147 | + }, | |
148 | + ] = useForm({ | |
149 | + labelWidth: 100, | |
150 | + schemas: accountFormSchema, | |
151 | + showActionButtonGroup: false, | |
152 | + actionColOptions: { | |
153 | + span: 18, | |
154 | + }, | |
155 | + }); | |
156 | + //获取所有父级id | |
157 | + function findForAllId(data = [], arr = []) { | |
158 | + for (const item of data) { | |
159 | + arr.push(item.id); | |
160 | + } | |
161 | + return arr; | |
162 | + } | |
180 | 163 | |
181 | - if (!unref(isAdd)) { | |
182 | - rowId.value = data.record.id; | |
183 | - const roleParams = new RoleOrOrganizationParam(rowId.value, true, false); | |
184 | - olderPhoneNumber.value = data.record.phoneNumber; | |
185 | - singleEditPostPhoneNumber.phoneNumber = data.record.phoneNumber; | |
186 | - findCurrentUserRelation(roleParams).then((result) => { | |
187 | - Reflect.set(data.record, 'roleIds', result); | |
188 | - setFieldsValue(data.record); | |
189 | - }); | |
190 | - updateSchema([ | |
191 | - { | |
192 | - field: 'phoneNumber', | |
193 | - dynamicRules: () => { | |
194 | - return [ | |
195 | - { | |
196 | - required: true, | |
197 | - validator(_, value) { | |
198 | - return new Promise((resolve, reject) => { | |
199 | - if (value == '') { | |
200 | - reject('请输入手机号'); | |
201 | - } else if (!phoneRegexp.test(value)) { | |
202 | - reject('请输入正确的手机号'); | |
203 | - } else { | |
204 | - resolve(); | |
205 | - } | |
206 | - }); | |
207 | - }, | |
208 | - }, | |
209 | - ]; | |
164 | + const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => { | |
165 | + await resetFields(); | |
166 | + checkStrictly.value = true; | |
167 | + setModalProps({ confirmLoading: false }); | |
168 | + isAdd.value = !!data?.isAdd; | |
169 | + const groupListModel = await findCurrentUserGroups(); | |
170 | + if (!unref(organizationTreeData).length) { | |
171 | + organizationTreeData.value = groupListModel; | |
172 | + buildNodeMap(toRaw(unref(organizationTreeData) as GroupListResultModel)); | |
173 | + const getAllIds = findForAllId(organizationTreeData.value as any, []); | |
174 | + //设置要展开的id | |
175 | + treeExpandData.value = getAllIds; | |
176 | + } | |
177 | + | |
178 | + if (!unref(isAdd)) { | |
179 | + rowId.value = data.record.id; | |
180 | + const roleParams = new RoleOrOrganizationParam(rowId.value, true, false); | |
181 | + olderPhoneNumber.value = data.record.phoneNumber; | |
182 | + singleEditPostPhoneNumber.phoneNumber = data.record.phoneNumber; | |
183 | + findCurrentUserRelation(roleParams).then((result) => { | |
184 | + Reflect.set(data.record, 'roleIds', result); | |
185 | + setFieldsValue(data.record); | |
186 | + }); | |
187 | + updateSchema([ | |
188 | + { | |
189 | + field: 'phoneNumber', | |
190 | + dynamicRules: () => { | |
191 | + return [ | |
192 | + { | |
193 | + required: true, | |
194 | + validator(_, value) { | |
195 | + return new Promise((resolve, reject) => { | |
196 | + if (value == '') { | |
197 | + reject('请输入手机号'); | |
198 | + } else if (!phoneRegexp.test(value)) { | |
199 | + reject('请输入正确的手机号'); | |
200 | + } else { | |
201 | + resolve(); | |
202 | + } | |
203 | + }); | |
204 | + }, | |
210 | 205 | }, |
211 | - }, | |
212 | - ]); | |
213 | - const organizationParams = new RoleOrOrganizationParam(rowId.value, false, true); | |
214 | - checkGroup.value = await findCurrentUserRelation(organizationParams); | |
215 | - } else { | |
216 | - updateSchema([ | |
217 | - { | |
218 | - field: 'phoneNumber', | |
219 | - dynamicRules: ({ values }) => { | |
220 | - return [ | |
221 | - { | |
222 | - required: true, | |
223 | - validator(_, value) { | |
224 | - return new Promise((resolve, reject) => { | |
225 | - if (value == '') { | |
226 | - reject('请输入手机号'); | |
227 | - } else if (!phoneRegexp.test(value)) { | |
228 | - reject('请输入正确的手机号'); | |
229 | - } else { | |
230 | - if (values.phoneNumber != undefined) { | |
231 | - // 此处可以用防抖函数优化性能 | |
232 | - IsPhoneExist(value).then(({ data }) => { | |
233 | - if (data != null) { | |
234 | - reject('手机号已存在'); | |
235 | - } else { | |
236 | - resolve(); | |
237 | - } | |
238 | - }); | |
206 | + ]; | |
207 | + }, | |
208 | + }, | |
209 | + ]); | |
210 | + const organizationParams = new RoleOrOrganizationParam(rowId.value, false, true); | |
211 | + const checked = await findCurrentUserRelation(organizationParams); | |
212 | + const halfChecked = getHalfCheckedNode(checked); | |
213 | + Object.assign(checkedKeys, { checked, halfChecked }); | |
214 | + setFieldsValue({ organizationIds: toRaw(checkedKeys) }); | |
215 | + } else { | |
216 | + updateSchema([ | |
217 | + { | |
218 | + field: 'phoneNumber', | |
219 | + dynamicRules: ({ values }) => { | |
220 | + return [ | |
221 | + { | |
222 | + required: true, | |
223 | + validator(_, value) { | |
224 | + return new Promise((resolve, reject) => { | |
225 | + if (value == '') { | |
226 | + reject('请输入手机号'); | |
227 | + } else if (!phoneRegexp.test(value)) { | |
228 | + reject('请输入正确的手机号'); | |
229 | + } else { | |
230 | + if (values.phoneNumber != undefined) { | |
231 | + // 此处可以用防抖函数优化性能 | |
232 | + IsPhoneExist(value).then(({ data }) => { | |
233 | + if (data != null) { | |
234 | + reject('手机号已存在'); | |
239 | 235 | } else { |
240 | 236 | resolve(); |
241 | 237 | } |
242 | - } | |
243 | - }); | |
244 | - }, | |
245 | - }, | |
246 | - ]; | |
238 | + }); | |
239 | + } else { | |
240 | + resolve(); | |
241 | + } | |
242 | + } | |
243 | + }); | |
244 | + }, | |
247 | 245 | }, |
248 | - }, | |
249 | - ]); | |
250 | - } | |
251 | - await updateSchema([ | |
252 | - { | |
253 | - field: 'username', | |
254 | - dynamicDisabled: !unref(isAdd), | |
246 | + ]; | |
255 | 247 | }, |
256 | - ]); | |
248 | + }, | |
249 | + ]); | |
250 | + } | |
251 | + await updateSchema([ | |
252 | + { | |
253 | + field: 'username', | |
254 | + dynamicDisabled: !unref(isAdd), | |
255 | + }, | |
256 | + ]); | |
257 | + }); | |
258 | + const getTitle = computed(() => (unref(isAdd) ? '新增管理员账号' : '编辑管理员账号')); | |
259 | + | |
260 | + const getFormatValues = (values: Recordable) => { | |
261 | + const organizationIds = values.organizationIds; | |
262 | + if (!organizationIds || isArray(organizationIds)) return values; | |
263 | + | |
264 | + values.organizationIds = values?.organizationIds?.checked; | |
265 | + | |
266 | + return values; | |
267 | + }; | |
268 | + | |
269 | + async function handleSubmit() { | |
270 | + setModalProps({ confirmLoading: true }); | |
271 | + try { | |
272 | + const values = getFieldsValue(); | |
273 | + if (!('organizationIds' in values)) { | |
274 | + createMessage.error('组织必选'); | |
275 | + } | |
276 | + | |
277 | + await validate(); | |
278 | + await addTenantList({ | |
279 | + ...getFormatValues(values), | |
280 | + level: 4, | |
281 | + tenantId: userInfo.getUserInfo.tenantId!, | |
257 | 282 | }); |
258 | - const getTitle = computed(() => (unref(isAdd) ? '新增管理员账号' : '编辑管理员账号')); | |
283 | + createMessage.success(unref(isAdd) ? '新增成功' : '编辑成功'); | |
284 | + closeModal(); | |
285 | + emit('success'); | |
286 | + } finally { | |
287 | + setModalProps({ confirmLoading: false }); | |
288 | + } | |
289 | + } | |
290 | + // 取消全部的时候清除回显时获取的 | |
291 | + const handleUnSelectAll = () => { | |
292 | + checkedKeysWithHalfChecked.value = []; | |
293 | + }; | |
294 | + | |
295 | + const strictlyStatus = ref(false); //层级关联或独立的状态 false为层级关联 true为层级独立 | |
296 | + | |
297 | + const handleStrictlyStatus = (status) => (strictlyStatus.value = status); | |
298 | + | |
299 | + const handleCheckClick = () => { | |
300 | + if (unref(checkStrictly)) { | |
301 | + checkStrictly.value = false; | |
302 | + } | |
303 | + }; | |
304 | + | |
305 | + const [registerDrawer, { openDrawer: addOpenDrawer }] = useDrawer(); | |
306 | + | |
307 | + const handleOpenCreate = () => { | |
308 | + addOpenDrawer(true, { isAdd: false }); | |
309 | + }; | |
310 | + const handleReload = async () => { | |
311 | + const groupListModel = await findCurrentUserGroups(); | |
312 | + organizationTreeData.value = groupListModel; | |
313 | + buildNodeMap(toRaw(unref(groupListModel))); | |
314 | + }; | |
315 | + | |
316 | + const treeNodeMap = ref<Record<string, { parentId?: string; children?: string[] }>>(); | |
259 | 317 | |
260 | - async function handleSubmit() { | |
261 | - setModalProps({ confirmLoading: true }); | |
262 | - try { | |
263 | - const values = getFieldsValue(); | |
264 | - if (!('organizationIds' in values)) { | |
265 | - createMessage.error('组织必选'); | |
266 | - } | |
267 | - await validate(); | |
268 | - await addTenantList({ ...values, level: 4, tenantId: userInfo.getUserInfo.tenantId! }); | |
269 | - createMessage.success(unref(isAdd) ? '新增成功' : '编辑成功'); | |
270 | - closeModal(); | |
271 | - emit('success'); | |
272 | - } finally { | |
273 | - setModalProps({ confirmLoading: false }); | |
318 | + function buildNodeMap(tree: GroupListResultModel) { | |
319 | + const nodeMap: Record<string, { parentId?: string; children?: string[] }> = {}; | |
320 | + | |
321 | + function traverse(tree: GroupListResultModel) { | |
322 | + for (let node of tree) { | |
323 | + Reflect.set(nodeMap, node.id, { | |
324 | + parentId: node.parentId, | |
325 | + children: node.children?.map((item) => item.id), | |
326 | + }); | |
327 | + | |
328 | + if (node.children && node.children.length) { | |
329 | + traverse(node.children); | |
274 | 330 | } |
275 | 331 | } |
276 | - // 取消全部的时候清除回显时获取的 | |
277 | - const handleUnSelectAll = () => { | |
278 | - checkedKeysWithHalfChecked.value = []; | |
279 | - }; | |
332 | + } | |
333 | + traverse(tree); | |
280 | 334 | |
281 | - const strictlyStatus = ref(false); //层级关联或独立的状态 false为层级关联 true为层级独立 | |
335 | + treeNodeMap.value = nodeMap; | |
336 | + } | |
282 | 337 | |
283 | - const handleStrictlyStatus = (status) => (strictlyStatus.value = status); | |
338 | + function getHalfCheckedNode(keys: string[]) { | |
339 | + const relation = unref(treeNodeMap) || {}; | |
340 | + const halfChecked: string[] = []; | |
284 | 341 | |
285 | - const handleCheckClick = (selectedKeys: CheckKeys, event: CheckEvent) => { | |
286 | - //fix 取消层级独立后selectedKeys不是数组,是{checked:[],halfChecked:[]}对象 迭代报错 | |
287 | - // 层级独立 | |
288 | - if (strictlyStatus.value) { | |
289 | - if (!Array.isArray(selectedKeys)) { | |
290 | - selectedKeys = selectedKeys?.checked; | |
291 | - event.halfCheckedKeys = []; | |
292 | - } | |
293 | - } else { | |
294 | - // 层级关联 | |
295 | - event.halfCheckedKeys = []; | |
296 | - } | |
297 | - checkedKeysWithHalfChecked.value = [ | |
298 | - ...selectedKeys, | |
299 | - ...(event.halfCheckedKeys as string[]), | |
300 | - ]; | |
301 | - }; | |
342 | + for (const key of keys) { | |
343 | + let current = relation[key]; | |
302 | 344 | |
303 | - const [registerDrawer, { openDrawer: addOpenDrawer }] = useDrawer(); | |
345 | + while (current) { | |
346 | + if (keys.includes(current.parentId!) || !current.parentId) { | |
347 | + break; | |
348 | + } | |
304 | 349 | |
305 | - const handleOpenCreate = () => { | |
306 | - addOpenDrawer(true, { isAdd: false }); | |
307 | - }; | |
308 | - const handleReload = async () => { | |
309 | - const groupListModel = await findCurrentUserGroups(); | |
310 | - copyTransTreeFun(groupListModel); | |
311 | - organizationTreeData.value = groupListModel; | |
312 | - }; | |
350 | + halfChecked.push(current.parentId!); | |
351 | + current = relation[current.parentId!]; | |
352 | + } | |
353 | + } | |
313 | 354 | |
314 | - return { | |
315 | - registerModal, | |
316 | - registerForm, | |
317 | - handleSubmit, | |
318 | - getTitle, | |
319 | - organizationTreeData, | |
320 | - checkGroup, | |
321 | - basicTreeRef, | |
322 | - treeExpandData, | |
323 | - roleOptions, | |
324 | - registerRoleDrawer, | |
325 | - handleOpenRole, | |
326 | - handleSuccess, | |
327 | - handleRoleSelect, | |
328 | - handleTreeSelect, | |
329 | - handleCheckClick, | |
330 | - handleUnSelectAll, | |
331 | - handleStrictlyStatus, | |
332 | - handleOpenCreate, | |
333 | - registerDrawer, | |
334 | - handleReload, | |
335 | - }; | |
336 | - }, | |
337 | - }); | |
355 | + return Array.from(new Set(halfChecked)); | |
356 | + } | |
338 | 357 | </script> |
339 | 358 | <style scoped lang="less"> |
340 | 359 | :deep(.vben-basic-tree) { | ... | ... |