Commit d8496ea8ed2abb73af4a5b506ca5c794a3909eff
Merge branch 'feat/account-role-manage' into 'main_dev'
Feat/account role manage See merge request yunteng/thingskit-front!1321
Showing
10 changed files
with
523 additions
and
496 deletions
| @@ -106,20 +106,21 @@ export const formSchema: FormSchema[] = [ | @@ -106,20 +106,21 @@ export const formSchema: FormSchema[] = [ | ||
| 106 | }, | 106 | }, |
| 107 | { | 107 | { |
| 108 | field: 'wechat', | 108 | field: 'wechat', |
| 109 | - label: '微信', | 109 | + label: '企业微信', |
| 110 | component: 'Input', | 110 | component: 'Input', |
| 111 | + helpMessage: '企业微信通知电话,须在对应企业微信绑定,否则不能收到告警通知。', | ||
| 111 | componentProps: { | 112 | componentProps: { |
| 112 | - placeholder: '请输入微信号', | 113 | + placeholder: '请输入企业微信号', |
| 113 | maxLength: 255, | 114 | maxLength: 255, |
| 114 | }, | 115 | }, |
| 115 | }, | 116 | }, |
| 116 | - { | ||
| 117 | - field: 'wechatMessage', | ||
| 118 | - label: ' ', | ||
| 119 | - slot: 'wechatMessage', | ||
| 120 | - component: 'Input', | ||
| 121 | - ifShow: ({ model }) => model.wechat, | ||
| 122 | - }, | 117 | + // { |
| 118 | + // field: 'wechatMessage', | ||
| 119 | + // label: ' ', | ||
| 120 | + // slot: 'wechatMessage', | ||
| 121 | + // component: 'Input', | ||
| 122 | + // ifShow: ({ model }) => model.wechat, | ||
| 123 | + // }, | ||
| 123 | { | 124 | { |
| 124 | field: 'dingtalk', | 125 | field: 'dingtalk', |
| 125 | label: '钉钉', | 126 | label: '钉钉', |
| @@ -61,7 +61,6 @@ | @@ -61,7 +61,6 @@ | ||
| 61 | </span> | 61 | </span> |
| 62 | </template> | 62 | </template> |
| 63 | </BasicTable> | 63 | </BasicTable> |
| 64 | - <BasicTable /> | ||
| 65 | <BasicModal title="输出参数" @register="registerModal" @ok="closeModal"> | 64 | <BasicModal title="输出参数" @register="registerModal" @ok="closeModal"> |
| 66 | <Input.TextArea v-model:value="outputData" :autosize="true" /> | 65 | <Input.TextArea v-model:value="outputData" :autosize="true" /> |
| 67 | </BasicModal> | 66 | </BasicModal> |
| @@ -185,8 +185,10 @@ export const list = [ | @@ -185,8 +185,10 @@ export const list = [ | ||
| 185 | { | 185 | { |
| 186 | deviceType: '网关/直连/网关子设备', | 186 | deviceType: '网关/直连/网关子设备', |
| 187 | function: '事件上报', | 187 | function: '事件上报', |
| 188 | - release: 'v1/devices/event/${deviceId}或${deviceName}/${identifier}', | ||
| 189 | - subscribe: 'v1/devices/event/${deviceId}或${deviceName}/${identifier}', | 188 | + release: |
| 189 | + 'v1/devices/event/${deviceId}/${identifier}或v1/devices/event/${deviceName}/${identifier}', | ||
| 190 | + subscribe: | ||
| 191 | + 'v1/devices/event/${deviceId}/${identifier}或v1/devices/event/${deviceName}/${identifier}', | ||
| 190 | platform: '订阅', | 192 | platform: '订阅', |
| 191 | device: '发布', | 193 | device: '发布', |
| 192 | }, | 194 | }, |
| @@ -128,7 +128,7 @@ export function useBasicDataTransform() { | @@ -128,7 +128,7 @@ export function useBasicDataTransform() { | ||
| 128 | description, | 128 | description, |
| 129 | name, | 129 | name, |
| 130 | }, | 130 | }, |
| 131 | - created: !id?.id, | 131 | + created: !!id?.id, |
| 132 | }, | 132 | }, |
| 133 | { | 133 | { |
| 134 | id: id?.id || buildUUID(), | 134 | id: id?.id || buildUUID(), |
| @@ -152,6 +152,7 @@ export function useBasicDataTransform() { | @@ -152,6 +152,7 @@ export function useBasicDataTransform() { | ||
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | const newNode = genNewNodeByData(node, nodeConfig); | 154 | const newNode = genNewNodeByData(node, nodeConfig); |
| 155 | + newNode.data.isSaved = true; | ||
| 155 | 156 | ||
| 156 | addNodes.push(newNode); | 157 | addNodes.push(newNode); |
| 157 | } | 158 | } |
| @@ -217,9 +218,10 @@ export function useBasicDataTransform() { | @@ -217,9 +218,10 @@ export function useBasicDataTransform() { | ||
| 217 | if (ignoreNodeKeys.includes(nodeData.config?.key as string)) continue; | 218 | if (ignoreNodeKeys.includes(nodeData.config?.key as string)) continue; |
| 218 | 219 | ||
| 219 | const data = nodeData.data; | 220 | const data = nodeData.data; |
| 221 | + | ||
| 220 | const resultNode = Object.assign( | 222 | const resultNode = Object.assign( |
| 221 | mergeData(data, nodeData, node), | 223 | mergeData(data, nodeData, node), |
| 222 | - nodeData.created | 224 | + nodeData?.isSaved |
| 223 | ? ({ | 225 | ? ({ |
| 224 | id: { id: node.id, entityType: RuleChainEntityType.RULE_NODE }, | 226 | id: { id: node.id, entityType: RuleChainEntityType.RULE_NODE }, |
| 225 | } as BasicNodeBindData) | 227 | } as BasicNodeBindData) |
| @@ -170,7 +170,7 @@ export function useContextMenuAction() { | @@ -170,7 +170,7 @@ export function useContextMenuAction() { | ||
| 170 | const { getAddNodesParams } = useAddNodes(); | 170 | const { getAddNodesParams } = useAddNodes(); |
| 171 | const { x, y } = position; | 171 | const { x, y } = position; |
| 172 | 172 | ||
| 173 | - const value = getAddNodesParams(position, data, { id }); | 173 | + const value = getAddNodesParams(position, { ...data, isSaved: false }, { id }); |
| 174 | 174 | ||
| 175 | setRuleNodeCache({ | 175 | setRuleNodeCache({ |
| 176 | nodes: [value], | 176 | nodes: [value], |
| @@ -50,8 +50,7 @@ export function useSaveAndRedo() { | @@ -50,8 +50,7 @@ export function useSaveAndRedo() { | ||
| 50 | 50 | ||
| 51 | const { connections, nodes, firstNodeIndex } = combineData( | 51 | const { connections, nodes, firstNodeIndex } = combineData( |
| 52 | flowActionType.getNodes, | 52 | flowActionType.getNodes, |
| 53 | - flowActionType.getEdges, | ||
| 54 | - true | 53 | + flowActionType.getEdges |
| 55 | ); | 54 | ); |
| 56 | 55 | ||
| 57 | handleSaveRuleChain(connections, nodes, firstNodeIndex, flowActionType); | 56 | handleSaveRuleChain(connections, nodes, firstNodeIndex, flowActionType); |
| @@ -138,6 +138,7 @@ export interface NodeData<T = BasicNodeFormData> { | @@ -138,6 +138,7 @@ export interface NodeData<T = BasicNodeFormData> { | ||
| 138 | config?: NodeItemConfigType; | 138 | config?: NodeItemConfigType; |
| 139 | data?: T; | 139 | data?: T; |
| 140 | created?: boolean; | 140 | created?: boolean; |
| 141 | + isSaved?: boolean; | ||
| 141 | } | 142 | } |
| 142 | 143 | ||
| 143 | export interface EdgeData { | 144 | export interface EdgeData { |
| @@ -14,9 +14,10 @@ | @@ -14,9 +14,10 @@ | ||
| 14 | </Button> | 14 | </Button> |
| 15 | <BasicTree | 15 | <BasicTree |
| 16 | v-if="organizationTreeData.length" | 16 | v-if="organizationTreeData.length" |
| 17 | + :check-strictly="checkStrictly" | ||
| 17 | v-model:value="model[field]" | 18 | v-model:value="model[field]" |
| 18 | :treeData="organizationTreeData" | 19 | :treeData="organizationTreeData" |
| 19 | - :checked-keys="checkGroup" | 20 | + :checked-keys="checkedKeys" |
| 20 | :expandedKeys="treeExpandData" | 21 | :expandedKeys="treeExpandData" |
| 21 | ref="basicTreeRef" | 22 | ref="basicTreeRef" |
| 22 | @check="handleCheckClick" | 23 | @check="handleCheckClick" |
| @@ -25,6 +26,7 @@ | @@ -25,6 +26,7 @@ | ||
| 25 | checkable | 26 | checkable |
| 26 | toolbar | 27 | toolbar |
| 27 | @change="handleTreeSelect" | 28 | @change="handleTreeSelect" |
| 29 | + :replace-fields="{ children: 'children', title: 'name', key: 'id' }" | ||
| 28 | /> | 30 | /> |
| 29 | </template> | 31 | </template> |
| 30 | <template #roleSlot="{ model, field }"> | 32 | <template #roleSlot="{ model, field }"> |
| @@ -53,8 +55,8 @@ | @@ -53,8 +55,8 @@ | ||
| 53 | </BasicModal> | 55 | </BasicModal> |
| 54 | <RoleDrawer @register="registerRoleDrawer" @success="handleSuccess" /> | 56 | <RoleDrawer @register="registerRoleDrawer" @success="handleSuccess" /> |
| 55 | </template> | 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 | import { BasicModal, useModalInner } from '/@/components/Modal'; | 60 | import { BasicModal, useModalInner } from '/@/components/Modal'; |
| 59 | import { BasicForm, useForm } from '/@/components/Form/index'; | 61 | import { BasicForm, useForm } from '/@/components/Form/index'; |
| 60 | import { accountFormSchema } from './account.data'; | 62 | import { accountFormSchema } from './account.data'; |
| @@ -64,262 +66,264 @@ | @@ -64,262 +66,264 @@ | ||
| 64 | SaveOrUpdateUserInfo, | 66 | SaveOrUpdateUserInfo, |
| 65 | filterRoleList, | 67 | filterRoleList, |
| 66 | } from '/@/api/system/system'; | 68 | } from '/@/api/system/system'; |
| 67 | - import { BasicTree, TreeItem, CheckKeys, CheckEvent } from '/@/components/Tree'; | 69 | + import { BasicTree, TreeItem, CheckKeys } from '/@/components/Tree'; |
| 68 | import { findCurrentUserGroups } from '/@/api/system/group'; | 70 | import { findCurrentUserGroups } from '/@/api/system/group'; |
| 69 | import { RoleOrOrganizationParam } from '/@/api/system/model/systemModel'; | 71 | import { RoleOrOrganizationParam } from '/@/api/system/model/systemModel'; |
| 70 | import { useMessage } from '/@/hooks/web/useMessage'; | 72 | import { useMessage } from '/@/hooks/web/useMessage'; |
| 71 | - import { copyTransTreeFun } from '/@/utils/fnUtils'; | ||
| 72 | import { TOption } from '/@/views/rule/linkedge/config/config.data'; | 73 | import { TOption } from '/@/views/rule/linkedge/config/config.data'; |
| 73 | import { PlusOutlined } from '@ant-design/icons-vue'; | 74 | import { PlusOutlined } from '@ant-design/icons-vue'; |
| 74 | import { useDrawer } from '/@/components/Drawer'; | 75 | import { useDrawer } from '/@/components/Drawer'; |
| 75 | import RoleDrawer from '../../role/CustomRoleDrawer.vue'; | 76 | import RoleDrawer from '../../role/CustomRoleDrawer.vue'; |
| 76 | import OrganizationDrawer from '/@/views/system/organization/OrganizationDrawer.vue'; | 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 | </script> | 327 | </script> |
| 324 | <style scoped lang="less"> | 328 | <style scoped lang="less"> |
| 325 | :deep(.vben-basic-tree) { | 329 | :deep(.vben-basic-tree) { |
| @@ -14,9 +14,10 @@ | @@ -14,9 +14,10 @@ | ||
| 14 | </Button> | 14 | </Button> |
| 15 | <BasicTree | 15 | <BasicTree |
| 16 | v-if="organizationTreeData.length" | 16 | v-if="organizationTreeData.length" |
| 17 | + :check-strictly="checkStrictly" | ||
| 17 | v-model:value="model[field]" | 18 | v-model:value="model[field]" |
| 18 | :treeData="organizationTreeData" | 19 | :treeData="organizationTreeData" |
| 19 | - :checked-keys="checkGroup" | 20 | + :checked-keys="checkedKeys" |
| 20 | :expandedKeys="treeExpandData" | 21 | :expandedKeys="treeExpandData" |
| 21 | ref="basicTreeRef" | 22 | ref="basicTreeRef" |
| 22 | @check="handleCheckClick" | 23 | @check="handleCheckClick" |
| @@ -25,6 +26,7 @@ | @@ -25,6 +26,7 @@ | ||
| 25 | checkable | 26 | checkable |
| 26 | toolbar | 27 | toolbar |
| 27 | @change="handleTreeSelect" | 28 | @change="handleTreeSelect" |
| 29 | + :replace-fields="{ children: 'children', title: 'name', key: 'id' }" | ||
| 28 | /> | 30 | /> |
| 29 | </template> | 31 | </template> |
| 30 | <template #roleSlot="{ model, field }"> | 32 | <template #roleSlot="{ model, field }"> |
| @@ -53,19 +55,18 @@ | @@ -53,19 +55,18 @@ | ||
| 53 | </BasicModal> | 55 | </BasicModal> |
| 54 | <RoleDrawer @register="registerRoleDrawer" @success="handleSuccess" /> | 56 | <RoleDrawer @register="registerRoleDrawer" @success="handleSuccess" /> |
| 55 | </template> | 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 | import { BasicModal, useModalInner } from '/@/components/Modal'; | 60 | import { BasicModal, useModalInner } from '/@/components/Modal'; |
| 59 | import { BasicForm, useForm } from '/@/components/Form/index'; | 61 | import { BasicForm, useForm } from '/@/components/Form/index'; |
| 60 | import { accountFormSchema } from './config'; | 62 | import { accountFormSchema } from './config'; |
| 61 | import { Button } from 'ant-design-vue'; | 63 | import { Button } from 'ant-design-vue'; |
| 62 | import { findCurrentUserRelation, filterRoleList } from '/@/api/system/system'; | 64 | import { findCurrentUserRelation, filterRoleList } from '/@/api/system/system'; |
| 63 | import { addTenantList } from '/@/api/system/account'; | 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 | import { findCurrentUserGroups } from '/@/api/system/group'; | 67 | import { findCurrentUserGroups } from '/@/api/system/group'; |
| 66 | import { RoleOrOrganizationParam } from '/@/api/system/model/systemModel'; | 68 | import { RoleOrOrganizationParam } from '/@/api/system/model/systemModel'; |
| 67 | import { useMessage } from '/@/hooks/web/useMessage'; | 69 | import { useMessage } from '/@/hooks/web/useMessage'; |
| 68 | - import { copyTransTreeFun } from '/@/utils/fnUtils'; | ||
| 69 | import { TOption } from '/@/views/rule/linkedge/config/config.data'; | 70 | import { TOption } from '/@/views/rule/linkedge/config/config.data'; |
| 70 | import { PlusOutlined } from '@ant-design/icons-vue'; | 71 | import { PlusOutlined } from '@ant-design/icons-vue'; |
| 71 | import { useDrawer } from '/@/components/Drawer'; | 72 | import { useDrawer } from '/@/components/Drawer'; |
| @@ -74,267 +75,285 @@ | @@ -74,267 +75,285 @@ | ||
| 74 | import { useUserStore } from '/@/store/modules/user'; | 75 | import { useUserStore } from '/@/store/modules/user'; |
| 75 | import { IsPhoneExist } from '/@/api/system/system'; | 76 | import { IsPhoneExist } from '/@/api/system/system'; |
| 76 | import { phoneRegexp } from '/@/utils/rules'; | 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 | } else { | 235 | } else { |
| 240 | resolve(); | 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 | </script> | 357 | </script> |
| 339 | <style scoped lang="less"> | 358 | <style scoped lang="less"> |
| 340 | :deep(.vben-basic-tree) { | 359 | :deep(.vben-basic-tree) { |