Browse Source

refactor: template script

xingyu4j 2 years ago
parent
commit
d3526e6f63

+ 104 - 103
yudao-ui-admin-vue3/src/views/system/dept/index.vue

@@ -1,3 +1,106 @@
+<template>
+  <div class="flex">
+    <el-card class="w-1/3 dept" :gutter="12" shadow="always">
+      <template #header>
+        <div class="card-header">
+          <span>部门列表</span>
+          <XButton
+            type="primary"
+            preIcon="ep:zoom-in"
+            title="新增根节点"
+            v-hasPermi="['system:dept:create']"
+            @click="handleCreate"
+          />
+        </div>
+      </template>
+      <div class="custom-tree-container">
+        <!-- <p>部门列表</p> -->
+        <!-- 操作工具栏 -->
+        <el-input v-model="filterText" placeholder="搜索部门" />
+        <el-tree
+          ref="treeRef"
+          node-key="id"
+          :data="deptOptions"
+          :props="defaultProps"
+          :highlight-current="true"
+          default-expand-all
+          :filter-node-method="filterNode"
+          :expand-on-click-node="false"
+        >
+          <template #default="{ node, data }">
+            <span class="custom-tree-node">
+              <span>{{ node.label }}</span>
+              <span>
+                <XTextButton
+                  preIcon="ep:zoom-in"
+                  :title="t('action.add')"
+                  v-hasPermi="['system:dept:create']"
+                  @click="handleCreate(data)"
+                />
+                <XTextButton
+                  preIcon="ep:edit"
+                  :title="t('action.edit')"
+                  v-hasPermi="['system:dept:update']"
+                  @click="handleUpdate(data)"
+                />
+                <XTextButton
+                  preIcon="ep:delete"
+                  :title="t('action.del')"
+                  v-hasPermi="['system:dept:delete']"
+                  @click="handleDelete(data)"
+                />
+              </span>
+            </span>
+          </template>
+        </el-tree>
+      </div>
+    </el-card>
+    <el-card class="w-2/3 dept" style="margin-left: 10px" :gutter="12" shadow="hover">
+      <template #header>
+        <div class="card-header">
+          <span>{{ formTitle }}</span>
+        </div>
+      </template>
+      <div v-if="!showForm">
+        <span><p>请从左侧选择部门</p></span>
+      </div>
+      <div v-if="showForm">
+        <!-- 操作工具栏 -->
+        <Form ref="formRef" :schema="modelSchema" :rules="rules">
+          <template #parentId>
+            <el-tree-select
+              node-key="id"
+              v-model="deptParentId"
+              :props="defaultProps"
+              :data="deptOptions"
+              check-strictly
+            />
+          </template>
+          <template #leaderUserId>
+            <el-select v-model="leaderUserId">
+              <el-option
+                v-for="item in userOption"
+                :key="parseInt(item.id)"
+                :label="item.nickname"
+                :value="parseInt(item.id)"
+              />
+            </el-select>
+          </template>
+        </Form>
+        <!-- 按钮:保存 -->
+        <XButton
+          type="primary"
+          :title="t('action.save')"
+          v-hasPermi="['system:dept:update']"
+          :loading="loading"
+          @click="submitForm()"
+        />
+        <!-- 按钮:关闭 -->
+        <XButton :loading="loading" :title="t('dialog.close')" @click="showForm = false" />
+      </div>
+    </el-card>
+  </div>
+</template>
 <script setup lang="ts">
 import { useI18n } from '@/hooks/web/useI18n'
 import { ElInput, ElCard, ElTree, ElTreeSelect, ElSelect, ElOption } from 'element-plus'
@@ -104,109 +207,7 @@ onMounted(async () => {
   await getUserList()
 })
 </script>
