@@ -14,6 +14,11 @@ const validatePhone = (rule, value, callback) => {
|
|||||||
callback(new Error('请输入手机号'));
|
callback(new Error('请输入手机号'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 详情回显为脱敏手机号(含 *)时放行,未修改则提交时剔除该字段
|
||||||
|
if (phone.includes('*')) {
|
||||||
|
callback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!/^1\d{10}$/.test(phone)) {
|
if (!/^1\d{10}$/.test(phone)) {
|
||||||
callback(new Error('请输入正确的手机号'));
|
callback(new Error('请输入正确的手机号'));
|
||||||
return;
|
return;
|
||||||
@@ -121,6 +126,62 @@ export default {
|
|||||||
order: 60,
|
order: 60,
|
||||||
rules: [{ required: true, message: '请选择小程序身份', trigger: 'change' }],
|
rules: [{ required: true, message: '请选择小程序身份', trigger: 'change' }],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '所属组织',
|
||||||
|
prop: 'deptId',
|
||||||
|
formslot: true,
|
||||||
|
hide: true,
|
||||||
|
span: 24,
|
||||||
|
order: 55,
|
||||||
|
rules: [{ required: true, message: '请选择所属组织', trigger: 'change' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '所属组织',
|
||||||
|
prop: 'deptName',
|
||||||
|
minWidth: 180,
|
||||||
|
overHidden: true,
|
||||||
|
addDisplay: false,
|
||||||
|
editDisplay: false,
|
||||||
|
viewDisplay: false,
|
||||||
|
order: 54,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '数据权限范围',
|
||||||
|
prop: 'dataScopeRange',
|
||||||
|
type: 'radio',
|
||||||
|
span: 24,
|
||||||
|
hide: true,
|
||||||
|
order: 53,
|
||||||
|
value: 1,
|
||||||
|
dicData: [
|
||||||
|
{ label: '仅所属组织', value: 1 },
|
||||||
|
{ label: '全部组织', value: 2 },
|
||||||
|
{ label: '自定义', value: 3 },
|
||||||
|
],
|
||||||
|
rules: [{ required: true, message: '请选择数据权限范围', trigger: 'change' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '数据层级范围',
|
||||||
|
prop: 'dataLevelRange',
|
||||||
|
type: 'radio',
|
||||||
|
span: 24,
|
||||||
|
hide: true,
|
||||||
|
order: 52,
|
||||||
|
value: 1,
|
||||||
|
dicData: [
|
||||||
|
{ label: '包含下级', value: 1 },
|
||||||
|
{ label: '仅本级', value: 2 },
|
||||||
|
],
|
||||||
|
rules: [{ required: true, message: '请选择数据层级范围', trigger: 'change' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '数据权限',
|
||||||
|
prop: 'dataScopeDeptIds',
|
||||||
|
formslot: true,
|
||||||
|
span: 24,
|
||||||
|
hide: true,
|
||||||
|
order: 51,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '性别',
|
label: '性别',
|
||||||
prop: 'sex',
|
prop: 'sex',
|
||||||
|
|||||||
+185
-39
@@ -20,33 +20,32 @@
|
|||||||
@on-load="onLoad"
|
@on-load="onLoad"
|
||||||
>
|
>
|
||||||
<template #menu-left>
|
<template #menu-left>
|
||||||
<el-button
|
<el-button type="primary" v-if="permission.mp_user_add" @click="$refs.crud.rowAdd()">
|
||||||
type="primary"
|
|
||||||
v-if="permission.mp_user_add"
|
|
||||||
@click="$refs.crud.rowAdd()"
|
|
||||||
>
|
|
||||||
新增
|
新增
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button type="primary" plain v-if="permission.mp_user_reset" @click="handleReset">
|
||||||
type="primary"
|
|
||||||
plain
|
|
||||||
v-if="permission.mp_user_reset"
|
|
||||||
@click="handleReset"
|
|
||||||
>
|
|
||||||
密码重置
|
密码重置
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button type="danger" plain v-if="permission.mp_user_delete" @click="handleDelete">
|
||||||
type="danger"
|
|
||||||
plain
|
|
||||||
v-if="permission.mp_user_delete"
|
|
||||||
@click="handleDelete"
|
|
||||||
>
|
|
||||||
批量删除
|
批量删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
<template #identities="{ row }">
|
<template #identities="{ row }">
|
||||||
{{ row.identitiesName || formatIdentities(row.identities) }}
|
{{ row.identitiesName || formatIdentities(row.identities) }}
|
||||||
</template>
|
</template>
|
||||||
|
<template #deptName="{ row }">
|
||||||
|
<template v-if="formatDeptNames(row.deptName).length">
|
||||||
|
<el-tag
|
||||||
|
v-for="name in formatDeptNames(row.deptName)"
|
||||||
|
:key="name"
|
||||||
|
size="small"
|
||||||
|
class="dept-tag"
|
||||||
|
>
|
||||||
|
{{ name }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
<span v-else>-</span>
|
||||||
|
</template>
|
||||||
<template #status="{ row }">
|
<template #status="{ row }">
|
||||||
<el-tag :type="row.status === 1 ? 'primary' : 'info'" class="status-text">
|
<el-tag :type="row.status === 1 ? 'primary' : 'info'" class="status-text">
|
||||||
{{ row.status === 1 ? '启用' : '停用' }}
|
{{ row.status === 1 ? '启用' : '停用' }}
|
||||||
@@ -55,6 +54,33 @@
|
|||||||
<template #updateUserName="{ row }">
|
<template #updateUserName="{ row }">
|
||||||
{{ formatUpdateUserName(row) }}
|
{{ formatUpdateUserName(row) }}
|
||||||
</template>
|
</template>
|
||||||
|
<template #deptId-form>
|
||||||
|
<el-cascader
|
||||||
|
v-model="deptCascaderValue"
|
||||||
|
:options="permissionDeptTree"
|
||||||
|
:props="deptCascaderProps"
|
||||||
|
:disabled="isViewMode"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
collapse-tags
|
||||||
|
collapse-tags-tooltip
|
||||||
|
placeholder="请选择所属组织(可多选)"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #dataScopeDeptIds-form>
|
||||||
|
<el-tree
|
||||||
|
v-if="Number(form.dataScopeRange) === 3"
|
||||||
|
ref="dataScopeTree"
|
||||||
|
:data="permissionDeptTree"
|
||||||
|
show-checkbox
|
||||||
|
node-key="id"
|
||||||
|
:default-checked-keys="form.dataScopeDeptIds || []"
|
||||||
|
:props="{ label: 'title', children: 'children' }"
|
||||||
|
@check="handleDataScopeCheck"
|
||||||
|
/>
|
||||||
|
<span v-else class="form-tip">选择「自定义」后可勾选数据权限组织</span>
|
||||||
|
</template>
|
||||||
<template #menu="{ row, index }">
|
<template #menu="{ row, index }">
|
||||||
<el-link
|
<el-link
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -70,25 +96,13 @@
|
|||||||
>
|
>
|
||||||
编辑
|
编辑
|
||||||
</el-link>
|
</el-link>
|
||||||
<el-link
|
<el-link type="primary" v-if="permission.mp_user_status" @click="handleStatus(row)">
|
||||||
type="primary"
|
|
||||||
v-if="permission.mp_user_status"
|
|
||||||
@click="handleStatus(row)"
|
|
||||||
>
|
|
||||||
{{ row.status === 1 ? '停用' : '启用' }}
|
{{ row.status === 1 ? '停用' : '启用' }}
|
||||||
</el-link>
|
</el-link>
|
||||||
<el-link
|
<el-link type="primary" v-if="permission.mp_user_reset" @click="handleResetForRow(row)">
|
||||||
type="primary"
|
|
||||||
v-if="permission.mp_user_reset"
|
|
||||||
@click="handleResetForRow(row)"
|
|
||||||
>
|
|
||||||
重置密码
|
重置密码
|
||||||
</el-link>
|
</el-link>
|
||||||
<el-link
|
<el-link type="danger" v-if="permission.mp_user_delete" @click="rowDel(row)">
|
||||||
type="danger"
|
|
||||||
v-if="permission.mp_user_delete"
|
|
||||||
@click="rowDel(row)"
|
|
||||||
>
|
|
||||||
删除
|
删除
|
||||||
</el-link>
|
</el-link>
|
||||||
</template>
|
</template>
|
||||||
@@ -108,9 +122,12 @@
|
|||||||
<script>
|
<script>
|
||||||
import { h } from 'vue';
|
import { h } from 'vue';
|
||||||
import { getList, getDetail, submit, remove, changeStatus, resetPassword } from '@/api/system/mpUser';
|
import { getList, getDetail, submit, remove, changeStatus, resetPassword } from '@/api/system/mpUser';
|
||||||
|
import { getDeptTree } from '@/api/system/dept';
|
||||||
import option from '@/option/system/mpUser';
|
import option from '@/option/system/mpUser';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import { formatUpdateUserName } from '@/utils/audit';
|
import { formatUpdateUserName } from '@/utils/audit';
|
||||||
|
import { sensitive } from '@/utils/sensitive';
|
||||||
|
import func from '@/utils/func';
|
||||||
|
|
||||||
const IDENTITY_LABEL = {
|
const IDENTITY_LABEL = {
|
||||||
driver: '司机',
|
driver: '司机',
|
||||||
@@ -132,10 +149,12 @@ export default {
|
|||||||
selectionList: [],
|
selectionList: [],
|
||||||
option,
|
option,
|
||||||
data: [],
|
data: [],
|
||||||
|
permissionDeptTree: [],
|
||||||
|
sensitiveManager: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters(['permission']),
|
...mapGetters(['permission', 'userInfo']),
|
||||||
permissionList() {
|
permissionList() {
|
||||||
return {
|
return {
|
||||||
addBtn: this.validData(this.permission.mp_user_add, false),
|
addBtn: this.validData(this.permission.mp_user_add, false),
|
||||||
@@ -147,6 +166,46 @@ export default {
|
|||||||
ids() {
|
ids() {
|
||||||
return this.selectionList.map(item => item.id).join(',');
|
return this.selectionList.map(item => item.id).join(',');
|
||||||
},
|
},
|
||||||
|
isViewMode() {
|
||||||
|
return this.dialogType === 'view';
|
||||||
|
},
|
||||||
|
deptCascaderProps() {
|
||||||
|
return {
|
||||||
|
label: 'title',
|
||||||
|
value: 'id',
|
||||||
|
children: 'children',
|
||||||
|
emitPath: false,
|
||||||
|
multiple: true,
|
||||||
|
checkStrictly: true,
|
||||||
|
expandTrigger: 'click',
|
||||||
|
disabled: 'disabled',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
deptCascaderValue: {
|
||||||
|
get() {
|
||||||
|
const ids = Array.isArray(this.form.deptId)
|
||||||
|
? this.form.deptId
|
||||||
|
: this.form.deptId
|
||||||
|
? String(this.form.deptId).split(',').filter(Boolean)
|
||||||
|
: [];
|
||||||
|
return ids
|
||||||
|
.filter(item => item !== undefined && item !== null && item !== '')
|
||||||
|
.map(item => (typeof item === 'number' ? item : String(item)));
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
this.form.deptId = Array.isArray(value)
|
||||||
|
? value.filter(item => item !== undefined && item !== null && item !== '')
|
||||||
|
: value
|
||||||
|
? [value]
|
||||||
|
: [];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.sensitiveManager = sensitive.create({
|
||||||
|
fields: ['phone', 'email'],
|
||||||
|
});
|
||||||
|
this.loadDeptTree();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
formatUpdateUserName,
|
formatUpdateUserName,
|
||||||
@@ -158,19 +217,59 @@ export default {
|
|||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join(',');
|
.join(',');
|
||||||
},
|
},
|
||||||
normalizeSubmitRow(row = {}) {
|
formatDeptNames(deptName) {
|
||||||
const payload = { ...row };
|
if (!deptName) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return String(deptName)
|
||||||
|
.split(',')
|
||||||
|
.map(item => item.trim())
|
||||||
|
.filter(Boolean);
|
||||||
|
},
|
||||||
|
loadDeptTree() {
|
||||||
|
const tenantId = this.userInfo?.tenantId;
|
||||||
|
if (!tenantId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getDeptTree(tenantId).then(res => {
|
||||||
|
this.permissionDeptTree = res.data.data || [];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleDataScopeCheck(_, checked) {
|
||||||
|
if (this.isViewMode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.form.dataScopeDeptIds = checked.checkedKeys || [];
|
||||||
|
},
|
||||||
|
normalizeSubmitRow(row = {}, isUpdate = false) {
|
||||||
|
let payload = { ...row };
|
||||||
|
// 编辑时剔除未改动的脱敏字段,避免把 138****8000 写回库
|
||||||
|
if (isUpdate && this.sensitiveManager) {
|
||||||
|
payload = this.sensitiveManager.getSubmitData(payload);
|
||||||
|
}
|
||||||
if (Array.isArray(payload.identities)) {
|
if (Array.isArray(payload.identities)) {
|
||||||
payload.identities = payload.identities.filter(Boolean).join(',');
|
payload.identities = payload.identities.filter(Boolean).join(',');
|
||||||
}
|
}
|
||||||
|
payload.deptId = func.join(payload.deptId);
|
||||||
if (payload.phone) {
|
if (payload.phone) {
|
||||||
payload.phone = String(payload.phone).trim();
|
payload.phone = String(payload.phone).trim();
|
||||||
}
|
}
|
||||||
if (!payload.account && payload.phone) {
|
// 脱敏手机号不能作为账号默认值
|
||||||
|
if (!payload.account && payload.phone && !String(payload.phone).includes('*')) {
|
||||||
payload.account = payload.phone;
|
payload.account = payload.phone;
|
||||||
}
|
}
|
||||||
|
payload.dataScopeRange = Number(payload.dataScopeRange || 1);
|
||||||
|
payload.dataLevelRange = Number(payload.dataLevelRange || 1);
|
||||||
|
if (payload.dataScopeRange === 3) {
|
||||||
|
payload.dataScopeDeptIds = Array.isArray(payload.dataScopeDeptIds)
|
||||||
|
? payload.dataScopeDeptIds
|
||||||
|
: [];
|
||||||
|
} else {
|
||||||
|
payload.dataScopeDeptIds = [];
|
||||||
|
}
|
||||||
delete payload.password;
|
delete payload.password;
|
||||||
delete payload.identitiesName;
|
delete payload.identitiesName;
|
||||||
|
delete payload.deptName;
|
||||||
delete payload.sexName;
|
delete payload.sexName;
|
||||||
delete payload.createUserName;
|
delete payload.createUserName;
|
||||||
delete payload.updateUserName;
|
delete payload.updateUserName;
|
||||||
@@ -178,13 +277,25 @@ export default {
|
|||||||
},
|
},
|
||||||
beforeOpen(done, type) {
|
beforeOpen(done, type) {
|
||||||
this.dialogType = type;
|
this.dialogType = type;
|
||||||
|
this.loadDeptTree();
|
||||||
if (['edit', 'view'].includes(type) && this.form.id) {
|
if (['edit', 'view'].includes(type) && this.form.id) {
|
||||||
getDetail(this.form.id).then(res => {
|
getDetail(this.form.id).then(res => {
|
||||||
const detail = res.data.data || {};
|
const detail = res.data.data || {};
|
||||||
if (detail.identities && typeof detail.identities === 'string') {
|
if (detail.identities && typeof detail.identities === 'string') {
|
||||||
detail.identities = detail.identities.split(',').filter(Boolean);
|
detail.identities = detail.identities.split(',').filter(Boolean);
|
||||||
}
|
}
|
||||||
this.form = detail;
|
const deptIds = func.split(detail.deptId || '');
|
||||||
|
this.form = {
|
||||||
|
...detail,
|
||||||
|
deptId: Array.isArray(deptIds) ? deptIds : [],
|
||||||
|
dataScopeRange: detail.dataScopeRange || 1,
|
||||||
|
dataLevelRange: detail.dataLevelRange || 1,
|
||||||
|
dataScopeDeptIds: detail.dataScopeDeptIds || [],
|
||||||
|
};
|
||||||
|
this.sensitiveManager?.saveInitialData(this.form);
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.dataScopeTree?.setCheckedKeys?.(this.form.dataScopeDeptIds || []);
|
||||||
|
});
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -193,12 +304,28 @@ export default {
|
|||||||
this.form = {
|
this.form = {
|
||||||
status: 1,
|
status: 1,
|
||||||
identities: ['driver'],
|
identities: ['driver'],
|
||||||
|
deptId: [],
|
||||||
|
dataScopeRange: 1,
|
||||||
|
dataLevelRange: 1,
|
||||||
|
dataScopeDeptIds: [],
|
||||||
};
|
};
|
||||||
|
this.sensitiveManager?.saveInitialData({});
|
||||||
}
|
}
|
||||||
done();
|
done();
|
||||||
},
|
},
|
||||||
rowSave(row, done, loading) {
|
rowSave(row, done, loading) {
|
||||||
submit(this.normalizeSubmitRow(row)).then(
|
const payload = this.normalizeSubmitRow(row, false);
|
||||||
|
if (!payload.deptId) {
|
||||||
|
this.$message.warning('请选择所属组织');
|
||||||
|
loading();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (payload.dataScopeRange === 3 && (!payload.dataScopeDeptIds || !payload.dataScopeDeptIds.length)) {
|
||||||
|
this.$message.warning('请选择自定义数据权限组织');
|
||||||
|
loading();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
submit(payload).then(
|
||||||
() => {
|
() => {
|
||||||
this.onLoad(this.page);
|
this.onLoad(this.page);
|
||||||
this.$message.success('操作成功');
|
this.$message.success('操作成功');
|
||||||
@@ -208,7 +335,18 @@ export default {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
rowUpdate(row, index, done, loading) {
|
rowUpdate(row, index, done, loading) {
|
||||||
submit(this.normalizeSubmitRow(row)).then(
|
const payload = this.normalizeSubmitRow(row, true);
|
||||||
|
if (!payload.deptId) {
|
||||||
|
this.$message.warning('请选择所属组织');
|
||||||
|
loading();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (payload.dataScopeRange === 3 && (!payload.dataScopeDeptIds || !payload.dataScopeDeptIds.length)) {
|
||||||
|
this.$message.warning('请选择自定义数据权限组织');
|
||||||
|
loading();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
submit(payload).then(
|
||||||
() => {
|
() => {
|
||||||
this.onLoad(this.page);
|
this.onLoad(this.page);
|
||||||
this.$message.success('操作成功');
|
this.$message.success('操作成功');
|
||||||
@@ -351,5 +489,13 @@ export default {
|
|||||||
:deep(.avue-crud__menu) {
|
:deep(.avue-crud__menu) {
|
||||||
min-height: auto;
|
min-height: auto;
|
||||||
}
|
}
|
||||||
|
.dept-tag {
|
||||||
|
margin-right: 4px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
.form-tip {
|
||||||
|
color: var(--el-text-color-secondary);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user