bonus-ui/src/views/system/user/index.vue

1081 lines
37 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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="5" :xs="24">
<div class="head-container">
<el-input v-model="deptName" placeholder="请输入部门名称" clearable size="small" prefix-icon="el-icon-search"
style="margin-bottom: 20px"
/>
</div>
<div class="head-container">
<el-tree :data="deptOptions" :props="defaultProps" :expand-on-click-node="false"
:filter-node-method="filterNode" ref="tree" node-key="id" default-expand-all highlight-current
@node-click="handleNodeClick"
/>
</div>
</el-col>
<!--用户数据-->
<!-- 查询条件卡片-->
<el-col :span="19" :xs="24">
<div class="card-container">
<div class="card-header query-header">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch"
class="query-form"
>
<el-form-item label="用户名称" prop="userName">
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 230px"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 230px"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="用户状态" clearable style="width: 230px">
<el-option v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker v-model="dateRange" style="width: 230px" value-format="yyyy-MM-dd" type="daterange"
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
></el-date-picker>
</el-form-item>
<el-form-item class="button-group">
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">查询</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
</div>
<!-- 操作按钮和表格卡片 -->
<div class="card-container">
<div class="card-header operation-header">
<el-row :gutter="10" class="mb8 operation-row">
<div class="action-bar">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
v-hasPermi="['system:user:add']"
>新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single"
@click="confirmPassword"
v-hasPermi="['system:user:edit']"
>修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:user:remove']"
>删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport"
v-hasPermi="['system:user:import']"
>导入
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
v-hasPermi="['system:user:export']"
>导出
</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
</div>
</el-row>
</div>
<el-table v-loading="loading" :data="userList" class="my-table" @selection-change="handleSelectionChange"
:selectable="checkSelectable" :row-class-name="getRowClassName">
<el-table-column type="selection" width="50" align="center"/>
<el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible"/>
<el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns[1].visible"
:show-overflow-tooltip="true"
/>
<el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns[2].visible"
:show-overflow-tooltip="true"
/>
<el-table-column label="部门" align="center" key="deptName" prop="dept.deptName" v-if="columns[3].visible"
:show-overflow-tooltip="true"
/>
<el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber"
v-if="columns[4].visible"
width="120"
>
<template slot-scope="scope">
<span>{{ hidePhone(scope.row.phonenumber) }}</span>
</template>
</el-table-column>
<el-table-column label="状态" align="center" key="status" v-if="columns[5].visible">
<template slot-scope="scope">
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1"
@change="handleStatusChange(scope.row)"
></el-switch>
</template>
</el-table-column>
<el-table-column label="账号时效" align="center">
<template slot-scope="scope">
<span>{{ scope.row.isPermanent == 1 ? "长期账号" : "临时账号" }}</span>
</template>
</el-table-column>
<el-table-column v-if="config.registersConfig.approvalStatus" label="审批状态" align="center">
<template slot-scope="scope">
<span>{{ scope.row.approvalStatus == 0 ? "未审批" : "已审批" }}</span>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
<template slot-scope="scope"
v-if="!hasSystemOrAuditrRole(scope.row.roles) && scope.row.userId !== 1 && scope.row.isBuiltIn !== '0'">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['system:user:edit']"
>修改
</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['system:user:remove']"
>删除
</el-button>
<el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)"
v-hasPermi="['system:user:resetPwd', 'system:user:edit']"
>
<el-button size="mini" type="text" icon="el-icon-d-arrow-right">更多</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="handleResetPwd" icon="el-icon-key"
v-hasPermi="['system:user:resetPwd']"
>重置密码
</el-dropdown-item>
<el-dropdown-item command="handleAuthRole" icon="el-icon-circle-check"
v-hasPermi="['system:user:edit']"
>分配角色
</el-dropdown-item>
<el-dropdown-item v-if="scope.row.approvalStatus==0" command="approvalStatus"
icon="el-icon-circle-check"
v-hasPermi="['system:user:approval']"
>账号审批
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-table-column>
</el-table>
<pagination :total="total" :page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize" @pagination="getList"
/>
</div>
</el-col>
</el-row>
<!-- 添加或修改用户配置对话框 -->
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
<el-form ref="form" :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" placeholder="请输入用户昵称" maxlength="30"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="组织机构" prop="deptId">
<treeselect v-model="form.deptId" :searchable="false" :disable-branch-nodes="false" :options="deptOptions"
:show-count="true" placeholder="请选择归属组织机构" @input="handleDeptChange"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="归属部门">
<treeselect
v-model="form.orgId"
:options="orgDeptTree"
placeholder="组织机构下辖部门"
:normalizer="orgDeptNormalizer"
:key="orgTreeKey"
no-options-text="暂无数据"
no-results-text="未找到匹配数据"
/>
</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" placeholder="请输入用户名称" maxlength="30"/>
</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" placeholder="请输入用户密码" type="password" maxlength="20"
show-password
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="用户性别">
<el-select v-model="form.sex" placeholder="请选择性别">
<el-option v-for="dict in dict.type.sys_user_sex" :key="dict.value" :label="dict.label"
:value="dict.value"
></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 dict.type.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 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"
:disabled="item.status == 1"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="角色" prop="roleIds">
<el-select v-model="form.roleIds" multiple placeholder="请选择角色">
<el-option
v-for="item in roleOptions"
:key="item.roleId"
:label="item.roleName"
:value="item.roleId"
:disabled="item.status == 1 || item.roleId === 1"
></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="登录权限" prop="loginTypeArr">
<el-checkbox-group v-model="loginTypeArr">
<el-checkbox v-for="dict in dict.type.sys_login_type" :key="dict.value" :label="dict.value">
{{ dict.label }}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="账号时效" prop="isPermanent">
<el-radio-group v-model="form.isPermanent">
<el-radio v-for="dict in dict.type.sys_user_permanent" :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="24">
<el-form-item label="备注">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
<!-- 用户导入对话框 -->
<el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
<el-upload ref="upload" :limit="1" accept=".xlsx, .xls" :headers="upload.headers"
:action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading"
:on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag
>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip text-center" slot="tip">
<div class="el-upload__tip" slot="tip">
<el-checkbox v-model="upload.updateSupport"/>
是否更新已经存在的用户数据
</div>
<span>仅允许导入xls、xlsx格式文件。</span>
<el-link type="primary" :underline="false" style="font-size:12px;vertical-align: baseline;"
@click="importTemplate"
>下载模板
</el-link>
</div>
</el-upload>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitFileForm">确 定</el-button>
<el-button @click="upload.open = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
listUser,
getUser,
delUser,
addUser,
updateUser,
resetUserPwd,
changeUserStatus,
deptTreeSelect, approvalStatus, confirmPassword, listDeptByOrgId
} from '@/api/system/user'
import { listOrgTreeSimple } from '@/api/system/newdept'
import {getToken} from '@/utils/auth'
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import {validateNewPassword} from '@/utils/validate'
export default {
name: 'User',
dicts: ['sys_normal_disable', 'sys_user_sex', 'sys_login_type', 'sys_user_permanent'],
components: {Treeselect},
data() {
return {
orgTreeKey: 0,
orgDeptTree: [],
// 1. 存储选中的部门ID关键
selectedDeptId: undefined,
// 2. 存储选中的部门名称(可选,用于回显更友好)
selectedDeptName: '',
// ... 其他原有变量
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 用户表格数据
userList: null,
// 弹出层标题
title: '',
// 部门树选项
deptOptions: undefined,
// 是否显示弹出层
open: false,
// 部门名称
deptName: undefined,
// 默认密码
initPassword: undefined,
// 日期范围
dateRange: [],
// 岗位选项
postOptions: [],
// 角色选项
roleOptions: [],
// 组织选项
orgOptions: [],
// 登录权限数组
loginTypeArr: [],
// 角色下拉多选限制数量
multipleLimit: 1,
// 表单参数
form: {
orgId: undefined
},
defaultProps: {
children: 'children',
label: 'label'
},
// 用户导入参数
upload: {
// 是否显示弹出层(用户导入)
open: false,
// 弹出层标题(用户导入)
title: '',
// 是否禁用上传
isUploading: false,
// 是否更新已经存在的用户数据
updateSupport: 0,
// 设置上传的请求头部
headers: {Authorization: 'Bearer ' + getToken()},
// 上传的地址
url: process.env.VUE_APP_BASE_API + '/system/user/importData'
},
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
userName: undefined,
phonenumber: undefined,
status: undefined,
deptId: undefined
},
// 列信息
columns: [
{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}
],
// 表单校验
rules: {
userName: [
{required: true, message: '用户名称不能为空', trigger: 'blur'},
{min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur'}
],
nickName: [
{required: true, message: '用户昵称不能为空', trigger: 'blur'}
],
deptId: [{required: true, message: '请选择归属部门', trigger: 'blur'}],
phonenumber: [
{required: true, message: '手机号不能为空', trigger: 'blur'},
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: '请输入正确的手机号码',
trigger: 'blur'
}
],
loginTypeArr: [
{required: true, validator: this.validateLoginType, trigger: 'change'}
],
password: [
{required: true, message: '密码不能为空', trigger: 'blur'},
{validator: validateNewPassword, trigger: 'blur'}
],
roleIds: [
{required: true, message: '请选择角色', trigger: 'change'}
]
}
}
},
computed: {
config() {
return JSON.parse(localStorage.getItem('systemConfig')) || {
registersConfig: {
phoneRegisters: true,
emailRegisters: true,
verificationCode: true,
approvalStatus: true,
}
}; // 获取 JSON 对象
}
},
watch: {
// 根据名称筛选部门树
deptName(val) {
this.$refs.tree.filter(val)
}
},
created() {
this.getList()
this.getDeptTree()
this.getConfigKey('sys.user.initPassword').then(response => {
this.initPassword = response.msg
})
},
methods: {
orgDeptNormalizer(node) {
return {
id: node.id,
label: node.orgName, // 关键在这里
children: node.children
}
},
/* 手机号码脱敏 */
hidePhone(phone) {
if (!phone) return '';
return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2');
},
/* 表单登录权限自定义校验 */
validateLoginType(rule, value, callback) {
if (this.loginTypeArr.length > 0) {
callback()
} else {
callback(new Error('请至少选择一个登录权限'))
}
},
/** 查询用户列表 */
getList() {
this.loading = true
listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
this.userList = response.rows
this.total = response.total
this.loading = false
}
)
},
/** 查询部门下拉树结构 */
getDeptTree() {
deptTreeSelect().then(response => {
this.deptOptions = this.filterTree(response.data)
})
},
filterTree(nodes) {
return nodes
.map(node => {
if (node.children) {
node.children = this.filterTree(node.children)
}
return node
})
.filter(node => node.status !== '1')
},
// 筛选节点
filterNode(value, data) {
if (!value) return true
return data.label.indexOf(value) !== -1
},
// 节点单击事件
handleNodeClick(data) {
this.queryParams.deptId = data.id
this.selectedDeptId = data.id; // 保存ID
this.selectedDeptName = data.label; // 保存名称(可选)
this.handleQuery()
},
// 归属部门变化时,获取归属组织选项
handleDeptChange(deptId) {
this.form.orgId = null;
this.orgDeptTree = [];
this.orgTreeKey++;
if (!deptId) return;
listDeptByOrgId(deptId).then(res => {
this.orgDeptTree = res.rows || [];
});
},
//用户审批状态修改
handleApprovalStatus(row) {
this.$modal.confirm('确认要审批' + row.userName + '"用户吗?').then(function () {
return approvalStatus({userId: row.userId})
}).then(() => {
this.$modal.msgSuccess('审批成功')
this.getList()
}).catch(function () {
})
},
// 用户状态修改
handleStatusChange(row) {
let text = row.status === '0' ? '启用' : '停用'
this.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?').then(function () {
return changeUserStatus(row.userId, row.status)
}).then(() => {
this.$modal.msgSuccess(text + '成功')
}).catch(function () {
row.status = row.status === '0' ? '1' : '0'
})
},
// 取消按钮
cancel() {
this.open = false
this.reset()
},
// 表单重置
reset() {
this.form = {
userId: undefined,
deptId: undefined,
orgId: undefined,
userName: undefined,
nickName: undefined,
password: undefined,
phonenumber: undefined,
email: undefined,
sex: undefined,
status: '0',
remark: undefined,
postIds: [],
roleIds: [],
roleId: null,
loginType: null
}
this.orgOptions = []
this.resetForm('form')
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.dateRange = []
this.resetForm('queryForm')
this.queryParams.deptId = undefined
this.selectedDeptId = undefined; // 清空ID
this.selectedDeptName = ''; // 清空名称
this.$refs.tree.setCurrentKey(null)
this.handleQuery()
},
// 多选框选中数据
handleSelectionChange(selection) {
// 过滤掉不可选的行(虽然界面上不可选,但为了安全起见还是过滤一次)
const validSelection = selection.filter(row => this.checkSelectable(row));
// 更新选中的roleId数组
this.ids = validSelection.map(item => item.userId);
// 更新单选和多选状态
this.single = validSelection.length !== 1;
this.multiple = !validSelection.length;
},
// 更多操作触发
handleCommand(command, row) {
switch (command) {
case 'handleResetPwd':
this.handleResetPwd(row)
break
case 'handleAuthRole':
this.handleAuthRole(row)
break
case 'approvalStatus':
this.handleApprovalStatus(row)
break
default:
break
}
},
/** 新增按钮操作 */
handleAdd() {
this.reset()
this.loginTypeArr.splice(0)
getUser().then(response => {
this.postOptions = response.posts
this.roleOptions = response.roles
this.open = true
this.title = '添加用户'
this.form.password = this.initPassword
// 核心给form.deptId赋值选中的部门IDtreeselect会自动匹配显示
if (this.selectedDeptId) {
this.form.deptId = this.selectedDeptId;
// 强制触发响应式更新解决偶发的treeselect不回显问题
this.$nextTick(() => {
this.$forceUpdate();
// 触发获取归属组织
this.handleDeptChange(this.selectedDeptId);
});
}
})
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
this.loginTypeArr.splice(0)
const userId = row.userId || this.ids
getUser(userId).then(response => {
this.form = response.data
const loginType = response.data.loginType
if (loginType) {
this.loginTypeArr = loginType.split(',')
}
this.postOptions = response.posts
this.roleOptions = response.roles
this.$set(this.form, 'postIds', response.postIds)
this.$set(this.form, 'roleIds', response.roleIds)
this.open = true
this.title = '修改用户'
this.form.password = ''
// 修改时也要获取归属组织选项
if (this.form.deptId) {
this.$nextTick(() => {
this.handleDeptChange(this.form.deptId)
})
}
})
},
confirmPassword(row) {
this.handleUpdate(row)
// this.$prompt('请输入密码,鉴别用户', '提示', {
// confirmButtonText: '确定',
// cancelButtonText: '取消',
// closeOnClickModal: false,
// inputPattern: /^.{8,16}$/,
// inputErrorMessage: '用户密码长度必须介于 8 和 16 之间',
// inputValidator: (value) => {
// // 调用 validateNewPassword 校验
// const errorMessage = function (error) {
// if (error) {
// return error.message;
// } else {
// console.log('验证通过');
// }
// };
// validateNewPassword(null, value, errorMessage);
// }
// }).then(({value}) => {
// confirmPassword(value).then(response => {
// this.$modal.msgSuccess('验证成功')
// this.handleUpdate(row)
// })
// }).catch(() => {
// })
},
confirmResetPwd(row) {
this.$prompt('请输入密码,鉴别用户', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
closeOnClickModal: false,
inputPattern: /^.{8,16}$/,
inputErrorMessage: '用户密码长度必须介于 8 和 16 之间',
inputValidator: (value) => {
// 调用 validateNewPassword 校验
const errorMessage = function (error) {
if (error) {
return error.message;
} else {
console.log('验证通过');
}
};
validateNewPassword(null, value, errorMessage);
}
}).then(({value}) => {
confirmPassword(value).then(response => {
this.$modal.msgSuccess('验证成功')
this.handleResetPwd(row)
})
}).catch(() => {
})
},
/** 重置密码按钮操作 */
handleResetPwd(row) {
this.$prompt('请输入"' + row.userName + '"的新密码', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
closeOnClickModal: false,
inputValidator: (value) => {
// 1⃣ 空值校验
if (!value || value.trim() === '') {
return '密码不能为空'
}
// 2⃣ 不能包含空格(任意位置)
if (/\s/.test(value)) {
return '密码不能包含空格'
}
// 3⃣ 长度校验
if (value.length < 8 || value.length > 16) {
return '用户密码长度必须介于 8 和 16 之间'
}
// 4⃣ 调用原有校验
let errorMsg = ''
validateNewPassword(null, value, (error) => {
if (error) {
errorMsg = error.message
}
})
if (errorMsg) {
return errorMsg
}
return true
}
})
.then(({ value }) => {
resetUserPwd(row.userId, value).then(() => {
this.$modal.msgSuccess('修改成功,新密码是:' + value)
})
})
.catch(() => {})
},
/** 分配角色操作 */
handleAuthRole: function (row) {
const userId = row.userId
this.$router.push('/system/user-auth/role/' + userId)
},
/** 提交按钮 */
submitForm: function () {
this.$refs['form'].validate(valid => {
this.form.loginType = this.loginTypeArr.toString()
if (valid) {
if (this.form.userId != undefined) {
updateUser(this.form).then(response => {
this.$modal.msgSuccess('修改成功')
this.open = false
this.getList()
})
} else {
addUser(this.form).then(response => {
this.$modal.msgSuccess('新增成功')
this.open = false
this.getList()
})
}
}
})
},
/** 删除按钮操作 */
handleDelete(row) {
const userIds = row.userId || this.ids
this.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?').then(function () {
return delUser(userIds)
}).then(() => {
this.getList()
this.$modal.msgSuccess('删除成功')
}).catch(() => {
})
},
/** 导出按钮操作 */
handleExport() {
this.download('system/user/export', {
...this.queryParams
}, `user_${new Date().getTime()}.xlsx`)
},
/** 导入按钮操作 */
handleImport() {
this.upload.title = '用户导入'
this.upload.open = true
},
/** 下载模板操作 */
importTemplate() {
this.download('system/user/importTemplate', {}, `user_template_${new Date().getTime()}.xlsx`).then(response => {
})
},
// 文件上传中处理
handleFileUploadProgress(event, file, fileList) {
this.upload.isUploading = true
},
// 文件上传成功处理
handleFileSuccess(response, file, fileList) {
this.upload.open = false
this.upload.isUploading = false
this.$refs.upload.clearFiles()
this.$alert('<div style=\'overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;\'>' + response.msg + '</div>', '导入结果', {dangerouslyUseHTMLString: true})
this.getList()
},
// 提交上传文件
submitFileForm() {
this.$refs.upload.submit()
},
hasSystemOrAuditrRole(roles) {
if (!roles || !Array.isArray(roles)) {
return false; // 如果 roles 为空或不是数组,返回 false
}
return roles.some(role => role.roleKey === 'systemAdmin' || role.roleKey === 'audit'); // 检查是否存在 roleKey 为 admin 的角色
},
// 检查行是否可选
checkSelectable(row) {
return !(row.userId === 1 || row.isBuiltIn === '0' || this.hasSystemOrAuditrRole(row.roles));
},
getRowClassName(row) {
return !this.checkSelectable(row) ? 'disabled-row' : '';
},
}
}
</script>
<style>
.disabled-row {
background-color: #f5f7fa !important;
color: #909399;
cursor: not-allowed;
}
.disabled-row .el-checkbox__input {
cursor: not-allowed !important;
}
.disabled-row:hover td {
background-color: #f5f7fa !important;
}
</style>
<style scoped>
.button-group {
margin-left: auto; /* 自动填充左侧空间,使按钮靠右 */
}
.app-container {
padding: 20px;
background-color: #f5f7fa;
}
.card-container {
background-color: #fff;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
overflow: hidden;
margin-bottom: 20px;
}
/* 查询条件卡片头部样式 */
.query-header {
padding: 14px;
border-bottom: 1px solid #e4e7ed;
display: flex;
align-items: center;
min-height: 60px !important;
}
.query-form {
display: flex;
align-items: center;
flex-wrap: wrap;
width: 100%;
gap: 15px;
}
.query-form .el-form-item {
margin-bottom: 0;
display: flex;
align-items: center;
}
.query-buttons {
display: flex;
gap: 10px;
}
/* 操作按钮卡片头部样式 */
.operation-header {
padding: 14px;
border-bottom: 1px solid #e4e7ed;
display: flex;
align-items: center;
min-height: 50px;
}
.operation-row {
display: flex;
align-items: center;
width: 100%;
margin-bottom: 0 !important;
}
/* 新增:统一的操作栏容器样式,用于将所有按钮和工具栏放在右侧 */
.action-bar {
display: flex;
align-items: center;
justify-content: flex-end !important; /* 关键:整体内容靠右对齐 */
gap: 10px; /* 统一设置内部元素的间距 */
width: 100%;
}
/* 表格样式 */
.card-container .el-table {
width: 100%;
}
/* 禁用行样式 */
.disabled-row {
background-color: #f5f7fa !important;
color: #909399;
cursor: not-allowed;
}
.disabled-row .el-checkbox__input {
cursor: not-allowed !important;
}
.disabled-row:hover td {
background-color: #f5f7fa !important;
}
/* 响应式调整 */
@media (max-width: 1200px) {
.query-form {
flex-direction: column;
align-items: flex-start;
gap: 10px;
}
.query-form .el-form-item {
width: 100%;
}
.query-buttons {
width: 100%;
justify-content: flex-end;
}
.operation-row {
flex-direction: column;
gap: 10px;
}
/* 在小屏幕上,操作栏自动变为垂直排列并左对齐 */
.action-bar {
flex-direction: column;
align-items: flex-start;
}
.left-buttons {
width: 100%;
justify-content: flex-start;
}
.right-toolbar-col {
width: 100%;
justify-content: flex-end;
}
}
.pagination-container {
padding: 15px 20px;
margin-top: 5px;;
display: flex;
justify-content: flex-end;
align-items: center;
}
</style>