commit
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>com.budwk</groupId>
|
<groupId>com.budwk</groupId>
|
||||||
<artifactId>zhgh_cug_v4</artifactId>
|
<artifactId>mini</artifactId>
|
||||||
<version>5.6.0-plus</version>
|
<version>5.6.0-plus</version>
|
||||||
<build>
|
<build>
|
||||||
<resources>
|
<resources>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<groupId>com.budwk</groupId>
|
<groupId>com.budwk</groupId>
|
||||||
<artifactId>zhgh_cug_v4</artifactId>
|
<artifactId>mini</artifactId>
|
||||||
<version>5.6.0-plus</version>
|
<version>5.6.0-plus</version>
|
||||||
<properties>
|
<properties>
|
||||||
<nutzboot.version>2.6.0-SNAPSHOT</nutzboot.version>
|
<nutzboot.version>2.6.0-SNAPSHOT</nutzboot.version>
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ public class DataCenterProperties {
|
|||||||
private String tokenUrl;
|
private String tokenUrl;
|
||||||
private String key;
|
private String key;
|
||||||
private String secret;
|
private String secret;
|
||||||
|
/** 人员和单位接口共用的请求头 apiKey。 */
|
||||||
|
private String apiKey;
|
||||||
private Map<String, String> urls = new HashMap<>();
|
private Map<String, String> urls = new HashMap<>();
|
||||||
|
|
||||||
public void init() {
|
public void init() {
|
||||||
@@ -34,6 +36,7 @@ public class DataCenterProperties {
|
|||||||
tokenUrl = all.get("data-center.token-url");
|
tokenUrl = all.get("data-center.token-url");
|
||||||
key = all.get("data-center.key");
|
key = all.get("data-center.key");
|
||||||
secret = all.get("data-center.secret");
|
secret = all.get("data-center.secret");
|
||||||
|
apiKey = all.get("data-center.api-key");
|
||||||
extract(all, "data-center.urls.", urls);
|
extract(all, "data-center.urls.", urls);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import com.budwk.app.sys.services.SysDataUserPullService;
|
|||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import io.swagger.annotations.ApiOperation;
|
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.Cnd;
|
||||||
import org.nutz.dao.Sqls;
|
import org.nutz.dao.Sqls;
|
||||||
import org.nutz.dao.sql.Sql;
|
import org.nutz.dao.sql.Sql;
|
||||||
@@ -64,6 +66,8 @@ public class SysDataUserPullController {
|
|||||||
@At
|
@At
|
||||||
@SaCheckPermission("sys.data.user.pull")
|
@SaCheckPermission("sys.data.user.pull")
|
||||||
@ApiOperation("拉取用户数据")
|
@ApiOperation("拉取用户数据")
|
||||||
|
// 无请求参数;service拉取完整批次,返回Result的code=0表示同步到本地数据源成功。
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
public Result pullData() {
|
public Result pullData() {
|
||||||
sysUserPullService.pull();
|
sysUserPullService.pull();
|
||||||
return Result.success();
|
return Result.success();
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ import io.swagger.annotations.Api;
|
|||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import org.nutz.dao.Cnd;
|
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.Sqls;
|
||||||
import org.nutz.dao.sql.Sql;
|
import org.nutz.dao.sql.Sql;
|
||||||
import org.nutz.ioc.Ioc;
|
import org.nutz.ioc.Ioc;
|
||||||
@@ -118,10 +120,15 @@ public class SysDataUserUpdateController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新单位数据,无请求参数;由service读取接口配置并同步全部单位。
|
||||||
|
* 返回Result对象,code=0表示全部同步成功,失败时由统一异常处理返回错误信息。
|
||||||
|
*/
|
||||||
@At
|
@At
|
||||||
@SaCheckPermission("sys.data.user.pull")
|
@SaCheckPermission("sys.data.user.pull")
|
||||||
@SLog(tag = "更新单位数据", msg = "更新单位数据")
|
@SLog(tag = "更新单位数据", msg = "更新单位数据")
|
||||||
@ApiOperation("更新单位数据")
|
@ApiOperation("更新单位数据")
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
public Result updateUnits(){
|
public Result updateUnits(){
|
||||||
sysDataUnitPullService.updateUnits();
|
sysDataUnitPullService.updateUnits();
|
||||||
return Result.success();
|
return Result.success();
|
||||||
|
|||||||
@@ -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_home_template;
|
||||||
import com.budwk.app.sys.models.Sys_menu;
|
import com.budwk.app.sys.models.Sys_menu;
|
||||||
import com.budwk.app.sys.services.SysMenuService;
|
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.sys.services.SysUserService;
|
||||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||||
import com.budwk.app.zhgh.activity.basic.service.ActivityBasicScopeService;
|
import com.budwk.app.zhgh.activity.basic.service.ActivityBasicScopeService;
|
||||||
import io.swagger.annotations.ApiOperation;
|
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.Cnd;
|
||||||
import org.nutz.dao.Dao;
|
import org.nutz.dao.Dao;
|
||||||
import org.nutz.dao.FieldFilter;
|
import org.nutz.dao.FieldFilter;
|
||||||
import org.nutz.dao.Sqls;
|
import org.nutz.dao.Sqls;
|
||||||
import org.nutz.dao.sql.Sql;
|
import org.nutz.dao.sql.Sql;
|
||||||
import org.nutz.dao.util.Daos;
|
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.Inject;
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
import org.nutz.json.Json;
|
|
||||||
import org.nutz.lang.Lang;
|
import org.nutz.lang.Lang;
|
||||||
import org.nutz.lang.Strings;
|
import org.nutz.lang.Strings;
|
||||||
import org.nutz.lang.util.NutMap;
|
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.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -58,7 +52,7 @@ public class SysHomeController {
|
|||||||
@Inject
|
@Inject
|
||||||
private SysUserService sysUserService;
|
private SysUserService sysUserService;
|
||||||
@Inject
|
@Inject
|
||||||
private RedisService redisService;
|
private SysHomeNewsService sysHomeNewsService;
|
||||||
@Inject
|
@Inject
|
||||||
private ActivityBasicScopeService activityBasicScopeService;
|
private ActivityBasicScopeService activityBasicScopeService;
|
||||||
|
|
||||||
@@ -289,38 +283,14 @@ public class SysHomeController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 无请求参数;Result.data为六栏目列表,label为栏目名,value为标题、日期、原文链接及可选图片的列表。
|
||||||
|
*/
|
||||||
@At
|
@At
|
||||||
@SaCheckLogin
|
@SaCheckLogin
|
||||||
@ApiOperation("获取新闻")
|
@ApiOperation("获取岭南工会首页新闻")
|
||||||
@Ok("json")
|
@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() {
|
public Result getNews() {
|
||||||
try {
|
return Result.success(sysHomeNewsService.getNews());
|
||||||
String url = "https://xgh.cug.edu.cn/";
|
|
||||||
Document document = Jsoup.connect(url).get();
|
|
||||||
Elements homeElements = document.select(".gh,.jc,.fc,.jg");
|
|
||||||
|
|
||||||
List<Map<String, Object>> news = homeElements.stream().map(homeElement -> {
|
|
||||||
//获取板块名称
|
|
||||||
String name = homeElement.selectFirst(".title").text();
|
|
||||||
Elements liElements = homeElement.select("li");
|
|
||||||
List<NutMap> 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,6 @@ package com.budwk.app.sys.controller;
|
|||||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
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 cn.hutool.core.util.StrUtil;
|
||||||
import com.budwk.app.base.annotation.SLog;
|
import com.budwk.app.base.annotation.SLog;
|
||||||
import com.budwk.app.base.constant.RoleConstant;
|
import com.budwk.app.base.constant.RoleConstant;
|
||||||
@@ -49,7 +45,6 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -295,34 +290,15 @@ public class SysUnitController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pid为可选根单位ID,未传时使用学校单位1;返回Result包装的单位树,children表示下级单位。
|
||||||
|
*/
|
||||||
@At("/tree")
|
@At("/tree")
|
||||||
@Ok("json")
|
@Ok("json")
|
||||||
@SaCheckLogin
|
@SaCheckLogin
|
||||||
public Object tree(@Param("pid") String pid, HttpServletRequest req) {
|
public Object tree(@Param("pid") String pid, HttpServletRequest req) {
|
||||||
try {
|
try {
|
||||||
String rootId = StrUtil.blankToDefault(pid, "0");
|
return Result.success(sysUnitService.getUnitTree(pid));
|
||||||
String virtualRootId = "root";
|
|
||||||
Cnd cnd = Cnd.NEW();
|
|
||||||
cnd.asc("unitcode");
|
|
||||||
List<Sys_unit> list = sysUnitService.query(cnd);
|
|
||||||
|
|
||||||
List<TreeNode<String>> 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<Tree<String>> treeList = TreeUtil.build(nodeList, virtualRootId);
|
|
||||||
return Result.success(treeList);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return Result.error();
|
return Result.error();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public class Sys_user extends BaseModel implements Serializable {
|
|||||||
@Column
|
@Column
|
||||||
@Comment("工号")
|
@Comment("工号")
|
||||||
@ColDefine(type = ColType.VARCHAR, width = 120)
|
@ColDefine(type = ColType.VARCHAR, width = 120)
|
||||||
@DataCenterColumn(name = "工号", key = "ZGH")
|
@DataCenterColumn(name = "工号", key = "GH")
|
||||||
private String loginname;
|
private String loginname;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@@ -49,7 +49,7 @@ public class Sys_user extends BaseModel implements Serializable {
|
|||||||
@Column
|
@Column
|
||||||
@Comment("性别")
|
@Comment("性别")
|
||||||
@ColDefine(type = ColType.VARCHAR, width = 10)
|
@ColDefine(type = ColType.VARCHAR, width = 10)
|
||||||
@DataCenterColumn(name = "性别", key = "XB", dict = "USER_SEX")
|
@DataCenterColumn(name = "性别", key = "XB")
|
||||||
private String sex;
|
private String sex;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@@ -70,7 +70,7 @@ public class Sys_user extends BaseModel implements Serializable {
|
|||||||
@Column
|
@Column
|
||||||
@Comment("政治面貌")
|
@Comment("政治面貌")
|
||||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
@DataCenterColumn(name = "政治面貌", key = "ZZMMM", dict = "USER_POLITICAL")
|
@DataCenterColumn(name = "政治面貌", key = "ZZMM", dict = "USER_POLITICAL")
|
||||||
private String political;
|
private String political;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@@ -81,7 +81,7 @@ public class Sys_user extends BaseModel implements Serializable {
|
|||||||
@Column
|
@Column
|
||||||
@Comment("民族")
|
@Comment("民族")
|
||||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||||
@DataCenterColumn(name = "民族", key = "MZM", dict = "USER_NATION")
|
@DataCenterColumn(name = "民族", key = "MZ", dict = "USER_NATION")
|
||||||
private String nation;
|
private String nation;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@@ -114,17 +114,19 @@ public class Sys_user extends BaseModel implements Serializable {
|
|||||||
@Column
|
@Column
|
||||||
@Comment("学历")
|
@Comment("学历")
|
||||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||||
|
@DataCenterColumn(name = "最高学历", key = "ZGXL")
|
||||||
private String education;
|
private String education;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@Comment("婚姻状况")
|
@Comment("婚姻状况")
|
||||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||||
|
@DataCenterColumn(name = "婚姻状况", key = "HYZK")
|
||||||
private String marriage;
|
private String marriage;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@Comment("学位")
|
@Comment("学位")
|
||||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||||
// @DataCenterColumn(name = "学位", key = "zgxwmc")
|
@DataCenterColumn(name = "学位", key = "ZGXW")
|
||||||
private String academicDegree;
|
private String academicDegree;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@@ -135,8 +137,16 @@ public class Sys_user extends BaseModel implements Serializable {
|
|||||||
@Column
|
@Column
|
||||||
@Comment("职称")
|
@Comment("职称")
|
||||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||||
|
@DataCenterColumn(name = "当前职称", key = "DQZC")
|
||||||
private String professionalTitle;
|
private String professionalTitle;
|
||||||
|
|
||||||
|
/** 信息中心 DQZW 为当前职务,与职称、职级分别保存。 */
|
||||||
|
@Column
|
||||||
|
@Comment("当前职务")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
@DataCenterColumn(name = "当前职务", key = "DQZW")
|
||||||
|
private String position;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@Comment("职级")
|
@Comment("职级")
|
||||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||||
@@ -175,7 +185,7 @@ public class Sys_user extends BaseModel implements Serializable {
|
|||||||
@Column
|
@Column
|
||||||
@Comment("来校时间")
|
@Comment("来校时间")
|
||||||
@ColDefine(type = ColType.VARCHAR, width = 10)
|
@ColDefine(type = ColType.VARCHAR, width = 10)
|
||||||
@DataCenterColumn(name = "来校时间", key = "LXNY")
|
@DataCenterColumn(name = "来校时间", key = "LXRQ")
|
||||||
private String arrivalAtSchoolDate;
|
private String arrivalAtSchoolDate;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@@ -208,7 +218,7 @@ public class Sys_user extends BaseModel implements Serializable {
|
|||||||
@Column
|
@Column
|
||||||
@Comment("教职工类别码")
|
@Comment("教职工类别码")
|
||||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
@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;
|
private String personType;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@@ -220,6 +230,7 @@ public class Sys_user extends BaseModel implements Serializable {
|
|||||||
@Column
|
@Column
|
||||||
@Comment("编制类别码")
|
@Comment("编制类别码")
|
||||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||||
|
@DataCenterColumn(name = "编制类别", key = "BZLB")
|
||||||
private String preparedBy;
|
private String preparedBy;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@@ -269,12 +280,13 @@ public class Sys_user extends BaseModel implements Serializable {
|
|||||||
|
|
||||||
@Column
|
@Column
|
||||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
@DataCenterColumn(name = "单位", key = "SZDWH")
|
@DataCenterColumn(name = "二级单位", key = "SZEJDWH")
|
||||||
private String unitId;
|
private String unitId;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@Comment("三级单位ID")
|
@Comment("三级单位ID")
|
||||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
@DataCenterColumn(name = "三级单位", key = "SZDWH")
|
||||||
private String threeUnitId;
|
private String threeUnitId;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@@ -343,6 +355,7 @@ public class Sys_user extends BaseModel implements Serializable {
|
|||||||
@Column
|
@Column
|
||||||
@Comment("校区")
|
@Comment("校区")
|
||||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||||
|
@DataCenterColumn(name = "校区", key = "XQH")
|
||||||
private String campus;
|
private String campus;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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<NutMap> getNews();
|
||||||
|
}
|
||||||
@@ -1,14 +1,25 @@
|
|||||||
package com.budwk.app.sys.services;
|
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.page.Pagination;
|
||||||
import com.budwk.app.base.param.PageForm;
|
import com.budwk.app.base.param.PageForm;
|
||||||
import com.budwk.app.base.service.BaseService;
|
import com.budwk.app.base.service.BaseService;
|
||||||
import com.budwk.app.sys.models.Sys_unit;
|
import com.budwk.app.sys.models.Sys_unit;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by wizzer on 2016/12/22.
|
* Created by wizzer on 2016/12/22.
|
||||||
*/
|
*/
|
||||||
public interface SysUnitService extends BaseService<Sys_unit> {
|
public interface SysUnitService extends BaseService<Sys_unit> {
|
||||||
|
/**
|
||||||
|
* 获取包含指定单位自身及其下级的单位树。
|
||||||
|
*
|
||||||
|
* @param pid 根单位ID;为空或空白时使用信息中心学校单位ID“1”
|
||||||
|
* @return 单位树列表;节点包含id、parentId、name、unitTypeCode及children,根单位不存在时返回空列表
|
||||||
|
*/
|
||||||
|
List<Tree<String>> getUnitTree(String pid);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页查询指定分工会的组成单位。
|
* 分页查询指定分工会的组成单位。
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
package com.budwk.app.sys.services.impl;
|
package com.budwk.app.sys.services.impl;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.core.util.URLUtil;
|
import cn.hutool.http.HttpResponse;
|
||||||
import cn.hutool.http.Header;
|
|
||||||
import cn.hutool.http.HttpRequest;
|
|
||||||
import cn.hutool.http.HttpUtil;
|
import cn.hutool.http.HttpUtil;
|
||||||
import cn.hutool.json.JSONArray;
|
import cn.hutool.json.JSONArray;
|
||||||
import cn.hutool.json.JSONObject;
|
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.Inject;
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
@@ -31,18 +27,14 @@ import java.util.Set;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @version 1.0
|
* 岭南师范学院单位同步:通过 apiKey 认证分页获取组织机构,并按单位编码更新本地单位。
|
||||||
* @Author zzr
|
|
||||||
* @name:SysDataUnitPullServiceImpl
|
|
||||||
* @Date 2025/9/15 17:52
|
|
||||||
* @注释
|
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@IocBean(args = {"refer:dao"})
|
@IocBean(args = {"refer:dao"})
|
||||||
public class SysDataUnitPullServiceImpl extends BaseServiceImpl<Sys_unit> implements SysDataUnitPullService {
|
public class SysDataUnitPullServiceImpl extends BaseServiceImpl<Sys_unit> implements SysDataUnitPullService {
|
||||||
|
|
||||||
private static final String DMP_UNIT_KEY = "unit";
|
private static final int UNIT_PAGE_SIZE = 100;
|
||||||
private static final int DMP_PAGE_SIZE = 1000;
|
private static final int REQUEST_TIMEOUT = 30000;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private DataCenterProperties dataCenterProperties;
|
private DataCenterProperties dataCenterProperties;
|
||||||
@@ -51,7 +43,9 @@ public class SysDataUnitPullServiceImpl extends BaseServiceImpl<Sys_unit> implem
|
|||||||
super(dao);
|
super(dao);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手动更新入口,无需参数、无返回值;全部分页拉取并校验成功后更新 sys_unit。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
@Aop(TransAop.READ_COMMITTED)
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
public void updateUnits() {
|
public void updateUnits() {
|
||||||
@@ -59,192 +53,167 @@ public class SysDataUnitPullServiceImpl extends BaseServiceImpl<Sys_unit> implem
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 拉取单位数据
|
* 人员拉取时复用的单位同步入口。
|
||||||
|
* unitIds 是调用方已有的本地单位编码列表,仅用于日志,不限制同步范围,以保证父级齐全;
|
||||||
|
* 无返回值,接口或入库失败时抛出异常,由事务回滚本次单位变更。
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@Aop(TransAop.READ_COMMITTED)
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
public void updateUnits(List<String> unitIds) {
|
public void updateUnits(List<String> unitIds) {
|
||||||
String accessToken = getDmpAccessToken();
|
List<JSONObject> units = pullUnits();
|
||||||
List<JSONObject> rawDataList = distinctDmpUnits(pullDmpUnits(getDmpUnitUrl(), accessToken));
|
Set<String> parentCodes = units.stream()
|
||||||
Set<String> parentCodes = rawDataList.stream()
|
|
||||||
.map(this::getNormalizedParentCode)
|
.map(this::getNormalizedParentCode)
|
||||||
.filter(StrUtil::isNotBlank)
|
.filter(StrUtil::isNotBlank)
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
rawDataList.stream()
|
// DWDJ 为外部单位等级,父级先入库后,子级才能获取正确的父级及树路径。
|
||||||
.sorted(Comparator.comparingInt(this::getUnitLevel))
|
units.sort(Comparator.comparingInt(raw -> raw.getInt("DWDJ")));
|
||||||
.forEach(raw -> saveOrUpdateUnit(raw, parentCodes));
|
for (JSONObject raw : units) {
|
||||||
|
saveOrUpdateUnit(raw, parentCodes);
|
||||||
log.info("信息中心单位数据同步完成,本次接口返回单位数量: {},待检查单位编码数量: {}", rawDataList.size(), unitIds == null ? 0 : unitIds.size());
|
}
|
||||||
|
log.info("单位数据同步完成,单位数量: {},调用方已有单位编码数量: {}",
|
||||||
|
units.size(), unitIds == null ? 0 : unitIds.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取信息中心开放平台访问令牌。
|
* 从配置读取 data-center.urls.unit 和 data-center.api-key,无方法参数。
|
||||||
* 参数来自 data-center.token-url、data-center.key、data-center.secret;
|
* GET 查询参数 pageNum 从 1 开始,pageSize 为每页条数,请求头 apiKey 为接口密钥;
|
||||||
* 返回值为后续单位接口 body 中 access_token 使用的字符串。
|
* status=0 表示成功,payload 包含 pageNo、pageSize、totalCount 及 resultList 单位对象数组。
|
||||||
|
* 返回全部分页按 DWMCDM 去重后的 JSON 列表;分页不完整或字段不合法时抛出异常,不写入部分数据。
|
||||||
*/
|
*/
|
||||||
private String getDmpAccessToken() {
|
private List<JSONObject> pullUnits() {
|
||||||
String tokenUrl = dataCenterProperties.getTokenUrl();
|
String url = dataCenterProperties.getUrls().get("unit");
|
||||||
if (StrUtil.isBlank(tokenUrl)) {
|
String apiKey = dataCenterProperties.getApiKey();
|
||||||
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);
|
|
||||||
if (StrUtil.isBlank(url)) {
|
if (StrUtil.isBlank(url)) {
|
||||||
throw new BaseException("未配置信息中心单位接口地址: data-center.urls." + DMP_UNIT_KEY);
|
throw new BaseException("未配置单位接口地址: data-center.urls.unit");
|
||||||
}
|
}
|
||||||
return url;
|
if (StrUtil.isBlank(apiKey)) {
|
||||||
|
throw new BaseException("未配置单位接口密钥: data-center.api-key");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 分页拉取单位接口数据。
|
|
||||||
* 入参 url 为单位接口地址,accessToken 为信息中心令牌;
|
|
||||||
* 请求 body 包含 access_token、per_page、page;
|
|
||||||
* 返回值为 result.data 合并后的单位原始 JSON 列表。
|
|
||||||
*/
|
|
||||||
private List<JSONObject> pullDmpUnits(String url, String accessToken) {
|
|
||||||
List<JSONObject> 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<JSONObject> distinctDmpUnits(List<JSONObject> rawDataList) {
|
|
||||||
Map<String, JSONObject> unitMap = new LinkedHashMap<>();
|
Map<String, JSONObject> unitMap = new LinkedHashMap<>();
|
||||||
for (JSONObject raw : rawDataList) {
|
int pageNum = 1;
|
||||||
String unitCode = raw.getStr("DWDM");
|
int pageSize = UNIT_PAGE_SIZE;
|
||||||
if (StrUtil.isBlank(unitCode)) {
|
long totalCount = -1;
|
||||||
continue;
|
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());
|
||||||
}
|
}
|
||||||
unitMap.putIfAbsent(unitCode, raw);
|
String responseBody = response.body();
|
||||||
|
if (!JSONUtil.isTypeJSONObject(responseBody)) {
|
||||||
|
throw new BaseException("获取单位数据失败,第{}页返回内容不是JSON对象", pageNum);
|
||||||
}
|
}
|
||||||
|
body = JSONUtil.parseObj(responseBody);
|
||||||
|
}
|
||||||
|
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());
|
return new ArrayList<>(unitMap.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存或更新单位。
|
* 校验每条单位的编码、名称及正整数等级,避免错误主键或非法等级进入本地单位树。
|
||||||
* DWDM 对应系统单位 id/unitcode,DWMC 对应名称,LSDWH 对应父级单位号,DWCC 对应信息中心原始单位层级。
|
|
||||||
*/
|
*/
|
||||||
private void saveOrUpdateUnit(JSONObject raw, Set<String> parentCodes) {
|
private void validateUnit(JSONObject raw) {
|
||||||
String unitCode = raw.getStr("DWDM");
|
if (raw == null || StrUtil.isBlank(raw.getStr("DWMCDM")) || StrUtil.isBlank(raw.getStr("DWMC"))) {
|
||||||
if (StrUtil.isBlank(unitCode)) {
|
throw new BaseException("单位接口存在缺少DWMCDM或DWMC的数据");
|
||||||
return;
|
}
|
||||||
|
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<String> parentCodes) {
|
||||||
|
String unitCode = raw.getStr("DWMCDM");
|
||||||
String parentId = getParentId(unitCode, getNormalizedParentCode(raw));
|
String parentId = getParentId(unitCode, getNormalizedParentCode(raw));
|
||||||
Sys_unit unit = fetch(unitCode);
|
Sys_unit unit = fetch(unitCode);
|
||||||
if (unit == null) {
|
boolean insert = unit == null;
|
||||||
|
if (insert) {
|
||||||
unit = new Sys_unit();
|
unit = new Sys_unit();
|
||||||
unit.setId(unitCode);
|
unit.setId(unitCode);
|
||||||
|
unit.setAliasName(raw.getStr("DWMC"));
|
||||||
|
}
|
||||||
unit.setUnitcode(unitCode);
|
unit.setUnitcode(unitCode);
|
||||||
unit.setPath(getUnitPath(parentId));
|
unit.setName(raw.getStr("DWMC"));
|
||||||
setUnitValue(unit, raw, parentId, parentCodes);
|
unit.setParentId(parentId);
|
||||||
dao().fastInsert(unit);
|
unit.setUnitLevel(raw.getInt("DWDJ"));
|
||||||
} else {
|
// 每次按接口等级重算部门类别,确保已有单位同步后也能正确显示单位干部入口。
|
||||||
setUnitValue(unit, raw, parentId, parentCodes);
|
unit.setUnitTypeCode(unit.getUnitLevel() == 3 ? 1 : 0);
|
||||||
|
unit.setHasChildren(parentCodes.contains(unitCode));
|
||||||
if (StrUtil.isBlank(unit.getPath())) {
|
if (StrUtil.isBlank(unit.getPath())) {
|
||||||
unit.setPath(getUnitPath(parentId));
|
unit.setPath(getUnitPath(parentId));
|
||||||
}
|
}
|
||||||
|
if (insert) {
|
||||||
|
dao().fastInsert(unit);
|
||||||
|
} else {
|
||||||
dao().updateIgnoreNull(unit);
|
dao().updateIgnoreNull(unit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据接口字段给系统单位赋值。
|
* 一级单位挂到系统根单位0,其余单位使用SJDWMCDM,避免学校记录的自引用形成环。
|
||||||
* DWYXBS 表示单位是否有效,DWCC 表示信息中心原始单位层次;
|
|
||||||
* 系统内置根单位占用一级层级,因此保存时统一将 DWCC 加一。
|
|
||||||
*/
|
*/
|
||||||
private void setUnitValue(Sys_unit unit, JSONObject raw, String parentId, Set<String> parentCodes) {
|
private String getNormalizedParentCode(JSONObject raw) {
|
||||||
String unitCode = raw.getStr("DWDM");
|
return Integer.valueOf(1).equals(raw.getInt("DWDJ")) ? "0" : raw.getStr("SJDWMCDM");
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算父级单位号。
|
* 沿用本地父级兜底规则:父编码为空、自引用或父级不存在时作为根级,系统根单位0可直接引用。
|
||||||
* LSDWH 为空、等于自身或本地不存在该父级时按根级处理;系统根单位 0 允许直接作为父级。
|
|
||||||
*/
|
*/
|
||||||
private String getParentId(String unitCode, String parentCode) {
|
private String getParentId(String unitCode, String parentCode) {
|
||||||
if (StrUtil.isBlank(parentCode) || unitCode.equals(parentCode)) {
|
if (StrUtil.isBlank(parentCode) || unitCode.equals(parentCode)) {
|
||||||
@@ -253,13 +222,11 @@ public class SysDataUnitPullServiceImpl extends BaseServiceImpl<Sys_unit> implem
|
|||||||
if ("0".equals(parentCode)) {
|
if ("0".equals(parentCode)) {
|
||||||
return parentCode;
|
return parentCode;
|
||||||
}
|
}
|
||||||
Sys_unit parentUnit = fetch(parentCode);
|
return fetch(parentCode) == null ? "" : parentCode;
|
||||||
return parentUnit == null ? "" : parentCode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据父级 path 生成当前单位 path。
|
* 新单位或缺失路径的单位复用项目getSubPath,在父级路径下生成唯一的四位子路径。
|
||||||
* 父级为空时生成根节点 path,父级存在时在父级 path 下生成子节点 path。
|
|
||||||
*/
|
*/
|
||||||
private String getUnitPath(String parentId) {
|
private String getUnitPath(String parentId) {
|
||||||
String parentPath = "";
|
String parentPath = "";
|
||||||
@@ -269,30 +236,4 @@ public class SysDataUnitPullServiceImpl extends BaseServiceImpl<Sys_unit> implem
|
|||||||
}
|
}
|
||||||
return getSubPath("sys_unit", "path", parentPath);
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.MemberChangeOrigin;
|
||||||
import com.budwk.app.zhgh.staffmanage.member.constant.MemberChangeType;
|
import com.budwk.app.zhgh.staffmanage.member.constant.MemberChangeType;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||||
import org.nutz.dao.Cnd;
|
import org.nutz.dao.Cnd;
|
||||||
import org.nutz.dao.Dao;
|
import org.nutz.dao.Dao;
|
||||||
@@ -161,10 +160,7 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService
|
|||||||
for (Sys_user_source source : sources) {
|
for (Sys_user_source source : sources) {
|
||||||
Sys_user user = userMap.get(source.getLoginname());
|
Sys_user user = userMap.get(source.getLoginname());
|
||||||
source.setMember(null);
|
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();
|
Sys_user u = new Sys_user();
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
package com.budwk.app.sys.services.impl;
|
package com.budwk.app.sys.services.impl;
|
||||||
|
|
||||||
import cn.hutool.core.codec.Base64;
|
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.CharsetUtil;
|
||||||
import cn.hutool.core.util.IdcardUtil;
|
import cn.hutool.core.util.IdcardUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.core.util.URLUtil;
|
|
||||||
import cn.hutool.crypto.digest.DigestUtil;
|
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.HttpRequest;
|
||||||
import cn.hutool.http.HttpUtil;
|
import cn.hutool.http.HttpUtil;
|
||||||
import cn.hutool.json.JSONArray;
|
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.exception.BaseException;
|
||||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||||
import com.budwk.app.sys.annotation.DataCenterColumn;
|
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_dict;
|
||||||
import com.budwk.app.sys.models.Sys_unit;
|
import com.budwk.app.sys.models.Sys_unit;
|
||||||
import com.budwk.app.sys.models.Sys_user;
|
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.SysDataUnitPullService;
|
||||||
import com.budwk.app.sys.services.SysDataUserPullService;
|
import com.budwk.app.sys.services.SysDataUserPullService;
|
||||||
import com.budwk.app.sys.services.SysDictService;
|
import com.budwk.app.sys.services.SysDictService;
|
||||||
import com.budwk.app.sys.utils.DataCenterUtil;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.nutz.aop.interceptor.async.Async;
|
import org.nutz.aop.interceptor.async.Async;
|
||||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||||
@@ -42,8 +36,6 @@ import org.nutz.lang.util.NutMap;
|
|||||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -51,9 +43,8 @@ import java.util.stream.Collectors;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class SysDataUserPullServiceImpl extends BaseServiceImpl<Sys_user_source> implements SysDataUserPullService {
|
public class SysDataUserPullServiceImpl extends BaseServiceImpl<Sys_user_source> implements SysDataUserPullService {
|
||||||
|
|
||||||
private static final String DMP_TEACHER_KEY = "teacher";
|
private static final int USER_PAGE_SIZE = 1000;
|
||||||
private static final String DMP_DISPATCH_KEY = "dispatch";
|
private static final int REQUEST_TIMEOUT = 30000;
|
||||||
private static final int DMP_PAGE_SIZE = 1000;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private SysDictService sysDictService;
|
private SysDictService sysDictService;
|
||||||
@@ -74,12 +65,10 @@ public class SysDataUserPullServiceImpl extends BaseServiceImpl<Sys_user_source>
|
|||||||
private static class FieldMapping {
|
private static class FieldMapping {
|
||||||
final Field field;
|
final Field field;
|
||||||
final String key;
|
final String key;
|
||||||
final String dict;
|
|
||||||
|
|
||||||
FieldMapping(Field field, String key, String dict) {
|
FieldMapping(Field field, String key) {
|
||||||
this.field = field;
|
this.field = field;
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.dict = dict;
|
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -101,7 +90,7 @@ public class SysDataUserPullServiceImpl extends BaseServiceImpl<Sys_user_source>
|
|||||||
for (Field field : fields) {
|
for (Field field : fields) {
|
||||||
DataCenterColumn annotation = field.getAnnotation(DataCenterColumn.class);
|
DataCenterColumn annotation = field.getAnnotation(DataCenterColumn.class);
|
||||||
if (annotation != null) {
|
if (annotation != null) {
|
||||||
mappings.add(new FieldMapping(field, annotation.key(), annotation.dict()));
|
mappings.add(new FieldMapping(field, annotation.key()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fieldMappings = mappings;
|
fieldMappings = mappings;
|
||||||
@@ -111,253 +100,175 @@ public class SysDataUserPullServiceImpl extends BaseServiceImpl<Sys_user_source>
|
|||||||
return fieldMappings;
|
return fieldMappings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拉取完整人员批次,无请求参数;返回本批次拉取时间,用于sys_user_source筛选。
|
||||||
|
* 接口及字段校验全部通过后补齐二、三级单位,再写入数据源;异常时由事务回滚。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
@Aop(TransAop.READ_COMMITTED)
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
public Date pull() {
|
public Date pull() {
|
||||||
try {
|
List<JSONObject> records = pullUsers();
|
||||||
// 获取数据中心的字典
|
if (records.isEmpty()) {
|
||||||
List<Sys_data_dict> dataDictList = dao().query(Sys_data_dict.class, Cnd.NEW());
|
throw new BaseException("人员接口未返回数据,本次未生成数据源批次");
|
||||||
// 字典码表Map,key为父级编码,value为子级字典列表
|
}
|
||||||
Map<String, List<Sys_data_dict>> dataDictMap = dataDictList.stream().collect(Collectors.groupingBy(Sys_data_dict::getParentCode));
|
Date pullTime = new Date();
|
||||||
|
List<Sys_user_source> sources = records.stream().map(raw -> mapUser(raw, pullTime)).toList();
|
||||||
String accessToken = getDmpAccessToken();
|
Set<String> requiredUnits = new HashSet<>();
|
||||||
List<JSONObject> rawDataList = new ArrayList<>();
|
for (Sys_user_source source : sources) {
|
||||||
rawDataList.addAll(pullDmpUsers(getDmpUrl(DMP_TEACHER_KEY), accessToken, "在岗教职工"));
|
if (StrUtil.isNotBlank(source.getUnitId())) {
|
||||||
rawDataList.addAll(pullDmpUsers(getDmpUrl(DMP_DISPATCH_KEY), accessToken, "在岗劳务派遣"));
|
requiredUnits.add(source.getUnitId());
|
||||||
rawDataList = distinctDmpUsers(rawDataList);
|
}
|
||||||
|
if (StrUtil.isNotBlank(source.getThreeUnitId())) {
|
||||||
if (rawDataList.isEmpty()) {
|
requiredUnits.add(source.getThreeUnitId());
|
||||||
log.warn("当前未获取到人员数据");
|
}
|
||||||
|
}
|
||||||
|
// 编码不再按长度截断,二级和三级单位均须存在,避免数据源保存悬空的单位关联。
|
||||||
|
Set<String> 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
Date nowDate = new Date();
|
/**
|
||||||
|
* raw为单条人员JSON,pullTime为本批次时间;返回待保存的Sys_user_source。
|
||||||
// 赋值
|
* 按Sys_user字段注解映射,XB直接保存中文,其余字典类字段保留接口值,不套用旧学校码表。
|
||||||
List<Sys_user_source> latestSourceList = rawDataList.stream().map(raw -> {
|
* SZEJDWH/SZEJDW为二级单位编码/名称,SZDWH为三级单位编码,DQZW为当前职务。
|
||||||
Sys_user_source sysUser = new Sys_user_source();
|
* 缺失或空白字段统一为null,避免后续updateIgnoreNull用空字符串覆盖已有人员信息。
|
||||||
|
*/
|
||||||
// 使用缓存的字段映射
|
private Sys_user_source mapUser(JSONObject raw, Date pullTime) {
|
||||||
|
Sys_user_source source = new Sys_user_source();
|
||||||
for (FieldMapping mapping : getFieldMappings()) {
|
for (FieldMapping mapping : getFieldMappings()) {
|
||||||
|
String value = StrUtil.trimToNull(raw.getStr(mapping.key));
|
||||||
|
if ("LXRQ".equals(mapping.key)) {
|
||||||
|
value = normalizeArrivalAtSchoolDate(value);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
// 根据字段类型设置值
|
mapping.field.set(source, value);
|
||||||
if (mapping.field.getType() == String.class) {
|
|
||||||
|
|
||||||
if (StrUtil.isNotBlank(mapping.dict)) {
|
|
||||||
List<Sys_data_dict> 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) {
|
} catch (IllegalAccessException e) {
|
||||||
log.error("设置字段值失败: {}", mapping.field.getName(), e);
|
throw new BaseException("人员字段映射失败: {}", mapping.key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
source.setUnitName(StrUtil.trimToNull(raw.getStr("SZEJDW")));
|
||||||
sysUser.setUnitName(raw.getStr("SZDW"));
|
source.setPullTime(pullTime);
|
||||||
sysUser.setUnitId(resolveSourceUnitId(raw.getStr("SZDWH")));
|
// 接口没有出生日期,仅对有效身份证推导生日;其他证件不强行转换,也不推导性别。
|
||||||
|
if (StrUtil.isNotBlank(source.getIdCard()) && IdcardUtil.isValidCard(source.getIdCard())) {
|
||||||
// 设置拉取时间
|
source.setBirthday(IdcardUtil.getBirthDate(source.getIdCard()));
|
||||||
sysUser.setPullTime(nowDate);
|
|
||||||
|
|
||||||
return sysUser;
|
|
||||||
}).toList();
|
|
||||||
|
|
||||||
log.info("用户数据初始化完成,等待插入,当前数据条数{}", latestSourceList.size());
|
|
||||||
// 插入到数据库
|
|
||||||
if (CollUtil.isNotEmpty(latestSourceList)) {
|
|
||||||
dao().insert(latestSourceList);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 人员的单位数据和数据库的单位数据比较,如果人员里面有单位不存在,去更新单位数据
|
|
||||||
List<String> 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<String> 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());
|
|
||||||
}
|
}
|
||||||
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 规范化信息中心返回的来校时间。
|
* LXRQ为接口来校日期字符串,支持日期、以空格或T分隔的时间及年月;
|
||||||
* 入参 arrivalAtSchoolDate 对应信息中心 LXNY 字段,允许 yyyy-MM-dd 或 yyyy-MM;
|
* 返回yyyy-MM-dd,年月补为当月01日,空值返回null,非法日期中止当前批次。
|
||||||
* 返回值用于 sys_user_source.arrivalAtSchoolDate 和后续 sys_user.arrivalAtSchoolDate,年月格式统一补为当月 01 日。
|
|
||||||
*/
|
*/
|
||||||
private String normalizeArrivalAtSchoolDate(String arrivalAtSchoolDate) {
|
private String normalizeArrivalAtSchoolDate(String value) {
|
||||||
String dateText = StrUtil.trim(arrivalAtSchoolDate);
|
if (StrUtil.isBlank(value)) {
|
||||||
if (StrUtil.isBlank(dateText)) {
|
return null;
|
||||||
return dateText;
|
|
||||||
}
|
}
|
||||||
if (dateText.matches("\\d{4}-\\d{1,2}-\\d{1,2}")) {
|
String date = value.trim().split("[T ]", 2)[0];
|
||||||
String[] parts = dateText.split("-");
|
try {
|
||||||
return parts[0] + "-" + StrUtil.padPre(parts[1], 2, '0') + "-" + StrUtil.padPre(parts[2], 2, '0');
|
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();
|
||||||
}
|
}
|
||||||
if (dateText.matches("\\d{4}-\\d{1,2}")) {
|
} catch (RuntimeException e) {
|
||||||
String[] parts = dateText.split("-");
|
throw new BaseException("人员接口LXRQ不是有效日期");
|
||||||
return parts[0] + "-" + StrUtil.padPre(parts[1], 2, '0') + "-01";
|
|
||||||
}
|
}
|
||||||
return dateText;
|
throw new BaseException("人员接口LXRQ日期格式不支持");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取信息中心开放平台访问令牌。
|
* 配置data-center.urls.teacher为人员接口地址,data-center.api-key为人员和单位共用密钥。
|
||||||
* 返回值为接口后续调用使用的 access_token 字符串。
|
* GET查询参数pageNum从1开始、pageSize为每页数量,请求头apiKey用于认证。
|
||||||
|
* status=0成功,payload.resultList为人员数组,pageNo/pageSize/totalCount用于校验分页完整性。
|
||||||
|
* 返回全部分页按GH去重的人员JSON列表;分页异常时抛出异常,不保存部分批次。
|
||||||
*/
|
*/
|
||||||
private String getDmpAccessToken() {
|
private List<JSONObject> pullUsers() {
|
||||||
String tokenUrl = dataCenterProperties.getTokenUrl();
|
String url = dataCenterProperties.getUrls().get("teacher");
|
||||||
if (StrUtil.isBlank(tokenUrl)) {
|
String apiKey = dataCenterProperties.getApiKey();
|
||||||
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);
|
|
||||||
if (StrUtil.isBlank(url)) {
|
if (StrUtil.isBlank(url)) {
|
||||||
throw new BaseException("未配置信息中心人员接口地址: data-center.urls." + key);
|
throw new BaseException("未配置人员接口地址: data-center.urls.teacher");
|
||||||
}
|
}
|
||||||
return url;
|
if (StrUtil.isBlank(apiKey)) {
|
||||||
|
throw new BaseException("未配置人员接口密钥: data-center.api-key");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 分页拉取单个人员接口数据。
|
|
||||||
* 入参 url 为人员接口地址,accessToken 为信息中心令牌,sourceName 用于日志区分接口来源。
|
|
||||||
* 返回值为该接口所有分页合并后的原始人员 JSON 列表。
|
|
||||||
*/
|
|
||||||
private List<JSONObject> pullDmpUsers(String url, String accessToken, String sourceName) {
|
|
||||||
List<JSONObject> 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<JSONObject> distinctDmpUsers(List<JSONObject> rawDataList) {
|
|
||||||
Map<String, JSONObject> userMap = new LinkedHashMap<>();
|
Map<String, JSONObject> userMap = new LinkedHashMap<>();
|
||||||
for (JSONObject raw : rawDataList) {
|
int pageNum = 1;
|
||||||
String loginName = raw.getStr("ZGH");
|
int pageSize = USER_PAGE_SIZE;
|
||||||
if (StrUtil.isBlank(loginName)) {
|
long totalCount = -1;
|
||||||
loginName = raw.getStr("ID");
|
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());
|
||||||
}
|
}
|
||||||
userMap.putIfAbsent(loginName, raw);
|
String responseBody = response.body();
|
||||||
|
if (!JSONUtil.isTypeJSONObject(responseBody)) {
|
||||||
|
throw new BaseException("获取人员数据失败,第{}页返回内容不是JSON对象", pageNum);
|
||||||
}
|
}
|
||||||
|
body = JSONUtil.parseObj(responseBody);
|
||||||
|
}
|
||||||
|
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());
|
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
|
@Async
|
||||||
private void updateDict(List<Sys_user_source> userSources) {
|
private void updateDict(List<Sys_user_source> userSources) {
|
||||||
//判断是否要更新在职状态字典
|
//判断是否要更新在职状态字典
|
||||||
|
|||||||
@@ -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<NutMap> lastSuccess;
|
||||||
|
private long nextRefreshAt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 无入参;返回接口约定的六栏目列表。成功结果缓存30分钟,网络失败时使用最近成功数据。
|
||||||
|
* 同一实例串行刷新,有历史结果时失败后一分钟内不重复请求官网;Redis不可用时仍可使用实例内缓存。
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public synchronized List<NutMap> getNews() {
|
||||||
|
if (lastSuccess != null && System.currentTimeMillis() < nextRefreshAt) {
|
||||||
|
return lastSuccess;
|
||||||
|
}
|
||||||
|
List<NutMap> 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<NutMap> 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<NutMap> readCache(String key) {
|
||||||
|
try {
|
||||||
|
String json = redisService.get(key);
|
||||||
|
if (json != null && !json.isBlank()) {
|
||||||
|
List<NutMap> list = Json.fromJsonAsList(NutMap.class, json);
|
||||||
|
if (list != null && list.size() == 6) {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("工会新闻缓存读取失败", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 按官网栏目顺序解析;任何栏目无法识别时不覆盖最近成功缓存,避免发布残缺数据。 */
|
||||||
|
private List<NutMap> 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<NutMap> result = new ArrayList<>();
|
||||||
|
for (String[] column : columns) {
|
||||||
|
List<NutMap> articles = new ArrayList<>();
|
||||||
|
Set<String> 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<Integer, String> 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<NutMap> 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 "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
package com.budwk.app.sys.services.impl;
|
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 cn.hutool.core.util.StrUtil;
|
||||||
import com.budwk.app.base.constant.RedisConstant;
|
import com.budwk.app.base.constant.RedisConstant;
|
||||||
import com.budwk.app.base.page.Pagination;
|
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.CacheDefaults;
|
||||||
import org.nutz.plugins.wkcache.annotation.CacheRemoveAll;
|
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.
|
* Created by wizzer on 2016/12/22.
|
||||||
*/
|
*/
|
||||||
@@ -29,6 +36,29 @@ public class SysUnitServiceImpl extends BaseServiceImpl<Sys_unit> implements Sys
|
|||||||
super(dao);
|
super(dao);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pid为空时以学校单位1为展示根;指定pid时返回该单位及其下级,不依赖实体单位0存在。
|
||||||
|
* 虚拟根仅用于组织返回结构,不修改数据库中的父级关系;缺少部门类别时按普通分类0展示。
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<Tree<String>> getUnitTree(String pid) {
|
||||||
|
String rootId = StrUtil.blankToDefault(pid, "1");
|
||||||
|
String virtualRootId = "root";
|
||||||
|
List<Sys_unit> units = query(Cnd.NEW().asc("unitcode"));
|
||||||
|
if (units.stream().noneMatch(unit -> rootId.equals(unit.getId()))) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
List<TreeNode<String>> 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);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按单位编码或名称筛选当前分工会的组成单位,并按单位编码倒序分页。
|
* 按单位编码或名称筛选当前分工会的组成单位,并按单位编码倒序分页。
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,17 +1,85 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<configuration scan="false" scanPeriod="60000" debug="false">
|
<configuration scan="false" scanPeriod="60000" debug="false">
|
||||||
|
|
||||||
<!-- 定义日志文件的存储路径 -->
|
<!-- 日志存储路径 -->
|
||||||
<property name="LOG_HOME" value="./logs"/>
|
<property name="LOG_HOME" value="./logs"/>
|
||||||
|
|
||||||
<!-- 控制台输出配置 -->
|
<!-- 控制台输出 -->
|
||||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
<encoder>
|
<encoder>
|
||||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
<!-- INFO级别日志文件配置 -->
|
|
||||||
|
<!--
|
||||||
|
#################################################################################
|
||||||
|
# #
|
||||||
|
# 全文输出日志(一个文件存储)start #
|
||||||
|
# #
|
||||||
|
#################################################################################
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- 所有级别日志写入同一个文件 -->
|
||||||
|
<appender name="ALL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>${LOG_HOME}/app.log</file>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${LOG_HOME}/app-%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||||
|
<maxHistory>300</maxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- 框架日志级别(按需调整) -->
|
||||||
|
<logger name="org.eclipse.jetty" level="INFO"/>
|
||||||
|
<logger name="org.quartz" level="INFO"/>
|
||||||
|
<logger name="org.nutz" level="DEBUG"/>
|
||||||
|
|
||||||
|
<!-- root logger:DEBUG 级别,输出到控制台和全量文件 -->
|
||||||
|
<root level="DEBUG">
|
||||||
|
<appender-ref ref="STDOUT"/>
|
||||||
|
<appender-ref ref="ALL_FILE"/>
|
||||||
|
</root>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
#################################################################################
|
||||||
|
# #
|
||||||
|
# 全文输出日志(一个文件存储)end #
|
||||||
|
# #
|
||||||
|
#################################################################################
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
#################################################################################
|
||||||
|
# #
|
||||||
|
# debug、info、error分文件输出 start #
|
||||||
|
# #
|
||||||
|
#################################################################################
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- DEBUG级别日志文件配置 -->
|
||||||
|
<!--<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>${LOG_HOME}/debug.log</file>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<level>DEBUG</level>
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${LOG_HOME}/debug-%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||||
|
<maxHistory>300</maxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!– INFO级别日志文件配置 –>
|
||||||
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
<file>${LOG_HOME}/info.log</file>
|
<file>${LOG_HOME}/info.log</file>
|
||||||
<encoder>
|
<encoder>
|
||||||
@@ -24,11 +92,11 @@
|
|||||||
</filter>
|
</filter>
|
||||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
<fileNamePattern>${LOG_HOME}/info-%d{yyyy-MM-dd}.log</fileNamePattern>
|
<fileNamePattern>${LOG_HOME}/info-%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||||
<maxHistory>30</maxHistory>
|
<maxHistory>300</maxHistory>
|
||||||
</rollingPolicy>
|
</rollingPolicy>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
<!-- ERROR级别日志文件配置 -->
|
<!– ERROR级别日志文件配置 –>
|
||||||
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
<file>${LOG_HOME}/error.log</file>
|
<file>${LOG_HOME}/error.log</file>
|
||||||
<encoder>
|
<encoder>
|
||||||
@@ -41,19 +109,31 @@
|
|||||||
</filter>
|
</filter>
|
||||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
<fileNamePattern>${LOG_HOME}/error-%d{yyyy-MM-dd}.log</fileNamePattern>
|
<fileNamePattern>${LOG_HOME}/error-%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||||
<maxHistory>30</maxHistory>
|
<maxHistory>300</maxHistory>
|
||||||
</rollingPolicy>
|
</rollingPolicy>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
<logger name="java" additivity="false" />
|
<!– 框架日志级别 –>
|
||||||
|
<!– <logger name="java" additivity="false" />–>
|
||||||
<logger name="org.eclipse.jetty" level="INFO"/>
|
<logger name="org.eclipse.jetty" level="INFO"/>
|
||||||
<logger name="org.quartz" level="INFO"/>
|
<logger name="org.quartz" level="INFO"/>
|
||||||
<logger name="org.nutz" level="DEBUG"/>
|
<logger name="org.nutz" level="DEBUG"/>
|
||||||
|
|
||||||
<!-- 日志级别和appender的关联 -->
|
<!– 日志级别和appender的关联 –>
|
||||||
<root level="DEBUG">
|
<root level="DEBUG">
|
||||||
<appender-ref ref="STDOUT"/>
|
<appender-ref ref="STDOUT"/>
|
||||||
|
<appender-ref ref="DEBUG_FILE"/>
|
||||||
<appender-ref ref="INFO_FILE"/>
|
<appender-ref ref="INFO_FILE"/>
|
||||||
<appender-ref ref="ERROR_FILE"/>
|
<appender-ref ref="ERROR_FILE"/>
|
||||||
</root>
|
</root>-->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
#################################################################################
|
||||||
|
# #
|
||||||
|
# debug、info、error分文件输出 end #
|
||||||
|
# #
|
||||||
|
#################################################################################
|
||||||
|
-->
|
||||||
|
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ layout("/layouts/v4/baseLayout.html"){
|
|||||||
|
|
||||||
<work-template v-if="$auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN'])"></work-template>
|
<work-template v-if="$auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN'])"></work-template>
|
||||||
|
|
||||||
<jcdt :list="websiteNews"></jcdt>
|
<jcdt :list="websiteNews" :loading="newsLoading" :error="newsError" @retry="getWebSiteNews"></jcdt>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -172,6 +172,8 @@ layout("/layouts/v4/baseLayout.html"){
|
|||||||
data(){
|
data(){
|
||||||
return{
|
return{
|
||||||
websiteNews: [],
|
websiteNews: [],
|
||||||
|
newsLoading: false,
|
||||||
|
newsError: "",
|
||||||
homeBannerList: "${config.AppHomeImg!}".split(",").map(item => item.trim()).filter(item => item)
|
homeBannerList: "${config.AppHomeImg!}".split(",").map(item => item.trim()).filter(item => item)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -188,10 +190,20 @@ layout("/layouts/v4/baseLayout.html"){
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getWebSiteNews(){
|
getWebSiteNews(){
|
||||||
|
if (this.newsLoading) return
|
||||||
|
this.newsLoading = true
|
||||||
|
this.newsError = ""
|
||||||
|
// 无请求参数;data为六栏目数组,value包含标题、日期、原文链接和可选图片。
|
||||||
this.$axios.post('/platform/home/getNews').then(res => {
|
this.$axios.post('/platform/home/getNews').then(res => {
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
this.websiteNews = res.data
|
this.websiteNews = res.data || []
|
||||||
|
} else {
|
||||||
|
this.newsError = res.msg || "工会新闻暂时无法获取"
|
||||||
}
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
this.newsError = "工会新闻暂时无法获取,请稍后重试"
|
||||||
|
}).finally(() => {
|
||||||
|
this.newsLoading = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,52 @@
|
|||||||
const jcdt = {
|
const jcdt = {
|
||||||
template: /*language=HTML*/ `
|
template: /*language=HTML*/ `
|
||||||
<div class="jcdt-wrapper">
|
<div class="jcdt-wrapper">
|
||||||
<div class="jcdt-container">
|
<div class="jcdt-container" v-loading="loading">
|
||||||
<el-carousel height="360px" :interval="10000" indicator-position="none">
|
<div class="jcdt-tabs" v-if="list.length">
|
||||||
<el-carousel-item v-for="item,index in list" :key="index">
|
<el-button v-for="(column, index) in list" :key="column.label"
|
||||||
|
:type="activeIndex === index ? 'primary' : 'default'" size="small"
|
||||||
|
@click="selectColumn(index)">{{ column.label }}</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="jcdt-empty" v-if="error">
|
||||||
|
{{ error }} <el-button type="text" @click="$emit('retry')">重试</el-button>
|
||||||
|
</div>
|
||||||
|
<el-empty v-if="!loading && !error && !list.length" description="暂无工会新闻"></el-empty>
|
||||||
|
<el-carousel v-if="list.length" ref="newsCarousel" height="430px" :interval="10000"
|
||||||
|
:autoplay="!isImageColumn(list[activeIndex])"
|
||||||
|
indicator-position="none" @change="onColumnChange">
|
||||||
|
<el-carousel-item v-for="item,index in displayColumns" :key="index">
|
||||||
<div class="jcdt-title">
|
<div class="jcdt-title">
|
||||||
<span>{{ item.label }}</span>
|
<span>{{ item.label }}</span>
|
||||||
|
<el-link :href="item.href" target="_blank" rel="noopener noreferrer" type="primary">更多</el-link>
|
||||||
</div>
|
</div>
|
||||||
<div class="jcdt-content">
|
<div class="jcdt-content" :class="{ 'jcdt-image-content': isImageColumn(item) }">
|
||||||
<div class="jcdt-list">
|
<!-- 两组相同图片同步移动一个组宽,首尾衔接;隐藏栏目暂停动画。 -->
|
||||||
<div class="jcdt-item" v-for="o,i in item.value" :key="i" @click="onLink(o)">
|
<div v-if="isImageColumn(item)" class="jcdt-image-track" :data-column="index">
|
||||||
<div class="date" v-if="o.time">
|
<div v-for="copy in 2" :key="copy" class="jcdt-image-group"
|
||||||
|
:style="{ '--image-count': item.scrollImages.length }">
|
||||||
|
<a class="jcdt-item" v-for="(o, i) in item.scrollImages" :key="i"
|
||||||
|
:href="o.href" target="_blank" rel="noopener noreferrer">
|
||||||
|
<div class="image">
|
||||||
|
<el-image :src="o.image" :alt="o.text" fit="cover">
|
||||||
|
<div slot="error">图片暂不可用</div>
|
||||||
|
</el-image>
|
||||||
|
</div>
|
||||||
|
<div class="title">{{ o.text }}</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="jcdt-list">
|
||||||
|
<a class="jcdt-item" v-for="o,i in item.value" :key="i" :href="o.href"
|
||||||
|
target="_blank" rel="noopener noreferrer">
|
||||||
|
<div class="image" v-if="o.image">
|
||||||
|
<el-image :src="o.image" :alt="o.text" fit="cover">
|
||||||
|
<div slot="error">图片暂不可用</div>
|
||||||
|
</el-image>
|
||||||
|
</div>
|
||||||
|
<!-- 源站未提供日期时仍保留时钟和行高,不补造日期。 -->
|
||||||
|
<div class="date" v-if="o.time || !o.image">
|
||||||
<i class="el-icon-alarm-clock"></i>
|
<i class="el-icon-alarm-clock"></i>
|
||||||
<span>{{o.time}}</span>
|
<span v-if="o.time">{{o.time}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div style="display: flex; align-items: center">
|
<div style="display: flex; align-items: center">
|
||||||
<div>
|
<div>
|
||||||
@@ -20,33 +54,149 @@ const jcdt = {
|
|||||||
</div>
|
</div>
|
||||||
<div class="title">{{o.text}}</div>
|
<div class="title">{{o.text}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-carousel-item>
|
</el-carousel-item>
|
||||||
</el-carousel>
|
</el-carousel>
|
||||||
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
data() {
|
data() {
|
||||||
return {}
|
return { activeIndex: 0 }
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
list: {
|
list: {
|
||||||
type: Array,
|
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: {
|
methods: {
|
||||||
onLink(item) {
|
// 切栏、刷新数据后等待 DOM 更新;只为当前图片栏目启动一个动画循环。
|
||||||
const url = this.isHttpOrHttps(item.href) ? item.href : "https://xgh.cug.edu.cn/" + item.href
|
syncImageScroll() {
|
||||||
window.open(url)
|
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) {
|
// 浏览器帧时间戳为毫秒;按每秒 45 像素移动,超过首组宽度后无缝回绕。
|
||||||
return /^(http:\/\/|https:\/\/)/i.test(url)
|
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*/ `
|
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 {
|
.jcdt-wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
@@ -122,6 +272,8 @@ const jcdt = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/deep/ .jcdt-item .date {
|
/deep/ .jcdt-item .date {
|
||||||
|
min-height: 28px;
|
||||||
|
line-height: 28px;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ layout("/layouts/platform.html"){
|
|||||||
<div id="app" v-cloak>
|
<div id="app" v-cloak>
|
||||||
<guava ref="guava">
|
<guava ref="guava">
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<common-query ref="commonQueryRef" user-attribute-multiple @search="search"></common-query>
|
<common-query ref="commonQueryRef" @search="search"></common-query>
|
||||||
</el-card>
|
</el-card>
|
||||||
<el-card shadow="never" class="mt10">
|
<el-card shadow="never" class="mt10">
|
||||||
<table-tool label="申请列表">
|
<table-tool label="申请列表">
|
||||||
|
|||||||
-6
@@ -40,12 +40,6 @@
|
|||||||
<dict-select v-model="pageForm.aidFundMemberUserType" code="AIDFUND_MEMBER_USER_TYPE"
|
<dict-select v-model="pageForm.aidFundMemberUserType" code="AIDFUND_MEMBER_USER_TYPE"
|
||||||
style="width: 100%"></dict-select>
|
style="width: 100%"></dict-select>
|
||||||
</search-item>-->
|
</search-item>-->
|
||||||
<search-item label="人员属性">
|
|
||||||
<dict-select v-if="userAttributeMultiple" v-model="pageForm.userAttributes" code="USER_ATTRIBUTE"
|
|
||||||
multiple collapse-tags clearable style="width: 100%"></dict-select>
|
|
||||||
<dict-select v-else v-model="pageForm.userAttribute" code="USER_ATTRIBUTE"
|
|
||||||
clearable style="width: 100%"></dict-select>
|
|
||||||
</search-item>
|
|
||||||
</template>
|
</template>
|
||||||
</search>
|
</search>
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,12 +1,5 @@
|
|||||||
const COMMON_QUERY = {
|
const COMMON_QUERY = {
|
||||||
template: "#member-apply-common-query-template",
|
template: "#member-apply-common-query-template",
|
||||||
props: {
|
|
||||||
// 默认保持原单选行为,仅由明确传参的页面开启人员属性多选。
|
|
||||||
userAttributeMultiple: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
store,
|
store,
|
||||||
mixins: [initTableMixins],
|
mixins: [initTableMixins],
|
||||||
data() {
|
data() {
|
||||||
@@ -21,8 +14,6 @@ const COMMON_QUERY = {
|
|||||||
personTypes: [],
|
personTypes: [],
|
||||||
preparedBys: [],
|
preparedBys: [],
|
||||||
aidFundMemberUserType: '',
|
aidFundMemberUserType: '',
|
||||||
userAttribute: '',
|
|
||||||
userAttributes: [],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -32,7 +23,6 @@ const COMMON_QUERY = {
|
|||||||
pageForm.userStates = JSON.stringify(this.pageForm.userStates)
|
pageForm.userStates = JSON.stringify(this.pageForm.userStates)
|
||||||
pageForm.personTypes = JSON.stringify(this.pageForm.personTypes)
|
pageForm.personTypes = JSON.stringify(this.pageForm.personTypes)
|
||||||
pageForm.preparedBys = JSON.stringify(this.pageForm.preparedBys)
|
pageForm.preparedBys = JSON.stringify(this.pageForm.preparedBys)
|
||||||
pageForm.userAttributes = JSON.stringify(this.pageForm.userAttributes)
|
|
||||||
this.$emit('search', pageForm)
|
this.$emit('search', pageForm)
|
||||||
},
|
},
|
||||||
async initData(){
|
async initData(){
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ layout("/layouts/platform.html"){
|
|||||||
<div id="app" v-cloak>
|
<div id="app" v-cloak>
|
||||||
<guava ref="guava">
|
<guava ref="guava">
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<common-query ref="commonQueryRef" user-attribute-multiple @search="search"></common-query>
|
<common-query ref="commonQueryRef" @search="search"></common-query>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-card shadow="never" class="mt10">
|
<el-card shadow="never" class="mt10">
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ layout("/layouts/platform.html"){
|
|||||||
<div id="app" v-cloak>
|
<div id="app" v-cloak>
|
||||||
<guava ref="guava">
|
<guava ref="guava">
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<common-query ref="commonQueryRef" user-attribute-multiple @search="search"></common-query>
|
<common-query ref="commonQueryRef" @search="search"></common-query>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-card shadow="never" class="mt10">
|
<el-card shadow="never" class="mt10">
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ layout("/layouts/platform.html"){
|
|||||||
<div id="app" v-cloak>
|
<div id="app" v-cloak>
|
||||||
<guava ref="guava">
|
<guava ref="guava">
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<common-query ref="commonQueryRef" user-attribute-multiple @search="search"></common-query>
|
<common-query ref="commonQueryRef" @search="search"></common-query>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-card shadow="never" class="mt10">
|
<el-card shadow="never" class="mt10">
|
||||||
|
|||||||
-7
@@ -29,12 +29,5 @@
|
|||||||
<dict-select v-model="pageForm.aidFundMemberUserType" placeholder="请选择人员分类" @change="doSearch"
|
<dict-select v-model="pageForm.aidFundMemberUserType" placeholder="请选择人员分类" @change="doSearch"
|
||||||
code="AIDFUND_MEMBER_USER_TYPE"></dict-select>
|
code="AIDFUND_MEMBER_USER_TYPE"></dict-select>
|
||||||
</search-item>-->
|
</search-item>-->
|
||||||
<search-item label="人员属性">
|
|
||||||
<dict-select v-if="userAttributeMultiple" v-model="pageForm.userAttributes"
|
|
||||||
placeholder="请选择人员属性" @change="doSearch" code="USER_ATTRIBUTE"
|
|
||||||
multiple collapse-tags clearable></dict-select>
|
|
||||||
<dict-select v-else v-model="pageForm.userAttribute" placeholder="请选择人员属性"
|
|
||||||
@change="doSearch" code="USER_ATTRIBUTE"></dict-select>
|
|
||||||
</search-item>
|
|
||||||
</search>
|
</search>
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
-11
@@ -1,12 +1,5 @@
|
|||||||
const COMMON_QUERY = {
|
const COMMON_QUERY = {
|
||||||
template: "#member-change-common-query-template",
|
template: "#member-change-common-query-template",
|
||||||
props: {
|
|
||||||
// 未显式开启时保持原单选行为,避免影响未列入本次范围的页面。
|
|
||||||
userAttributeMultiple: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
store,
|
store,
|
||||||
mixins: [initTableMixins],
|
mixins: [initTableMixins],
|
||||||
data() {
|
data() {
|
||||||
@@ -21,8 +14,6 @@ const COMMON_QUERY = {
|
|||||||
personTypes: [],
|
personTypes: [],
|
||||||
preparedBys: [],
|
preparedBys: [],
|
||||||
aidFundMemberUserType: '',
|
aidFundMemberUserType: '',
|
||||||
userAttribute: '',
|
|
||||||
userAttributes: [],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -32,8 +23,6 @@ const COMMON_QUERY = {
|
|||||||
pageForm.userStates = JSON.stringify(this.pageForm.userStates)
|
pageForm.userStates = JSON.stringify(this.pageForm.userStates)
|
||||||
pageForm.personTypes = JSON.stringify(this.pageForm.personTypes)
|
pageForm.personTypes = JSON.stringify(this.pageForm.personTypes)
|
||||||
pageForm.preparedBys = JSON.stringify(this.pageForm.preparedBys)
|
pageForm.preparedBys = JSON.stringify(this.pageForm.preparedBys)
|
||||||
// 多选人员属性沿用现有数组查询参数的JSON提交方式。
|
|
||||||
pageForm.userAttributes = JSON.stringify(this.pageForm.userAttributes)
|
|
||||||
this.$emit('search', pageForm)
|
this.$emit('search', pageForm)
|
||||||
},
|
},
|
||||||
async initData(){
|
async initData(){
|
||||||
|
|||||||
@@ -73,8 +73,8 @@ const INFO = {
|
|||||||
</template>
|
</template>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="变更信息" name="changeInfo" v-if="viewData.changeInfos">
|
<el-tab-pane label="变更信息" name="changeInfo" v-if="visibleChangeInfos.length">
|
||||||
<el-table :data="viewData.changeInfos" :size="tableSize" @sort-change="pageOrder" ref="table"
|
<el-table :data="visibleChangeInfos" :size="tableSize" @sort-change="pageOrder" ref="table"
|
||||||
row-key="id" style="width: 100%">
|
row-key="id" style="width: 100%">
|
||||||
<el-table-column :index="indexMethod" align="center" header-align="center"
|
<el-table-column :index="indexMethod" align="center" header-align="center"
|
||||||
label="序号" type="index" width="80px"></el-table-column>
|
label="序号" type="index" width="80px"></el-table-column>
|
||||||
@@ -144,6 +144,12 @@ const INFO = {
|
|||||||
activeName: "basicInfo",
|
activeName: "basicInfo",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
// 人员属性不再展示,其他变更明细保持原有顺序,不改写后端返回的历史数据。
|
||||||
|
visibleChangeInfos() {
|
||||||
|
return (this.viewData.changeInfos || []).filter((item) => item.field !== "userAttribute" && item.fieldName !== "人员属性")
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 打开
|
// 打开
|
||||||
onOpen(row) {
|
onOpen(row) {
|
||||||
|
|||||||
+15
-2
@@ -1,5 +1,6 @@
|
|||||||
const MEMBER_ALL_CHANGE_INFO = {
|
const MEMBER_ALL_CHANGE_INFO = {
|
||||||
template: /*language=HTML*/ `
|
template: /*language=HTML*/ `
|
||||||
|
<div>
|
||||||
<el-tabs v-model="activeName">
|
<el-tabs v-model="activeName">
|
||||||
<el-tab-pane label="基础信息" name="basicInfo">
|
<el-tab-pane label="基础信息" name="basicInfo">
|
||||||
<el-descriptions :column="3" border class="descriptions-form">
|
<el-descriptions :column="3" border class="descriptions-form">
|
||||||
@@ -61,9 +62,9 @@ const MEMBER_ALL_CHANGE_INFO = {
|
|||||||
</template>
|
</template>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="历史变更记录" name="changeInfo" v-if="viewData.allChangeInfo">
|
<el-tab-pane label="历史变更记录" name="changeInfo" v-if="visibleChangeHistory.length">
|
||||||
<el-timeline>
|
<el-timeline>
|
||||||
<el-timeline-item placement="top" v-for="(changeData, index) in viewData.allChangeInfo"
|
<el-timeline-item placement="top" v-for="(changeData, index) in visibleChangeHistory"
|
||||||
:key="index" :timestamp="changeData.timestamp">
|
:key="index" :timestamp="changeData.timestamp">
|
||||||
<el-card>
|
<el-card>
|
||||||
<h4>{{ changeData.changeOriginName }}</h4>
|
<h4>{{ changeData.changeOriginName }}</h4>
|
||||||
@@ -87,6 +88,8 @@ const MEMBER_ALL_CHANGE_INFO = {
|
|||||||
</el-timeline>
|
</el-timeline>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
`,
|
`,
|
||||||
store,
|
store,
|
||||||
data(){
|
data(){
|
||||||
@@ -95,6 +98,16 @@ const MEMBER_ALL_CHANGE_INFO = {
|
|||||||
activeName: "basicInfo"
|
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:{
|
methods:{
|
||||||
onOpen(userId){
|
onOpen(userId){
|
||||||
this.$axios.post('/platform/member/change/manage/getAllChangeMemberInfo', {userId})
|
this.$axios.post('/platform/member/change/manage/getAllChangeMemberInfo', {userId})
|
||||||
|
|||||||
+1
-6
@@ -149,12 +149,6 @@ const MEMBER_CHANGE = {
|
|||||||
:disabled="allowFields('personType')" style="width: 100%"></dict-select>
|
:disabled="allowFields('personType')" style="width: 100%"></dict-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="人员属性">
|
|
||||||
<el-form-item prop="userAttribute">
|
|
||||||
<dict-select v-model="formData.userAttribute" code="USER_ATTRIBUTE"
|
|
||||||
style="width: 100%"></dict-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-descriptions-item>
|
|
||||||
<!-- <el-descriptions-item label="人员分类">-->
|
<!-- <el-descriptions-item label="人员分类">-->
|
||||||
<!-- <el-form-item prop="aidFundMemberUserType">-->
|
<!-- <el-form-item prop="aidFundMemberUserType">-->
|
||||||
<!-- <dict-select v-model="formData.aidFundMemberUserType" code="AIDFUND_MEMBER_USER_TYPE"-->
|
<!-- <dict-select v-model="formData.aidFundMemberUserType" code="AIDFUND_MEMBER_USER_TYPE"-->
|
||||||
@@ -530,6 +524,7 @@ const MEMBER_CHANGE = {
|
|||||||
this.$set(this.formData, "userState", userState)
|
this.$set(this.formData, "userState", userState)
|
||||||
this.$set(this.formData, "personType", personType)
|
this.$set(this.formData, "personType", personType)
|
||||||
this.$set(this.formData, "preparedBy", preparedBy)
|
this.$set(this.formData, "preparedBy", preparedBy)
|
||||||
|
// 仅保留原值随表单传递,避免移除控件后被变更比较误判为清空。
|
||||||
this.$set(this.formData, "userAttribute", userAttribute)
|
this.$set(this.formData, "userAttribute", userAttribute)
|
||||||
this.$set(this.formData, "aidFundMemberUserType", aidFundMemberUserType)
|
this.$set(this.formData, "aidFundMemberUserType", aidFundMemberUserType)
|
||||||
this.$set(this.formData, "unitName", unit ? unit.name : null)
|
this.$set(this.formData, "unitName", unit ? unit.name : null)
|
||||||
|
|||||||
@@ -50,10 +50,6 @@ layout("/layouts/platform.html"){
|
|||||||
<!-- <dict-select v-model="pageForm.aidFundMemberUserType" placeholder="请选择人员分类" @change="doSearch"-->
|
<!-- <dict-select v-model="pageForm.aidFundMemberUserType" placeholder="请选择人员分类" @change="doSearch"-->
|
||||||
<!-- code="AIDFUND_MEMBER_USER_TYPE"></dict-select>-->
|
<!-- code="AIDFUND_MEMBER_USER_TYPE"></dict-select>-->
|
||||||
<!-- </search-item>-->
|
<!-- </search-item>-->
|
||||||
<search-item label="人员属性">
|
|
||||||
<dict-select v-model="pageForm.userAttributes" placeholder="请选择人员属性" @change="doSearch"
|
|
||||||
code="USER_ATTRIBUTE" multiple collapse-tags clearable></dict-select>
|
|
||||||
</search-item>
|
|
||||||
<search-item label="更新日期">
|
<search-item label="更新日期">
|
||||||
<el-date-picker :picker-options="pickerOptions" @change="changeDateRangeChange"
|
<el-date-picker :picker-options="pickerOptions" @change="changeDateRangeChange"
|
||||||
align="right" end-placeholder="结束日期" format="yyyy-MM-dd"
|
align="right" end-placeholder="结束日期" format="yyyy-MM-dd"
|
||||||
@@ -76,10 +72,6 @@ layout("/layouts/platform.html"){
|
|||||||
设置人员分类
|
设置人员分类
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
||||||
<el-button :disabled="!checkUsers.length" @click="openBatchEditUserAttribute" class="ml5" icon="el-icon-edit"
|
|
||||||
size="small" type="primary">
|
|
||||||
设置人员属性
|
|
||||||
</el-button>
|
|
||||||
|
|
||||||
<el-button :disabled="!checkUsers.length" @click="openBatchEditUserState" class="ml5" icon="el-icon-edit"
|
<el-button :disabled="!checkUsers.length" @click="openBatchEditUserState" class="ml5" icon="el-icon-edit"
|
||||||
size="small" type="primary">
|
size="small" type="primary">
|
||||||
@@ -238,48 +230,6 @@ layout("/layouts/platform.html"){
|
|||||||
<member-all-change ref="memberAllChangeRef"></member-all-change>
|
<member-all-change ref="memberAllChangeRef"></member-all-change>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-drawer
|
|
||||||
:before-close="handleClose"
|
|
||||||
:visible.sync="batchEditUserAttributeVisible"
|
|
||||||
size="1000px" title="批量设置人员属性">
|
|
||||||
<el-timeline style="margin-right: 40px">
|
|
||||||
<el-timeline-item placement="top" timestamp="">
|
|
||||||
<el-form :model="batchFormDataUserAttribute" label-width="100px" ref="batchFormUserAttribute">
|
|
||||||
<el-row :gutter="60">
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="人员属性">
|
|
||||||
<dict-select
|
|
||||||
@change="checkUsers.map(v => $set(v, 'userAttribute', batchFormDataUserAttribute.userAttribute))"
|
|
||||||
clearable code="USER_ATTRIBUTE"
|
|
||||||
placeholder="请选择人员属性"
|
|
||||||
style="width: 300px"
|
|
||||||
v-model="batchFormDataUserAttribute.userAttribute"></dict-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-form>
|
|
||||||
</el-timeline-item>
|
|
||||||
<el-timeline-item placement="top" timestamp="">
|
|
||||||
<el-table :data="checkUsers" class="vi-table" height="70vh" row-key="id" style="width: 100%">
|
|
||||||
<el-table-column align="center" header-align="center" label="工号" prop="loginname" show-overflow-tooltip></el-table-column>
|
|
||||||
<el-table-column align="center" header-align="center" label="姓名" prop="username" show-overflow-tooltip></el-table-column>
|
|
||||||
<el-table-column align="center" header-align="center" label="所属单位" prop="unitName" show-overflow-tooltip></el-table-column>
|
|
||||||
<el-table-column align="center" header-align="center" label="所属工会" prop="unionName" show-overflow-tooltip></el-table-column>
|
|
||||||
<el-table-column align="center" header-align="center" label="人员属性" prop="userAttribute" show-overflow-tooltip width="300px">
|
|
||||||
<template scope="{row}">
|
|
||||||
<dict-select clearable code="USER_ATTRIBUTE" placeholder="请选择人员属性" style="width: 200px"
|
|
||||||
v-model="row.userAttribute"></dict-select>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</el-timeline-item>
|
|
||||||
</el-timeline>
|
|
||||||
|
|
||||||
<span style="position: absolute;bottom: 20px;right: 20px">
|
|
||||||
<el-button @click="batchEditUserAttributeVisible = false;checkUsers=[];$refs.table.clearSelection()">取消</el-button>
|
|
||||||
<el-button :loading="batchEditLoading" @click="doBatchEditUserAttribute" type="primary">确定</el-button>
|
|
||||||
</span>
|
|
||||||
</el-drawer>
|
|
||||||
|
|
||||||
<el-drawer
|
<el-drawer
|
||||||
:before-close="handleClose"
|
:before-close="handleClose"
|
||||||
@@ -523,7 +473,6 @@ layout("/layouts/platform.html"){
|
|||||||
isMember: 1,
|
isMember: 1,
|
||||||
changeTypes: [],
|
changeTypes: [],
|
||||||
aidFundMemberUserType: "",
|
aidFundMemberUserType: "",
|
||||||
userAttributes: [],
|
|
||||||
},
|
},
|
||||||
unions: [],
|
unions: [],
|
||||||
units: [],
|
units: [],
|
||||||
@@ -531,12 +480,10 @@ layout("/layouts/platform.html"){
|
|||||||
id: "",
|
id: "",
|
||||||
checkUsers: [],
|
checkUsers: [],
|
||||||
batchEditLoading: false,
|
batchEditLoading: false,
|
||||||
batchEditUserAttributeVisible: false,
|
|
||||||
batchEditMemberVisible: false,
|
batchEditMemberVisible: false,
|
||||||
batchEditAidFundTypeVisible: false,
|
batchEditAidFundTypeVisible: false,
|
||||||
batchEditUserStateVisible: false,
|
batchEditUserStateVisible: false,
|
||||||
unitMoveVisible: false,
|
unitMoveVisible: false,
|
||||||
batchFormDataUserAttribute: {},
|
|
||||||
batchFormDataMember: {member: false, welfareMember: false},
|
batchFormDataMember: {member: false, welfareMember: false},
|
||||||
batchFormDataAidFundType: {},
|
batchFormDataAidFundType: {},
|
||||||
batchFormDataUserState: {},
|
batchFormDataUserState: {},
|
||||||
@@ -569,7 +516,6 @@ layout("/layouts/platform.html"){
|
|||||||
{ prop: "personType", label: "人员类型", width: 120, sortable: true },
|
{ prop: "personType", label: "人员类型", width: 120, sortable: true },
|
||||||
// 临时屏蔽“人员分类”列表字段,不删除配置,后续需要可恢复。
|
// 临时屏蔽“人员分类”列表字段,不删除配置,后续需要可恢复。
|
||||||
// { prop: "aidFundMemberUserType", 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: "idCardType", label: "证件类型", width: 120, sortable: true, checked: 0 },
|
||||||
{ prop: "idCard", 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 },
|
{ prop: "marriage", label: "婚姻状况", width: 120, sortable: true, checked: 0 },
|
||||||
@@ -597,16 +543,6 @@ layout("/layouts/platform.html"){
|
|||||||
"member-all-change": MEMBER_ALL_CHANGE_INFO,
|
"member-all-change": MEMBER_ALL_CHANGE_INFO,
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 分页和导出共用该参数构建方法,保证人员属性多选值始终按 JSON 数组提交。
|
|
||||||
buildQueryPageForm(source = this.pageForm) {
|
|
||||||
const pageForm = clone(source)
|
|
||||||
pageForm.userAttributes = JSON.stringify(source.userAttributes || [])
|
|
||||||
return pageForm
|
|
||||||
},
|
|
||||||
// 覆盖公共分页方法,使后端按人员属性集合执行查询。
|
|
||||||
pageData(data = null) {
|
|
||||||
return initTableMixins.methods.pageData.call(this, this.buildQueryPageForm(data || this.pageForm))
|
|
||||||
},
|
|
||||||
dropdownCommand(command) {
|
dropdownCommand(command) {
|
||||||
const {type, data} = command
|
const {type, data} = command
|
||||||
if (type === 'view') {
|
if (type === 'view') {
|
||||||
@@ -667,7 +603,7 @@ layout("/layouts/platform.html"){
|
|||||||
* 导出会员名单
|
* 导出会员名单
|
||||||
*/
|
*/
|
||||||
exportExcel() {
|
exportExcel() {
|
||||||
const pageForm = this.buildQueryPageForm()
|
const pageForm = clone(this.pageForm)
|
||||||
const data = this.tableColumns.filter(item => this.checkedFields.includes(item.prop)).map(item => {
|
const data = this.tableColumns.filter(item => this.checkedFields.includes(item.prop)).map(item => {
|
||||||
return {prop: item.prop, label: item.label}
|
return {prop: item.prop, label: item.label}
|
||||||
})
|
})
|
||||||
@@ -731,10 +667,6 @@ layout("/layouts/platform.html"){
|
|||||||
this.$refs.table.clearSelection()
|
this.$refs.table.clearSelection()
|
||||||
}).catch(() => {})
|
}).catch(() => {})
|
||||||
},
|
},
|
||||||
openBatchEditUserAttribute() {
|
|
||||||
this.batchFormDataUserAttribute = {}
|
|
||||||
this.batchEditUserAttributeVisible = true
|
|
||||||
},
|
|
||||||
openBatchEditMember() {
|
openBatchEditMember() {
|
||||||
this.batchFormDataMember = {member: false, welfareMember: false}
|
this.batchFormDataMember = {member: false, welfareMember: false}
|
||||||
this.batchEditMemberVisible = true
|
this.batchEditMemberVisible = true
|
||||||
@@ -785,23 +717,6 @@ layout("/layouts/platform.html"){
|
|||||||
this.$set(this.unitMoveFormData, "unitName", "")
|
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() {
|
async doBatchEditMember() {
|
||||||
const batch = this.checkUsers.map(v => {
|
const batch = this.checkUsers.map(v => {
|
||||||
return {id: v.id, member: v.member, welfareMember: v.welfareMember}
|
return {id: v.id, member: v.member, welfareMember: v.welfareMember}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ layout("/layouts/platform.html"){
|
|||||||
<div id="app">
|
<div id="app">
|
||||||
<guava ref="guava">
|
<guava ref="guava">
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<common-query ref="commonQueryRef" user-attribute-multiple @search="search"></common-query>
|
<common-query ref="commonQueryRef" @search="search"></common-query>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-card shadow="never" class="mt10">
|
<el-card shadow="never" class="mt10">
|
||||||
|
|||||||
@@ -42,10 +42,6 @@ layout("/layouts/platform.html"){
|
|||||||
<dict-select v-model="pageForm.aidFundMemberUserType" placeholder="请选择人员分类" @change="doSearch"
|
<dict-select v-model="pageForm.aidFundMemberUserType" placeholder="请选择人员分类" @change="doSearch"
|
||||||
code="AIDFUND_MEMBER_USER_TYPE"></dict-select>
|
code="AIDFUND_MEMBER_USER_TYPE"></dict-select>
|
||||||
</search-item>-->
|
</search-item>-->
|
||||||
<search-item label="人员属性">
|
|
||||||
<dict-select v-model="pageForm.userAttributes" placeholder="请选择人员属性" @change="doSearch"
|
|
||||||
code="USER_ATTRIBUTE" multiple collapse-tags clearable></dict-select>
|
|
||||||
</search-item>
|
|
||||||
</search>
|
</search>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
@@ -151,7 +147,6 @@ layout("/layouts/platform.html"){
|
|||||||
personType: "",
|
personType: "",
|
||||||
changeType: "",
|
changeType: "",
|
||||||
aidFundMemberUserType: "",
|
aidFundMemberUserType: "",
|
||||||
userAttributes: []
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -198,8 +193,6 @@ layout("/layouts/platform.html"){
|
|||||||
pageForm.personTypes = JSON.stringify(pageForm.personTypes)
|
pageForm.personTypes = JSON.stringify(pageForm.personTypes)
|
||||||
pageForm.changeTypes = JSON.stringify(pageForm.changeTypes)
|
pageForm.changeTypes = JSON.stringify(pageForm.changeTypes)
|
||||||
pageForm.changeOrigins = JSON.stringify(pageForm.changeOrigins)
|
pageForm.changeOrigins = JSON.stringify(pageForm.changeOrigins)
|
||||||
// 人员属性为多选条件,提交前转换为后端可解析的 JSON 数组。
|
|
||||||
pageForm.userAttributes = JSON.stringify(pageForm.userAttributes)
|
|
||||||
|
|
||||||
this.$axios.post(loc() + '/pageData', pageForm)
|
this.$axios.post(loc() + '/pageData', pageForm)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ layout("/layouts/platform.html"){
|
|||||||
<div id="app" v-cloak>
|
<div id="app" v-cloak>
|
||||||
<guava ref="guava">
|
<guava ref="guava">
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<common-query ref="commonQueryRef" user-attribute-multiple @search="search"></common-query>
|
<common-query ref="commonQueryRef" @search="search"></common-query>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-card shadow="never" class="mt10">
|
<el-card shadow="never" class="mt10">
|
||||||
|
|||||||
@@ -59,8 +59,8 @@
|
|||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="变更信息" name="changeInfo" v-if="viewData.changeInfos">
|
<el-tab-pane label="变更信息" name="changeInfo" v-if="visibleChangeInfos.length">
|
||||||
<el-table :data="viewData.changeInfos" :size="tableSize" @sort-change="pageOrder" ref="table" row-key="id" style="width: 100%">
|
<el-table :data="visibleChangeInfos" :size="tableSize" @sort-change="pageOrder" ref="table" row-key="id" style="width: 100%">
|
||||||
<el-table-column :index="indexMethod" align="center" header-align="center"
|
<el-table-column :index="indexMethod" align="center" header-align="center"
|
||||||
label="序号" type="index" width="80px"></el-table-column>
|
label="序号" type="index" width="80px"></el-table-column>
|
||||||
<el-table-column prop="fieldName" label="变更字段" header-align="center"></el-table-column>
|
<el-table-column prop="fieldName" label="变更字段" header-align="center"></el-table-column>
|
||||||
@@ -119,6 +119,12 @@
|
|||||||
doneTasks: []
|
doneTasks: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
// 人员属性不再展示,其他变更明细保持原有顺序,不改写后端返回的历史数据。
|
||||||
|
visibleChangeInfos() {
|
||||||
|
return (this.viewData.changeInfos || []).filter((item) => item.field !== "userAttribute" && item.fieldName !== "人员属性")
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
info() {
|
info() {
|
||||||
this.$axios.post("/platform/member/change/view/findMemberChangeRecord", { id: this.businessId }).then((res) => {
|
this.$axios.post("/platform/member/change/view/findMemberChangeRecord", { id: this.businessId }).then((res) => {
|
||||||
|
|||||||
@@ -73,7 +73,6 @@ const MEMBER_INFO = {
|
|||||||
<el-descriptions-item label="人员类型">{{ viewData.personType }}</el-descriptions-item>
|
<el-descriptions-item label="人员类型">{{ viewData.personType }}</el-descriptions-item>
|
||||||
|
|
||||||
<!-- 第 4 行 -->
|
<!-- 第 4 行 -->
|
||||||
<el-descriptions-item label="人员属性">{{ viewData.userAttribute }}</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="职称">{{ viewData.professionalTitle }}</el-descriptions-item>
|
<el-descriptions-item label="职称">{{ viewData.professionalTitle }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="职级">{{ viewData.professionalLevel }}</el-descriptions-item>
|
<el-descriptions-item label="职级">{{ viewData.professionalLevel }}</el-descriptions-item>
|
||||||
|
|
||||||
@@ -85,6 +84,7 @@ const MEMBER_INFO = {
|
|||||||
<el-descriptions-item label="行政岗级">{{ viewData.administrativePositionLevel }}</el-descriptions-item>
|
<el-descriptions-item label="行政岗级">{{ viewData.administrativePositionLevel }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="人员分类" v-if="false">{{ viewData.aidFundMemberUserType }}</el-descriptions-item>
|
<el-descriptions-item label="人员分类" v-if="false">{{ viewData.aidFundMemberUserType }}</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
store,
|
store,
|
||||||
|
|||||||
@@ -43,9 +43,5 @@
|
|||||||
<dict-select v-model="pageForm.aidFundMemberUserType" placeholder="请选择人员分类" @change="doSearch"
|
<dict-select v-model="pageForm.aidFundMemberUserType" placeholder="请选择人员分类" @change="doSearch"
|
||||||
code="AIDFUND_MEMBER_USER_TYPE"></dict-select>
|
code="AIDFUND_MEMBER_USER_TYPE"></dict-select>
|
||||||
</search-item>-->
|
</search-item>-->
|
||||||
<search-item label="人员属性">
|
|
||||||
<dict-select v-model="pageForm.userAttributes" placeholder="请选择人员属性" @change="doSearch"
|
|
||||||
code="USER_ATTRIBUTE" multiple collapse-tags clearable></dict-select>
|
|
||||||
</search-item>
|
|
||||||
</search>
|
</search>
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ const COMMON_QUERY = {
|
|||||||
personTypes: [],
|
personTypes: [],
|
||||||
preparedBys: [],
|
preparedBys: [],
|
||||||
aidFundMemberUserType: '',
|
aidFundMemberUserType: '',
|
||||||
userAttributes: [],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -37,8 +36,6 @@ const COMMON_QUERY = {
|
|||||||
pageForm.userStates = JSON.stringify(this.pageForm.userStates)
|
pageForm.userStates = JSON.stringify(this.pageForm.userStates)
|
||||||
pageForm.personTypes = JSON.stringify(this.pageForm.personTypes)
|
pageForm.personTypes = JSON.stringify(this.pageForm.personTypes)
|
||||||
pageForm.preparedBys = JSON.stringify(this.pageForm.preparedBys)
|
pageForm.preparedBys = JSON.stringify(this.pageForm.preparedBys)
|
||||||
// 人员属性多选值按现有数组查询参数口径提交。
|
|
||||||
pageForm.userAttributes = JSON.stringify(this.pageForm.userAttributes)
|
|
||||||
this.$emit('search', pageForm)
|
this.$emit('search', pageForm)
|
||||||
},
|
},
|
||||||
handleUnionChange() {
|
handleUnionChange() {
|
||||||
|
|||||||
+1
-7
@@ -102,12 +102,6 @@
|
|||||||
style="width: 100%"></dict-select>
|
style="width: 100%"></dict-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="人员属性">
|
|
||||||
<el-form-item prop="userAttribute">
|
|
||||||
<dict-select v-model="formData.userAttribute" code="USER_ATTRIBUTE"
|
|
||||||
style="width: 100%"></dict-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="人员分类">
|
<el-descriptions-item label="人员分类">
|
||||||
<el-form-item prop="aidFundMemberUserType">
|
<el-form-item prop="aidFundMemberUserType">
|
||||||
<dict-select v-model="formData.aidFundMemberUserType" code="AIDFUND_MEMBER_USER_TYPE"
|
<dict-select v-model="formData.aidFundMemberUserType" code="AIDFUND_MEMBER_USER_TYPE"
|
||||||
@@ -252,7 +246,7 @@
|
|||||||
`,
|
`,
|
||||||
store,
|
store,
|
||||||
dicts: ["USER_NATION", "USER_POLITICAL", "USER_EDUCATION", "USER_ACADEMIC_DEGREE", "USER_CAMPUS",
|
dicts: ["USER_NATION", "USER_POLITICAL", "USER_EDUCATION", "USER_ACADEMIC_DEGREE", "USER_CAMPUS",
|
||||||
"USER_STATE", "USER_PREPARED_BY_TYPE", "USER_PERSON_TYPE", "USER_MARRIAGE","AIDFUND_MEMBER_USER_TYPE","USER_ATTRIBUTE"],
|
"USER_STATE", "USER_PREPARED_BY_TYPE", "USER_PERSON_TYPE", "USER_MARRIAGE","AIDFUND_MEMBER_USER_TYPE"],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
formData: {},
|
formData: {},
|
||||||
|
|||||||
@@ -292,7 +292,6 @@ layout("/layouts/platform.html"){
|
|||||||
search(pageForm) {
|
search(pageForm) {
|
||||||
if (pageForm) {
|
if (pageForm) {
|
||||||
// 当前页的在职状态、人员类型使用标签数组筛选,公共查询组件回传的是字符串,
|
// 当前页的在职状态、人员类型使用标签数组筛选,公共查询组件回传的是字符串,
|
||||||
// 这里保留当前页数组,避免选择人员属性后把标签筛选状态覆盖掉。
|
|
||||||
const currentUserStates = this.pageForm.userStates
|
const currentUserStates = this.pageForm.userStates
|
||||||
const currentPersonTypes = this.pageForm.personTypes
|
const currentPersonTypes = this.pageForm.personTypes
|
||||||
this.pageForm = {...this.pageForm, ...pageForm}
|
this.pageForm = {...this.pageForm, ...pageForm}
|
||||||
|
|||||||
@@ -458,7 +458,6 @@ layout("/layouts/platform.html"){
|
|||||||
{ prop: "unionName", label: "所属工会", sortable: true },
|
{ prop: "unionName", label: "所属工会", sortable: true },
|
||||||
{ prop: "unitName", label: "所属单位",sortable: true },
|
{ prop: "unitName", label: "所属单位",sortable: true },
|
||||||
// { prop: "aidFundMemberUserType", 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: "idCardType", label: "证件类型", width: 120, sortable: true, checked: 0 },
|
||||||
{ prop: "idCard", 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 },
|
{ prop: "marriage", label: "婚姻状况", width: 120, sortable: true, checked: 0 },
|
||||||
|
|||||||
@@ -49,10 +49,6 @@ layout("/layouts/platform.html"){
|
|||||||
<search-item label="人员分类" v-if="false">
|
<search-item label="人员分类" v-if="false">
|
||||||
<dict-select v-model="pageForm.aidFundMemberUserType" placeholder="请选择人员分类" @change="doSearch" code="AIDFUND_MEMBER_USER_TYPE"></dict-select>
|
<dict-select v-model="pageForm.aidFundMemberUserType" placeholder="请选择人员分类" @change="doSearch" code="AIDFUND_MEMBER_USER_TYPE"></dict-select>
|
||||||
</search-item>
|
</search-item>
|
||||||
<search-item label="人员属性">
|
|
||||||
<dict-select v-model="pageForm.userAttributes" placeholder="请选择人员属性" @change="doSearch"
|
|
||||||
code="USER_ATTRIBUTE" multiple collapse-tags clearable></dict-select>
|
|
||||||
</search-item>
|
|
||||||
</search>
|
</search>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
@@ -102,7 +98,7 @@ layout("/layouts/platform.html"){
|
|||||||
new Vue({
|
new Vue({
|
||||||
el: "#app",
|
el: "#app",
|
||||||
mixins: [initTableMixins],
|
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() {
|
data() {
|
||||||
return {
|
return {
|
||||||
pageForm: {
|
pageForm: {
|
||||||
@@ -110,7 +106,6 @@ layout("/layouts/platform.html"){
|
|||||||
memberSearchName: "",
|
memberSearchName: "",
|
||||||
memberSearchKeyWord: "",
|
memberSearchKeyWord: "",
|
||||||
aidFundMemberUserType: "",
|
aidFundMemberUserType: "",
|
||||||
userAttributes: []
|
|
||||||
},
|
},
|
||||||
userId: "",
|
userId: "",
|
||||||
unions: [],
|
unions: [],
|
||||||
@@ -133,16 +128,6 @@ layout("/layouts/platform.html"){
|
|||||||
"member-info": MEMBER_INFO
|
"member-info": MEMBER_INFO
|
||||||
},
|
},
|
||||||
methods: {
|
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) {
|
openView(row) {
|
||||||
this.$refs.guava.view(() => {
|
this.$refs.guava.view(() => {
|
||||||
this.$refs.memberInfoRef.onOpen(row.id)
|
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 })
|
this.$downLoad("/platform/member/info/history/doExportByUnion", { year: this.pageForm.year })
|
||||||
},
|
},
|
||||||
doExport() {
|
doExport() {
|
||||||
this.$downLoad("/platform/member/info/history/doExport", this.buildQueryPageForm())
|
this.$downLoad("/platform/member/info/history/doExport", clone(this.pageForm))
|
||||||
},
|
},
|
||||||
async initData() {
|
async initData() {
|
||||||
if (this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])) {
|
if (this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])) {
|
||||||
|
|||||||
@@ -49,10 +49,6 @@ layout("/layouts/platform.html"){
|
|||||||
<search-item label="人员分类" v-if="false">
|
<search-item label="人员分类" v-if="false">
|
||||||
<dict-select v-model="pageForm.aidFundMemberUserType" placeholder="请选择人员分类" @change="doSearch" code="AIDFUND_MEMBER_USER_TYPE"></dict-select>
|
<dict-select v-model="pageForm.aidFundMemberUserType" placeholder="请选择人员分类" @change="doSearch" code="AIDFUND_MEMBER_USER_TYPE"></dict-select>
|
||||||
</search-item>
|
</search-item>
|
||||||
<search-item label="人员属性">
|
|
||||||
<dict-select v-model="pageForm.userAttributes" placeholder="请选择人员属性" @change="doSearch"
|
|
||||||
code="USER_ATTRIBUTE" multiple collapse-tags clearable></dict-select>
|
|
||||||
</search-item>
|
|
||||||
</search>
|
</search>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
@@ -109,11 +105,10 @@ layout("/layouts/platform.html"){
|
|||||||
new Vue({
|
new Vue({
|
||||||
el: "#app",
|
el: "#app",
|
||||||
mixins: [initTableMixins],
|
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() {
|
data() {
|
||||||
return {
|
return {
|
||||||
pageForm: {
|
pageForm: {
|
||||||
userAttributes: [],
|
|
||||||
year: new Date().getFullYear() + "",
|
year: new Date().getFullYear() + "",
|
||||||
memberSearchName: "",
|
memberSearchName: "",
|
||||||
memberSearchKeyWord: ""
|
memberSearchKeyWord: ""
|
||||||
@@ -141,12 +136,6 @@ layout("/layouts/platform.html"){
|
|||||||
"member-add-form": MEMBER_ADD_FORM
|
"member-add-form": MEMBER_ADD_FORM
|
||||||
},
|
},
|
||||||
methods: {
|
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() {
|
openAdd() {
|
||||||
this.$refs.guava.edit(() => {
|
this.$refs.guava.edit(() => {
|
||||||
this.$refs.memberAddFormRef.onOpen()
|
this.$refs.memberAddFormRef.onOpen()
|
||||||
|
|||||||
-37
@@ -129,29 +129,6 @@ layout("/layouts/platform.html"){
|
|||||||
</span>
|
</span>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row type="flex" align="middle" class="query-row query-row-tag">
|
|
||||||
<el-col class="query-row-title">人员属性:</el-col>
|
|
||||||
<el-col class="query-row-content query-row-content-tag">
|
|
||||||
<el-tag class="query-tag-item"
|
|
||||||
v-for="item in userAttributeOptions"
|
|
||||||
:key="item.code"
|
|
||||||
:effect="pageForm.userAttributes.includes(item.code)?'dark':'plain'"
|
|
||||||
@click="tagClick('userAttributes',item.code)">
|
|
||||||
{{ item.name }}
|
|
||||||
</el-tag>
|
|
||||||
<span class="query-tag-actions">
|
|
||||||
<el-link type="danger"
|
|
||||||
v-if="userAttributeOptions.length&&pageForm.userAttributes.length"
|
|
||||||
:underline="false"
|
|
||||||
@click="pageForm.userAttributes=[];doSearch()">清空
|
|
||||||
</el-link>
|
|
||||||
<el-link :underline="false"
|
|
||||||
@click="pageForm.userAttributes=userAttributeOptions.map(p=>p.code);doSearch()"
|
|
||||||
type="success">全部
|
|
||||||
</el-link>
|
|
||||||
</span>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-card shadow="never" class="mt10">
|
<el-card shadow="never" class="mt10">
|
||||||
@@ -237,12 +214,10 @@ layout("/layouts/platform.html"){
|
|||||||
units: [],
|
units: [],
|
||||||
personTypeOptions: [],
|
personTypeOptions: [],
|
||||||
aidFundMemberUserTypeOptions: [],
|
aidFundMemberUserTypeOptions: [],
|
||||||
userAttributeOptions: [],
|
|
||||||
pageForm: {
|
pageForm: {
|
||||||
currentYear: moment().format("YYYY"),
|
currentYear: moment().format("YYYY"),
|
||||||
queryType: "fgh",
|
queryType: "fgh",
|
||||||
personTypes: [],
|
personTypes: [],
|
||||||
userAttributes: [],
|
|
||||||
aidFundMemberUserTypes: []
|
aidFundMemberUserTypes: []
|
||||||
},
|
},
|
||||||
fullTableData: []
|
fullTableData: []
|
||||||
@@ -271,16 +246,11 @@ layout("/layouts/platform.html"){
|
|||||||
this.$businessTool.getDictOptions("AIDFUND_MEMBER_USER_TYPE").then((data) => {
|
this.$businessTool.getDictOptions("AIDFUND_MEMBER_USER_TYPE").then((data) => {
|
||||||
this.aidFundMemberUserTypeOptions = data
|
this.aidFundMemberUserTypeOptions = data
|
||||||
})
|
})
|
||||||
this.$businessTool.getDictOptions("USER_ATTRIBUTE").then((data) => {
|
|
||||||
this.userAttributeOptions = data
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
pageData() {
|
pageData() {
|
||||||
// 统计接口按 JSON 字符串接收多选条件,这里统一在提交前做转换,保证人员分类和人员属性都能正确过滤。
|
|
||||||
const pageForm = clone(this.pageForm)
|
const pageForm = clone(this.pageForm)
|
||||||
pageForm.personTypes = JSON.stringify(this.pageForm.personTypes)
|
pageForm.personTypes = JSON.stringify(this.pageForm.personTypes)
|
||||||
pageForm.aidFundMemberUserTypes = JSON.stringify(this.pageForm.aidFundMemberUserTypes)
|
pageForm.aidFundMemberUserTypes = JSON.stringify(this.pageForm.aidFundMemberUserTypes)
|
||||||
pageForm.userAttributes = JSON.stringify(this.pageForm.userAttributes)
|
|
||||||
this.$axios.post(loc() + "/pageData", pageForm).then((res) => {
|
this.$axios.post(loc() + "/pageData", pageForm).then((res) => {
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
this.tableData = res.data
|
this.tableData = res.data
|
||||||
@@ -296,13 +266,6 @@ layout("/layouts/platform.html"){
|
|||||||
this.pageForm.personTypes.push(code)
|
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 (key === "aidFundMemberUserTypes") {
|
||||||
if (this.pageForm.aidFundMemberUserTypes.includes(code)) {
|
if (this.pageForm.aidFundMemberUserTypes.includes(code)) {
|
||||||
this.pageForm.aidFundMemberUserTypes.splice(this.pageForm.aidFundMemberUserTypes.indexOf(code), 1)
|
this.pageForm.aidFundMemberUserTypes.splice(this.pageForm.aidFundMemberUserTypes.indexOf(code), 1)
|
||||||
|
|||||||
-3
@@ -165,7 +165,6 @@ layout("/layouts/platform.html"){
|
|||||||
{ prop: "unitName", label: "所属单位", width: 120, sortable: true },
|
{ prop: "unitName", label: "所属单位", width: 120, sortable: true },
|
||||||
// 临时屏蔽“人员分类”列表字段,不删除配置,后续需要可恢复。
|
// 临时屏蔽“人员分类”列表字段,不删除配置,后续需要可恢复。
|
||||||
// { prop: "aidFundMemberUserType", 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: "idCardType", label: "证件类型", width: 120, sortable: true, checked: 0 },
|
||||||
{ prop: "idCard", 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 },
|
{ 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.memberTypes = JSON.stringify(this.pageForm.memberTypes)
|
||||||
pageForm.personTypes = JSON.stringify(this.pageForm.personTypes)
|
pageForm.personTypes = JSON.stringify(this.pageForm.personTypes)
|
||||||
pageForm.aidFundMemberUserTypes = JSON.stringify(this.pageForm.aidFundMemberUserTypes)
|
pageForm.aidFundMemberUserTypes = JSON.stringify(this.pageForm.aidFundMemberUserTypes)
|
||||||
pageForm.userAttributes = JSON.stringify(this.pageForm.userAttributes)
|
|
||||||
pageForm.userStates = JSON.stringify(this.pageForm.userStates)
|
pageForm.userStates = JSON.stringify(this.pageForm.userStates)
|
||||||
const data = this.tableColumns.filter(item => this.checkedFields.includes(item.prop)).map(item => {
|
const data = this.tableColumns.filter(item => this.checkedFields.includes(item.prop)).map(item => {
|
||||||
return {prop: item.prop, label: item.label}
|
return {prop: item.prop, label: item.label}
|
||||||
@@ -230,7 +228,6 @@ layout("/layouts/platform.html"){
|
|||||||
pageForm.memberTypes = JSON.stringify(this.pageForm.memberTypes)
|
pageForm.memberTypes = JSON.stringify(this.pageForm.memberTypes)
|
||||||
pageForm.personTypes = JSON.stringify(this.pageForm.personTypes)
|
pageForm.personTypes = JSON.stringify(this.pageForm.personTypes)
|
||||||
pageForm.aidFundMemberUserTypes = JSON.stringify(this.pageForm.aidFundMemberUserTypes)
|
pageForm.aidFundMemberUserTypes = JSON.stringify(this.pageForm.aidFundMemberUserTypes)
|
||||||
pageForm.userAttributes = JSON.stringify(this.pageForm.userAttributes)
|
|
||||||
pageForm.preparedBys = JSON.stringify(this.pageForm.preparedBys)
|
pageForm.preparedBys = JSON.stringify(this.pageForm.preparedBys)
|
||||||
pageForm.memberStatus = JSON.stringify(this.pageForm.memberStatus)
|
pageForm.memberStatus = JSON.stringify(this.pageForm.memberStatus)
|
||||||
pageForm.userStates = JSON.stringify(this.pageForm.userStates)
|
pageForm.userStates = JSON.stringify(this.pageForm.userStates)
|
||||||
|
|||||||
-30
@@ -113,30 +113,6 @@ const MEMBER_STATISTICS_COMPREHENSIVE_QUERY_FORM = {
|
|||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-row type="flex" align="middle" class="query-row query-row-tag">
|
|
||||||
<el-col class="query-row-title">人员属性:</el-col>
|
|
||||||
<el-col class="query-row-content query-row-content-tag">
|
|
||||||
<el-tag
|
|
||||||
style="margin-right: 10px;cursor: pointer"
|
|
||||||
v-for="item in userAttributeOptions"
|
|
||||||
:key="item.code"
|
|
||||||
:type="item.name"
|
|
||||||
:effect="pageForm.userAttributes.includes(item.code)?'dark':'plain'"
|
|
||||||
@click="tagClick('userAttributes',item.code)">
|
|
||||||
{{ item.name }}
|
|
||||||
</el-tag>
|
|
||||||
|
|
||||||
<el-link type="danger"
|
|
||||||
v-if="userAttributeOptions.length&&pageForm.userAttributes.length"
|
|
||||||
:underline="false"
|
|
||||||
@click="pageForm.userAttributes=[];doSearch()">清空
|
|
||||||
</el-link>
|
|
||||||
<el-link :underline="false"
|
|
||||||
@click="pageForm.userAttributes=userAttributeOptions.map(p=>p.code);doSearch()"
|
|
||||||
type="success">全部
|
|
||||||
</el-link>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
|
|
||||||
<el-row type="flex" align="middle" class="query-row">
|
<el-row type="flex" align="middle" class="query-row">
|
||||||
<el-col class="query-row-content">
|
<el-col class="query-row-content">
|
||||||
@@ -235,7 +211,6 @@ const MEMBER_STATISTICS_COMPREHENSIVE_QUERY_FORM = {
|
|||||||
personTypes: [],
|
personTypes: [],
|
||||||
preparedBys: [],
|
preparedBys: [],
|
||||||
aidFundMemberUserTypes: [],
|
aidFundMemberUserTypes: [],
|
||||||
userAttributes: [],
|
|
||||||
userStates: [],
|
userStates: [],
|
||||||
memberStatus: [],
|
memberStatus: [],
|
||||||
year: moment().format("YYYY"),
|
year: moment().format("YYYY"),
|
||||||
@@ -253,7 +228,6 @@ const MEMBER_STATISTICS_COMPREHENSIVE_QUERY_FORM = {
|
|||||||
personTypeOptions: [],
|
personTypeOptions: [],
|
||||||
preparedByOptions: [],
|
preparedByOptions: [],
|
||||||
aidFundMemberUserTypeOptions: [],
|
aidFundMemberUserTypeOptions: [],
|
||||||
userAttributeOptions: [],
|
|
||||||
userStateOptions: [],
|
userStateOptions: [],
|
||||||
memberStatusOptions: [],
|
memberStatusOptions: [],
|
||||||
unions: [],
|
unions: [],
|
||||||
@@ -346,7 +320,6 @@ const MEMBER_STATISTICS_COMPREHENSIVE_QUERY_FORM = {
|
|||||||
this.pageForm.personTypes = []
|
this.pageForm.personTypes = []
|
||||||
this.pageForm.preparedBys = []
|
this.pageForm.preparedBys = []
|
||||||
this.pageForm.aidFundMemberUserTypes = []
|
this.pageForm.aidFundMemberUserTypes = []
|
||||||
this.pageForm.userAttributes = []
|
|
||||||
this.pageForm.memberStatus = []
|
this.pageForm.memberStatus = []
|
||||||
this.pageForm.userStates = []
|
this.pageForm.userStates = []
|
||||||
this.pageForm.unionId = []
|
this.pageForm.unionId = []
|
||||||
@@ -387,9 +360,6 @@ const MEMBER_STATISTICS_COMPREHENSIVE_QUERY_FORM = {
|
|||||||
this.$businessTool.getDictOptions("AIDFUND_MEMBER_USER_TYPE").then((data) => {
|
this.$businessTool.getDictOptions("AIDFUND_MEMBER_USER_TYPE").then((data) => {
|
||||||
this.aidFundMemberUserTypeOptions = data
|
this.aidFundMemberUserTypeOptions = data
|
||||||
})
|
})
|
||||||
this.$businessTool.getDictOptions("USER_ATTRIBUTE").then((data) => {
|
|
||||||
this.userAttributeOptions = data
|
|
||||||
})
|
|
||||||
this.$businessTool.getDictOptions("USER_STATE").then((data) => {
|
this.$businessTool.getDictOptions("USER_STATE").then((data) => {
|
||||||
this.userStateOptions = data
|
this.userStateOptions = data
|
||||||
})
|
})
|
||||||
|
|||||||
-37
@@ -129,29 +129,6 @@ layout("/layouts/platform.html"){
|
|||||||
</span>
|
</span>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row type="flex" align="middle" class="query-row query-row-tag">
|
|
||||||
<el-col class="query-row-title">人员属性:</el-col>
|
|
||||||
<el-col class="query-row-content query-row-content-tag">
|
|
||||||
<el-tag class="query-tag-item"
|
|
||||||
v-for="item in userAttributeOptions"
|
|
||||||
:key="item.code"
|
|
||||||
:effect="pageForm.userAttributes.includes(item.code)?'dark':'plain'"
|
|
||||||
@click="tagClick('userAttributes',item.code)">
|
|
||||||
{{ item.name }}
|
|
||||||
</el-tag>
|
|
||||||
<span class="query-tag-actions">
|
|
||||||
<el-link type="danger"
|
|
||||||
v-if="userAttributeOptions.length&&pageForm.userAttributes.length"
|
|
||||||
:underline="false"
|
|
||||||
@click="pageForm.userAttributes=[];doSearch()">清空
|
|
||||||
</el-link>
|
|
||||||
<el-link :underline="false"
|
|
||||||
@click="pageForm.userAttributes=userAttributeOptions.map(p=>p.code);doSearch()"
|
|
||||||
type="success">全部
|
|
||||||
</el-link>
|
|
||||||
</span>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-card shadow="never" class="mt10">
|
<el-card shadow="never" class="mt10">
|
||||||
@@ -198,12 +175,10 @@ layout("/layouts/platform.html"){
|
|||||||
unions: [],
|
unions: [],
|
||||||
units: [],
|
units: [],
|
||||||
personTypeOptions: [],
|
personTypeOptions: [],
|
||||||
userAttributeOptions: [],
|
|
||||||
pageForm: {
|
pageForm: {
|
||||||
currentYear: moment().format("YYYY"),
|
currentYear: moment().format("YYYY"),
|
||||||
queryType: "fgh",
|
queryType: "fgh",
|
||||||
personTypes: [],
|
personTypes: [],
|
||||||
userAttributes: [],
|
|
||||||
aidFundMemberUserTypes: []
|
aidFundMemberUserTypes: []
|
||||||
},
|
},
|
||||||
aidFundMemberUserTypeOptions: [],
|
aidFundMemberUserTypeOptions: [],
|
||||||
@@ -232,9 +207,6 @@ layout("/layouts/platform.html"){
|
|||||||
this.$businessTool.getDictOptions("AIDFUND_MEMBER_USER_TYPE").then((data) => {
|
this.$businessTool.getDictOptions("AIDFUND_MEMBER_USER_TYPE").then((data) => {
|
||||||
this.aidFundMemberUserTypeOptions = data
|
this.aidFundMemberUserTypeOptions = data
|
||||||
})
|
})
|
||||||
this.$businessTool.getDictOptions("USER_ATTRIBUTE").then((data) => {
|
|
||||||
this.userAttributeOptions = data
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
tagClick(key,code) {
|
tagClick(key,code) {
|
||||||
if (key === "personTypes") {
|
if (key === "personTypes") {
|
||||||
@@ -244,13 +216,6 @@ layout("/layouts/platform.html"){
|
|||||||
this.pageForm.personTypes.push(code)
|
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 (key === "aidFundMemberUserTypes") {
|
||||||
if (this.pageForm.aidFundMemberUserTypes.includes(code)) {
|
if (this.pageForm.aidFundMemberUserTypes.includes(code)) {
|
||||||
this.pageForm.aidFundMemberUserTypes.splice(this.pageForm.aidFundMemberUserTypes.indexOf(code), 1)
|
this.pageForm.aidFundMemberUserTypes.splice(this.pageForm.aidFundMemberUserTypes.indexOf(code), 1)
|
||||||
@@ -262,10 +227,8 @@ layout("/layouts/platform.html"){
|
|||||||
},
|
},
|
||||||
pageData() {
|
pageData() {
|
||||||
const pageForm = clone(this.pageForm)
|
const pageForm = clone(this.pageForm)
|
||||||
// 统计接口按 JSON 字符串接收多选条件,这里把人员分类和人员属性统一成同一提交口径。
|
|
||||||
pageForm.personTypes = JSON.stringify(this.pageForm.personTypes)
|
pageForm.personTypes = JSON.stringify(this.pageForm.personTypes)
|
||||||
pageForm.aidFundMemberUserTypes = JSON.stringify(this.pageForm.aidFundMemberUserTypes)
|
pageForm.aidFundMemberUserTypes = JSON.stringify(this.pageForm.aidFundMemberUserTypes)
|
||||||
pageForm.userAttributes = JSON.stringify(this.pageForm.userAttributes)
|
|
||||||
this.$axios.post(loc() + "/pageData", pageForm).then((res) => {
|
this.$axios.post(loc() + "/pageData", pageForm).then((res) => {
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
this.tableData = res.data
|
this.tableData = res.data
|
||||||
|
|||||||
Reference in New Issue
Block a user