Commit c0d5a566 by YunaiV

Vue3 重构:REVIEW 部门管理

parent 44dc02a0
<template> <template>
<Dialog :title="modelTitle" v-model="modelVisible" width="800"> <Dialog :title="modelTitle" v-model="modelVisible">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="80px"> <el-form
<el-row> ref="formRef"
<el-col :span="24" v-if="formData.parentId !== 0"> :model="formData"
<el-form-item label="上级部门" prop="parentId"> :rules="formRules"
<el-tree-select label-width="80px"
v-model="formData.parentId" v-loading="formLoading"
:data="deptOptions" >
:props="{ value: 'id', label: 'name', children: 'children' }" <el-form-item label="上级部门" prop="parentId">
value-key="deptId" <el-tree-select
placeholder="选择上级部门" v-model="formData.parentId"
check-strictly :data="deptTree"
/> :props="{ value: 'id', label: 'name', children: 'children' }"
</el-form-item> value-key="deptId"
</el-col> placeholder="请选择上级部门"
<el-col :span="12"> check-strictly
<el-form-item label="部门名称" prop="name"> default-expand-all
<el-input v-model="formData.name" placeholder="请输入部门名称" /> />
</el-form-item> </el-form-item>
</el-col> <el-form-item label="部门名称" prop="name">
<el-col :span="12"> <el-input v-model="formData.name" placeholder="请输入部门名称" />
<el-form-item label="显示排序" prop="sort"> </el-form-item>
<el-input-number v-model="formData.sort" controls-position="right" :min="0" /> <el-form-item label="显示排序" prop="sort">
</el-form-item> <el-input-number v-model="formData.sort" controls-position="right" :min="0" />
</el-col> </el-form-item>
<el-col :span="12"> <el-form-item label="负责人" prop="leaderUserId">
<el-form-item label="负责人" prop="leaderUserId"> <el-select
<el-select v-model="formData.leaderUserId"
v-model="formData.leaderUserId" placeholder="请输入负责人"
placeholder="请输入负责人" clearable
clearable style="width: 100%"
style="width: 100%" >
> <el-option
<el-option v-for="item in userList"
v-for="item in userList" :key="item.id"
:key="item.id" :label="item.nickname"
:label="item.nickname" :value="item.id"
:value="item.id" />
/> </el-select>
</el-select> </el-form-item>
</el-form-item> <el-form-item label="联系电话" prop="phone">
</el-col> <el-input v-model="formData.phone" placeholder="请输入联系电话" maxlength="11" />
<el-col :span="12"> </el-form-item>
<el-form-item label="联系电话" prop="phone"> <el-form-item label="邮箱" prop="email">
<el-input v-model="formData.phone" placeholder="请输入联系电话" maxlength="11" /> <el-input v-model="formData.email" placeholder="请输入邮箱" maxlength="50" />
</el-form-item> </el-form-item>
</el-col> <el-form-item label="状态" prop="status">
<el-col :span="12"> <el-select v-model="formData.status" placeholder="请选择状态" clearable>
<el-form-item label="邮箱" prop="email"> <el-option
<el-input v-model="formData.email" placeholder="请输入邮箱" maxlength="50" /> v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
</el-form-item> :key="dict.value"
</el-col> :label="dict.label"
<el-col :span="12"> :value="dict.value"
<el-form-item label="状态" prop="status"> />
<el-select v-model="formData.status" placeholder="请选择状态" clearable> </el-select>
<el-option </el-form-item>
v-for="dict in getDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="parseInt(dict.value)"
:label="dict.label"
:value="parseInt(dict.value)"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form> </el-form>
<template #footer> <template #footer>
<el-button type="primary" @click="submitForm">确 定</el-button> <el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="modelVisible = false">取 消</el-button> <el-button @click="modelVisible = false">取 消</el-button>
</template> </template>
</Dialog> </Dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { DICT_TYPE, getDictOptions } from '@/utils/dict' import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import * as DeptApi from '@/api/system/dept'
import { UserVO } from '@/api/system/user'
import { handleTree } from '@/utils/tree' import { handleTree } from '@/utils/tree'
import * as DeptApi from '@/api/system/dept'
import * as UserApi from '@/api/system/user'
import { CommonStatusEnum } from '@/utils/constants'
const { t } = useI18n() // 国际化 const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗 const message = useMessage() // 消息弹窗
const modelVisible = ref(false) // 弹窗的是否展示 const modelVisible = ref(false) // 弹窗的是否展示
const modelTitle = ref('') // 弹窗的标题 const modelTitle = ref('') // 弹窗的标题
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
const formType = ref('') // 表单的类型:create - 新增;update - 修改 const formType = ref('') // 表单的类型:create - 新增;update - 修改
const formRef = ref() // 表单 Ref
const deptOptions = ref() // 树形结构
const userList = ref() // 负责人列表选项结构
const formData = ref({ const formData = ref({
id: undefined, id: undefined,
title: '', title: '',
...@@ -96,22 +84,23 @@ const formData = ref({ ...@@ -96,22 +84,23 @@ const formData = ref({
leaderUserId: undefined, leaderUserId: undefined,
phone: undefined, phone: undefined,
email: undefined, email: undefined,
status: undefined status: CommonStatusEnum.ENABLE
}) })
const formRules = reactive({ const formRules = reactive({
parentId: [{ required: true, message: '上级部门不能为空', trigger: 'blur' }], parentId: [{ required: true, message: '上级部门不能为空', trigger: 'blur' }],
name: [{ required: true, message: '部门名称不能为空', trigger: 'blur' }], name: [{ required: true, message: '部门名称不能为空', trigger: 'blur' }],
order: [{ required: true, message: '显示排序不能为空', trigger: 'blur' }], sort: [{ required: true, message: '显示排序不能为空', trigger: 'blur' }],
email: [{ type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change'] }], email: [{ type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change'] }],
phone: [ phone: [
{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: '请输入正确的手机号码', trigger: 'blur' } { pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: '请输入正确的手机号码', trigger: 'blur' }
] ]
}) })
const formRef = ref() // 表单 Ref
const deptTree = ref() // 树形结构
const userList = ref<UserApi.UserVO[]>([]) // 用户列表
/** 打开弹窗 */ /** 打开弹窗 */
const openModal = async (type: string, id?: number, userOption?: UserVO[]) => { const open = async (type: string, id?: number) => {
userList.value = userOption
modelVisible.value = true modelVisible.value = true
modelTitle.value = t('action.' + type) modelTitle.value = t('action.' + type)
formType.value = type formType.value = type
...@@ -125,9 +114,12 @@ const openModal = async (type: string, id?: number, userOption?: UserVO[]) => { ...@@ -125,9 +114,12 @@ const openModal = async (type: string, id?: number, userOption?: UserVO[]) => {
formLoading.value = false formLoading.value = false
} }
} }
// 获得用户列表
userList.value = await UserApi.getSimpleUserList()
// 获得部门树
await getTree()
} }
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
defineExpose({ openModal }) // 提供 openModal 方法,用于打开弹窗
/** 提交表单 */ /** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
...@@ -166,22 +158,17 @@ const resetForm = () => { ...@@ -166,22 +158,17 @@ const resetForm = () => {
leaderUserId: undefined, leaderUserId: undefined,
phone: undefined, phone: undefined,
email: undefined, email: undefined,
status: undefined status: CommonStatusEnum.ENABLE
} }
formRef.value?.resetFields() formRef.value?.resetFields()
} }
// 获取下拉框[上级]的数据 /** 获得部门树 */
const getTree = async () => { const getTree = async () => {
deptOptions.value = [] deptTree.value = []
const res = await DeptApi.listSimpleDeptApi() const data = await DeptApi.listSimpleDeptApi()
let dept: Tree = { id: 0, name: '顶级部门', children: [] } let dept: Tree = { id: 0, name: '顶级部门', children: [] }
dept.children = handleTree(res) dept.children = handleTree(data)
deptOptions.value.push(dept) deptTree.value.push(dept)
} }
// ========== 初始化 ==========
onMounted(async () => {
await getTree()
})
</script> </script>
...@@ -9,50 +9,61 @@ ...@@ -9,50 +9,61 @@
label-width="68px" label-width="68px"
> >
<el-form-item label="部门名称" prop="title"> <el-form-item label="部门名称" prop="title">
<el-input v-model="queryParams.name" placeholder="请输入部门名称" clearable /> <el-input
v-model="queryParams.name"
placeholder="请输入部门名称"
clearable
class="!w-240px"
/>
</el-form-item> </el-form-item>
<el-form-item label="部门状态" prop="status"> <el-form-item label="部门状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择" clearable> <el-select
v-model="queryParams.status"
placeholder="请选择不么你状态"
clearable
class="!w-240px"
>
<el-option <el-option
v-for="dict in getDictOptions(DICT_TYPE.COMMON_STATUS)" v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="parseInt(dict.value)" :key="dict.value"
:label="dict.label" :label="dict.label"
:value="parseInt(dict.value)" :value="dict.value"
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button <el-button
type="primary" type="primary"
plain plain
@click="openModal('create')" @click="openForm('create')"
v-hasPermi="['system:dept:create']" v-hasPermi="['system:dept:create']"
><Icon icon="ep:plus" class="mr-5px" /> 新增</el-button
>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain @click="toggleExpandAll"
><Icon icon="ep:sort" class="mr-5px" /> 展开/折叠</el-button
> >
</el-col> <Icon icon="ep:plus" class="mr-5px" /> 新增
</el-row> </el-button>
<!-- 列表 --> <el-button type="danger" plain @click="toggleExpandAll">
<Icon icon="ep:sort" class="mr-5px" /> 展开/折叠
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table <el-table
v-if="refreshTable"
v-loading="loading" v-loading="loading"
:data="deptDatas" :data="list"
row-key="id" row-key="id"
v-if="refreshTable"
:default-expand-all="isExpandAll" :default-expand-all="isExpandAll"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
> >
<el-table-column prop="name" label="部门名称" width="260" /> <el-table-column prop="name" label="部门名称" width="260" />
<el-table-column prop="leader" label="负责人" :formatter="userNicknameFormat" width="120" /> <el-table-column prop="leader" label="负责人" width="120">
<template #default="scope">
{{ userList.find((user) => user.id === scope.row.leaderUserId)?.nickname }}
</template>
</el-table-column>
<el-table-column prop="sort" label="排序" width="200" /> <el-table-column prop="sort" label="排序" width="200" />
<el-table-column prop="status" label="状态" width="100"> <el-table-column prop="status" label="状态" width="100">
<template #default="scope"> <template #default="scope">
...@@ -66,43 +77,44 @@ ...@@ -66,43 +77,44 @@
width="180" width="180"
:formatter="dateFormatter" :formatter="dateFormatter"
/> />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="fixed-width">
<template #default="scope"> <template #default="scope">
<el-button <el-button
link link
type="primary" type="primary"
icon="el-icon-edit" @click="openForm('update', scope.row.id)"
@click="openModal('update', scope.row.id)"
v-hasPermi="['system:dept:update']" v-hasPermi="['system:dept:update']"
>修改</el-button
> >
修改
</el-button>
<el-button <el-button
v-if="scope.row.parentId !== 0"
link link
type="danger" type="danger"
icon="el-icon-delete"
@click="handleDelete(scope.row.id)" @click="handleDelete(scope.row.id)"
v-hasPermi="['system:dept:delete']" v-hasPermi="['system:dept:delete']"
>删除</el-button
> >
删除
</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
</ContentWrap> </ContentWrap>
<!-- 添加或修改部门对话框 --> <!-- 表单弹窗:添加/修改 -->
<dept-form ref="modalRef" @success="getList" /> <DeptForm ref="formRef" @success="getList" />
</template> </template>
<script setup lang="ts" name="Dept"> <script setup lang="ts" name="Dept">
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import { handleTree } from '@/utils/tree' import { handleTree } from '@/utils/tree'
import * as DeptApi from '@/api/system/dept' import * as DeptApi from '@/api/system/dept'
import { DICT_TYPE, getDictOptions } from '@/utils/dict' import DeptForm from './DeptForm.vue'
import DeptForm from './form.vue' import * as UserApi from '@/api/system/user'
import { dateFormatter } from '@/utils/formatTime'
import { getSimpleUserList, UserVO } from '@/api/system/user'
const message = useMessage() // 消息弹窗 const message = useMessage() // 消息弹窗
const { t } = useI18n() // 国际化 const { t } = useI18n() // 国际化
// 搜索变量
const loading = ref(true) // 列表的加载中
const list = ref() // 列表的数据
const queryParams = reactive({ const queryParams = reactive({
title: '', title: '',
name: undefined, name: undefined,
...@@ -110,19 +122,20 @@ const queryParams = reactive({ ...@@ -110,19 +122,20 @@ const queryParams = reactive({
pageNo: 1, pageNo: 1,
pageSize: 100 pageSize: 100
}) })
const queryFormRef = ref() // 搜索的表单 const queryFormRef = ref() // 搜索的表单
const deptDatas = ref() // 数据变量
const userOption = ref<UserVO[]>([])
const isExpandAll = ref(true) // 是否展开,默认全部展开 const isExpandAll = ref(true) // 是否展开,默认全部展开
const refreshTable = ref(true) // 重新渲染表格状态 const refreshTable = ref(true) // 重新渲染表格状态
const loading = ref(true) // 列表的加载中 const userList = ref<UserApi.UserVO[]>([]) // 用户列表
// 获取用户列表 /** 查询部门列表 */
const getUserList = async () => { const getList = async () => {
const res = await getSimpleUserList() loading.value = true
userOption.value = res try {
const data = await DeptApi.getDeptPageApi(queryParams)
list.value = handleTree(data)
} finally {
loading.value = false
}
} }
/** 展开/折叠操作 */ /** 展开/折叠操作 */
...@@ -140,6 +153,19 @@ const handleQuery = () => { ...@@ -140,6 +153,19 @@ const handleQuery = () => {
getList() getList()
} }
/** 重置按钮操作 */
const resetQuery = () => {
queryParams.pageNo = 1
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */ /** 删除按钮操作 */
const handleDelete = async (id: number) => { const handleDelete = async (id: number) => {
try { try {
...@@ -153,47 +179,10 @@ const handleDelete = async (id: number) => { ...@@ -153,47 +179,10 @@ const handleDelete = async (id: number) => {
} catch {} } catch {}
} }
/** 查询部门列表 */ /** 初始化 **/
const getList = async () => {
loading.value = true
try {
const res = await DeptApi.getDeptPageApi(queryParams)
deptDatas.value = handleTree(res)
} finally {
loading.value = false
}
}
/** 重置按钮操作 */
const resetQuery = () => {
queryParams.pageNo = 1
queryParams.name = undefined
queryParams.status = undefined
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const modalRef = ref()
const openModal = (type: string, id?: number) => {
modalRef.value.openModal(type, id, userOption.value)
}
const userNicknameFormat = (row) => {
if (!row || !row.leaderUserId) {
return '未设置'
}
for (const user of userOption.value) {
if (row.leaderUserId === user.id) {
return user.nickname
}
}
return '未知【' + row.leaderUserId + '】'
}
// ========== 初始化 ==========
onMounted(async () => { onMounted(async () => {
await getUserList()
await getList() await getList()
// 获取用户列表
userList.value = await UserApi.getSimpleUserList()
}) })
</script> </script>
...@@ -99,7 +99,7 @@ ...@@ -99,7 +99,7 @@
width="180" width="180"
:formatter="dateFormatter" :formatter="dateFormatter"
/> />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="small-paddingfixed-width">
<template #default="scope"> <template #default="scope">
<el-button <el-button
link link
......
...@@ -169,7 +169,7 @@ ...@@ -169,7 +169,7 @@
<el-table-column <el-table-column
label="操作" label="操作"
align="center" align="center"
class-name="small-padding fixed-width" class-name="fixed-width"
width="210" width="210"
fixed="right" fixed="right"
> >
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment