From 67bf620d011e17abc2a5743300ff8aaf43470f47 Mon Sep 17 00:00:00 2001 From: zhangrui Date: Thu, 11 Jun 2026 17:26:11 +0800 Subject: [PATCH] 1 --- .../tour/controller/TourLedgerController.java | 47 ++++++- .../RecuperationLineController.java | 5 +- .../service/RecuperationLineService.java | 7 + .../impl/RecuperationLineServiceImpl.java | 14 ++ .../Tour/branchUserAssignment/index.html | 5 +- .../zhgh/dayofficework/Tour/ledger/index.html | 21 ++- .../Tour/schoolUserAssignment/index.html | 5 +- .../recuperation/line/basicForm.js | 20 ++- src/test/java/com/budwk/app/FlowTest.java | 122 +++++++++++++++++- 9 files changed, 227 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourLedgerController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourLedgerController.java index 4a6206c5..35b2252b 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourLedgerController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/tour/controller/TourLedgerController.java @@ -9,6 +9,7 @@ import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity; import cn.dev33.satoken.annotation.SaCheckPermission; 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.model.ExcelImportRes; import com.budwk.app.base.page.Pagination; import com.budwk.app.base.param.PageForm; @@ -17,6 +18,8 @@ import com.budwk.app.base.utils.CommonDownloadUtil; import com.budwk.app.flow.enums.ProcessInstanceStateEnum; import com.budwk.app.sys.models.Sys_union; import com.budwk.app.sys.views.View_user; +import com.budwk.app.web.commons.auth.utils.AuthUtil; +import com.budwk.app.web.commons.auth.utils.SecurityUtil; import com.budwk.app.zhgh.dayofficework.tour.mode.TourLedgerImportExcelMode; import com.budwk.app.zhgh.dayofficework.tour.models.TourLedger; import com.budwk.app.zhgh.dayofficework.tour.models.TourLedgerDirectRelative; @@ -196,6 +199,9 @@ public class TourLedgerController { if (ledger == null) { return Result.error("台账记录不存在"); } + if (!canAccessLedgerUnion(ledger.getUnionId())) { + return Result.error("无权查看该台账记录"); + } ledger.setLineName(getCurrentLineName(ledger)); Cnd familyCnd = Cnd.NEW(); familyCnd.and(TourLedgerFamily::getLedgerId, "=", id); @@ -225,6 +231,9 @@ public class TourLedgerController { if (ledger == null) { return Result.error("台账记录不存在"); } + if (!canAccessLedgerUnion(ledger.getUnionId())) { + return Result.error("无权删除该台账记录"); + } tourLedgerFamilyService.clear(Cnd.where(TourLedgerFamily::getLedgerId, "=", id)); tourLedgerService.delete(id); return Result.success(); @@ -239,7 +248,9 @@ public class TourLedgerController { if (idList.isEmpty()) { return Result.error("请选择要设置的参加人员"); } - tourLedgerService.dao().update(TourLedger.class, Chain.make("joined", true), Cnd.where("id", "in", idList)); + Cnd cnd = Cnd.where("id", "in", idList); + cnd.andEX("unionId", "=", resolveLedgerUnionId(null)); + tourLedgerService.dao().update(TourLedger.class, Chain.make("joined", true), cnd); return Result.success(); } @@ -811,6 +822,9 @@ public class TourLedgerController { @SaCheckPermission("tour.ledger") public Result unionOptions() { Cnd cnd = Cnd.NEW(); + if (isBranchUnionChairmanScope()) { + cnd.and("id", "=", SecurityUtil.getUnionId()); + } cnd.asc("unionCode"); cnd.asc("name"); return Result.success(tourLedgerService.dao().query(Sys_union.class, cnd)); @@ -825,7 +839,7 @@ public class TourLedgerController { cnd.andEX("t.`year`", "<=", endYear == null ? LocalDate.now().getYear() : endYear); cnd.and("t.lineName", "IS NOT", null); cnd.and("t.lineName", "<>", ""); - cnd.andEX("t.unionId", "=", unionId); + cnd.andEX("t.unionId", "=", resolveLedgerUnionId(unionId)); cnd.andEX("t.lineType", "=", lineType); appendTravelPeriodFilter(cnd, travelPeriod); appendKeywordFilter(cnd, keyword); @@ -864,7 +878,7 @@ public class TourLedgerController { cnd.and("m.travelStartTime", "<>", ""); cnd.and("m.travelEndTime", "IS NOT", null); cnd.and("m.travelEndTime", "<>", ""); - cnd.andEX("t.unionId", "=", unionId); + cnd.andEX("t.unionId", "=", resolveLedgerUnionId(unionId)); cnd.andEX("t.lineType", "=", lineType); appendLineFilter(cnd, lineId); appendKeywordFilter(cnd, keyword); @@ -892,7 +906,7 @@ public class TourLedgerController { cnd.and("t.delFlag", "=", false); cnd.andEX("t.`year`", ">=", startYear); cnd.andEX("t.`year`", "<=", endYear == null ? LocalDate.now().getYear() : endYear); - cnd.andEX("t.unionId", "=", unionId); + cnd.andEX("t.unionId", "=", resolveLedgerUnionId(unionId)); cnd.andEX("t.lineType", "=", lineType); appendLineFilter(cnd, lineId); appendTravelPeriodFilter(cnd, travelPeriod); @@ -902,6 +916,31 @@ public class TourLedgerController { return cnd; } + private boolean hasSchoolLedgerScope() { + return AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name()); + } + + private boolean isBranchUnionChairmanScope() { + return !hasSchoolLedgerScope() && AuthUtil.hasRole(RoleConstant.BRANCH_UNION_CHAIRMAN.name()); + } + + private String resolveLedgerUnionId(String unionId) { + // 分工会主席只能查询当前登录人所在分工会;校工会管理员保留页面传入条件,支持查全部。 + if (isBranchUnionChairmanScope()) { + String currentUnionId = SecurityUtil.getUnionId(); + return StrUtil.isBlank(currentUnionId) ? "__NO_UNION__" : currentUnionId; + } + return unionId; + } + + private boolean canAccessLedgerUnion(String unionId) { + if (!isBranchUnionChairmanScope()) { + return true; + } + String currentUnionId = SecurityUtil.getUnionId(); + return StrUtil.isNotBlank(currentUnionId) && StrUtil.equals(currentUnionId, unionId); + } + private void appendApprovedWorkflowFilter(Cnd cnd) { SqlExpressionGroup group = new SqlExpressionGroup(); group.or("ins.id", "IS", null); diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/controller/RecuperationLineController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/controller/RecuperationLineController.java index f84fa769..83418d92 100644 --- a/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/controller/RecuperationLineController.java +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/controller/RecuperationLineController.java @@ -49,7 +49,6 @@ import javax.servlet.http.HttpServletResponse; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.stream.Collectors; /** @@ -110,9 +109,7 @@ public class RecuperationLineController { @ApiOperation("获取编号") @SaCheckPermission("recuperation.line") public Result getNo() { - Object serialNumber = dao.func2(RecuperationLine.class, "max", "serialNumber"); - serialNumber = Objects.requireNonNullElse(serialNumber, 0); - return Result.success(Integer.parseInt(serialNumber.toString()) + 1); + return Result.success(lineService.generateNextSerialNumber()); } @At diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/RecuperationLineService.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/RecuperationLineService.java index 41eb6a7b..40ab98e5 100644 --- a/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/RecuperationLineService.java +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/RecuperationLineService.java @@ -39,6 +39,13 @@ public interface RecuperationLineService extends BaseService { */ void editLine(RecuperationLine line); + /** + * 生成新增线路默认编码,按现有纯数字线路编码最大值自增。 + * + * @return 新线路默认编码 + */ + String generateNextSerialNumber(); + /** * 开启或关闭线路 * diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/impl/RecuperationLineServiceImpl.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/impl/RecuperationLineServiceImpl.java index ead2faef..eff4b9e6 100644 --- a/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/impl/RecuperationLineServiceImpl.java +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/recuperation/service/impl/RecuperationLineServiceImpl.java @@ -81,6 +81,20 @@ public class RecuperationLineServiceImpl extends BaseServiceImpl {}) }, + // 分配路线选项展示线路管理中的线路类型,便于同名线路按类型区分。 matterOptionLabel(item) { const lineName = item.lineName || "" - return lineName || item.matterName || "" + const lineType = item.lineType || "" + const label = lineName || item.matterName || "" + return label && lineType ? label + "(" + lineType + ")" : label } }, mounted() { diff --git a/src/main/resources/views/platform/zhgh/dayofficework/Tour/ledger/index.html b/src/main/resources/views/platform/zhgh/dayofficework/Tour/ledger/index.html index befa4454..b589eb66 100644 --- a/src/main/resources/views/platform/zhgh/dayofficework/Tour/ledger/index.html +++ b/src/main/resources/views/platform/zhgh/dayofficework/Tour/ledger/index.html @@ -33,7 +33,7 @@ layout("/layouts/platform.html"){ @keyup.enter.native="doSearch"> - + @@ -367,6 +367,7 @@ layout("/layouts/platform.html"){ showImportDialog: false, multipleSelection: [], filterOptionsTimer: null, + currentUnionId: "", pageForm: { pageNumber: 1, pageSize: 10, @@ -398,6 +399,17 @@ layout("/layouts/platform.html"){ handleSelectionChange(val) { this.multipleSelection = val || [] }, + canSelectUnion() { + return this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"]) + }, + isBranchUnionChairmanOnly() { + return !this.canSelectUnion() && this.$auth.hasRole("BRANCH_UNION_CHAIRMAN") + }, + applyUnionScope() { + if (this.isBranchUnionChairmanOnly() && this.currentUnionId) { + this.pageForm.unionId = this.currentUnionId + } + }, clearTableSelection() { this.multipleSelection = [] if (this.$refs.tableRef) { @@ -501,7 +513,7 @@ layout("/layouts/platform.html"){ this.pageForm.startYear = moment().format("YYYY") this.pageForm.endYear = moment().format("YYYY") this.pageForm.keyword = "" - this.pageForm.unionId = "" + this.pageForm.unionId = this.isBranchUnionChairmanOnly() ? this.currentUnionId : "" this.pageForm.lineId = "" this.pageForm.travelPeriod = "" this.pageForm.lineType = "" @@ -556,6 +568,10 @@ layout("/layouts/platform.html"){ this.$axios.post(loc() + "/unionOptions").then((res) => { if (res.code === 0) { this.unionOptions = res.data || [] + if (this.isBranchUnionChairmanOnly()) { + this.currentUnionId = this.unionOptions.length ? this.unionOptions[0].id : "" + this.applyUnionScope() + } } }) }, @@ -611,6 +627,7 @@ layout("/layouts/platform.html"){ }) }, doSearch() { + this.applyUnionScope() this.tableKey = new Date().getTime() this.pageForm.pageNumber = 1 this.clearTableSelection() diff --git a/src/main/resources/views/platform/zhgh/dayofficework/Tour/schoolUserAssignment/index.html b/src/main/resources/views/platform/zhgh/dayofficework/Tour/schoolUserAssignment/index.html index e3c7b411..c4d2ddaf 100644 --- a/src/main/resources/views/platform/zhgh/dayofficework/Tour/schoolUserAssignment/index.html +++ b/src/main/resources/views/platform/zhgh/dayofficework/Tour/schoolUserAssignment/index.html @@ -686,9 +686,12 @@ layout("/layouts/platform.html"){ }) }).catch(() => {}) }, + // 分配线路选项展示线路管理中的线路类型,便于同名线路按类型区分。 matterOptionLabel(item) { const lineName = item.lineName || "" - return lineName || item.matterName || "" + const lineType = item.lineType || "" + const label = lineName || item.matterName || "" + return label && lineType ? label + "(" + lineType + ")" : label } }, mounted() { diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/recuperation/line/basicForm.js b/src/main/resources/views/platform/zhgh/staffbenefit/recuperation/line/basicForm.js index b9a3425c..77593d40 100644 --- a/src/main/resources/views/platform/zhgh/staffbenefit/recuperation/line/basicForm.js +++ b/src/main/resources/views/platform/zhgh/staffbenefit/recuperation/line/basicForm.js @@ -29,8 +29,8 @@ const basicForm = { - - + + @@ -240,7 +240,7 @@ const basicForm = { isDisabled: true }, formRules: { - serialNumber: [{required: true, message: '请输入排序号', trigger: ['change', 'blur']}], + serialNumber: [{required: true, message: '请输入线路编码', trigger: ['change', 'blur']}], lineName: [{required: true, message: '请输入线路名称', trigger: ['change', 'blur']}], travelAgencyId: [{required: true, message: '请选择旅行社', trigger: ['change', 'blur']}], regionalNature: [{required: true, message: '请选择区域性质', trigger: ['change', 'blur']}], @@ -297,6 +297,9 @@ const basicForm = { this.formData = {...data} }) } else { + this.formData = { + isDisabled: true + } await this.getNumber() const createMode = await this.getCreateMode() this.$set(this.formData, 'createMode', createMode) @@ -333,8 +336,15 @@ const basicForm = { return resp.data }, async getNumber() { - const resp = await this.$axios.post(loc() + '/getNo') - this.$set(this.formData, 'serialNumber', resp.data) + return this.$axios.post(loc() + '/getNo').then((resp) => { + if (resp.code === 0) { + this.$set(this.formData, 'serialNumber', resp.data) + } else { + this.$message.warning(resp.msg || '线路编码生成失败') + } + }).catch(() => { + this.$message.warning('线路编码生成失败') + }) }, }, async created() { diff --git a/src/test/java/com/budwk/app/FlowTest.java b/src/test/java/com/budwk/app/FlowTest.java index 264f60c7..76f371c0 100644 --- a/src/test/java/com/budwk/app/FlowTest.java +++ b/src/test/java/com/budwk/app/FlowTest.java @@ -1,21 +1,39 @@ package com.budwk.app; +import cn.afterturn.easypoi.excel.ExcelImportUtil; +import cn.afterturn.easypoi.excel.annotation.Excel; +import cn.afterturn.easypoi.excel.entity.ImportParams; +import cn.hutool.core.date.DateUtil; import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.StrUtil; +import com.budwk.app.base.constant.RoleConstant; +import com.budwk.app.base.sms.SmsService; import com.budwk.app.flow.constant.FlowConst; import com.budwk.app.flow.engine.FlowEngine; import com.budwk.app.flow.engine.model.*; import com.budwk.app.flow.entity.ProcessTask; import com.budwk.app.flow.enums.ProcessSubmitTypeEnum; +import com.budwk.app.sys.models.Sys_role; +import com.budwk.app.sys.models.Sys_user; +import com.budwk.app.sys.models.Sys_user_role; +import com.budwk.app.sys.services.SysRoleService; +import lombok.Data; import org.junit.Test; import org.junit.runner.RunWith; import org.nutz.aop.interceptor.ioc.TransAop; import org.nutz.boot.test.junit4.NbJUnit4Runner; +import org.nutz.dao.Chain; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; import org.nutz.ioc.aop.Aop; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Lang; -import java.util.List; -import java.util.Set; +import java.io.File; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; @IocBean @RunWith(NbJUnit4Runner.class) @@ -23,6 +41,12 @@ public class FlowTest { @Inject private FlowEngine flowEngine; + @Inject + private Dao dao; + @Inject + private SmsService smsService; + @Inject + private SysRoleService sysRoleService; @Test @Aop(TransAop.READ_COMMITTED) @@ -91,4 +115,98 @@ public class FlowTest { } + @Test + public void importZJIPCMemberRoster() { + File dir = new File("C:\\Users\\mayn\\Desktop\\客户\\浙江工业职业学院\\基础数据\\浙江工业职业技术学院最新会员名册"); + File[] files = dir.listFiles((file, name) -> name.endsWith(".xls") || name.endsWith(".xlsx")); + if (files == null || files.length == 0) { + System.out.println("未找到会员名单 Excel 文件"); + return; + } + Arrays.sort(files, Comparator.comparing(File::getName)); + + ImportParams importParams = new ImportParams(); + importParams.setTitleRows(1); + importParams.setHeadRows(1); + + List importList = new ArrayList<>(); + for (File file : files) { + List rows = ExcelImportUtil.importExcel(file, MemberRosterImportTemp.class, importParams); + importList.addAll(rows.stream() + .filter(row -> StrUtil.isNotBlank(row.getLoginName())) + .toList()); + } + List loginNames = importList.stream() + .map(MemberRosterImportTemp::getLoginName) + .map(String::trim) + .distinct() + .toList(); + if (Lang.isEmpty(loginNames)) { + System.out.println("Excel 中未读取到有效教工号"); + return; + } + + Sys_role memberRole = sysRoleService.getByCode(RoleConstant.MEMBER); + if (memberRole == null) { + System.out.println("会员角色不存在"); + return; + } + + List users = dao.query(Sys_user.class, Cnd.where(Sys_user::getLoginname, "in", loginNames)); + Map userMap = users.stream().collect(Collectors.toMap(Sys_user::getLoginname, Function.identity(), (a, b) -> a)); + List missingLoginNames = loginNames.stream() + .filter(loginName -> !userMap.containsKey(loginName)) + .toList(); + if (Lang.isNotEmpty(missingLoginNames)) { + System.out.println("系统中未匹配到的教工号:" + missingLoginNames); + } + + List userIds = users.stream().map(Sys_user::getId).distinct().toList(); + if (Lang.isEmpty(userIds)) { + System.out.println("没有可导入为会员的用户"); + return; + } + + // 模仿 /platform/member/info/batchMake/batchMake:设置会员状态和入会时间。 + dao.update(Sys_user.class, Chain.make("member", true) + .add("memberTime", DateUtil.now()), + Cnd.where(Sys_user::getId, "in", userIds)); + + List existingRoles = dao.query(Sys_user_role.class, Cnd.where(Sys_user_role::getUserId, "in", userIds) + .and(Sys_user_role::getRoleId, "=", memberRole.getId())); + Set hasRoleUserIds = existingRoles.stream().map(Sys_user_role::getUserId).collect(Collectors.toSet()); + List roleList = userIds.stream() + .filter(userId -> !hasRoleUserIds.contains(userId)) + .map(userId -> { + Sys_user_role userRole = new Sys_user_role(); + userRole.setUserId(userId); + userRole.setRoleId(memberRole.getId()); + return userRole; + }) + .toList(); + if (Lang.isNotEmpty(roleList)) { + dao.insert(roleList); + } + + System.out.println("Excel 读取人数:" + importList.size()); + System.out.println("有效教工号数:" + loginNames.size()); + System.out.println("匹配并设置会员人数:" + userIds.size()); + System.out.println("新增会员角色人数:" + roleList.size()); + } + + @Data + public static class MemberRosterImportTemp { + @Excel(name = "姓名") + private String userName; + + @Excel(name = "部门") + private String unitName; + + @Excel(name = "教工号") + private String loginName; + + @Excel(name = "联系电话") + private String mobile; + } + }