Showing
14 changed files
with
2102 additions
and
1 deletions
| 1 | +<template> | ||
| 2 | + <div> | ||
| 3 | + <PageWrapper :title="`用户资料`" contentBackground @back="goBack"> | ||
| 4 | + <Description size="middle" @register="register" /> | ||
| 5 | + </PageWrapper> | ||
| 6 | + </div> | ||
| 7 | +</template> | ||
| 8 | + | ||
| 9 | +<script> | ||
| 10 | + import { defineComponent } from 'vue'; | ||
| 11 | + import { useRoute } from 'vue-router'; | ||
| 12 | + import { PageWrapper } from '/@/components/Page'; | ||
| 13 | + import { useGo } from '/@/hooks/web/usePage'; | ||
| 14 | + import { Description } from '../../../components/Description'; | ||
| 15 | + import { getAccountInfo } from '../../../api/system/system'; | ||
| 16 | + import { accountSchema } from './account.detail.data'; | ||
| 17 | + import { useDescription } from '../../../components/Description'; | ||
| 18 | + import { useTabs } from '/@/hooks/web/useTabs'; | ||
| 19 | + const accountData = {}; | ||
| 20 | + export default defineComponent({ | ||
| 21 | + name: 'AccountDetail', | ||
| 22 | + components: { PageWrapper, Description }, | ||
| 23 | + setup() { | ||
| 24 | + const route = useRoute(); | ||
| 25 | + const go = useGo(); | ||
| 26 | + const { setTitle, close } = useTabs(); | ||
| 27 | + const [register, { setDescProps }] = useDescription({ | ||
| 28 | + title: '账号基础信息', | ||
| 29 | + data: accountData, | ||
| 30 | + schema: accountSchema, | ||
| 31 | + column: 3, | ||
| 32 | + }); | ||
| 33 | + getAccountInfo(route.params?.id).then((result) => { | ||
| 34 | + Reflect.set(accountData, 'remark', result.remark); | ||
| 35 | + Reflect.set(accountData, 'realName', result.realName); | ||
| 36 | + Reflect.set(accountData, 'phoneNumber', result.phoneNumber); | ||
| 37 | + Reflect.set(accountData, 'email', result.email); | ||
| 38 | + Reflect.set(accountData, 'username', result.username); | ||
| 39 | + Reflect.set( | ||
| 40 | + accountData, | ||
| 41 | + 'enabled', | ||
| 42 | + result.enabled ? '正常' : !result.enabled ? '禁用' : '已过期' | ||
| 43 | + ); | ||
| 44 | + Reflect.set(accountData, 'accountExpireTime', result.accountExpireTime); | ||
| 45 | + Reflect.set(accountData, 'createTime', result.createTime); | ||
| 46 | + Reflect.set(accountData, 'updateTime', result.updateTime); | ||
| 47 | + // 设置Tab的标题(不会影响页面标题) | ||
| 48 | + setTitle('详情:用户' + result.realName); | ||
| 49 | + setDescProps(accountData); | ||
| 50 | + }); | ||
| 51 | + // 页面左侧点击返回链接时的操作 | ||
| 52 | + function goBack() { | ||
| 53 | + // 本例的效果时点击返回始终跳转到账号列表页,实际应用时可返回上一页 | ||
| 54 | + close(); | ||
| 55 | + go('/system/account'); | ||
| 56 | + } | ||
| 57 | + return { goBack, accountSchema, accountData, register }; | ||
| 58 | + }, | ||
| 59 | + }); | ||
| 60 | +</script> | ||
| 61 | + | ||
| 62 | +<style scoped> | ||
| 63 | + .vben-collapse-container { | ||
| 64 | + background-color: white !important; | ||
| 65 | + } | ||
| 66 | +</style> |
| 1 | +<template> | ||
| 2 | + <BasicModal | ||
| 3 | + width="650px" | ||
| 4 | + v-bind="$attrs" | ||
| 5 | + @register="registerModal" | ||
| 6 | + :title="getTitle" | ||
| 7 | + @ok="handleSubmit" | ||
| 8 | + > | ||
| 9 | + <div style="height: 50vh"> | ||
| 10 | + <BasicForm @register="registerForm"> | ||
| 11 | + <template #organizationId="{ model, field }"> | ||
| 12 | + <Button type="link" @click="handleOpenCreate" style="padding: 0; z-index: 9999" | ||
| 13 | + >新增组织 | ||
| 14 | + </Button> | ||
| 15 | + <BasicTree | ||
| 16 | + v-if="organizationTreeData.length" | ||
| 17 | + v-model:value="model[field]" | ||
| 18 | + :treeData="organizationTreeData" | ||
| 19 | + :checked-keys="checkGroup" | ||
| 20 | + :expandedKeys="treeExpandData" | ||
| 21 | + ref="basicTreeRef" | ||
| 22 | + @check="handleCheckClick" | ||
| 23 | + @unSelectAll="handleUnSelectAll" | ||
| 24 | + @strictlyStatus="handleStrictlyStatus" | ||
| 25 | + checkable | ||
| 26 | + toolbar | ||
| 27 | + @change="handleTreeSelect" | ||
| 28 | + /> | ||
| 29 | + </template> | ||
| 30 | + <template #roleSlot="{ model, field }"> | ||
| 31 | + <a-select | ||
| 32 | + mode="multiple" | ||
| 33 | + allowClear | ||
| 34 | + placeholder="请选择角色" | ||
| 35 | + v-model:value="model[field]" | ||
| 36 | + @change="handleRoleSelect" | ||
| 37 | + :options="roleOptions.map((item) => ({ value: item.value, label: item.label }))" | ||
| 38 | + > | ||
| 39 | + <template #dropdownRender="{ menuNode: menu }"> | ||
| 40 | + <v-nodes :vnodes="menu" /> | ||
| 41 | + <a-divider style="margin: 4px 0" /> | ||
| 42 | + <div @click="handleOpenRole" style="padding: 4px 0; cursor: pointer"> | ||
| 43 | + <plus-outlined /> | ||
| 44 | + 新增角色 | ||
| 45 | + </div> | ||
| 46 | + </template> | ||
| 47 | + </a-select> | ||
| 48 | + </template> | ||
| 49 | + </BasicForm> | ||
| 50 | + | ||
| 51 | + <OrganizationDrawer @register="registerDrawer" @success="handleReload" /> | ||
| 52 | + </div> | ||
| 53 | + </BasicModal> | ||
| 54 | + <RoleDrawer @register="registerRoleDrawer" @success="handleSuccess" /> | ||
| 55 | +</template> | ||
| 56 | +<script lang="ts"> | ||
| 57 | + import { defineComponent, ref, computed, unref, reactive, onMounted } from 'vue'; | ||
| 58 | + import { BasicModal, useModalInner } from '/@/components/Modal'; | ||
| 59 | + import { BasicForm, useForm } from '/@/components/Form/index'; | ||
| 60 | + import { accountFormSchema } from './account.data'; | ||
| 61 | + import { Button } from 'ant-design-vue'; | ||
| 62 | + import { | ||
| 63 | + findCurrentUserRelation, | ||
| 64 | + SaveOrUpdateUserInfo, | ||
| 65 | + filterRoleList, | ||
| 66 | + } from '/@/api/system/system'; | ||
| 67 | + import { BasicTree, TreeItem, CheckKeys, CheckEvent } from '/@/components/Tree'; | ||
| 68 | + import { findCurrentUserGroups } from '/@/api/system/group'; | ||
| 69 | + import { RoleOrOrganizationParam } from '/@/api/system/model/systemModel'; | ||
| 70 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
| 71 | + import { copyTransTreeFun } from '/@/utils/fnUtils'; | ||
| 72 | + import { TOption } from '/@/views/rule/linkedge/config/config.data'; | ||
| 73 | + import { PlusOutlined } from '@ant-design/icons-vue'; | ||
| 74 | + import { useDrawer } from '/@/components/Drawer'; | ||
| 75 | + import RoleDrawer from '../../role/RoleDrawer.vue'; | ||
| 76 | + import OrganizationDrawer from '/@/views/system/organization/OrganizationDrawer.vue'; | ||
| 77 | + | ||
| 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(); | ||
| 120 | + | ||
| 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(); | ||
| 138 | + }; | ||
| 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 | + }, | ||
| 157 | + }); | ||
| 158 | + //获取所有父级id | ||
| 159 | + function findForAllId(data = [], arr = []) { | ||
| 160 | + for (const item of data) { | ||
| 161 | + arr.push(item.id); | ||
| 162 | + } | ||
| 163 | + return arr; | ||
| 164 | + } | ||
| 165 | + | ||
| 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; | ||
| 177 | + } | ||
| 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); | ||
| 190 | + } | ||
| 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) ? '新增账号' : '编辑账号')); | ||
| 203 | + | ||
| 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 | + await SaveOrUpdateUserInfo(postData as any, unref(isUpdate)); | ||
| 249 | + closeModal(); | ||
| 250 | + emit('success'); | ||
| 251 | + createMessage.success(unref(isUpdate) ? '编辑成功' : '新增成功'); | ||
| 252 | + } finally { | ||
| 253 | + setTimeout(() => { | ||
| 254 | + setModalProps({ confirmLoading: false }); | ||
| 255 | + }, 300); | ||
| 256 | + } | ||
| 257 | + } | ||
| 258 | + // 取消全部的时候清除回显时获取的 | ||
| 259 | + const handleUnSelectAll = () => { | ||
| 260 | + checkedKeysWithHalfChecked.value = []; | ||
| 261 | + }; | ||
| 262 | + | ||
| 263 | + const strictlyStatus = ref(false); //层级关联或独立的状态 false为层级关联 true为层级独立 | ||
| 264 | + | ||
| 265 | + const handleStrictlyStatus = (status) => (strictlyStatus.value = status); | ||
| 266 | + | ||
| 267 | + const handleCheckClick = (selectedKeys: CheckKeys, event: CheckEvent) => { | ||
| 268 | + //fix 取消层级独立后selectedKeys不是数组,是{checked:[],halfChecked:[]}对象 迭代报错 | ||
| 269 | + // 层级独立 | ||
| 270 | + if (strictlyStatus.value) { | ||
| 271 | + if (!Array.isArray(selectedKeys)) { | ||
| 272 | + selectedKeys = selectedKeys?.checked; | ||
| 273 | + event.halfCheckedKeys = []; | ||
| 274 | + } | ||
| 275 | + } else { | ||
| 276 | + // 层级关联 | ||
| 277 | + event.halfCheckedKeys = []; | ||
| 278 | + } | ||
| 279 | + checkedKeysWithHalfChecked.value = [ | ||
| 280 | + ...selectedKeys, | ||
| 281 | + ...(event.halfCheckedKeys as string[]), | ||
| 282 | + ]; | ||
| 283 | + }; | ||
| 284 | + | ||
| 285 | + const [registerDrawer, { openDrawer: addOpenDrawer }] = useDrawer(); | ||
| 286 | + | ||
| 287 | + const handleOpenCreate = () => { | ||
| 288 | + addOpenDrawer(true, { isUpdate: false }); | ||
| 289 | + }; | ||
| 290 | + const handleReload = async () => { | ||
| 291 | + const groupListModel = await findCurrentUserGroups(); | ||
| 292 | + copyTransTreeFun(groupListModel); | ||
| 293 | + organizationTreeData.value = groupListModel; | ||
| 294 | + }; | ||
| 295 | + | ||
| 296 | + return { | ||
| 297 | + registerModal, | ||
| 298 | + registerForm, | ||
| 299 | + handleSubmit, | ||
| 300 | + getTitle, | ||
| 301 | + organizationTreeData, | ||
| 302 | + checkGroup, | ||
| 303 | + basicTreeRef, | ||
| 304 | + treeExpandData, | ||
| 305 | + roleOptions, | ||
| 306 | + registerRoleDrawer, | ||
| 307 | + handleOpenRole, | ||
| 308 | + handleSuccess, | ||
| 309 | + handleRoleSelect, | ||
| 310 | + handleTreeSelect, | ||
| 311 | + handleCheckClick, | ||
| 312 | + handleUnSelectAll, | ||
| 313 | + handleStrictlyStatus, | ||
| 314 | + handleOpenCreate, | ||
| 315 | + registerDrawer, | ||
| 316 | + handleReload, | ||
| 317 | + }; | ||
| 318 | + }, | ||
| 319 | + }); | ||
| 320 | +</script> | ||
| 321 | +<style scoped lang="less"> | ||
| 322 | + :deep(.vben-basic-tree) { | ||
| 323 | + width: 100% !important; | ||
| 324 | + margin-top: -28px !important; | ||
| 325 | + padding: 0; | ||
| 326 | + } | ||
| 327 | + | ||
| 328 | + :deep(.is-unflod) { | ||
| 329 | + display: none !important; | ||
| 330 | + } | ||
| 331 | + | ||
| 332 | + :deep(.is-flod) { | ||
| 333 | + display: none !important; | ||
| 334 | + } | ||
| 335 | +</style> |
| 1 | +import { isAccountExist, IsPhoneExist } from '/@/api/system/system'; | ||
| 2 | +import { BasicColumn } from '/@/components/Table'; | ||
| 3 | +import { FormSchema } from '/@/components/Table'; | ||
| 4 | +import { emailRule, ChineseRegexp, EmailRegexp, phoneRegexp } from '/@/utils/rules'; | ||
| 5 | + | ||
| 6 | +let olderPhoneNumber; | ||
| 7 | + | ||
| 8 | +export const columns: BasicColumn[] = [ | ||
| 9 | + { | ||
| 10 | + title: '用户名', | ||
| 11 | + dataIndex: 'username', | ||
| 12 | + width: 120, | ||
| 13 | + }, | ||
| 14 | + { | ||
| 15 | + title: '姓名', | ||
| 16 | + dataIndex: 'realName', | ||
| 17 | + width: 120, | ||
| 18 | + }, | ||
| 19 | + { | ||
| 20 | + title: '手机号码', | ||
| 21 | + dataIndex: 'phoneNumber', | ||
| 22 | + width: 120, | ||
| 23 | + }, | ||
| 24 | + { | ||
| 25 | + title: '邮箱', | ||
| 26 | + dataIndex: 'email', | ||
| 27 | + width: 120, | ||
| 28 | + }, | ||
| 29 | + { | ||
| 30 | + title: '创建时间', | ||
| 31 | + dataIndex: 'createTime', | ||
| 32 | + width: 180, | ||
| 33 | + }, | ||
| 34 | + { | ||
| 35 | + title: '状态', | ||
| 36 | + dataIndex: 'userStatusEnum', | ||
| 37 | + width: 120, | ||
| 38 | + slots: { customRender: 'status' }, | ||
| 39 | + }, | ||
| 40 | +]; | ||
| 41 | + | ||
| 42 | +export const searchFormSchema: FormSchema[] = [ | ||
| 43 | + { | ||
| 44 | + field: 'username', | ||
| 45 | + label: '用户名', | ||
| 46 | + component: 'Input', | ||
| 47 | + colProps: { span: 8 }, | ||
| 48 | + componentProps: { | ||
| 49 | + maxLength: 255, | ||
| 50 | + placeholder: '请输入用户名', | ||
| 51 | + }, | ||
| 52 | + }, | ||
| 53 | + { | ||
| 54 | + field: 'realName', | ||
| 55 | + label: '姓名', | ||
| 56 | + component: 'Input', | ||
| 57 | + colProps: { span: 8 }, | ||
| 58 | + componentProps: { | ||
| 59 | + maxLength: 255, | ||
| 60 | + placeholder: '请输入姓名', | ||
| 61 | + }, | ||
| 62 | + }, | ||
| 63 | +]; | ||
| 64 | + | ||
| 65 | +export const accountFormSchema: FormSchema[] = [ | ||
| 66 | + { | ||
| 67 | + field: 'id', | ||
| 68 | + label: 'id', | ||
| 69 | + component: 'Input', | ||
| 70 | + show: false, | ||
| 71 | + componentProps: { | ||
| 72 | + maxLength: 36, | ||
| 73 | + }, | ||
| 74 | + }, | ||
| 75 | + { | ||
| 76 | + field: 'username', | ||
| 77 | + label: '用户名', | ||
| 78 | + component: 'Input', | ||
| 79 | + colProps: { span: 12 }, | ||
| 80 | + dynamicDisabled: false, | ||
| 81 | + componentProps: { | ||
| 82 | + maxLength: 36, | ||
| 83 | + placeholder: '请输入用户名', | ||
| 84 | + }, | ||
| 85 | + dynamicRules: ({ values }) => { | ||
| 86 | + return [ | ||
| 87 | + { | ||
| 88 | + required: true, | ||
| 89 | + validator(_, value) { | ||
| 90 | + return new Promise((resolve, reject) => { | ||
| 91 | + if (value == '') { | ||
| 92 | + reject('请输入用户名'); | ||
| 93 | + } else if (ChineseRegexp.test(value)) { | ||
| 94 | + reject('用户名不能含有中文'); | ||
| 95 | + } else if (EmailRegexp.test(value)) { | ||
| 96 | + reject('用户名不能为电子邮箱格式'); | ||
| 97 | + } else { | ||
| 98 | + if (values.username != undefined && values.id == undefined) { | ||
| 99 | + isAccountExist(value).then(({ data }) => { | ||
| 100 | + if (data != null) { | ||
| 101 | + reject('用户名已存在'); | ||
| 102 | + } else { | ||
| 103 | + resolve(); | ||
| 104 | + } | ||
| 105 | + }); | ||
| 106 | + } else { | ||
| 107 | + resolve(); | ||
| 108 | + } | ||
| 109 | + } | ||
| 110 | + }); | ||
| 111 | + }, | ||
| 112 | + }, | ||
| 113 | + ]; | ||
| 114 | + }, | ||
| 115 | + }, | ||
| 116 | + { | ||
| 117 | + field: 'password', | ||
| 118 | + label: '密码', | ||
| 119 | + component: 'InputPassword', | ||
| 120 | + required: true, | ||
| 121 | + colProps: { span: 12 }, | ||
| 122 | + }, | ||
| 123 | + { | ||
| 124 | + field: 'realName', | ||
| 125 | + label: '姓名', | ||
| 126 | + component: 'Input', | ||
| 127 | + colProps: { span: 12 }, | ||
| 128 | + required: true, | ||
| 129 | + componentProps: { | ||
| 130 | + maxLength: 10, | ||
| 131 | + }, | ||
| 132 | + }, | ||
| 133 | + { | ||
| 134 | + label: '角色', | ||
| 135 | + field: 'roleIds', | ||
| 136 | + component: 'Select', | ||
| 137 | + colProps: { span: 12 }, | ||
| 138 | + slot: 'roleSlot', | ||
| 139 | + rules: [ | ||
| 140 | + { | ||
| 141 | + required: true, | ||
| 142 | + message: '请选择角色', | ||
| 143 | + type: 'array', | ||
| 144 | + }, | ||
| 145 | + ], | ||
| 146 | + }, | ||
| 147 | + { | ||
| 148 | + label: '手机号', | ||
| 149 | + field: 'phoneNumber', | ||
| 150 | + component: 'Input', | ||
| 151 | + colProps: { span: 12 }, | ||
| 152 | + dynamicRules: ({ values }) => { | ||
| 153 | + return [ | ||
| 154 | + { | ||
| 155 | + required: true, | ||
| 156 | + validator(_, value) { | ||
| 157 | + return new Promise((resolve, reject) => { | ||
| 158 | + if (value == '') { | ||
| 159 | + reject('请输入手机号'); | ||
| 160 | + } else if (!phoneRegexp.test(value)) { | ||
| 161 | + reject('请输入正确的手机号'); | ||
| 162 | + } else { | ||
| 163 | + if (values.phoneNumber != undefined) { | ||
| 164 | + // 此处可以用防抖函数优化性能 | ||
| 165 | + IsPhoneExist(value).then(({ data }) => { | ||
| 166 | + if (data != null) { | ||
| 167 | + reject('手机号已存在'); | ||
| 168 | + } else { | ||
| 169 | + resolve(); | ||
| 170 | + } | ||
| 171 | + }); | ||
| 172 | + } else { | ||
| 173 | + resolve(); | ||
| 174 | + } | ||
| 175 | + } | ||
| 176 | + }); | ||
| 177 | + }, | ||
| 178 | + }, | ||
| 179 | + ]; | ||
| 180 | + }, | ||
| 181 | + componentProps({ formActionType }) { | ||
| 182 | + const { clearValidate } = formActionType; | ||
| 183 | + return { | ||
| 184 | + onChange(value) { | ||
| 185 | + if (value == olderPhoneNumber) { | ||
| 186 | + clearValidate('phoneNumber'); | ||
| 187 | + } | ||
| 188 | + }, | ||
| 189 | + }; | ||
| 190 | + }, | ||
| 191 | + }, | ||
| 192 | + { | ||
| 193 | + label: '邮箱', | ||
| 194 | + field: 'email', | ||
| 195 | + component: 'Input', | ||
| 196 | + colProps: { span: 12 }, | ||
| 197 | + rules: emailRule, | ||
| 198 | + }, | ||
| 199 | + { | ||
| 200 | + field: 'accountExpireTime', | ||
| 201 | + label: '有效期', | ||
| 202 | + component: 'DatePicker', | ||
| 203 | + colProps: { span: 12 }, | ||
| 204 | + componentProps: { | ||
| 205 | + showTime: true, | ||
| 206 | + format: 'YYYY-MM-DD HH:mm:ss', | ||
| 207 | + }, | ||
| 208 | + }, | ||
| 209 | + { | ||
| 210 | + field: 'enabled', | ||
| 211 | + label: '状态', | ||
| 212 | + component: 'RadioButtonGroup', | ||
| 213 | + colProps: { span: 12 }, | ||
| 214 | + defaultValue: true, | ||
| 215 | + componentProps: { | ||
| 216 | + options: [ | ||
| 217 | + { label: '启用', value: true }, | ||
| 218 | + { label: '禁用', value: false }, | ||
| 219 | + ], | ||
| 220 | + }, | ||
| 221 | + }, | ||
| 222 | + { | ||
| 223 | + field: 'remark', | ||
| 224 | + label: '备注', | ||
| 225 | + component: 'InputTextArea', | ||
| 226 | + colProps: { span: 24 }, | ||
| 227 | + componentProps: { | ||
| 228 | + maxLength: 255, | ||
| 229 | + placeholder: '请输入备注', | ||
| 230 | + }, | ||
| 231 | + }, | ||
| 232 | + { | ||
| 233 | + field: 'organizationIds', | ||
| 234 | + label: '所属组织', | ||
| 235 | + component: 'Input', | ||
| 236 | + slot: 'organizationId', | ||
| 237 | + required: true, | ||
| 238 | + }, | ||
| 239 | +]; |
| 1 | +import { DescItem } from '/@/components/Description'; | ||
| 2 | + | ||
| 3 | +export const accountSchema: DescItem[] = [ | ||
| 4 | + { | ||
| 5 | + field: 'realName', | ||
| 6 | + label: '用户姓名', | ||
| 7 | + }, | ||
| 8 | + { | ||
| 9 | + field: 'phoneNumber', | ||
| 10 | + label: '手机号', | ||
| 11 | + }, | ||
| 12 | + { | ||
| 13 | + field: 'email', | ||
| 14 | + label: '邮箱', | ||
| 15 | + }, | ||
| 16 | + { | ||
| 17 | + field: 'username', | ||
| 18 | + label: '账号', | ||
| 19 | + }, | ||
| 20 | + { | ||
| 21 | + field: 'enabled', | ||
| 22 | + label: '状态', | ||
| 23 | + }, | ||
| 24 | + { | ||
| 25 | + field: 'accountExpireTime', | ||
| 26 | + label: '有效期', | ||
| 27 | + }, | ||
| 28 | + { | ||
| 29 | + field: 'createTime', | ||
| 30 | + label: '创建时间', | ||
| 31 | + }, | ||
| 32 | + { | ||
| 33 | + field: 'updateTime', | ||
| 34 | + label: '更新时间', | ||
| 35 | + }, | ||
| 36 | + { | ||
| 37 | + field: 'remark', | ||
| 38 | + label: '备注', | ||
| 39 | + }, | ||
| 40 | +]; |
src/views/system/account/custom/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div> | ||
| 3 | + <PageWrapper dense contentFullHeight contentClass="flex"> | ||
| 4 | + <OrganizationIdTree @select="handleSelect" ref="organizationIdTreeRef" /> | ||
| 5 | + <BasicTable | ||
| 6 | + style="flex: auto" | ||
| 7 | + :clickToRowSelect="false" | ||
| 8 | + @register="registerTable" | ||
| 9 | + class="w-3/4 xl:w-4/5" | ||
| 10 | + > | ||
| 11 | + <template #toolbar> | ||
| 12 | + <Authority value="api:yt:user:post"> | ||
| 13 | + <a-button type="primary" @click="handleCreate">新增账号</a-button> | ||
| 14 | + </Authority> | ||
| 15 | + <Authority value="api:yt:user:delete"> | ||
| 16 | + <Popconfirm | ||
| 17 | + title="您确定要批量删除数据" | ||
| 18 | + ok-text="确定" | ||
| 19 | + cancel-text="取消" | ||
| 20 | + @confirm="handleDeleteOrBatchDelete(null)" | ||
| 21 | + > | ||
| 22 | + <a-button color="error" :disabled="hasBatchDelete"> 批量删除 </a-button> | ||
| 23 | + </Popconfirm> | ||
| 24 | + </Authority> | ||
| 25 | + </template> | ||
| 26 | + <template #status="{ record }"> | ||
| 27 | + <Tag | ||
| 28 | + :color=" | ||
| 29 | + record.userStatusEnum === 'NORMAL' | ||
| 30 | + ? 'green' | ||
| 31 | + : record.userStatusEnum === 'DISABLED' | ||
| 32 | + ? 'red' | ||
| 33 | + : 'orange' | ||
| 34 | + " | ||
| 35 | + > | ||
| 36 | + {{ | ||
| 37 | + record.userStatusEnum === 'NORMAL' | ||
| 38 | + ? '正常' | ||
| 39 | + : record.userStatusEnum === 'DISABLED' | ||
| 40 | + ? '已禁用' | ||
| 41 | + : '已过期' | ||
| 42 | + }} | ||
| 43 | + </Tag> | ||
| 44 | + </template> | ||
| 45 | + <template #action="{ record }"> | ||
| 46 | + <TableAction | ||
| 47 | + :actions="[ | ||
| 48 | + { | ||
| 49 | + label: '进入', | ||
| 50 | + icon: 'ant-design:login-outlined', | ||
| 51 | + tooltip: `以${!isAdmin(role) ? '客户' : '平台'}用户身份登录`, | ||
| 52 | + onClick: handleLoginCustomAdmin.bind(null, record), | ||
| 53 | + }, | ||
| 54 | + { | ||
| 55 | + label: '用户详情', | ||
| 56 | + auth: 'api:yt:user:get', | ||
| 57 | + icon: 'clarity:info-standard-line', | ||
| 58 | + tooltip: '用户详情', | ||
| 59 | + onClick: handleView.bind(null, record), | ||
| 60 | + ifShow: record.level != 0, | ||
| 61 | + }, | ||
| 62 | + { | ||
| 63 | + label: '编辑', | ||
| 64 | + auth: 'api:yt:user:update', | ||
| 65 | + icon: 'clarity:note-edit-line', | ||
| 66 | + tooltip: '编辑', | ||
| 67 | + onClick: handleEdit.bind(null, record), | ||
| 68 | + ifShow: record.level != 0, | ||
| 69 | + }, | ||
| 70 | + ]" | ||
| 71 | + :drop-down-actions="[ | ||
| 72 | + { | ||
| 73 | + label: '删除', | ||
| 74 | + auth: 'api:yt:user:delete', | ||
| 75 | + icon: 'ant-design:delete-outlined', | ||
| 76 | + color: 'error', | ||
| 77 | + tooltip: '删除', | ||
| 78 | + ifShow: record.level != 0, | ||
| 79 | + popConfirm: { | ||
| 80 | + title: '是否确认删除', | ||
| 81 | + confirm: handleDeleteOrBatchDelete.bind(null, record), | ||
| 82 | + }, | ||
| 83 | + }, | ||
| 84 | + { | ||
| 85 | + label: '清除密码', | ||
| 86 | + auth: 'api:yt:user:resetPassword', | ||
| 87 | + icon: 'ant-design:delete-outlined', | ||
| 88 | + color: 'error', | ||
| 89 | + tooltip: '清除密码', | ||
| 90 | + popConfirm: { | ||
| 91 | + title: '是否确认清除密码', | ||
| 92 | + confirm: handleClearPassword.bind(null, record), | ||
| 93 | + }, | ||
| 94 | + }, | ||
| 95 | + ]" | ||
| 96 | + /> | ||
| 97 | + </template> | ||
| 98 | + </BasicTable> | ||
| 99 | + <AccountModal @register="registerModal" @success="handleSuccess" /> | ||
| 100 | + </PageWrapper> | ||
| 101 | + </div> | ||
| 102 | +</template> | ||
| 103 | +<script lang="ts"> | ||
| 104 | + import { defineComponent, reactive, nextTick } from 'vue'; | ||
| 105 | + import { BasicTable, useTable, TableAction } from '/@/components/Table'; | ||
| 106 | + import { deleteUser, getAccountList } from '/@/api/system/system'; | ||
| 107 | + import { PageWrapper } from '/@/components/Page'; | ||
| 108 | + import { useResetOrganizationTree, OrganizationIdTree } from '/@/views/common/organizationIdTree'; | ||
| 109 | + import { Tag, Popconfirm } from 'ant-design-vue'; | ||
| 110 | + import { useModal } from '/@/components/Modal'; | ||
| 111 | + import AccountModal from './AccountModal.vue'; | ||
| 112 | + import { columns, searchFormSchema } from './account.data'; | ||
| 113 | + import { useGo } from '/@/hooks/web/usePage'; | ||
| 114 | + import { useBatchDelete } from '/@/hooks/web/useBatchDelete'; | ||
| 115 | + import { Authority } from '/@/components/Authority'; | ||
| 116 | + import { getAuthCache } from '/@/utils/auth'; | ||
| 117 | + import { USER_INFO_KEY } from '/@/enums/cacheEnum'; | ||
| 118 | + import { isAdmin } from '/@/enums/roleEnum'; | ||
| 119 | + import { TenantListItemRecord } from '/@/api/tenant/tenantInfo'; | ||
| 120 | + import { useFastEnter } from '/@/hooks/business/useFastEnter'; | ||
| 121 | + import { clearUserPassword } from '/@/api/system/system'; | ||
| 122 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
| 123 | + | ||
| 124 | + export default defineComponent({ | ||
| 125 | + name: 'AccountManagement', | ||
| 126 | + components: { | ||
| 127 | + BasicTable, | ||
| 128 | + PageWrapper, | ||
| 129 | + OrganizationIdTree, | ||
| 130 | + AccountModal, | ||
| 131 | + TableAction, | ||
| 132 | + Tag, | ||
| 133 | + Authority, | ||
| 134 | + Popconfirm, | ||
| 135 | + }, | ||
| 136 | + setup() { | ||
| 137 | + const { createMessage } = useMessage(); | ||
| 138 | + const userInfo: any = getAuthCache(USER_INFO_KEY); | ||
| 139 | + const role: string = userInfo?.roles[0]; | ||
| 140 | + | ||
| 141 | + const go = useGo(); | ||
| 142 | + const [registerModal, { openModal }] = useModal(); | ||
| 143 | + let searchInfo = reactive<Recordable>({}); | ||
| 144 | + const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo); | ||
| 145 | + const [registerTable, { reload, setProps }] = useTable({ | ||
| 146 | + title: '账号列表', | ||
| 147 | + api: getAccountList, | ||
| 148 | + rowKey: 'id', | ||
| 149 | + columns, | ||
| 150 | + searchInfo, | ||
| 151 | + formConfig: { | ||
| 152 | + labelWidth: 120, | ||
| 153 | + schemas: searchFormSchema, | ||
| 154 | + // autoSubmitOnEnter: true, | ||
| 155 | + resetFunc: resetFn, | ||
| 156 | + }, | ||
| 157 | + useSearchForm: true, | ||
| 158 | + showTableSetting: true, | ||
| 159 | + bordered: true, | ||
| 160 | + actionColumn: { | ||
| 161 | + width: 240, | ||
| 162 | + title: '操作', | ||
| 163 | + dataIndex: 'action', | ||
| 164 | + slots: { customRender: 'action' }, | ||
| 165 | + fixed: 'right', | ||
| 166 | + }, | ||
| 167 | + }); | ||
| 168 | + const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions } = useBatchDelete( | ||
| 169 | + deleteUser, | ||
| 170 | + handleSuccess, | ||
| 171 | + setProps | ||
| 172 | + ); | ||
| 173 | + nextTick(() => { | ||
| 174 | + setProps(selectionOptions); | ||
| 175 | + }); | ||
| 176 | + | ||
| 177 | + function handleCreate() { | ||
| 178 | + openModal(true, { | ||
| 179 | + isUpdate: false, | ||
| 180 | + }); | ||
| 181 | + } | ||
| 182 | + function handleEdit(record: Recordable) { | ||
| 183 | + openModal(true, { | ||
| 184 | + record, | ||
| 185 | + isUpdate: true, | ||
| 186 | + }); | ||
| 187 | + } | ||
| 188 | + function handleSuccess() { | ||
| 189 | + reload(); | ||
| 190 | + } | ||
| 191 | + | ||
| 192 | + function handleSelect(organization) { | ||
| 193 | + searchInfo.organizationId = organization; | ||
| 194 | + reload(); | ||
| 195 | + } | ||
| 196 | + | ||
| 197 | + function handleView(record: Recordable) { | ||
| 198 | + go('/system/account_detail/' + record.id); | ||
| 199 | + } | ||
| 200 | + | ||
| 201 | + async function handleLoginCustomAdmin(record: TenantListItemRecord) { | ||
| 202 | + try { | ||
| 203 | + useFastEnter(record, go); | ||
| 204 | + } catch (error) { | ||
| 205 | + } finally { | ||
| 206 | + } | ||
| 207 | + } | ||
| 208 | + | ||
| 209 | + const handleClearPassword = async (record: Recordable) => { | ||
| 210 | + const { id } = record; | ||
| 211 | + if (!id) return; | ||
| 212 | + const { message } = await clearUserPassword(id); | ||
| 213 | + createMessage.success(message); | ||
| 214 | + }; | ||
| 215 | + | ||
| 216 | + return { | ||
| 217 | + handleLoginCustomAdmin, | ||
| 218 | + registerTable, | ||
| 219 | + registerModal, | ||
| 220 | + handleCreate, | ||
| 221 | + handleEdit, | ||
| 222 | + handleSuccess, | ||
| 223 | + handleSelect, | ||
| 224 | + handleView, | ||
| 225 | + organizationIdTreeRef, | ||
| 226 | + hasBatchDelete, | ||
| 227 | + handleDeleteOrBatchDelete, | ||
| 228 | + isAdmin, | ||
| 229 | + role, | ||
| 230 | + handleClearPassword, | ||
| 231 | + }; | ||
| 232 | + }, | ||
| 233 | + }); | ||
| 234 | +</script> |
src/views/system/account/tenant/config.ts
0 → 100644
| 1 | +import { BasicColumn, FormSchema } from '/@/components/Table'; | ||
| 2 | + | ||
| 3 | +export const searchFormSchema: FormSchema[] = [ | ||
| 4 | + { | ||
| 5 | + field: 'roleName', | ||
| 6 | + label: '角色名称', | ||
| 7 | + component: 'Input', | ||
| 8 | + colProps: { span: 6 }, | ||
| 9 | + componentProps: { | ||
| 10 | + maxLength: 255, | ||
| 11 | + }, | ||
| 12 | + }, | ||
| 13 | + { | ||
| 14 | + field: 'status', | ||
| 15 | + label: '状态', | ||
| 16 | + component: 'Select', | ||
| 17 | + componentProps: { | ||
| 18 | + options: [ | ||
| 19 | + { label: '启用', value: 1 }, | ||
| 20 | + { label: '停用', value: 0 }, | ||
| 21 | + ], | ||
| 22 | + }, | ||
| 23 | + colProps: { span: 6 }, | ||
| 24 | + }, | ||
| 25 | +]; | ||
| 26 | + | ||
| 27 | +export const columns: BasicColumn[] = [ | ||
| 28 | + { | ||
| 29 | + title: '角色名称', | ||
| 30 | + dataIndex: 'name', | ||
| 31 | + width: 200, | ||
| 32 | + }, | ||
| 33 | + { | ||
| 34 | + title: '角色Code', | ||
| 35 | + dataIndex: 'code', | ||
| 36 | + width: 200, | ||
| 37 | + }, | ||
| 38 | + { | ||
| 39 | + title: '状态', | ||
| 40 | + dataIndex: 'status', | ||
| 41 | + width: 120, | ||
| 42 | + slots: { customRender: 'status' }, | ||
| 43 | + }, | ||
| 44 | + | ||
| 45 | + { | ||
| 46 | + title: '备注', | ||
| 47 | + dataIndex: 'remark', | ||
| 48 | + width: 240, | ||
| 49 | + }, | ||
| 50 | + { | ||
| 51 | + title: '创建时间', | ||
| 52 | + dataIndex: 'createTime', | ||
| 53 | + width: 180, | ||
| 54 | + }, | ||
| 55 | +]; |
src/views/system/account/tenant/index.vue
0 → 100644
src/views/system/role/custom/RoleDrawer.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <BasicDrawer | ||
| 3 | + v-bind="$attrs" | ||
| 4 | + @register="registerDrawer" | ||
| 5 | + showFooter | ||
| 6 | + :title="getTitle" | ||
| 7 | + width="500px" | ||
| 8 | + @ok="handleSubmit" | ||
| 9 | + > | ||
| 10 | + <BasicForm @register="registerForm"> | ||
| 11 | + <template #menu> | ||
| 12 | + <Spin :spinning="spinning"> | ||
| 13 | + <BasicTree | ||
| 14 | + v-if="treeData.length" | ||
| 15 | + checkable | ||
| 16 | + toolbar | ||
| 17 | + ref="treeRef" | ||
| 18 | + :treeData="treeData" | ||
| 19 | + @check="handleCheckClick" | ||
| 20 | + :replace-fields="{ title: 'name', key: 'id' }" | ||
| 21 | + :checkedKeys="roleMenus" | ||
| 22 | + title="菜单分配" | ||
| 23 | + /> | ||
| 24 | + </Spin> | ||
| 25 | + </template> | ||
| 26 | + </BasicForm> | ||
| 27 | + </BasicDrawer> | ||
| 28 | +</template> | ||
| 29 | +<script lang="ts"> | ||
| 30 | + import { defineComponent, ref, computed, unref, nextTick } from 'vue'; | ||
| 31 | + import { BasicForm, useForm } from '/@/components/Form/index'; | ||
| 32 | + import { formSchema, KeysTypeEnum, RoleMenuDictEnum } from './role.data'; | ||
| 33 | + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; | ||
| 34 | + import { BasicTree, TreeActionType, TreeItem } from '/@/components/Tree'; | ||
| 35 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
| 36 | + const { t } = useI18n(); // 加载国际化 | ||
| 37 | + // 加载菜单数据 | ||
| 38 | + import { getMeMenuList, getMenusIdsByRoleId } from '/@/api/sys/menu'; | ||
| 39 | + import { useI18n } from '/@/hooks/web/useI18n'; | ||
| 40 | + import { MenuRecord } from '/@/api/sys/model/menuModel'; | ||
| 41 | + import { saveOrUpdateRoleInfoWithMenu } from '/@/api/system/system'; | ||
| 42 | + import { findDictItemByCode } from '/@/api/system/dict'; | ||
| 43 | + import { RoleEnum } from '/@/enums/roleEnum'; | ||
| 44 | + import { Spin } from 'ant-design-vue'; | ||
| 45 | + import { useRole } from '/@/hooks/business/useRole'; | ||
| 46 | + import { RoleListItem } from '/@/api/system/model/systemModel'; | ||
| 47 | + | ||
| 48 | + type TreeData = MenuRecord & TreeItem; | ||
| 49 | + | ||
| 50 | + export default defineComponent({ | ||
| 51 | + name: 'RoleDrawer', | ||
| 52 | + components: { BasicDrawer, BasicForm, BasicTree, Spin }, | ||
| 53 | + emits: ['success', 'register'], | ||
| 54 | + setup(_, { emit }) { | ||
| 55 | + const isUpdate = ref<boolean>(true); | ||
| 56 | + const treeData = ref<TreeData[]>([]); | ||
| 57 | + const roleMenus = ref<string[]>([]); | ||
| 58 | + const roleId = ref<string>(''); | ||
| 59 | + const treeRef = ref<Nullable<TreeActionType>>(); | ||
| 60 | + const checked = ref<string[]>([]); //需要选中的节点 | ||
| 61 | + const spinning = ref(false); | ||
| 62 | + const checkedKeysWithHalfChecked = ref<string[]>([]); | ||
| 63 | + | ||
| 64 | + const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({ | ||
| 65 | + labelWidth: 100, | ||
| 66 | + schemas: formSchema, | ||
| 67 | + showActionButtonGroup: false, | ||
| 68 | + }); | ||
| 69 | + | ||
| 70 | + const transformName = (data: TreeData[]) => { | ||
| 71 | + return data.map((item) => { | ||
| 72 | + item.name = t(item.name); | ||
| 73 | + if (item.children && item.children.length) { | ||
| 74 | + item.children = transformName(item.children as unknown as TreeData[]); | ||
| 75 | + } | ||
| 76 | + return item; | ||
| 77 | + }); | ||
| 78 | + }; | ||
| 79 | + | ||
| 80 | + const { isTenantAdmin, isSysadmin, getRole } = useRole(); | ||
| 81 | + const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner( | ||
| 82 | + async (data: { isUpdate: boolean; record: RoleListItem }) => { | ||
| 83 | + resetFields(); | ||
| 84 | + roleId.value = ''; | ||
| 85 | + // 在打开弹窗时清除所有选择的菜单 | ||
| 86 | + treeRef.value && treeRef.value?.setCheckedKeys([]); | ||
| 87 | + isUpdate.value = data.isUpdate; | ||
| 88 | + let roleType = unref(getRole) || RoleEnum.SYS_ADMIN; | ||
| 89 | + | ||
| 90 | + // 租户管理员创建角色时 菜单分配为客户菜单 | ||
| 91 | + if (unref(isTenantAdmin)) { | ||
| 92 | + roleType = RoleEnum.CUSTOMER_USER; | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + try { | ||
| 96 | + spinning.value = true; | ||
| 97 | + // 需要在setFieldsValue之前先填充treeData,否则Tree组件可能会报key not exist警告 | ||
| 98 | + | ||
| 99 | + // if (!unref(treeData).length) { | ||
| 100 | + // 获取全部的菜单 | ||
| 101 | + const menuListModel = await getMeMenuList(); | ||
| 102 | + treeData.value = transformName(menuListModel as unknown as TreeData[]); | ||
| 103 | + // } | ||
| 104 | + | ||
| 105 | + const keys = await getPermissionByRole(roleType); | ||
| 106 | + const { keyType } = RoleMenuDictEnum[roleType]; | ||
| 107 | + treeData.value = filterPermissionTreeData( | ||
| 108 | + unref(treeData) as unknown as TreeData[], | ||
| 109 | + keys, | ||
| 110 | + keyType | ||
| 111 | + ); | ||
| 112 | + | ||
| 113 | + // 如果编辑的是超级管理员 则不再过滤平台管理员禁用的权限 | ||
| 114 | + // 如果是超级管理员创建角色 创建角色属于平台管理员 因此过滤平台管理员禁用的权限 | ||
| 115 | + if (data?.record?.roleType !== RoleEnum.SYS_ADMIN && unref(isSysadmin)) { | ||
| 116 | + const keys = await getPermissionByRole(RoleEnum.PLATFORM_ADMIN); | ||
| 117 | + const { keyType } = RoleMenuDictEnum[RoleEnum.PLATFORM_ADMIN]; | ||
| 118 | + treeData.value = filterPermissionTreeData( | ||
| 119 | + unref(treeData) as unknown as TreeData[], | ||
| 120 | + keys, | ||
| 121 | + keyType | ||
| 122 | + ); | ||
| 123 | + } | ||
| 124 | + | ||
| 125 | + // 更新 | ||
| 126 | + if (unref(isUpdate)) { | ||
| 127 | + checked.value = []; | ||
| 128 | + roleId.value = data.record.id; | ||
| 129 | + | ||
| 130 | + //通过角色id去获取角色对应的菜单的ids | ||
| 131 | + checkedKeysWithHalfChecked.value = roleMenus.value = await getMenusIdsByRoleId( | ||
| 132 | + data.record.id | ||
| 133 | + ); | ||
| 134 | + excludeHalfCheckedKeys(unref(treeData)); | ||
| 135 | + await nextTick(); | ||
| 136 | + unref(treeRef)?.setCheckedKeys(roleMenus.value); | ||
| 137 | + setFieldsValue(data.record); | ||
| 138 | + } else { | ||
| 139 | + } | ||
| 140 | + } catch (error) { | ||
| 141 | + throw error; | ||
| 142 | + } finally { | ||
| 143 | + spinning.value = false; | ||
| 144 | + } | ||
| 145 | + } | ||
| 146 | + ); | ||
| 147 | + | ||
| 148 | + const getTitle = computed(() => (!unref(isUpdate) ? '新增角色' : '编辑角色')); | ||
| 149 | + | ||
| 150 | + async function handleSubmit() { | ||
| 151 | + setDrawerProps({ confirmLoading: true }); | ||
| 152 | + const { createMessage } = useMessage(); | ||
| 153 | + try { | ||
| 154 | + const values = await validate(); | ||
| 155 | + const treeCheckedKeys: string[] = (unref(treeRef)?.getCheckedKeys() as string[]) || []; | ||
| 156 | + const menu = [...new Set([...unref(checkedKeysWithHalfChecked), ...treeCheckedKeys])]; | ||
| 157 | + const req = { | ||
| 158 | + id: roleId.value, | ||
| 159 | + name: values.name, | ||
| 160 | + remark: values.remark, | ||
| 161 | + status: values.status, | ||
| 162 | + menu, | ||
| 163 | + }; | ||
| 164 | + if (req.menu == undefined) return createMessage.error('请勾选权限菜单'); | ||
| 165 | + saveOrUpdateRoleInfoWithMenu(req).then(() => { | ||
| 166 | + closeDrawer(); | ||
| 167 | + emit('success'); | ||
| 168 | + createMessage.success(`${unref(isUpdate) ? '编辑' : '新增'}成功`); | ||
| 169 | + }); | ||
| 170 | + } finally { | ||
| 171 | + setTimeout(() => { | ||
| 172 | + setDrawerProps({ confirmLoading: false }); | ||
| 173 | + }, 300); | ||
| 174 | + } | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + const getPermissionByRole = async (roleType: RoleEnum) => { | ||
| 178 | + try { | ||
| 179 | + const { key } = RoleMenuDictEnum[roleType]; | ||
| 180 | + const res = await findDictItemByCode({ dictCode: key }); | ||
| 181 | + return res.map((item) => item.itemValue); | ||
| 182 | + } catch (error) {} | ||
| 183 | + return []; | ||
| 184 | + }; | ||
| 185 | + | ||
| 186 | + const filterPermissionTreeData = ( | ||
| 187 | + data: MenuRecord[], | ||
| 188 | + permissionKeys: string[], | ||
| 189 | + keysType: KeysTypeEnum | ||
| 190 | + ): TreeData[] => { | ||
| 191 | + const permissionCompare = ( | ||
| 192 | + data: MenuRecord[], | ||
| 193 | + permissionKeys: string[], | ||
| 194 | + keysType: KeysTypeEnum | ||
| 195 | + ): TreeData[] => { | ||
| 196 | + return data.filter((item) => { | ||
| 197 | + item.name = t(item.name); | ||
| 198 | + const findFlag = permissionKeys.includes(item.permission); | ||
| 199 | + | ||
| 200 | + item.show = findFlag ? keysType === KeysTypeEnum.ENABLED : undefined; | ||
| 201 | + | ||
| 202 | + if (item.children && item.children.length) { | ||
| 203 | + if (item.show) return true; | ||
| 204 | + if (item.show === undefined) { | ||
| 205 | + item.children = permissionCompare(item.children, permissionKeys, keysType); | ||
| 206 | + item.show = item.children.some((item) => | ||
| 207 | + keysType === KeysTypeEnum.ENABLED | ||
| 208 | + ? item.show | ||
| 209 | + : item.show === undefined | ||
| 210 | + ? true | ||
| 211 | + : item.show | ||
| 212 | + ); | ||
| 213 | + return item.show; | ||
| 214 | + } | ||
| 215 | + } | ||
| 216 | + | ||
| 217 | + return keysType === KeysTypeEnum.ENABLED | ||
| 218 | + ? item.show | ||
| 219 | + : item.show === undefined | ||
| 220 | + ? true | ||
| 221 | + : item.show; | ||
| 222 | + }) as unknown as TreeData[]; | ||
| 223 | + }; | ||
| 224 | + | ||
| 225 | + return permissionCompare(data, permissionKeys, keysType); | ||
| 226 | + }; | ||
| 227 | + | ||
| 228 | + const excludeHalfCheckedKeys = (treeData: MenuRecord[]) => { | ||
| 229 | + const needExcludeKeys: string[] = []; | ||
| 230 | + const query = (data: MenuRecord[]) => { | ||
| 231 | + data.forEach((item) => { | ||
| 232 | + item.checked = roleMenus.value.includes(item.id); | ||
| 233 | + if (item.children && item.children.length) { | ||
| 234 | + query(item.children); | ||
| 235 | + item.checked = item.children.every((item) => item.checked); | ||
| 236 | + } | ||
| 237 | + if (!item.checked) { | ||
| 238 | + needExcludeKeys.push(item.id); | ||
| 239 | + } | ||
| 240 | + }); | ||
| 241 | + }; | ||
| 242 | + query(treeData); | ||
| 243 | + roleMenus.value = unref(roleMenus).filter((key) => !needExcludeKeys.includes(key)); | ||
| 244 | + return needExcludeKeys; | ||
| 245 | + }; | ||
| 246 | + | ||
| 247 | + const handleCheckClick = (selectedKeys: string[], event: CheckEvent) => { | ||
| 248 | + checkedKeysWithHalfChecked.value = [ | ||
| 249 | + ...selectedKeys, | ||
| 250 | + ...(event.halfCheckedKeys as string[]), | ||
| 251 | + ]; | ||
| 252 | + }; | ||
| 253 | + | ||
| 254 | + return { | ||
| 255 | + spinning, | ||
| 256 | + registerDrawer, | ||
| 257 | + registerForm, | ||
| 258 | + getTitle, | ||
| 259 | + handleSubmit, | ||
| 260 | + treeData, | ||
| 261 | + roleMenus, | ||
| 262 | + treeRef, | ||
| 263 | + handleCheckClick, | ||
| 264 | + }; | ||
| 265 | + }, | ||
| 266 | + }); | ||
| 267 | +</script> | ||
| 268 | + | ||
| 269 | +<style scoped lang="less"> | ||
| 270 | + :deep(.vben-basic-tree) { | ||
| 271 | + width: 100% !important; | ||
| 272 | + } | ||
| 273 | + | ||
| 274 | + :deep(.is-unflod) { | ||
| 275 | + display: none !important; | ||
| 276 | + } | ||
| 277 | + | ||
| 278 | + :deep(.is-flod) { | ||
| 279 | + display: none !important; | ||
| 280 | + } | ||
| 281 | +</style> |
src/views/system/role/custom/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div> | ||
| 3 | + <BasicTable | ||
| 4 | + :rowSelection="{ type: 'checkbox' }" | ||
| 5 | + @register="registerTable" | ||
| 6 | + :clickToRowSelect="false" | ||
| 7 | + > | ||
| 8 | + <template #toolbar> | ||
| 9 | + <Authority value="api:yt:role:saveOrUpdateRoleInfoWithMenu:post"> | ||
| 10 | + <a-button type="primary" @click="handleCreate">新增角色</a-button> | ||
| 11 | + </Authority> | ||
| 12 | + <Authority value="api:yt:role:delete"> | ||
| 13 | + <Popconfirm | ||
| 14 | + title="您确定要批量删除数据" | ||
| 15 | + ok-text="确定" | ||
| 16 | + cancel-text="取消" | ||
| 17 | + @confirm="handleDeleteOrBatchDelete(null)" | ||
| 18 | + > | ||
| 19 | + <a-button type="primary" color="error" :disabled="hasBatchDelete"> 批量删除 </a-button> | ||
| 20 | + </Popconfirm> | ||
| 21 | + </Authority> | ||
| 22 | + </template> | ||
| 23 | + <template #status="{ record }"> | ||
| 24 | + <Authority value="api:yt:role:saveOrUpdateRoleInfoWithMenu:update"> | ||
| 25 | + <Switch | ||
| 26 | + :checked="record.status === 1" | ||
| 27 | + :loading="record.pendingStatus" | ||
| 28 | + checkedChildren="启用" | ||
| 29 | + unCheckedChildren="禁用" | ||
| 30 | + @change="(checked:boolean)=>statusChange(checked,record)" | ||
| 31 | + /> | ||
| 32 | + </Authority> | ||
| 33 | + <Tag | ||
| 34 | + v-if="!hasPermission('api:yt:role:saveOrUpdateRoleInfoWithMenu:update')" | ||
| 35 | + :color="record.status ? 'green' : 'red'" | ||
| 36 | + > | ||
| 37 | + {{ record.status ? '启用' : '禁用' }} | ||
| 38 | + </Tag> | ||
| 39 | + </template> | ||
| 40 | + <template #action="{ record }"> | ||
| 41 | + <TableAction | ||
| 42 | + :actions="[ | ||
| 43 | + { | ||
| 44 | + label: '编辑', | ||
| 45 | + auth: 'api:yt:role:saveOrUpdateRoleInfoWithMenu:update', | ||
| 46 | + icon: 'clarity:note-edit-line', | ||
| 47 | + onClick: handleEdit.bind(null, record), | ||
| 48 | + }, | ||
| 49 | + { | ||
| 50 | + label: '删除', | ||
| 51 | + auth: 'api:yt:role:delete', | ||
| 52 | + icon: 'ant-design:delete-outlined', | ||
| 53 | + color: 'error', | ||
| 54 | + ifShow: record.roleType != RoleEnum.SYS_ADMIN, | ||
| 55 | + popConfirm: { | ||
| 56 | + title: '是否确认删除', | ||
| 57 | + confirm: handleDeleteOrBatchDelete.bind(null, record), | ||
| 58 | + }, | ||
| 59 | + }, | ||
| 60 | + ]" | ||
| 61 | + /> | ||
| 62 | + </template> | ||
| 63 | + </BasicTable> | ||
| 64 | + <RoleDrawer @register="registerDrawer" @success="handleSuccess" /> | ||
| 65 | + </div> | ||
| 66 | +</template> | ||
| 67 | +<script lang="ts"> | ||
| 68 | + import { defineComponent, nextTick } from 'vue'; | ||
| 69 | + import { BasicTable, useTable, TableAction } from '/@/components/Table'; | ||
| 70 | + import { delRole, getRoleListByPage, setRoleStatus } from '/@/api/system/system'; | ||
| 71 | + import { useDrawer } from '/@/components/Drawer'; | ||
| 72 | + import RoleDrawer from './RoleDrawer.vue'; | ||
| 73 | + import { columns, searchFormSchema } from './role.data'; | ||
| 74 | + import { RoleEnum } from '/@/enums/roleEnum'; | ||
| 75 | + import { Authority } from '/@/components/Authority'; | ||
| 76 | + import { useBatchDelete } from '/@/hooks/web/useBatchDelete'; | ||
| 77 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
| 78 | + import { Switch, Popconfirm, Tag } from 'ant-design-vue'; | ||
| 79 | + import { usePermission } from '/@/hooks/web/usePermission'; | ||
| 80 | + | ||
| 81 | + export default defineComponent({ | ||
| 82 | + name: 'RoleManagement', | ||
| 83 | + components: { BasicTable, RoleDrawer, TableAction, Authority, Switch, Popconfirm, Tag }, | ||
| 84 | + setup() { | ||
| 85 | + const { hasPermission } = usePermission(); | ||
| 86 | + const [registerDrawer, { openDrawer }] = useDrawer(); | ||
| 87 | + function handleSuccess() { | ||
| 88 | + reload(); | ||
| 89 | + } | ||
| 90 | + const [registerTable, { setProps, reload, setSelectedRowKeys }] = useTable({ | ||
| 91 | + title: '客户角色列表', | ||
| 92 | + api: getRoleListByPage, | ||
| 93 | + columns, | ||
| 94 | + formConfig: { | ||
| 95 | + labelWidth: 120, | ||
| 96 | + schemas: searchFormSchema, | ||
| 97 | + }, | ||
| 98 | + useSearchForm: true, | ||
| 99 | + showTableSetting: true, | ||
| 100 | + bordered: true, | ||
| 101 | + showIndexColumn: false, | ||
| 102 | + actionColumn: { | ||
| 103 | + width: 200, | ||
| 104 | + title: '操作', | ||
| 105 | + dataIndex: 'action', | ||
| 106 | + slots: { customRender: 'action' }, | ||
| 107 | + fixed: 'right', | ||
| 108 | + }, | ||
| 109 | + }); | ||
| 110 | + const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions, resetSelectedRowKeys } = | ||
| 111 | + useBatchDelete(delRole, handleSuccess, setProps); | ||
| 112 | + selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => { | ||
| 113 | + // Demo:status为1的选择框禁用 | ||
| 114 | + if (record.status === 1) { | ||
| 115 | + return { disabled: true }; | ||
| 116 | + } else { | ||
| 117 | + return { disabled: false }; | ||
| 118 | + } | ||
| 119 | + }; | ||
| 120 | + nextTick(() => { | ||
| 121 | + setProps(selectionOptions); | ||
| 122 | + }); | ||
| 123 | + | ||
| 124 | + function handleCreate() { | ||
| 125 | + openDrawer(true, { | ||
| 126 | + isUpdate: false, | ||
| 127 | + }); | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + function handleEdit(record: Recordable) { | ||
| 131 | + openDrawer(true, { | ||
| 132 | + record, | ||
| 133 | + isUpdate: true, | ||
| 134 | + }); | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + const statusChange = async (checked, record) => { | ||
| 138 | + setProps({ | ||
| 139 | + loading: true, | ||
| 140 | + }); | ||
| 141 | + setSelectedRowKeys([]); | ||
| 142 | + resetSelectedRowKeys(); | ||
| 143 | + const newStatus = checked ? 1 : 0; | ||
| 144 | + const { createMessage } = useMessage(); | ||
| 145 | + try { | ||
| 146 | + await setRoleStatus(record.id, newStatus); | ||
| 147 | + if (newStatus) { | ||
| 148 | + createMessage.success(`启用成功`); | ||
| 149 | + } else { | ||
| 150 | + createMessage.success('禁用成功'); | ||
| 151 | + } | ||
| 152 | + } finally { | ||
| 153 | + setProps({ | ||
| 154 | + loading: false, | ||
| 155 | + }); | ||
| 156 | + reload(); | ||
| 157 | + } | ||
| 158 | + }; | ||
| 159 | + | ||
| 160 | + return { | ||
| 161 | + registerTable, | ||
| 162 | + registerDrawer, | ||
| 163 | + handleCreate, | ||
| 164 | + handleEdit, | ||
| 165 | + handleSuccess, | ||
| 166 | + RoleEnum, | ||
| 167 | + hasBatchDelete, | ||
| 168 | + handleDeleteOrBatchDelete, | ||
| 169 | + statusChange, | ||
| 170 | + hasPermission, | ||
| 171 | + }; | ||
| 172 | + }, | ||
| 173 | + }); | ||
| 174 | +</script> |
src/views/system/role/custom/role.data.ts
0 → 100644
| 1 | +import { BasicColumn } from '/@/components/Table'; | ||
| 2 | +import { FormSchema } from '/@/components/Table'; | ||
| 3 | +import { DictEnum } from '/@/enums/dictEnum'; | ||
| 4 | +import { RoleEnum } from '/@/enums/roleEnum'; | ||
| 5 | + | ||
| 6 | +export enum KeysTypeEnum { | ||
| 7 | + DISABLED = 'disabled', | ||
| 8 | + ENABLED = 'enabled', | ||
| 9 | +} | ||
| 10 | + | ||
| 11 | +export const RoleMenuDictEnum: Recordable<{ key: string; keyType: KeysTypeEnum }> = { | ||
| 12 | + [RoleEnum.PLATFORM_ADMIN]: { | ||
| 13 | + key: DictEnum.DISABLED_PLATFORM_ADMIN_AUTH, | ||
| 14 | + keyType: KeysTypeEnum.DISABLED, | ||
| 15 | + }, | ||
| 16 | + [RoleEnum.SYS_ADMIN]: { key: DictEnum.ENABLED_SYSADMIN_AUTH, keyType: KeysTypeEnum.ENABLED }, | ||
| 17 | + [RoleEnum.TENANT_ADMIN]: { key: DictEnum.DISABLED_TENANT_AUTH, keyType: KeysTypeEnum.DISABLED }, | ||
| 18 | + [RoleEnum.CUSTOMER_USER]: { key: DictEnum.DISABLE_CUSTOMER_AUTH, keyType: KeysTypeEnum.DISABLED }, | ||
| 19 | +}; | ||
| 20 | + | ||
| 21 | +export const columns: BasicColumn[] = [ | ||
| 22 | + { | ||
| 23 | + title: '角色名称', | ||
| 24 | + dataIndex: 'name', | ||
| 25 | + width: 200, | ||
| 26 | + }, | ||
| 27 | + { | ||
| 28 | + title: '角色Code', | ||
| 29 | + dataIndex: 'code', | ||
| 30 | + width: 200, | ||
| 31 | + }, | ||
| 32 | + { | ||
| 33 | + title: '状态', | ||
| 34 | + dataIndex: 'status', | ||
| 35 | + width: 120, | ||
| 36 | + slots: { customRender: 'status' }, | ||
| 37 | + }, | ||
| 38 | + | ||
| 39 | + { | ||
| 40 | + title: '备注', | ||
| 41 | + dataIndex: 'remark', | ||
| 42 | + width: 240, | ||
| 43 | + }, | ||
| 44 | + { | ||
| 45 | + title: '创建时间', | ||
| 46 | + dataIndex: 'createTime', | ||
| 47 | + width: 180, | ||
| 48 | + }, | ||
| 49 | +]; | ||
| 50 | + | ||
| 51 | +export const searchFormSchema: FormSchema[] = [ | ||
| 52 | + { | ||
| 53 | + field: 'roleName', | ||
| 54 | + label: '角色名称', | ||
| 55 | + component: 'Input', | ||
| 56 | + colProps: { span: 6 }, | ||
| 57 | + componentProps: { | ||
| 58 | + maxLength: 255, | ||
| 59 | + }, | ||
| 60 | + }, | ||
| 61 | + { | ||
| 62 | + field: 'status', | ||
| 63 | + label: '状态', | ||
| 64 | + component: 'Select', | ||
| 65 | + componentProps: { | ||
| 66 | + options: [ | ||
| 67 | + { label: '启用', value: 1 }, | ||
| 68 | + { label: '停用', value: 0 }, | ||
| 69 | + ], | ||
| 70 | + }, | ||
| 71 | + colProps: { span: 6 }, | ||
| 72 | + }, | ||
| 73 | +]; | ||
| 74 | + | ||
| 75 | +export const formSchema: FormSchema[] = [ | ||
| 76 | + { | ||
| 77 | + field: 'name', | ||
| 78 | + label: '角色名称', | ||
| 79 | + required: true, | ||
| 80 | + component: 'Input', | ||
| 81 | + componentProps: { | ||
| 82 | + maxLength: 255, | ||
| 83 | + placeholder: '请输入角色名称', | ||
| 84 | + }, | ||
| 85 | + }, | ||
| 86 | + { | ||
| 87 | + field: 'status', | ||
| 88 | + label: '状态', | ||
| 89 | + component: 'RadioButtonGroup', | ||
| 90 | + defaultValue: 1, | ||
| 91 | + componentProps: { | ||
| 92 | + options: [ | ||
| 93 | + { label: '启用', value: 1 }, | ||
| 94 | + { label: '停用', value: 0 }, | ||
| 95 | + ], | ||
| 96 | + }, | ||
| 97 | + }, | ||
| 98 | + { | ||
| 99 | + label: '备注', | ||
| 100 | + field: 'remark', | ||
| 101 | + component: 'InputTextArea', | ||
| 102 | + componentProps: { | ||
| 103 | + maxLength: 255, | ||
| 104 | + placeholder: '请输入备注', | ||
| 105 | + }, | ||
| 106 | + }, | ||
| 107 | + { | ||
| 108 | + label: '', | ||
| 109 | + field: 'menu', | ||
| 110 | + slot: 'menu', | ||
| 111 | + component: 'Input', | ||
| 112 | + }, | ||
| 113 | +]; |
| @@ -88,7 +88,7 @@ | @@ -88,7 +88,7 @@ | ||
| 88 | reload(); | 88 | reload(); |
| 89 | } | 89 | } |
| 90 | const [registerTable, { setProps, reload, setSelectedRowKeys }] = useTable({ | 90 | const [registerTable, { setProps, reload, setSelectedRowKeys }] = useTable({ |
| 91 | - title: '角色列表', | 91 | + title: '客户角色列表', |
| 92 | api: getRoleListByPage, | 92 | api: getRoleListByPage, |
| 93 | columns, | 93 | columns, |
| 94 | formConfig: { | 94 | formConfig: { |
src/views/system/role/tenant/RoleDrawer.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <BasicDrawer | ||
| 3 | + v-bind="$attrs" | ||
| 4 | + @register="registerDrawer" | ||
| 5 | + showFooter | ||
| 6 | + :title="getTitle" | ||
| 7 | + width="500px" | ||
| 8 | + @ok="handleSubmit" | ||
| 9 | + > | ||
| 10 | + <BasicForm @register="registerForm"> | ||
| 11 | + <template #menu> | ||
| 12 | + <Spin :spinning="spinning"> | ||
| 13 | + <BasicTree | ||
| 14 | + v-if="treeData.length" | ||
| 15 | + :treeData="treeData" | ||
| 16 | + :replaceFields="{ title: 'name', key: 'id' }" | ||
| 17 | + :checkedKeys="roleMenus" | ||
| 18 | + @check="handleCheckClick" | ||
| 19 | + @unSelectAll="handleUnSelectAll" | ||
| 20 | + checkable | ||
| 21 | + toolbar | ||
| 22 | + ref="treeRef" | ||
| 23 | + title="权限分配" | ||
| 24 | + /> | ||
| 25 | + </Spin> | ||
| 26 | + </template> | ||
| 27 | + </BasicForm> | ||
| 28 | + </BasicDrawer> | ||
| 29 | +</template> | ||
| 30 | +<script lang="ts"> | ||
| 31 | + import { defineComponent, ref, computed, unref, nextTick } from 'vue'; | ||
| 32 | + import { BasicForm, useForm } from '/@/components/Form/index'; | ||
| 33 | + import { formSchema } from './role.data'; | ||
| 34 | + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; | ||
| 35 | + import { BasicTree, CheckEvent, TreeActionType, TreeItem, CheckKeys } from '/@/components/Tree'; | ||
| 36 | + const { t } = useI18n(); // 加载国际化 | ||
| 37 | + // 加载菜单数据 | ||
| 38 | + import { getAdminMenuList, getMenuList, getMenusIdsByRoleId } from '/@/api/sys/menu'; | ||
| 39 | + import { useI18n } from '/@/hooks/web/useI18n'; | ||
| 40 | + import { MenuRecord } from '/@/api/sys/model/menuModel'; | ||
| 41 | + import { saveOrUpdateRoleInfoWithMenu } from '/@/api/system/system'; | ||
| 42 | + import { RoleEnum } from '/@/enums/roleEnum'; | ||
| 43 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
| 44 | + import { findDictItemByCode } from '/@/api/system/dict'; | ||
| 45 | + import { Spin } from 'ant-design-vue'; | ||
| 46 | + import { useRole } from '/@/hooks/business/useRole'; | ||
| 47 | + import { RoleMenuDictEnum, KeysTypeEnum } from '../custom/role.data'; | ||
| 48 | + | ||
| 49 | + type TreeData = MenuRecord & TreeItem; | ||
| 50 | + | ||
| 51 | + export default defineComponent({ | ||
| 52 | + name: 'RoleDrawer', | ||
| 53 | + components: { BasicDrawer, BasicForm, BasicTree, Spin }, | ||
| 54 | + emits: ['success', 'register'], | ||
| 55 | + setup(_, { emit }) { | ||
| 56 | + const isUpdate = ref(true); | ||
| 57 | + const treeData = ref<TreeData[]>([]); | ||
| 58 | + const roleMenus = ref<string[]>([]); | ||
| 59 | + const roleId = ref(''); | ||
| 60 | + const treeRef = ref<Nullable<TreeActionType>>(null); | ||
| 61 | + const checked = ref<string[]>([]); //需要选中的节点 | ||
| 62 | + const spinning = ref(false); | ||
| 63 | + const checkedKeysWithHalfChecked = ref<(string | number)[]>([]); | ||
| 64 | + | ||
| 65 | + const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({ | ||
| 66 | + labelWidth: 90, | ||
| 67 | + schemas: formSchema, | ||
| 68 | + showActionButtonGroup: false, | ||
| 69 | + }); | ||
| 70 | + | ||
| 71 | + const transformName = (data: TreeData[]) => { | ||
| 72 | + return data.map((item) => { | ||
| 73 | + item.name = t(item.name); | ||
| 74 | + if (item.children && item.children.length) { | ||
| 75 | + item.children = transformName(item.children as unknown as TreeData[]); | ||
| 76 | + } | ||
| 77 | + return item; | ||
| 78 | + }); | ||
| 79 | + }; | ||
| 80 | + | ||
| 81 | + const { isPlatformAdmin } = useRole(); | ||
| 82 | + const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => { | ||
| 83 | + resetFields(); | ||
| 84 | + roleId.value = ''; | ||
| 85 | + // 在打开弹窗时清除所有选择的菜单 | ||
| 86 | + treeRef.value && treeRef.value?.setCheckedKeys([]); | ||
| 87 | + isUpdate.value = data.isUpdate; | ||
| 88 | + const roleType = RoleEnum.TENANT_ADMIN; | ||
| 89 | + try { | ||
| 90 | + spinning.value = true; | ||
| 91 | + | ||
| 92 | + if (!unref(treeData).length) { | ||
| 93 | + // 获取全部的菜单 | ||
| 94 | + const menuListModel = unref(isPlatformAdmin) | ||
| 95 | + ? await getAdminMenuList() | ||
| 96 | + : await getMenuList(); | ||
| 97 | + treeData.value = transformName(menuListModel as unknown as TreeData[]); | ||
| 98 | + } | ||
| 99 | + const keys = await getPermissionByRole(roleType); | ||
| 100 | + const { keyType } = RoleMenuDictEnum[roleType]; | ||
| 101 | + treeData.value = filterPermissionTreeData( | ||
| 102 | + unref(treeData) as unknown as TreeData[], | ||
| 103 | + keys, | ||
| 104 | + keyType | ||
| 105 | + ); | ||
| 106 | + | ||
| 107 | + // 更新 | ||
| 108 | + if (unref(isUpdate)) { | ||
| 109 | + checked.value = []; | ||
| 110 | + roleId.value = data.record.id; | ||
| 111 | + | ||
| 112 | + //通过角色id去获取角色对应的菜单的ids | ||
| 113 | + checkedKeysWithHalfChecked.value = roleMenus.value = await getMenusIdsByRoleId( | ||
| 114 | + data.record.id | ||
| 115 | + ); | ||
| 116 | + | ||
| 117 | + excludeHalfCheckedKeys(unref(treeData)); | ||
| 118 | + | ||
| 119 | + await nextTick(); | ||
| 120 | + treeRef.value?.setCheckedKeys(roleMenus.value); | ||
| 121 | + setFieldsValue(data.record); | ||
| 122 | + } else { | ||
| 123 | + } | ||
| 124 | + } catch (error) { | ||
| 125 | + throw error; | ||
| 126 | + } finally { | ||
| 127 | + spinning.value = false; | ||
| 128 | + } | ||
| 129 | + }); | ||
| 130 | + const getTitle = computed(() => (!unref(isUpdate) ? '新增角色' : '编辑角色')); | ||
| 131 | + | ||
| 132 | + // 取消全部的时候清除回显时获取的 | ||
| 133 | + const handleUnSelectAll = () => { | ||
| 134 | + checkedKeysWithHalfChecked.value = []; | ||
| 135 | + }; | ||
| 136 | + | ||
| 137 | + async function handleSubmit() { | ||
| 138 | + setDrawerProps({ loading: true, confirmLoading: true }); | ||
| 139 | + const { createMessage } = useMessage(); | ||
| 140 | + let treeCheckedKeys: string[] | CheckKeys = | ||
| 141 | + (unref(treeRef)?.getCheckedKeys() as string[] | CheckKeys) || []; | ||
| 142 | + //fix 取消层级独立后(unref(treeRef)?.getCheckedKeys() as string[])的数据不是数组,是{checked:[],halfChecked:[]}对象,迭代报错 | ||
| 143 | + if (!Array.isArray(treeCheckedKeys)) { | ||
| 144 | + treeCheckedKeys = treeCheckedKeys?.checked; | ||
| 145 | + } | ||
| 146 | + const menu = [...new Set([...unref(checkedKeysWithHalfChecked), ...treeCheckedKeys])]; | ||
| 147 | + try { | ||
| 148 | + const values = await validate(); | ||
| 149 | + const req = { | ||
| 150 | + id: roleId.value, | ||
| 151 | + name: values.name, | ||
| 152 | + remark: values.remark, | ||
| 153 | + status: values.status, | ||
| 154 | + roleType: RoleEnum.TENANT_ADMIN, | ||
| 155 | + menu, | ||
| 156 | + }; | ||
| 157 | + if (req.menu == undefined || !req.menu.length) | ||
| 158 | + return createMessage.error('请勾选权限菜单'); | ||
| 159 | + const res = await saveOrUpdateRoleInfoWithMenu(req); | ||
| 160 | + if (res) { | ||
| 161 | + closeDrawer(); | ||
| 162 | + emit('success'); | ||
| 163 | + createMessage.success(`${unref(isUpdate) ? '编辑' : '新增'}成功`); | ||
| 164 | + setDrawerProps({ loading: false }); | ||
| 165 | + setDrawerProps({ confirmLoading: false }); | ||
| 166 | + } | ||
| 167 | + } finally { | ||
| 168 | + setTimeout(() => { | ||
| 169 | + setDrawerProps({ loading: false }); | ||
| 170 | + setDrawerProps({ confirmLoading: false }); | ||
| 171 | + }, 300); | ||
| 172 | + } | ||
| 173 | + } | ||
| 174 | + | ||
| 175 | + const getPermissionByRole = async (roleType: RoleEnum) => { | ||
| 176 | + try { | ||
| 177 | + const { key } = RoleMenuDictEnum[roleType]; | ||
| 178 | + const res = await findDictItemByCode({ dictCode: key }); | ||
| 179 | + return res.map((item) => item.itemValue); | ||
| 180 | + } catch (error) {} | ||
| 181 | + return []; | ||
| 182 | + }; | ||
| 183 | + | ||
| 184 | + const filterPermissionTreeData = ( | ||
| 185 | + data: MenuRecord[], | ||
| 186 | + permissionKeys: string[], | ||
| 187 | + keysType: KeysTypeEnum | ||
| 188 | + ): TreeData[] => { | ||
| 189 | + const permissionCompare = ( | ||
| 190 | + data: MenuRecord[], | ||
| 191 | + permissionKeys: string[], | ||
| 192 | + keysType: KeysTypeEnum | ||
| 193 | + ): TreeData[] => { | ||
| 194 | + return data.filter((item) => { | ||
| 195 | + item.name = t(item.name); | ||
| 196 | + const findFlag = permissionKeys.includes(item.permission); | ||
| 197 | + | ||
| 198 | + item.show = findFlag ? keysType === KeysTypeEnum.ENABLED : undefined; | ||
| 199 | + | ||
| 200 | + if (item.children && item.children.length) { | ||
| 201 | + if (item.show) return true; | ||
| 202 | + if (item.show === undefined) { | ||
| 203 | + item.children = permissionCompare(item.children, permissionKeys, keysType); | ||
| 204 | + item.show = item.children.some((item) => | ||
| 205 | + keysType === KeysTypeEnum.ENABLED | ||
| 206 | + ? item.show | ||
| 207 | + : item.show === undefined | ||
| 208 | + ? true | ||
| 209 | + : item.show | ||
| 210 | + ); | ||
| 211 | + return item.show; | ||
| 212 | + } | ||
| 213 | + } | ||
| 214 | + | ||
| 215 | + return keysType === KeysTypeEnum.ENABLED | ||
| 216 | + ? item.show | ||
| 217 | + : item.show === undefined | ||
| 218 | + ? true | ||
| 219 | + : item.show; | ||
| 220 | + }) as unknown as TreeData[]; | ||
| 221 | + }; | ||
| 222 | + | ||
| 223 | + return permissionCompare(data, permissionKeys, keysType); | ||
| 224 | + }; | ||
| 225 | + | ||
| 226 | + const excludeHalfCheckedKeys = (treeData: MenuRecord[]) => { | ||
| 227 | + const needExcludeKeys: string[] = []; | ||
| 228 | + const query = (data: MenuRecord[]) => { | ||
| 229 | + data.forEach((item) => { | ||
| 230 | + item.checked = roleMenus.value.includes(item.id); | ||
| 231 | + if (item.children && item.children.length) { | ||
| 232 | + query(item.children); | ||
| 233 | + item.checked = item.children.every((item) => item.checked); | ||
| 234 | + } | ||
| 235 | + if (!item.checked) { | ||
| 236 | + needExcludeKeys.push(item.id); | ||
| 237 | + } | ||
| 238 | + }); | ||
| 239 | + }; | ||
| 240 | + query(treeData); | ||
| 241 | + roleMenus.value = unref(roleMenus).filter((key) => !needExcludeKeys.includes(key)); | ||
| 242 | + return needExcludeKeys; | ||
| 243 | + }; | ||
| 244 | + | ||
| 245 | + const handleCheckClick = (selectedKeys: CheckKeys, event: CheckEvent) => { | ||
| 246 | + //fix 取消层级独立后selectedKeys不是数组,是{checked:[],halfChecked:[]}对象 迭代报错 | ||
| 247 | + if (!Array.isArray(selectedKeys)) { | ||
| 248 | + selectedKeys = selectedKeys?.checked; | ||
| 249 | + event.halfCheckedKeys = []; | ||
| 250 | + } | ||
| 251 | + checkedKeysWithHalfChecked.value = [ | ||
| 252 | + ...selectedKeys, | ||
| 253 | + ...(event.halfCheckedKeys as string[]), | ||
| 254 | + ]; | ||
| 255 | + }; | ||
| 256 | + | ||
| 257 | + return { | ||
| 258 | + spinning, | ||
| 259 | + registerDrawer, | ||
| 260 | + registerForm, | ||
| 261 | + getTitle, | ||
| 262 | + handleSubmit, | ||
| 263 | + treeData, | ||
| 264 | + roleMenus, | ||
| 265 | + treeRef, | ||
| 266 | + handleCheckClick, | ||
| 267 | + handleUnSelectAll, | ||
| 268 | + }; | ||
| 269 | + }, | ||
| 270 | + }); | ||
| 271 | +</script> | ||
| 272 | + | ||
| 273 | +<style scoped lang="less"> | ||
| 274 | + :deep(.vben-basic-tree) { | ||
| 275 | + width: 100% !important; | ||
| 276 | + } | ||
| 277 | + | ||
| 278 | + :deep(.is-unflod) { | ||
| 279 | + display: none !important; | ||
| 280 | + } | ||
| 281 | + | ||
| 282 | + :deep(.is-flod) { | ||
| 283 | + display: none !important; | ||
| 284 | + } | ||
| 285 | +</style> |
src/views/system/role/tenant/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div> | ||
| 3 | + <BasicTable | ||
| 4 | + @register="registerTable" | ||
| 5 | + :rowSelection="{ type: 'checkbox' }" | ||
| 6 | + :clickToRowSelect="false" | ||
| 7 | + > | ||
| 8 | + <template #toolbar> | ||
| 9 | + <Authority value="api:yt:role:saveOrUpdateRoleInfoWithMenu:post"> | ||
| 10 | + <a-button type="primary" @click="handleCreate"> 新增角色 </a-button> | ||
| 11 | + </Authority> | ||
| 12 | + <Authority value="api:yt:role:delete"> | ||
| 13 | + <Popconfirm | ||
| 14 | + title="您确定要批量删除数据" | ||
| 15 | + ok-text="确定" | ||
| 16 | + cancel-text="取消" | ||
| 17 | + @confirm="handleDeleteOrBatchDelete(null)" | ||
| 18 | + > | ||
| 19 | + <a-button type="primary" color="error" :disabled="hasBatchDelete"> 批量删除 </a-button> | ||
| 20 | + </Popconfirm> | ||
| 21 | + </Authority> | ||
| 22 | + </template> | ||
| 23 | + <template #status="{ record }"> | ||
| 24 | + <Switch | ||
| 25 | + :checked="record.status === 1" | ||
| 26 | + :loading="record.pendingStatus" | ||
| 27 | + checkedChildren="启用" | ||
| 28 | + unCheckedChildren="禁用" | ||
| 29 | + @change="(checked:boolean)=>statusChange(checked,record)" | ||
| 30 | + /> | ||
| 31 | + </template> | ||
| 32 | + <template #action="{ record }"> | ||
| 33 | + <TableAction | ||
| 34 | + :actions="[ | ||
| 35 | + { | ||
| 36 | + label: '编辑', | ||
| 37 | + auth: 'api:yt:role:saveOrUpdateRoleInfoWithMenu:update', | ||
| 38 | + icon: 'clarity:note-edit-line', | ||
| 39 | + onClick: handleEdit.bind(null, record), | ||
| 40 | + }, | ||
| 41 | + { | ||
| 42 | + label: '删除', | ||
| 43 | + auth: 'api:yt:role:delete', | ||
| 44 | + ifShow: !record.status, | ||
| 45 | + icon: 'ant-design:delete-outlined', | ||
| 46 | + color: 'error', | ||
| 47 | + popConfirm: { | ||
| 48 | + title: '是否确认删除', | ||
| 49 | + confirm: handleDeleteOrBatchDelete.bind(null, record), | ||
| 50 | + }, | ||
| 51 | + }, | ||
| 52 | + ]" | ||
| 53 | + /> | ||
| 54 | + </template> | ||
| 55 | + </BasicTable> | ||
| 56 | + <RoleDrawer @register="registerDrawer" @success="handleSuccess" /> | ||
| 57 | + </div> | ||
| 58 | +</template> | ||
| 59 | +<script lang="ts"> | ||
| 60 | + import { defineComponent, nextTick } from 'vue'; | ||
| 61 | + import { BasicTable, useTable, TableAction } from '/@/components/Table'; | ||
| 62 | + import { delRole, getTenantRoleRoleListByPage, setRoleStatus } from '/@/api/system/system'; | ||
| 63 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
| 64 | + import { useDrawer } from '/@/components/Drawer'; | ||
| 65 | + import RoleDrawer from './RoleDrawer.vue'; | ||
| 66 | + import { columns, searchFormSchema } from './role.data'; | ||
| 67 | + import { RoleEnum } from '/@/enums/roleEnum'; | ||
| 68 | + import { Authority } from '/@/components/Authority'; | ||
| 69 | + import { useBatchDelete } from '/@/hooks/web/useBatchDelete'; | ||
| 70 | + import { Switch, Popconfirm } from 'ant-design-vue'; | ||
| 71 | + | ||
| 72 | + export default defineComponent({ | ||
| 73 | + name: 'TenantRoleManagement', | ||
| 74 | + components: { BasicTable, RoleDrawer, TableAction, Authority, Switch, Popconfirm }, | ||
| 75 | + setup() { | ||
| 76 | + const [registerDrawer, { openDrawer }] = useDrawer(); | ||
| 77 | + function handleSuccess() { | ||
| 78 | + reload(); | ||
| 79 | + } | ||
| 80 | + const [registerTable, { reload, setProps, setSelectedRowKeys }] = useTable({ | ||
| 81 | + title: '租户角色列表', | ||
| 82 | + api: getTenantRoleRoleListByPage, | ||
| 83 | + columns, | ||
| 84 | + formConfig: { | ||
| 85 | + labelWidth: 120, | ||
| 86 | + schemas: searchFormSchema, | ||
| 87 | + }, | ||
| 88 | + useSearchForm: true, | ||
| 89 | + showTableSetting: true, | ||
| 90 | + bordered: true, | ||
| 91 | + showIndexColumn: false, | ||
| 92 | + actionColumn: { | ||
| 93 | + width: 200, | ||
| 94 | + title: '操作', | ||
| 95 | + dataIndex: 'action', | ||
| 96 | + slots: { customRender: 'action' }, | ||
| 97 | + fixed: 'right', | ||
| 98 | + }, | ||
| 99 | + }); | ||
| 100 | + const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions, resetSelectedRowKeys } = | ||
| 101 | + useBatchDelete(delRole, handleSuccess, setProps); | ||
| 102 | + selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => { | ||
| 103 | + // Demo:status为1的选择框禁用 | ||
| 104 | + if (record.status === 1) { | ||
| 105 | + return { disabled: true }; | ||
| 106 | + } else { | ||
| 107 | + return { disabled: false }; | ||
| 108 | + } | ||
| 109 | + }; | ||
| 110 | + nextTick(() => { | ||
| 111 | + setProps(selectionOptions); | ||
| 112 | + }); | ||
| 113 | + | ||
| 114 | + function handleCreate() { | ||
| 115 | + openDrawer(true, { | ||
| 116 | + isUpdate: false, | ||
| 117 | + }); | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + function handleEdit(record: Recordable) { | ||
| 121 | + openDrawer(true, { | ||
| 122 | + record, | ||
| 123 | + isUpdate: true, | ||
| 124 | + }); | ||
| 125 | + } | ||
| 126 | + const statusChange = async (checked, record) => { | ||
| 127 | + setProps({ | ||
| 128 | + loading: true, | ||
| 129 | + }); | ||
| 130 | + setSelectedRowKeys([]); | ||
| 131 | + resetSelectedRowKeys(); | ||
| 132 | + const newStatus = checked ? 1 : 0; | ||
| 133 | + const { createMessage } = useMessage(); | ||
| 134 | + try { | ||
| 135 | + await setRoleStatus(record.id, newStatus); | ||
| 136 | + if (newStatus) { | ||
| 137 | + createMessage.success(`启用成功`); | ||
| 138 | + } else { | ||
| 139 | + createMessage.success('禁用成功'); | ||
| 140 | + } | ||
| 141 | + } finally { | ||
| 142 | + setProps({ | ||
| 143 | + loading: false, | ||
| 144 | + }); | ||
| 145 | + reload(); | ||
| 146 | + } | ||
| 147 | + }; | ||
| 148 | + | ||
| 149 | + return { | ||
| 150 | + statusChange, | ||
| 151 | + registerTable, | ||
| 152 | + registerDrawer, | ||
| 153 | + handleCreate, | ||
| 154 | + handleEdit, | ||
| 155 | + handleSuccess, | ||
| 156 | + RoleEnum, | ||
| 157 | + hasBatchDelete, | ||
| 158 | + handleDeleteOrBatchDelete, | ||
| 159 | + }; | ||
| 160 | + }, | ||
| 161 | + }); | ||
| 162 | +</script> |
src/views/system/role/tenant/role.data.ts
0 → 100644
| 1 | +import { BasicColumn } from '/@/components/Table'; | ||
| 2 | +import { FormSchema } from '/@/components/Table'; | ||
| 3 | +import { RoleEnum } from '/@/enums/roleEnum'; | ||
| 4 | +export const columns: BasicColumn[] = [ | ||
| 5 | + { | ||
| 6 | + title: '角色名称', | ||
| 7 | + dataIndex: 'name', | ||
| 8 | + width: 180, | ||
| 9 | + }, | ||
| 10 | + { | ||
| 11 | + title: '角色Code', | ||
| 12 | + dataIndex: 'code', | ||
| 13 | + width: 180, | ||
| 14 | + }, | ||
| 15 | + { | ||
| 16 | + title: '状态', | ||
| 17 | + dataIndex: 'status', | ||
| 18 | + width: 120, | ||
| 19 | + slots: { customRender: 'status' }, | ||
| 20 | + }, | ||
| 21 | + { | ||
| 22 | + title: '备注', | ||
| 23 | + dataIndex: 'remark', | ||
| 24 | + width: 240, | ||
| 25 | + }, | ||
| 26 | + { | ||
| 27 | + title: '创建时间', | ||
| 28 | + dataIndex: 'createTime', | ||
| 29 | + width: 180, | ||
| 30 | + }, | ||
| 31 | +]; | ||
| 32 | + | ||
| 33 | +export const searchFormSchema: FormSchema[] = [ | ||
| 34 | + { | ||
| 35 | + field: 'roleName', | ||
| 36 | + label: '角色名称', | ||
| 37 | + component: 'Input', | ||
| 38 | + colProps: { span: 6 }, | ||
| 39 | + componentProps: { | ||
| 40 | + maxLength: 255, | ||
| 41 | + placeholder: '请输入角色名称', | ||
| 42 | + }, | ||
| 43 | + }, | ||
| 44 | + | ||
| 45 | + { | ||
| 46 | + field: 'roleType', | ||
| 47 | + label: '', | ||
| 48 | + component: 'Input', | ||
| 49 | + colProps: { span: 8 }, | ||
| 50 | + defaultValue: RoleEnum.TENANT_ADMIN, | ||
| 51 | + ifShow: false, | ||
| 52 | + componentProps: { | ||
| 53 | + maxLength: 20, | ||
| 54 | + }, | ||
| 55 | + }, | ||
| 56 | + | ||
| 57 | + { | ||
| 58 | + field: 'status', | ||
| 59 | + label: '状态', | ||
| 60 | + component: 'Select', | ||
| 61 | + componentProps: { | ||
| 62 | + options: [ | ||
| 63 | + { label: '启用', value: 1 }, | ||
| 64 | + { label: '停用', value: 0 }, | ||
| 65 | + ], | ||
| 66 | + }, | ||
| 67 | + colProps: { span: 6 }, | ||
| 68 | + }, | ||
| 69 | +]; | ||
| 70 | + | ||
| 71 | +export const formSchema: FormSchema[] = [ | ||
| 72 | + { | ||
| 73 | + field: 'name', | ||
| 74 | + label: '角色名称', | ||
| 75 | + required: true, | ||
| 76 | + component: 'Input', | ||
| 77 | + componentProps: { | ||
| 78 | + maxLength: 255, | ||
| 79 | + placeholder: '请输入角色名称', | ||
| 80 | + }, | ||
| 81 | + }, | ||
| 82 | + { | ||
| 83 | + field: 'status', | ||
| 84 | + label: '状态', | ||
| 85 | + component: 'RadioButtonGroup', | ||
| 86 | + defaultValue: 0, | ||
| 87 | + componentProps: { | ||
| 88 | + options: [ | ||
| 89 | + { label: '启用', value: 1 }, | ||
| 90 | + { label: '停用', value: 0 }, | ||
| 91 | + ], | ||
| 92 | + }, | ||
| 93 | + }, | ||
| 94 | + { | ||
| 95 | + label: '备注', | ||
| 96 | + field: 'remark', | ||
| 97 | + component: 'InputTextArea', | ||
| 98 | + componentProps: { | ||
| 99 | + maxLength: 255, | ||
| 100 | + placeholder: '请输入备注', | ||
| 101 | + }, | ||
| 102 | + }, | ||
| 103 | + { | ||
| 104 | + label: ' ', | ||
| 105 | + field: 'menu', | ||
| 106 | + slot: 'menu', | ||
| 107 | + component: 'Input', | ||
| 108 | + componentProps: { | ||
| 109 | + maxLength: 255, | ||
| 110 | + }, | ||
| 111 | + }, | ||
| 112 | +]; |