diff --git a/dependency-reduced-pom.xml b/dependency-reduced-pom.xml index 5b84c29..0984c76 100644 --- a/dependency-reduced-pom.xml +++ b/dependency-reduced-pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.budwk - zhgh_cug_v4 + mini 5.6.0-plus diff --git a/pom.xml b/pom.xml index f7dc410..013d5a5 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 jar com.budwk - zhgh_cug_v4 + mini 5.6.0-plus 2.6.0-SNAPSHOT diff --git a/src/main/java/com/budwk/app/base/config/DataCenterProperties.java b/src/main/java/com/budwk/app/base/config/DataCenterProperties.java index 4c51fee..701c11e 100644 --- a/src/main/java/com/budwk/app/base/config/DataCenterProperties.java +++ b/src/main/java/com/budwk/app/base/config/DataCenterProperties.java @@ -27,6 +27,8 @@ public class DataCenterProperties { private String tokenUrl; private String key; private String secret; + /** 人员和单位接口共用的请求头 apiKey。 */ + private String apiKey; private Map urls = new HashMap<>(); public void init() { @@ -34,6 +36,7 @@ public class DataCenterProperties { tokenUrl = all.get("data-center.token-url"); key = all.get("data-center.key"); secret = all.get("data-center.secret"); + apiKey = all.get("data-center.api-key"); extract(all, "data-center.urls.", urls); } diff --git a/src/main/java/com/budwk/app/sys/controller/SysDataUserPullController.java b/src/main/java/com/budwk/app/sys/controller/SysDataUserPullController.java index 1bb61fd..4148df5 100644 --- a/src/main/java/com/budwk/app/sys/controller/SysDataUserPullController.java +++ b/src/main/java/com/budwk/app/sys/controller/SysDataUserPullController.java @@ -11,6 +11,8 @@ import com.budwk.app.sys.services.SysDataUserPullService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiOperation; +import org.nutz.aop.interceptor.ioc.TransAop; +import org.nutz.ioc.aop.Aop; import org.nutz.dao.Cnd; import org.nutz.dao.Sqls; import org.nutz.dao.sql.Sql; @@ -64,6 +66,8 @@ public class SysDataUserPullController { @At @SaCheckPermission("sys.data.user.pull") @ApiOperation("拉取用户数据") + // 无请求参数;service拉取完整批次,返回Result的code=0表示同步到本地数据源成功。 + @Aop(TransAop.READ_COMMITTED) public Result pullData() { sysUserPullService.pull(); return Result.success(); diff --git a/src/main/java/com/budwk/app/sys/controller/SysDataUserUpdateController.java b/src/main/java/com/budwk/app/sys/controller/SysDataUserUpdateController.java index 091080d..e577c7a 100644 --- a/src/main/java/com/budwk/app/sys/controller/SysDataUserUpdateController.java +++ b/src/main/java/com/budwk/app/sys/controller/SysDataUserUpdateController.java @@ -18,6 +18,8 @@ import io.swagger.annotations.Api; import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiOperation; import org.nutz.dao.Cnd; +import org.nutz.aop.interceptor.ioc.TransAop; +import org.nutz.ioc.aop.Aop; import org.nutz.dao.Sqls; import org.nutz.dao.sql.Sql; import org.nutz.ioc.Ioc; @@ -118,10 +120,15 @@ public class SysDataUserUpdateController { } + /** + * 更新单位数据,无请求参数;由service读取接口配置并同步全部单位。 + * 返回Result对象,code=0表示全部同步成功,失败时由统一异常处理返回错误信息。 + */ @At @SaCheckPermission("sys.data.user.pull") @SLog(tag = "更新单位数据", msg = "更新单位数据") @ApiOperation("更新单位数据") + @Aop(TransAop.READ_COMMITTED) public Result updateUnits(){ sysDataUnitPullService.updateUnits(); return Result.success(); diff --git a/src/main/java/com/budwk/app/sys/controller/SysHomeController.java b/src/main/java/com/budwk/app/sys/controller/SysHomeController.java index 1325815..4186a43 100644 --- a/src/main/java/com/budwk/app/sys/controller/SysHomeController.java +++ b/src/main/java/com/budwk/app/sys/controller/SysHomeController.java @@ -12,25 +12,20 @@ import com.budwk.app.sys.models.Sys_home_activity; import com.budwk.app.sys.models.Sys_home_template; import com.budwk.app.sys.models.Sys_menu; import com.budwk.app.sys.services.SysMenuService; +import com.budwk.app.sys.services.SysHomeNewsService; import com.budwk.app.sys.services.SysUserService; import com.budwk.app.web.commons.auth.utils.AuthUtil; import com.budwk.app.web.commons.auth.utils.SecurityUtil; import com.budwk.app.zhgh.activity.basic.service.ActivityBasicScopeService; import io.swagger.annotations.ApiOperation; -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.select.Elements; import org.nutz.dao.Cnd; import org.nutz.dao.Dao; import org.nutz.dao.FieldFilter; import org.nutz.dao.Sqls; import org.nutz.dao.sql.Sql; import org.nutz.dao.util.Daos; -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.Lang; import org.nutz.lang.Strings; import org.nutz.lang.util.NutMap; @@ -42,7 +37,6 @@ import org.nutz.mvc.annotation.Param; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; -import java.io.IOException; import java.util.*; import java.util.stream.Collectors; @@ -58,7 +52,7 @@ public class SysHomeController { @Inject private SysUserService sysUserService; @Inject - private RedisService redisService; + private SysHomeNewsService sysHomeNewsService; @Inject private ActivityBasicScopeService activityBasicScopeService; @@ -289,38 +283,14 @@ public class SysHomeController { } + /** + * 无请求参数;Result.data为六栏目列表,label为栏目名,value为标题、日期、原文链接及可选图片的列表。 + */ @At @SaCheckLogin - @ApiOperation("获取新闻") + @ApiOperation("获取岭南工会首页新闻") @Ok("json") -// @CacheDefaults(cacheName = RedisConstant.PLATFORM_REDIS_WKCACHE_PREFIX + "web_news", isHash = true) -// @CacheResult(cacheKey = "news", ignoreNull = true, cacheLiveTime = 60 * 60 * 24) public Result getNews() { - try { - String url = "https://xgh.cug.edu.cn/"; - Document document = Jsoup.connect(url).get(); - Elements homeElements = document.select(".gh,.jc,.fc,.jg"); - - List> news = homeElements.stream().map(homeElement -> { - //获取板块名称 - String name = homeElement.selectFirst(".title").text(); - Elements liElements = homeElement.select("li"); - List ele = liElements.stream().map(liElement -> { - NutMap row = NutMap.NEW(); - String href = liElement.selectFirst("a").attr("href"); - String time = liElement.selectFirst("span").text(); - String title = liElement.selectFirst("a").attr("title"); - row.put("href", href); - row.put("time", time); - row.put("text", title); - return row; - }).toList(); - return Map.of("label", name, "value", ele); - }).collect(Collectors.toList()); - redisService.setex("gonghui_news", 60 * 60 * 24, Json.toJson(news)); - return Result.success(news); - } catch (IOException e) { - throw new RuntimeException(e); - } + return Result.success(sysHomeNewsService.getNews()); } } diff --git a/src/main/java/com/budwk/app/sys/controller/SysUnitController.java b/src/main/java/com/budwk/app/sys/controller/SysUnitController.java index 1f862dc..1713a2c 100644 --- a/src/main/java/com/budwk/app/sys/controller/SysUnitController.java +++ b/src/main/java/com/budwk/app/sys/controller/SysUnitController.java @@ -3,10 +3,6 @@ package com.budwk.app.sys.controller; import cn.dev33.satoken.annotation.SaCheckLogin; import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.stp.StpUtil; -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.lang.tree.Tree; -import cn.hutool.core.lang.tree.TreeNode; -import cn.hutool.core.lang.tree.TreeUtil; import cn.hutool.core.util.StrUtil; import com.budwk.app.base.annotation.SLog; import com.budwk.app.base.constant.RoleConstant; @@ -49,7 +45,6 @@ import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; import java.util.ArrayList; import java.util.List; -import java.util.Map; ; @@ -295,34 +290,15 @@ public class SysUnitController { } } + /** + * pid为可选根单位ID,未传时使用学校单位1;返回Result包装的单位树,children表示下级单位。 + */ @At("/tree") @Ok("json") @SaCheckLogin public Object tree(@Param("pid") String pid, HttpServletRequest req) { try { - String rootId = StrUtil.blankToDefault(pid, "0"); - String virtualRootId = "root"; - Cnd cnd = Cnd.NEW(); - cnd.asc("unitcode"); - List list = sysUnitService.query(cnd); - - List> nodeList = CollUtil.newArrayList(); - for (int i = 0; i < list.size(); i++) { - Sys_unit unit = list.get(i); - /* - * 单位根节点存在 id 与 parentId 都为 0 的自引用数据。 - * 构建树时把当前查询根挂到虚拟根下,避免“中国地质大学”和 parentId=0 的学院被构造成同级。 - */ - String parentId = rootId.equals(unit.getId()) ? virtualRootId : unit.getParentId(); - nodeList.add(new TreeNode<>(unit.getId(), parentId, unit.getName(), i) - .setExtra( - Map.of( - "unitTypeCode", unit.getUnitTypeCode() - ) - )); - } - List> treeList = TreeUtil.build(nodeList, virtualRootId); - return Result.success(treeList); + return Result.success(sysUnitService.getUnitTree(pid)); } catch (Exception e) { return Result.error(); } diff --git a/src/main/java/com/budwk/app/sys/models/Sys_user.java b/src/main/java/com/budwk/app/sys/models/Sys_user.java index 20985e2..8b30d93 100644 --- a/src/main/java/com/budwk/app/sys/models/Sys_user.java +++ b/src/main/java/com/budwk/app/sys/models/Sys_user.java @@ -37,7 +37,7 @@ public class Sys_user extends BaseModel implements Serializable { @Column @Comment("工号") @ColDefine(type = ColType.VARCHAR, width = 120) - @DataCenterColumn(name = "工号", key = "ZGH") + @DataCenterColumn(name = "工号", key = "GH") private String loginname; @Column @@ -49,7 +49,7 @@ public class Sys_user extends BaseModel implements Serializable { @Column @Comment("性别") @ColDefine(type = ColType.VARCHAR, width = 10) - @DataCenterColumn(name = "性别", key = "XB", dict = "USER_SEX") + @DataCenterColumn(name = "性别", key = "XB") private String sex; @Column @@ -70,7 +70,7 @@ public class Sys_user extends BaseModel implements Serializable { @Column @Comment("政治面貌") @ColDefine(type = ColType.VARCHAR, width = 100) - @DataCenterColumn(name = "政治面貌", key = "ZZMMM", dict = "USER_POLITICAL") + @DataCenterColumn(name = "政治面貌", key = "ZZMM", dict = "USER_POLITICAL") private String political; @Column @@ -81,7 +81,7 @@ public class Sys_user extends BaseModel implements Serializable { @Column @Comment("民族") @ColDefine(type = ColType.VARCHAR, width = 20) - @DataCenterColumn(name = "民族", key = "MZM", dict = "USER_NATION") + @DataCenterColumn(name = "民族", key = "MZ", dict = "USER_NATION") private String nation; @Column @@ -114,17 +114,19 @@ public class Sys_user extends BaseModel implements Serializable { @Column @Comment("学历") @ColDefine(type = ColType.VARCHAR, width = 20) + @DataCenterColumn(name = "最高学历", key = "ZGXL") private String education; @Column @Comment("婚姻状况") @ColDefine(type = ColType.VARCHAR, width = 20) + @DataCenterColumn(name = "婚姻状况", key = "HYZK") private String marriage; @Column @Comment("学位") @ColDefine(type = ColType.VARCHAR, width = 50) -// @DataCenterColumn(name = "学位", key = "zgxwmc") + @DataCenterColumn(name = "学位", key = "ZGXW") private String academicDegree; @Column @@ -135,8 +137,16 @@ public class Sys_user extends BaseModel implements Serializable { @Column @Comment("职称") @ColDefine(type = ColType.VARCHAR, width = 50) + @DataCenterColumn(name = "当前职称", key = "DQZC") private String professionalTitle; + /** 信息中心 DQZW 为当前职务,与职称、职级分别保存。 */ + @Column + @Comment("当前职务") + @ColDefine(type = ColType.VARCHAR, width = 100) + @DataCenterColumn(name = "当前职务", key = "DQZW") + private String position; + @Column @Comment("职级") @ColDefine(type = ColType.VARCHAR, width = 50) @@ -175,7 +185,7 @@ public class Sys_user extends BaseModel implements Serializable { @Column @Comment("来校时间") @ColDefine(type = ColType.VARCHAR, width = 10) - @DataCenterColumn(name = "来校时间", key = "LXNY") + @DataCenterColumn(name = "来校时间", key = "LXRQ") private String arrivalAtSchoolDate; @Column @@ -208,7 +218,7 @@ public class Sys_user extends BaseModel implements Serializable { @Column @Comment("教职工类别码") @ColDefine(type = ColType.VARCHAR, width = 30) - @DataCenterColumn(name = "教职工类别码", key = "RYLX", dict = "USER_PERSON_TYPE") + @DataCenterColumn(name = "教职工类别码", key = "JZGLB", dict = "USER_PERSON_TYPE") private String personType; @Column @@ -220,6 +230,7 @@ public class Sys_user extends BaseModel implements Serializable { @Column @Comment("编制类别码") @ColDefine(type = ColType.VARCHAR, width = 30) + @DataCenterColumn(name = "编制类别", key = "BZLB") private String preparedBy; @Column @@ -269,12 +280,13 @@ public class Sys_user extends BaseModel implements Serializable { @Column @ColDefine(type = ColType.VARCHAR, width = 32) - @DataCenterColumn(name = "单位", key = "SZDWH") + @DataCenterColumn(name = "二级单位", key = "SZEJDWH") private String unitId; @Column @Comment("三级单位ID") @ColDefine(type = ColType.VARCHAR, width = 32) + @DataCenterColumn(name = "三级单位", key = "SZDWH") private String threeUnitId; @Column @@ -343,6 +355,7 @@ public class Sys_user extends BaseModel implements Serializable { @Column @Comment("校区") @ColDefine(type = ColType.VARCHAR, width = 20) + @DataCenterColumn(name = "校区", key = "XQH") private String campus; diff --git a/src/main/java/com/budwk/app/sys/services/SysHomeNewsService.java b/src/main/java/com/budwk/app/sys/services/SysHomeNewsService.java new file mode 100644 index 0000000..c8310ea --- /dev/null +++ b/src/main/java/com/budwk/app/sys/services/SysHomeNewsService.java @@ -0,0 +1,14 @@ +package com.budwk.app.sys.services; + +import org.nutz.lang.util.NutMap; + +import java.util.List; + +public interface SysHomeNewsService { + /** + * 无请求参数,读取岭南工会官网首页的六个栏目。 + * 返回栏目列表:label 为栏目名,href 为更多链接,value 为文章列表; + * 文章 text 为标题、time 为官网显示日期、href 为原文链接、image 为可选图片地址。 + */ + List getNews(); +} diff --git a/src/main/java/com/budwk/app/sys/services/SysUnitService.java b/src/main/java/com/budwk/app/sys/services/SysUnitService.java index 1214da9..5b5af42 100644 --- a/src/main/java/com/budwk/app/sys/services/SysUnitService.java +++ b/src/main/java/com/budwk/app/sys/services/SysUnitService.java @@ -1,14 +1,25 @@ package com.budwk.app.sys.services; +import cn.hutool.core.lang.tree.Tree; import com.budwk.app.base.page.Pagination; import com.budwk.app.base.param.PageForm; import com.budwk.app.base.service.BaseService; import com.budwk.app.sys.models.Sys_unit; +import java.util.List; + /** * Created by wizzer on 2016/12/22. */ public interface SysUnitService extends BaseService { + /** + * 获取包含指定单位自身及其下级的单位树。 + * + * @param pid 根单位ID;为空或空白时使用信息中心学校单位ID“1” + * @return 单位树列表;节点包含id、parentId、name、unitTypeCode及children,根单位不存在时返回空列表 + */ + List> getUnitTree(String pid); + /** * 分页查询指定分工会的组成单位。 * diff --git a/src/main/java/com/budwk/app/sys/services/impl/SysDataUnitPullServiceImpl.java b/src/main/java/com/budwk/app/sys/services/impl/SysDataUnitPullServiceImpl.java index c42ecf1..f9c8cc1 100644 --- a/src/main/java/com/budwk/app/sys/services/impl/SysDataUnitPullServiceImpl.java +++ b/src/main/java/com/budwk/app/sys/services/impl/SysDataUnitPullServiceImpl.java @@ -1,10 +1,7 @@ package com.budwk.app.sys.services.impl; -import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; -import cn.hutool.core.util.URLUtil; -import cn.hutool.http.Header; -import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; import cn.hutool.http.HttpUtil; import cn.hutool.json.JSONArray; import cn.hutool.json.JSONObject; @@ -21,7 +18,6 @@ import org.nutz.ioc.aop.Aop; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Comparator; import java.util.LinkedHashMap; @@ -31,18 +27,14 @@ import java.util.Set; import java.util.stream.Collectors; /** - * @version 1.0 - * @Author zzr - * @name:SysDataUnitPullServiceImpl - * @Date 2025/9/15 17:52 - * @注释 + * 岭南师范学院单位同步:通过 apiKey 认证分页获取组织机构,并按单位编码更新本地单位。 */ @Slf4j @IocBean(args = {"refer:dao"}) public class SysDataUnitPullServiceImpl extends BaseServiceImpl implements SysDataUnitPullService { - private static final String DMP_UNIT_KEY = "unit"; - private static final int DMP_PAGE_SIZE = 1000; + private static final int UNIT_PAGE_SIZE = 100; + private static final int REQUEST_TIMEOUT = 30000; @Inject private DataCenterProperties dataCenterProperties; @@ -51,7 +43,9 @@ public class SysDataUnitPullServiceImpl extends BaseServiceImpl implem super(dao); } - + /** + * 手动更新入口,无需参数、无返回值;全部分页拉取并校验成功后更新 sys_unit。 + */ @Override @Aop(TransAop.READ_COMMITTED) public void updateUnits() { @@ -59,192 +53,167 @@ public class SysDataUnitPullServiceImpl extends BaseServiceImpl implem } /** - * 拉取单位数据 + * 人员拉取时复用的单位同步入口。 + * unitIds 是调用方已有的本地单位编码列表,仅用于日志,不限制同步范围,以保证父级齐全; + * 无返回值,接口或入库失败时抛出异常,由事务回滚本次单位变更。 */ @Override @Aop(TransAop.READ_COMMITTED) public void updateUnits(List unitIds) { - String accessToken = getDmpAccessToken(); - List rawDataList = distinctDmpUnits(pullDmpUnits(getDmpUnitUrl(), accessToken)); - Set parentCodes = rawDataList.stream() + List units = pullUnits(); + Set parentCodes = units.stream() .map(this::getNormalizedParentCode) .filter(StrUtil::isNotBlank) .collect(Collectors.toSet()); - rawDataList.stream() - .sorted(Comparator.comparingInt(this::getUnitLevel)) - .forEach(raw -> saveOrUpdateUnit(raw, parentCodes)); - - log.info("信息中心单位数据同步完成,本次接口返回单位数量: {},待检查单位编码数量: {}", rawDataList.size(), unitIds == null ? 0 : unitIds.size()); + // DWDJ 为外部单位等级,父级先入库后,子级才能获取正确的父级及树路径。 + units.sort(Comparator.comparingInt(raw -> raw.getInt("DWDJ"))); + for (JSONObject raw : units) { + saveOrUpdateUnit(raw, parentCodes); + } + log.info("单位数据同步完成,单位数量: {},调用方已有单位编码数量: {}", + units.size(), unitIds == null ? 0 : unitIds.size()); } /** - * 获取信息中心开放平台访问令牌。 - * 参数来自 data-center.token-url、data-center.key、data-center.secret; - * 返回值为后续单位接口 body 中 access_token 使用的字符串。 + * 从配置读取 data-center.urls.unit 和 data-center.api-key,无方法参数。 + * GET 查询参数 pageNum 从 1 开始,pageSize 为每页条数,请求头 apiKey 为接口密钥; + * status=0 表示成功,payload 包含 pageNo、pageSize、totalCount 及 resultList 单位对象数组。 + * 返回全部分页按 DWMCDM 去重后的 JSON 列表;分页不完整或字段不合法时抛出异常,不写入部分数据。 */ - private String getDmpAccessToken() { - String tokenUrl = dataCenterProperties.getTokenUrl(); - if (StrUtil.isBlank(tokenUrl)) { - throw new BaseException("未配置信息中心token地址: data-center.token-url"); - } - String key = dataCenterProperties.getKey(); - if (StrUtil.isBlank(key)) { - throw new BaseException("未配置信息中心token key: data-center.key"); - } - String secret = dataCenterProperties.getSecret(); - if (StrUtil.isBlank(secret)) { - throw new BaseException("未配置信息中心token secret: data-center.secret"); - } - - String params = URLUtil.buildQuery(Map.of("key", key, "secret", secret), StandardCharsets.UTF_8); - String tokenResBody = HttpUtil.createGet(tokenUrl + "?" + params).execute().body(); - JSONObject tokenJsonBody = JSONUtil.parseObj(tokenResBody); - String accessToken = tokenJsonBody.getStr("access_token"); - if (StrUtil.isBlank(accessToken) && tokenJsonBody.getJSONObject("result") != null) { - accessToken = tokenJsonBody.getJSONObject("result").getStr("access_token"); - } - if (StrUtil.isBlank(accessToken) && tokenJsonBody.getJSONObject("data") != null) { - accessToken = tokenJsonBody.getJSONObject("data").getStr("access_token"); - } - if (StrUtil.isBlank(accessToken)) { - accessToken = tokenJsonBody.getStr("token"); - } - if (StrUtil.isBlank(accessToken)) { - throw new BaseException("获取信息中心token失败"); - } - return accessToken; - } - - /** - * 读取信息中心单位接口地址。 - * 配置项为 data-center.urls.unit,返回值为单位全量接口URL。 - */ - private String getDmpUnitUrl() { - String url = dataCenterProperties.getUrls().get(DMP_UNIT_KEY); + private List pullUnits() { + String url = dataCenterProperties.getUrls().get("unit"); + String apiKey = dataCenterProperties.getApiKey(); if (StrUtil.isBlank(url)) { - throw new BaseException("未配置信息中心单位接口地址: data-center.urls." + DMP_UNIT_KEY); + throw new BaseException("未配置单位接口地址: data-center.urls.unit"); + } + if (StrUtil.isBlank(apiKey)) { + throw new BaseException("未配置单位接口密钥: data-center.api-key"); } - return url; - } - /** - * 分页拉取单位接口数据。 - * 入参 url 为单位接口地址,accessToken 为信息中心令牌; - * 请求 body 包含 access_token、per_page、page; - * 返回值为 result.data 合并后的单位原始 JSON 列表。 - */ - private List pullDmpUnits(String url, String accessToken) { - List rawDataList = new ArrayList<>(); - int page = 1; - int maxPage = 1; - int total = 0; - - do { - HttpRequest httpRequest = HttpUtil.createPost(url); - httpRequest.header(Header.CONTENT_TYPE, "application/json"); - httpRequest.body(JSONUtil.toJsonStr(Map.of( - "access_token", accessToken, - "per_page", String.valueOf(DMP_PAGE_SIZE), - "page", String.valueOf(page) - ))); - - log.info("请求信息中心单位数据,第{}页: {}", page, httpRequest); - String resBody = httpRequest.execute().body(); - log.info("请求信息中心单位数据第{}页结果: {}", page, resBody); - JSONObject jsonBody = JSONUtil.parseObj(resBody); - - if (jsonBody.getInt("code") != 10000) { - throw new BaseException("获取信息中心单位数据失败,错误码: " + jsonBody.getInt("code") + ";错误原因:" + jsonBody.getStr("message")); - } - - JSONObject result = jsonBody.getJSONObject("result"); - if (result == null) { - break; - } - total = result.getInt("total", total); - maxPage = result.getInt("max_page", maxPage); - JSONArray data = result.getJSONArray("data"); - if (CollUtil.isNotEmpty(data)) { - rawDataList.addAll(data.stream().map(v -> (JSONObject) v).toList()); - } - log.info("信息中心单位数据拉取进度: {}/{}", rawDataList.size(), total); - page++; - } while (page <= maxPage); - - return rawDataList; - } - - /** - * 按单位代码去重,避免接口分页或源数据重复导致同一 DWDM 重复写入。 - */ - private List distinctDmpUnits(List rawDataList) { Map unitMap = new LinkedHashMap<>(); - for (JSONObject raw : rawDataList) { - String unitCode = raw.getStr("DWDM"); - if (StrUtil.isBlank(unitCode)) { - continue; + int pageNum = 1; + int pageSize = UNIT_PAGE_SIZE; + long totalCount = -1; + long receivedCount = 0; + do { + JSONObject body; + // 响应使用完毕即关闭;日志仅记录进度,不输出含 apiKey 的请求对象。 + try (HttpResponse response = HttpUtil.createGet(url) + .header("apiKey", apiKey) + .form("pageNum", pageNum) + .form("pageSize", pageSize) + .timeout(REQUEST_TIMEOUT) + .execute()) { + if (!response.isOk()) { + throw new BaseException("获取单位数据失败,第{}页HTTP状态码: {}", pageNum, response.getStatus()); + } + String responseBody = response.body(); + if (!JSONUtil.isTypeJSONObject(responseBody)) { + throw new BaseException("获取单位数据失败,第{}页返回内容不是JSON对象", pageNum); + } + body = JSONUtil.parseObj(responseBody); } - unitMap.putIfAbsent(unitCode, raw); - } + if (!Integer.valueOf(0).equals(body.getInt("status"))) { + throw new BaseException("获取单位数据失败,第{}页status: {}", pageNum, body.getInt("status")); + } + JSONObject payload = body.getJSONObject("payload"); + if (payload == null) { + throw new BaseException("获取单位数据失败,第{}页缺少payload", pageNum); + } + Integer responsePage = payload.getInt("pageNo"); + Integer responseSize = payload.getInt("pageSize"); + Long responseTotal = payload.getLong("totalCount"); + JSONArray records = payload.getJSONArray("resultList"); + if (!Integer.valueOf(pageNum).equals(responsePage) || responseSize == null || responseSize <= 0 + || responseTotal == null || responseTotal < 0 || records == null) { + throw new BaseException("单位接口第{}页分页信息或resultList不合法", pageNum); + } + // 以首个响应的实际分页大小为准;后续总数或页大小变化时中止,避免漏同步。 + if (pageNum == 1) { + totalCount = responseTotal; + pageSize = responseSize; + } else if (totalCount != responseTotal || pageSize != responseSize) { + throw new BaseException("单位接口分页总数或每页条数发生变化,请重新同步"); + } + long expectedCount = Math.min(pageSize, totalCount - receivedCount); + if (records.size() != expectedCount) { + throw new BaseException("单位接口第{}页数据不完整,预期{}条,实际{}条", pageNum, expectedCount, records.size()); + } + int previousSize = unitMap.size(); + for (int i = 0; i < records.size(); i++) { + JSONObject raw = records.getJSONObject(i); + validateUnit(raw); + unitMap.putIfAbsent(raw.getStr("DWMCDM"), raw); + } + if (!records.isEmpty() && unitMap.size() == previousSize) { + throw new BaseException("单位接口第{}页未返回新的单位编码,请检查分页是否生效", pageNum); + } + receivedCount += records.size(); + log.info("单位数据拉取进度: {}/{},当前第{}页", receivedCount, totalCount, pageNum); + pageNum++; + } while (receivedCount < totalCount); return new ArrayList<>(unitMap.values()); } /** - * 保存或更新单位。 - * DWDM 对应系统单位 id/unitcode,DWMC 对应名称,LSDWH 对应父级单位号,DWCC 对应信息中心原始单位层级。 + * 校验每条单位的编码、名称及正整数等级,避免错误主键或非法等级进入本地单位树。 */ - private void saveOrUpdateUnit(JSONObject raw, Set parentCodes) { - String unitCode = raw.getStr("DWDM"); - if (StrUtil.isBlank(unitCode)) { - return; + private void validateUnit(JSONObject raw) { + if (raw == null || StrUtil.isBlank(raw.getStr("DWMCDM")) || StrUtil.isBlank(raw.getStr("DWMC"))) { + throw new BaseException("单位接口存在缺少DWMCDM或DWMC的数据"); } + Integer level = raw.getInt("DWDJ"); + if (level == null || level <= 0 || level == Integer.MAX_VALUE) { + throw new BaseException("单位{}的DWDJ不是有效的正整数等级", raw.getStr("DWMCDM")); + } + if ("0".equals(raw.getStr("DWMCDM"))) { + throw new BaseException("接口单位编码0与系统内置根单位冲突"); + } + } + /** + * raw 为已校验的单位对象,parentCodes 为本次数据中的父单位编码集合,无返回值。 + * DWMCDM 映射 id/unitcode,DWMC 映射 name,SJDWMCDM 映射 parentId,DWDJ 直接映射 unitLevel,相比原同步规则整体降低一级。 + * 新增和已有单位均按同步等级设置部门类别:三级为1,其余为0;地址、简称等保留已有值,新增单位以名称作为简称。 + */ + @Aop(TransAop.READ_COMMITTED) + private void saveOrUpdateUnit(JSONObject raw, Set parentCodes) { + String unitCode = raw.getStr("DWMCDM"); String parentId = getParentId(unitCode, getNormalizedParentCode(raw)); Sys_unit unit = fetch(unitCode); - if (unit == null) { + boolean insert = unit == null; + if (insert) { unit = new Sys_unit(); unit.setId(unitCode); - unit.setUnitcode(unitCode); + unit.setAliasName(raw.getStr("DWMC")); + } + unit.setUnitcode(unitCode); + unit.setName(raw.getStr("DWMC")); + unit.setParentId(parentId); + unit.setUnitLevel(raw.getInt("DWDJ")); + // 每次按接口等级重算部门类别,确保已有单位同步后也能正确显示单位干部入口。 + unit.setUnitTypeCode(unit.getUnitLevel() == 3 ? 1 : 0); + unit.setHasChildren(parentCodes.contains(unitCode)); + if (StrUtil.isBlank(unit.getPath())) { unit.setPath(getUnitPath(parentId)); - setUnitValue(unit, raw, parentId, parentCodes); + } + if (insert) { dao().fastInsert(unit); } else { - setUnitValue(unit, raw, parentId, parentCodes); - if (StrUtil.isBlank(unit.getPath())) { - unit.setPath(getUnitPath(parentId)); - } dao().updateIgnoreNull(unit); } } /** - * 根据接口字段给系统单位赋值。 - * DWYXBS 表示单位是否有效,DWCC 表示信息中心原始单位层次; - * 系统内置根单位占用一级层级,因此保存时统一将 DWCC 加一。 + * 一级单位挂到系统根单位0,其余单位使用SJDWMCDM,避免学校记录的自引用形成环。 */ - private void setUnitValue(Sys_unit unit, JSONObject raw, String parentId, Set parentCodes) { - String unitCode = raw.getStr("DWDM"); - String unitName = raw.getStr("DWMC"); - String aliasName = StrUtil.blankToDefault(raw.getStr("DWJC"), unitName); - Integer rawUnitLevel = raw.getInt("DWCC"); - Integer unitLevel = getNormalizedUnitLevel(raw); - boolean availableBusinessUnit = "是".equals(raw.getStr("DWYXBS")) && Integer.valueOf(2).equals(rawUnitLevel); - - unit.setParentId(parentId); - unit.setName(unitName); - unit.setAliasName(aliasName); - unit.setUnitcode(unitCode); - unit.setAddress(raw.getStr("DWDZ")); - unit.setUnitLevel(unitLevel); - unit.setUnitType(raw.getStr("DWLB")); - unit.setUnitTypeCode(availableBusinessUnit ? 1 : 0); - unit.setHasChildren(parentCodes.contains(unitCode)); + private String getNormalizedParentCode(JSONObject raw) { + return Integer.valueOf(1).equals(raw.getInt("DWDJ")) ? "0" : raw.getStr("SJDWMCDM"); } /** - * 计算父级单位号。 - * LSDWH 为空、等于自身或本地不存在该父级时按根级处理;系统根单位 0 允许直接作为父级。 + * 沿用本地父级兜底规则:父编码为空、自引用或父级不存在时作为根级,系统根单位0可直接引用。 */ private String getParentId(String unitCode, String parentCode) { if (StrUtil.isBlank(parentCode) || unitCode.equals(parentCode)) { @@ -253,13 +222,11 @@ public class SysDataUnitPullServiceImpl extends BaseServiceImpl implem if ("0".equals(parentCode)) { return parentCode; } - Sys_unit parentUnit = fetch(parentCode); - return parentUnit == null ? "" : parentCode; + return fetch(parentCode) == null ? "" : parentCode; } /** - * 根据父级 path 生成当前单位 path。 - * 父级为空时生成根节点 path,父级存在时在父级 path 下生成子节点 path。 + * 新单位或缺失路径的单位复用项目getSubPath,在父级路径下生成唯一的四位子路径。 */ private String getUnitPath(String parentId) { String parentPath = ""; @@ -269,30 +236,4 @@ public class SysDataUnitPullServiceImpl extends BaseServiceImpl implem } return getSubPath("sys_unit", "path", parentPath); } - - /** - * 信息中心一级单位应挂在系统根单位 0 下,其余单位沿用接口返回的 LSDWH。 - */ - private String getNormalizedParentCode(JSONObject raw) { - Integer rawUnitLevel = raw.getInt("DWCC"); - if (Integer.valueOf(1).equals(rawUnitLevel)) { - return "0"; - } - return raw.getStr("LSDWH"); - } - - /** - * 系统内置根单位占用一级层级,信息中心单位层次入库时统一加一。 - */ - private Integer getNormalizedUnitLevel(JSONObject raw) { - Integer rawUnitLevel = raw.getInt("DWCC"); - return rawUnitLevel == null ? null : rawUnitLevel + 1; - } - - /** - * DWCC 为信息中心单位层次,排序时用于尽量先处理父级单位,便于后续子级找到父节点。 - */ - private int getUnitLevel(JSONObject raw) { - return raw.getInt("DWCC", 0); - } } diff --git a/src/main/java/com/budwk/app/sys/services/impl/SysDataUserAllUpdateServiceImpl.java b/src/main/java/com/budwk/app/sys/services/impl/SysDataUserAllUpdateServiceImpl.java index 790ad4d..f7e5505 100644 --- a/src/main/java/com/budwk/app/sys/services/impl/SysDataUserAllUpdateServiceImpl.java +++ b/src/main/java/com/budwk/app/sys/services/impl/SysDataUserAllUpdateServiceImpl.java @@ -23,7 +23,6 @@ import com.budwk.app.zhgh.democratic.proposal.models.ProposalConfig; import com.budwk.app.zhgh.staffmanage.member.constant.MemberChangeOrigin; import com.budwk.app.zhgh.staffmanage.member.constant.MemberChangeType; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import org.nutz.aop.interceptor.ioc.TransAop; import org.nutz.dao.Cnd; import org.nutz.dao.Dao; @@ -161,10 +160,7 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService for (Sys_user_source source : sources) { Sys_user user = userMap.get(source.getLoginname()); source.setMember(null); - String unitId = source.getUnitId(); - if (StringUtils.isNotBlank(unitId) && unitId.length() == 5) { - source.setUnitId(unitId.substring(0, 3)); - } + // 数据源已分别保存二级和三级单位编码,正式更新时保留完整编码。 // 创建用户对象 Sys_user u = new Sys_user(); diff --git a/src/main/java/com/budwk/app/sys/services/impl/SysDataUserPullServiceImpl.java b/src/main/java/com/budwk/app/sys/services/impl/SysDataUserPullServiceImpl.java index 894af09..072fe89 100644 --- a/src/main/java/com/budwk/app/sys/services/impl/SysDataUserPullServiceImpl.java +++ b/src/main/java/com/budwk/app/sys/services/impl/SysDataUserPullServiceImpl.java @@ -1,14 +1,11 @@ package com.budwk.app.sys.services.impl; import cn.hutool.core.codec.Base64; -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.IdcardUtil; import cn.hutool.core.util.StrUtil; -import cn.hutool.core.util.URLUtil; import cn.hutool.crypto.digest.DigestUtil; -import cn.hutool.http.Header; +import cn.hutool.http.HttpResponse; import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpUtil; import cn.hutool.json.JSONArray; @@ -18,8 +15,6 @@ import com.budwk.app.base.config.DataCenterProperties; import com.budwk.app.base.exception.BaseException; import com.budwk.app.base.service.impl.BaseServiceImpl; import com.budwk.app.sys.annotation.DataCenterColumn; -import com.budwk.app.sys.enums.Api2FinanceFiledMap; -import com.budwk.app.sys.models.Sys_data_dict; import com.budwk.app.sys.models.Sys_dict; import com.budwk.app.sys.models.Sys_unit; import com.budwk.app.sys.models.Sys_user; @@ -27,7 +22,6 @@ import com.budwk.app.sys.models.Sys_user_source; import com.budwk.app.sys.services.SysDataUnitPullService; import com.budwk.app.sys.services.SysDataUserPullService; import com.budwk.app.sys.services.SysDictService; -import com.budwk.app.sys.utils.DataCenterUtil; import lombok.extern.slf4j.Slf4j; import org.nutz.aop.interceptor.async.Async; import org.nutz.aop.interceptor.ioc.TransAop; @@ -42,8 +36,6 @@ import org.nutz.lang.util.NutMap; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.lang.reflect.Field; -import java.math.BigDecimal; -import java.nio.charset.StandardCharsets; import java.util.*; import java.util.stream.Collectors; @@ -51,9 +43,8 @@ import java.util.stream.Collectors; @Slf4j public class SysDataUserPullServiceImpl extends BaseServiceImpl implements SysDataUserPullService { - private static final String DMP_TEACHER_KEY = "teacher"; - private static final String DMP_DISPATCH_KEY = "dispatch"; - private static final int DMP_PAGE_SIZE = 1000; + private static final int USER_PAGE_SIZE = 1000; + private static final int REQUEST_TIMEOUT = 30000; @Inject private SysDictService sysDictService; @@ -74,12 +65,10 @@ public class SysDataUserPullServiceImpl extends BaseServiceImpl private static class FieldMapping { final Field field; final String key; - final String dict; - FieldMapping(Field field, String key, String dict) { + FieldMapping(Field field, String key) { this.field = field; this.key = key; - this.dict = dict; field.setAccessible(true); } } @@ -101,7 +90,7 @@ public class SysDataUserPullServiceImpl extends BaseServiceImpl for (Field field : fields) { DataCenterColumn annotation = field.getAnnotation(DataCenterColumn.class); if (annotation != null) { - mappings.add(new FieldMapping(field, annotation.key(), annotation.dict())); + mappings.add(new FieldMapping(field, annotation.key())); } } fieldMappings = mappings; @@ -111,253 +100,175 @@ public class SysDataUserPullServiceImpl extends BaseServiceImpl return fieldMappings; } + /** + * 拉取完整人员批次,无请求参数;返回本批次拉取时间,用于sys_user_source筛选。 + * 接口及字段校验全部通过后补齐二、三级单位,再写入数据源;异常时由事务回滚。 + */ @Override @Aop(TransAop.READ_COMMITTED) public Date pull() { + List records = pullUsers(); + if (records.isEmpty()) { + throw new BaseException("人员接口未返回数据,本次未生成数据源批次"); + } + Date pullTime = new Date(); + List sources = records.stream().map(raw -> mapUser(raw, pullTime)).toList(); + Set requiredUnits = new HashSet<>(); + for (Sys_user_source source : sources) { + if (StrUtil.isNotBlank(source.getUnitId())) { + requiredUnits.add(source.getUnitId()); + } + if (StrUtil.isNotBlank(source.getThreeUnitId())) { + requiredUnits.add(source.getThreeUnitId()); + } + } + // 编码不再按长度截断,二级和三级单位均须存在,避免数据源保存悬空的单位关联。 + Set existingUnits = dao().query(Sys_unit.class, Cnd.NEW()).stream() + .map(Sys_unit::getId).collect(Collectors.toSet()); + if (!existingUnits.containsAll(requiredUnits)) { + sysDataUnitPullService.updateUnits(new ArrayList<>(existingUnits)); + existingUnits = dao().query(Sys_unit.class, Cnd.NEW()).stream() + .map(Sys_unit::getId).collect(Collectors.toSet()); + if (!existingUnits.containsAll(requiredUnits)) { + throw new BaseException("单位同步后仍缺少人员所属单位,请核对人员与单位接口编码"); + } + } + dao().insert(sources); + log.info("人员数据源拉取完成,本批次人数: {}", sources.size()); + return pullTime; + } + + /** + * raw为单条人员JSON,pullTime为本批次时间;返回待保存的Sys_user_source。 + * 按Sys_user字段注解映射,XB直接保存中文,其余字典类字段保留接口值,不套用旧学校码表。 + * SZEJDWH/SZEJDW为二级单位编码/名称,SZDWH为三级单位编码,DQZW为当前职务。 + * 缺失或空白字段统一为null,避免后续updateIgnoreNull用空字符串覆盖已有人员信息。 + */ + private Sys_user_source mapUser(JSONObject raw, Date pullTime) { + Sys_user_source source = new Sys_user_source(); + for (FieldMapping mapping : getFieldMappings()) { + String value = StrUtil.trimToNull(raw.getStr(mapping.key)); + if ("LXRQ".equals(mapping.key)) { + value = normalizeArrivalAtSchoolDate(value); + } + try { + mapping.field.set(source, value); + } catch (IllegalAccessException e) { + throw new BaseException("人员字段映射失败: {}", mapping.key); + } + } + source.setUnitName(StrUtil.trimToNull(raw.getStr("SZEJDW"))); + source.setPullTime(pullTime); + // 接口没有出生日期,仅对有效身份证推导生日;其他证件不强行转换,也不推导性别。 + if (StrUtil.isNotBlank(source.getIdCard()) && IdcardUtil.isValidCard(source.getIdCard())) { + source.setBirthday(IdcardUtil.getBirthDate(source.getIdCard())); + } + return source; + } + + /** + * LXRQ为接口来校日期字符串,支持日期、以空格或T分隔的时间及年月; + * 返回yyyy-MM-dd,年月补为当月01日,空值返回null,非法日期中止当前批次。 + */ + private String normalizeArrivalAtSchoolDate(String value) { + if (StrUtil.isBlank(value)) { + return null; + } + String date = value.trim().split("[T ]", 2)[0]; try { - // 获取数据中心的字典 - List dataDictList = dao().query(Sys_data_dict.class, Cnd.NEW()); - // 字典码表Map,key为父级编码,value为子级字典列表 - Map> dataDictMap = dataDictList.stream().collect(Collectors.groupingBy(Sys_data_dict::getParentCode)); - - String accessToken = getDmpAccessToken(); - List rawDataList = new ArrayList<>(); - rawDataList.addAll(pullDmpUsers(getDmpUrl(DMP_TEACHER_KEY), accessToken, "在岗教职工")); - rawDataList.addAll(pullDmpUsers(getDmpUrl(DMP_DISPATCH_KEY), accessToken, "在岗劳务派遣")); - rawDataList = distinctDmpUsers(rawDataList); - - if (rawDataList.isEmpty()) { - log.warn("当前未获取到人员数据"); + String[] parts = date.split("-"); + if (parts.length == 2 || parts.length == 3) { + return java.time.LocalDate.of(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]), + parts.length == 3 ? Integer.parseInt(parts[2]) : 1).toString(); } - - Date nowDate = new Date(); - - // 赋值 - List latestSourceList = rawDataList.stream().map(raw -> { - Sys_user_source sysUser = new Sys_user_source(); - - // 使用缓存的字段映射 - for (FieldMapping mapping : getFieldMappings()) { - try { - // 根据字段类型设置值 - if (mapping.field.getType() == String.class) { - - if (StrUtil.isNotBlank(mapping.dict)) { - List sysDataDicts = dataDictMap.getOrDefault(mapping.dict, Collections.emptyList()); - Sys_data_dict sysDataDict = sysDataDicts.stream() - .filter(v -> raw.getStr(mapping.key, "").equals(v.getCode())) - .findFirst().orElse(new Sys_data_dict()); - mapping.field.set(sysUser, StrUtil.blankToDefault(sysDataDict.getName(), raw.getStr(mapping.key))); - } else { - // 特殊处理 根据身份证号获取性别和出生年月 - if ("SFZJH".equals(mapping.key)) { - String idCard = raw.getStr(mapping.key); - mapping.field.set(sysUser, idCard); - // 设置出生年月 - try { - sysUser.setBirthday(IdcardUtil.getBirthDate(idCard)); - } catch (Exception e) { - sysUser.setBirthday(null); - } - } else if ("LXNY".equals(mapping.key)) { - mapping.field.set(sysUser, normalizeArrivalAtSchoolDate(raw.getStr(mapping.key))); - } else { - mapping.field.set(sysUser, raw.getStr(mapping.key)); - } - } - } else if (mapping.field.getType() == Date.class) { - mapping.field.set(sysUser, raw.getDate(mapping.key)); - } - } catch (IllegalAccessException e) { - log.error("设置字段值失败: {}", mapping.field.getName(), e); - } - } - - sysUser.setUnitName(raw.getStr("SZDW")); - sysUser.setUnitId(resolveSourceUnitId(raw.getStr("SZDWH"))); - - // 设置拉取时间 - sysUser.setPullTime(nowDate); - - return sysUser; - }).toList(); - - log.info("用户数据初始化完成,等待插入,当前数据条数{}", latestSourceList.size()); - // 插入到数据库 - if (CollUtil.isNotEmpty(latestSourceList)) { - dao().insert(latestSourceList); - } - - // 人员的单位数据和数据库的单位数据比较,如果人员里面有单位不存在,去更新单位数据 - List sourceUnitIds = latestSourceList.stream().map(Sys_user_source::getUnitId).filter(StrUtil::isNotBlank).distinct().toList(); - Sql sql = Sqls.create("select id from sys_unit group by id"); - sql.setCallback(Sqls.callback.strList()); - dao().execute(sql); - List unitIds = sql.getList(String.class); - - if (!new HashSet<>(unitIds).containsAll(sourceUnitIds)) { - log.info("单位需要更新,正在同步更新"); - sysDataUnitPullService.updateUnits(unitIds); - } - return nowDate; - } catch (Exception e) { - throw new BaseException("数据拉取失败,{}", e.getMessage()); + } catch (RuntimeException e) { + throw new BaseException("人员接口LXRQ不是有效日期"); } + throw new BaseException("人员接口LXRQ日期格式不支持"); } - /** - * 规范化信息中心返回的来校时间。 - * 入参 arrivalAtSchoolDate 对应信息中心 LXNY 字段,允许 yyyy-MM-dd 或 yyyy-MM; - * 返回值用于 sys_user_source.arrivalAtSchoolDate 和后续 sys_user.arrivalAtSchoolDate,年月格式统一补为当月 01 日。 + * 配置data-center.urls.teacher为人员接口地址,data-center.api-key为人员和单位共用密钥。 + * GET查询参数pageNum从1开始、pageSize为每页数量,请求头apiKey用于认证。 + * status=0成功,payload.resultList为人员数组,pageNo/pageSize/totalCount用于校验分页完整性。 + * 返回全部分页按GH去重的人员JSON列表;分页异常时抛出异常,不保存部分批次。 */ - private String normalizeArrivalAtSchoolDate(String arrivalAtSchoolDate) { - String dateText = StrUtil.trim(arrivalAtSchoolDate); - if (StrUtil.isBlank(dateText)) { - return dateText; - } - if (dateText.matches("\\d{4}-\\d{1,2}-\\d{1,2}")) { - String[] parts = dateText.split("-"); - return parts[0] + "-" + StrUtil.padPre(parts[1], 2, '0') + "-" + StrUtil.padPre(parts[2], 2, '0'); - } - if (dateText.matches("\\d{4}-\\d{1,2}")) { - String[] parts = dateText.split("-"); - return parts[0] + "-" + StrUtil.padPre(parts[1], 2, '0') + "-01"; - } - return dateText; - } - - /** - * 获取信息中心开放平台访问令牌。 - * 返回值为接口后续调用使用的 access_token 字符串。 - */ - private String getDmpAccessToken() { - String tokenUrl = dataCenterProperties.getTokenUrl(); - if (StrUtil.isBlank(tokenUrl)) { - throw new BaseException("未配置信息中心token地址: data-center.token-url"); - } - String key = dataCenterProperties.getKey(); - if (StrUtil.isBlank(key)) { - throw new BaseException("未配置信息中心token key: data-center.key"); - } - String secret = dataCenterProperties.getSecret(); - if (StrUtil.isBlank(secret)) { - throw new BaseException("未配置信息中心token secret: data-center.secret"); - } - // 信息中心token接口要求key和secret通过URL参数传入,配置中分开维护,调用时统一组装。 - String params = URLUtil.buildQuery(Map.of("key", key, "secret", secret), StandardCharsets.UTF_8); - HttpRequest tokenHttpRequest = HttpUtil.createGet(tokenUrl + "?" + params); - log.info("请求信息中心token: {}", tokenHttpRequest); - String tokenResBody = tokenHttpRequest.execute().body(); - log.info("请求信息中心token结果: {}", tokenResBody); - - JSONObject tokenJsonBody = JSONUtil.parseObj(tokenResBody); - String accessToken = tokenJsonBody.getStr("access_token"); - if (StrUtil.isBlank(accessToken) && tokenJsonBody.getJSONObject("result") != null) { - accessToken = tokenJsonBody.getJSONObject("result").getStr("access_token"); - } - if (StrUtil.isBlank(accessToken) && tokenJsonBody.getJSONObject("data") != null) { - accessToken = tokenJsonBody.getJSONObject("data").getStr("access_token"); - } - if (StrUtil.isBlank(accessToken)) { - accessToken = tokenJsonBody.getStr("token"); - } - if (StrUtil.isBlank(accessToken)) { - throw new BaseException("获取信息中心token失败"); - } - return accessToken; - } - - /** - * 读取信息中心人员接口地址。 - * 入参 key 对应 data-center.urls 下的配置项,返回值为具体接口URL。 - */ - private String getDmpUrl(String key) { - String url = dataCenterProperties.getUrls().get(key); + private List pullUsers() { + String url = dataCenterProperties.getUrls().get("teacher"); + String apiKey = dataCenterProperties.getApiKey(); if (StrUtil.isBlank(url)) { - throw new BaseException("未配置信息中心人员接口地址: data-center.urls." + key); + throw new BaseException("未配置人员接口地址: data-center.urls.teacher"); + } + if (StrUtil.isBlank(apiKey)) { + throw new BaseException("未配置人员接口密钥: data-center.api-key"); } - return url; - } - /** - * 分页拉取单个人员接口数据。 - * 入参 url 为人员接口地址,accessToken 为信息中心令牌,sourceName 用于日志区分接口来源。 - * 返回值为该接口所有分页合并后的原始人员 JSON 列表。 - */ - private List pullDmpUsers(String url, String accessToken, String sourceName) { - List rawDataList = new ArrayList<>(); - int page = 1; - int maxPage = 1; - int total = 0; - - do { - // 信息中心接口单页最多返回1000条,按page循环拉完当前接口全部数据。 - HttpRequest httpRequest = HttpUtil.createPost(url); - httpRequest.header(Header.CONTENT_TYPE, "application/json"); - httpRequest.body(JSONUtil.toJsonStr(Map.of( - "access_token", accessToken, - "per_page", String.valueOf(DMP_PAGE_SIZE), - "page", String.valueOf(page) - ))); - - log.info("请求{}人员数据,第{}页: {}", sourceName, page, httpRequest); - String resBody = httpRequest.execute().body(); - log.info("请求{}人员数据第{}页结果: {}", sourceName, page, resBody); - JSONObject jsonBody = JSONUtil.parseObj(resBody); - - if (jsonBody.getInt("code") != 10000) { - throw new BaseException("获取" + sourceName + "人员数据失败,错误码: " + jsonBody.getInt("code") + ";错误原因:" + jsonBody.getStr("message")); - } - - JSONObject result = jsonBody.getJSONObject("result"); - if (result == null) { - break; - } - total = result.getInt("total", total); - maxPage = result.getInt("max_page", maxPage); - JSONArray data = result.getJSONArray("data"); - if (CollUtil.isNotEmpty(data)) { - rawDataList.addAll(data.stream().map(v -> (JSONObject) v).toList()); - } - log.info("{}人员数据拉取进度: {}/{}", sourceName, rawDataList.size(), total); - page++; - } while (page <= maxPage); - - return rawDataList; - } - - /** - * 合并两个接口数据时按职工号去重,避免同一批次出现重复人员。 - * 返回值保持第一次出现的数据,用于后续统一映射入库。 - */ - private List distinctDmpUsers(List rawDataList) { Map userMap = new LinkedHashMap<>(); - for (JSONObject raw : rawDataList) { - String loginName = raw.getStr("ZGH"); - if (StrUtil.isBlank(loginName)) { - loginName = raw.getStr("ID"); + int pageNum = 1; + int pageSize = USER_PAGE_SIZE; + long totalCount = -1; + long receivedCount = 0; + do { + JSONObject body; + // 响应使用完毕即关闭;日志仅记录进度,不输出含 apiKey 的请求对象。 + try (HttpResponse response = HttpUtil.createGet(url) + .header("apiKey", apiKey) + .form("pageNum", pageNum) + .form("pageSize", pageSize) + .timeout(REQUEST_TIMEOUT) + .execute()) { + if (!response.isOk()) { + throw new BaseException("获取人员数据失败,第{}页HTTP状态码: {}", pageNum, response.getStatus()); + } + String responseBody = response.body(); + if (!JSONUtil.isTypeJSONObject(responseBody)) { + throw new BaseException("获取人员数据失败,第{}页返回内容不是JSON对象", pageNum); + } + body = JSONUtil.parseObj(responseBody); } - userMap.putIfAbsent(loginName, raw); - } + if (!Integer.valueOf(0).equals(body.getInt("status"))) { + throw new BaseException("获取人员数据失败,第{}页status: {}", pageNum, body.getInt("status")); + } + JSONObject payload = body.getJSONObject("payload"); + if (payload == null) { + throw new BaseException("获取人员数据失败,第{}页缺少payload", pageNum); + } + Integer responsePage = payload.getInt("pageNo"); + Integer responseSize = payload.getInt("pageSize"); + Long responseTotal = payload.getLong("totalCount"); + JSONArray records = payload.getJSONArray("resultList"); + if (!Integer.valueOf(pageNum).equals(responsePage) || responseSize == null || responseSize <= 0 + || responseTotal == null || responseTotal < 0 || records == null) { + throw new BaseException("人员接口第{}页分页信息或resultList不合法", pageNum); + } + // 以首个响应的实际分页大小为准;后续总数或页大小变化时中止,避免漏同步。 + if (pageNum == 1) { + totalCount = responseTotal; + pageSize = responseSize; + } else if (totalCount != responseTotal || pageSize != responseSize) { + throw new BaseException("人员接口分页总数或每页条数发生变化,请重新同步"); + } + long expectedCount = Math.min(pageSize, totalCount - receivedCount); + if (records.size() != expectedCount) { + throw new BaseException("人员接口第{}页数据不完整,预期{}条,实际{}条", pageNum, expectedCount, records.size()); + } + int previousSize = userMap.size(); + for (int i = 0; i < records.size(); i++) { + JSONObject raw = records.getJSONObject(i); + if (raw == null || StrUtil.isBlank(raw.getStr("GH")) || StrUtil.isBlank(raw.getStr("XM"))) { + throw new BaseException("人员接口存在缺少GH或XM的数据"); + } + userMap.putIfAbsent(raw.getStr("GH").trim(), raw); + } + if (!records.isEmpty() && userMap.size() == previousSize) { + throw new BaseException("人员接口第{}页未返回新的人员编码,请检查分页是否生效", pageNum); + } + receivedCount += records.size(); + log.info("人员数据拉取进度: {}/{},当前第{}页", receivedCount, totalCount, pageNum); + pageNum++; + } while (receivedCount < totalCount); return new ArrayList<>(userMap.values()); } - /** - * 根据接口返回的所在单位号转换数据源用户单位。 - * 入参 rawUnitId 对应人员接口 SZDWH:5位表示三级单位,需要写入其二级父单位;其他长度保持接口原值。 - * 返回值为 sys_user_source.unitId 使用的单位ID,找不到三级单位或父级为空时保留接口原始单位号,避免人员数据丢失。 - */ - private String resolveSourceUnitId(String rawUnitId) { - if (StrUtil.isBlank(rawUnitId) || rawUnitId.length() != 5) { - return rawUnitId; - } - Sys_unit unit = dao().fetch(Sys_unit.class, rawUnitId); - if (unit == null || StrUtil.isBlank(unit.getParentId())) { - return rawUnitId; - } - return unit.getParentId(); - } - @Async private void updateDict(List userSources) { //判断是否要更新在职状态字典 diff --git a/src/main/java/com/budwk/app/sys/services/impl/SysHomeNewsServiceImpl.java b/src/main/java/com/budwk/app/sys/services/impl/SysHomeNewsServiceImpl.java new file mode 100644 index 0000000..42b9551 --- /dev/null +++ b/src/main/java/com/budwk/app/sys/services/impl/SysHomeNewsServiceImpl.java @@ -0,0 +1,171 @@ +package com.budwk.app.sys.services.impl; + +import com.budwk.app.base.exception.BaseException; +import com.budwk.app.sys.services.SysHomeNewsService; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +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.util.NutMap; +import org.nutz.log.Log; +import org.nutz.log.Logs; + +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** 岭南工会首页新闻获取;只解析公开标题和链接,不抓取或执行文章脚本。 */ +@IocBean +public class SysHomeNewsServiceImpl implements SysHomeNewsService { + private static final Log log = Logs.get(); + private static final String HOME_URL = "https://d.lingnan.edu.cn/gh/index.htm"; + private static final String CACHE_KEY = "budwk5mini:lingnan:home_news:v1"; + private static final String LAST_SUCCESS_KEY = CACHE_KEY + ":last_success"; + private static final Pattern IMAGE_PATTERN = Pattern.compile( + "u_u10_imgs\\.addImg\\(\\s*\"([^\"]+)\"\\s*,\\s*\"(\\d+)\""); + + @Inject + private RedisService redisService; + + private List lastSuccess; + private long nextRefreshAt; + + /** + * 无入参;返回接口约定的六栏目列表。成功结果缓存30分钟,网络失败时使用最近成功数据。 + * 同一实例串行刷新,有历史结果时失败后一分钟内不重复请求官网;Redis不可用时仍可使用实例内缓存。 + */ + @Override + public synchronized List getNews() { + if (lastSuccess != null && System.currentTimeMillis() < nextRefreshAt) { + return lastSuccess; + } + List cached = readCache(CACHE_KEY); + if (cached != null) { + // Redis的剩余有效期可能不足30分钟,下一次请求仍以Redis是否过期为准。 + lastSuccess = cached; + return cached; + } + try { + Document document = Jsoup.connect(HOME_URL).userAgent("Mozilla/5.0") + .timeout(10000).maxBodySize(2 * 1024 * 1024).get(); + List news = parseHomepage(document); + lastSuccess = news; + nextRefreshAt = System.currentTimeMillis() + 30 * 60 * 1000L; + try { + String json = Json.toJson(news); + redisService.setex(LAST_SUCCESS_KEY, 7 * 24 * 60 * 60, json); + redisService.setex(CACHE_KEY, 30 * 60, json); + } catch (Exception e) { + log.warn("工会新闻缓存写入失败,使用本次获取结果", e); + } + return news; + } catch (Exception e) { + log.warn("岭南工会首页获取失败,尝试使用最近成功数据", e); + if (lastSuccess == null) { + lastSuccess = readCache(LAST_SUCCESS_KEY); + } + if (lastSuccess != null) { + nextRefreshAt = System.currentTimeMillis() + 60 * 1000L; + return lastSuccess; + } + throw new BaseException("工会官网新闻暂时无法获取,请稍后重试"); + } + } + + /** 缓存不存在、损坏或Redis不可用时返回null,不阻断官网抓取。 */ + private List readCache(String key) { + try { + String json = redisService.get(key); + if (json != null && !json.isBlank()) { + List list = Json.fromJsonAsList(NutMap.class, json); + if (list != null && list.size() == 6) { + return list; + } + } + } catch (Exception e) { + log.warn("工会新闻缓存读取失败", e); + } + return null; + } + + /** 按官网栏目顺序解析;任何栏目无法识别时不覆盖最近成功缓存,避免发布残缺数据。 */ + private List parseHomepage(Document document) { + String[][] columns = { + {"新闻中心", "c123980", "index/xwzx__.htm"}, + {"通知公告", "c123972", "index/tzgg__.htm"}, + {"女工青工", "c123973", "index/ngqg_.htm"}, + {"文体工作", "c123974", "index/wtgz__.htm"}, + {"岭师教工", "c123975", "index/lsjg_.htm"} + }; + List result = new ArrayList<>(); + for (String[] column : columns) { + List articles = new ArrayList<>(); + Set links = new HashSet<>(); + for (Element anchor : document.select("a." + column[1] + "[href]")) { + String href = absoluteUrl(anchor.attr("href")); + String title = anchor.attr("title").trim(); + if (title.isEmpty()) { + title = anchor.text().trim(); + } + if (href.isEmpty() || title.isEmpty() || !links.add(href)) { + continue; + } + Element row = anchor.closest("tr"); + Element date = row == null ? null : row.selectFirst("td.timestyle" + column[1].substring(1)); + // 官网仅给月日或未给日期时原样保留,不推算年份、不从文章标题猜日期。 + articles.add(NutMap.NEW().addv("text", title).addv("href", href) + .addv("time", date == null ? "" : date.text().trim())); + } + if (articles.isEmpty()) { + throw new IllegalStateException("无法识别工会首页栏目:" + column[0]); + } + result.add(NutMap.NEW().addv("label", column[0]).addv("href", absoluteUrl(column[2])).addv("value", articles)); + } + // 图片标签初始src为loading.gif;只读取预加载脚本中的地址和索引,不执行脚本。 + Map images = new HashMap<>(); + Matcher matcher = IMAGE_PATTERN.matcher(document.html()); + while (matcher.find()) { + images.put(Integer.parseInt(matcher.group(2)), absoluteUrl(matcher.group(1).replace("\\/", "/"))); + } + List pictures = new ArrayList<>(); + int index = 0; + for (Element image : document.select("#u_u10_demo1 img[name=u_u10_img]")) { + String source = images.get(index++); + Element anchor = image.closest("a[href]"); + String href = anchor == null ? "" : absoluteUrl(anchor.attr("href")); + if (source == null || source.isEmpty() || href.isEmpty()) { + throw new IllegalStateException("工会首页图片地址解析失败"); + } + pictures.add(NutMap.NEW().addv("text", image.attr("alt")).addv("href", href) + .addv("time", "").addv("image", source)); + } + if (pictures.isEmpty()) { + throw new IllegalStateException("无法识别工会首页图片展示栏目"); + } + result.add(NutMap.NEW().addv("label", "图片展示").addv("href", absoluteUrl("index/tpzs.htm")).addv("value", pictures)); + return result; + } + + /** 官网相对路径补全为绝对地址;仅返回HTTP(S)链接,保留原文外链及其查询参数。 */ + private String absoluteUrl(String value) { + if (value == null || value.isBlank()) { + return ""; + } + try { + URI uri = URI.create(HOME_URL).resolve(value.trim()); + return (("https".equalsIgnoreCase(uri.getScheme()) || "http".equalsIgnoreCase(uri.getScheme())) + && uri.getHost() != null) ? uri.toString() : ""; + } catch (IllegalArgumentException e) { + return ""; + } + } +} diff --git a/src/main/java/com/budwk/app/sys/services/impl/SysUnitServiceImpl.java b/src/main/java/com/budwk/app/sys/services/impl/SysUnitServiceImpl.java index f805b30..cb1308a 100644 --- a/src/main/java/com/budwk/app/sys/services/impl/SysUnitServiceImpl.java +++ b/src/main/java/com/budwk/app/sys/services/impl/SysUnitServiceImpl.java @@ -1,5 +1,8 @@ package com.budwk.app.sys.services.impl; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.lang.tree.TreeNode; +import cn.hutool.core.lang.tree.TreeUtil; import cn.hutool.core.util.StrUtil; import com.budwk.app.base.constant.RedisConstant; import com.budwk.app.base.page.Pagination; @@ -19,6 +22,10 @@ import org.nutz.lang.Strings; import org.nutz.plugins.wkcache.annotation.CacheDefaults; import org.nutz.plugins.wkcache.annotation.CacheRemoveAll; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + /** * Created by wizzer on 2016/12/22. */ @@ -29,6 +36,29 @@ public class SysUnitServiceImpl extends BaseServiceImpl implements Sys super(dao); } + /** + * pid为空时以学校单位1为展示根;指定pid时返回该单位及其下级,不依赖实体单位0存在。 + * 虚拟根仅用于组织返回结构,不修改数据库中的父级关系;缺少部门类别时按普通分类0展示。 + */ + @Override + public List> getUnitTree(String pid) { + String rootId = StrUtil.blankToDefault(pid, "1"); + String virtualRootId = "root"; + List units = query(Cnd.NEW().asc("unitcode")); + if (units.stream().noneMatch(unit -> rootId.equals(unit.getId()))) { + return List.of(); + } + List> nodes = new ArrayList<>(); + for (int i = 0; i < units.size(); i++) { + Sys_unit unit = units.get(i); + // 仅将本次查询根挂到虚拟根下,其他节点保留实际父级,避免学校与下级并列。 + String parentId = rootId.equals(unit.getId()) ? virtualRootId : unit.getParentId(); + nodes.add(new TreeNode<>(unit.getId(), parentId, unit.getName(), i) + .setExtra(Map.of("unitTypeCode", unit.getUnitTypeCode() == null ? 0 : unit.getUnitTypeCode()))); + } + return TreeUtil.build(nodes, virtualRootId); + } + /** * 按单位编码或名称筛选当前分工会的组成单位,并按单位编码倒序分页。 */ diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 4a00be9..87e2ef2 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -1,17 +1,85 @@ - + - + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - + + + + + + ${LOG_HOME}/app.log + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + ${LOG_HOME}/app-%d{yyyy-MM-dd}.log + 300 + + + + + + + + + + + + + + + + + + + + + + + + <!– ERROR级别日志文件配置 –> ${LOG_HOME}/error.log @@ -41,19 +109,31 @@ ${LOG_HOME}/error-%d{yyyy-MM-dd}.log - 30 + 300 - + <!– 框架日志级别 –> + <!– –> - + <!– 日志级别和appender的关联 –> + - + --> + + + + diff --git a/src/main/resources/views/layouts/v4/home/index.html b/src/main/resources/views/layouts/v4/home/index.html index 347e226..fc68e6b 100644 --- a/src/main/resources/views/layouts/v4/home/index.html +++ b/src/main/resources/views/layouts/v4/home/index.html @@ -153,7 +153,7 @@ layout("/layouts/v4/baseLayout.html"){ - + @@ -172,6 +172,8 @@ layout("/layouts/v4/baseLayout.html"){ data(){ return{ websiteNews: [], + newsLoading: false, + newsError: "", homeBannerList: "${config.AppHomeImg!}".split(",").map(item => item.trim()).filter(item => item) } }, @@ -188,10 +190,20 @@ layout("/layouts/v4/baseLayout.html"){ }, methods: { getWebSiteNews(){ + if (this.newsLoading) return + this.newsLoading = true + this.newsError = "" + // 无请求参数;data为六栏目数组,value包含标题、日期、原文链接和可选图片。 this.$axios.post('/platform/home/getNews').then(res => { if (res.code === 0) { - this.websiteNews = res.data + this.websiteNews = res.data || [] + } else { + this.newsError = res.msg || "工会新闻暂时无法获取" } + }).catch(() => { + this.newsError = "工会新闻暂时无法获取,请稍后重试" + }).finally(() => { + this.newsLoading = false }) } } diff --git a/src/main/resources/views/layouts/v4/home/jcdt.js b/src/main/resources/views/layouts/v4/home/jcdt.js index dbeefbc..a4ea7b9 100644 --- a/src/main/resources/views/layouts/v4/home/jcdt.js +++ b/src/main/resources/views/layouts/v4/home/jcdt.js @@ -1,18 +1,52 @@ const jcdt = { template: /*language=HTML*/ `
-
- - +
+
+ {{ column.label }} +
+
+ {{ error }} 重试 +
+ + +
{{ item.label }} + 更多
-
- `, data() { - return {} + return { activeIndex: 0 } }, props: { list: { type: Array, - default: [] + default: () => [] + }, + loading: { type: Boolean, default: false }, + error: { type: String, default: "" } + }, + created() { + // 动画状态不参与 Vue 渲染,避免每一帧重新生成新闻卡片。 + this._imageScroll = { frame: null, track: null, offset: 0, previousTime: null } + }, + mounted() { + this.syncImageScroll() + }, + beforeDestroy() { + this.stopImageScroll() + }, + watch: { + activeIndex() { + this.syncImageScroll() + }, + list: { + deep: true, + handler() { + this.syncImageScroll() + } + } + }, + computed: { + // 图片不足四张时重复完整序列,保证宽屏滚动也不会露出空白;不修改接口原数据。 + displayColumns() { + return this.list.map(item => { + if (!this.isImageColumn(item)) return item + const images = item.value || [] + const scrollImages = [] + if (images.length) { + const copies = Math.ceil(4 / images.length) + for (let i = 0; i < copies; i++) scrollImages.push(...images) + } + return Object.assign({}, item, { scrollImages }) + }) } }, methods: { - onLink(item) { - const url = this.isHttpOrHttps(item.href) ? item.href : "https://xgh.cug.edu.cn/" + item.href - window.open(url) + // 切栏、刷新数据后等待 DOM 更新;只为当前图片栏目启动一个动画循环。 + syncImageScroll() { + this.stopImageScroll() + this.$nextTick(() => { + if (this._isDestroyed || this._isBeingDestroyed) return + this.stopImageScroll() + if (!this.isImageColumn(this.list[this.activeIndex])) return + const track = this.$el.querySelector('.jcdt-image-track[data-column="' + this.activeIndex + '"]') + if (!track || !track.querySelector('.jcdt-item')) return + const state = this._imageScroll + if (state.track !== track) { + state.track = track + state.offset = 0 + } + state.frame = requestAnimationFrame(this.advanceImageScroll) + }) }, - isHttpOrHttps(url) { - return /^(http:\/\/|https:\/\/)/i.test(url) + // 浏览器帧时间戳为毫秒;按每秒 45 像素移动,超过首组宽度后无缝回绕。 + advanceImageScroll(timestamp) { + const state = this._imageScroll + state.frame = null + if (this._isDestroyed || this._isBeingDestroyed || !this.isImageColumn(this.list[this.activeIndex])) return + const group = state.track && state.track.firstElementChild + if (!group) return + const width = group.getBoundingClientRect().width + // 限制后台标签恢复后的单帧位移;实时读取组宽以适应窗口尺寸变化。 + const elapsed = state.previousTime === null ? 0 : Math.min(timestamp - state.previousTime, 100) + state.previousTime = timestamp + if (width > 0) { + state.offset = (state.offset + elapsed * 0.045) % width + state.track.style.transform = 'translate3d(-' + state.offset + 'px, 0, 0)' + } + state.frame = requestAnimationFrame(this.advanceImageScroll) + }, + // 离开栏目或销毁组件时取消待执行帧,保留当前位置供再次进入时续播。 + stopImageScroll() { + const state = this._imageScroll + if (!state) return + if (state.frame !== null) cancelAnimationFrame(state.frame) + state.frame = null + state.previousTime = null + }, + // 栏目对象来自新闻接口;仅图片展示使用连续滚动,并暂停外层自动切栏。 + isImageColumn(item) { + return !!item && item.label === '图片展示' + }, + // 手动栏目切换与轮播共用同一索引,避免标题按钮和内容不同步。 + selectColumn(index) { + this.$refs.newsCarousel.setActiveItem(index) + }, + onColumnChange(index) { + this.activeIndex = index } }, style: /*language=CSS*/ ` + .jcdt-tabs { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 8px; + } + .jcdt-empty { text-align: center; padding: 20px; } + /deep/ .jcdt-content { height: 330px; overflow-y: auto; padding: 8px; } + /deep/ .jcdt-image-content { overflow: hidden; --visible-cards: 4; } + /deep/ .jcdt-image-track { display: flex; width: 100%; will-change: transform; } + /* 每组含末尾间距,平移整组宽度后与下一组完全重合。 */ + /deep/ .jcdt-image-group { + display: grid; + grid-template-columns: repeat(var(--image-count), minmax(0, 1fr)); + gap: 20px; + padding-right: 20px; + box-sizing: border-box; + flex: 0 0 calc((100% + 20px) / var(--visible-cards) * var(--image-count)); + } + /deep/ .jcdt-image-group .title { height: 45px; } + /deep/ .jcdt-title .el-link { margin-left: 16px; } + /deep/ .jcdt-item { color: inherit; text-decoration: none; min-width: 0; } + /deep/ .jcdt-item .el-image { width: 100%; height: 100%; } + @media (max-width: 900px) { + /deep/ .jcdt-image-content { --visible-cards: 2; } + /deep/ .jcdt-list { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; } + } + @media (max-width: 520px) { + /deep/ .jcdt-image-content { --visible-cards: 1; } + /deep/ .jcdt-list { grid-template-columns: minmax(0, 1fr) !important; } + } .jcdt-wrapper { width: 100%; background-size: cover; @@ -122,6 +272,8 @@ const jcdt = { } /deep/ .jcdt-item .date { + min-height: 28px; + line-height: 28px; font-size: 20px; font-weight: bold; white-space: nowrap; diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/apply/branchunionapproval/index.html b/src/main/resources/views/platform/zhgh/staffmanage/member/apply/branchunionapproval/index.html index 0e37bb1..a2c6899 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/apply/branchunionapproval/index.html +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/apply/branchunionapproval/index.html @@ -4,7 +4,7 @@ layout("/layouts/platform.html"){
- + diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/apply/common/commonQuery.html b/src/main/resources/views/platform/zhgh/staffmanage/member/apply/common/commonQuery.html index 19ed14a..5472504 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/apply/common/commonQuery.html +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/apply/common/commonQuery.html @@ -40,12 +40,6 @@ --> - - - - diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/apply/common/commonQuery.js b/src/main/resources/views/platform/zhgh/staffmanage/member/apply/common/commonQuery.js index db7164f..f1a36be 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/apply/common/commonQuery.js +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/apply/common/commonQuery.js @@ -1,12 +1,5 @@ const COMMON_QUERY = { template: "#member-apply-common-query-template", - props: { - // 默认保持原单选行为,仅由明确传参的页面开启人员属性多选。 - userAttributeMultiple: { - type: Boolean, - default: false - } - }, store, mixins: [initTableMixins], data() { @@ -21,8 +14,6 @@ const COMMON_QUERY = { personTypes: [], preparedBys: [], aidFundMemberUserType: '', - userAttribute: '', - userAttributes: [], } } }, @@ -32,7 +23,6 @@ const COMMON_QUERY = { pageForm.userStates = JSON.stringify(this.pageForm.userStates) pageForm.personTypes = JSON.stringify(this.pageForm.personTypes) pageForm.preparedBys = JSON.stringify(this.pageForm.preparedBys) - pageForm.userAttributes = JSON.stringify(this.pageForm.userAttributes) this.$emit('search', pageForm) }, async initData(){ diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/apply/mine/index.html b/src/main/resources/views/platform/zhgh/staffmanage/member/apply/mine/index.html index ea54da5..3884a7e 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/apply/mine/index.html +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/apply/mine/index.html @@ -4,7 +4,7 @@ layout("/layouts/platform.html"){
- + diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/apply/schoolunionapproval/index.html b/src/main/resources/views/platform/zhgh/staffmanage/member/apply/schoolunionapproval/index.html index 93881b8..e684ba4 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/apply/schoolunionapproval/index.html +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/apply/schoolunionapproval/index.html @@ -4,7 +4,7 @@ layout("/layouts/platform.html"){
- + diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/change/branchunionaudit/index.html b/src/main/resources/views/platform/zhgh/staffmanage/member/change/branchunionaudit/index.html index d78a842..ffc4c2b 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/change/branchunionaudit/index.html +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/change/branchunionaudit/index.html @@ -5,7 +5,7 @@ layout("/layouts/platform.html"){
- + diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/change/common/commonQuery.html b/src/main/resources/views/platform/zhgh/staffmanage/member/change/common/commonQuery.html index 97d56c7..524b219 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/change/common/commonQuery.html +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/change/common/commonQuery.html @@ -29,12 +29,5 @@ --> - - - - diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/change/common/commonQuery.js b/src/main/resources/views/platform/zhgh/staffmanage/member/change/common/commonQuery.js index 2fb4d15..07135ab 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/change/common/commonQuery.js +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/change/common/commonQuery.js @@ -1,12 +1,5 @@ const COMMON_QUERY = { template: "#member-change-common-query-template", - props: { - // 未显式开启时保持原单选行为,避免影响未列入本次范围的页面。 - userAttributeMultiple: { - type: Boolean, - default: false - } - }, store, mixins: [initTableMixins], data() { @@ -21,8 +14,6 @@ const COMMON_QUERY = { personTypes: [], preparedBys: [], aidFundMemberUserType: '', - userAttribute: '', - userAttributes: [], } } }, @@ -32,8 +23,6 @@ const COMMON_QUERY = { pageForm.userStates = JSON.stringify(this.pageForm.userStates) pageForm.personTypes = JSON.stringify(this.pageForm.personTypes) pageForm.preparedBys = JSON.stringify(this.pageForm.preparedBys) - // 多选人员属性沿用现有数组查询参数的JSON提交方式。 - pageForm.userAttributes = JSON.stringify(this.pageForm.userAttributes) this.$emit('search', pageForm) }, async initData(){ diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/change/common/info.js b/src/main/resources/views/platform/zhgh/staffmanage/member/change/common/info.js index 5e2ae63..705c804 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/change/common/info.js +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/change/common/info.js @@ -73,8 +73,8 @@ const INFO = { - - + @@ -144,6 +144,12 @@ const INFO = { activeName: "basicInfo", } }, + computed: { + // 人员属性不再展示,其他变更明细保持原有顺序,不改写后端返回的历史数据。 + visibleChangeInfos() { + return (this.viewData.changeInfos || []).filter((item) => item.field !== "userAttribute" && item.fieldName !== "人员属性") + } + }, methods: { // 打开 onOpen(row) { diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/change/common/memberAllChangeInfo.js b/src/main/resources/views/platform/zhgh/staffmanage/member/change/common/memberAllChangeInfo.js index 6364300..502d3a6 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/change/common/memberAllChangeInfo.js +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/change/common/memberAllChangeInfo.js @@ -1,5 +1,6 @@ const MEMBER_ALL_CHANGE_INFO = { template: /*language=HTML*/ ` +
@@ -61,9 +62,9 @@ const MEMBER_ALL_CHANGE_INFO = { - + -

{{ changeData.changeOriginName }}

@@ -87,6 +88,8 @@ const MEMBER_ALL_CHANGE_INFO = {
+ +
`, store, data(){ @@ -95,6 +98,16 @@ const MEMBER_ALL_CHANGE_INFO = { activeName: "basicInfo" } }, + computed: { + // 仅过滤展示的人员属性明细,保留原始历史;过滤后无明细的时间节点不展示。 + visibleChangeHistory() { + return (this.viewData.allChangeInfo || []).map((entry) => { + return Object.assign({}, entry, { + changeInfos: (entry.changeInfos || []).filter((item) => item.field !== "userAttribute" && item.fieldName !== "人员属性") + }) + }).filter((entry) => entry.changeInfos.length > 0) + } + }, methods:{ onOpen(userId){ this.$axios.post('/platform/member/change/manage/getAllChangeMemberInfo', {userId}) diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/change/common/memberChange.js b/src/main/resources/views/platform/zhgh/staffmanage/member/change/common/memberChange.js index fae0f78..4010843 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/change/common/memberChange.js +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/change/common/memberChange.js @@ -149,12 +149,6 @@ const MEMBER_CHANGE = { :disabled="allowFields('personType')" style="width: 100%"> - - - - - @@ -530,6 +524,7 @@ const MEMBER_CHANGE = { this.$set(this.formData, "userState", userState) this.$set(this.formData, "personType", personType) this.$set(this.formData, "preparedBy", preparedBy) + // 仅保留原值随表单传递,避免移除控件后被变更比较误判为清空。 this.$set(this.formData, "userAttribute", userAttribute) this.$set(this.formData, "aidFundMemberUserType", aidFundMemberUserType) this.$set(this.formData, "unitName", unit ? unit.name : null) diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/change/manage/index.html b/src/main/resources/views/platform/zhgh/staffmanage/member/change/manage/index.html index 4c4b0b7..e6d91f0 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/change/manage/index.html +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/change/manage/index.html @@ -50,10 +50,6 @@ layout("/layouts/platform.html"){ - - - - - 设置人员属性 - @@ -238,48 +230,6 @@ layout("/layouts/platform.html"){ - - - - - - - - - - - - - - - - - - - - - - - - - - - - 取消 - 确定 - - this.checkedFields.includes(item.prop)).map(item => { return {prop: item.prop, label: item.label} }) @@ -731,10 +667,6 @@ layout("/layouts/platform.html"){ this.$refs.table.clearSelection() }).catch(() => {}) }, - openBatchEditUserAttribute() { - this.batchFormDataUserAttribute = {} - this.batchEditUserAttributeVisible = true - }, openBatchEditMember() { this.batchFormDataMember = {member: false, welfareMember: false} this.batchEditMemberVisible = true @@ -785,23 +717,6 @@ layout("/layouts/platform.html"){ this.$set(this.unitMoveFormData, "unitName", "") } }, - async doBatchEditUserAttribute() { - const batch = this.checkUsers.map(v => { - return {id: v.id, userAttribute: v.userAttribute} - }) - this.batchEditLoading = true - const resp = await this.$axios.post("/platform/member/change/manage/batchUpdateUserAttribute", {users: JSON.stringify(batch)}) - if (resp.code === 0) { - this.$message.success(resp.msg) - this.pageData() - this.$refs.table.clearSelection() - this.batchEditUserAttributeVisible = false - this.checkUsers = [] - } else { - this.$message.error(resp.msg) - } - this.batchEditLoading = false - }, async doBatchEditMember() { const batch = this.checkUsers.map(v => { return {id: v.id, member: v.member, welfareMember: v.welfareMember} diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/change/mine/index.html b/src/main/resources/views/platform/zhgh/staffmanage/member/change/mine/index.html index f5f35f8..1f22f06 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/change/mine/index.html +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/change/mine/index.html @@ -4,7 +4,7 @@ layout("/layouts/platform.html"){
- + diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/change/record/index.html b/src/main/resources/views/platform/zhgh/staffmanage/member/change/record/index.html index 9651f50..918bfb3 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/change/record/index.html +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/change/record/index.html @@ -42,10 +42,6 @@ layout("/layouts/platform.html"){ --> - - - @@ -151,7 +147,6 @@ layout("/layouts/platform.html"){ personType: "", changeType: "", aidFundMemberUserType: "", - userAttributes: [] } } }, @@ -198,8 +193,6 @@ layout("/layouts/platform.html"){ pageForm.personTypes = JSON.stringify(pageForm.personTypes) pageForm.changeTypes = JSON.stringify(pageForm.changeTypes) pageForm.changeOrigins = JSON.stringify(pageForm.changeOrigins) - // 人员属性为多选条件,提交前转换为后端可解析的 JSON 数组。 - pageForm.userAttributes = JSON.stringify(pageForm.userAttributes) this.$axios.post(loc() + '/pageData', pageForm) .then(res => { diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/change/schoolunionaudit/index.html b/src/main/resources/views/platform/zhgh/staffmanage/member/change/schoolunionaudit/index.html index 92c4f93..cd128e7 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/change/schoolunionaudit/index.html +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/change/schoolunionaudit/index.html @@ -5,7 +5,7 @@ layout("/layouts/platform.html"){
- + diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/change/view/index.html b/src/main/resources/views/platform/zhgh/staffmanage/member/change/view/index.html index ed7f8a9..b35fcb6 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/change/view/index.html +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/change/view/index.html @@ -59,8 +59,8 @@ - - + + @@ -119,6 +119,12 @@ doneTasks: [] } }, + computed: { + // 人员属性不再展示,其他变更明细保持原有顺序,不改写后端返回的历史数据。 + visibleChangeInfos() { + return (this.viewData.changeInfos || []).filter((item) => item.field !== "userAttribute" && item.fieldName !== "人员属性") + } + }, methods: { info() { this.$axios.post("/platform/member/change/view/findMemberChangeRecord", { id: this.businessId }).then((res) => { diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/common/info/memberInfo.js b/src/main/resources/views/platform/zhgh/staffmanage/member/common/info/memberInfo.js index aa4c1c5..42ea6fa 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/common/info/memberInfo.js +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/common/info/memberInfo.js @@ -73,7 +73,6 @@ const MEMBER_INFO = { {{ viewData.personType }} - {{ viewData.userAttribute }} {{ viewData.professionalTitle }} {{ viewData.professionalLevel }} @@ -85,6 +84,7 @@ const MEMBER_INFO = { {{ viewData.administrativePositionLevel }} {{ viewData.aidFundMemberUserType }} +
`, store, diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/info/common/commonQuery.html b/src/main/resources/views/platform/zhgh/staffmanage/member/info/common/commonQuery.html index eedae74..ad8e536 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/info/common/commonQuery.html +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/info/common/commonQuery.html @@ -43,9 +43,5 @@ --> - - - diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/info/common/commonQuery.js b/src/main/resources/views/platform/zhgh/staffmanage/member/info/common/commonQuery.js index b5722e2..fe2a4e3 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/info/common/commonQuery.js +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/info/common/commonQuery.js @@ -22,7 +22,6 @@ const COMMON_QUERY = { personTypes: [], preparedBys: [], aidFundMemberUserType: '', - userAttributes: [], } } }, @@ -37,8 +36,6 @@ const COMMON_QUERY = { pageForm.userStates = JSON.stringify(this.pageForm.userStates) pageForm.personTypes = JSON.stringify(this.pageForm.personTypes) pageForm.preparedBys = JSON.stringify(this.pageForm.preparedBys) - // 人员属性多选值按现有数组查询参数口径提交。 - pageForm.userAttributes = JSON.stringify(this.pageForm.userAttributes) this.$emit('search', pageForm) }, handleUnionChange() { diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/info/common/memberAddForm.js b/src/main/resources/views/platform/zhgh/staffmanage/member/info/common/memberAddForm.js index f4c3eb3..0181912 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/info/common/memberAddForm.js +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/info/common/memberAddForm.js @@ -102,12 +102,6 @@ style="width: 100%"> - - - - - - - - @@ -102,7 +98,7 @@ layout("/layouts/platform.html"){ new Vue({ el: "#app", mixins: [initTableMixins], - dicts: ["USER_STATE", "USER_PERSON_TYPE", "MEMBER_CHANGE_TYPE", "AIDFUND_MEMBER_USER_TYPE", "USER_ATTRIBUTE"], + dicts: ["USER_STATE", "USER_PERSON_TYPE", "MEMBER_CHANGE_TYPE", "AIDFUND_MEMBER_USER_TYPE"], data() { return { pageForm: { @@ -110,7 +106,6 @@ layout("/layouts/platform.html"){ memberSearchName: "", memberSearchKeyWord: "", aidFundMemberUserType: "", - userAttributes: [] }, userId: "", unions: [], @@ -133,16 +128,6 @@ layout("/layouts/platform.html"){ "member-info": MEMBER_INFO }, methods: { - // 分页和导出共用该参数构建方法,保证人员属性多选值始终按 JSON 数组提交。 - buildQueryPageForm() { - const pageForm = clone(this.pageForm) - pageForm.userAttributes = JSON.stringify(this.pageForm.userAttributes || []) - return pageForm - }, - // 覆盖公共分页方法,使后端按人员属性集合执行查询。 - pageData() { - return initTableMixins.methods.pageData.call(this, this.buildQueryPageForm()) - }, openView(row) { this.$refs.guava.view(() => { this.$refs.memberInfoRef.onOpen(row.id) @@ -152,7 +137,7 @@ layout("/layouts/platform.html"){ this.$downLoad("/platform/member/info/history/doExportByUnion", { year: this.pageForm.year }) }, doExport() { - this.$downLoad("/platform/member/info/history/doExport", this.buildQueryPageForm()) + this.$downLoad("/platform/member/info/history/doExport", clone(this.pageForm)) }, async initData() { if (this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])) { diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/info/input/index.html b/src/main/resources/views/platform/zhgh/staffmanage/member/info/input/index.html index 3ec4178..7647779 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/info/input/index.html +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/info/input/index.html @@ -49,10 +49,6 @@ layout("/layouts/platform.html"){ - - - @@ -109,11 +105,10 @@ layout("/layouts/platform.html"){ new Vue({ el: "#app", mixins: [initTableMixins], - dicts: ["USER_STATE", "USER_PERSON_TYPE", "MEMBER_CHANGE_TYPE","AIDFUND_MEMBER_USER_TYPE","USER_ATTRIBUTE"], + dicts: ["USER_STATE", "USER_PERSON_TYPE", "MEMBER_CHANGE_TYPE","AIDFUND_MEMBER_USER_TYPE"], data() { return { pageForm: { - userAttributes: [], year: new Date().getFullYear() + "", memberSearchName: "", memberSearchKeyWord: "" @@ -141,12 +136,6 @@ layout("/layouts/platform.html"){ "member-add-form": MEMBER_ADD_FORM }, methods: { - // 人员属性为多选条件,分页查询前统一转换为后端可接收的 JSON 数组。 - pageData(data = null) { - const pageForm = clone(data || this.pageForm) - pageForm.userAttributes = JSON.stringify(this.pageForm.userAttributes || []) - return initTableMixins.methods.pageData.call(this, pageForm) - }, openAdd() { this.$refs.guava.edit(() => { this.$refs.memberAddFormRef.onOpen() diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/statistics/analysis/index.html b/src/main/resources/views/platform/zhgh/staffmanage/member/statistics/analysis/index.html index 9aa148f..faf2503 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/statistics/analysis/index.html +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/statistics/analysis/index.html @@ -129,29 +129,6 @@ layout("/layouts/platform.html"){ - - 人员属性: - - @@ -237,12 +214,10 @@ layout("/layouts/platform.html"){ units: [], personTypeOptions: [], aidFundMemberUserTypeOptions: [], - userAttributeOptions: [], pageForm: { currentYear: moment().format("YYYY"), queryType: "fgh", personTypes: [], - userAttributes: [], aidFundMemberUserTypes: [] }, fullTableData: [] @@ -271,16 +246,11 @@ layout("/layouts/platform.html"){ this.$businessTool.getDictOptions("AIDFUND_MEMBER_USER_TYPE").then((data) => { this.aidFundMemberUserTypeOptions = data }) - this.$businessTool.getDictOptions("USER_ATTRIBUTE").then((data) => { - this.userAttributeOptions = data - }) }, pageData() { - // 统计接口按 JSON 字符串接收多选条件,这里统一在提交前做转换,保证人员分类和人员属性都能正确过滤。 const pageForm = clone(this.pageForm) pageForm.personTypes = JSON.stringify(this.pageForm.personTypes) pageForm.aidFundMemberUserTypes = JSON.stringify(this.pageForm.aidFundMemberUserTypes) - pageForm.userAttributes = JSON.stringify(this.pageForm.userAttributes) this.$axios.post(loc() + "/pageData", pageForm).then((res) => { if (res.code === 0) { this.tableData = res.data @@ -296,13 +266,6 @@ layout("/layouts/platform.html"){ this.pageForm.personTypes.push(code) } } - if (key === "userAttributes") { - if (this.pageForm.userAttributes.includes(code)) { - this.pageForm.userAttributes.splice(this.pageForm.userAttributes.indexOf(code), 1) - } else { - this.pageForm.userAttributes.push(code) - } - } if (key === "aidFundMemberUserTypes") { if (this.pageForm.aidFundMemberUserTypes.includes(code)) { this.pageForm.aidFundMemberUserTypes.splice(this.pageForm.aidFundMemberUserTypes.indexOf(code), 1) diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/statistics/comprehensive/index.html b/src/main/resources/views/platform/zhgh/staffmanage/member/statistics/comprehensive/index.html index 42c0013..980dd53 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/statistics/comprehensive/index.html +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/statistics/comprehensive/index.html @@ -165,7 +165,6 @@ layout("/layouts/platform.html"){ { prop: "unitName", label: "所属单位", width: 120, sortable: true }, // 临时屏蔽“人员分类”列表字段,不删除配置,后续需要可恢复。 // { prop: "aidFundMemberUserType", label: "人员分类", width: 120, sortable: true }, - { prop: "userAttribute", label: "人员属性", width: 120, sortable: true }, { prop: "idCardType", label: "证件类型", width: 120, sortable: true, checked: 0 }, { prop: "idCard", label: "证件号码", width: 120, sortable: true, checked: 0 }, { prop: "marriage", label: "婚姻状况", width: 120, sortable: true, checked: 0 }, @@ -205,7 +204,6 @@ layout("/layouts/platform.html"){ pageForm.memberTypes = JSON.stringify(this.pageForm.memberTypes) pageForm.personTypes = JSON.stringify(this.pageForm.personTypes) pageForm.aidFundMemberUserTypes = JSON.stringify(this.pageForm.aidFundMemberUserTypes) - pageForm.userAttributes = JSON.stringify(this.pageForm.userAttributes) pageForm.userStates = JSON.stringify(this.pageForm.userStates) const data = this.tableColumns.filter(item => this.checkedFields.includes(item.prop)).map(item => { return {prop: item.prop, label: item.label} @@ -230,7 +228,6 @@ layout("/layouts/platform.html"){ pageForm.memberTypes = JSON.stringify(this.pageForm.memberTypes) pageForm.personTypes = JSON.stringify(this.pageForm.personTypes) pageForm.aidFundMemberUserTypes = JSON.stringify(this.pageForm.aidFundMemberUserTypes) - pageForm.userAttributes = JSON.stringify(this.pageForm.userAttributes) pageForm.preparedBys = JSON.stringify(this.pageForm.preparedBys) pageForm.memberStatus = JSON.stringify(this.pageForm.memberStatus) pageForm.userStates = JSON.stringify(this.pageForm.userStates) diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/statistics/comprehensive/queryForm.js b/src/main/resources/views/platform/zhgh/staffmanage/member/statistics/comprehensive/queryForm.js index ec1a83c..3fc020c 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/statistics/comprehensive/queryForm.js +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/statistics/comprehensive/queryForm.js @@ -113,30 +113,6 @@ const MEMBER_STATISTICS_COMPREHENSIVE_QUERY_FORM = { - - 人员属性: - - @@ -235,7 +211,6 @@ const MEMBER_STATISTICS_COMPREHENSIVE_QUERY_FORM = { personTypes: [], preparedBys: [], aidFundMemberUserTypes: [], - userAttributes: [], userStates: [], memberStatus: [], year: moment().format("YYYY"), @@ -253,7 +228,6 @@ const MEMBER_STATISTICS_COMPREHENSIVE_QUERY_FORM = { personTypeOptions: [], preparedByOptions: [], aidFundMemberUserTypeOptions: [], - userAttributeOptions: [], userStateOptions: [], memberStatusOptions: [], unions: [], @@ -346,7 +320,6 @@ const MEMBER_STATISTICS_COMPREHENSIVE_QUERY_FORM = { this.pageForm.personTypes = [] this.pageForm.preparedBys = [] this.pageForm.aidFundMemberUserTypes = [] - this.pageForm.userAttributes = [] this.pageForm.memberStatus = [] this.pageForm.userStates = [] this.pageForm.unionId = [] @@ -387,9 +360,6 @@ const MEMBER_STATISTICS_COMPREHENSIVE_QUERY_FORM = { this.$businessTool.getDictOptions("AIDFUND_MEMBER_USER_TYPE").then((data) => { this.aidFundMemberUserTypeOptions = data }) - this.$businessTool.getDictOptions("USER_ATTRIBUTE").then((data) => { - this.userAttributeOptions = data - }) this.$businessTool.getDictOptions("USER_STATE").then((data) => { this.userStateOptions = data }) diff --git a/src/main/resources/views/platform/zhgh/staffmanage/member/statistics/summary/index.html b/src/main/resources/views/platform/zhgh/staffmanage/member/statistics/summary/index.html index c9331c1..d27c333 100644 --- a/src/main/resources/views/platform/zhgh/staffmanage/member/statistics/summary/index.html +++ b/src/main/resources/views/platform/zhgh/staffmanage/member/statistics/summary/index.html @@ -129,29 +129,6 @@ layout("/layouts/platform.html"){ - - 人员属性: - - @@ -198,12 +175,10 @@ layout("/layouts/platform.html"){ unions: [], units: [], personTypeOptions: [], - userAttributeOptions: [], pageForm: { currentYear: moment().format("YYYY"), queryType: "fgh", personTypes: [], - userAttributes: [], aidFundMemberUserTypes: [] }, aidFundMemberUserTypeOptions: [], @@ -232,9 +207,6 @@ layout("/layouts/platform.html"){ this.$businessTool.getDictOptions("AIDFUND_MEMBER_USER_TYPE").then((data) => { this.aidFundMemberUserTypeOptions = data }) - this.$businessTool.getDictOptions("USER_ATTRIBUTE").then((data) => { - this.userAttributeOptions = data - }) }, tagClick(key,code) { if (key === "personTypes") { @@ -244,13 +216,6 @@ layout("/layouts/platform.html"){ this.pageForm.personTypes.push(code) } } - if (key === "userAttributes") { - if (this.pageForm.userAttributes.includes(code)) { - this.pageForm.userAttributes.splice(this.pageForm.userAttributes.indexOf(code), 1) - } else { - this.pageForm.userAttributes.push(code) - } - } if (key === "aidFundMemberUserTypes") { if (this.pageForm.aidFundMemberUserTypes.includes(code)) { this.pageForm.aidFundMemberUserTypes.splice(this.pageForm.aidFundMemberUserTypes.indexOf(code), 1) @@ -262,10 +227,8 @@ layout("/layouts/platform.html"){ }, pageData() { const pageForm = clone(this.pageForm) - // 统计接口按 JSON 字符串接收多选条件,这里把人员分类和人员属性统一成同一提交口径。 pageForm.personTypes = JSON.stringify(this.pageForm.personTypes) pageForm.aidFundMemberUserTypes = JSON.stringify(this.pageForm.aidFundMemberUserTypes) - pageForm.userAttributes = JSON.stringify(this.pageForm.userAttributes) this.$axios.post(loc() + "/pageData", pageForm).then((res) => { if (res.code === 0) { this.tableData = res.data