Commit d3526e6f6307d853a5402ed8e2d3fdd7e5c1ce44

Authored by xingyu4j
1 parent fabca00f

refactor: template script

yudao-ui-admin-vue3/src/views/system/dept/index.vue
  1 +<template>
  2 + <div class="flex">
  3 + <el-card class="w-1/3 dept" :gutter="12" shadow="always">
  4 + <template #header>
  5 + <div class="card-header">
  6 + <span>部门列表</span>
  7 + <XButton
  8 + type="primary"
  9 + preIcon="ep:zoom-in"
  10 + title="新增根节点"
  11 + v-hasPermi="['system:dept:create']"
  12 + @click="handleCreate"
  13 + />
  14 + </div>
  15 + </template>
  16 + <div class="custom-tree-container">
  17 + <!-- <p>部门列表</p> -->
  18 + <!-- 操作工具栏 -->
  19 + <el-input v-model="filterText" placeholder="搜索部门" />
  20 + <el-tree
  21 + ref="treeRef"
  22 + node-key="id"
  23 + :data="deptOptions"
  24 + :props="defaultProps"
  25 + :highlight-current="true"
  26 + default-expand-all
  27 + :filter-node-method="filterNode"
  28 + :expand-on-click-node="false"
  29 + >
  30 + <template #default="{ node, data }">
  31 + <span class="custom-tree-node">
  32 + <span>{{ node.label }}</span>
  33 + <span>
  34 + <XTextButton
  35 + preIcon="ep:zoom-in"
  36 + :title="t('action.add')"
  37 + v-hasPermi="['system:dept:create']"
  38 + @click="handleCreate(data)"
  39 + />
  40 + <XTextButton
  41 + preIcon="ep:edit"
  42 + :title="t('action.edit')"
  43 + v-hasPermi="['system:dept:update']"
  44 + @click="handleUpdate(data)"
  45 + />
  46 + <XTextButton
  47 + preIcon="ep:delete"
  48 + :title="t('action.del')"
  49 + v-hasPermi="['system:dept:delete']"
  50 + @click="handleDelete(data)"
  51 + />
  52 + </span>
  53 + </span>
  54 + </template>
  55 + </el-tree>
  56 + </div>
  57 + </el-card>
  58 + <el-card class="w-2/3 dept" style="margin-left: 10px" :gutter="12" shadow="hover">
  59 + <template #header>
  60 + <div class="card-header">
  61 + <span>{{ formTitle }}</span>
  62 + </div>
  63 + </template>
  64 + <div v-if="!showForm">
  65 + <span><p>请从左侧选择部门</p></span>
  66 + </div>
  67 + <div v-if="showForm">
  68 + <!-- 操作工具栏 -->
  69 + <Form ref="formRef" :schema="modelSchema" :rules="rules">
  70 + <template #parentId>
  71 + <el-tree-select
  72 + node-key="id"
  73 + v-model="deptParentId"
  74 + :props="defaultProps"
  75 + :data="deptOptions"
  76 + check-strictly
  77 + />
  78 + </template>
  79 + <template #leaderUserId>
  80 + <el-select v-model="leaderUserId">
  81 + <el-option
  82 + v-for="item in userOption"
  83 + :key="parseInt(item.id)"
  84 + :label="item.nickname"
  85 + :value="parseInt(item.id)"
  86 + />
  87 + </el-select>
  88 + </template>
  89 + </Form>
  90 + <!-- 按钮:保存 -->
  91 + <XButton
  92 + type="primary"
  93 + :title="t('action.save')"
  94 + v-hasPermi="['system:dept:update']"
  95 + :loading="loading"
  96 + @click="submitForm()"
  97 + />
  98 + <!-- 按钮:关闭 -->
  99 + <XButton :loading="loading" :title="t('dialog.close')" @click="showForm = false" />
  100 + </div>
  101 + </el-card>
  102 + </div>
  103 +</template>