-<template>
-  <div class="flex">
-    <el-card class="w-1/3 dept" :gutter="12" shadow="always">
-      <template #header>
-        <div class="card-header">
-          <span>部门列表</span>
-          <XButton
-            type="primary"
-            preIcon="ep:zoom-in"
-            title="新增根节点"
-            v-hasPermi="['system:dept:create']"
-            @click="handleCreate"
-          />
-        </div>
-      </template>
-      <div class="custom-tree-container">
-        <!-- <p>部门列表</p> -->
-        <!-- 操作工具栏 -->
-        <el-input v-model="filterText" placeholder="搜索部门" />
-        <el-tree
-          ref="treeRef"
-          node-key="id"
-          :data="deptOptions"
-          :props="defaultProps"
-          :highlight-current="true"
-          default-expand-all
-          :filter-node-method="filterNode"
-          :expand-on-click-node="false"
-        >
-          <template #default="{ node, data }">
-            <span class="custom-tree-node">
-              <span>{{ node.label }}</span>
-              <span>
-                <XTextButton
-                  preIcon="ep:zoom-in"
-                  :title="t('action.add')"
-                  v-hasPermi="['system:dept:create']"
-                  @click="handleCreate(data)"
-                />
-                <XTextButton
-                  preIcon="ep:edit"
-                  :title="t('action.edit')"
-                  v-hasPermi="['system:dept:update']"
-                  @click="handleUpdate(data)"
-                />
-                <XTextButton
-                  preIcon="ep:delete"
-                  :title="t('action.del')"
-                  v-hasPermi="['system:dept:delete']"
-                  @click="handleDelete(data)"
-                />
-              </span>
-            </span>
-          </template>
-        </el-tree>
-      </div>
-    </el-card>
-    <el-card class="w-2/3 dept" style="margin-left: 10px" :gutter="12" shadow="hover">
-      <template #header>
-        <div class="card-header">
-          <span>{{ formTitle }}</span>
-        </div>
-      </template>
-      <div v-if="!showForm">
-        <span><p>请从左侧选择部门</p></span>
-      </div>
-      <div v-if="showForm">
-        <!-- 操作工具栏 -->
-        <Form ref="formRef" :schema="modelSchema" :rules="rules">
-          <template #parentId>
-            <el-tree-select
-              node-key="id"
-              v-model="deptParentId"
-              :props="defaultProps"
-              :data="deptOptions"
-              check-strictly
-            />
-          </template>
-          <template #leaderUserId>
-            <el-select v-model="leaderUserId">
-              <el-option
-                v-for="item in userOption"
-                :key="parseInt(item.id)"
-                :label="item.nickname"
-                :value="parseInt(item.id)"
-              />
-            </el-select>
-          </template>
-        </Form>
-        <!-- 按钮:保存 -->
-        <XButton
-          type="primary"
-          :title="t('action.save')"
-          v-hasPermi="['system:dept:update']"
-          :loading="loading"
-          @click="submitForm()"
-        />
-        <!-- 按钮:关闭 -->
-        <XButton :loading="loading" :title="t('dialog.close')" @click="showForm = false" />
-      </div>
-    </el-card>
-  </div>
-</template>
+
 <style scoped>
 .dept {
   height: 600px;

+ 90 - 91
yudao-ui-admin-vue3/src/views/system/tenantPackage/index.vue

@@ -1,3 +1,93 @@
+<template>
+  <!-- 搜索工作区 -->
+  <ContentWrap>
+    <Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />
+  </ContentWrap>
+  <ContentWrap>
+    <!-- 操作工具栏 -->
+    <div class="mb-10px">
+      <el-button type="primary" @click="handleCreate">
+        <Icon icon="ep:zoom-in" class="mr-5px" /> {{ t('action.add') }}
+      </el-button>
+    </div>
+    <!-- 列表 -->
+    <Table
+      :columns="allSchemas.tableColumns"
+      :selection="false"
+      :data="tableObject.tableList"
+      :loading="tableObject.loading"
+      :pagination="{
+        total: tableObject.total
+      }"
+      v-model:pageSize="tableObject.pageSize"
+      v-model:currentPage="tableObject.currentPage"
+      @register="register"
+    >
+      <template #status="{ row }">
+        <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
+      </template>
+      <template #createTime="{ row }">
+        <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
+      </template>
+      <template #action="{ row }">
+        <el-button link type="primary" @click="handleUpdate(row)">
+          <Icon icon="ep:edit" class="mr-1px" /> {{ t('action.edit') }}
+        </el-button>
+        <el-button link type="primary" @click="delList(row.id, false)">
+          <Icon icon="ep:delete" class="mr-1px" /> {{ t('action.del') }}
+        </el-button>
+      </template>
+    </Table>
+  </ContentWrap>
+
+  <XModal v-model="dialogVisible" :title="dialogTitle" maxHeight="500px" width="50%">
+    <!-- 对话框(添加 / 修改) -->
+    <Form
+      v-if="['create', 'update'].includes(actionType)"
+      :schema="allSchemas.formSchema"
+      :rules="rules"
+      ref="formRef"
+    >
+      <template #menuIds>
+        <el-card class="box-card">
+          <template #header>
+            <div class="card-header">
+              全选/全不选:
+              <el-switch
+                v-model="treeNodeAll"
+                inline-prompt
+                active-text="是"
+                inactive-text="否"
+                @change="handleCheckedTreeNodeAll()"
+              />
+            </div>
+          </template>
+          <el-tree
+            ref="treeRef"
+            node-key="id"
+            show-checkbox
+            :props="defaultProps"
+            :data="menuOptions"
+            empty-text="加载中,请稍后"
+          />
+        </el-card>
+      </template>
+    </Form>
+    <!-- 操作按钮 -->
+    <template #footer>
+      <!-- 按钮:保存 -->
+      <XButton
+        v-if="['create', 'update'].includes(actionType)"
+        type="primary"
+        :title="t('action.save')"
+        :loading="loading"
+        @click="submitForm()"
+      />
+      <!-- 按钮:关闭 -->
+      <XButton :loading="loading" :title="t('dialog.close')" @click="dialogVisible = false" />
+    </template>
+  </XModal>
+</template>
 <script setup lang="ts">
 import { onMounted, ref, unref } from 'vue'
 import dayjs from 'dayjs'
