Merge remote-tracking branch 'origin/main'
This commit is contained in:
@@ -230,7 +230,7 @@ public class FlowTodoCenterController {
|
|||||||
dao.execute(todoSql);
|
dao.execute(todoSql);
|
||||||
int todoCount = todoSql.getInt();
|
int todoCount = todoSql.getInt();
|
||||||
|
|
||||||
// 查询我的已办任务
|
// 已办统计排除发起节点 startTask,与已办列表保持一致,避免将本人发起流程计入已办数量。
|
||||||
Sql doneSql = Sqls.create("""
|
Sql doneSql = Sqls.create("""
|
||||||
SELECT
|
SELECT
|
||||||
count(1)
|
count(1)
|
||||||
@@ -240,6 +240,7 @@ public class FlowTodoCenterController {
|
|||||||
WHERE
|
WHERE
|
||||||
ta.actorId = @userId
|
ta.actorId = @userId
|
||||||
AND t.taskState = 20
|
AND t.taskState = 20
|
||||||
|
AND t.taskName != 'startTask'
|
||||||
""");
|
""");
|
||||||
doneSql.setParam("userId", SecurityUtil.getUserId());
|
doneSql.setParam("userId", SecurityUtil.getUserId());
|
||||||
doneSql.setCallback(Sqls.callback.integer());
|
doneSql.setCallback(Sqls.callback.integer());
|
||||||
|
|||||||
@@ -69,17 +69,6 @@ public class SysDataUserPullController {
|
|||||||
return Result.success();
|
return Result.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@At
|
|
||||||
@SaCheckPermission("sys.data.user.pull")
|
|
||||||
@ApiOperation("同步教职工手机号")
|
|
||||||
public Result syncTeacherMobile() {
|
|
||||||
try {
|
|
||||||
return Result.success(sysUserPullService.syncTeacherMobile());
|
|
||||||
} catch (Exception e) {
|
|
||||||
return Result.error(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@At
|
@At
|
||||||
@SaCheckPermission("sys.data.user.pull")
|
@SaCheckPermission("sys.data.user.pull")
|
||||||
@ApiOperation("删除用户数据")
|
@ApiOperation("删除用户数据")
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import com.budwk.app.sys.services.*;
|
|||||||
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;
|
||||||
@@ -47,6 +49,8 @@ public class SysDataUserUpdateController {
|
|||||||
@Inject
|
@Inject
|
||||||
private SysUserService sysUserService;
|
private SysUserService sysUserService;
|
||||||
@Inject
|
@Inject
|
||||||
|
private SysUserMobileSyncService sysUserMobileSyncService;
|
||||||
|
@Inject
|
||||||
private SysDataUserPullService sysDataUserPullService;
|
private SysDataUserPullService sysDataUserPullService;
|
||||||
@Inject
|
@Inject
|
||||||
private SysDataUnitPullService sysDataUnitPullService;
|
private SysDataUnitPullService sysDataUnitPullService;
|
||||||
@@ -62,7 +66,8 @@ public class SysDataUserUpdateController {
|
|||||||
@At
|
@At
|
||||||
@SaCheckPermission("sys.data.user.pull")
|
@SaCheckPermission("sys.data.user.pull")
|
||||||
@ApiOperation("分页数据")
|
@ApiOperation("分页数据")
|
||||||
@Ok("json:{locked:'password|idCard|mobile'}")
|
// 手机号用于列表核对拉取结果;密码和身份证号仍不返回。
|
||||||
|
@Ok("json:{locked:'password|idCard'}")
|
||||||
public Result pageData(@Valid SysDataUserUpdatePageForm pageForm) {
|
public Result pageData(@Valid SysDataUserUpdatePageForm pageForm) {
|
||||||
Sql sql = Sqls.create("""
|
Sql sql = Sqls.create("""
|
||||||
SELECT
|
SELECT
|
||||||
@@ -136,4 +141,46 @@ public class SysDataUserUpdateController {
|
|||||||
sysDataDictPullService.pullDataDict();
|
sysDataDictPullService.pullDataDict();
|
||||||
return Result.success();
|
return Result.success();
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 预览:scope传ALL/MEMBER/FILTER,mode传FILL/REFRESH,pageForm传列表筛选条件。
|
||||||
|
* 返回NutMap,scopeCount/existingCount/cooldownCount/total分别为范围、已有号、冷却及待请求工号数。
|
||||||
|
*/
|
||||||
|
@At
|
||||||
|
@SaCheckPermission("sys.data.user.update")
|
||||||
|
public Result mobilePreview(String scope, String mode, SysDataUserUpdatePageForm pageForm) {
|
||||||
|
return Result.success(sysUserMobileSyncService.preview(scope, mode, pageForm));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动:scope/mode及pageForm同预览;action传NEW/RESUME/RETRY,sourceTaskId仅继续或重试时传原任务编号。
|
||||||
|
* 返回NutMap进度:taskId任务编号、status状态及total/processed/updated/empty/failed/skipped各项人数。
|
||||||
|
*/
|
||||||
|
@At
|
||||||
|
@SaCheckPermission("sys.data.user.update")
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
|
@SLog(tag = "手机号拉取", msg = "启动手机号后台拉取任务")
|
||||||
|
public Result mobileStart(String scope, String mode, SysDataUserUpdatePageForm pageForm, String sourceTaskId, String action) {
|
||||||
|
return Result.success(sysUserMobileSyncService.start(scope, mode, pageForm, sourceTaskId, action));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 进度:taskId可为空(最近任务)或传启动接口返回的编号;返回与启动一致的NutMap,不返回手机号与工号队列。
|
||||||
|
*/
|
||||||
|
@At
|
||||||
|
@SaCheckPermission("sys.data.user.update")
|
||||||
|
public Result mobileStatus(String taskId) {
|
||||||
|
return Result.success(sysUserMobileSyncService.status(taskId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止:taskId必须传当前任务编号;返回NutMap最新进度,当前请求结束后停止且保留已完成结果。
|
||||||
|
*/
|
||||||
|
@At
|
||||||
|
@SaCheckPermission("sys.data.user.update")
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
|
@SLog(tag = "手机号拉取", msg = "停止手机号后台拉取任务")
|
||||||
|
public Result mobileStop(String taskId) {
|
||||||
|
return Result.success(sysUserMobileSyncService.stop(taskId));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,4 +53,20 @@ public interface SysDataUserPullService extends BaseService<Sys_user_source> {
|
|||||||
* @return 同步过程统计信息,包含工号手机号映射
|
* @return 同步过程统计信息,包含工号手机号映射
|
||||||
*/
|
*/
|
||||||
NutMap syncTeacherMobileByJobNos(List<String> jobNos);
|
NutMap syncTeacherMobileByJobNos(List<String> jobNos);
|
||||||
|
/**
|
||||||
|
* 按单个工号读取数据中心手机号,不修改数据库;空字符串表示接口明确没有号码。
|
||||||
|
* @param jobNo 非空教职工工号
|
||||||
|
* @return 已校验的手机号;接口异常、工号不匹配或号码格式异常时抛出异常
|
||||||
|
*/
|
||||||
|
String fetchTeacherMobile(String jobNo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存单人工号的有效号码,使用请求前快照避免覆盖期间的人工修改。
|
||||||
|
* @param jobNo 数据中心查询工号
|
||||||
|
* @param mobile 已校验的非空手机号
|
||||||
|
* @param originalMobiles 请求前的用户ID到原手机号映射
|
||||||
|
* @param fillOnly true仅补空号,false核对更新已有号码
|
||||||
|
* @return 实际更新的系统用户行数
|
||||||
|
*/
|
||||||
|
int saveTeacherMobile(String jobNo, String mobile, Map<String, String> originalMobiles, boolean fillOnly);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -438,6 +438,101 @@ public class SysDataUserPullServiceImpl extends BaseServiceImpl<Sys_user_source>
|
|||||||
return listMap(sql);
|
return listMap(sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 后台任务逐工号读取号码:每个分页请求均设置超时,且不输出号码或接口原文。
|
||||||
|
* 分页间等待一秒,避免单人工号多页响应绕过任务限速。
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String fetchTeacherMobile(String jobNo) {
|
||||||
|
DataCenterProperties.Credential credential = dataCenterProperties.credential(TEACHER_MOBILE_CONFIG_KEY);
|
||||||
|
Set<String> numbers = new LinkedHashSet<>();
|
||||||
|
int pages = 1;
|
||||||
|
for (int page = 1; page <= pages; page++) {
|
||||||
|
if (page > 1) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
throw new BaseException("手机号拉取已中断");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String body;
|
||||||
|
try (cn.hutool.http.HttpResponse response = HttpUtil.createPost(credential.getUrl())
|
||||||
|
.header(Header.CONTENT_TYPE, "application/json")
|
||||||
|
.header("X-H3C-TOKEN", credential.getToken())
|
||||||
|
.timeout(10000)
|
||||||
|
.body(JSONUtil.toJsonStr(buildTeacherMobileRequestBody(jobNo, page, TEACHER_MOBILE_PAGE_SIZE)))
|
||||||
|
.execute()) {
|
||||||
|
if (response.getStatus() != 200) {
|
||||||
|
throw new BaseException("手机号接口HTTP异常,请稍后重试");
|
||||||
|
}
|
||||||
|
body = response.body();
|
||||||
|
}
|
||||||
|
pages = collectTeacherMobilePage(body, jobNo, numbers);
|
||||||
|
}
|
||||||
|
return numbers.isEmpty() ? "" : numbers.iterator().next();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 校验单工号响应结构、页数与号码一致性;只有明确的空records或空号码才视为无号码。 */
|
||||||
|
private int collectTeacherMobilePage(String body, String jobNo, Set<String> numbers) {
|
||||||
|
JSONObject response = JSONUtil.parseObj(body);
|
||||||
|
if (!"0".equals(response.getStr("code"))) {
|
||||||
|
throw new BaseException("手机号接口未成功返回,请检查接口授权或稍后重试");
|
||||||
|
}
|
||||||
|
JSONObject data = response.getJSONObject("data");
|
||||||
|
JSONObject pagination = data == null ? response : data;
|
||||||
|
int pages = Math.max(pagination.getInt("pages", 1),
|
||||||
|
(int) Math.ceil(pagination.getInt("total", 0) / (double) TEACHER_MOBILE_PAGE_SIZE));
|
||||||
|
// 单工号异常大分页通常意味着过滤条件失效,禁止继续当作全量接口拉取。
|
||||||
|
if (pages > 5) {
|
||||||
|
throw new BaseException("单工号返回数据量异常");
|
||||||
|
}
|
||||||
|
JSONArray records = response.getJSONArray("records");
|
||||||
|
if (records == null && data != null) records = data.getJSONArray("records");
|
||||||
|
if (records == null) {
|
||||||
|
throw new BaseException("手机号接口缺少records字段");
|
||||||
|
}
|
||||||
|
for (Object record : records) {
|
||||||
|
JSONObject row = JSONUtil.parseObj(record);
|
||||||
|
if (!jobNo.equals(StrUtil.trimToEmpty(row.getStr("gh")))) {
|
||||||
|
throw new BaseException("手机号接口返回工号不匹配");
|
||||||
|
}
|
||||||
|
String mobile = StrUtil.trimToEmpty(row.getStr("sjh"));
|
||||||
|
if (mobile.startsWith("+86")) mobile = mobile.substring(3);
|
||||||
|
if (mobile.startsWith("0086")) mobile = mobile.substring(4);
|
||||||
|
if (StrUtil.isNotBlank(mobile)) {
|
||||||
|
if (!mobile.matches("1[3-9][0-9]{9}")) {
|
||||||
|
throw new BaseException("接口手机号格式异常");
|
||||||
|
}
|
||||||
|
numbers.add(mobile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (numbers.size() > 1) {
|
||||||
|
throw new BaseException("同一工号返回多个不同手机号,需人工核实");
|
||||||
|
}
|
||||||
|
return pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仅在原手机号未被他人修改时落库;空返回值不清空原号,补齐模式不覆盖已有号码。
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
|
public int saveTeacherMobile(String jobNo, String mobile, Map<String, String> originalMobiles, boolean fillOnly) {
|
||||||
|
if (StrUtil.isBlank(mobile) || !mobile.matches("1[3-9][0-9]{9}")) return 0;
|
||||||
|
int updated = 0;
|
||||||
|
for (Map.Entry<String, String> entry : originalMobiles.entrySet()) {
|
||||||
|
String oldMobile = entry.getValue();
|
||||||
|
if (Objects.equals(oldMobile, mobile) || (fillOnly && StrUtil.isNotBlank(oldMobile))) continue;
|
||||||
|
Cnd cnd = Cnd.where(Sys_user::getId, "=", entry.getKey())
|
||||||
|
.and(Sys_user::getLoginname, "=", jobNo);
|
||||||
|
if (oldMobile == null) cnd.and("mobile", "IS", null);
|
||||||
|
else cnd.and("mobile", "=", oldMobile);
|
||||||
|
updated += dao().update(Sys_user.class, Chain.make("mobile", mobile), cnd);
|
||||||
|
}
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从数据中心分页同步教职工手机号,并按工号更新 sys_user.mobile。
|
* 从数据中心分页同步教职工手机号,并按工号更新 sys_user.mobile。
|
||||||
*/
|
*/
|
||||||
|
|||||||
-29
@@ -5,11 +5,8 @@ import cn.dev33.satoken.annotation.SaMode;
|
|||||||
import cn.hutool.core.util.DesensitizedUtil;
|
import cn.hutool.core.util.DesensitizedUtil;
|
||||||
import com.alibaba.excel.EasyExcel;
|
import com.alibaba.excel.EasyExcel;
|
||||||
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.page.Pagination;
|
import com.budwk.app.base.page.Pagination;
|
||||||
import com.budwk.app.base.result.Result;
|
import com.budwk.app.base.result.Result;
|
||||||
import com.budwk.app.sys.services.SysDataUserPullService;
|
|
||||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
|
||||||
import com.budwk.app.zhgh.staffmanage.member.models.MemberHistory;
|
import com.budwk.app.zhgh.staffmanage.member.models.MemberHistory;
|
||||||
import com.budwk.app.zhgh.staffmanage.member.param.pageform.MemberInfoPageForm;
|
import com.budwk.app.zhgh.staffmanage.member.param.pageform.MemberInfoPageForm;
|
||||||
import com.budwk.app.zhgh.staffmanage.member.service.MemberInfoService;
|
import com.budwk.app.zhgh.staffmanage.member.service.MemberInfoService;
|
||||||
@@ -51,9 +48,6 @@ public class MemberInfoGroupController {
|
|||||||
@Inject
|
@Inject
|
||||||
private MemberInfoService memberInfoService;
|
private MemberInfoService memberInfoService;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private SysDataUserPullService sysUserPullService;
|
|
||||||
|
|
||||||
@At("")
|
@At("")
|
||||||
@Ok("beetl:/platform/zhgh/staffmanage/member/info/group/index.html")
|
@Ok("beetl:/platform/zhgh/staffmanage/member/info/group/index.html")
|
||||||
@SaCheckPermission("member.info.group")
|
@SaCheckPermission("member.info.group")
|
||||||
@@ -86,29 +80,6 @@ public class MemberInfoGroupController {
|
|||||||
return Result.success(memberInfoService.dao().count(MemberHistory.class, Cnd.where("year", "=", year)));
|
return Result.success(memberInfoService.dao().count(MemberHistory.class, Cnd.where("year", "=", year)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@At
|
|
||||||
@SaCheckPermission("member.info.group")
|
|
||||||
@Aop(TransAop.READ_COMMITTED)
|
|
||||||
@SLog(tag = "会员档案管理", msg = "获取会员手机号")
|
|
||||||
public Result syncMobile() {
|
|
||||||
try {
|
|
||||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
|
||||||
return Result.error("当前用户无权获取会员手机号");
|
|
||||||
}
|
|
||||||
List<String> jobNos = memberInfoService.queryRandomBlankMobileMemberJobNos(500);
|
|
||||||
if (jobNos.isEmpty()) {
|
|
||||||
return Result.error("当前没有手机号为空的会员");
|
|
||||||
}
|
|
||||||
NutMap result = sysUserPullService.syncTeacherMobileByJobNos(jobNos);
|
|
||||||
result.put("sampleCount", jobNos.size());
|
|
||||||
return Result.success(result);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("会员手机号获取失败", e);
|
|
||||||
return Result.error(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@At
|
@At
|
||||||
@SaCheckPermission("member.info.group")
|
@SaCheckPermission("member.info.group")
|
||||||
@Aop(TransAop.READ_COMMITTED)
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
|
|||||||
@@ -69,11 +69,13 @@ const initTableMixins = {
|
|||||||
const address = this.pageDataUrl ? this.pageDataUrl : loc() + "/pageData"
|
const address = this.pageDataUrl ? this.pageDataUrl : loc() + "/pageData"
|
||||||
this.tableLoading = true
|
this.tableLoading = true
|
||||||
this.$axios.post(address, data ? data : this.pageForm).then((res) => {
|
this.$axios.post(address, data ? data : this.pageForm).then((res) => {
|
||||||
this.tableLoading = false
|
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
this.tableData = res.data.list
|
this.tableData = res.data.list
|
||||||
this.pageForm.totalCount = res.data.totalCount
|
this.pageForm.totalCount = res.data.totalCount
|
||||||
}
|
}
|
||||||
|
}).finally(() => {
|
||||||
|
// 列表请求成功或失败后均关闭加载遮罩,避免异常时持续转圈。
|
||||||
|
this.tableLoading = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
notifySuccess(msg) {
|
notifySuccess(msg) {
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ layout("/layouts/platform.html"){
|
|||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<table-tool :label="pageForm.pullTime ? pageForm.pullTime + '数据' : '全部数据'">
|
<table-tool :label="pageForm.pullTime ? pageForm.pullTime + '数据' : '全部数据'">
|
||||||
<el-button type="primary" size="mini" :loading="pullLoading" @click="pull" icon="el-icon-download">拉取信息中心数据</el-button>
|
<el-button type="primary" size="mini" :loading="pullLoading" @click="pull" icon="el-icon-download">拉取信息中心数据</el-button>
|
||||||
<el-button type="primary" size="mini" :loading="syncTeacherMobileLoading" @click="syncTeacherMobile" icon="el-icon-mobile-phone">同步教职工手机号</el-button>
|
|
||||||
<el-button type="danger" size="mini" @click="openDelete" icon="el-icon-delete">删除本地数据源</el-button>
|
<el-button type="danger" size="mini" @click="openDelete" icon="el-icon-delete">删除本地数据源</el-button>
|
||||||
</table-tool>
|
</table-tool>
|
||||||
<el-table :key="tableKey" :data="tableData" @sort-change="pageOrder" header-align="center" v-loading="tableLoading">
|
<el-table :key="tableKey" :data="tableData" @sort-change="pageOrder" header-align="center" v-loading="tableLoading">
|
||||||
@@ -121,8 +120,7 @@ layout("/layouts/platform.html"){
|
|||||||
pullTimeOptions: false,
|
pullTimeOptions: false,
|
||||||
sourceTime: [],
|
sourceTime: [],
|
||||||
pullTimeDialogVisible: false,
|
pullTimeDialogVisible: false,
|
||||||
pullLoading: false,
|
pullLoading: false
|
||||||
syncTeacherMobileLoading: false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -150,42 +148,6 @@ layout("/layouts/platform.html"){
|
|||||||
.catch(() => {})
|
.catch(() => {})
|
||||||
},
|
},
|
||||||
|
|
||||||
syncTeacherMobile() {
|
|
||||||
this.$confirm("确定要同步教职工手机号吗?", "提示", {
|
|
||||||
type: "warning",
|
|
||||||
confirmButtonText: "确定",
|
|
||||||
cancelButtonText: "取消"
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
this.syncTeacherMobileLoading = true
|
|
||||||
this.$axios
|
|
||||||
.post("/platform/sys/data/user/pull/syncTeacherMobile")
|
|
||||||
.then((resp) => {
|
|
||||||
if (resp.code === 0) {
|
|
||||||
const data = resp.data || {}
|
|
||||||
this.$alert(
|
|
||||||
"接口总数:" + (data.total || 0) +
|
|
||||||
"<br>总页数:" + (data.pages || 0) +
|
|
||||||
"<br>拉取数量:" + (data.pulledCount || 0) +
|
|
||||||
"<br>有效手机号数量:" + (data.validMobileCount || 0) +
|
|
||||||
"<br>匹配用户数量:" + (data.matchedUserCount || 0) +
|
|
||||||
"<br>更新用户数量:" + (data.updatedUserCount || 0),
|
|
||||||
"同步完成",
|
|
||||||
{
|
|
||||||
dangerouslyUseHTMLString: true,
|
|
||||||
confirmButtonText: "确定"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
this.pageData()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.syncTeacherMobileLoading = false
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch(() => {})
|
|
||||||
},
|
|
||||||
|
|
||||||
getSearchOptions() {
|
getSearchOptions() {
|
||||||
this.$axios.post("/platform/sys/data/user/pull/searchOptions").then((resp) => {
|
this.$axios.post("/platform/sys/data/user/pull/searchOptions").then((resp) => {
|
||||||
if (resp.code === 0) {
|
if (resp.code === 0) {
|
||||||
|
|||||||
@@ -51,10 +51,11 @@ layout("/layouts/platform.html"){
|
|||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<table-tool label="系统当前用户数据">
|
<table-tool label="系统当前用户数据">
|
||||||
<el-button type="primary" size="mini" @click="updateDataDict" icon="el-icon-refresh">更新【码表】数据</el-button>
|
<el-button type="primary" size="mini" @click="updateDataDict" icon="el-icon-refresh">更新【码表】数据</el-button>
|
||||||
|
<el-button v-if="$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN'])" type="primary" size="mini" @click="openMobileSync" icon="el-icon-phone">拉取【手机号】</el-button>
|
||||||
<el-button type="primary" size="mini" @click="updateUnits" icon="el-icon-refresh">更新【单位】数据</el-button>
|
<el-button type="primary" size="mini" @click="updateUnits" icon="el-icon-refresh">更新【单位】数据</el-button>
|
||||||
<el-button type="primary" size="mini" @click="openUpdate" icon="el-icon-refresh">更新【人员】数据</el-button>
|
<el-button type="primary" size="mini" @click="openUpdate" icon="el-icon-refresh">更新【人员】数据</el-button>
|
||||||
</table-tool>
|
</table-tool>
|
||||||
<el-table :key="tableKey" :data="tableData" @sort-change="pageOrder" header-align="center">
|
<el-table v-loading="tableLoading" :key="tableKey" :data="tableData" @sort-change="pageOrder" header-align="center">
|
||||||
<el-table-column type="index" width="70" label="序号" fixed="left"></el-table-column>
|
<el-table-column type="index" width="70" label="序号" fixed="left"></el-table-column>
|
||||||
<el-table-column prop="loginname" label="工号" width="100" fixed="left"></el-table-column>
|
<el-table-column prop="loginname" label="工号" width="100" fixed="left"></el-table-column>
|
||||||
<el-table-column prop="username" label="姓名" fixed="left" width="120" show-overflow-tooltip></el-table-column>
|
<el-table-column prop="username" label="姓名" fixed="left" width="120" show-overflow-tooltip></el-table-column>
|
||||||
@@ -67,7 +68,8 @@ layout("/layouts/platform.html"){
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="changeTime" label="变更时间" sortable width="150"></el-table-column>
|
<el-table-column prop="changeTime" label="变更时间" sortable width="150"></el-table-column>
|
||||||
<el-table-column prop="sex" label="性别" sortable></el-table-column>
|
<el-table-column prop="sex" label="性别" sortable></el-table-column>
|
||||||
<!-- <el-table-column prop="mobile" label="手机号" width="120"></el-table-column>-->
|
<!-- 展示系统当前手机号,便于核对后台拉取结果。 -->
|
||||||
|
<el-table-column prop="mobile" label="手机号" width="130"></el-table-column>
|
||||||
<el-table-column prop="birthday" label="生日" sortable width="120">
|
<el-table-column prop="birthday" label="生日" sortable width="120">
|
||||||
<template slot-scope="{row}">{{$moment(row.birthday).format('YYYY-MM-DD')}}</template>
|
<template slot-scope="{row}">{{$moment(row.birthday).format('YYYY-MM-DD')}}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@@ -75,14 +77,8 @@ layout("/layouts/platform.html"){
|
|||||||
<el-table-column prop="preparedBy" label="编制类别" sortable width="120"></el-table-column>
|
<el-table-column prop="preparedBy" label="编制类别" sortable width="120"></el-table-column>
|
||||||
<el-table-column prop="personType" label="教职工类别" sortable width="120"></el-table-column>
|
<el-table-column prop="personType" label="教职工类别" sortable width="120"></el-table-column>
|
||||||
<el-table-column prop="arrivalAtSchoolDate" label="来校年月" sortable width="120"></el-table-column>
|
<el-table-column prop="arrivalAtSchoolDate" label="来校年月" sortable width="120"></el-table-column>
|
||||||
<el-table-column prop="technicalTitle" label="技术职称" sortable width="120"></el-table-column>
|
|
||||||
<el-table-column prop="position" label="职务" sortable width="120" show-overflow-tooltip></el-table-column>
|
|
||||||
<el-table-column prop="education" label="学历" show-overflow-tooltip sortable width="120"></el-table-column>
|
|
||||||
<el-table-column prop="academicDegree" label="学位" show-overflow-tooltip sortable width="120"></el-table-column>
|
|
||||||
<el-table-column prop="unitName" label="单位" show-overflow-tooltip sortable width="120"></el-table-column>
|
<el-table-column prop="unitName" label="单位" show-overflow-tooltip sortable width="120"></el-table-column>
|
||||||
<el-table-column prop="unitId" label="单位编码" sortable width="120"></el-table-column>
|
<el-table-column prop="unitId" label="单位编码" sortable width="120"></el-table-column>
|
||||||
<el-table-column prop="nationality" label="国籍" sortable></el-table-column>
|
|
||||||
<el-table-column prop="nation" label="民族" sortable></el-table-column>
|
|
||||||
</el-table>
|
</el-table>
|
||||||
<!--#include("/layouts/pagination.html"){}#-->
|
<!--#include("/layouts/pagination.html"){}#-->
|
||||||
</el-card>
|
</el-card>
|
||||||
@@ -129,6 +125,51 @@ layout("/layouts/platform.html"){
|
|||||||
<el-button type="primary" @click="execUpdate" :disabled="updateLoading">确 定</el-button>
|
<el-button type="primary" @click="execUpdate" :disabled="updateLoading">确 定</el-button>
|
||||||
</span>
|
</span>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
<el-dialog title="拉取手机号" :visible.sync="mobileDialog" width="680px" @closed="closeMobilePolling">
|
||||||
|
<el-alert title="后台逐人拉取,会员优先。关闭弹框不停止任务;无号码结果七天内跳过。" type="info" :closable="false"></el-alert>
|
||||||
|
<el-form label-width="110px" style="margin-top: 16px" :disabled="mobileRunning || formLoading">
|
||||||
|
<el-form-item label="人员范围">
|
||||||
|
<el-select v-model="mobileScope" @change="invalidateMobilePreview">
|
||||||
|
<el-option label="全部系统人员" value="ALL"></el-option>
|
||||||
|
<el-option label="仅会员" value="MEMBER"></el-option>
|
||||||
|
<el-option label="当前筛选的全部结果" value="FILTER"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="拉取模式">
|
||||||
|
<el-radio-group v-model="mobileMode" @change="invalidateMobilePreview">
|
||||||
|
<el-radio label="FILL">只补手机号为空的人员</el-radio>
|
||||||
|
<el-radio label="REFRESH">重新核对(含已有号码)</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button :loading="mobilePreviewLoading" @click="previewMobileSync">预览本次人数</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<p v-if="mobilePreview">
|
||||||
|
范围 {{mobilePreview.scopeCount}} 人,已有号码 {{mobilePreview.existingCount}} 人,
|
||||||
|
冷却跳过 {{mobilePreview.cooldownCount}} 人,本次待请求 {{mobilePreview.total}} 人(按工号去重)。
|
||||||
|
</p>
|
||||||
|
<p v-if="mobilePreview && mobilePreview.total">按每秒最多 1 次请求执行,实际耗时还取决于接口响应速度。</p>
|
||||||
|
<div v-if="mobileTask.taskId" v-loading="mobileStatusLoading && !mobileTask.status">
|
||||||
|
<el-divider>最近任务</el-divider>
|
||||||
|
<p>{{mobileStatusLabel}} · {{mobileTask.message}}</p>
|
||||||
|
<p>任务范围:{{mobileTask.scope === 'MEMBER' ? '仅会员' : (mobileTask.scope === 'FILTER' ? '筛选结果' : '全部系统人员')}};
|
||||||
|
模式:{{mobileTask.mode === 'REFRESH' ? '重新核对' : '只补空号'}}</p>
|
||||||
|
<el-progress :percentage="mobileProgress"></el-progress>
|
||||||
|
<p>已处理 {{mobileTask.processed || 0}} / {{mobileTask.total || 0}};
|
||||||
|
已更新 {{mobileTask.updated || 0}};无号码 {{mobileTask.empty || 0}};
|
||||||
|
失败 {{mobileTask.failed || 0}};跳过或未变更 {{mobileTask.skipped || 0}}。</p>
|
||||||
|
<p v-if="!mobileRunning">任务与续传记录保留七天。继续任务会先处理剩余人员,再重试原失败项。</p>
|
||||||
|
</div>
|
||||||
|
<span slot="footer">
|
||||||
|
<el-button @click="closeMobileSync">关闭</el-button>
|
||||||
|
<el-button v-if="mobileRunning" type="warning" :loading="formLoading" @click="stopMobileSync">停止任务</el-button>
|
||||||
|
<el-button v-if="!mobileRunning && mobileTask.taskId && mobileTask.processed < mobileTask.total" :loading="formLoading" @click="startMobileSync('RESUME')">继续任务</el-button>
|
||||||
|
<el-button v-if="!mobileRunning && mobileTask.failed > 0" :loading="formLoading" @click="startMobileSync('RETRY')">仅重试失败项</el-button>
|
||||||
|
<el-button type="primary" :loading="formLoading" :disabled="mobileRunning || mobileStatusLoading || mobilePreviewLoading || !mobilePreview || !mobilePreview.total" @click="startMobileSync('NEW')">开始拉取</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -139,6 +180,17 @@ layout("/layouts/platform.html"){
|
|||||||
mixins: [initTableMixins],
|
mixins: [initTableMixins],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
mobileDialog: false,
|
||||||
|
mobileScope: "ALL",
|
||||||
|
mobileMode: "FILL",
|
||||||
|
mobileFilters: {},
|
||||||
|
mobilePreview: null,
|
||||||
|
mobilePreviewVersion: 0,
|
||||||
|
mobilePreviewLoading: false,
|
||||||
|
mobileStatusLoading: false,
|
||||||
|
mobileTask: {},
|
||||||
|
mobilePollTimer: null,
|
||||||
|
mobileDisposed: false,
|
||||||
updateDialog: false,
|
updateDialog: false,
|
||||||
pullTimeOptions: false,
|
pullTimeOptions: false,
|
||||||
updateFromData: {
|
updateFromData: {
|
||||||
@@ -176,7 +228,114 @@ layout("/layouts/platform.html"){
|
|||||||
components: {
|
components: {
|
||||||
"member-all-change-info": MEMBER_ALL_CHANGE_INFO
|
"member-all-change-info": MEMBER_ALL_CHANGE_INFO
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
mobileRunning() { return this.mobileTask.status === "RUNNING" },
|
||||||
|
mobileProgress() {
|
||||||
|
return this.mobileTask.total ? Math.min(100, Math.floor((this.mobileTask.processed || 0) * 100 / this.mobileTask.total)) : 0
|
||||||
|
},
|
||||||
|
mobileStatusLabel() {
|
||||||
|
const labels = { RUNNING: "执行中", STOPPED: "已停止", PAUSED: "已暂停", INTERRUPTED: "已中断", COMPLETED: "已完成" }
|
||||||
|
return labels[this.mobileTask.status] || "读取中"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
this.mobileDisposed = true
|
||||||
|
this.closeMobilePolling()
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
// 打开时固定本次列表筛选条件;只读取进度,外部手机号请求必须由开始按钮触发。
|
||||||
|
openMobileSync() {
|
||||||
|
this.mobileFilters = Object.assign({}, this.pageForm)
|
||||||
|
this.mobileDialog = true
|
||||||
|
this.invalidateMobilePreview()
|
||||||
|
this.loadMobileStatus()
|
||||||
|
},
|
||||||
|
invalidateMobilePreview() {
|
||||||
|
this.mobilePreviewVersion++
|
||||||
|
this.mobilePreview = null
|
||||||
|
},
|
||||||
|
// scope为ALL/MEMBER/FILTER,mode为FILL/REFRESH;筛选参数只参与FILTER,不传分页含义。
|
||||||
|
mobileParams() {
|
||||||
|
return Object.assign({}, this.mobileFilters, { scope: this.mobileScope, mode: this.mobileMode })
|
||||||
|
},
|
||||||
|
previewMobileSync() {
|
||||||
|
if (this.mobilePreviewLoading) return
|
||||||
|
const version = ++this.mobilePreviewVersion
|
||||||
|
this.mobilePreview = null
|
||||||
|
this.mobilePreviewLoading = true
|
||||||
|
this.$axios.post("/platform/sys/data/user/update/mobilePreview", this.mobileParams())
|
||||||
|
.then((res) => {
|
||||||
|
// 选项改变后不显示旧请求的预览,避免按旧人数开始新范围任务。
|
||||||
|
if (res.code === 0 && version === this.mobilePreviewVersion) this.mobilePreview = res.data
|
||||||
|
})
|
||||||
|
.catch(() => { this.$message.error("预览失败,请稍后重试") })
|
||||||
|
.finally(() => { this.mobilePreviewLoading = false })
|
||||||
|
},
|
||||||
|
// NEW使用预览范围;RESUME/RETRY由后端按sourceTaskId恢复原任务范围及模式,不能被当前选项替换。
|
||||||
|
startMobileSync(action) {
|
||||||
|
if (this.formLoading || this.mobileRunning) return
|
||||||
|
const params = Object.assign(this.mobileParams(), { action: action, sourceTaskId: this.mobileTask.taskId || "" })
|
||||||
|
const refresh = action === "NEW" ? this.mobileMode === "REFRESH" : this.mobileTask.mode === "REFRESH"
|
||||||
|
const message = refresh ? "本次会核对并更新已有手机号,确定开始吗?" : "确定在后台拉取手机号吗?"
|
||||||
|
this.$confirm(message, "提示", { type: "warning" }).then(() => {
|
||||||
|
this.formLoading = true
|
||||||
|
return this.$axios.post("/platform/sys/data/user/update/mobileStart", params)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.mobileTask = res.data || {}
|
||||||
|
this.invalidateMobilePreview()
|
||||||
|
this.$message.success("任务已提交,可关闭弹框稍后查看")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => { this.$message.error("启动未成功,请查看最新任务状态") })
|
||||||
|
.finally(() => {
|
||||||
|
this.formLoading = false
|
||||||
|
this.loadMobileStatus()
|
||||||
|
})
|
||||||
|
}).catch(() => {})
|
||||||
|
},
|
||||||
|
loadMobileStatus() {
|
||||||
|
if (this.mobileStatusLoading || this.mobileDisposed || !this.mobileDialog) return
|
||||||
|
this.closeMobilePolling()
|
||||||
|
this.mobileStatusLoading = true
|
||||||
|
this.$axios.post("/platform/sys/data/user/update/mobileStatus", {})
|
||||||
|
.then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
const wasRunning = this.mobileRunning
|
||||||
|
this.mobileTask = res.data || {}
|
||||||
|
if (wasRunning && !this.mobileRunning) this.pageData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => { this.$message.error("读取任务进度失败,将稍后重试") })
|
||||||
|
.finally(() => {
|
||||||
|
this.mobileStatusLoading = false
|
||||||
|
// 使用单次计时器串行轮询;弹框关闭或页面销毁后不再注册,避免重复绑定与泄漏。
|
||||||
|
if (this.mobileDialog && !this.mobileDisposed) {
|
||||||
|
this.mobilePollTimer = setTimeout(() => { this.loadMobileStatus() }, 3000)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
stopMobileSync() {
|
||||||
|
if (this.formLoading) return
|
||||||
|
this.formLoading = true
|
||||||
|
this.$axios.post("/platform/sys/data/user/update/mobileStop", { taskId: this.mobileTask.taskId })
|
||||||
|
.then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.mobileTask = res.data || {}
|
||||||
|
this.$message.success("停止请求已提交,等待当前工号处理结束")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => { this.$message.error("停止请求失败,请稍后重试") })
|
||||||
|
.finally(() => { this.formLoading = false })
|
||||||
|
},
|
||||||
|
closeMobilePolling() {
|
||||||
|
if (this.mobilePollTimer) clearTimeout(this.mobilePollTimer)
|
||||||
|
this.mobilePollTimer = null
|
||||||
|
},
|
||||||
|
closeMobileSync() {
|
||||||
|
this.$set(this, "mobileDialog", false)
|
||||||
|
this.closeMobilePolling()
|
||||||
|
},
|
||||||
// 更新单位数据
|
// 更新单位数据
|
||||||
updateUnits() {
|
updateUnits() {
|
||||||
this.$confirm("确定要更新单位数据吗?", "提示", {
|
this.$confirm("确定要更新单位数据吗?", "提示", {
|
||||||
|
|||||||
@@ -20,14 +20,6 @@ layout("/layouts/platform.html"){
|
|||||||
>
|
>
|
||||||
备份历史会员
|
备份历史会员
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
|
||||||
v-if="$auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN'])"
|
|
||||||
type="primary"
|
|
||||||
size="small"
|
|
||||||
icon="el-icon-mobile-phone"
|
|
||||||
:loading="syncMobileLoading"
|
|
||||||
@click="syncMobile"
|
|
||||||
>获取手机号</el-button>
|
|
||||||
<el-button type="primary" size="small" icon="el-icon-download" @click="exportMember">会员档案导出</el-button>
|
<el-button type="primary" size="small" icon="el-icon-download" @click="exportMember">会员档案导出</el-button>
|
||||||
<el-popover
|
<el-popover
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
@@ -157,8 +149,7 @@ layout("/layouts/platform.html"){
|
|||||||
],
|
],
|
||||||
checkedFields: [],
|
checkedFields: [],
|
||||||
|
|
||||||
importDialog: false,
|
importDialog: false
|
||||||
syncMobileLoading: false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
@@ -189,39 +180,6 @@ layout("/layouts/platform.html"){
|
|||||||
openArchive() {
|
openArchive() {
|
||||||
this.$refs.archiveMemberRef.archiveDialogVisible = true
|
this.$refs.archiveMemberRef.archiveDialogVisible = true
|
||||||
},
|
},
|
||||||
syncMobile() {
|
|
||||||
this.$confirm("将从手机号为空的会员中随机取500人获取手机号,确定继续吗?", "提示", {
|
|
||||||
confirmButtonText: "确定",
|
|
||||||
cancelButtonText: "取消",
|
|
||||||
type: "warning"
|
|
||||||
}).then(() => {
|
|
||||||
this.syncMobileLoading = true
|
|
||||||
this.$axios.post(loc() + "/syncMobile").then((res) => {
|
|
||||||
if (res.code === 0) {
|
|
||||||
const data = res.data || {}
|
|
||||||
const failedJobNos = data.failedJobNos || []
|
|
||||||
this.$alert(
|
|
||||||
"抽取人数:" + (data.sampleCount || 0) +
|
|
||||||
"<br>请求人数:" + (data.requestUserCount || 0) +
|
|
||||||
"<br>接口返回数量:" + (data.pulledCount || 0) +
|
|
||||||
"<br>有效手机号数量:" + (data.validMobileCount || 0) +
|
|
||||||
"<br>系统用户更新数量:" + (data.updatedUserCount || 0) +
|
|
||||||
"<br>失败工号数量:" + failedJobNos.length,
|
|
||||||
"手机号获取完成",
|
|
||||||
{
|
|
||||||
dangerouslyUseHTMLString: true,
|
|
||||||
confirmButtonText: "确定"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
this.pageData()
|
|
||||||
} else {
|
|
||||||
this.$message.warning(res.msg || "手机号获取失败")
|
|
||||||
}
|
|
||||||
}).finally(() => {
|
|
||||||
this.syncMobileLoading = false
|
|
||||||
})
|
|
||||||
}).catch(() => {})
|
|
||||||
},
|
|
||||||
openView(userId) {
|
openView(userId) {
|
||||||
this.$refs.guava.view(() => {
|
this.$refs.guava.view(() => {
|
||||||
this.$refs.infoRef.onOpen(userId)
|
this.$refs.infoRef.onOpen(userId)
|
||||||
|
|||||||
@@ -2,10 +2,50 @@
|
|||||||
layout("/layouts/platform.html"){
|
layout("/layouts/platform.html"){
|
||||||
#-->
|
#-->
|
||||||
|
|
||||||
<div id="app" v-cloak>
|
<style>
|
||||||
|
/* 扣除平台顶部导航 64px 和内容区上下间距 20px,让列表使用剩余可视高度。 */
|
||||||
|
.thirty-teach-summary-page {
|
||||||
|
height: calc(100vh - 84px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.thirty-teach-summary-page > .guava-main-content {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thirty-teach-summary-page > .guava-main-content > .transition-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thirty-teach-summary-page .summary-search-card,
|
||||||
|
.thirty-teach-summary-page .summary-list-card > .el-card__body > .ele-table-tool {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 列表卡片允许收缩,避免数据行撑高外层页面;表头和合计由 el-table 固定。 */
|
||||||
|
.thirty-teach-summary-page .summary-list-card {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thirty-teach-summary-page .summary-list-card > .el-card__body {
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thirty-teach-summary-page .summary-table-container {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div id="app" class="thirty-teach-summary-page" v-cloak>
|
||||||
<guava ref="guava">
|
<guava ref="guava">
|
||||||
<template>
|
<template>
|
||||||
<el-card shadow="never">
|
<el-card shadow="never" class="summary-search-card">
|
||||||
<search @search="doSearch">
|
<search @search="doSearch">
|
||||||
<search-item label="所属工会">
|
<search-item label="所属工会">
|
||||||
<el-select v-model="pageForm.unionId" placeholder="请选择所属工会"
|
<el-select v-model="pageForm.unionId" placeholder="请选择所属工会"
|
||||||
@@ -29,14 +69,15 @@ layout("/layouts/platform.html"){
|
|||||||
|
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-card shadow="never" class="mt10">
|
<el-card shadow="never" class="mt10 summary-list-card">
|
||||||
<table-tool label="教职工汇总">
|
<table-tool label="教职工汇总">
|
||||||
<el-button size="small" @click="doExportSummary" type="primary">
|
<el-button size="small" @click="doExportSummary" type="primary">
|
||||||
导出汇总表
|
导出汇总表
|
||||||
</el-button>
|
</el-button>
|
||||||
</table-tool>
|
</table-tool>
|
||||||
|
<div class="summary-table-container">
|
||||||
<el-table ref="table" :data="tableData" style="width: 100%" row-key="id"
|
<el-table ref="table" :data="tableData" style="width: 100%" row-key="id"
|
||||||
@sort-change="pageOrder" show-summary
|
@sort-change="pageOrder" show-summary height="100%"
|
||||||
v-loading="tableLoading" :size="tableSize" class="vi-table">
|
v-loading="tableLoading" :size="tableSize" class="vi-table">
|
||||||
<el-table-column align="center" header-align="center" type="index"
|
<el-table-column align="center" header-align="center" type="index"
|
||||||
:index="indexMethod" label="序号"
|
:index="indexMethod" label="序号"
|
||||||
@@ -52,6 +93,7 @@ layout("/layouts/platform.html"){
|
|||||||
>
|
>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
</el-card>
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
@@ -71,10 +113,10 @@ layout("/layouts/platform.html"){
|
|||||||
},
|
},
|
||||||
tableColumns: [
|
tableColumns: [
|
||||||
{prop: 'name', label: '分工会名称', sortable: true},
|
{prop: 'name', label: '分工会名称', sortable: true},
|
||||||
|
{prop: 'userNum', label: '人数', sortable: true},
|
||||||
{prop: 'willThirtyNum', label: '即将满30年', sortable: true},
|
{prop: 'willThirtyNum', label: '即将满30年', sortable: true},
|
||||||
{prop: 'anniversaryThirtyNum', label: '周年满30年', sortable: true},
|
{prop: 'anniversaryThirtyNum', label: '周年满30年', sortable: true},
|
||||||
{prop: 'overThirtyNum', label: '超过30年', sortable: true},
|
{prop: 'overThirtyNum', label: '超过30年', sortable: true},
|
||||||
{prop: 'userNum', label: '人数', sortable: true},
|
|
||||||
],
|
],
|
||||||
unionOptions: [],
|
unionOptions: [],
|
||||||
unitOptions: [],
|
unitOptions: [],
|
||||||
|
|||||||
@@ -2,10 +2,50 @@
|
|||||||
layout("/layouts/platform.html"){
|
layout("/layouts/platform.html"){
|
||||||
#-->
|
#-->
|
||||||
|
|
||||||
<div id="app" v-cloak>
|
<style>
|
||||||
|
/* 扣除平台顶部导航 64px 和内容区上下间距 20px,让列表使用剩余可视高度。 */
|
||||||
|
.welfare-statistics-page {
|
||||||
|
height: calc(100vh - 84px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.welfare-statistics-page > .guava-main-content {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welfare-statistics-page > .guava-main-content > .transition-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welfare-statistics-page .statistics-search-card,
|
||||||
|
.welfare-statistics-page .statistics-list-card > .el-card__body > .ele-table-tool {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 列表卡片允许收缩,避免数据行撑高外层页面;表头和合计由 el-table 固定。 */
|
||||||
|
.welfare-statistics-page .statistics-list-card {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welfare-statistics-page .statistics-list-card > .el-card__body {
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welfare-statistics-page .statistics-table-container {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div id="app" class="welfare-statistics-page" v-cloak>
|
||||||
<guava ref="guava">
|
<guava ref="guava">
|
||||||
<template>
|
<template>
|
||||||
<el-card shadow="never">
|
<el-card class="statistics-search-card" shadow="never">
|
||||||
<search @search="doSearch">
|
<search @search="doSearch">
|
||||||
<search-item label="年度">
|
<search-item label="年度">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
@@ -31,7 +71,7 @@ layout("/layouts/platform.html"){
|
|||||||
</search>
|
</search>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-card class="mt10" shadow="never" v-loading="tableLoading">
|
<el-card class="mt10 statistics-list-card" shadow="never" v-loading="tableLoading">
|
||||||
<table-tool label="工会列表">
|
<table-tool label="工会列表">
|
||||||
<el-button @click="exportByWelfareOptions" icon="el-icon-printer" size="small" type="primary">按福利选项导出</el-button>
|
<el-button @click="exportByWelfareOptions" icon="el-icon-printer" size="small" type="primary">按福利选项导出</el-button>
|
||||||
<template v-if="$auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN','SCHOOL_UNION_WELFARE_ADMIN'])">
|
<template v-if="$auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN','SCHOOL_UNION_WELFARE_ADMIN'])">
|
||||||
@@ -40,11 +80,13 @@ layout("/layouts/platform.html"){
|
|||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</table-tool>
|
</table-tool>
|
||||||
|
<div class="statistics-table-container">
|
||||||
<el-table
|
<el-table
|
||||||
:data="tableData"
|
:data="tableData"
|
||||||
:size="tableSize"
|
:size="tableSize"
|
||||||
@sort-change="pageOrder"
|
@sort-change="pageOrder"
|
||||||
class="vi-table"
|
class="vi-table"
|
||||||
|
height="100%"
|
||||||
lazy
|
lazy
|
||||||
ref="table"
|
ref="table"
|
||||||
row-key="id"
|
row-key="id"
|
||||||
@@ -72,6 +114,7 @@ layout("/layouts/platform.html"){
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
</guava>
|
</guava>
|
||||||
|
|||||||
Reference in New Issue
Block a user