1 <script setup lang="ts"> 104 <script setup lang="ts">
2 import { useI18n } from '@/hooks/web/useI18n' 105 import { useI18n } from '@/hooks/web/useI18n'
3 import { ElInput, ElCard, ElTree, ElTreeSelect, ElSelect, ElOption } from 'element-plus' 106 import { ElInput, ElCard, ElTree, ElTreeSelect, ElSelect, ElOption } from 'element-plus'
@@ -104,109 +207,7 @@ onMounted(async () =&gt; { @@ -104,109 +207,7 @@ onMounted(async () =&gt; {
104 await getUserList() 207 await getUserList()
105 }) 208 })
106 </script> 209 </script>
107 -<template>  
108 - <div class="flex">  
109 - <el-card class="w-1/3 dept" :gutter="12" shadow="always">  
110 - <template #header>  
111 - <div class="card-header">  
112 - <span>部门列表</span>  
113 - <XButton  
114 - type="primary"  
115 - preIcon="ep:zoom-in"  
116 - title="新增根节点"  
117 - v-hasPermi="['system:dept:create']"  
118 - @click="handleCreate"  
119 - />  
120 - </div>  
121 - </template>  
122 - <div class="custom-tree-container">  
123 - <!-- <p>部门列表</p> -->  
124 - <!-- 操作工具栏 -->  
125 - <el-input v-model="filterText" placeholder="搜索部门" />  
126 - <el-tree  
127 - ref="treeRef"  
128 - node-key="id"  
129 - :data="deptOptions"  
130 - :props="defaultProps"  
131 - :highlight-current="true"  
132 - default-expand-all  
133 - :filter-node-method="filterNode"  
134 - :expand-on-click-node="false"  
135 - >  
136 - <template #default="{ node, data }">  
137 - <span class="custom-tree-node">  
138 - <span>{{ node.label }}</span>  
139 - <span>  
140 - <XTextButton  
141 - preIcon="ep:zoom-in"  
142 - :title="t('action.add')"  
143 - v-hasPermi="['system:dept:create']"  
144 - @click="handleCreate(data)"  
145 - />  
146 - <XTextButton  
147 - preIcon="ep:edit"  
148 - :title="t('action.edit')"  
149 - v-hasPermi="['system:dept:update']"  
150 - @click="handleUpdate(data)"  
151 - />  
152 - <XTextButton  
153 - preIcon="ep:delete"  
154 - :title="t('action.del')"  
155 - v-hasPermi="['system:dept:delete']"  
156 - @click="handleDelete(data)"  
157 - />  
158 - </span>  
159 - </span>  
160 - </template>  
161 - </el-tree>  
162 - </div>  
163 - </el-card>  
164 - <el-card class="w-2/3 dept" style="margin-left: 10px" :gutter="12" shadow="hover">  
165 - <template #header>  
166 - <div class="card-header">  
167 - <span>{{ formTitle }}</span>  
168 - </div>  
169 - </template>  
170 - <div v-if="!showForm">  
171 - <span><p>请从左侧选择部门</p></span>  
172 - </div>  
173 - <div v-if="showForm">  
174 - <!-- 操作工具栏 -->  
175 - <Form ref="formRef" :schema="modelSchema" :rules="rules">  
176 - <template #parentId>  
177 - <el-tree-select  
178 - node-key="id"  
179 - v-model="deptParentId"  
180 - :props="defaultProps"  
181 - :data="deptOptions"  
182 - check-strictly  
183 - />  
184 - </template>  
185 - <template #leaderUserId>  
186 - <el-select v-model="leaderUserId">  
187 - <el-option  
188 - v-for="item in userOption"  
189 - :key="parseInt(item.id)"  
190 - :label="item.nickname"  
191 - :value="parseInt(item.id)"  
192 - />  
193 - </el-select>  
194 - </template>  
195 - </Form>  
196 - <!-- 按钮:保存 -->  
197 - <XButton  
198 - type="primary"  
199 - :title="t('action.save')"  
200 - v-hasPermi="['system:dept:update']"  
201 - :loading="loading"  
202 - @click="submitForm()"  
203 - />  
204 - <!-- 按钮:关闭 -->  
205 - <XButton :loading="loading" :title="t('dialog.close')" @click="showForm = false" />  
206 - </div>  
207 - </el-card>  
208 - </div>  
209 -</template> 210 +
210 <style scoped> 211 <style scoped>
211 .dept { 212 .dept {
212 height: 600px; 213 height: 600px;
yudao-ui-admin-vue3/src/views/system/tenantPackage/index.vue
  1 +<template>
  2 + <!-- 搜索工作区 -->
  3 + <ContentWrap>
  4 + <Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />
  5 + </ContentWrap>
  6 + <ContentWrap>
  7 + <!-- 操作工具栏 -->
  8 + <div class="mb-10px">
  9 + <el-button type="primary" @click="handleCreate">
  10 + <Icon icon="ep:zoom-in" class="mr-5px" /> {{ t('action.add') }}
  11 + </el-button>
  12 + </div>
  13 + <!-- 列表 -->
  14 + <Table
  15 + :columns="allSchemas.tableColumns"
  16 + :selection="false"
  17 + :data="tableObject.tableList"
  18 + :loading="tableObject.loading"
  19 + :pagination="{
  20 + total: tableObject.total
  21 + }"
  22 + v-model:pageSize="tableObject.pageSize"
  23 + v-model:currentPage="tableObject.currentPage"
  24 + @register="register"
  25 + >
  26 + <template #status="{ row }">
  27 + <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
  28 + </template>
  29 + <template #createTime="{ row }">
  30 + <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
  31 + </template>
  32 + <template #action="{ row }">
  33 + <el-button link type="primary" @click="handleUpdate(row)">
  34 + <Icon icon="ep:edit" class="mr-1px" /> {{ t('action.edit') }}
  35 + </el-button>
  36 + <el-button link type="primary" @click="delList(row.id, false)">
  37 + <Icon icon="ep:delete" class="mr-1px" /> {{ t('action.del') }}
  38 + </el-button>
  39 + </template>
  40 + </Table>
  41 + </ContentWrap>
  42 +
  43 + <XModal v-model="dialogVisible" :title="dialogTitle" maxHeight="500px" width="50%">
  44 + <!-- 对话框(添加 / 修改) -->
  45 + <Form
  46 + v-if="['create', 'update'].includes(actionType)"
  47 + :schema="allSchemas.formSchema"
  48 + :rules="rules"
  49 + ref="formRef"
  50 + >
  51 + <template #menuIds>
  52 + <el-card class="box-card">
  53 + <template #header>
  54 + <div class="card-header">
  55 + 全选/全不选:
  56 + <el-switch
  57 + v-model="treeNodeAll"
  58 + inline-prompt
  59 + active-text="是"
  60 + inactive-text="否"
  61 + @change="handleCheckedTreeNodeAll()"
  62 + />
  63 + </div>
  64 + </template>
  65 + <el-tree
  66 + ref="treeRef"
  67 + node-key="id"
  68 + show-checkbox
  69 + :props="defaultProps"
  70 + :data="menuOptions"
  71 + empty-text="加载中,请稍后"
  72 + />
  73 + </el-card>
  74 + </template>
  75 + </Form>
  76 + <!-- 操作按钮 -->
  77 + <template #footer>
  78 + <!-- 按钮:保存 -->
  79 + <XButton
  80 + v-if="['create', 'update'].includes(actionType)"
  81 + type="primary"
  82 + :title="t('action.save')"
  83 + :loading="loading"
  84 + @click="submitForm()"
  85 + />
  86 + <!-- 按钮:关闭 -->
  87 + <XButton :loading="loading" :title="t('dialog.close')" @click="dialogVisible = false" />
  88 + </template>
  89 + </XModal>
  90 +</template>
1 <script setup lang="ts"> 91 <script setup lang="ts">
2 import { onMounted, ref, unref } from 'vue' 92 import { onMounted, ref, unref } from 'vue'
3 import dayjs from 'dayjs' 93 import dayjs from 'dayjs'
@@ -107,94 +197,3 @@ onMounted(async () =&gt; { @@ -107,94 +197,3 @@ onMounted(async () =&gt; {
107 }) 197 })
108 // getList() 198 // getList()
109 </script> 199 </script>
110 -  
111 -<template>  
112 - <!-- 搜索工作区 -->  
113 - <ContentWrap>  
114 - <Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />  
115 - </ContentWrap>  
116 - <ContentWrap>  
117 - <!-- 操作工具栏 -->  
118 - <div class="mb-10px">  
119 - <el-button type="primary" @click="handleCreate">  
120 - <Icon icon="ep:zoom-in" class="mr-5px" /> {{ t('action.add') }}  
121 - </el-button>  
122 - </div>  
123 - <!-- 列表 -->  
124 - <Table  
125 - :columns="allSchemas.tableColumns"  
126 - :selection="false"  
127 - :data="tableObject.tableList"  
128 - :loading="tableObject.loading"  
129 - :pagination="{  
130 - total: tableObject.total  
131 - }"  
132 - v-model:pageSize="tableObject.pageSize"  
133 - v-model:currentPage="tableObject.currentPage"  
134 - @register="register"  
135 - >  
136 - <template #status="{ row }">  
137 - <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />  
138 - </template>  
139 - <template #createTime="{ row }">  
140 - <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>  
141 - </template>  
142 - <template #action="{ row }">  
143 - <el-button link type="primary" @click="handleUpdate(row)">  
144 - <Icon icon="ep:edit" class="mr-1px" /> {{ t('action.edit') }}  
145 - </el-button>  
146 - <el-button link type="primary" @click="delList(row.id, false)">  
147 - <Icon icon="ep:delete" class="mr-1px" /> {{ t('action.del') }}  
148 - </el-button>  
149 - </template>  
150 - </Table>  
151 - </ContentWrap>  
152 -  
153 - <XModal v-model="dialogVisible" :title="dialogTitle" maxHeight="500px" width="50%">  
154 - <!-- 对话框(添加 / 修改) -->  
155 - <Form  
156 - v-if="['create', 'update'].includes(actionType)"  
157 - :schema="allSchemas.formSchema"  
158 - :rules="rules"  
159 - ref="formRef"  
160 - >  
161 - <template #menuIds>  
162 - <el-card class="box-card">  
163 - <template #header>  
164 - <div class="card-header">  
165 - 全选/全不选:  
166 - <el-switch  
167 - v-model="treeNodeAll"  
168 - inline-prompt  
169 - active-text="是"  
170 - inactive-text="否"  
171 - @change="handleCheckedTreeNodeAll()"  
172 - />  
173 - </div>  
174 - </template>  
175 - <el-tree  
176 - ref="treeRef"  
177 - node-key="id"  
178 - show-checkbox  
179 - :props="defaultProps"  
180 - :data="menuOptions"  
181 - empty-text="加载中,请稍后"  
182 - />  
183 - </el-card>  
184 - </template>  
185 - </Form>  
186 - <!-- 操作按钮 -->  
187 - <template #footer>  
188 - <!-- 按钮:保存 -->  
189 - <XButton  
190 - v-if="['create', 'update'].includes(actionType)"  
191 - type="primary"  
192 - :title="t('action.save')"  
193 - :loading="loading"  
194 - @click="submitForm()"  
195 - />  
196 - <!-- 按钮:关闭 -->  
197 - <XButton :loading="loading" :title="t('dialog.close')" @click="dialogVisible = false" />  
198 - </template>  
199 - </XModal>  
200 -</template>  
yudao-ui-admin-vue3/src/views/system/user/index.vue
1 -<script setup lang="ts">  
2 -import { onMounted, reactive, ref, unref, watch } from 'vue'  
3 -import dayjs from 'dayjs'  
4 -import {  
5 - ElTag,  
6 - ElInput,  
7 - ElCard,  
8 - ElTree,  
9 - ElTreeSelect,  
10 - ElSelect,  
11 - ElOption,  
12 - ElTransfer,  
13 - ElForm,  
14 - ElFormItem,  
15 - ElUpload,  
16 - ElSwitch,  
17 - ElCheckbox,  
18 - UploadInstance,  
19 - UploadRawFile  
20 -} from 'element-plus'  
21 -import { handleTree } from '@/utils/tree'  
22 -import { useI18n } from '@/hooks/web/useI18n'  
23 -import { useTable } from '@/hooks/web/useTable'  
24 -import { FormExpose } from '@/components/Form'  
25 -import type { UserVO } from '@/api/system/user/types'  
26 -import type { PostVO } from '@/api/system/post'  
27 -import type { PermissionAssignUserRoleReqVO } from '@/api/system/permission/types'  
28 -import { listSimpleDeptApi } from '@/api/system/dept'  
29 -import { listSimplePostsApi } from '@/api/system/post'  
30 -import { listSimpleRolesApi } from '@/api/system/role'  
31 -import { aassignUserRoleApi, listUserRolesApi } from '@/api/system/permission'  
32 -import { rules, allSchemas } from './user.data'  
33 -import * as UserApi from '@/api/system/user'  
34 -import download from '@/utils/download'  
35 -import { useRouter } from 'vue-router'  
36 -import { CommonStatusEnum } from '@/utils/constants'  
37 -import { getAccessToken, getTenantId } from '@/utils/auth'  
38 -import { useMessage } from '@/hooks/web/useMessage'  
39 -  
40 -const message = useMessage()  
41 -  
42 -const defaultProps = {  
43 - children: 'children',  
44 - label: 'name',  
45 - value: 'id'  
46 -}  
47 -const { t } = useI18n() // 国际化  
48 -  
49 -// ========== 列表相关 ==========  
50 -const tableTitle = ref('用户列表')  
51 -const { register, tableObject, methods } = useTable<UserVO>({  
52 - getListApi: UserApi.getUserPageApi,  
53 - delListApi: UserApi.deleteUserApi,  
54 - exportListApi: UserApi.exportUserApi  
55 -})  
56 -const { getList, setSearchParams, delList, exportList } = methods  
57 -  
58 -// ========== 创建部门树结构 ==========  
59 -const filterText = ref('')  
60 -const deptOptions = ref<any[]>([]) // 树形结构  
61 -const searchForm = ref<FormExpose>()  
62 -const treeRef = ref<InstanceType<typeof ElTree>>()  
63 -const getTree = async () => {  
64 - const res = await listSimpleDeptApi()  
65 - deptOptions.value.push(...handleTree(res))  
66 -}  
67 -const filterNode = (value: string, data: Tree) => {  
68 - if (!value) return true  
69 - return data.name.includes(value)  
70 -}  
71 -const handleDeptNodeClick = (data: { [key: string]: any }) => {  
72 - tableObject.params = {  
73 - deptId: data.id  
74 - }  
75 - tableTitle.value = data.name  
76 - methods.getList()  
77 -}  
78 -const { push } = useRouter()  
79 -const handleDeptEdit = () => {  
80 - push('/system/dept')  
81 -}  
82 -watch(filterText, (val) => {  
83 - treeRef.value!.filter(val)  
84 -})  
85 -// ========== CRUD 相关 ==========  
86 -const loading = ref(false) // 遮罩层  
87 -const actionType = ref('') // 操作按钮的类型  
88 -const dialogVisible = ref(false) // 是否显示弹出层  
89 -const dialogTitle = ref('edit') // 弹出层标题  
90 -const formRef = ref<FormExpose>() // 表单 Ref  
91 -const deptId = ref() // 部门ID  
92 -const postIds = ref<string[]>([]) // 岗位ID  
93 -const postOptions = ref<PostVO[]>([]) //岗位列表  
94 -  
95 -// 获取岗位列表  
96 -const getPostOptions = async () => {  
97 - const res = await listSimplePostsApi()  
98 - postOptions.value.push(...res)  
99 -}  
100 -// 设置标题  
101 -const setDialogTile = async (type: string) => {  
102 - dialogTitle.value = t('action.' + type)  
103 - actionType.value = type  
104 - dialogVisible.value = true  
105 -}  
106 -  
107 -// 新增操作  
108 -const handleAdd = async () => {  
109 - // 重置表单  
110 - deptId.value = null  
111 - postIds.value = []  
112 - dialogVisible.value = true  
113 - dialogTitle.value = t('action.create')  
114 - actionType.value = 'create'  
115 - await unref(formRef)?.getElFormRef().resetFields()  
116 -}  
117 -  
118 -// 修改操作  
119 -const handleUpdate = async (row: UserVO) => {  
120 - await setDialogTile('update')  
121 - unref(formRef)?.delSchema('username')  
122 - unref(formRef)?.delSchema('password')  
123 - // 设置数据  
124 - const res = await UserApi.getUserApi(row.id)  
125 - deptId.value = res.deptId  
126 - postIds.value = res.postIds  
127 - unref(formRef)?.setValues(res)  
128 -}  
129 -  
130 -// 提交按钮  
131 -const submitForm = async () => {  
132 - loading.value = true  
133 - // 提交请求  
134 - try {  
135 - const data = unref(formRef)?.formModel as UserVO  
136 - data.deptId = deptId.value  
137 - data.postIds = postIds.value  
138 - if (actionType.value === 'create') {  
139 - await UserApi.createUserApi(data)  
140 - message.success(t('common.createSuccess'))  
141 - } else {  
142 - await UserApi.updateUserApi(data)  
143 - message.success(t('common.updateSuccess'))  
144 - }  
145 - // 操作成功,重新加载列表  
146 - dialogVisible.value = false  
147 - await getList()  
148 - } finally {  
149 - loading.value = false  
150 - }  
151 -}  
152 -// 改变用户状态操作  
153 -const handleStatusChange = async (row: UserVO) => {  
154 - const text = row.status === CommonStatusEnum.ENABLE ? '启用' : '停用'  
155 - message  
156 - .confirm('确认要"' + text + '""' + row.username + '"用户吗?', t('common.reminder'))  
157 - .then(async () => {  
158 - row.status =  
159 - row.status === CommonStatusEnum.ENABLE ? CommonStatusEnum.ENABLE : CommonStatusEnum.DISABLE  
160 - await UserApi.updateUserStatusApi(row.id, row.status)  
161 - message.success(text + '成功')  
162 - await getList()  
163 - })  
164 - .catch(() => {  
165 - row.status =  
166 - row.status === CommonStatusEnum.ENABLE ? CommonStatusEnum.DISABLE : CommonStatusEnum.ENABLE  
167 - })  
168 -}  
169 -// 重置密码  
170 -const handleResetPwd = (row: UserVO) => {  
171 - message.prompt('请输入"' + row.username + '"的新密码', t('common.reminder')).then(({ value }) => {  
172 - UserApi.resetUserPwdApi(row.id, value).then(() => {  
173 - message.success('修改成功,新密码是:' + value)  
174 - })  
175 - })  
176 -}  
177 -// 分配角色  
178 -const roleDialogVisible = ref(false)  
179 -const roleOptions = ref()  
180 -const userRole = reactive({  
181 - id: 0,  
182 - username: '',  
183 - nickname: '',  
184 - roleIds: []  
185 -})  
186 -const handleRole = async (row: UserVO) => {  
187 - userRole.id = row.id  
188 - userRole.username = row.username  
189 - userRole.nickname = row.nickname  
190 - // 获得角色拥有的权限集合  
191 - const roles = await listUserRolesApi(row.id)  
192 - userRole.roleIds = roles  
193 - // 获取角色列表  
194 - const roleOpt = await listSimpleRolesApi()  
195 - roleOptions.value = roleOpt  
196 - roleDialogVisible.value = true  
197 -}  
198 -// 提交  
199 -const submitRole = async () => {  
200 - const data = ref<PermissionAssignUserRoleReqVO>({  
201 - userId: userRole.id,  
202 - roleIds: userRole.roleIds  
203 - })  
204 - await aassignUserRoleApi(data.value)  
205 - message.success(t('common.updateSuccess'))  
206 - roleDialogVisible.value = false  
207 -}  
208 -// ========== 详情相关 ==========  
209 -const detailRef = ref()  
210 -  
211 -// 详情操作  
212 -const handleDetail = async (row: UserVO) => {  
213 - // 设置数据  
214 - detailRef.value = row  
215 - await setDialogTile('detail')  
216 -}  
217 -// ========== 导入相关 ==========  
218 -const importDialogVisible = ref(false)  
219 -const uploadDisabled = ref(false)  
220 -const importDialogTitle = ref('用户导入')  
221 -const updateSupport = ref(0)  
222 -let updateUrl = import.meta.env.VITE_BASE_URL + import.meta.env.VITE_API_URL + '/system/user/import'  
223 -const uploadHeaders = ref()  
224 -// 下载导入模版  
225 -const handleImportTemp = async () => {  
226 - const res = await UserApi.importUserTemplateApi()  
227 - download.excel(res, '用户导入模版.xls')  
228 -}  
229 -// 文件上传之前判断  
230 -const beforeExcelUpload = (file: UploadRawFile) => {  
231 - const isExcel =  
232 - file.type === 'application/vnd.ms-excel' ||  
233 - file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'  
234 - const isLt5M = file.size / 1024 / 1024 < 5  
235 - if (!isExcel) message.error('上传文件只能是 xls / xlsx 格式!')  
236 - if (!isLt5M) message.error('上传文件大小不能超过 5MB!')  
237 - return isExcel && isLt5M  
238 -}  
239 -// 文件上传  
240 -const uploadRef = ref<UploadInstance>()  
241 -const submitFileForm = () => {  
242 - uploadHeaders.value = {  
243 - Authorization: 'Bearer ' + getAccessToken(),  
244 - 'tenant-id': getTenantId()  
245 - }  
246 - uploadDisabled.value = true  
247 - uploadRef.value!.submit()  
248 -}  
249 -// 文件上传成功  
250 -const handleFileSuccess = (response: any): void => {  
251 - if (response.code !== 0) {  
252 - message.error(response.msg)  
253 - return  
254 - }  
255 - importDialogVisible.value = false  
256 - uploadDisabled.value = false  
257 - const data = response.data  
258 - let text = '上传成功数量:' + data.createUsernames.length + ';'  
259 - for (let username of data.createUsernames) {  
260 - text += '< ' + username + ' >'  
261 - }  
262 - text += '更新成功数量:' + data.updateUsernames.length + ';'  
263 - for (const username of data.updateUsernames) {  
264 - text += '< ' + username + ' >'  
265 - }  
266 - text += '更新失败数量:' + Object.keys(data.failureUsernames).length + ';'  
267 - for (const username in data.failureUsernames) {  
268 - text += '< ' + username + ': ' + data.failureUsernames[username] + ' >'  
269 - }  
270 - message.alert(text)  
271 - getList()  
272 -}  
273 -// 文件数超出提示  
274 -const handleExceed = (): void => {  
275 - message.error('最多只能上传一个文件!')  
276 -}  
277 -// 上传错误提示  
278 -const excelUploadError = (): void => {  
279 - message.error('导入数据失败,请您重新上传!')  
280 -}  
281 -// ========== 初始化 ==========  
282 -onMounted(async () => {  
283 - await getPostOptions()  
284 - await getList()  
285 - await getTree()  
286 -})  
287 -</script>  
288 -  
289 <template> 1 <template>
290 <div class="flex"> 2 <div class="flex">
291 <el-card class="w-1/5 user" :gutter="12" shadow="always"> 3 <el-card class="w-1/5 user" :gutter="12" shadow="always">
@@ -546,6 +258,293 @@ onMounted(async () =&gt; { @@ -546,6 +258,293 @@ onMounted(async () =&gt; {
546 </template> 258 </template>
547 </XModal> 259 </XModal>
548 </template> 260 </template>
  261 +<script setup lang="ts">
  262 +import { onMounted, reactive, ref, unref, watch } from 'vue'
  263 +import dayjs from 'dayjs'
  264 +import {
  265 + ElTag,
  266 + ElInput,
  267 + ElCard,
  268 + ElTree,
  269 + ElTreeSelect,
  270 + ElSelect,
  271 + ElOption,
  272 + ElTransfer,
  273 + ElForm,
  274 + ElFormItem,
  275 + ElUpload,
  276 + ElSwitch,
  277 + ElCheckbox,
  278 + UploadInstance,
  279 + UploadRawFile
  280 +} from 'element-plus'
  281 +import { handleTree } from '@/utils/tree'
  282 +import { useI18n } from '@/hooks/web/useI18n'
  283 +import { useTable } from '@/hooks/web/useTable'
  284 +import { FormExpose } from '@/components/Form'
  285 +import type { UserVO } from '@/api/system/user/types'
  286 +import type { PostVO } from '@/api/system/post'
  287 +import type { PermissionAssignUserRoleReqVO } from '@/api/system/permission/types'
  288 +import { listSimpleDeptApi } from '@/api/system/dept'
  289 +import { listSimplePostsApi } from '@/api/system/post'
  290 +import { listSimpleRolesApi } from '@/api/system/role'
  291 +import { aassignUserRoleApi, listUserRolesApi } from '@/api/system/permission'
  292 +import { rules, allSchemas } from './user.data'
  293 +import * as UserApi from '@/api/system/user'
  294 +import download from '@/utils/download'
  295 +import { useRouter } from 'vue-router'
  296 +import { CommonStatusEnum } from '@/utils/constants'
  297 +import { getAccessToken, getTenantId } from '@/utils/auth'
  298 +import { useMessage } from '@/hooks/web/useMessage'
  299 +
  300 +const message = useMessage()
  301 +
  302 +const defaultProps = {
  303 + children: 'children',
  304 + label: 'name',
  305 + value: 'id'
  306 +}
  307 +const { t } = useI18n() // 国际化
  308 +
  309 +// ========== 列表相关 ==========
  310 +const tableTitle = ref('用户列表')
  311 +const { register, tableObject, methods } = useTable<UserVO>({
  312 + getListApi: UserApi.getUserPageApi,
  313 + delListApi: UserApi.deleteUserApi,
  314 + exportListApi: UserApi.exportUserApi
  315 +})
  316 +const { getList, setSearchParams, delList, exportList } = methods
  317 +
  318 +// ========== 创建部门树结构 ==========
  319 +const filterText = ref('')
  320 +const deptOptions = ref<any[]>([]) // 树形结构
  321 +const searchForm = ref<FormExpose>()
  322 +const treeRef = ref<InstanceType<typeof ElTree>>()
  323 +const getTree = async () => {
  324 + const res = await listSimpleDeptApi()
  325 + deptOptions.value.push(...handleTree(res))
  326 +}
  327 +const filterNode = (value: string, data: Tree) => {
  328 + if (!value) return true
  329 + return data.name.includes(value)
  330 +}
  331 +const handleDeptNodeClick = (data: { [key: string]: any }) => {
  332 + tableObject.params = {
  333 + deptId: data.id
  334 + }
  335 + tableTitle.value = data.name
  336 + methods.getList()
  337 +}
  338 +const { push } = useRouter()
  339 +const handleDeptEdit = () => {
  340 + push('/system/dept')
  341 +}
  342 +watch(filterText, (val) => {
  343 + treeRef.value!.filter(val)
  344 +})
  345 +// ========== CRUD 相关 ==========
  346 +const loading = ref(false) // 遮罩层
  347 +const actionType = ref('') // 操作按钮的类型
  348 +const dialogVisible = ref(false) // 是否显示弹出层
  349 +const dialogTitle = ref('edit') // 弹出层标题
  350 +const formRef = ref<FormExpose>() // 表单 Ref
  351 +const deptId = ref() // 部门ID
  352 +const postIds = ref<string[]>([]) // 岗位ID
  353 +const postOptions = ref<PostVO[]>([]) //岗位列表
  354 +
  355 +// 获取岗位列表
  356 +const getPostOptions = async () => {
  357 + const res = await listSimplePostsApi()
  358 + postOptions.value.push(...res)
  359 +}
  360 +// 设置标题
  361 +const setDialogTile = async (type: string) => {
  362 + dialogTitle.value = t('action.' + type)
  363 + actionType.value = type
  364 + dialogVisible.value = true
  365 +}
  366 +
  367 +// 新增操作
  368 +const handleAdd = async () => {
  369 + // 重置表单
  370 + deptId.value = null
  371 + postIds.value = []
  372 + dialogVisible.value = true
  373 + dialogTitle.value = t('action.create')
  374 + actionType.value = 'create'
  375 + await unref(formRef)?.getElFormRef().resetFields()
  376 +}
  377 +
  378 +// 修改操作
  379 +const handleUpdate = async (row: UserVO) => {
  380 + await setDialogTile('update')
  381 + unref(formRef)?.delSchema('username')
  382 + unref(formRef)?.delSchema('password')
  383 + // 设置数据
  384 + const res = await UserApi.getUserApi(row.id)
  385 + deptId.value = res.deptId
  386 + postIds.value = res.postIds
  387 + unref(formRef)?.setValues(res)
  388 +}
  389 +
  390 +// 提交按钮
  391 +const submitForm = async () => {
  392 + loading.value = true
  393 + // 提交请求
  394 + try {
  395 + const data = unref(formRef)?.formModel as UserVO
  396 + data.deptId = deptId.value
  397 + data.postIds = postIds.value
  398 + if (actionType.value === 'create') {
  399 + await UserApi.createUserApi(data)
  400 + message.success(t('common.createSuccess'))
  401 + } else {
  402 + await UserApi.updateUserApi(data)
  403 + message.success(t('common.updateSuccess'))
  404 + }
  405 + // 操作成功,重新加载列表
  406 + dialogVisible.value = false
  407 + await getList()
  408 + } finally {
  409 + loading.value = false
  410 + }
  411 +}
  412 +// 改变用户状态操作
  413 +const handleStatusChange = async (row: UserVO) => {
  414 + const text = row.status === CommonStatusEnum.ENABLE ? '启用' : '停用'
  415 + message
  416 + .confirm('确认要"' + text + '""' + row.username + '"用户吗?', t('common.reminder'))
  417 + .then(async () => {
  418 + row.status =
  419 + row.status === CommonStatusEnum.ENABLE ? CommonStatusEnum.ENABLE : CommonStatusEnum.DISABLE
  420 + await UserApi.updateUserStatusApi(row.id, row.status)
  421 + message.success(text + '成功')
  422 + await getList()
  423 + })
  424 + .catch(() => {
  425 + row.status =
  426 + row.status === CommonStatusEnum.ENABLE ? CommonStatusEnum.DISABLE : CommonStatusEnum.ENABLE
  427 + })
  428 +}
  429 +// 重置密码
  430 +const handleResetPwd = (row: UserVO) => {
  431 + message.prompt('请输入"' + row.username + '"的新密码', t('common.reminder')).then(({ value }) => {
  432 + UserApi.resetUserPwdApi(row.id, value).then(() => {
  433 + message.success('修改成功,新密码是:' + value)
  434 + })
  435 + })
  436 +}
  437 +// 分配角色
  438 +const roleDialogVisible = ref(false)
  439 +const roleOptions = ref()
  440 +const userRole = reactive({
  441 + id: 0,
  442 + username: '',
  443 + nickname: '',
  444 + roleIds: []
  445 +})
  446 +const handleRole = async (row: UserVO) => {
  447 + userRole.id = row.id
  448 + userRole.username = row.username
  449 + userRole.nickname = row.nickname
  450 + // 获得角色拥有的权限集合
  451 + const roles = await listUserRolesApi(row.id)
  452 + userRole.roleIds = roles
  453 + // 获取角色列表
  454 + const roleOpt = await listSimpleRolesApi()
  455 + roleOptions.value = roleOpt
  456 + roleDialogVisible.value = true
  457 +}
  458 +// 提交
  459 +const submitRole = async () => {
  460 + const data = ref<PermissionAssignUserRoleReqVO>({
  461 + userId: userRole.id,
  462 + roleIds: userRole.roleIds
  463 + })
  464 + await aassignUserRoleApi(data.value)
  465 + message.success(t('common.updateSuccess'))
  466 + roleDialogVisible.value = false
  467 +}
  468 +// ========== 详情相关 ==========
  469 +const detailRef = ref()
  470 +
  471 +// 详情操作
  472 +const handleDetail = async (row: UserVO) => {
  473 + // 设置数据
  474 + detailRef.value = row
  475 + await setDialogTile('detail')
  476 +}
  477 +// ========== 导入相关 ==========
  478 +const importDialogVisible = ref(false)
  479 +const uploadDisabled = ref(false)
  480 +const importDialogTitle = ref('用户导入')
  481 +const updateSupport = ref(0)
  482 +let updateUrl = import.meta.env.VITE_BASE_URL + import.meta.env.VITE_API_URL + '/system/user/import'
  483 +const uploadHeaders = ref()
  484 +// 下载导入模版
  485 +const handleImportTemp = async () => {
  486 + const res = await UserApi.importUserTemplateApi()
  487 + download.excel(res, '用户导入模版.xls')
  488 +}
  489 +// 文件上传之前判断
  490 +const beforeExcelUpload = (file: UploadRawFile) => {
  491 + const isExcel =
  492 + file.type === 'application/vnd.ms-excel' ||
  493 + file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
  494 + const isLt5M = file.size / 1024 / 1024 < 5
  495 + if (!isExcel) message.error('上传文件只能是 xls / xlsx 格式!')
  496 + if (!isLt5M) message.error('上传文件大小不能超过 5MB!')
  497 + return isExcel && isLt5M
  498 +}
  499 +// 文件上传
  500 +const uploadRef = ref<UploadInstance>()
  501 +const submitFileForm = () => {
  502 + uploadHeaders.value = {
  503 + Authorization: 'Bearer ' + getAccessToken(),
  504 + 'tenant-id': getTenantId()
  505 + }
  506 + uploadDisabled.value = true
  507 + uploadRef.value!.submit()
  508 +}
  509 +// 文件上传成功
  510 +const handleFileSuccess = (response: any): void => {
  511 + if (response.code !== 0) {
  512 + message.error(response.msg)
  513 + return
  514 + }
  515 + importDialogVisible.value = false
  516 + uploadDisabled.value = false
  517 + const data = response.data
  518 + let text = '上传成功数量:' + data.createUsernames.length + ';'
  519 + for (let username of data.createUsernames) {
  520 + text += '< ' + username + ' >'
  521 + }
  522 + text += '更新成功数量:' + data.updateUsernames.length + ';'
  523 + for (const username of data.updateUsernames) {
  524 + text += '< ' + username + ' >'
  525 + }
  526 + text += '更新失败数量:' + Object.keys(data.failureUsernames).length + ';'
  527 + for (const username in data.failureUsernames) {
  528 + text += '< ' + username + ': ' + data.failureUsernames[username] + ' >'
  529 + }
  530 + message.alert(text)
  531 + getList()
  532 +}
  533 +// 文件数超出提示
  534 +const handleExceed = (): void => {
  535 + message.error('最多只能上传一个文件!')
  536 +}
  537 +// 上传错误提示
  538 +const excelUploadError = (): void => {
  539 + message.error('导入数据失败,请您重新上传!')
  540 +}
  541 +// ========== 初始化 ==========
  542 +onMounted(async () => {
  543 + await getPostOptions()
  544 + await getList()
  545 + await getTree()
  546 +})
  547 +</script>
549 548
550 <style scoped> 549 <style scoped>
551 .user { 550 .user {