From c6d0f5b7d4698c8bec3023d130d18b1fa2c43e4c Mon Sep 17 00:00:00 2001 From: = <=> Date: Wed, 19 Aug 2026 16:58:43 +0800 Subject: [PATCH 1/3] commit --- .../CadreTrainingMineController.java | 4 +- .../CadreTrainingSignUpController.java | 6 ++- .../cadreTraining/signUp/signForm.js | 50 ++++++------------- 3 files changed, 24 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/cadreTraining/controller/CadreTrainingMineController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/cadreTraining/controller/CadreTrainingMineController.java index 2b5909cf..9f52aa23 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/cadreTraining/controller/CadreTrainingMineController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/cadreTraining/controller/CadreTrainingMineController.java @@ -110,7 +110,9 @@ public class CadreTrainingMineController { cnd.where().andLike(CadreTrainingAct::getName, pageForm.getSearchKeyword()); } cnd.desc("info.applyTime"); - cnd.and("info.userId", "=", SecurityUtil.getUserId()); + // 本人报名和本人代他人报名的记录都应在“我的报名”中展示。 + cnd.and(Cnd.exps("info.userId", "=", SecurityUtil.getUserId()) + .or("info.applyUserId", "=", SecurityUtil.getUserId())); sql.setCondition(cnd); Pagination pagination = cadreTrainingSignUpService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); return Result.success(pagination); diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/cadreTraining/controller/CadreTrainingSignUpController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/cadreTraining/controller/CadreTrainingSignUpController.java index 7ae9d864..7ee056cb 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/cadreTraining/controller/CadreTrainingSignUpController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/cadreTraining/controller/CadreTrainingSignUpController.java @@ -68,7 +68,8 @@ public class CadreTrainingSignUpController { @ApiOperation("分页查询") public Result pageData(@Valid PageForm pageForm,Integer year, boolean isEnrolled) { Sql sql = Sqls.create(""" - SELECT + -- 同一活动存在多条代报名记录时,活动列表仅展示一次。 + SELECT DISTINCT info.*, CASE WHEN cts.id IS NOT NULL THEN 1 ELSE 0 END AS isEnrolled FROM @@ -101,6 +102,9 @@ public class CadreTrainingSignUpController { List instances = new ArrayList<>(); for (CadreTrainingSignUp signUp : cadreTrainingSignUps) { + // 代报名记录必须以当前登录人为报名操作人,供“已报名”和“我的报名”按操作人查询。 + signUp.setApplyUserId(SecurityUtil.getUserId()); + signUp.setApplyUserUserName(SecurityUtil.getUserUsername()); if (StrUtil.isBlank(signUp.getId())) { signUp.setApplyTime(new Date()); } diff --git a/src/main/resources/views/platform/zhgh/dayofficework/cadreTraining/signUp/signForm.js b/src/main/resources/views/platform/zhgh/dayofficework/cadreTraining/signUp/signForm.js index 2dd537a0..246a428a 100644 --- a/src/main/resources/views/platform/zhgh/dayofficework/cadreTraining/signUp/signForm.js +++ b/src/main/resources/views/platform/zhgh/dayofficework/cadreTraining/signUp/signForm.js @@ -65,7 +65,7 @@ const signForm = { @@ -74,7 +74,7 @@ const signForm = { 取消 确认报名 + :disabled="pendingTeamUsers.length === 0 ">确认报名 @@ -88,7 +88,7 @@ const signForm = { dialogVisible: false, viewData: {}, id: null, - //表格用户(实际上只包含当前用户) + // 表格同时展示已报名人员和本次新增人员 teamUsers: [], quota: 0, // 报名名额限制 signedUsers: [], // 已报名人员列表 @@ -97,6 +97,10 @@ const signForm = { } }, computed: { + // 仅未保存的人员需要参与本次提交和名额校验。 + pendingTeamUsers() { + return this.teamUsers.filter(user => !user.id) + }, remainingQuota() { // 如果 quota 为 null 或 undefined,显示"不限" if (this.quota == null || this.quota === 0) return "不限" @@ -143,7 +147,7 @@ const signForm = { this.$message.error("请勿重复添加") return } - if (this.quota > 0 && (this.signedUsers.length + this.teamUsers.length) >= this.quota) { + if (this.quota > 0 && (this.signedUsers.length + this.pendingTeamUsers.length) >= this.quota) { this.$message.error("已达到报名人数上限") return } @@ -164,28 +168,12 @@ const signForm = { if (signedResponse.code === 0) { this.signedUsers = Array.isArray(signedResponse.data) ? signedResponse.data : [] + // 已报名人员必须回显,避免分工会主席无法查看已代报记录。 + this.teamUsers = this.signedUsers.slice() + // 检查当前用户是否已报名 const currentUser = this.signedUsers.find(user => user.userId === this.$store.state.user.id) this.isSignUp = !!currentUser - - // 显示当前用户信息 - if (currentUser) { - this.teamUsers = this.signedUsers; - } else { - // 如果当前用户未报名,显示当前用户信息用于报名 - this.teamUsers = [{ - userId: this.$store.state.user.id, - userName: this.$store.state.user.username, - loginName: this.$store.state.user.loginname, - unitId: this.$store.state.user?.unit?.id, - unitName: this.$store.state.user?.unit?.name, - unionId: this.$store.state.user?.union?.id, - unionName: this.$store.state.user?.union?.name, - sex: this.$store.state.user.sex, - mobile: this.$store.state.user.mobile, - remark: '' - }] - } } } catch (error) { this.$message.error("获取用户数据失败") @@ -215,20 +203,14 @@ const signForm = { //提交报名 async onConfirm() { - // 检查是否已报名(仅当当前用户已报名时) - if (this.isSignUp && this.teamUsers.some(user => user.userId === this.$store.state.user.id)) { - this.$message.warning("您已报名该活动!") - return - } - - // 检查是否有报名人员 - if (this.teamUsers.length === 0) { + // 检查是否有新增报名人员 + if (this.pendingTeamUsers.length === 0) { this.$message.warning("请至少添加一名报名人员!") return } // 检查名额是否足够 - if (this.quota > 0 && (this.signedUsers.length + this.teamUsers.length) > this.quota) { + if (this.quota > 0 && (this.signedUsers.length + this.pendingTeamUsers.length) > this.quota) { // 添加空值检查 const remaining = this.quota ? this.quota - this.signedUsers.length : 0; this.$message.warning('报名人数超过限额!当前还可报名' + remaining + '人'); @@ -239,13 +221,13 @@ const signForm = { try { this.submitLoading = true; - this.$confirm('您确定要为' + this.teamUsers.length + '人报名吗?', "提示", { confirmButtonText: "确定", + this.$confirm('您确定要为' + this.pendingTeamUsers.length + '人报名吗?', "提示", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning" }).then(async () => { try { // 构造报名数据数组 - const signUpDataArray = this.teamUsers.map(user => { + const signUpDataArray = this.pendingTeamUsers.map(user => { return { cadreTrainingActId: this.id, userId: user.userId, From a359a01790372bf0379add088ca935ba20ee6586 Mon Sep 17 00:00:00 2001 From: zhouhefeng Date: Thu, 20 Aug 2026 08:35:36 +0800 Subject: [PATCH 2/3] commit --- .../senior/ProposalExpeditingController.java | 3 ++- .../transact/ProposalControlController.java | 3 ++- .../democratic/proposal/senior/basic/index.html | 6 +++--- .../democratic/proposal/senior/feedback/index.html | 6 +++--- .../democratic/proposal/senior/type/index.html | 6 +++--- .../proposal/transact/control/index.html | 14 ++++++++++---- 6 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalExpeditingController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalExpeditingController.java index c96630de..c0276759 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalExpeditingController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/senior/ProposalExpeditingController.java @@ -101,7 +101,8 @@ public class ProposalExpeditingController { $condition """); Cnd cnd = Cnd.NEW(); - cnd.and("t.taskName", "in", List.of("master_reply", "slave_reply", "opinion_master_reply")); + // 催办列表只展示现行 WF 承办答复环节中尚未完成的主办、二次答复及意见答复任务。 + cnd.and("t.taskName", "in", List.of("unit_reply", "two_unit_reply", "opinion_unit_reply")); if (!AuthUtil.hasRole(RoleConstant.SYSADMIN.name()) && !AuthUtil.hasRole(RoleConstant.SCHOOL_UNION_ADMIN.name())) { cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId())); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalControlController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalControlController.java index 9f77a5ec..ca93d97a 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalControlController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalControlController.java @@ -47,6 +47,7 @@ public class ProposalControlController { @SaCheckPermission("proposal.control") @ApiOperation("分页列表") public Result pageData(@Valid ProposalSearchParam pageForm) { + // 状态调整属于提案业务,只保留能够关联到 proposal_info 的 WF 任务,排除其他业务流程产生的空白行。 Sql sql = Sqls.create(""" SELECT info.*, @@ -72,7 +73,7 @@ public class ProposalControlController { LEFT JOIN wf_process_instance ins ON ins.id = t.processInstanceId LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id LEFT JOIN wf_process_task nt ON nt.processInstanceId = ins.id AND nt.taskState = 10 - LEFT JOIN proposal_info info ON info.id = ins.businessNo + INNER JOIN proposal_info info ON info.id = ins.businessNo LEFT JOIN proposal_type type ON type.id = info.typeId LEFT JOIN teacher_congress_session tcs ON tcs.id = info.sessionId LEFT JOIN teacher_congress_delegation tcd ON tcd.id = info.delegationId diff --git a/src/main/resources/views/platform/zhgh/democratic/proposal/senior/basic/index.html b/src/main/resources/views/platform/zhgh/democratic/proposal/senior/basic/index.html index 3494e878..0ab56f15 100644 --- a/src/main/resources/views/platform/zhgh/democratic/proposal/senior/basic/index.html +++ b/src/main/resources/views/platform/zhgh/democratic/proposal/senior/basic/index.html @@ -10,7 +10,7 @@ layout("/layouts/platform.html"){ + v-model="pageForm.searchSessionId"> @@ -277,7 +277,7 @@ layout("/layouts/platform.html"){ this.listDelegation() }, listDelegation() { - this.$axios.post("/platform/proposal/common/listDelegation", {sessionId: this.pageForm.sessionId}).then((res) => { + this.$axios.post("/platform/proposal/common/listDelegation", {sessionId: this.pageForm.searchSessionId}).then((res) => { if (res.code === 0) { this.delegationOptions = res.data } @@ -288,7 +288,7 @@ layout("/layouts/platform.html"){ if (res.code === 0) { this.sessionOptions = res.data if (this.sessionOptions) { - this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id) + this.$set(this.pageForm, "searchSessionId", this.sessionOptions[0].id) this.listDelegation() this.pageData() } diff --git a/src/main/resources/views/platform/zhgh/democratic/proposal/senior/feedback/index.html b/src/main/resources/views/platform/zhgh/democratic/proposal/senior/feedback/index.html index b0f429e1..e21d2b55 100644 --- a/src/main/resources/views/platform/zhgh/democratic/proposal/senior/feedback/index.html +++ b/src/main/resources/views/platform/zhgh/democratic/proposal/senior/feedback/index.html @@ -10,7 +10,7 @@ layout("/layouts/platform.html"){ + v-model="pageForm.searchSessionId"> @@ -207,7 +207,7 @@ layout("/layouts/platform.html"){ this.listDelegation() }, listDelegation() { - this.$axios.post("/platform/proposal/common/listDelegation", {sessionId: this.pageForm.sessionId}).then((res) => { + this.$axios.post("/platform/proposal/common/listDelegation", {sessionId: this.pageForm.searchSessionId}).then((res) => { if (res.code === 0) { this.delegationOptions = res.data } @@ -218,7 +218,7 @@ layout("/layouts/platform.html"){ if (res.code === 0) { this.sessionOptions = res.data if (this.sessionOptions) { - this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id) + this.$set(this.pageForm, "searchSessionId", this.sessionOptions[0].id) this.listDelegation() this.pageData() } diff --git a/src/main/resources/views/platform/zhgh/democratic/proposal/senior/type/index.html b/src/main/resources/views/platform/zhgh/democratic/proposal/senior/type/index.html index 9dc757f2..f0b24782 100644 --- a/src/main/resources/views/platform/zhgh/democratic/proposal/senior/type/index.html +++ b/src/main/resources/views/platform/zhgh/democratic/proposal/senior/type/index.html @@ -9,7 +9,7 @@ layout("/layouts/platform.html"){ - + @@ -181,7 +181,7 @@ layout("/layouts/platform.html"){ this.listDelegation() }, listDelegation() { - this.$axios.post("/platform/proposal/common/listDelegation", { sessionId: this.pageForm.sessionId }).then((res) => { + this.$axios.post("/platform/proposal/common/listDelegation", { sessionId: this.pageForm.searchSessionId }).then((res) => { if (res.code === 0) { this.delegationOptions = res.data } @@ -192,7 +192,7 @@ layout("/layouts/platform.html"){ if (res.code === 0) { this.sessionOptions = res.data if (this.sessionOptions) { - this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id) + this.$set(this.pageForm, "searchSessionId", this.sessionOptions[0].id) this.listDelegation() this.pageData() } diff --git a/src/main/resources/views/platform/zhgh/democratic/proposal/transact/control/index.html b/src/main/resources/views/platform/zhgh/democratic/proposal/transact/control/index.html index 4868b471..bda3ffa6 100644 --- a/src/main/resources/views/platform/zhgh/democratic/proposal/transact/control/index.html +++ b/src/main/resources/views/platform/zhgh/democratic/proposal/transact/control/index.html @@ -6,7 +6,7 @@ layout("/layouts/platform.html"){ - + @@ -85,6 +85,7 @@ layout("/layouts/platform.html"){ el: "#app", store, mixins: [initTableMixins], + components: { "proposal-info": PROPOSAL_INFO }, @@ -111,11 +112,12 @@ layout("/layouts/platform.html"){ jumpForm: { targetTaskName: "", tf_audit: true - } + }, + sessionOptions:[], } }, created() { - this.pageData() + // 默认届次确定后再加载表格,避免无届次请求覆盖已按届次筛选的结果。 this.listOpenSession() }, methods: { @@ -173,10 +175,14 @@ layout("/layouts/platform.html"){ listOpenSession() { this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => { if (res.code === 0) { - this.sessionOptions = res.data + this.sessionOptions = res.data || [] if (this.sessionOptions && this.sessionOptions.length) { this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id) this.pageData() + } else { + // 没有开启的教代会时保持空列表,避免发起无届次的全量流程查询。 + this.tableData = [] + this.$set(this.pageForm, "totalCount", 0) } } }) From 9d6e6eb189652c9e8eddcf91ef96e74d265bdcd3 Mon Sep 17 00:00:00 2001 From: = <=> Date: Thu, 20 Aug 2026 08:39:10 +0800 Subject: [PATCH 3/3] commit --- .../ClubSchoolAuditReportController.java | 148 +++++++++++++++++- .../controller/AssetManageController.java | 16 +- .../infoManage/schoolAuditReport/index.html | 4 + 3 files changed, 162 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/budwk/app/zhgh/club/controller/infoManage/ClubSchoolAuditReportController.java b/src/main/java/com/budwk/app/zhgh/club/controller/infoManage/ClubSchoolAuditReportController.java index e302329e..99110ba4 100644 --- a/src/main/java/com/budwk/app/zhgh/club/controller/infoManage/ClubSchoolAuditReportController.java +++ b/src/main/java/com/budwk/app/zhgh/club/controller/infoManage/ClubSchoolAuditReportController.java @@ -2,10 +2,14 @@ package com.budwk.app.zhgh.club.controller.infoManage; import cn.dev33.satoken.annotation.SaCheckPermission; import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.URLUtil; +import cn.hutool.json.JSONObject; import com.budwk.app.base.page.Pagination; import com.budwk.app.base.result.Result; import com.budwk.app.base.utils.PageUtil; import com.budwk.app.flow.enums.ProcessTaskStateEnum; +import com.budwk.app.sys.models.Sys_file; +import com.budwk.app.sys.utils.SysFileMinIoUtil; import com.budwk.app.web.commons.auth.utils.SecurityUtil; import com.budwk.app.zhgh.club.param.ClubUserPageForm; import com.budwk.app.zhgh.club.service.SysClubInfoManageService; @@ -14,12 +18,24 @@ import org.nutz.dao.Sqls; import org.nutz.dao.sql.Sql; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.json.Json; +import org.nutz.lang.util.NutMap; import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Param; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; /** * @Author: JyuHsin @@ -32,6 +48,8 @@ import java.util.List; @At("/platform/club/infoManage/schoolAuditReport") public class ClubSchoolAuditReportController { + private static final Logger log = LoggerFactory.getLogger(ClubSchoolAuditReportController.class); + @Inject private SysClubInfoManageService clubInfoManageService; @@ -44,6 +62,71 @@ public class ClubSchoolAuditReportController { @SaCheckPermission("club.infoManage.schoolAuditReport") public Result pageData(@Valid ClubUserPageForm pageForm, @Param(value = "approval") Boolean approval) { + Sql sql = buildPageDataSql(pageForm, approval); + Pagination pagination = clubInfoManageService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + return Result.success(pagination); + } + + /** + * 导出当前筛选范围内的换届报告附件压缩包。 + * + * @param pageForm 页面查询条件 + * @param approval 审核状态,与列表页保持一致 + * @param response HTTP 下载响应 + */ + @At + @Ok("void") + @SaCheckPermission("club.infoManage.schoolAuditReport") + public void exportRefreshReportZip(@Valid ClubUserPageForm pageForm, + @Param(value = "approval") Boolean approval, + HttpServletResponse response) throws IOException { + List reportList = clubInfoManageService.listMap(buildPageDataSql(pageForm, approval)); + response.setContentType("application/zip"); + response.setHeader("Content-Disposition", "attachment;filename=" + URLUtil.encode("换届报告.zip")); + + // 显式指定 UTF-8,确保压缩包内中文目录和文件名正常显示。 + try (ZipOutputStream zipOutputStream = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()), StandardCharsets.UTF_8)) { + Set entryNames = new HashSet<>(); + for (NutMap report : reportList) { + String filesJson = report.getString("files"); + if (StrUtil.isBlank(filesJson)) { + continue; + } + List files = Json.fromJsonAsList(JSONObject.class, filesJson); + String folderName = buildFolderName(report); + for (int index = 0; index < files.size(); index++) { + JSONObject fileInfo = files.get(index); + Sys_file sysFile = findSysFile(fileInfo); + if (sysFile == null) { + log.warn("换届报告附件不存在,报告ID:{},附件:{}", report.getString("id"), fileInfo); + continue; + } + byte[] fileBytes = SysFileMinIoUtil.getFileBytes(sysFile.getBucket(), sysFile.getStoragePath()); + if (fileBytes == null || fileBytes.length == 0) { + log.warn("换届报告附件内容为空,报告ID:{},附件ID:{}", report.getString("id"), sysFile.getId()); + continue; + } + String fileName = StrUtil.blankToDefault(fileInfo.getStr("name"), fileInfo.getStr("filename")); + if (StrUtil.isBlank(fileName)) { + fileName = sysFile.getName(); + } + String entryName = buildUniqueEntryName(folderName + "/" + sanitizeFileName(fileName), entryNames); + zipOutputStream.putNextEntry(new ZipEntry(entryName)); + zipOutputStream.write(fileBytes); + zipOutputStream.closeEntry(); + } + } + } + } + + /** + * 构建列表与导出共用的换届报告查询,确保“查什么导什么”。 + * + * @param pageForm 页面查询条件 + * @param approval 审核状态 + * @return 已绑定筛选条件的查询对象 + */ + private Sql buildPageDataSql(ClubUserPageForm pageForm, Boolean approval) { Sql sql = Sqls.create(""" SELECT info.*, @@ -79,7 +162,7 @@ public class ClubSchoolAuditReportController { cnd.and("t.taskName", "=", "d4323546-8d09-419e-88d4-7b15862ca29d"); cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId())); - if (approval) { + if (Boolean.TRUE.equals(approval)) { cnd.and("t.taskState", "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.INTERRUPT.getCode())); } else { cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode()); @@ -96,8 +179,67 @@ public class ClubSchoolAuditReportController { cnd.groupBy("t.id"); sql.setCondition(cnd); + return sql; + } - Pagination pagination = clubInfoManageService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); - return Result.success(pagination); + /** + * 兼容新旧附件 JSON 结构,按附件 ID 或下载地址查找文件元数据。 + * + * @param fileInfo 附件 JSON 信息 + * @return 系统文件记录;未找到时返回 null + */ + private Sys_file findSysFile(JSONObject fileInfo) { + String fileId = fileInfo.getStr("id"); + if (StrUtil.isNotBlank(fileId)) { + return clubInfoManageService.dao().fetch(Sys_file.class, fileId); + } + String fileUrl = fileInfo.getStr("url"); + if (StrUtil.isBlank(fileUrl)) { + return null; + } + return clubInfoManageService.dao().fetch(Sys_file.class, Cnd.where(Sys_file::getDownloadPath, "=", fileUrl)); + } + + /** + * 使用社团名称建立目录,方便按换届报告来源查阅。 + * + * @param report 换届报告记录 + * @return Zip 内目录名称 + */ + private String buildFolderName(NutMap report) { + return sanitizeFileName(report.getString("clubName")); + } + + /** + * 保留附件原始文件名;同一社团目录存在同名文件时追加序号,避免覆盖。 + * + * @param entryName 原始 Zip 条目名称 + * @param entryNames 已写入的 Zip 条目名称 + * @return 唯一的 Zip 条目名称 + */ + private String buildUniqueEntryName(String entryName, Set entryNames) { + if (entryNames.add(entryName)) { + return entryName; + } + int extensionIndex = entryName.lastIndexOf('.'); + String name = extensionIndex > entryName.lastIndexOf('/') ? entryName.substring(0, extensionIndex) : entryName; + String extension = extensionIndex > entryName.lastIndexOf('/') ? entryName.substring(extensionIndex) : ""; + int index = 2; + String uniqueEntryName; + do { + uniqueEntryName = name + "(" + index + ")" + extension; + index++; + } while (!entryNames.add(uniqueEntryName)); + return uniqueEntryName; + } + + /** + * 去除 Zip 条目路径分隔符,避免附件名影响压缩包目录结构。 + * + * @param fileName 原始文件名 + * @return 可安全写入 Zip 的文件名 + */ + private String sanitizeFileName(String fileName) { + return StrUtil.blankToDefault(fileName, "未命名文件").replace("/", "_").replace("\\", "_"); } } diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/asset/controller/AssetManageController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/asset/controller/AssetManageController.java index 3d768e1c..6aa6a0c9 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/asset/controller/AssetManageController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/asset/controller/AssetManageController.java @@ -9,9 +9,11 @@ import cn.dev33.satoken.annotation.SaMode; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.budwk.app.base.annotation.SLog; +import com.budwk.app.base.constant.RoleConstant; import com.budwk.app.base.page.Pagination; import com.budwk.app.base.result.Result; import com.budwk.app.base.utils.CommonDownloadUtil; +import com.budwk.app.web.commons.auth.utils.AuthUtil; import com.budwk.app.web.commons.auth.utils.SecurityUtil; import com.budwk.app.zhgh.dayofficework.asset.model.Asset; import com.budwk.app.zhgh.dayofficework.asset.model.AssetDepreciationRecord; @@ -27,6 +29,7 @@ import org.nutz.aop.interceptor.ioc.TransAop; import org.nutz.dao.Cnd; import org.nutz.dao.Sqls; import org.nutz.dao.sql.Sql; +import org.nutz.dao.util.cri.SqlExpressionGroup; import org.nutz.ioc.aop.Aop; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; @@ -157,9 +160,16 @@ public class AssetManageController { @SaCheckPermission(value = {"asset.manage", "asset.stocktaking", "h5.asset.stocktaking"}, mode = SaMode.OR) public Result searchAssetUseUser(String query) { Cnd cnd = Cnd.NEW(); - cnd.where().orLike("username", query); - cnd.where().orLike("loginname", query); - cnd.where().orLike("id", query); + // 三个关键词条件必须整体分组,避免 OR 条件绕过分工会数据范围。 + SqlExpressionGroup searchGroup = new SqlExpressionGroup(); + searchGroup.orLike("username", query); + searchGroup.orLike("loginname", query); + searchGroup.orLike("id", query); + cnd.and(searchGroup); + // 分工会侧盘点人员只能选择本分工会成员,校工会和系统管理员保留全校查询范围。 + if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) { + cnd.and("unionId", "=", SecurityUtil.getUnionId()); + } Sql sql = Sqls.create(""" SELECT id, diff --git a/src/main/resources/views/platform/zhgh/club/infoManage/schoolAuditReport/index.html b/src/main/resources/views/platform/zhgh/club/infoManage/schoolAuditReport/index.html index 3bbe6171..17ffcfd2 100644 --- a/src/main/resources/views/platform/zhgh/club/infoManage/schoolAuditReport/index.html +++ b/src/main/resources/views/platform/zhgh/club/infoManage/schoolAuditReport/index.html @@ -32,6 +32,7 @@ layout("/layouts/platform.html"){ + 导出换届报告Zip 已审核 未审核 @@ -158,6 +159,9 @@ layout("/layouts/platform.html"){ }) }) }, + exportRefreshReportZip() { + this.$downLoad("/platform/club/infoManage/schoolAuditReport/exportRefreshReportZip", this.pageForm) + }, async pageData() { const resp = await this.$axios.post("/platform/club/infoManage/schoolAuditReport/pageData", this.pageForm) if (resp.code === 0) {