You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

791 lines
29 KiB

<template>
<div class="wrap">
<!-- 左边的组织 -->
<div class="side">
<div class="m-b-20">
<h6 class="p-title">后台员工账号</h6>
<el-radio-group v-model="studentType" @change="changeType">
<div class="m-b-20">
<el-radio :label="1">所有员工</el-radio>
</div>
<div>
<el-radio :label="2">未加入部门的员工</el-radio>
</div>
</el-radio-group>
</div>
<el-divider></el-divider>
<div>
<div class="flex-between">
<h6 class="p-title" style="margin-bottom: 0">组织架构</h6>
<el-button type="text" @click="addOrg" v-auth="'/system:后台账号:新增部门'">添加</el-button>
</div>
<div style="height: 504px; max-height: 504px; overflow: auto">
<el-tree
:data="orgList"
default-expand-all
ref="orgTree"
node-key="id"
highlight-current
:expand-on-click-node="false"
@node-click="handleNodeClick"
:props="{children: 'children', label: 'organizationName', isLeaf: 'leaf'}"
>
<span class="custom-tree-node" slot-scope="{ node, data }">
<span class="org-name">{{ node.label }}</span>
<span>
<el-button
v-auth="'/system:后台账号:新增部门'"
type="text"
icon="el-icon-circle-plus-outline"
@click="() => addOrg(node, data)">
</el-button>
<el-button
v-auth="'/system:后台账号:编辑部门'"
type="text"
icon="el-icon-edit-outline"
@click="() => editOrg(node, data)">
</el-button>
<el-button
v-auth="'/system:后台账号:删除部门'"
type="text"
icon="el-icon-delete"
@click="() => delOrg(node, data)">
</el-button>
</span>
</span>
</el-tree>
</div>
</div>
<el-dialog
:title="orgForm.id ? '编辑' : '新增' + '部门'"
:visible.sync="orgVisible"
:close-on-click-modal="false"
width="50%"
>
<el-form v-if="orgVisible" ref="orgForm" :model="orgForm" :rules="orgRules" label-width="100px">
<el-form-item label="部门名称" prop="organizationName">
<el-input v-model.trim="orgForm.organizationName" placeholder="请输入"></el-input>
</el-form-item>
<el-form-item label="上级部门">
<span v-if="orgForm.parentName">{{ orgForm.parentName }}</span>
<el-cascader
v-else
:options="orgListDia"
v-model="cascaderValue"
:props="cascaderProps"
clearable
style="width: 100%"
>
</el-cascader>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="closeOrg">取 消</el-button>
<el-button type="primary" @click="orgSubmit">确 定</el-button>
</span>
</el-dialog>
</div>
<!-- 右边的员工 -->
<div class="right">
<h6 class="p-title">筛选</h6>
<div class="tool">
<ul class="filter">
<li>
<el-input style="width: 250px;" placeholder="请输入员工姓名/手机号" prefix-icon="el-icon-search" v-model="keyWord" clearable></el-input>
</li>
</ul>
<div>
<el-button type="primary" @click="addStaff" v-auth="'/system:后台账号:新增员工'">新增员工</el-button>
<el-button type="primary" @click="batchImport" v-auth="'/system:后台账号:批量导入'">批量导入</el-button>
</div>
</div>
<el-table :data="listData" class="table" ref="table" stripe header-align="center" @selection-change="handleSelectionChange" row-key="accountId">
<el-table-column type="selection" width="55" align="center" :reserve-selection="true"></el-table-column>
<el-table-column type="index" width="60" label="序号" align="center"></el-table-column>
<el-table-column prop="userName" label="员工姓名" align="center" min-width="100"></el-table-column>
<el-table-column prop="account" label="账号" align="center" min-width="100"></el-table-column>
<el-table-column prop="phone" label="手机号" align="center" width="120"></el-table-column>
<el-table-column prop="staffArchitectureName" label="所在部门" align="center" min-width="200" show-overflow-tooltip></el-table-column>
<el-table-column prop="roleName" label="授权角色" align="center" min-width="200" show-overflow-tooltip></el-table-column>
<el-table-column prop="lastLoginTime" label="最后登录时间" align="center" width="130"></el-table-column>
<el-table-column label="操作" align="center" width="300">
<template slot-scope="scope">
<el-button type="text" v-auth="'/system:后台账号:查看'" @click="queryStaff(scope.row,true)">查看</el-button>
<el-button type="text" v-auth="'/system:后台账号:编辑'" @click="queryStaff(scope.row,false)">编辑</el-button>
<el-button type="text" v-auth="'/system:后台账号:重置密码'" @click="resetPassword(scope.row)">重置密码</el-button>
<el-button type="text" v-auth="'/system:后台账号:删除'" @click="delStaff(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background @current-change="currentChange" :current-page="page" layout="total, prev, pager, next" :total="total"></el-pagination>
</div>
<el-dialog :title="isDetail ? '查看' : (form.accountId ? '编辑' : '新增') + '员工'" :visible.sync="staffVisible" width="580px" class="dialog" :close-on-click-modal="false" @close="closeStaff">
<el-form ref="form" :model="form" :rules="rules" label-width="150px" :disabled="isDetail" style='margin-right: 80px;'>
<el-form-item prop="workNumber" label="工号">
<el-input v-model.trim="form.workNumber" placeholder="请输入工号"></el-input>
</el-form-item>
<el-form-item prop="userName" label="姓名">
<el-input v-model.trim="form.userName" placeholder="请输入姓名"></el-input>
</el-form-item>
<el-form-item prop="account" label="账号">
<el-input v-model.trim="form.account" placeholder="请输入账号"></el-input>
</el-form-item>
<el-form-item prop="roleList" label="授权角色">
<el-select class="w-100" v-model="form.roleList" multiple>
<template v-for="item in roleList">
<!-- 不显示超管 -->
<el-option
v-if="item.roleName !== '超级管理员'"
:key="item.id"
:label="item.roleName"
:value="item.id">
</el-option>
</template>
</el-select>
</el-form-item>
<el-form-item label="所在部门">
<el-cascader
class="w-100"
v-model="form.staffArchitectureId"
:options="orgList"
:props="casProps"
></el-cascader>
</el-form-item>
<el-form-item prop="phone" label="手机号">
<el-input v-model.trim="form.phone" placeholder="请输入手机号" maxlength="11"></el-input>
</el-form-item>
<el-form-item prop="email" label="邮箱">
<el-input v-model.trim="form.email" placeholder="请输入邮箱"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer" v-if="!isDetail">
<el-button @click="staffVisible = false">取消</el-button>
<el-button type="primary" @click="submitStaff">确定</el-button>
</span>
</el-dialog>
<el-dialog title="批量导入" :visible.sync="importVisible" width="24%" :close-on-click-modal="false">
<div style="text-align: center">
<div style="margin-bottom: 10px;">
<el-button type="primary" @click="download">模板下载<i class="el-icon-download el-icon--right"></i></el-button>
</div>
<el-upload
ref="importStaff"
name="file"
accept=".xls,.xlsx"
:on-remove="handleRemove"
:on-error="uploadError"
:on-success="uploadSuccess"
:before-remove="beforeRemove"
:limit="1"
:on-exceed="handleExceed"
:action="this.api.importStaff"
:file-list="uploadList"
:headers="headers"
>
<el-button type="primary" class="ml20">上传文件<i class="el-icon-upload2 el-icon--right"></i></el-button>
</el-upload>
<el-link v-if="uploadFaild" type="primary" @click="showFaild">部分数据导入失败,查看失败原因</el-link>
</div>
<span slot="footer" class="dialog-footer">
<el-button size="small" @click="importVisible = false">取 消</el-button>
<el-button size="small" type="primary" @click="uploadSure"> </el-button>
</span>
</el-dialog>
</div>
</div>
</template>
<script>
import util from "@/libs/util";
import Setting from "@/setting";
import OrgTree from "@/components/org-tree/src/tree";
export default {
components: { OrgTree },
data() {
const accountPass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入账号'))
} else {
const pattern = /^[A-Za-z0-9]*$/
if(pattern.test(value)){
this.accountChange()
callback()
}else{
callback(new Error('请输入正确账号格式'))
}
}
}
const workNumberPass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入工号'))
} else {
const pattern = /^[A-Za-z0-9]*$/
if(pattern.test(value)){
this.worknumberChange()
callback()
}else{
callback(new Error('请输入正确工号格式'))
}
}
}
const phonePass = (rule, value, callback) => {
if (value) {
const pattern = /^1[3456789]\d{9}$/
if(pattern.test(value)){
// this.phoneChange()
callback()
}else{
callback(new Error('请输入正确手机号格式'))
}
} else {
callback()
}
}
const emailPass = (rule, value, callback) => {
if (value) {
const pattern = /^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/
if(pattern.test(value)){
// this.emailChange()
callback()
}else{
callback(new Error('请输入正确邮箱格式'))
}
} else {
callback()
}
}
return {
orgList: [],
orgListDia: [],
studentType: 1, //类型:必填一个(1.所有员工 2.未加入班级员工)
orgVisible: false, // 员工组织架对话框
orgForm: {
id: '',
organizationName: ''
},
cascaderValue: [], // 上级部门
cascaderProps: {
checkStrictly: true,
label: "organizationName",
value: "id"
},
treeVisible: true,
treeNode: {},
treeResolve: [],
isDetail: false,
keyWord: '',
roleList: [],
form: {
accountId: '',
userName: '',
phone: '',
roleList: [],
uniqueIdentification: '',
workNumber: '',
email: '',
account: '',
staffArchitectureId: []
},
orgRules: {
organizationName: [
{ required: true, message: "请输入部门名称", trigger: "blur" }
]
},
rules: {
account: [
{ required: true,validator: accountPass, trigger: 'blur' }
],
userName: [
{ required: true, message: "请输入姓名", trigger: "blur" }
],
workNumber: [
{ required: true,validator: workNumberPass, trigger: 'blur' }
],
roleList: [
{ required: true, message: "请选择授权角色", trigger: "change" }
],
phone: [
{ validator: phonePass, trigger: 'blur' }
],
email: [
{ validator: emailPass, trigger: 'blur' }
]
},
listData: [],
page: 1,
pageSize: 10,
total: 0,
multipleSelection: [],
staffVisible: false,
accountReapeat: false,
originAccount: '',
workNumberReapeat: false,
originWorkNumber: '',
phoneRepeat: false,
emailRepeat: false,
casProps: {
multiple: true,
checkStrictly: true,
label: 'organizationName',
value: 'id',
isLeaf: 'leaf'
},
importVisible: false,
uploadList: [],
uploadFaild: false,
exportCode: '',
headers: {
token: util.local.get(Setting.tokenKey)
},
disableds:false,
submiting: false // 新增编辑防抖标识
};
},
watch: {
keyWord: function(val) {
clearTimeout(this.searchTimer);
this.searchTimer = setTimeout(this.getStaff, 500);
}
},
mounted() {
this.getOrg()
this.getRole()
},
methods: {
// 获取组织
async getOrg() {
const res = await this.$post(this.api.treeListArch)
const list = res.treeList
// 没有子级,删除children属性
const handleLeaf = list => {
list.map(e => {
if (e.children.length) {
handleLeaf(e.children)
} else {
delete e.children
}
})
}
handleLeaf(list)
this.orgList = list
this.handleOrgId(list)
this.getStaff()
},
// 每个层级加上父级id的集合
handleOrgId(list, ids) {
list.forEach(e => {
e.ids = ids ? [...ids, e.id] : [e.id]
e.children && this.handleOrgId(e.children, e.ids)
})
},
// 组织类别筛选回调
changeType() {
this.$refs.orgTree.setCurrentKey(null)
this.initData()
},
// 添加部门
addOrg(node, data) {
const list = JSON.parse(JSON.stringify(this.orgList))
this.handleOrg(list)
this.orgListDia = list
this.orgForm = {
id: '',
parentId: data ? data.id : 1,
level: data ? data.level + 1 : 1,
parentName: data ? data.organizationName : '',
organizationName: ''
}
this.orgVisible = true
},
// 编辑部门
editOrg(node, data) {
const list = JSON.parse(JSON.stringify(this.orgList))
this.handleOrg(list, data.id, 0)
this.orgListDia = list
this.orgForm = {
id: data.id,
organizationName: data.organizationName
}
this.orgVisible = true
const ids = data.ids
ids.splice(ids.length - 1, 1)
this.cascaderValue = ids
},
// 处理更换部门的禁选
handleOrg(list, id, disabled) {
list.forEach(e => {
// 如果是已经找到了要禁选的层级,则直接改变disabled,并递归
if (disabled) {
e.disabled = true
e.children && this.handleOrg(e.children, id, 1)
} else {
if (e.id === id) {
e.disabled = true
e.children && this.handleOrg(e.children, id, 1)
} else {
e.children && this.handleOrg(e.children, id, 0)
}
}
})
},
// 删除部门
delOrg(node, data) {
this.$confirm("确定要删除吗?", "提示", {
type: "warning"
}).then(() => {
this.$post(`${this.api.deleteArch}?id=${data.id}`).then(res => {
util.successMsg("删除成功")
this.getOrg()
}).catch(res => {})
}).catch(() => {})
},
// 提交组织架构新增/编辑
orgSubmit() {
this.$refs.orgForm.validate((valid) => {
if (valid) {
const form = this.orgForm
const cas = this.cascaderValue
const len = cas.length
if (cas && len) {
this.orgForm.parentId = cas[len - 1]
this.orgForm.level = len + 1
}
if (!form.id) {
// 添加
this.$post(this.api.saveArch, form).then(res => {
util.successMsg("新增成功!")
this.closeOrg()
}).catch(err => {})
} else {
// 编辑
this.$post(this.api.updateArch, form).then(res => {
util.successMsg("编辑成功!")
this.closeOrg()
}).catch(err => {})
}
}
});
},
// 点击树节点查询列表数据
handleNodeClick(data) {
this.$refs.table.clearSelection()
this.studentType = null
this.getStaff()
},
// 关闭组织新增编辑弹框
closeOrg() {
this.orgVisible = false
this.cascaderValue = []
this.getOrg()
},
// 员工列表
getStaff() {
this.$post(this.api.staffList, {
type: this.studentType || 1,
staffArchitectureId: this.$refs.orgTree.getCurrentKey() || '',
keyWord: this.keyWord,
pageNum: this.page,
pageSize: this.pageSize
}).then(res => {
this.listData = res.page.records
this.total = res.page.total
}).catch(err => {})
},
// 切换页码
currentChange(val) {
this.page = val
this.getStaff()
},
handleSelectionChange(val) { // 多选
this.multipleSelection = val
},
initData() {
this.$refs.table.clearSelection()
this.page = 1
this.getStaff()
},
// 删除
delStaff(row) {
this.$confirm("确定要删除吗?", "提示", {
type: "warning"
}).then(() => {
this.$post(`${this.api.delStaff}?accountIds=${row.accountId}`).then(res => {
util.successMsg("删除成功")
this.getStaff()
}).catch(res => {})
}).catch(() => {})
},
// 重置密码
resetPassword(row) {
const newPwd = Setting.initialPassword
this.$confirm(`重置后的密码为:${newPwd},确定重置?`, "提示", { type: "warning" }).then(() => {
this.$get(`${this.api.resetPwd}?userId=${row.userId}&newPwd=${newPwd}`).then(res => {
util.successMsg("重置成功")
}).catch(res => {})
}).catch(() => {})
},
// 添加员工
addStaff() {
this.staffVisible = true
this.$nextTick(() => {
this.$refs.form.clearValidate()
})
},
// 编辑/查看
queryStaff(row, isDetail) {
const archId = []
// 处理部门id
const handleArchId = (list, ids, parentId = []) => {
list.map(e => {
// 把部门id分割成二维数组,[[1, 2], [3, 4]],每个层级的id都要放进去,后端返回的是最后一级的id,无法回显
if (ids.includes(e.id)) {
archId.push([...parentId, e.id])
} else {
e.children && handleArchId(e.children, ids, [...parentId, e.id])
}
})
}
this.isDetail = isDetail
this.staffVisible = true
this.$get(`${this.api.staffDetail}?accountId=${row.accountId}`).then(res => {
const { data } = res
const { staffArchitectureId, roleId } = data
if (roleId) {
const roleList = roleId.split(',').map(e => Number(e))
const list = this.roleList
if (roleList.length) {
let has = false // 是否在角色列表里有已选择的角色,全部都被删除了,则提示
for (const i in roleList) {
if (list.find(n => n.id === roleList[i])) {
has = true
break
}
}
if (!has) {
util.warningMsg('角色被删请重新选择')
data.roleList = []
} else {
data.roleList = roleList
}
}
}
if (staffArchitectureId) {
handleArchId(this.orgList, staffArchitectureId.split(',').map(e => Number(e)))
data.staffArchitectureId = archId
}
this.form = data
this.originAccount = data.account
this.originWorkNumber = data.workNumber
}).catch(res => {})
},
// 获取角色数据
getRole() {
this.$get(`${this.api.roleList}?page=1&size=1000&name=&platformId=${Setting.platformId}&port=0`).then(res => {
this.roleList = res.rolePage.records
}).catch(res => {})
},
// 账号判重
accountChange() {
const form = this.form
const { account } = form
if (account === this.originAccount) {
this.accountReapeat = false
} else {
const { accountId } = form
this.$post(`${this.api.checkWorkNumOrAccount}?platformId=${Setting.platformId}&type=2&account=${account}${accountId ? `&accountId=${accountId}` : ''}`).then(res => {
this.accountReapeat = false
}).catch(err => {
this.accountReapeat = true
})
}
},
// 工号判重
worknumberChange() {
const form = this.form
const { workNumber } = form
if (workNumber === this.originWorkNumber) {
this.workNumberReapeat = false
} else {
const { accountId } = form
this.$post(`${this.api.checkWorkNumOrAccount}?platformId=${Setting.platformId}&type=2&workNumber=${workNumber}${accountId ? `&accountId=${accountId}` : ''}`).then(res => {
this.workNumberReapeat = false
}).catch(err => {
this.workNumberReapeat = true
})
}
},
// 手机号判重
phoneChange() {
const form = this.form
const { phone } = form
if (phone) {
const { accountId } = form
this.$post(`${this.api.checkEmailOrPhone}?phone=${phone}${accountId ? `&accountId=${accountId}` : ''}`).then(res => {
this.phoneRepeat = false
}).catch(err => {
this.phoneRepeat = true
})
}
},
// 邮箱判重
emailChange() {
const form = this.form
const { email } = form
if (email) {
const { accountId } = form
this.$post(`${this.api.checkEmailOrPhone}?email=${email}${accountId ? `&accountId=${accountId}` : ''}`).then(res => {
this.emailRepeat = false
}).catch(err => {
this.emailRepeat = true
})
}
},
// 提交新增/编辑员工
submitStaff() {
this.$refs.form.validate((valid) => {
if (valid) {
if (this.submiting) return false
if (this.accountReapeat) return util.warningMsg("该账号已存在")
if (this.workNumberReapeat) return util.warningMsg("该工号已存在")
if (this.phoneRepeat) return util.warningMsg("该手机号已存在")
if (this.emailRepeat) return util.warningMsg("该邮箱已存在")
this.submiting = true
const form = JSON.parse(JSON.stringify(this.form))
const ids = form.staffArchitectureId
if (ids) form.staffArchitectureId = ids.map(e => e[e.length - 1])
if (form.accountId) {
this.$post(this.api.modifyStaff, form).then(res => {
util.successMsg("编辑成功!")
this.staffVisible = false
setTimeout(() => {
this.submiting = false
}, 2000)
}).catch(res => {
setTimeout(() => {
this.submiting = false
}, 2000)
})
} else {
form.uniqueIdentification = new Date().getTime()
this.$post(this.api.saveStaff, form).then(res => {
util.successMsg("新增成功!")
this.staffVisible = false
setTimeout(() => {
this.submiting = false
}, 2000)
}).catch(res => {
setTimeout(() => {
this.submiting = false
}, 2000)
})
}
}
})
},
// 关闭新增员工对话框
closeStaff() {
this.form = {
accountId: '',
userName: '',
account: '',
phone: '',
uniqueIdentification: '',
workNumber: '',
email: '',
staffArchitectureId: [],
roleList: []
}
this.isDetail = false
this.getStaff()
},
// 批量导入
batchImport() {
this.importVisible = true
this.uploadList = []
this.uploadFaild = false
},
// 模板下载
download() {
location.href = this.api.staffTemplate
},
// 上传文件
handleExceed(files, fileList) {
util.warningMsg(
`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!`
)
},
// 下载失败文件
showFaild() {
location.href = `${this.api.exportFailure}?exportCode=${this.exportCode}`
},
uploadSuccess(res, file, fileList) {
this.uploadFaild = false
if (res.status === 200) {
if (res.data.exportCode) {
this.exportCode = res.data.exportCode
this.uploadFaild = true
util.errorMsg(`本次上传有${res.data.failureNum}个错误信息录入`)
}
} else {
res.message ? util.errorMsg(res.message) : util.errorMsg("上传失败,请检查数据")
}
},
uploadError(err, file, fileList) {
this.$message({
message: "上传出错,请重试!",
type: "error",
center: true
})
},
beforeRemove(file, fileList) {
return this.$confirm(`确定移除 ${file.name}`)
},
handleRemove(file, fileList) {
this.uploadList = fileList
this.uploadFaild = false
},
uploadSure() {
this.importVisible = false
this.studentType = 1
this.keyWord = ''
this.$refs.orgTree.setCurrentKey(null)
this.getOrg()
}
}
};
</script>
<style lang="scss" scoped>
.m-b-20 {
margin-bottom: 20px;
}
.org-name {
margin-right: 20px;
}
.w-100 {
width: 100%;
}
.wrap {
display: flex;
height: calc(100vh - 223px);
padding: 0 24px;
.side {
width: 300px;
padding: 24px 10px 24px 0;
margin-right: 24px;
border-right: 1px solid rgba(0, 0, 0, 0.06);
}
.right {
width: calc(100% - 374px);
padding: 24px 0;
}
}
</style>