Files
2023-06-13 17:21:00 +08:00

890 lines
24 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container">
<el-row :gutter="20">
<!--部门数据-->
<el-col :span="4" :xs="24">
<div class="head-container">
<el-input
v-model="deptName"
clearable
placeholder="请输入部门名称"
prefix-icon="Search"
style="margin-bottom: 20px"
/>
</div>
<div class="head-container">
<el-tree
ref="deptTreeRef"
:data="deptOptions"
:expand-on-click-node="false"
:filter-node-method="filterNode"
:props="{ label: 'label', children: 'children' }"
default-expand-all
highlight-current
node-key="id"
@node-click="handleNodeClick"
/>
</div>
</el-col>
<!--用户数据-->
<el-col :span="20" :xs="24">
<el-form
v-show="showSearch"
ref="queryRef"
:inline="true"
:model="queryParams"
label-width="68px"
>
<el-form-item label="姓名" prop="nickname">
<el-input
v-model="queryParams.nickname"
clearable
placeholder="请输入姓名"
style="width: 240px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="手机号码" prop="phone">
<el-input
v-model="queryParams.phone"
clearable
placeholder="请输入手机号码"
style="width: 240px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select
v-model="queryParams.status"
clearable
placeholder="用户状态"
style="width: 240px"
>
<el-option
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="创建时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
end-placeholder="结束日期"
range-separator="-"
start-placeholder="开始日期"
type="daterange"
value-format="YYYY-MM-DD"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button icon="Search" type="primary" @click="handleQuery"
>搜索
</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
v-hasPermi="['system:user:add']"
icon="Plus"
plain
type="primary"
@click="handleAdd"
>新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
v-hasPermi="['system:user:edit']"
:disabled="single"
icon="Edit"
plain
type="success"
@click="handleUpdate"
>修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
v-hasPermi="['system:user:remove']"
:disabled="multiple"
icon="Delete"
plain
type="danger"
@click="handleDelete"
>删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
v-hasPermi="['system:user:import']"
icon="Upload"
plain
type="info"
@click="handleImport"
>导入
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
v-hasPermi="['system:user:export']"
icon="Download"
plain
type="warning"
@click="handleExport"
>导出
</el-button>
</el-col>
<right-toolbar
v-model:showSearch="showSearch"
:columns="columns"
@queryTable="getList"
></right-toolbar>
</el-row>
<el-table
v-loading="loading"
:data="userList"
@selection-change="handleSelectionChange"
>
<el-table-column align="center" type="selection" width="50" />
<el-table-column
v-if="columns[0].visible"
key="userId"
align="center"
label="用户编号"
prop="userId"
/>
<el-table-column
v-if="columns[1].visible"
key="username"
:show-overflow-tooltip="true"
align="center"
label="登录账号"
prop="username"
/>
<el-table-column
v-if="columns[2].visible"
key="nickname"
:show-overflow-tooltip="true"
align="center"
label="姓名"
prop="nickname"
/>
<el-table-column
v-if="columns[3].visible"
key="deptName"
:show-overflow-tooltip="true"
align="center"
label="部门"
prop="deptName"
/>
<el-table-column
v-if="columns[4].visible"
key="phone"
align="center"
label="手机号码"
prop="phone"
width="120"
/>
<el-table-column
v-if="columns[5].visible"
key="status"
align="center"
label="状态"
>
<template #default="scope">
<el-switch
v-model="scope.row.status"
active-value="1"
inactive-value="0"
@change="handleStatusChange(scope.row)"
></el-switch>
</template>
</el-table-column>
<el-table-column
v-if="columns[6].visible"
align="center"
label="创建时间"
prop="createTime"
width="160"
>
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column
align="center"
class-name="small-padding fixed-width"
label="操作"
width="150"
>
<template #default="scope">
<el-tooltip
v-if="scope.row.userId !== 1"
content="修改"
placement="top"
>
<el-button
v-hasPermi="['system:user:edit']"
icon="Edit"
link
type="primary"
@click="handleUpdate(scope.row)"
></el-button>
</el-tooltip>
<el-tooltip
v-if="scope.row.userId !== 1"
content="删除"
placement="top"
>
<el-button
v-hasPermi="['system:user:remove']"
icon="Delete"
link
type="primary"
@click="handleDelete(scope.row)"
></el-button>
</el-tooltip>
<el-tooltip
v-if="scope.row.userId !== 1"
content="重置密码"
placement="top"
>
<el-button
v-hasPermi="['system:user:resetPwd']"
icon="Key"
link
type="primary"
@click="handleResetPwd(scope.row)"
></el-button>
</el-tooltip>
<el-tooltip
v-if="scope.row.userId !== 1"
content="分配角色"
placement="top"
>
<el-button
v-hasPermi="['system:user:edit']"
icon="CircleCheck"
link
type="primary"
@click="handleAuthRole(scope.row)"
></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
v-model:limit="queryParams.pageSize"
v-model:page="queryParams.pageNum"
:total="total"
@pagination="getList"
/>
</el-col>
</el-row>
<!-- 添加或修改用户配置对话框 -->
<el-dialog
draggable
v-model="open"
:title="title"
append-to-body
width="600px"
>
<el-form ref="userRef" :model="form" :rules="rules" label-width="80px">
<el-row>
<el-col :span="12">
<el-form-item label="姓名" prop="nickname">
<el-input
v-model="form.nickname"
maxlength="30"
placeholder="请输入姓名"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="性别">
<el-select v-model="form.gender" placeholder="请选择">
<el-option
v-for="dict in sys_user_gender"
:key="dict.value"
:label="dict.label"
:value="dict.value"
></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="手机" prop="phone">
<el-input
v-model="form.phone"
maxlength="11"
placeholder="请输入手机号码"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="邮箱" prop="email">
<el-input
v-model="form.email"
maxlength="50"
placeholder="请输入邮箱"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="部门" prop="deptId">
<el-tree-select
v-model="form.deptId"
:data="deptOptions"
:props="{ value: 'id', label: 'label', children: 'children' }"
check-strictly
placeholder="请选择部门"
value-key="id"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="岗位">
<el-select v-model="form.postIds" multiple placeholder="请选择">
<el-option
v-for="item in postOptions"
:key="item.postId"
:label="item.postName"
:value="item.postId"
></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="角色">
<el-select v-model="form.roleIds" multiple placeholder="请选择">
<el-option
v-for="item in roleOptions"
:key="item.roleId"
:label="item.roleName"
:value="item.roleId"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="dict.value"
>{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item
v-if="form.userId == undefined"
label="登录账号"
prop="username"
>
<el-input
v-model="form.username"
autocomplete="off"
maxlength="30"
placeholder="请输入登录账号"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
v-if="form.userId == undefined"
label="登录密码"
prop="password"
>
<el-input
v-model="form.password"
autocomplete="off"
maxlength="20"
placeholder="请输入登录密码"
show-password
type="password"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="备注">
<el-input
v-model="form.remark"
placeholder="请输入内容"
type="textarea"
></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
<!-- 用户导入对话框 -->
<el-dialog
draggable
v-model="upload.open"
:title="upload.title"
append-to-body
width="400px"
>
<el-upload
ref="uploadRef"
:action="upload.url + '?updateSupport=' + upload.updateSupport"
:auto-upload="false"
:disabled="upload.isUploading"
:headers="upload.headers"
:limit="1"
:on-progress="handleFileUploadProgress"
:on-success="handleFileSuccess"
accept=".xlsx, .xls"
drag
>
<el-icon class="el-icon--upload">
<upload-filled />
</el-icon>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<template #tip>
<div class="el-upload__tip text-center">
<ol style="text-align: start; margin-left: 20px">
<li>(*)为必填项</li>
<li>部门,角色,岗位请填数字编号</li>
<li>角色,岗位若存在多个,请以英文逗号隔开</li>
<li>禁止任何的换行或空格</li>
<li style="color: #f00; font-size: 13px">
请手动更改单元格格式为文本格式
</li>
<li>
<span>仅允许导入xlsxlsx格式文件</span>
<el-link
:underline="false"
style="font-size: 12px; vertical-align: baseline"
type="primary"
@click="importTemplate"
>下载模板
</el-link>
</li>
</ol>
</div>
</template>
</el-upload>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitFileForm"> </el-button>
<el-button @click="upload.open = false"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script lang="jsx" name="User" setup>
import { getToken } from "@/utils/auth";
import {
addUser,
changeUserStatus,
delUser,
deptTreeSelect,
getUser,
listUser,
resetUserPwd,
updateUser,
} from "@/api/system/user";
import { sys_normal_disable, sys_user_gender } from "@/constant/dict";
import { ElMessageBox } from "element-plus";
const router = useRouter();
const { proxy } = getCurrentInstance();
const userList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const dateRange = ref([]);
const deptName = ref("");
const deptOptions = ref(undefined);
const initPassword = ref(undefined);
const postOptions = ref([]);
const roleOptions = ref([]);
/*** 用户导入参数 */
const upload = reactive({
// 是否显示弹出层(用户导入)
open: false,
// 弹出层标题(用户导入)
title: "",
// 是否禁用上传
isUploading: false,
// 是否更新已经存在的用户数据
updateSupport: 0,
// 设置上传的请求头部
headers: { Authorization: "Bearer " + getToken() },
// 上传的地址
url: import.meta.env.VITE_APP_BASE_API + "/system/user/importData",
});
// 列显隐信息
const columns = ref([
{ key: 0, label: `用户编号`, visible: true },
{ key: 1, label: `登录账号`, visible: true },
{ key: 2, label: `姓名`, visible: true },
{ key: 3, label: `部门`, visible: true },
{ key: 4, label: `手机号码`, visible: true },
{ key: 5, label: `状态`, visible: true },
{ key: 6, label: `创建时间`, visible: true },
]);
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
userName: undefined,
phone: undefined,
status: undefined,
deptId: undefined,
},
rules: {
userName: [
{ required: true, message: "登录账号不能为空", trigger: "blur" },
{
min: 2,
max: 20,
message: "登录账号长度必须介于 2 和 20 之间",
trigger: "blur",
},
],
nickName: [{ required: true, message: "姓名不能为空", trigger: "blur" }],
password: [
{ required: true, message: "登录密码不能为空", trigger: "blur" },
{
min: 5,
max: 20,
message: "登录密码长度必须介于 5 和 20 之间",
trigger: "blur",
},
],
email: [
{
type: "email",
message: "请输入正确的邮箱地址",
trigger: ["blur", "change"],
},
],
phone: [
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: "请输入正确的手机号码",
trigger: "blur",
},
],
},
});
const { queryParams, form, rules } = toRefs(data);
/** 通过条件过滤节点 */
const filterNode = (value, data) => {
if (!value) return true;
return data.label.indexOf(value) !== -1;
};
/** 根据名称筛选部门树 */
watch(deptName, (val) => {
proxy.$refs["deptTreeRef"].filter(val);
});
/** 查询部门下拉树结构 */
function getDeptTree() {
deptTreeSelect().then((response) => {
deptOptions.value = response.data;
});
}
/** 查询用户列表 */
function getList() {
loading.value = true;
listUser(proxy.addDateRange(queryParams.value, dateRange.value)).then(
(res) => {
loading.value = false;
userList.value = res.rows;
total.value = res.total;
}
);
}
/** 节点单击事件 */
function handleNodeClick(data) {
queryParams.value.deptId = data.id;
handleQuery();
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = [];
proxy.resetForm("queryRef");
queryParams.value.deptId = undefined;
proxy.$refs.deptTreeRef.setCurrentKey(null);
console.log(queryParams.value);
handleQuery();
}
/** 删除按钮操作 */
function handleDelete(row) {
const userIds = row.userId || ids.value;
const userNames = row.userId
? [row.username]
: userList.value
.filter((el) => userIds.includes(el.userId))
.map((el) => el.username);
const messageVnode = () => (
<>
{userNames.map((username, idx) => (
<el-tag
key={idx}
style={{
marginLeft: idx >= 1 ? "4px" : 0,
}}
type="warning"
>
{username}
</el-tag>
))}
</>
);
ElMessageBox.confirm(messageVnode, "确认删除", {
type: "danger",
"confirm-button-class": "confirm-delete-button",
})
.then(function () {
return delUser(userIds);
})
.then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
})
.catch(() => {});
}
/** 导出按钮操作 */
function handleExport() {
proxy.download(
"system/user/export",
{
...queryParams.value,
},
`user_${new Date().getTime()}.xlsx`
);
}
/** 用户状态修改 */
function handleStatusChange(row) {
let text = row.status === "1" ? "启用" : "停用";
proxy.$modal
.confirm("确认要" + text + '"' + row.nickname + '"用户吗?')
.then(function () {
return changeUserStatus(row.userId, row.status);
})
.then(() => {
proxy.$modal.msgSuccess(text + "成功");
})
.catch(function () {
row.status = row.status === "0" ? "1" : "0";
});
}
/** 更多操作 */
function handleCommand(command, row) {
switch (command) {
case "handleResetPwd":
handleResetPwd(row);
break;
case "handleAuthRole":
handleAuthRole(row);
break;
default:
break;
}
}
/** 跳转角色分配 */
function handleAuthRole(row) {
const userId = row.userId;
router.push("/system/user-auth/role/" + userId);
}
/** 重置密码按钮操作 */
function handleResetPwd(row) {
proxy
.$prompt('请输入"' + row.nickname + '"的新密码', "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
closeOnClickModal: false,
inputPattern: /^.{5,20}$/,
inputErrorMessage: "登录密码长度必须介于 5 和 20 之间",
})
.then(({ value }) => {
resetUserPwd(row.userId, value).then((response) => {
proxy.$modal.msgSuccess("修改成功,新密码是:" + value);
});
})
.catch(() => {});
}
/** 选择条数 */
function handleSelectionChange(selection) {
ids.value = selection.map((item) => item.userId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 导入按钮操作 */
function handleImport() {
upload.title = "用户导入";
upload.open = true;
}
/** 下载模板操作 */
function importTemplate() {
proxy.download(
"system/user/importTemplate",
{},
`user_template_${new Date().getTime()}.xlsx`
);
}
/**文件上传中处理 */
const handleFileUploadProgress = (event, file, fileList) => {
upload.isUploading = true;
};
/** 文件上传成功处理 */
const handleFileSuccess = (response, file, fileList) => {
upload.open = false;
upload.isUploading = false;
proxy.$refs["uploadRef"].handleRemove(file);
proxy.$alert(
"<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" +
response.msg +
"</div>",
"导入结果",
{ dangerouslyUseHTMLString: true }
);
getList();
};
/** 提交上传文件 */
function submitFileForm() {
proxy.$refs["uploadRef"].submit();
}
/** 重置操作表单 */
function reset() {
form.value = {
userId: undefined,
deptId: undefined,
userName: undefined,
nickName: undefined,
password: undefined,
phone: undefined,
email: undefined,
gender: undefined,
status: "1",
remark: undefined,
postIds: [],
roleIds: [],
};
proxy.resetForm("userRef");
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 新增按钮操作 */
function handleAdd() {
reset();
getUser().then((response) => {
postOptions.value = response.posts;
roleOptions.value = response.roles;
open.value = true;
title.value = "添加用户";
form.value.password = initPassword.value;
});
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const userId = row.userId || ids.value;
getUser(userId).then((response) => {
form.value = response.data;
postOptions.value = response.posts;
roleOptions.value = response.roles;
form.value.postIds = response.postIds;
form.value.roleIds = response.roleIds;
open.value = true;
title.value = "修改用户";
form.password = "";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["userRef"].validate((valid) => {
if (valid) {
if (form.value.userId != undefined) {
updateUser(form.value).then((response) => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addUser(form.value).then((response) => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
}
getDeptTree();
getList();
</script>