@@ -107,94 +197,3 @@ onMounted(async () => {
 })
 // getList()
 </script>
-
-<template>
-  <!-- 搜索工作区 -->
-  <ContentWrap>
-    <Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />
-  </ContentWrap>
-  <ContentWrap>
-    <!-- 操作工具栏 -->
-    <div class="mb-10px">
-      <el-button type="primary" @click="handleCreate">
-        <Icon icon="ep:zoom-in" class="mr-5px" /> {{ t('action.add') }}
-      </el-button>
-    </div>
-    <!-- 列表 -->
-    <Table
-      :columns="allSchemas.tableColumns"
-      :selection="false"
-      :data="tableObject.tableList"
-      :loading="tableObject.loading"
-      :pagination="{
-        total: tableObject.total
-      }"
-      v-model:pageSize="tableObject.pageSize"
-      v-model:currentPage="tableObject.currentPage"
-      @register="register"
-    >
-      <template #status="{ row }">
-        <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
-      </template>
-      <template #createTime="{ row }">
-        <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
-      </template>
-      <template #action="{ row }">
-        <el-button link type="primary" @click="handleUpdate(row)">
-          <Icon icon="ep:edit" class="mr-1px" /> {{ t('action.edit') }}
-        </el-button>
-        <el-button link type="primary" @click="delList(row.id, false)">
-          <Icon icon="ep:delete" class="mr-1px" /> {{ t('action.del') }}
-        </el-button>
-      </template>
-    </Table>
-  </ContentWrap>
-
-  <XModal v-model="dialogVisible" :title="dialogTitle" maxHeight="500px" width="50%">
-    <!-- 对话框(添加 / 修改) -->
-    <Form
-      v-if="['create', 'update'].includes(actionType)"
-      :schema="allSchemas.formSchema"
-      :rules="rules"
-      ref="formRef"
-    >
-      <template #menuIds>
-        <el-card class="box-card">
-          <template #header>
-            <div class="card-header">
-              全选/全不选:
-              <el-switch
-                v-model="treeNodeAll"
-                inline-prompt
-                active-text="是"
-                inactive-text="否"
-                @change="handleCheckedTreeNodeAll()"
-              />
-            </div>
-          </template>
-          <el-tree
-            ref="treeRef"
-            node-key="id"
-            show-checkbox
-            :props="defaultProps"
-            :data="menuOptions"
-            empty-text="加载中,请稍后"
-          />
-        </el-card>
-      </template>
-    </Form>
-    <!-- 操作按钮 -->
-    <template #footer>
-      <!-- 按钮:保存 -->
-      <XButton
-        v-if="['create', 'update'].includes(actionType)"
-        type="primary"
-        :title="t('action.save')"
-        :loading="loading"
-        @click="submitForm()"
-      />
-      <!-- 按钮:关闭 -->
-      <XButton :loading="loading" :title="t('dialog.close')" @click="dialogVisible = false" />
-    </template>
-  </XModal>
-</template>

+ 287 - 288
yudao-ui-admin-vue3/src/views/system/user/index.vue

@@ -1,291 +1,3 @@
-<script setup lang="ts">
-import { onMounted, reactive, ref, unref, watch } from 'vue'
-import dayjs from 'dayjs'
-import {
-  ElTag,
-  ElInput,
-  ElCard,
-  ElTree,
-  ElTreeSelect,
-  ElSelect,
-  ElOption,
-  ElTransfer,
-  ElForm,
-  ElFormItem,
-  ElUpload,
-  ElSwitch,
-  ElCheckbox,
-  UploadInstance,
-  UploadRawFile
-} from 'element-plus'
-import { handleTree } from '@/utils/tree'
-import { useI18n } from '@/hooks/web/useI18n'
-import { useTable } from '@/hooks/web/useTable'
-import { FormExpose } from '@/components/Form'
-import type { UserVO } from '@/api/system/user/types'
-import type { PostVO } from '@/api/system/post'
-import type { PermissionAssignUserRoleReqVO } from '@/api/system/permission/types'
-import { listSimpleDeptApi } from '@/api/system/dept'
-import { listSimplePostsApi } from '@/api/system/post'
-import { listSimpleRolesApi } from '@/api/system/role'
-import { aassignUserRoleApi, listUserRolesApi } from '@/api/system/permission'
-import { rules, allSchemas } from './user.data'
-import * as UserApi from '@/api/system/user'
-import download from '@/utils/download'
-import { useRouter } from 'vue-router'
-import { CommonStatusEnum } from '@/utils/constants'
-import { getAccessToken, getTenantId } from '@/utils/auth'
-import { useMessage } from '@/hooks/web/useMessage'
-
-const message = useMessage()
-
-const defaultProps = {
-  children: 'children',
-  label: 'name',
-  value: 'id'
-}
-const { t } = useI18n() // 国际化
-
-// ========== 列表相关 ==========
-const tableTitle = ref('用户列表')
-const { register, tableObject, methods } = useTable<UserVO>({
-  getListApi: UserApi.getUserPageApi,
-  delListApi: UserApi.deleteUserApi,
-  exportListApi: UserApi.exportUserApi
-})
-const { getList, setSearchParams, delList, exportList } = methods
-
-// ========== 创建部门树结构 ==========
-const filterText = ref('')
-const deptOptions = ref<any[]>([]) // 树形结构
-const searchForm = ref<FormExpose>()
-const treeRef = ref<InstanceType<typeof ElTree>>()
-const getTree = async () => {
-  const res = await listSimpleDeptApi()
-  deptOptions.value.push(...handleTree(res))
-}
-const filterNode = (value: string, data: Tree) => {
-  if (!value) return true
-  return data.name.includes(value)
-}
-const handleDeptNodeClick = (data: { [key: string]: any }) => {
-  tableObject.params = {
-    deptId: data.id
-  }
-  tableTitle.value = data.name
-  methods.getList()
-}
-const { push } = useRouter()
-const handleDeptEdit = () => {
-  push('/system/dept')
-}
-watch(filterText, (val) => {
-  treeRef.value!.filter(val)
-})
-// ========== CRUD 相关 ==========
-const loading = ref(false) // 遮罩层
-const actionType = ref('') // 操作按钮的类型
-const dialogVisible = ref(false) // 是否显示弹出层
-const dialogTitle = ref('edit') // 弹出层标题
-const formRef = ref<FormExpose>() // 表单 Ref
-const deptId = ref() // 部门ID
-const postIds = ref<string[]>([]) // 岗位ID
-const postOptions = ref<PostVO[]>([]) //岗位列表
-
-// 获取岗位列表
-const getPostOptions = async () => {
-  const res = await listSimplePostsApi()
-  postOptions.value.push(...res)
-}
-// 设置标题
-const setDialogTile = async (type: string) => {
-  dialogTitle.value = t('action.' + type)
-  actionType.value = type
-  dialogVisible.value = true
-}
-
-// 新增操作
-const handleAdd = async () => {
-  // 重置表单
-  deptId.value = null
-  postIds.value = []
-  dialogVisible.value = true
-  dialogTitle.value = t('action.create')
-  actionType.value = 'create'
-  await unref(formRef)?.getElFormRef().resetFields()
-}
-
-// 修改操作
-const handleUpdate = async (row: UserVO) => {
-  await setDialogTile('update')
-  unref(formRef)?.delSchema('username')
-  unref(formRef)?.delSchema('password')
-  // 设置数据
-  const res = await UserApi.getUserApi(row.id)
-  deptId.value = res.deptId
-  postIds.value = res.postIds
-  unref(formRef)?.setValues(res)
-}
-
-// 提交按钮
-const submitForm = async () => {
-  loading.value = true
-  // 提交请求
-  try {
-    const data = unref(formRef)?.formModel as UserVO
-    data.deptId = deptId.value
-    data.postIds = postIds.value
-    if (actionType.value === 'create') {
-      await UserApi.createUserApi(data)
-      message.success(t('common.createSuccess'))
-    } else {
-      await UserApi.updateUserApi(data)
-      message.success(t('common.updateSuccess'))
-    }
-    // 操作成功,重新加载列表
-    dialogVisible.value = false
-    await getList()
-  } finally {
-    loading.value = false
-  }
-}
-// 改变用户状态操作
-const handleStatusChange = async (row: UserVO) => {
-  const text = row.status === CommonStatusEnum.ENABLE ? '启用' : '停用'
-  message
-    .confirm('确认要"' + text + '""' + row.username + '"用户吗?', t('common.reminder'))
-    .then(async () => {
-      row.status =
-        row.status === CommonStatusEnum.ENABLE ? CommonStatusEnum.ENABLE : CommonStatusEnum.DISABLE
-      await UserApi.updateUserStatusApi(row.id, row.status)
-      message.success(text + '成功')
-      await getList()
-    })
-    .catch(() => {
-      row.status =
-        row.status === CommonStatusEnum.ENABLE ? CommonStatusEnum.DISABLE : CommonStatusEnum.ENABLE
-    })
-}
-// 重置密码
-const handleResetPwd = (row: UserVO) => {
-  message.prompt('请输入"' + row.username + '"的新密码', t('common.reminder')).then(({ value }) => {
-    UserApi.resetUserPwdApi(row.id, value).then(() => {
-      message.success('修改成功,新密码是:' + value)
-    })
-  })
-}
-// 分配角色
-const roleDialogVisible = ref(false)
-const roleOptions = ref()
-const userRole = reactive({
-  id: 0,
-  username: '',
-  nickname: '',
-  roleIds: []
-})
-const handleRole = async (row: UserVO) => {
-  userRole.id = row.id
-  userRole.username = row.username
-  userRole.nickname = row.nickname
-  // 获得角色拥有的权限集合
-  const roles = await listUserRolesApi(row.id)
-  userRole.roleIds = roles
-  // 获取角色列表
-  const roleOpt = await listSimpleRolesApi()
-  roleOptions.value = roleOpt
-  roleDialogVisible.value = true
-}
-// 提交
-const submitRole = async () => {
-  const data = ref<PermissionAssignUserRoleReqVO>({
-    userId: userRole.id,
-    roleIds: userRole.roleIds
-  })
-  await aassignUserRoleApi(data.value)
-  message.success(t('common.updateSuccess'))
-  roleDialogVisible.value = false
-}
-// ========== 详情相关 ==========
-const detailRef = ref()
-
-// 详情操作
-const handleDetail = async (row: UserVO) => {
-  // 设置数据
-  detailRef.value = row
-  await setDialogTile('detail')
-}
-// ========== 导入相关 ==========
-const importDialogVisible = ref(false)
-const uploadDisabled = ref(false)
-const importDialogTitle = ref('用户导入')
-const updateSupport = ref(0)
-let updateUrl = import.meta.env.VITE_BASE_URL + import.meta.env.VITE_API_URL + '/system/user/import'
-const uploadHeaders = ref()
-// 下载导入模版
-const handleImportTemp = async () => {
-  const res = await UserApi.importUserTemplateApi()
-  download.excel(res, '用户导入模版.xls')
-}
-// 文件上传之前判断
-const beforeExcelUpload = (file: UploadRawFile) => {
-  const isExcel =
-    file.type === 'application/vnd.ms-excel' ||
-    file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
-  const isLt5M = file.size / 1024 / 1024 < 5
-  if (!isExcel) message.error('上传文件只能是 xls / xlsx 格式!')
-  if (!isLt5M) message.error('上传文件大小不能超过 5MB!')
-  return isExcel && isLt5M
-}
-// 文件上传
-const uploadRef = ref<UploadInstance>()
-const submitFileForm = () => {
-  uploadHeaders.value = {
-    Authorization: 'Bearer ' + getAccessToken(),
-    'tenant-id': getTenantId()
-  }
-  uploadDisabled.value = true
-  uploadRef.value!.submit()
-}
-// 文件上传成功
-const handleFileSuccess = (response: any): void => {
-  if (response.code !== 0) {
-    message.error(response.msg)
-    return
-  }
-  importDialogVisible.value = false
-  uploadDisabled.value = false
-  const data = response.data
-  let text = '上传成功数量:' + data.createUsernames.length + ';'
-  for (let username of data.createUsernames) {
-    text += '< ' + username + ' >'
-  }
-  text += '更新成功数量:' + data.updateUsernames.length + ';'
-  for (const username of data.updateUsernames) {
-    text += '< ' + username + ' >'
-  }
-  text += '更新失败数量:' + Object.keys(data.failureUsernames).length + ';'
-  for (const username in data.failureUsernames) {
-    text += '< ' + username + ': ' + data.failureUsernames[username] + ' >'
-  }
-  message.alert(text)
-  getList()
-}
-// 文件数超出提示
-const handleExceed = (): void => {
-  message.error('最多只能上传一个文件!')
-}
-// 上传错误提示
-const excelUploadError = (): void => {
-  message.error('导入数据失败,请您重新上传!')
-}
-// ========== 初始化 ==========
-onMounted(async () => {
-  await getPostOptions()
-  await getList()
-  await getTree()
-})
-</script>
-
 <template>
   <div class="flex">
     <el-card class="w-1/5 user" :gutter="12" shadow="always">
