This commit is contained in:
green 2025-11-27 10:34:00 +08:00
parent 915ac72596
commit f22200c965
2 changed files with 320 additions and 86 deletions

View File

@ -1,61 +1,61 @@
# 数据源配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
druid:
# 主库数据源
master:
url: jdbc:mysql://127.0.0.1:3306/ry_xinli?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: ry_xinli
password: ZLZBcfGtsWJe5r4z
# 从库数据源
slave:
# 从数据源开关/默认关闭
enabled: false
url:
username:
password:
# 初始连接数
initialSize: 10
# 最小连接池数量
minIdle: 20
# 最大连接池数量
maxActive: 100
# 配置获取连接等待超时的时间减少到20秒快速失败
maxWait: 20000
# 配置连接超时时间
connectTimeout: 10000
# 配置网络超时时间
socketTimeout: 30000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问(生产环境必须配置!)
allow: 127.0.0.1,192.168.0.0/16
url-pattern: /druid/*
# 控制台管理用户名和密码(重要:生产环境必须修改)
login-username: ddnai_admin
login-password: Ddnai@2025#Druid
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
druid:
# 主库数据源
master:
url: jdbc:mysql://1.15.149.240:3306/ry_xinli?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: ry_xinli
password: ZLZBcfGtsWJe5r4z
# 从库数据源
slave:
# 从数据源开关/默认关闭
enabled: false
url:
username:
password:
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置连接超时时间
connectTimeout: 30000
# 配置网络超时时间
socketTimeout: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问(生产环境必须配置!)
allow: 127.0.0.1,192.168.0.0/16
url-pattern: /druid/*
# 控制台管理用户名和密码(重要:生产环境必须修改)
login-username: ddnai_admin
login-password: Ddnai@2025#Druid
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true

View File

@ -102,39 +102,50 @@
/>
<!-- 添加或修改权限对话框 -->
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
<el-form-item label="量表" prop="scaleId">
<el-select v-model="form.scaleId" placeholder="请选择量表" style="width: 100%;" filterable>
<el-option
v-for="scale in scaleList"
:key="scale.scaleId"
:label="scale.scaleName"
:value="scale.scaleId">
</el-option>
</el-select>
<div style="border: 1px solid #DCDFE6; border-radius: 4px; padding: 10px; max-height: 300px; overflow-y: auto;">
<el-input
v-model="scaleSearchKeyword"
placeholder="请输入量表名称搜索"
clearable
size="small"
style="margin-bottom: 10px;"
prefix-icon="el-icon-search">
</el-input>
<el-table
:data="filteredScaleList"
@row-click="handleScaleRowClick"
highlight-current-row
max-height="250">
<el-table-column width="55" align="center">
<template slot-scope="scope">
<el-radio
:label="scope.row.scaleId"
v-model="form.scaleId"
@change="handleScaleChange(scope.row)">
<span></span>
</el-radio>
</template>
</el-table-column>
<el-table-column label="量表名称" prop="scaleName" :show-overflow-tooltip="true" />
<el-table-column label="量表编码" prop="scaleCode" width="150" />
<el-table-column label="题目数量" prop="itemCount" width="100" align="center" />
</el-table>
</div>
</el-form-item>
<el-form-item label="用户" prop="userIds">
<el-select
v-model="form.userIds"
placeholder="请选择用户(可多选,留空表示所有用户)"
clearable
filterable
multiple
reserve-keyword
:loading="userSearchLoading"
<el-input
:value="selectedUserDisplay"
placeholder="点击选择用户(留空表示所有用户)"
readonly
style="width: 100%;"
@focus="handleSelectFocus"
@change="handleUserIdsChange">
<el-option
v-for="user in userOptions"
:key="user.userId"
:label="user.nickName ? `${user.nickName}${user.userName}` : user.userName"
:value="user.userId">
</el-option>
</el-select>
@focus="showUserSelectDialog = true">
<el-button slot="append" icon="el-icon-search" @click="showUserSelectDialog = true">选择</el-button>
</el-input>
<div style="margin-top: 5px; color: #909399; font-size: 12px;">
提示可输入姓名或账号搜索支持多选留空表示所有用户
提示留空表示所有用户点击"选择"按钮可按信息编号姓名监区筛选用户
</div>
</el-form-item>
<el-form-item label="开始时间" prop="startTime">
@ -170,6 +181,71 @@
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- 用户选择对话框 -->
<el-dialog title="选择用户" :visible.sync="showUserSelectDialog" width="900px" append-to-body>
<el-form :model="userQueryParams" ref="userQueryForm" size="small" :inline="true">
<el-form-item label="信息编号" prop="infoNumber">
<el-input
v-model="userQueryParams.infoNumber"
placeholder="请输入信息编号"
clearable
@keyup.enter.native="handleUserQuery"
/>
</el-form-item>
<el-form-item label="姓名" prop="userName">
<el-input
v-model="userQueryParams.userName"
placeholder="请输入姓名"
clearable
@keyup.enter.native="handleUserQuery"
/>
</el-form-item>
<el-form-item label="监区" prop="deptId">
<el-select v-model="userQueryParams.deptId" placeholder="请选择监区" clearable style="width: 200px">
<el-option
v-for="dept in deptOptions"
:key="dept.id"
:label="dept.label"
:value="dept.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleUserQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetUserQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table
ref="userTable"
:data="userSelectList"
@selection-change="handleUserSelectionChange"
height="400px"
v-loading="userSelectLoading">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="信息编号" prop="infoNumber" width="120" />
<el-table-column label="姓名" prop="userName" :show-overflow-tooltip="true" />
<el-table-column label="账号" prop="userAccount" :show-overflow-tooltip="true" />
<el-table-column label="监区" prop="deptName" :show-overflow-tooltip="true" />
<el-table-column label="状态" align="center" prop="status" width="80">
<template slot-scope="scope">
<el-tag v-if="scope.row.status === '0'" type="success" size="small">正常</el-tag>
<el-tag v-else type="danger" size="small">停用</el-tag>
</template>
</el-table-column>
</el-table>
<pagination
v-show="userSelectTotal > 0"
:total="userSelectTotal"
:page.sync="userQueryParams.pageNum"
:limit.sync="userQueryParams.pageSize"
@pagination="getUserSelectList"
/>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="handleConfirmUserSelect"> </el-button>
<el-button @click="showUserSelectDialog = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
@ -179,6 +255,8 @@ import { listScale } from "@/api/psychology/scale";
import { allocatedUserList } from "@/api/system/role";
import { listRole } from "@/api/system/role";
import { getUser } from "@/api/system/user";
import { listProfile } from "@/api/psychology/profile";
import { deptTreeSelect } from "@/api/system/user";
export default {
name: "PsyScalePermission",
@ -200,6 +278,8 @@ export default {
permissionList: [],
//
scaleList: [],
//
scaleSearchKeyword: "",
//
userOptions: [],
//
@ -210,6 +290,24 @@ export default {
title: "",
//
open: false,
//
showUserSelectDialog: false,
//
userSelectList: [],
userSelectTotal: 0,
userSelectLoading: false,
selectedUserIds: [],
//
deptOptions: [],
//
userQueryParams: {
pageNum: 1,
pageSize: 10,
infoNumber: undefined,
userName: undefined,
deptId: undefined,
status: '0'
},
//
queryParams: {
pageNum: 1,
@ -231,10 +329,60 @@ export default {
}
};
},
computed: {
//
filteredScaleList() {
if (!this.scaleSearchKeyword) {
return this.scaleList;
}
const keyword = this.scaleSearchKeyword.toLowerCase();
return this.scaleList.filter(scale => {
const scaleName = (scale.scaleName || '').toLowerCase();
const scaleCode = (scale.scaleCode || '').toLowerCase();
return scaleName.includes(keyword) || scaleCode.includes(keyword);
});
},
//
selectedUserDisplay() {
const userIds = this.form.userIds || [];
if (userIds.length === 0) {
return "";
} else if (userIds.length === 1) {
const user = this.userOptions.find(u => u.userId === userIds[0]);
return user ? (user.nickName ? `${user.nickName}${user.userName}` : user.userName) : "";
} else {
return `已选择 ${userIds.length} 个用户`;
}
}
},
watch: {
//
showUserSelectDialog(val) {
if (val) {
//
this.resetUserQuery();
this.selectedUserIds = [...(this.form.userIds || [])];
this.getUserSelectList().then(() => {
//
this.$nextTick(() => {
if (this.form.userIds && this.form.userIds.length > 0 && this.$refs.userTable) {
this.form.userIds.forEach(userId => {
const row = this.userSelectList.find(u => u.userId === userId);
if (row) {
this.$refs.userTable.toggleRowSelection(row, true);
}
});
}
});
});
}
}
},
created() {
this.getList();
this.loadScales();
this.loadUsers();
this.loadDeptTree();
},
methods: {
/** 查询权限列表 */
@ -345,6 +493,88 @@ export default {
console.error("获取学员角色ID失败:", error);
});
},
/** 加载部门树 */
loadDeptTree() {
deptTreeSelect().then(response => {
this.deptOptions = response.data || [];
});
},
/** 量表行点击 */
handleScaleRowClick(row) {
this.form.scaleId = row.scaleId;
},
/** 量表选择改变 */
handleScaleChange(scale) {
this.form.scaleId = scale.scaleId;
},
/** 获取用户选择列表 */
getUserSelectList() {
this.userSelectLoading = true;
// 使
const query = {
pageNum: this.userQueryParams.pageNum,
pageSize: this.userQueryParams.pageSize,
infoNumber: this.userQueryParams.infoNumber,
userName: this.userQueryParams.userName,
deptId: this.userQueryParams.deptId,
status: this.userQueryParams.status
};
return listProfile(query).then(response => {
this.userSelectList = (response.rows || []).map(profile => ({
userId: profile.userId,
infoNumber: profile.infoNumber,
userName: profile.userName,
userAccount: profile.infoNumber, // 使
deptName: profile.deptName,
status: profile.status || '0'
}));
this.userSelectTotal = response.total || 0;
this.userSelectLoading = false;
return response;
}).catch(() => {
this.userSelectLoading = false;
return Promise.reject();
});
},
/** 用户查询 */
handleUserQuery() {
this.userQueryParams.pageNum = 1;
this.getUserSelectList();
},
/** 重置用户查询 */
resetUserQuery() {
this.resetForm("userQueryForm");
this.userQueryParams = {
pageNum: 1,
pageSize: 10,
infoNumber: undefined,
userName: undefined,
deptId: undefined,
status: '0'
};
this.handleUserQuery();
},
/** 用户选择改变 */
handleUserSelectionChange(selection) {
this.selectedUserIds = selection.map(item => item.userId);
},
/** 确认用户选择 */
handleConfirmUserSelect() {
// form.userIds
this.form.userIds = [...this.selectedUserIds];
// userOptions
this.selectedUserIds.forEach(userId => {
const user = this.userSelectList.find(u => u.userId === userId);
if (user && !this.userOptions.find(u => u.userId === userId)) {
this.userOptions.push({
userId: user.userId,
userName: user.userAccount || user.userName,
nickName: user.userName
});
}
});
this.showUserSelectDialog = false;
},
/** 搜索用户(远程搜索) */
searchUsers(keyword) {
if (!this.studentRoleId) {
@ -545,6 +775,8 @@ export default {
_permissionIds: undefined, // ID
_groupKey: undefined // key
};
this.scaleSearchKeyword = "";
this.selectedUserIds = [];
this.resetForm("form");
},
/** 搜索按钮操作 */
@ -574,6 +806,7 @@ export default {
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.scaleSearchKeyword = "";
// userOptions
if (this.userOptions.length === 0) {
this.searchUsers("");
@ -584,6 +817,7 @@ export default {
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
this.scaleSearchKeyword = "";
// ID
const permissionIds = row.permissionIds || (row.permissionId ? [row.permissionId] : []);