From 48892370c0ff648bafd0c40b68b4f7250e876db3 Mon Sep 17 00:00:00 2001 From: zhouhefeng Date: Mon, 27 Apr 2026 08:42:06 +0800 Subject: [PATCH] Changes --- .../flow/controller/FlowDesignController.java | 47 +- .../budwk/app/flow/entity/ProcessDesign.java | 5 + .../sys/controller/SysDataToolController.java | 451 +++++++++ .../app/sys/enums/SysDataImportPlugin.java | 123 +++ .../ActivityBasicScopeController.java | 63 +- .../basic/models/ActivityUserScope.java | 3 +- .../param/ActivityUserScopePageParam.java | 1 + .../module/activity/UserDataScope.vue | 6 +- .../components/module/activity/UserScope.vue | 876 +++++++++--------- .../views/platform/flow/design/index.html | 31 +- .../views/platform/sys/data/tool/index.html | 524 +++++++++++ .../views/platform/sys/menu/index.html | 33 + .../sys/union/branchUnionUserManage.js | 158 +++- .../trainSignUp/annualLimit/index.html | 32 +- 14 files changed, 1890 insertions(+), 463 deletions(-) create mode 100644 src/main/java/com/budwk/app/sys/controller/SysDataToolController.java create mode 100644 src/main/java/com/budwk/app/sys/enums/SysDataImportPlugin.java create mode 100644 src/main/resources/views/platform/sys/data/tool/index.html diff --git a/src/main/java/com/budwk/app/flow/controller/FlowDesignController.java b/src/main/java/com/budwk/app/flow/controller/FlowDesignController.java index d0814f1f..8af02627 100644 --- a/src/main/java/com/budwk/app/flow/controller/FlowDesignController.java +++ b/src/main/java/com/budwk/app/flow/controller/FlowDesignController.java @@ -18,6 +18,7 @@ import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.nutz.aop.interceptor.ioc.TransAop; +import org.nutz.dao.Chain; import org.nutz.dao.Cnd; import org.nutz.dao.Dao; import org.nutz.dao.Sqls; @@ -110,14 +111,39 @@ public class FlowDesignController { @ApiOperation("获取流程设计分页列表") @SaCheckPermission("flow.design") public Result pageData(PageForm pageForm, String displayName, String name, String category, Boolean deployed) { + Sql sql = Sqls.create(""" + SELECT + pd.* + FROM + wf_process_design pd + LEFT JOIN wf_process_category pc ON pc.id = pd.category + $condition + """); Cnd cnd = Cnd.NEW(); - cnd.and(Cnd.likeEX(ProcessDesign::getDisplayName, displayName)); - cnd.and(Cnd.likeEX(ProcessDesign::getName, name)); - cnd.andEX(ProcessDesign::getCategory, "=", category); - cnd.andEX(ProcessDesign::getIsDeployed, "=", deployed); + cnd.and(Cnd.likeEX("pd.displayName", displayName)); + cnd.and(Cnd.likeEX("pd.name", name)); + cnd.andEX("pd.category", "=", category); + cnd.andEX("pd.isDeployed", "=", deployed); + if ("sortNo".equals(pageForm.getPageOrderName())) { + if ("descending".equals(pageForm.getPageOrderBy())) { + cnd.desc("pd.sortNo"); + } else { + cnd.asc("pd.sortNo"); + } + } else if ("category".equals(pageForm.getPageOrderName())) { + if ("descending".equals(pageForm.getPageOrderBy())) { + cnd.desc("pc.name"); + } else { + cnd.asc("pc.name"); + } + } else { + cnd.asc("pd.sortNo"); + } + cnd.asc("pd.id"); - Pagination pagination = processDesignService.listPage(pageForm.getPageNumber(), pageForm.getPageSize(), cnd); + sql.setCondition(cnd); + Pagination pagination = processDesignService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); return Result.success(pagination); } @@ -206,6 +232,17 @@ public class FlowDesignController { return Result.success(); } + @At + @ApiOperation("修改流程设计排序编码") + @SaCheckPermission("flow.design") + public Result updateSortNo(@Param("id") Long id, @Param("sortNo") Integer sortNo) { + if (id == null || sortNo == null || sortNo < 0) { + return Result.error("排序编码必须是非负整数"); + } + processDesignService.update(Chain.make("sortNo", sortNo), Cnd.where(ProcessDesign::getId, "=", id)); + return Result.success(); + } + @At @SaCheckLogin @ApiOperation("获取流程设计任务参与者处理类") diff --git a/src/main/java/com/budwk/app/flow/entity/ProcessDesign.java b/src/main/java/com/budwk/app/flow/entity/ProcessDesign.java index 065c04b2..1b63eb68 100644 --- a/src/main/java/com/budwk/app/flow/entity/ProcessDesign.java +++ b/src/main/java/com/budwk/app/flow/entity/ProcessDesign.java @@ -68,6 +68,11 @@ public class ProcessDesign extends BaseModel { @Column private Integer isDeployed; + @Comment("排序编码") + @Column + @Default("0") + private Integer sortNo; + @Comment("备注") @Column private String remark; diff --git a/src/main/java/com/budwk/app/sys/controller/SysDataToolController.java b/src/main/java/com/budwk/app/sys/controller/SysDataToolController.java new file mode 100644 index 00000000..3e9fa87c --- /dev/null +++ b/src/main/java/com/budwk/app/sys/controller/SysDataToolController.java @@ -0,0 +1,451 @@ +package com.budwk.app.sys.controller; + +import cn.afterturn.easypoi.excel.ExcelExportUtil; +import cn.afterturn.easypoi.excel.annotation.Excel; +import cn.afterturn.easypoi.excel.entity.ExportParams; +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.util.StrUtil; +import com.budwk.app.base.annotation.SLog; +import com.budwk.app.base.result.Result; +import com.budwk.app.base.utils.CommonDownloadUtil; +import com.budwk.app.sys.enums.SysDataImportPlugin; +import com.budwk.app.sys.services.SysRoleService; +import com.budwk.app.sys.services.SysUserService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.DateUtil; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.WorkbookFactory; +import org.nutz.dao.Chain; +import org.nutz.dao.Cnd; +import org.nutz.dao.Sqls; +import org.nutz.dao.entity.Record; +import org.nutz.dao.sql.Sql; +import org.nutz.integration.jedis.RedisService; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.json.Json; +import org.nutz.lang.random.R; +import org.nutz.lang.util.NutMap; +import org.nutz.mvc.annotation.AdaptBy; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; +import org.nutz.mvc.annotation.Param; +import org.nutz.mvc.upload.TempFile; +import org.nutz.mvc.upload.UploadAdaptor; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +@Slf4j +@IocBean +@Ok("json:full") +@At("/platform/sys/data/tool") +@Api("系统数据高级工具") +public class SysDataToolController { + + private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + @Inject + private SysUserService sysUserService; + @Inject + private SysRoleService sysRoleService; + @Inject + private RedisService redisService; + + @At("") + @Ok("beetl:/platform/sys/data/tool/index.html") + @SaCheckPermission("sys.data.advanced.tool") + public void index() { + } + + @At + @ApiOperation("查询数据库中的表") + @SaCheckPermission("sys.data.advanced.tool") + public Result tableNames() { + Sql sql = Sqls.create(""" + SELECT + table_name, + table_rows, + table_comment + FROM + information_schema.TABLES + WHERE + table_schema = (SELECT DATABASE()) + ORDER BY + table_name + """); + return Result.success(sysUserService.listMap(sql)); + } + + @At + @ApiOperation("查询数据表字段") + @SaCheckPermission("sys.data.advanced.tool") + public Result columns(String tableName) { + if (StrUtil.isBlank(tableName)) { + return Result.error("请选择数据表"); + } + return Result.success(getColumns(tableName)); + } + + @At + @ApiOperation("执行高级导入") + @SLog(tag = "数据管理-高级工具", msg = "执行高级导入") + @SaCheckPermission("sys.data.advanced.tool") + @AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"}) + public Result importData(@Param("file") TempFile file, + String tableName, + String relation, + Integer method, + String field, + String plugins) throws IOException { + if (file == null) { + return Result.error("请上传 Excel 文件"); + } + if (StrUtil.isBlank(tableName)) { + return Result.error("请选择数据表"); + } + if (method == null) { + return Result.error("请选择导入方式"); + } + if ((method == 1 || method == 3) && StrUtil.isBlank(field)) { + return Result.error("请选择关键字段"); + } + if (StrUtil.isBlank(relation)) { + return Result.error("请配置字段对应关系"); + } + + List columns = getColumns(tableName); + if (columns.isEmpty()) { + return Result.error("未获取到数据表字段"); + } + + NutMap[] relations = parseRelations(relation); + List dataList = getDataForExcel(file, relations); + List pluginList = parsePlugins(plugins); + pluginList.sort(Comparator.comparingInt(SysDataImportPlugin::getLocation)); + Record pkRecord = getPrimaryKey(columns).orElse(null); + Set tableColumns = new HashSet<>(); + columns.forEach(column -> tableColumns.add(column.getString("column_name"))); + + int total = 0; + int success = 0; + List errors = new ArrayList<>(); + + for (NutMap row : dataList) { + total++; + try { + if (StrUtil.isNotBlank(field)) { + row.setv(field, row.getString(field)); + } + + Chain chain = buildChain(row, tableColumns); + if (chain == null) { + continue; + } + + Object pk; + if (method == 1) { + Record currentRecord = sysUserService.dao().fetch(tableName, Cnd.where(field, "=", row.get(field))); + if (currentRecord == null) { + pk = prepareBefore(tableName, pkRecord, field, pluginList, true, chain, row, tableColumns); + sysUserService.dao().insert(tableName, chain); + } else { + pk = prepareBefore(tableName, pkRecord, field, pluginList, false, chain, row, tableColumns); + sysUserService.dao().update(tableName, chain, Cnd.where(field, "=", row.get(field))); + } + } else if (method == 2) { + pk = prepareBefore(tableName, pkRecord, field, pluginList, true, chain, row, tableColumns); + sysUserService.dao().insert(tableName, chain); + } else if (method == 3) { + pk = prepareBefore(tableName, pkRecord, field, pluginList, false, chain, row, tableColumns); + sysUserService.dao().update(tableName, chain, Cnd.where(field, "=", row.get(field))); + } else { + throw new IllegalArgumentException("导入方式不正确"); + } + + applyAfterPlugins(tableName, tableColumns, chain, pk, pluginList); + success++; + } catch (Exception e) { + log.error("高级导入失败, table={}, row={}", tableName, row, e); + errors.add(new ImportError(Json.toJson(row), e.getMessage())); + } + } + + String cacheKey = ""; + if (!errors.isEmpty()) { + cacheKey = R.UU32(); + redisService.setex(cacheKey, 60 * 60 * 5, Json.toJson(errors)); + } + + sysUserService.clearCache(); + sysRoleService.clearCache(); + return Result.success(NutMap.NEW().addv("total", total).addv("success", success).addv("cacheKey", cacheKey)); + } + + @At + @Ok("void") + @ApiOperation("导出错误记录") + @SaCheckPermission("sys.data.advanced.tool") + public void exportErrors(HttpServletResponse response, String cacheKey) { + if (StrUtil.isBlank(cacheKey)) { + CommonDownloadUtil.download("导入错误记录.xlsx", + ExcelExportUtil.exportExcel(new ExportParams(), ImportError.class, new ArrayList<>()), + response); + return; + } + String json = redisService.get(cacheKey); + List errors = StrUtil.isBlank(json) ? new ArrayList<>() : Json.fromJsonAsList(ImportError.class, json); + CommonDownloadUtil.download("导入错误记录.xlsx", + ExcelExportUtil.exportExcel(new ExportParams(), ImportError.class, errors), + response); + } + + private void applyAfterPlugins(String tableName, + Set tableColumns, + Chain chain, + Object pk, + List pluginList) { + if (pluginList.isEmpty()) { + return; + } + SysDataImportPlugin.PluginContext context = new SysDataImportPlugin.PluginContext( + tableName, + tableColumns, + chain, + pk, + sysUserService.dao(), + sysRoleService + ); + pluginList.forEach(plugin -> plugin.after(context)); + } + + private Object prepareBefore(String tableName, + Record pkRecord, + String field, + List pluginList, + boolean save, + Chain chain, + NutMap row, + Set tableColumns) { + Object pk = resolvePrimaryKeyValue(tableName, pkRecord, field, save, chain, row); + SysDataImportPlugin.PluginContext context = new SysDataImportPlugin.PluginContext( + tableName, + tableColumns, + chain, + pk, + sysUserService.dao(), + sysRoleService + ); + pluginList.forEach(plugin -> plugin.before(context)); + return pk; + } + + private Object resolvePrimaryKeyValue(String tableName, + Record pkRecord, + String field, + boolean save, + Chain chain, + NutMap row) { + if (pkRecord == null) { + return null; + } + String pkColumnName = pkRecord.getString("column_name"); + String pkColumnType = pkRecord.getString("column_type"); + + Object pk; + if (save) { + pk = row.get(pkColumnName); + if (pk == null) { + pk = generatePrimaryKey(pkColumnType); + chain.add(pkColumnName, pk); + } + } else { + Record record = sysUserService.dao().fetch(tableName, Cnd.where(field, "=", row.get(field))); + if (record == null) { + throw new IllegalArgumentException("未找到关键字段匹配的记录"); + } + pk = record.get(pkColumnName); + } + + if (pk == null) { + throw new IllegalArgumentException("主键生成失败"); + } + return pk; + } + + private Object generatePrimaryKey(String pkColumnType) { + if (StrUtil.isBlank(pkColumnType)) { + return R.UU32(); + } + return switch (pkColumnType.toLowerCase()) { + case "int", "integer" -> R.random(1000, 9999); + case "varchar(16)" -> R.UU16(); + case "varchar(64)" -> R.UU64(); + default -> R.UU32(); + }; + } + + private Chain buildChain(NutMap row, Set tableColumns) { + NutMap filtered = NutMap.NEW(); + row.forEach((key, value) -> { + if (key != null && tableColumns.contains(key)) { + filtered.addv(key, value); + } + }); + return filtered.isEmpty() ? null : Chain.from(filtered); + } + + private NutMap[] parseRelations(String relationJson) { + List relationList = Json.fromJsonAsList(NutMap.class, relationJson); + return relationList.toArray(new NutMap[0]); + } + + private List parsePlugins(String pluginsJson) { + if (StrUtil.isBlank(pluginsJson)) { + return new ArrayList<>(); + } + List pluginNames = Json.fromJsonAsList(String.class, pluginsJson); + List plugins = new ArrayList<>(); + for (String pluginName : pluginNames) { + if (StrUtil.isBlank(pluginName)) { + continue; + } + plugins.add(SysDataImportPlugin.valueOf(pluginName)); + } + return plugins; + } + + private Optional getPrimaryKey(List columns) { + return columns.stream().filter(column -> "PRI".equalsIgnoreCase(column.getString("column_key"))).findFirst(); + } + + private List getColumns(String tableName) { + Sql sql = Sqls.create(""" + SELECT + column_name, + is_nullable, + column_type, + column_key, + column_comment + FROM + information_schema.COLUMNS + WHERE + table_name = @tableName + AND table_schema = (SELECT DATABASE()) + ORDER BY + ordinal_position + """).setParam("tableName", tableName); + return sysUserService.list(sql); + } + + private List getDataForExcel(TempFile file, NutMap[] relation) throws IOException { + List result = new ArrayList<>(); + Map headerColumnMap = new HashMap<>(); + + Sheet sheet = WorkbookFactory.create(file.getInputStream()).getSheetAt(0); + Row headerRow = sheet.getRow(0); + if (headerRow == null) { + return result; + } + + int columnNum = headerRow.getPhysicalNumberOfCells(); + for (int i = 0; i < columnNum; i++) { + Cell cell = headerRow.getCell(i); + if (cell == null) { + continue; + } + String header = cell.getStringCellValue(); + for (NutMap item : relation) { + if (StrUtil.equals(item.getString("relation"), header)) { + headerColumnMap.put(i, item.getString("column_name")); + break; + } + } + } + + int rowNum = sheet.getPhysicalNumberOfRows(); + for (int i = 1; i < rowNum; i++) { + Row row = sheet.getRow(i); + if (row == null) { + continue; + } + NutMap data = NutMap.NEW(); + for (int j = 0; j < columnNum; j++) { + String columnName = headerColumnMap.get(j); + if (columnName == null) { + continue; + } + data.setv(columnName, getCellValue(row.getCell(j))); + } + if (!data.isEmpty()) { + result.add(data); + } + } + return result; + } + + private Object getCellValue(Cell cell) { + if (cell == null) { + return null; + } + CellType cellType = cell.getCellType(); + if (cellType == CellType.NUMERIC) { + if (DateUtil.isCellDateFormatted(cell)) { + Date date = cell.getDateCellValue(); + return DATE_TIME_FORMATTER.format(LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault())); + } + double numericValue = cell.getNumericCellValue(); + BigDecimal decimal = BigDecimal.valueOf(numericValue); + if (String.valueOf(numericValue).contains("E")) { + return decimal.toPlainString(); + } + if (numericValue == Math.rint(numericValue)) { + return decimal.toBigInteger(); + } + return numericValue; + } + if (cellType == CellType.STRING) { + return cell.getStringCellValue(); + } + if (cellType == CellType.BOOLEAN) { + return cell.getBooleanCellValue(); + } + if (cellType == CellType.ERROR) { + return cell.getErrorCellValue(); + } + return null; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class ImportError { + @Excel(name = "行数据", width = 80) + private String row; + + @Excel(name = "错误原因", width = 40) + private String errorMsg; + } +} diff --git a/src/main/java/com/budwk/app/sys/enums/SysDataImportPlugin.java b/src/main/java/com/budwk/app/sys/enums/SysDataImportPlugin.java new file mode 100644 index 00000000..7bfe4df8 --- /dev/null +++ b/src/main/java/com/budwk/app/sys/enums/SysDataImportPlugin.java @@ -0,0 +1,123 @@ +package com.budwk.app.sys.enums; + +import com.budwk.app.base.annotation.DictEnum; +import com.budwk.app.base.constant.RoleConstant; +import com.budwk.app.base.utils.PwdUtil; +import com.budwk.app.sys.models.Sys_role; +import com.budwk.app.sys.models.Sys_user_role; +import com.budwk.app.sys.services.SysRoleService; +import lombok.Getter; +import org.nutz.dao.Chain; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.lang.random.R; + +import java.util.Date; +import java.util.Set; + +/** + * 高级导入工具插件。 + */ +@Getter +@DictEnum(key = "sysDataImportPlugin", name = "系统数据高级工具插件") +public enum SysDataImportPlugin { + + USER_INIT(1, "初始化系统用户"), + MEMBER_INIT(2, "设置为会员"); + + private final int location; + private final String description; + + SysDataImportPlugin(int location, String description) { + this.location = location; + this.description = description; + } + + public void before(PluginContext context) { + if (!context.isSysUserTable()) { + return; + } + if (this == USER_INIT) { + String salt = R.UU32(); + context.addValue("salt", salt); + context.addValue("password", PwdUtil.getPassword(PwdUtil.generate(12), salt)); + context.addValue("loginCount", 0); + context.addValue("disabled", false); + return; + } + if (this == MEMBER_INIT) { + context.addValue("member", true); + context.addValue("memberTime", new Date()); + } + } + + public void after(PluginContext context) { + if (!context.isSysUserTable()) { + return; + } + if (this == USER_INIT) { + context.ensureRole(RoleConstant.PUBLIC); + return; + } + if (this == MEMBER_INIT) { + context.ensureRole(RoleConstant.MEMBER); + } + } + + @Getter + public static class PluginContext { + private final String tableName; + private final Set tableColumns; + private final Chain chain; + private final Object pk; + private final Dao dao; + private final SysRoleService sysRoleService; + + public PluginContext(String tableName, + Set tableColumns, + Chain chain, + Object pk, + Dao dao, + SysRoleService sysRoleService) { + this.tableName = tableName; + this.tableColumns = tableColumns; + this.chain = chain; + this.pk = pk; + this.dao = dao; + this.sysRoleService = sysRoleService; + } + + public boolean isSysUserTable() { + return "sys_user".equalsIgnoreCase(tableName); + } + + public boolean hasColumn(String columnName) { + return tableColumns.contains(columnName); + } + + public void addValue(String columnName, Object value) { + if (hasColumn(columnName)) { + chain.add(columnName, value); + } + } + + public void ensureRole(RoleConstant roleConstant) { + if (pk == null || !isSysUserTable()) { + return; + } + Sys_role sysRole = sysRoleService.getByCode(roleConstant); + if (sysRole == null) { + return; + } + int count = dao.count(Sys_user_role.class, Cnd.where("userId", "=", String.valueOf(pk)) + .and("roleId", "=", sysRole.getId())); + if (count > 0) { + return; + } + Sys_user_role userRole = new Sys_user_role(); + userRole.setUserId(String.valueOf(pk)); + userRole.setRoleId(sysRole.getId()); + dao.insert(userRole); + } + } +} diff --git a/src/main/java/com/budwk/app/zhgh/activity/basic/controller/ActivityBasicScopeController.java b/src/main/java/com/budwk/app/zhgh/activity/basic/controller/ActivityBasicScopeController.java index 2bb49796..fb4fcd8b 100644 --- a/src/main/java/com/budwk/app/zhgh/activity/basic/controller/ActivityBasicScopeController.java +++ b/src/main/java/com/budwk/app/zhgh/activity/basic/controller/ActivityBasicScopeController.java @@ -311,10 +311,7 @@ public class ActivityBasicScopeController { cnd.orderBy(activityUserScopePageParam.getPageOrderName(), activityUserScopePageParam.getPageOrderBy().equalsIgnoreCase("ascending") ? "ASC" : "DESC"); } - if (activityUserScopePageParam.getActivityGroupId() != null) { - Sql sqlx = activityBasicScopeService.buildGroupUserIdSubSql(activityUserScopePageParam.getActivityGroupId()); - cnd.and("u.id", activityUserScopePageParam.getReverseSelection() ? "IN" : "NOT IN", sqlx); - } + appendActivityGroupCondition(cnd, activityUserScopePageParam); cnd.andEX("u.id", IN_OR_NIN_OP, activityUserScopePageParam.getUserId()); @@ -326,7 +323,7 @@ public class ActivityBasicScopeController { cnd.and("u.welfareMember", EQ_OR_NEQ_OP, 1); } if (ArrayUtils.contains(activityUserScopePageParam.getMemberTypes(), "基金会员")) { - cnd.and(new Static(" u.loginname " + IN_OR_NIN_OP + " (select loginname from sick_fund_member)")); + cnd.and("u.aidFundMember", EQ_OR_NEQ_OP, 1); } } @@ -351,8 +348,12 @@ public class ActivityBasicScopeController { if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())){ cnd.andEX("u.unionid", "=", SecurityUtil.getUnionId()); } - cnd.andEX("u.unionid", EQ_OR_NEQ_OP, activityUserScopePageParam.getUnionId()); - cnd.andEX("u.unitid", EQ_OR_NEQ_OP, activityUserScopePageParam.getUnitId()); + String[] unionIds = getUnionIds(activityUserScopePageParam); + if (Lang.isNotEmpty(unionIds)) { + cnd.andEX("u.unionid", IN_OR_NIN_OP, unionIds); + } else { + cnd.andEX("u.unionid", EQ_OR_NEQ_OP, activityUserScopePageParam.getUnionId()); + } cnd.andEX("u.personType", IN_OR_NIN_OP, activityUserScopePageParam.getPersonTypes()); cnd.andEX("u.userState", IN_OR_NIN_OP, activityUserScopePageParam.getUserStates()); cnd.andEX("u.sex", IN_OR_NIN_OP, activityUserScopePageParam.getSexTypes()); @@ -367,6 +368,34 @@ public class ActivityBasicScopeController { } + private void appendActivityGroupCondition(Cnd cnd, ActivityUserScopePageParam activityUserScopePageParam) { + Integer activityGroupId = activityUserScopePageParam.getActivityGroupId(); + if (activityGroupId == null) { + return; + } + boolean reverseSelection = Boolean.TRUE.equals(activityUserScopePageParam.getReverseSelection()); + Integer groupType = activityBasicScopeService.getGroupType(activityGroupId); + if (GROUP_TYPE_RESULT == groupType) { + String existsSql = """ + EXISTS ( + SELECT 1 + FROM activity_user_scope aus + WHERE aus.groupId = %d + AND aus.userId = u.id + ) + """.formatted(activityGroupId); + cnd.and(new Static(reverseSelection ? existsSql : "NOT " + existsSql)); + return; + } + + ActivityUserScope groupInfo = activityBasicScopeService.getGroupInfo(activityGroupId); + if (groupInfo == null || StrUtil.isBlank(groupInfo.getGroupSql())) { + return; + } + String groupSql = "(" + groupInfo.getGroupSql() + ")"; + cnd.and(new Static(reverseSelection ? groupSql : "NOT " + groupSql)); + } + /** * 结果分组会把当前筛选出的用户快照保存下来,因此只落 userId 明细数据。 */ @@ -550,7 +579,7 @@ public class ActivityBasicScopeController { conditionList.add("u.welfareMember " + eqOrNeq + " 1"); } if (ArrayUtils.contains(activityUserScopePageParam.getMemberTypes(), "基金会员")) { - conditionList.add("u.loginname " + inOrNotIn + " (select loginname from sick_fund_member)"); + conditionList.add("u.aidFundMember " + eqOrNeq + " 1"); } } @@ -574,8 +603,12 @@ public class ActivityBasicScopeController { conditionList.add("u.unionid = " + wrapSqlValue(SecurityUtil.getUnionId())); } - addSingleValueCondition(conditionList, "u.unionid", eqOrNeq, activityUserScopePageParam.getUnionId()); - addSingleValueCondition(conditionList, "u.unitid", eqOrNeq, activityUserScopePageParam.getUnitId()); + String[] unionIds = getUnionIds(activityUserScopePageParam); + if (Lang.isNotEmpty(unionIds)) { + addArrayCondition(conditionList, "u.unionid", inOrNotIn, unionIds); + } else { + addSingleValueCondition(conditionList, "u.unionid", eqOrNeq, activityUserScopePageParam.getUnionId()); + } addArrayCondition(conditionList, "u.personType", inOrNotIn, activityUserScopePageParam.getPersonTypes()); addArrayCondition(conditionList, "u.userState", inOrNotIn, activityUserScopePageParam.getUserStates()); addArrayCondition(conditionList, "u.sex", inOrNotIn, activityUserScopePageParam.getSexTypes()); @@ -610,6 +643,16 @@ public class ActivityBasicScopeController { } } + private String[] getUnionIds(ActivityUserScopePageParam activityUserScopePageParam) { + if (Lang.isNotEmpty(activityUserScopePageParam.getUnionIds())) { + return activityUserScopePageParam.getUnionIds(); + } + if (StrUtil.isNotBlank(activityUserScopePageParam.getUnionId())) { + return new String[]{activityUserScopePageParam.getUnionId()}; + } + return null; + } + private void addArrayCondition(List conditionList, String columnName, String operator, String[] values) { if (Lang.isNotEmpty(values)) { conditionList.add(columnName + " " + operator + " (" + buildSqlStringList(values) + ")"); diff --git a/src/main/java/com/budwk/app/zhgh/activity/basic/models/ActivityUserScope.java b/src/main/java/com/budwk/app/zhgh/activity/basic/models/ActivityUserScope.java index 509f6236..c71ff5bc 100644 --- a/src/main/java/com/budwk/app/zhgh/activity/basic/models/ActivityUserScope.java +++ b/src/main/java/com/budwk/app/zhgh/activity/basic/models/ActivityUserScope.java @@ -20,7 +20,8 @@ import java.io.Serializable; @Comment("活动人员范围设置") @TableIndexes({ @Index(name = "INDEX_ACTIVITY_USER_SCOPE_GROUPID", fields = {"groupId"}, unique = false), - @Index(name = "INDEX_ACTIVITY_USER_SCOPE_USERID", fields = {"userId"}, unique = false) + @Index(name = "INDEX_ACTIVITY_USER_SCOPE_USERID", fields = {"userId"}, unique = false), + @Index(name = "INDEX_ACTIVITY_USER_SCOPE_GROUPID_USERID", fields = {"groupId", "userId"}, unique = false) }) public class ActivityUserScope extends BaseModel implements Serializable { diff --git a/src/main/java/com/budwk/app/zhgh/activity/basic/param/ActivityUserScopePageParam.java b/src/main/java/com/budwk/app/zhgh/activity/basic/param/ActivityUserScopePageParam.java index 133bc3e6..1f0138c5 100644 --- a/src/main/java/com/budwk/app/zhgh/activity/basic/param/ActivityUserScopePageParam.java +++ b/src/main/java/com/budwk/app/zhgh/activity/basic/param/ActivityUserScopePageParam.java @@ -16,6 +16,7 @@ public class ActivityUserScopePageParam extends PageForm { // 工会id private String unionId; + private String[] unionIds; // 单位id private String unitId; // 人类型 diff --git a/src/main/resources/static/components/module/activity/UserDataScope.vue b/src/main/resources/static/components/module/activity/UserDataScope.vue index b0fcc714..1786fce5 100644 --- a/src/main/resources/static/components/module/activity/UserDataScope.vue +++ b/src/main/resources/static/components/module/activity/UserDataScope.vue @@ -148,6 +148,7 @@ :prop="column.prop" :key="column.prop" :sortable="column.sortable" + :formatter="column.formatter" > - - + + + - + 添加至原有分组 添加到新分组 - + 保存人员结果 保存SQL条件 @@ -351,38 +350,47 @@ - + {{ formatGroupDisplayName(item) }} -
当前还没有同类型分组,请先创建新分组。
+
当前还没有同类型分组,请先创建新分组。
+ - +
- - 取 消 - 确 定 - + + 取消 + 确定 +
- - + + @@ -409,33 +417,23 @@ module.exports = { activityGroupList: [], activityGroupList2: [], memberTypeOptions: [ - { - code: "unionMember", - name: "工会会员" - }, - { - code: "welfareMember", - name: "福利会员" - }, - { - code: "sickFundMember", - name: "基金会员" - } + { code: "unionMember", name: "工会会员" }, + { code: "welfareMember", name: "福利会员" }, + { code: "sickFundMember", name: "基金会员" } ], sexTypeOptions: [ - {code: "男", name: "男"}, - {code: "女", name: "女"} + { code: "male", name: "男" }, + { code: "female", name: "女" } ], pageForm: { age: [0, 0], - unionId: "", - unitId: "", + unionIds: [], clubId: "", searchName: "u.username", personTypes: [], userStates: [], memberStatus: [], - memberTypes: [], + memberTypes: ["工会会员"], sexTypes: [], minAge: 0, maxAge: 0, @@ -448,36 +446,30 @@ module.exports = { activityUserCnd: "", reverseSelection: false }, - activityUnions: [], unions: [], - units: [], - activityUnits: [], - meetingOptions: [], roleList: [], tableHeight: "0px", tableColumns: [ - {prop: "loginName", label: "工号"}, - {prop: "userName", label: "姓名"}, - {prop: "sex", label: "性别"}, - {prop: "birthday", label: "出生年月", sortable: true}, - {prop: "age", label: "年龄", sortable: true}, - {prop: "mobile", label: "联系电话"}, - {prop: "personType", label: "教职工类别", sortable: true}, - {prop: "userState", label: "在职状态", sortable: true}, - {prop: "unitName", label: "所属单位", sortable: true}, - {prop: "unionName", label: "所属工会", sortable: true} - // {prop: 'activityUnionName', label: '活动工会', sortable: true}, + { prop: "loginName", label: "工号" }, + { prop: "userName", label: "姓名" }, + { prop: "sex", label: "性别" }, + { prop: "birthday", label: "出生年月", sortable: true }, + { prop: "age", label: "年龄", sortable: true }, + { prop: "mobile", label: "联系电话" }, + { prop: "personType", label: "教职工类别", sortable: true }, + { prop: "userState", label: "在职状态", sortable: true }, + { prop: "unitName", label: "所属单位", sortable: true }, + { prop: "unionName", label: "所属工会", sortable: true } ], rules: { - setGroupType: [{required: true, message: "请选择添加方式", trigger: ["blur", "change"]}], - groupType: [{required: true, message: "请选择保存方式", trigger: ["blur", "change"]}], - setGroupId: [{required: true, message: "请选择分组", trigger: ["blur", "change"]}], - setGroupName: [{required: true, message: "请输入分组名称", trigger: ["blur", "change"]}] + setGroupType: [{ required: true, message: "请选择添加方式", trigger: ["blur", "change"] }], + groupType: [{ required: true, message: "请选择保存方式", trigger: ["blur", "change"] }], + setGroupId: [{ required: true, message: "请选择分组", trigger: ["blur", "change"] }], + setGroupName: [{ required: true, message: "请输入分组名称", trigger: ["blur", "change"] }] }, - relatedSessionMenus: ["aca4d14498c145ceb5b24ed70776aae2", "733d7266652740a3aeac9da97ab5eeca", "fe2d0768e26d4a80beeb159306bb8d01"], roleData: {}, importDialogVisible: false, - sessionOptions: [], + sessionOptions: [] } }, computed: { @@ -516,6 +508,26 @@ module.exports = { groupType: 1 } }, + getInitialUnionIds() { + if ((this.is_sysadmin || this.is_A06 || this.is_H02) === false && this.is_H04 === true && this.unionid) { + return [this.unionid] + } + return [] + }, + normalizePageForm(pageForm) { + const form = clone(pageForm) + form.personTypes = JSON.stringify(form.personTypes) + form.userStates = JSON.stringify(form.userStates) + form.memberStatus = JSON.stringify(form.memberStatus) + form.memberTypes = JSON.stringify(form.memberTypes) + form.sexTypes = JSON.stringify(form.sexTypes) + form.roleIds = JSON.stringify(form.roleIds) + form.userId = JSON.stringify(form.userId) + form.age = JSON.stringify(form.age) + form.unionIds = JSON.stringify(form.unionIds) + form.activityUserCnd = form.activityUserCnd ? JSON.stringify(form.activityUserCnd) : form.activityUserCnd + return form + }, openSetDialog() { this.formData = this.getDefaultFormData() this.setDialogVisible = true @@ -540,6 +552,10 @@ module.exports = { this.formData.setGroupId = null } }, + handleActivityGroupChange(val) { + this.pageForm.memberTypes = val ? [] : ["工会会员"] + this.doSearch() + }, formatGroupDisplayName(group) { if (Number(group.groupType) === 2) { return group.groupName + "(SQL条件)" @@ -553,41 +569,31 @@ module.exports = { } }) }, - flush(exists_login_name_redis_key) { - this.pageForm.existsLoginNameRedisKey = exists_login_name_redis_key + flush(existsLoginNameRedisKey) { + this.pageForm.existsLoginNameRedisKey = existsLoginNameRedisKey this.doSearch() }, clearImportDialog() { this.importDialogVisible = false }, doExportUser() { - let props = {} - this.tableColumns.forEach((v) => { - props[v.prop] = v.label + const props = {} + this.tableColumns.forEach((item) => { + props[item.prop] = item.label }) - const pageForm = clone(this.pageForm) - pageForm.personTypes = JSON.stringify(pageForm.personTypes) - pageForm.userStates = JSON.stringify(pageForm.userStates) - pageForm.memberStatus = JSON.stringify(pageForm.memberStatus) - pageForm.memberTypes = JSON.stringify(pageForm.memberTypes) - pageForm.sexTypes = JSON.stringify(pageForm.sexTypes) - pageForm.roleIds = JSON.stringify(pageForm.roleIds) - pageForm.userId = JSON.stringify(pageForm.userId) - pageForm.age = JSON.stringify(pageForm.age) + const pageForm = this.normalizePageForm(this.pageForm) pageForm.props = JSON.stringify(props) - pageForm.activityUserCnd = pageForm.activityUserCnd ? JSON.stringify(pageForm.activityUserCnd) : pageForm.activityUserCnd this.$downLoad("/platform/activity/basic/scope/doExportUser", { data: JSON.stringify(pageForm) }) }, doReset() { this.pageForm.userId = [] - this.pageForm.memberTypes = [] + this.pageForm.memberTypes = ["工会会员"] this.pageForm.sexTypes = [] this.pageForm.personTypes = [] this.pageForm.userStates = [] - this.pageForm.unionId = "" - this.pageForm.unitId = "" + this.pageForm.unionIds = this.getInitialUnionIds() this.pageForm.module = "" this.pageForm.teacherMeetingId = "" this.pageForm.roleIds = [] @@ -599,46 +605,52 @@ module.exports = { this.doSearch() }, async queryUser(val) { - const resp = await $.get("/open/common/userOptions", {query: val}) + const resp = await $.get("/open/common/userOptions", { query: val }) this.userList = resp.data }, - tagClick(key, val) { - let idx = this.pageForm[key].indexOf(val) - if (idx !== -1) { - this.pageForm[key].splice(idx, 1) + tagClick(key, value) { + const index = this.pageForm[key].indexOf(value) + if (index !== -1) { + this.pageForm[key].splice(index, 1) } else { - this.pageForm[key].push(val) + this.pageForm[key].push(value) } this.doSearch() }, - async flushUnits() { - this.$set(this.pageForm, "unitId", "") - if (this.is_sysadmin || this.is_A06) { - this.units = await this.$businessTool.listUnit(this.pageForm.unionId) - // this.activityUnits = await getActivityUnits(this.pageForm.activityUnionId) - } else { - this.units = await this.$businessTool.listUnit(this.unionId) - } + doSearch(showFullLoading = false) { + this.tableKey = new Date().getTime() + this.pageForm.pageNumber = 1 + this.pageData(showFullLoading === true) }, - async pageData() { - const pageForm = clone(this.pageForm) - pageForm.personTypes = JSON.stringify(pageForm.personTypes) - pageForm.userStates = JSON.stringify(pageForm.userStates) - pageForm.memberStatus = JSON.stringify(pageForm.memberStatus) - pageForm.memberTypes = JSON.stringify(pageForm.memberTypes) - pageForm.sexTypes = JSON.stringify(pageForm.sexTypes) - pageForm.roleIds = JSON.stringify(pageForm.roleIds) - pageForm.userId = JSON.stringify(pageForm.userId) - pageForm.age = JSON.stringify(pageForm.age) - pageForm.activityUserCnd = pageForm.activityUserCnd ? JSON.stringify(pageForm.activityUserCnd) : pageForm.activityUserCnd + async pageData(showFullLoading = false) { + this.tableLoading = true + const loading = showFullLoading && this.pageForm.activityGroupId + ? this.$loading({ + lock: true, + text: "正在查询,请稍候...", + spinner: "el-icon-loading", + background: "rgba(255, 255, 255, 0.65)" + }) + : null + try { + const resp = await $.post("/platform/activity/basic/scope/pageData", { + data: JSON.stringify(this.normalizePageForm(this.pageForm)) + }) - const resp = await $.post("/platform/activity/basic/scope/pageData", {data: JSON.stringify(pageForm)}) - - if (resp.code === 0) { - this.tableData = resp.data.list - this.pageForm.totalCount = resp.data.totalCount - } else { - this.notifyWarning(resp.msg) + if (resp.code === 0) { + this.tableData = (resp.data.list || []).map((item) => ({ + ...item, + birthday: item.birthday ? moment(item.birthday).format("YYYY-MM-DD") : item.birthday + })) + this.pageForm.totalCount = resp.data.totalCount + } else { + this.notifyWarning(resp.msg) + } + } finally { + this.tableLoading = false + if (loading) { + loading.close() + } } }, async doSetActivityUser() { @@ -651,29 +663,22 @@ module.exports = { this.$message.warning("请先指定筛选条件!") return } + const confirm = await this.$confirm("是否将符合搜索条件的用户设为活动人员?", "提示", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning" }) + if (confirm === "confirm") { this.settingLoading = true - const pageForm = clone(this.pageForm) - pageForm.personTypes = JSON.stringify(pageForm.personTypes) - pageForm.userStates = JSON.stringify(pageForm.userStates) - pageForm.memberStatus = JSON.stringify(pageForm.memberStatus) - pageForm.memberTypes = JSON.stringify(pageForm.memberTypes) - pageForm.sexTypes = JSON.stringify(pageForm.sexTypes) - pageForm.roleIds = JSON.stringify(pageForm.roleIds) - pageForm.userId = JSON.stringify(pageForm.userId) - pageForm.age = JSON.stringify(pageForm.age) - pageForm.activityUserCnd = pageForm.activityUserCnd ? JSON.stringify(pageForm.activityUserCnd) : pageForm.activityUserCnd - + const pageForm = this.normalizePageForm(this.pageForm) Object.assign(pageForm, this.formData) - const resp = await $.post("/platform/activity/basic/scope/doSetActivityUser", {data: JSON.stringify(pageForm)}) + const resp = await $.post("/platform/activity/basic/scope/doSetActivityUser", { + data: JSON.stringify(pageForm) + }) if (resp.code === 0) { this.setDialogVisible = false - // this.userScopeDialog = false await this.getActivityGroup() this.doSearch() this.$message.success(resp.msg) @@ -689,20 +694,17 @@ module.exports = { async getActivityGroup() { const resp = await $.get("/platform/activity/basic/scope/getActivityUserScopeGroup") this.activityGroupList = resp.data || [] - this.activityGroupList2 = [] - this.activityGroupList.forEach((v) => { - this.activityGroupList2.push({ - groupId: v.groupId, - groupName: this.formatGroupDisplayName(v) + "范围之外人员" - }) - }) + this.activityGroupList2 = this.activityGroupList.map((item) => ({ + groupId: item.groupId, + groupName: this.formatGroupDisplayName(item) + "范围之外人员" + })) }, async getRoleListByMenuId() { - const {data} = await $.post("/platform/activity/basic/scope/getRoleListByMenuId") + const { data } = await $.post("/platform/activity/basic/scope/getRoleListByMenuId") this.roleList = data }, async getRolesAndUnion() { - const {data} = await $.post("/platform/activity/basic/scope/getRolesAndUnion") + const { data } = await $.post("/platform/activity/basic/scope/getRolesAndUnion") this.roleData = data } }, @@ -710,18 +712,13 @@ module.exports = { this.listSession() await this.getRolesAndUnion() this.clubOptions = await this.$businessTool.listClubByRole() - if ((this.is_sysadmin || this.is_A06 || this.is_H02) === false && this.is_H04 === true) { - this.unions = this.$businessTool.listUnion(this.unionid) - this.$set(this.pageForm, "unionId", this.unions[0].id) - } else { - this.unions = await this.$businessTool.listUnion() + this.unions = (this.is_sysadmin || this.is_A06 || this.is_H02) + ? await this.$businessTool.listUnion() + : this.$businessTool.listUnion(this.unionid) + this.pageForm.unionIds = this.getInitialUnionIds() + if (!this.is_H04 && this.is_H02 && this.clubOptions.length > 0) { + this.$set(this.pageForm, "clubId", this.clubOptions[0].id) } - if (this.is_H04 === false && this.is_H02 === true) { - if (this.clubOptions.length > 0) { - this.$set(this.pageForm, "clubId", this.clubOptions[0].id) - } - } - await this.flushUnits() await this.getActivityGroup() this.personTypeOptions = await this.$businessTool.getDictOptions("USER_PERSON_TYPE") this.userStateOptions = await this.$businessTool.getDictOptions("USER_STATE") @@ -752,6 +749,7 @@ module.exports = { .query-row > .query-content { min-width: 200px; overflow: hidden; + flex: 1; } .query-row > .query-content > .el-tag { @@ -759,11 +757,11 @@ module.exports = { margin-top: 5px; } -@media screen and (max-width: 992px) { - .query-row:nth-child(4) .query-content .el-col:not(:last-child) { - margin-bottom: 5px; - } +.query-actions { + justify-content: end; +} +@media screen and (max-width: 992px) { .query-title { display: none; } @@ -803,4 +801,24 @@ module.exports = { line-height: 20px; margin-top: 8px; } + +.existing-group-radio-list { + display: grid; + grid-template-columns: repeat(auto-fill, 190px); + column-gap: 24px; + row-gap: 5px; + align-items: start; +} + +.existing-group-radio-list /deep/ .existing-group-radio, +.existing-group-radio-list /deep/ .el-radio.is-bordered, +.existing-group-radio-list /deep/ .el-radio.is-bordered + .el-radio.is-bordered { + margin: 0 !important; + width: 190px; +} + +.existing-group-radio-list /deep/ .el-radio.is-bordered { + display: flex; + align-items: center; +} diff --git a/src/main/resources/views/platform/flow/design/index.html b/src/main/resources/views/platform/flow/design/index.html index d46055a2..44ce7cfb 100644 --- a/src/main/resources/views/platform/flow/design/index.html +++ b/src/main/resources/views/platform/flow/design/index.html @@ -43,7 +43,7 @@ layout("/layouts/platform.html"){ - + @@ -54,6 +54,19 @@ layout("/layouts/platform.html"){ + + +