“培训审批修改v1.2”
This commit is contained in:
1 parent
2e4d35b41e
commit
53e5afaafe
3 files changed
+180
-46
No files matched your search
+77
-1
@@ -19,7 +19,6 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
@@ -28,6 +27,10 @@ import org.dromara.system.domain.vo.SysUserVo;
|
||||
import org.dromara.system.service.ISysUserService;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.rs.domain.vo.SysUserBasicVo;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* 培训申请控制器
|
||||
@@ -439,4 +442,77 @@ public class RsTrainingApplicationController extends BaseController {
|
||||
return R.fail("查询失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量查询同行人基本信息
|
||||
* 用于培训申请/记录详情展示,不限制account_type
|
||||
*
|
||||
* 权限说明:
|
||||
* - 只需要培训申请的查询权限即可
|
||||
* - 不需要system:teacher:list权限
|
||||
* - 只返回用户的基本信息(姓名、部门等),不暴露敏感数据
|
||||
*
|
||||
* @param userIds 用户ID列表(逗号分隔)
|
||||
* @return 用户基本信息列表
|
||||
*/
|
||||
@SaCheckPermission("rs:trainingapplication:query")
|
||||
@GetMapping("/companions/batch")
|
||||
public R<List<SysUserBasicVo>> batchQueryCompanions(@RequestParam String userIds) {
|
||||
log.info("批量查询同行人信息,用户ID列表: {}", userIds);
|
||||
|
||||
// 参数验证
|
||||
if (StringUtils.isBlank(userIds)) {
|
||||
log.warn("同行人ID列表为空");
|
||||
return R.ok(new ArrayList<>());
|
||||
}
|
||||
|
||||
// 解析用户ID列表
|
||||
List<Long> userIdList = new ArrayList<>();
|
||||
try {
|
||||
String[] idArray = userIds.split(",");
|
||||
for (String idStr : idArray) {
|
||||
if (StringUtils.isNotBlank(idStr)) {
|
||||
userIdList.add(Long.parseLong(idStr.trim()));
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
log.error("解析用户ID失败: {}", e.getMessage());
|
||||
return R.fail("用户ID格式错误");
|
||||
}
|
||||
|
||||
if (CollUtil.isEmpty(userIdList)) {
|
||||
log.warn("解析后的用户ID列表为空");
|
||||
return R.ok(new ArrayList<>());
|
||||
}
|
||||
|
||||
// 批量查询用户信息
|
||||
List<SysUserBasicVo> userList = new ArrayList<>();
|
||||
for (Long userId : userIdList) {
|
||||
try {
|
||||
// 调用用户服务查询
|
||||
SysUserVo sysUser = sysUserService.selectUserById(userId);
|
||||
if (sysUser != null) {
|
||||
SysUserBasicVo vo = new SysUserBasicVo();
|
||||
vo.setUserId(sysUser.getUserId());
|
||||
vo.setUserName(sysUser.getUserName());
|
||||
vo.setNickName(sysUser.getNickName());
|
||||
vo.setAccountType(sysUser.getAccountType());
|
||||
vo.setStatus(sysUser.getStatus());
|
||||
vo.setDeptId(sysUser.getDeptId());
|
||||
// 设置部门名称(SysUserVo已经包含deptName字段)
|
||||
vo.setDeptName(sysUser.getDeptName());
|
||||
userList.add(vo);
|
||||
log.debug("查询到用户: userId={}, nickName={}", userId, sysUser.getNickName());
|
||||
} else {
|
||||
log.warn("用户不存在: userId={}", userId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("查询用户{}失败: {}", userId, e.getMessage());
|
||||
// 继续查询下一个用户,不中断整个流程
|
||||
}
|
||||
}
|
||||
|
||||
log.info("批量查询同行人完成,请求{}个,查询到{}个", userIdList.size(), userList.size());
|
||||
return R.ok(userList);
|
||||
}
|
||||
}
|
||||
@@ -458,3 +458,29 @@ export function getPendingTrainingApplications() {
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量查询同行人基本信息
|
||||
* 用于培训申请/记录详情展示
|
||||
* @param userIds 用户ID数组
|
||||
* @returns 用户基本信息列表
|
||||
*/
|
||||
export interface UserBasicVO {
|
||||
userId: number;
|
||||
userName: string;
|
||||
nickName: string;
|
||||
accountType: string;
|
||||
status: string;
|
||||
deptId?: number;
|
||||
deptName?: string;
|
||||
}
|
||||
|
||||
export function batchQueryCompanions(userIds: number[]) {
|
||||
return request({
|
||||
url: '/rs/training/application/companions/batch',
|
||||
method: 'get',
|
||||
params: {
|
||||
userIds: userIds.join(',')
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -999,6 +999,7 @@ import {
|
||||
deleteTrainingApplication,
|
||||
getTrainingApprovalHistory,
|
||||
resubmitTrainingApplication,
|
||||
batchQueryCompanions,
|
||||
updateRecordAttachments,
|
||||
listAllApprovalRecords
|
||||
} from '@/api/rs/training';
|
||||
@@ -1432,6 +1433,9 @@ const applicationForm = reactive<{
|
||||
// 同行人选择器相关
|
||||
const selectedCompanions = ref<TeacherVO[]>([]);
|
||||
|
||||
// 同行人姓名缓存(用于详情展示)
|
||||
const companionNamesCache = ref<Record<string, string>>({});
|
||||
|
||||
// 培训申请表单校验规则
|
||||
const applicationRules = reactive<any>({
|
||||
// 情况基本信息验证
|
||||
@@ -1716,7 +1720,7 @@ function getTeacherList() {
|
||||
});
|
||||
}
|
||||
|
||||
/** 异步加载教师列表用于详情显示 */
|
||||
/** 异步加载教师列表用于详情显示(容错版,权限不足时不报错)*/
|
||||
async function loadTeacherListForDisplay() {
|
||||
try {
|
||||
console.log('开始加载教师列表...');
|
||||
@@ -1733,8 +1737,9 @@ async function loadTeacherListForDisplay() {
|
||||
}));
|
||||
console.log('教师列表加载完成:', teacherList.value.length, '位教师');
|
||||
console.log('教师ID列表:', teacherList.value.map(t => t.teacherId));
|
||||
} catch (error) {
|
||||
console.error('获取教师列表失败:', error);
|
||||
} catch (error: any) {
|
||||
console.warn('获取教师列表失败(可能是权限不足),将使用备用查询方式:', error);
|
||||
// ⚠️ 不再抛出错误,允许使用备用的同行人查询接口
|
||||
teacherList.value = [];
|
||||
}
|
||||
}
|
||||
@@ -2131,66 +2136,91 @@ function formatFileSize(bytes: number | string | undefined): string {
|
||||
return parseFloat((size / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
/** 获取同行人姓名列表 */
|
||||
function getCompanionNames(companions: (string | number)[] | string | null | undefined): string {
|
||||
/** 异步加载同行人姓名并缓存(使用新的批量查询接口)*/
|
||||
async function loadCompanionNames(companions: (string | number)[] | string | null | undefined): Promise<string> {
|
||||
if (!companions) {
|
||||
console.log('[同行人解析] 同行人数据为空');
|
||||
return '';
|
||||
}
|
||||
|
||||
let companionArray: (string | number)[] = [];
|
||||
// 生成缓存key
|
||||
const cacheKey = typeof companions === 'string' ? companions : JSON.stringify(companions);
|
||||
|
||||
// 如果是字符串,尝试解析JSON
|
||||
// 如果已缓存,直接返回
|
||||
if (companionNamesCache.value[cacheKey]) {
|
||||
return companionNamesCache.value[cacheKey];
|
||||
}
|
||||
|
||||
let companionArray: number[] = [];
|
||||
|
||||
// 解析同行人ID列表
|
||||
if (typeof companions === 'string') {
|
||||
try {
|
||||
companionArray = JSON.parse(companions);
|
||||
if (!Array.isArray(companionArray)) {
|
||||
console.log('[同行人解析] JSON解析结果不是数组:', companionArray);
|
||||
return '';
|
||||
const parsed = JSON.parse(companions);
|
||||
if (Array.isArray(parsed)) {
|
||||
companionArray = parsed.map(id => Number(id));
|
||||
}
|
||||
console.log('[同行人解析] JSON解析成功:', companionArray);
|
||||
} catch (e) {
|
||||
// 如果JSON解析失败,可能是逗号分隔的字符串
|
||||
companionArray = companions.split(',').map(id => id.trim()).filter(id => id);
|
||||
companionArray = companions.split(',')
|
||||
.map(id => Number(id.trim()))
|
||||
.filter(id => !isNaN(id));
|
||||
console.log('[同行人解析] 使用逗号分隔解析:', companionArray);
|
||||
}
|
||||
} else if (Array.isArray(companions)) {
|
||||
companionArray = companions;
|
||||
companionArray = companions.map(id => Number(id));
|
||||
console.log('[同行人解析] 直接使用数组:', companionArray);
|
||||
}
|
||||
|
||||
if (companionArray.length === 0) {
|
||||
console.log('[同行人解析] 同行人数组为空');
|
||||
return '';
|
||||
}
|
||||
|
||||
// 如果教师列表还未加载,显示"加载中..."
|
||||
if (teacherList.value.length === 0) {
|
||||
console.log('[同行人解析] 教师列表未加载,返回加载中');
|
||||
return '加载中...';
|
||||
try {
|
||||
// 调用新的批量查询接口(不需要system:teacher:list权限)
|
||||
console.log('[同行人查询] 调用批量查询接口:', companionArray);
|
||||
const response: any = await batchQueryCompanions(companionArray);
|
||||
const users = response.data || [];
|
||||
|
||||
console.log('[同行人查询] 查询结果:', users.length, '个用户');
|
||||
|
||||
// 拼接姓名
|
||||
const names = companionArray.map(userId => {
|
||||
const user = users.find((u: any) => u.userId === userId);
|
||||
const name = user ? (user.nickName || user.userName) : `未知用户(ID:${userId})`;
|
||||
console.log(`[同行人查询] ID ${userId} -> ${name}`);
|
||||
return name;
|
||||
}).join('、');
|
||||
|
||||
// 缓存结果
|
||||
companionNamesCache.value[cacheKey] = names;
|
||||
console.log('[同行人查询] 最终结果:', names);
|
||||
return names;
|
||||
} catch (error) {
|
||||
console.error('[同行人查询] 接口调用失败:', error);
|
||||
// 降级方案:显示ID列表
|
||||
const fallback = `同行人ID: ${companionArray.join('、')}`;
|
||||
companionNamesCache.value[cacheKey] = fallback;
|
||||
return fallback;
|
||||
}
|
||||
|
||||
console.log('[同行人解析] 教师列表已加载:', teacherList.value.length, '位教师');
|
||||
console.log('[同行人解析] 需要查找的ID:', companionArray);
|
||||
|
||||
const names = companionArray.map(teacherId => {
|
||||
// 确保teacherId转换为正确的类型进行比较
|
||||
const teacher = teacherList.value.find(t =>
|
||||
String(t.teacherId) === String(teacherId) ||
|
||||
Number(t.teacherId) === Number(teacherId)
|
||||
);
|
||||
const name = teacher ? teacher.teacherName : `未知教师(ID:${teacherId})`;
|
||||
console.log(`[同行人解析] ID ${teacherId} -> ${name}`);
|
||||
return name;
|
||||
}).join('、');
|
||||
|
||||
console.log('[同行人解析] 最终结果:', names);
|
||||
return names;
|
||||
}
|
||||
|
||||
/** 格式化同行人员显示(表格列使用) */
|
||||
function formatCompanions(companions: string | undefined): string {
|
||||
return getCompanionNames(companions);
|
||||
/** 获取同行人姓名列表(同步版,从缓存读取)*/
|
||||
function getCompanionNames(companions: (string | number)[] | string | null | undefined): string {
|
||||
if (!companions) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const cacheKey = typeof companions === 'string' ? companions : JSON.stringify(companions);
|
||||
|
||||
// 从缓存返回
|
||||
if (companionNamesCache.value[cacheKey]) {
|
||||
return companionNamesCache.value[cacheKey];
|
||||
}
|
||||
|
||||
// 如果缓存中没有,返回"加载中..."并异步加载
|
||||
loadCompanionNames(companions);
|
||||
return '加载中...';
|
||||
}
|
||||
|
||||
/** 查看申请详情 */
|
||||
@@ -2210,20 +2240,22 @@ async function handleViewApplicant(row: any) {
|
||||
}
|
||||
}
|
||||
|
||||
// 确保教师列表已加载(用于显示同行人姓名)
|
||||
if (teacherList.value.length === 0) {
|
||||
await loadTeacherListForDisplay();
|
||||
}
|
||||
|
||||
// 复制申请详情
|
||||
Object.assign(applicationDetail, row);
|
||||
|
||||
console.log('[查看申请详情] 详情数据已设置:', {
|
||||
userName: applicationDetail.userName,
|
||||
nickName: applicationDetail.nickName,
|
||||
attachmentIds: applicationDetail.attachmentIds // 添加附件ID日志
|
||||
companions: applicationDetail.companions,
|
||||
attachmentIds: applicationDetail.attachmentIds
|
||||
});
|
||||
|
||||
// 预加载同行人信息(使用新接口,不需要system:teacher:list权限)
|
||||
if (row.companions) {
|
||||
await loadCompanionNames(row.companions);
|
||||
console.log('[查看申请详情] 同行人信息已预加载');
|
||||
}
|
||||
|
||||
// 加载申请详情的附件数据
|
||||
await handleApplicationDetailAttachmentData(row.attachmentIds);
|
||||
|
||||
|
||||
Reference in new issue
Block a user