@@ -546,6 +258,293 @@ onMounted(async () => {
     </template>
   </XModal>
 </template>
+<script setup lang="ts">
+import { onMounted, reactive, ref, unref, watch } from 'vue'
+import dayjs from 'dayjs'
+import {
+  ElTag,
+  ElInput,
+  ElCard,
+  ElTree,
+  ElTreeSelect,
+  ElSelect,
+  ElOption,
+  ElTransfer,
+  ElForm,
+  ElFormItem,
+  ElUpload,
+  ElSwitch,
+  ElCheckbox,
+  UploadInstance,
+  UploadRawFile
+} from 'element-plus'
+import { handleTree } from '@/utils/tree'
+import { useI18n } from '@/hooks/web/useI18n'
+import { useTable } from '@/hooks/web/useTable'
+import { FormExpose } from '@/components/Form'
+import type { UserVO } from '@/api/system/user/types'
+import type { PostVO } from '@/api/system/post'
+import type { PermissionAssignUserRoleReqVO } from '@/api/system/permission/types'
+import { listSimpleDeptApi } from '@/api/system/dept'
+import { listSimplePostsApi } from '@/api/system/post'
+import { listSimpleRolesApi } from '@/api/system/role'
+import { aassignUserRoleApi, listUserRolesApi } from '@/api/system/permission'
+import { rules, allSchemas } from './user.data'
+import * as UserApi from '@/api/system/user'
+import download from '@/utils/download'
+import { useRouter } from 'vue-router'
+import { CommonStatusEnum } from '@/utils/constants'
+import { getAccessToken, getTenantId } from '@/utils/auth'
+import { useMessage } from '@/hooks/web/useMessage'
+
+const message = useMessage()
+
+const defaultProps = {
+  children: 'children',
+  label: 'name',
+  value: 'id'
+}
+const { t } = useI18n() // 国际化
+
+// ========== 列表相关 ==========
+const tableTitle = ref('用户列表')
+const { register, tableObject, methods } = useTable<UserVO>({
+  getListApi: UserApi.getUserPageApi,
+  delListApi: UserApi.deleteUserApi,
+  exportListApi: UserApi.exportUserApi
+})
+const { getList, setSearchParams, delList, exportList } = methods
+
+// ========== 创建部门树结构 ==========
+const filterText = ref('')
+const deptOptions = ref<any[]>([]) // 树形结构
+const searchForm = ref<FormExpose>()
+const treeRef = ref<InstanceType<typeof ElTree>>()
+const getTree = async () => {
+  const res = await listSimpleDeptApi()
+  deptOptions.value.push(...handleTree(res))
+}
+const filterNode = (value: string, data: Tree) => {
+  if (!value) return true
+  return data.name.includes(value)
+}
+const handleDeptNodeClick = (data: { [key: string]: any }) => {
+  tableObject.params = {
+    deptId: data.id
+  }
+  tableTitle.value = data.name
+  methods.getList()
+}
+const { push } = useRouter()
+const handleDeptEdit = () => {
+  push('/system/dept')
+}
+watch(filterText, (val) => {
+  treeRef.value!.filter(val)
+})
+// ========== CRUD 相关 ==========
+const loading = ref(false) // 遮罩层
+const actionType = ref('') // 操作按钮的类型
+const dialogVisible = ref(false) // 是否显示弹出层
+const dialogTitle = ref('edit') // 弹出层标题
+const formRef = ref<FormExpose>() // 表单 Ref
+const deptId = ref() // 部门ID
+const postIds = ref<string[]>([]) // 岗位ID
+const postOptions = ref<PostVO[]>([]) //岗位列表
+
+// 获取岗位列表
+const getPostOptions = async () => {
+  const res = await listSimplePostsApi()
+  postOptions.value.push(...res)
+}
+// 设置标题
+const setDialogTile = async (type: string) => {
+  dialogTitle.value = t('action.' + type)
+  actionType.value = type
+  dialogVisible.value = true
+}
+
+// 新增操作
+const handleAdd = async () => {
+  // 重置表单
+  deptId.value = null
+  postIds.value = []
+  dialogVisible.value = true
+  dialogTitle.value = t('action.create')
+  actionType.value = 'create'
+  await unref(formRef)?.getElFormRef().resetFields()
+}
+
+// 修改操作
+const handleUpdate = async (row: UserVO) => {
+  await setDialogTile('update')
+  unref(formRef)?.delSchema('username')
+  unref(formRef)?.delSchema('password')
+  // 设置数据
+  const res = await UserApi.getUserApi(row.id)
+  deptId.value = res.deptId
+  postIds.value = res.postIds
+  unref(formRef)?.setValues(res)
+}
+
+// 提交按钮
+const submitForm = async () => {
+  loading.value = true
+  // 提交请求
+  try {
+    const data = unref(formRef)?.formModel as UserVO
+    data.deptId = deptId.value
+    data.postIds = postIds.value
+    if (actionType.value === 'create') {
+      await UserApi.createUserApi(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await UserApi.updateUserApi(data)
+      message.success(t('common.updateSuccess'))
+    }
+    // 操作成功,重新加载列表
+    dialogVisible.value = false
+    await getList()
+  } finally {
+    loading.value = false
+  }
+}
+// 改变用户状态操作
+const handleStatusChange = async (row: UserVO) => {
+  const text = row.status === CommonStatusEnum.ENABLE ? '启用' : '停用'
+  message
+    .confirm('确认要"' + text + '""' + row.username + '"用户吗?', t('common.reminder'))
+    .then(async () => {
+      row.status =
+        row.status === CommonStatusEnum.ENABLE ? CommonStatusEnum.ENABLE : CommonStatusEnum.DISABLE
+      await UserApi.updateUserStatusApi(row.id, row.status)
+      message.success(text + '成功')
+      await getList()
+    })
+    .catch(() => {
+      row.status =
+        row.status === CommonStatusEnum.ENABLE ? CommonStatusEnum.DISABLE : CommonStatusEnum.ENABLE
+    })
+}
+// 重置密码
+const handleResetPwd = (row: UserVO) => {
+  message.prompt('请输入"' + row.username + '"的新密码', t('common.reminder')).then(({ value }) => {
+    UserApi.resetUserPwdApi(row.id, value).then(() => {
+      message.success('修改成功,新密码是:' + value)
+    })
+  })
+}
+// 分配角色
+const roleDialogVisible = ref(false)
+const roleOptions = ref()
+const userRole = reactive({
+  id: 0,
+  username: '',
+  nickname: '',
+  roleIds: []
+})
+const handleRole = async (row: UserVO) => {
+  userRole.id = row.id
+  userRole.username = row.username
+  userRole.nickname = row.nickname
+  // 获得角色拥有的权限集合
+  const roles = await listUserRolesApi(row.id)
+  userRole.roleIds = roles
+  // 获取角色列表
+  const roleOpt = await listSimpleRolesApi()
+  roleOptions.value = roleOpt
+  roleDialogVisible.value = true
+}
+// 提交
+const submitRole = async () => {
+  const data = ref<PermissionAssignUserRoleReqVO>({
+    userId: userRole.id,
+    roleIds: userRole.roleIds
+  })
+  await aassignUserRoleApi(data.value)
+  message.success(t('common.updateSuccess'))
+  roleDialogVisible.value = false
+}
+// ========== 详情相关 ==========
+const detailRef = ref()
+
+// 详情操作
+const handleDetail = async (row: UserVO) => {
+  // 设置数据
+  detailRef.value = row
+  await setDialogTile('detail')
+}
+// ========== 导入相关 ==========
+const importDialogVisible = ref(false)
+const uploadDisabled = ref(false)
+const importDialogTitle = ref('用户导入')
+const updateSupport = ref(0)
+let updateUrl = import.meta.env.VITE_BASE_URL + import.meta.env.VITE_API_URL + '/system/user/import'
+const uploadHeaders = ref()
+// 下载导入模版
+const handleImportTemp = async () => {
+  const res = await UserApi.importUserTemplateApi()
+  download.excel(res, '用户导入模版.xls')
+}
+// 文件上传之前判断
+const beforeExcelUpload = (file: UploadRawFile) => {
+  const isExcel =
+    file.type === 'application/vnd.ms-excel' ||
+    file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
+  const isLt5M = file.size / 1024 / 1024 < 5
+  if (!isExcel) message.error('上传文件只能是 xls / xlsx 格式!')
+  if (!isLt5M) message.error('上传文件大小不能超过 5MB!')
+  return isExcel && isLt5M
+}
+// 文件上传
+const uploadRef = ref<UploadInstance>()
+const submitFileForm = () => {
+  uploadHeaders.value = {
+    Authorization: 'Bearer ' + getAccessToken(),
+    'tenant-id': getTenantId()
+  }
+  uploadDisabled.value = true
+  uploadRef.value!.submit()
+}
+// 文件上传成功
+const handleFileSuccess = (response: any): void => {
+  if (response.code !== 0) {
+    message.error(response.msg)
+    return
+  }
+  importDialogVisible.value = false
+  uploadDisabled.value = false
+  const data = response.data
+  let text = '上传成功数量:' + data.createUsernames.length + ';'
+  for (let username of data.createUsernames) {
+    text += '< ' + username + ' >'
+  }
+  text += '更新成功数量:' + data.updateUsernames.length + ';'
+  for (const username of data.updateUsernames) {
+    text += '< ' + username + ' >'
+  }
+  text += '更新失败数量:' + Object.keys(data.failureUsernames).length + ';'
+  for (const username in data.failureUsernames) {
+    text += '< ' + username + ': ' + data.failureUsernames[username] + ' >'
+  }
+  message.alert(text)
+  getList()
+}
+// 文件数超出提示
+const handleExceed = (): void => {
+  message.error('最多只能上传一个文件!')
+}
+// 上传错误提示
+const excelUploadError = (): void => {
+  message.error('导入数据失败,请您重新上传!')
+}
+// ========== 初始化 ==========
+onMounted(async () => {
+  await getPostOptions()
+  await getList()
+  await getTree()
+})
+</script>
 
 <style scoped>
 .user {