1、车船模块fix bug

2、运力模块fix bug
3、新增设备台账
4、其他bug 修复
5、调整组织、人员模块
This commit is contained in:
2026-08-07 08:28:21 +08:00
parent 1e4de76978
commit 6a02e9126b
37 changed files with 2593 additions and 645 deletions
+251 -71
View File
@@ -37,7 +37,7 @@
v-if="permission.user_add && !auditMode"
type="primary"
icon="el-icon-plus"
@click="$refs.crud.rowAdd()"
@click="openUserDialog('add')"
>
</el-button>
<el-button
@@ -134,7 +134,7 @@
<el-link
type="primary"
v-if="this.permission.user_edit"
@click.stop="$refs.crud.rowEdit(row, index)"
@click.stop="openUserDialog('edit', row)"
>编辑
</el-link>
<el-dropdown @command="command => handleDropdownCommand(command, row, index)">
@@ -147,12 +147,6 @@
<el-dropdown-item command="grantRole" v-if="permission.user_role">
角色配置
</el-dropdown-item>
<el-dropdown-item
command="platformConfig"
v-if="userInfo.authority.includes('admin')"
>
平台配置
</el-dropdown-item>
<el-dropdown-item command="authLog" v-if="userInfo.authority.includes('admin')">
认证日志
</el-dropdown-item>
@@ -172,20 +166,62 @@
</template>
</el-dropdown>
</template>
<template #tenantName="{ row }">
<el-tag>{{ row.tenantName }}</el-tag>
</template>
<template #roleName="{ row }">
<el-tag>{{ row.roleName }}</el-tag>
</template>
<template #deptName="{ row }">
<el-tag>{{ row.deptName }}</el-tag>
</template>
<template #userTypeName="{ row }">
<el-tag>{{ row.userTypeName }}</el-tag>
</template>
</avue-crud>
<el-dialog
v-model="userDialog"
:title="userDialogMode === 'add' ? '新增用户' : '编辑用户'"
width="90%"
top="5vh"
append-to-body
destroy-on-close
class="user-edit-dialog"
>
<template #header>
<span class="dialog-title">{{ userDialogMode === 'add' ? '新增用户' : '编辑用户' }}</span>
</template>
<el-form ref="userFormRef" :model="form" :rules="userRules" label-position="right" label-width="120px">
<el-row :gutter="20">
<el-col :span="6"><el-form-item label="账号名" prop="account"><el-input v-model="form.account" /></el-form-item></el-col>
<el-col :span="6"><el-form-item label="姓名" prop="realName"><el-input v-model="form.realName" /></el-form-item></el-col>
<el-col :span="6"><el-form-item label="手机号" prop="phone"><el-input v-model="form.phone" /></el-form-item></el-col>
<el-col :span="6"><el-form-item label="邮箱"><el-input v-model="form.email" /></el-form-item></el-col>
<el-col :span="6"><el-form-item label="性别"><el-select v-model="form.sex" class="full-width"><el-option label="男" :value="1" /><el-option label="女" :value="2" /><el-option label="未知" :value="3" /></el-select></el-form-item></el-col>
<el-col :span="6"><el-form-item label="岗位" prop="postId"><el-tree-select v-model="form.postId" :data="postList" :props="{ label: 'postName', value: 'id' }" check-strictly class="full-width" /></el-form-item></el-col>
<el-col :span="6"><el-form-item label="所属组织" prop="deptId"><el-tree-select v-model="form.deptId" :data="permissionDeptTree" :props="{ label: 'title', value: 'id' }" multiple check-strictly show-checkbox class="full-width" /></el-form-item></el-col>
<el-col :span="6"><el-form-item label="工号"><el-input v-model="form.code" /></el-form-item></el-col>
<el-col :span="6"><el-form-item label="人员类别"><el-select v-model="form.personCategory" class="full-width"><el-option label="内部员工" :value="1" /><el-option label="承运商" :value="2" /></el-select></el-form-item></el-col>
<el-col :span="18"><el-form-item label="数据权限范围"><el-radio-group v-model="form.dataScopeRange"><el-radio :value="1">仅所属组织</el-radio><el-radio :value="2">全部组织</el-radio><el-radio :value="3">自定义</el-radio></el-radio-group></el-form-item></el-col>
<el-col :span="18" :offset="6"><el-form-item label="数据层级范围"><el-radio-group v-model="form.dataLevelRange"><el-radio :value="1">包含下级</el-radio><el-radio :value="2">仅本级</el-radio></el-radio-group></el-form-item></el-col>
<el-col :span="24"><el-form-item label="备注"><el-input v-model="form.remark" type="textarea" :rows="3" maxlength="200" show-word-limit /></el-form-item></el-col>
</el-row>
</el-form>
<el-tabs class="user-permission-tabs">
<el-tab-pane label="已拥有角色">
<el-table :data="formRoleList" border>
<el-table-column type="index" label="序号" width="70" />
<el-table-column prop="id" label="角色编号" />
<el-table-column prop="title" label="角色名称" />
<el-table-column label="操作" width="90"><template #default="{ row }"><el-link type="danger" @click="removeFormRole(row.id)">删除</el-link></template></el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane v-if="form.dataScopeRange === 3" label="数据权限">
<el-tree :data="permissionDeptTree" show-checkbox node-key="id" :default-checked-keys="form.dataScopeDeptIds || []" :props="{ label: 'title', children: 'children' }" @check="handleDataScopeCheck" />
</el-tab-pane>
<el-tab-pane label="客商权限">
<div class="permission-toolbar customer-toolbar"><el-checkbox v-model="form.includeNewCustomer" :true-value="1" :false-value="0">包含新增的客商</el-checkbox></div>
<el-table ref="customerTable" :data="customerList" border @selection-change="handleCustomerSelection"><el-table-column type="selection" width="55" /><el-table-column prop="customerCode" label="客商编码" /><el-table-column prop="fullName" label="客商名称" /></el-table>
</el-tab-pane>
</el-tabs>
<template #footer><span class="dialog-footer"><el-button type="primary" @click="submitUserForm">保存</el-button><el-button @click="userDialog = false">返回</el-button><el-button v-if="userDialogMode === 'edit'" @click="resetDialogPassword">重置密码</el-button><el-button @click="handleAddRole">添加角色</el-button></span></template>
</el-dialog>
<!-- 用户角色配置 -->
<el-dialog title="用户角色配置" append-to-body v-model="roleBox" width="345px">
<el-row
@@ -200,8 +236,13 @@
size="small"
@change="handleLinkedChange('treeRole')"
/>
<el-tooltip content="开启后勾选父节点会自动勾选所有子节点,关闭则可独立勾选任意节点" placement="top">
<el-icon style="margin-left: 4px; color: #909399; cursor: pointer"><el-icon-question-filled /></el-icon>
<el-tooltip
content="开启后勾选父节点会自动勾选所有子节点,关闭则可独立勾选任意节点"
placement="top"
>
<el-icon style="margin-left: 4px; color: #909399; cursor: pointer"
><el-icon-question-filled
/></el-icon>
</el-tooltip>
</span>
<el-button-group>
@@ -246,17 +287,6 @@
</avue-form>
</el-dialog>
<!-- 用户平台配置行级别 -->
<el-dialog title="用户平台配置" append-to-body v-model="platformBox" width="600px">
<avue-form ref="platformFormRef" :option="platformFormOption" v-model="platformForm" />
<template #footer>
<span class="dialog-footer">
<el-button @click="platformBox = false"> </el-button>
<el-button type="primary" @click="submitPlatformConfig"> </el-button>
</span>
</template>
</el-dialog>
<!-- 管理员修改密码 -->
<el-dialog title="修改密码" append-to-body v-model="passwordBox" width="460px">
<el-form
@@ -265,7 +295,7 @@
:rules="passwordRules"
label-width="auto"
>
<el-form-item label="登录账号">
<el-form-item label="账号">
<el-input v-model="passwordForm.account" disabled />
</el-form-item>
<el-form-item label="新密码" prop="password">
@@ -296,10 +326,8 @@
import {
getList,
getUser,
getUserPlatform,
remove,
update,
updatePlatform,
add,
grant,
resetPassword,
@@ -308,6 +336,7 @@ import {
auditRefuse,
setLeader,
getLeaderList,
getCustomerOptions,
} from '@/api/system/user';
import { exportBlob } from '@/api/common';
import { getDeptTree } from '@/api/system/dept';
@@ -315,14 +344,13 @@ import { getRoleTree } from '@/api/system/role';
import { getPostList } from '@/api/system/post';
import { mapGetters } from 'vuex';
import { h } from 'vue';
import website from '@/config/website';
import { getToken } from '@/utils/auth';
import { downloadXls } from '@/utils/util';
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
import func from '@/utils/func';
import { sensitive } from '@/utils/sensitive';
import { excelOption, platformFormOption, treeOption, userOption } from '@/option/system/user';
import { excelOption, treeOption, userOption } from '@/option/system/user';
import AuthLog from './authlog.vue';
import AuthLock from './authlock.vue';
@@ -331,13 +359,15 @@ export default {
data() {
return {
form: {},
userDialog: false,
userDialogMode: 'add',
search: {},
sensitiveManager: null,
roleBox: false,
roleLinked: false,
roleFormMode: false,
grantUserId: '',
excelBox: false,
platformBox: false,
passwordBox: false,
initFlag: true,
auditMode: false,
@@ -357,11 +387,12 @@ export default {
roleTreeObj: [],
treeDeptId: '',
treeData: [],
permissionDeptTree: [],
postList: [],
customerList: [],
treeOption: treeOption,
userOption: userOption(this),
platformFormOption: platformFormOption,
data: [],
platformForm: {},
passwordForm: {},
passwordRules: {
password: [
@@ -373,16 +404,17 @@ export default {
{ validator: this.validatePassword2, trigger: 'blur' },
],
},
userRules: {
account: [{ required: true, message: '请输入账号名', trigger: 'blur' }],
realName: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
phone: [{ required: true, message: '请输入手机号', trigger: 'blur' }],
deptId: [{ required: true, message: '请选择所属组织', trigger: 'change' }],
},
excelForm: {},
excelOption: excelOption,
};
},
watch: {
'form.tenantId'() {
if (this.form.tenantId !== '' && this.initFlag) {
this.initData(this.form.tenantId);
}
},
'excelForm.isCovered'() {
if (this.excelForm.isCovered !== '') {
const column = this.findColumn(this.excelOption.column, 'excelFile');
@@ -407,14 +439,20 @@ export default {
});
return ids.join(',');
},
formRoleList() {
const selected = new Set(func.split(this.form.roleId || '').map(String));
const roles = [];
const walk = nodes =>
(nodes || []).forEach(node => {
if (selected.has(String(node.id))) roles.push(node);
walk(node.children);
});
walk(this.roleGrantList);
return roles;
},
},
mounted() {
// 非租户模式默认加载管理组数据
if (!website.tenantMode) {
this.initData(website.tenantId);
} else {
this.initData();
}
this.initData(this.userInfo.tenantId || this.website.tenantId);
},
created() {
// 创建脱敏工具实例
@@ -437,8 +475,6 @@ export default {
this.$refs.authLog.openUserAuthLog(row.id, row.name);
} else if (command === 'lockUser') {
this.$refs.authLock.openLockUser(row.id, row.account);
} else if (command === 'platformConfig') {
this.handlePlatformForRow(row);
} else if (command === 'resetPassword') {
this.handleResetForRow(row);
} else if (command === 'setPassword') {
@@ -488,14 +524,17 @@ export default {
},
initData(tenantId) {
getRoleTree(tenantId).then(res => {
this.roleGrantList = res.data.data;
const column = this.findColumn(this.userOption.group, 'roleId');
column.dicData = res.data.data;
});
getDeptTree(tenantId).then(res => {
this.permissionDeptTree = res.data.data;
const column = this.findColumn(this.userOption.group, 'deptId');
column.dicData = res.data.data;
});
getPostList(tenantId).then(res => {
this.postList = res.data.data;
const column = this.findColumn(this.userOption.group, 'postId');
column.dicData = res.data.data;
});
@@ -503,9 +542,18 @@ export default {
const column = this.findColumn(this.userOption.group, 'leaderId');
column.dicData = res.data.data;
});
getCustomerOptions().then(res => {
this.customerList = res.data.data || [];
});
},
submitRole() {
const roleList = this.$refs.treeRole.getCheckedKeys().join(',');
if (this.roleFormMode) {
this.form.roleId = roleList;
this.roleBox = false;
this.roleFormMode = false;
return;
}
grant(this.grantUserId, roleList).then(() => {
this.roleBox = false;
this.$message({
@@ -515,6 +563,98 @@ export default {
this.onLoad(this.page);
});
},
handleAddRole() {
this.roleFormMode = true;
this.roleTreeObj = func.split(this.form.roleId || '');
this.roleLinked = false;
getRoleTree(this.userInfo.tenantId).then(res => {
this.roleGrantList = res.data.data;
this.roleBox = true;
this.$nextTick(() => this.applyCheckedKeys('treeRole', this.roleTreeObj));
});
},
removeFormRole(roleId) {
this.form.roleId = func
.split(this.form.roleId || '')
.filter(id => String(id) !== String(roleId));
},
handleDataScopeCheck(_, checked) {
this.form.dataScopeDeptIds = checked.checkedKeys;
},
handleCustomerSelection(rows) {
this.form.customerIds = rows.map(row => row.id);
},
openUserDialog(mode, row = {}) {
this.userDialogMode = mode;
if (mode === 'add') {
this.form = {
account: '',
realName: '',
phone: '',
email: '',
sex: 3,
postId: '',
deptId: [],
code: '',
personCategory: 1,
dataScopeRange: 1,
dataLevelRange: 1,
remark: '',
roleId: '',
dataScopeDeptIds: [],
customerIds: [],
includeNewCustomer: 0,
};
this.userDialog = true;
this.$nextTick(() => this.$refs.userFormRef && this.$refs.userFormRef.clearValidate());
return;
}
getUser(row.id).then(res => {
const user = res.data.data;
this.form = {
...user,
deptId: func.split(user.deptId || ''),
postId: func.split(user.postId || '')[0] || '',
roleId: func.join(user.roleId || ''),
dataScopeDeptIds: user.dataScopeDeptIds || [],
customerIds: user.customerIds || [],
includeNewCustomer: user.includeNewCustomer || 0,
personCategory: user.personCategory || 1,
dataScopeRange: user.dataScopeRange || 1,
dataLevelRange: user.dataLevelRange || 1,
};
this.sensitiveManager.saveInitialData(this.form);
this.userDialog = true;
this.$nextTick(() => {
this.$refs.userFormRef && this.$refs.userFormRef.clearValidate();
(this.form.customerIds || []).forEach(id => {
const customer = this.customerList.find(item => String(item.id) === String(id));
if (customer) this.$refs.customerTable && this.$refs.customerTable.toggleRowSelection(customer, true);
});
});
});
},
submitUserForm() {
this.$refs.userFormRef.validate(valid => {
if (!valid) return;
const row = {
...this.form,
deptId: func.join(this.form.deptId),
postId: func.join(this.form.postId),
roleId: func.join(this.form.roleId),
leaderId: func.join(this.form.leaderId),
};
const request = this.userDialogMode === 'add' ? add(row) : update(this.sensitiveManager.getSubmitData(row));
request.then(() => {
this.userDialog = false;
this.onLoad(this.page);
this.$message.success('操作成功!');
});
});
},
resetDialogPassword() {
this.handleResetForRow(this.form);
},
rowSave(row, done, loading) {
row.deptId = func.join(row.deptId);
row.roleId = func.join(row.roleId);
@@ -779,23 +919,6 @@ export default {
if (!tree) return;
tree.setCheckedKeys(keys);
},
// ========== 平台配置(行级别) ==========
handlePlatformForRow(row) {
getUserPlatform(row.id).then(res => {
this.platformForm = { ...res.data.data, account: row.account };
this.platformBox = true;
});
},
submitPlatformConfig() {
updatePlatform(
this.platformForm.id,
this.platformForm.userType,
this.platformForm.userExt
).then(() => {
this.platformBox = false;
this.$message({ type: 'success', message: '操作成功!' });
});
},
handlePasswordForRow(row) {
this.passwordForm = {
userId: row.id,
@@ -902,12 +1025,11 @@ export default {
},
onLoad(page, params = {}) {
this.loading = true;
getList(
page.currentPage,
page.pageSize,
Object.assign(params, this.query, { status: this.auditMode ? 0 : 1 }),
this.treeDeptId
).then(res => {
const queryParams = { ...this.query, ...params };
if (this.auditMode) {
queryParams.status = 0;
}
getList(page.currentPage, page.pageSize, queryParams, this.treeDeptId).then(res => {
const data = res.data.data;
this.page.total = data.total;
this.data = data.records;
@@ -931,4 +1053,62 @@ export default {
.box .el-scrollbar__wrap {
overflow: scroll;
}
.user-permission-tabs {
width: 100%;
margin-top: 8px;
}
.user-edit-dialog .dialog-title {
display: inline-flex;
align-items: center;
font-size: 16px;
font-weight: 600;
}
.user-edit-dialog .dialog-title::before {
width: 4px;
height: 18px;
margin-right: 8px;
background: #409eff;
content: '';
}
.user-edit-dialog .el-form-item {
margin-bottom: 16px;
}
.user-edit-dialog .el-form-item__label {
white-space: nowrap;
}
.user-edit-dialog .el-radio-group {
white-space: nowrap;
}
.full-width {
width: 100%;
}
.user-permission-tabs .el-tabs__header {
margin-bottom: 12px;
}
.permission-toolbar {
display: flex;
justify-content: flex-end;
margin-bottom: 12px;
}
.customer-toolbar {
justify-content: flex-start;
}
.avue-dialog .el-form-item__label {
white-space: nowrap;
}
.avue-dialog .el-radio-group {
white-space: nowrap;
}
</style>