地大bug整改,提案数据看板列表增加字段,是否重点提案;会员数据看板增加年同比,修复会员人员占比数字没有显示;
This commit is contained in:
+17
-177
@@ -1,66 +1,23 @@
|
|||||||
package com.budwk.app.zhgh.democratic.proposal.controller.dashboard;
|
package com.budwk.app.zhgh.democratic.proposal.controller.dashboard;
|
||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
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.result.Result;
|
import com.budwk.app.base.result.Result;
|
||||||
import com.budwk.app.flow.engine.model.ProcessModel;
|
|
||||||
import com.budwk.app.flow.engine.model.TaskModel;
|
|
||||||
import com.budwk.app.flow.entity.ProcessDefine;
|
|
||||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
|
||||||
import com.budwk.app.flow.service.ProcessDefineService;
|
|
||||||
import com.budwk.app.sys.models.Sys_dict;
|
|
||||||
import com.budwk.app.sys.services.SysDictService;
|
|
||||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalInfo;
|
|
||||||
import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService;
|
import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import org.nutz.dao.Cnd;
|
|
||||||
import org.nutz.dao.Dao;
|
|
||||||
import org.nutz.dao.Sqls;
|
|
||||||
import org.nutz.dao.sql.Sql;
|
|
||||||
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.lang.util.NutMap;
|
|
||||||
import org.nutz.mvc.annotation.At;
|
import org.nutz.mvc.annotation.At;
|
||||||
import org.nutz.mvc.annotation.Ok;
|
import org.nutz.mvc.annotation.Ok;
|
||||||
import org.nutz.mvc.annotation.Param;
|
import org.nutz.mvc.annotation.Param;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@IocBean
|
@IocBean
|
||||||
@At("/platform/proposal/dashboard")
|
@At("/platform/proposal/dashboard")
|
||||||
@Api("提案数据看板")
|
@Api("提案数据看板")
|
||||||
@Ok("json:full")
|
@Ok("json:full")
|
||||||
public class ProposalDashboardController {
|
public class ProposalDashboardController {
|
||||||
|
|
||||||
/**
|
|
||||||
* 工作台表格允许排序的字段映射,值为查询中的真实字段或安全别名。
|
|
||||||
*/
|
|
||||||
private static final Map<String, String> DASHBOARD_ORDER_COLUMNS = Map.ofEntries(
|
|
||||||
Map.entry("code", "info.code"),
|
|
||||||
Map.entry("name", "info.name"),
|
|
||||||
Map.entry("createUserName", "info.createUserName"),
|
|
||||||
Map.entry("typeName", "typeName"),
|
|
||||||
Map.entry("delegationName", "delegationName"),
|
|
||||||
Map.entry("caseFilingResult", "info.caseFilingResult"),
|
|
||||||
Map.entry("isConsolidation", "info.isConsolidation"),
|
|
||||||
Map.entry("masterUnitName", "masterUnitName"),
|
|
||||||
Map.entry("slaveUnitNames", "slaveUnitNames"),
|
|
||||||
Map.entry("curTaskName", "curTaskName"),
|
|
||||||
Map.entry("instanceState", "instanceState")
|
|
||||||
);
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private ProposalCommonService proposalCommonService;
|
private ProposalCommonService proposalCommonService;
|
||||||
@Inject
|
|
||||||
private ProcessDefineService processDefineService;
|
|
||||||
@Inject
|
|
||||||
private SysDictService sysDictService;
|
|
||||||
@Inject
|
|
||||||
private Dao dao;
|
|
||||||
|
|
||||||
@At("")
|
@At("")
|
||||||
@Ok("beetl:/platform/zhgh/democratic/proposal/dashboard/index.html")
|
@Ok("beetl:/platform/zhgh/democratic/proposal/dashboard/index.html")
|
||||||
@@ -68,147 +25,30 @@ public class ProposalDashboardController {
|
|||||||
public void index() {
|
public void index() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接收届次ID查询卡片;Result.data 为卡片列表,含 count 或 todoCount/doneCount。
|
||||||
|
* @param sessionId 教代会届次ID;为空时卡片数量为零
|
||||||
|
* @return 统一结果对象,data 为各节点和立案结果统计
|
||||||
|
*/
|
||||||
@At
|
@At
|
||||||
@SaCheckPermission("proposal.dashboard")
|
@SaCheckPermission("proposal.dashboard")
|
||||||
public Result listNode(@Param("sessionId") String sessionId) {
|
public Result listNode(@Param("sessionId") String sessionId) {
|
||||||
List<NutMap> nodes = new ArrayList<>();
|
return Result.success(proposalCommonService.listDashboardNodes(sessionId));
|
||||||
|
|
||||||
// 提案总数
|
|
||||||
nodes.add(NutMap.NEW().addv("name", "提案总数").addv("id", "total").addv("type", "total").addv("count", 0));
|
|
||||||
|
|
||||||
// 节点
|
|
||||||
ProcessDefine define = processDefineService.getLastByName("JDHTA_NC");
|
|
||||||
ProcessModel processModel = processDefineService.processDefineToModel(define);
|
|
||||||
// 按流程图的连线关系遍历任务节点,保证看板展示顺序与流程图一致。
|
|
||||||
List<TaskModel> taskModels = processModel.getModels(TaskModel.class);
|
|
||||||
|
|
||||||
List<String> excludeNodes = new ArrayList<>(3);
|
|
||||||
excludeNodes.add("撰写提案");
|
|
||||||
excludeNodes.add("邀请附议人");
|
|
||||||
excludeNodes.add("提案附议");
|
|
||||||
|
|
||||||
// opinion_unit_reply、two_unit_reply 为临时屏蔽的承办单位答复节点,不在看板展示。
|
|
||||||
List<String> hiddenNodeIds = List.of("opinion_unit_reply", "two_unit_reply");
|
|
||||||
List<NutMap> taskNodes = new ArrayList<>(taskModels.stream()
|
|
||||||
.filter(taskModel -> !excludeNodes.contains(taskModel.getDisplayName()))
|
|
||||||
.filter(taskModel -> !hiddenNodeIds.contains(taskModel.getName()))
|
|
||||||
.map(taskModel -> NutMap.NEW()
|
|
||||||
.addv("name", taskModel.getDisplayName())
|
|
||||||
.addv("id", taskModel.getName())
|
|
||||||
.addv("type", "task")
|
|
||||||
.addv("count", 0)
|
|
||||||
.addv("todoCount", 0)
|
|
||||||
.addv("doneCount", 0)
|
|
||||||
).toList());
|
|
||||||
|
|
||||||
// 立案结果
|
|
||||||
List<Sys_dict> caseFilingResult = sysDictService.getSubListByCode("PROPOSAL_CASE_FILING_RESULT");
|
|
||||||
List<NutMap> caseFilingResultNodes = new ArrayList<>();
|
|
||||||
for (Sys_dict dict : caseFilingResult) {
|
|
||||||
caseFilingResultNodes.add(NutMap.NEW()
|
|
||||||
.addv("name", dict.getName())
|
|
||||||
.addv("id", dict.getCode())
|
|
||||||
.addv("type", "caseFilingResult")
|
|
||||||
.addv("count", 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 立案结果需展示在委员会确认承办单位之前,反馈评价统一固定到看板末尾。
|
/**
|
||||||
List<NutMap> feedbackNodes = taskNodes.stream()
|
* 接收看板筛选参数,返回与卡片统计范围一致的提案分页数据。
|
||||||
.filter(taskNode -> "feedback".equals(taskNode.getString("id")))
|
* @param pageForm pageNumber/pageSize 为页码和每页条数,pageOrderName/pageOrderBy 为排序参数
|
||||||
.toList();
|
* @param sessionId 教代会届次ID;为空时返回空列表
|
||||||
taskNodes.removeIf(taskNode -> "feedback".equals(taskNode.getString("id")));
|
* @param selectNodeId task 节点编码或立案结果字典编码
|
||||||
int committeeFilingUnitIndex = taskNodes.size();
|
* @param selectNodeType task、total 或 caseFilingResult;为空时按总数查询
|
||||||
for (int i = 0; i < taskNodes.size(); i++) {
|
* @param selectNodeMode done 表示已办,其余值表示待办
|
||||||
if ("committeeFilingUnit".equals(taskNodes.get(i).getString("id"))) {
|
* @return Result.data.list 为提案列表,Result.data.totalCount 为筛选后的总数
|
||||||
committeeFilingUnitIndex = i;
|
*/
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
taskNodes.addAll(committeeFilingUnitIndex, caseFilingResultNodes);
|
|
||||||
nodes.addAll(taskNodes);
|
|
||||||
nodes.addAll(feedbackNodes);
|
|
||||||
|
|
||||||
Map<String, NutMap> taskProposalCounts = proposalCommonService.countDashboardTaskProposals(sessionId);
|
|
||||||
|
|
||||||
for (NutMap node : nodes) {
|
|
||||||
if (node.getString("type").equals("task")) {
|
|
||||||
NutMap taskCount = taskProposalCounts.get(node.getString("id"));
|
|
||||||
node.put("todoCount", taskCount == null ? 0 : taskCount.getLong("todoCount", 0L));
|
|
||||||
node.put("doneCount", taskCount == null ? 0 : taskCount.getLong("doneCount", 0L));
|
|
||||||
} else if (node.getString("type").equals("total")) {
|
|
||||||
int count = dao.count(ProposalInfo.class, Cnd.where(ProposalInfo::getSessionId, "=", sessionId));
|
|
||||||
node.put("count", count);
|
|
||||||
} else if (node.getString("type").equals("caseFilingResult")) {
|
|
||||||
int count = dao.count(ProposalInfo.class, Cnd.where(ProposalInfo::getSessionId, "=", sessionId).and(ProposalInfo::getCaseFilingResult, "=", node.getString("id")));
|
|
||||||
node.put("count", count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.success(nodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@At
|
@At
|
||||||
@SaCheckPermission("proposal.dashboard")
|
@SaCheckPermission("proposal.dashboard")
|
||||||
public Result pageData(PageForm pageForm, String sessionId, String selectNodeId, String selectNodeType, String selectNodeMode) {
|
public Result pageData(PageForm pageForm, String sessionId, String selectNodeId, String selectNodeType, String selectNodeMode) {
|
||||||
Sql sql = Sqls.create("""
|
return Result.success(proposalCommonService.pageDashboardData(pageForm, sessionId,
|
||||||
SELECT
|
selectNodeId, selectNodeType, selectNodeMode));
|
||||||
info.*,
|
|
||||||
type.name AS typeName,
|
|
||||||
tcs.fullName AS sessionName,
|
|
||||||
tcd.`name` AS delegationName,
|
|
||||||
ins.id AS instanceId,
|
|
||||||
ins.businessNo,
|
|
||||||
ins.state instanceState,
|
|
||||||
ins.variable instanceVariable,
|
|
||||||
ins.processDefineId instanceProcessDefineId,
|
|
||||||
t.displayName curTaskName,
|
|
||||||
GROUP_CONCAT(DISTINCT CASE WHEN pru.isMaster = 1 THEN pru.unitName END) AS masterUnitName,
|
|
||||||
GROUP_CONCAT(DISTINCT CASE WHEN pru.isMaster = 0 THEN pru.unitName END) AS slaveUnitNames
|
|
||||||
FROM
|
|
||||||
proposal_info info
|
|
||||||
LEFT JOIN proposal_type type on type.id = info.typeId
|
|
||||||
LEFT JOIN teacher_congress_session tcs on tcs.id = info.sessionId
|
|
||||||
LEFT JOIN teacher_congress_delegation tcd on tcd.id = info.delegationId
|
|
||||||
LEFT JOIN teacher_congress_delegate tcde on tcde.loginName = info.createUserLoginName
|
|
||||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
|
|
||||||
LEFT JOIN proposal_reply_unit pru ON pru.proposalId = info.id
|
|
||||||
LEFT JOIN wf_process_task t ON t.processInstanceId = ins.id AND t.taskState = @taskState
|
|
||||||
$condition
|
|
||||||
""");
|
|
||||||
Cnd cnd = Cnd.NEW();
|
|
||||||
cnd.and("info.sessionId", "=", sessionId);
|
|
||||||
cnd.groupBy("info.id");
|
|
||||||
|
|
||||||
// 默认显示进行中的任务
|
|
||||||
sql.setParam("taskState", ProcessTaskStateEnum.DOING.getCode());
|
|
||||||
|
|
||||||
if (StrUtil.isNotBlank(selectNodeType) && StrUtil.isNotBlank(selectNodeId)) {
|
|
||||||
switch (selectNodeType) {
|
|
||||||
case "task":
|
|
||||||
cnd.and("t.taskName", "=", selectNodeId);
|
|
||||||
|
|
||||||
if (selectNodeMode.equals("todo")) {
|
|
||||||
sql.setParam("taskState", ProcessTaskStateEnum.DOING.getCode());
|
|
||||||
} else {
|
|
||||||
sql.setParam("taskState", ProcessTaskStateEnum.FINISHED.getCode());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
case "total":
|
|
||||||
break;
|
|
||||||
case "caseFilingResult":
|
|
||||||
cnd.and("info.caseFilingResult", "=", selectNodeId);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据工作台字段白名单追加排序,未选择排序时保持原有查询顺序。
|
|
||||||
proposalCommonService.applySafePageOrder(cnd, pageForm, DASHBOARD_ORDER_COLUMNS);
|
|
||||||
sql.setCondition(cnd);
|
|
||||||
Pagination pagination = proposalCommonService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
|
||||||
return Result.success(pagination);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+18
@@ -288,4 +288,22 @@ public interface ProposalCommonService extends BaseService<ProposalInfo> {
|
|||||||
* @return 键为流程节点编码、值为待办和已办数量的统计结果
|
* @return 键为流程节点编码、值为待办和已办数量的统计结果
|
||||||
*/
|
*/
|
||||||
Map<String, NutMap> countDashboardTaskProposals(String sessionId);
|
Map<String, NutMap> countDashboardTaskProposals(String sessionId);
|
||||||
|
/**
|
||||||
|
* 查询看板卡片,统计范围与列表一致。
|
||||||
|
* @param sessionId 届次ID;为空时数量为零
|
||||||
|
* @return 包含节点编码、类型、名称和统计数量的卡片列表
|
||||||
|
*/
|
||||||
|
List<NutMap> listDashboardNodes(String sessionId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询看板提案分页数据。
|
||||||
|
* @param pageForm 分页及排序参数
|
||||||
|
* @param sessionId 届次ID;为空时返回空列表
|
||||||
|
* @param selectNodeId 流程节点编码或立案结果编码
|
||||||
|
* @param selectNodeType task、total 或 caseFilingResult
|
||||||
|
* @param selectNodeMode done 表示已办,其余值表示待办
|
||||||
|
* @return 分页对象,list 为提案记录,totalCount 为相同条件下的提案总数
|
||||||
|
*/
|
||||||
|
Pagination pageDashboardData(PageForm pageForm, String sessionId, String selectNodeId,
|
||||||
|
String selectNodeType, String selectNodeMode);
|
||||||
}
|
}
|
||||||
|
|||||||
+238
-3
@@ -23,6 +23,10 @@ import com.budwk.app.base.utils.PageUtil;
|
|||||||
import com.budwk.app.base.utils.SysOfficeTemplateUtil;
|
import com.budwk.app.base.utils.SysOfficeTemplateUtil;
|
||||||
import com.budwk.app.flow.constant.FlowConst;
|
import com.budwk.app.flow.constant.FlowConst;
|
||||||
import com.budwk.app.flow.engine.FlowEngine;
|
import com.budwk.app.flow.engine.FlowEngine;
|
||||||
|
import com.budwk.app.flow.engine.model.ProcessModel;
|
||||||
|
import com.budwk.app.flow.engine.model.TaskModel;
|
||||||
|
import com.budwk.app.flow.entity.ProcessDefine;
|
||||||
|
import com.budwk.app.flow.service.ProcessDefineService;
|
||||||
import com.budwk.app.flow.engine.util.FlowUtil;
|
import com.budwk.app.flow.engine.util.FlowUtil;
|
||||||
import com.budwk.app.flow.entity.ProcessInstance;
|
import com.budwk.app.flow.entity.ProcessInstance;
|
||||||
import com.budwk.app.flow.entity.ProcessTask;
|
import com.budwk.app.flow.entity.ProcessTask;
|
||||||
@@ -82,6 +86,24 @@ import java.util.stream.Collectors;
|
|||||||
@IocBean(args = {"refer:dao"})
|
@IocBean(args = {"refer:dao"})
|
||||||
public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> implements ProposalCommonService {
|
public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> implements ProposalCommonService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工作台表格允许排序的字段映射,值为查询中的真实字段或安全别名。
|
||||||
|
*/
|
||||||
|
private static final Map<String, String> DASHBOARD_ORDER_COLUMNS = Map.ofEntries(
|
||||||
|
Map.entry("code", "info.code"),
|
||||||
|
Map.entry("name", "info.name"),
|
||||||
|
Map.entry("createUserName", "info.createUserName"),
|
||||||
|
Map.entry("typeName", "typeName"),
|
||||||
|
Map.entry("delegationName", "delegationName"),
|
||||||
|
Map.entry("caseFilingResult", "info.caseFilingResult"),
|
||||||
|
Map.entry("caseFilingType", "info.caseFilingType"),
|
||||||
|
Map.entry("isConsolidation", "info.isConsolidation"),
|
||||||
|
Map.entry("masterUnitName", "masterUnitName"),
|
||||||
|
Map.entry("slaveUnitNames", "slaveUnitNames"),
|
||||||
|
Map.entry("curTaskName", "curTaskName"),
|
||||||
|
Map.entry("instanceState", "instanceState")
|
||||||
|
);
|
||||||
|
|
||||||
/** 确定立案提案的 Word 模板编码。 */
|
/** 确定立案提案的 Word 模板编码。 */
|
||||||
private static final String PROPOSAL_CONFIRM_FILING_TEMPLATE_CODE = "proposal_confirm_filing";
|
private static final String PROPOSAL_CONFIRM_FILING_TEMPLATE_CODE = "proposal_confirm_filing";
|
||||||
|
|
||||||
@@ -187,6 +209,8 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
|||||||
@Inject
|
@Inject
|
||||||
private SysDictService sysDictService;
|
private SysDictService sysDictService;
|
||||||
@Inject
|
@Inject
|
||||||
|
private ProcessDefineService processDefineService;
|
||||||
|
@Inject
|
||||||
private SysUserService sysUserService;
|
private SysUserService sysUserService;
|
||||||
@Inject
|
@Inject
|
||||||
private TeacherCongressDelegateService teacherCongressDelegateService;
|
private TeacherCongressDelegateService teacherCongressDelegateService;
|
||||||
@@ -506,6 +530,216 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
|||||||
return sql;
|
return sql;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取提案看板卡片,沿用现有节点顺序,数量与下方列表共用同一数据范围。
|
||||||
|
* @param sessionId 教代会届次ID;为空时所有卡片数量为零
|
||||||
|
* @return 卡片列表;任务卡片含 todoCount/doneCount,其他卡片含 count
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<NutMap> listDashboardNodes(String sessionId) {
|
||||||
|
List<NutMap> nodes = new ArrayList<>();
|
||||||
|
|
||||||
|
// 提案总数
|
||||||
|
nodes.add(NutMap.NEW().addv("name", "提案总数").addv("id", "total").addv("type", "total").addv("count", 0));
|
||||||
|
|
||||||
|
// 节点
|
||||||
|
ProcessDefine define = processDefineService.getLastByName("JDHTA_NC");
|
||||||
|
ProcessModel processModel = processDefineService.processDefineToModel(define);
|
||||||
|
// 按流程图的连线关系遍历任务节点,保证看板展示顺序与流程图一致。
|
||||||
|
List<TaskModel> taskModels = processModel.getModels(TaskModel.class);
|
||||||
|
|
||||||
|
List<String> excludeNodes = new ArrayList<>(3);
|
||||||
|
excludeNodes.add("撰写提案");
|
||||||
|
excludeNodes.add("邀请附议人");
|
||||||
|
excludeNodes.add("提案附议");
|
||||||
|
|
||||||
|
// opinion_unit_reply、two_unit_reply 为临时屏蔽的承办单位答复节点,不在看板展示。
|
||||||
|
List<String> hiddenNodeIds = List.of("opinion_unit_reply", "two_unit_reply");
|
||||||
|
List<NutMap> taskNodes = new ArrayList<>(taskModels.stream()
|
||||||
|
.filter(taskModel -> !excludeNodes.contains(taskModel.getDisplayName()))
|
||||||
|
.filter(taskModel -> !hiddenNodeIds.contains(taskModel.getName()))
|
||||||
|
.map(taskModel -> NutMap.NEW()
|
||||||
|
.addv("name", taskModel.getDisplayName())
|
||||||
|
.addv("id", taskModel.getName())
|
||||||
|
.addv("type", "task")
|
||||||
|
.addv("count", 0)
|
||||||
|
.addv("todoCount", 0)
|
||||||
|
.addv("doneCount", 0)
|
||||||
|
).toList());
|
||||||
|
|
||||||
|
// 立案结果
|
||||||
|
List<Sys_dict> caseFilingResult = sysDictService.getSubListByCode("PROPOSAL_CASE_FILING_RESULT");
|
||||||
|
List<NutMap> caseFilingResultNodes = new ArrayList<>();
|
||||||
|
for (Sys_dict dict : caseFilingResult) {
|
||||||
|
caseFilingResultNodes.add(NutMap.NEW()
|
||||||
|
.addv("name", dict.getName())
|
||||||
|
.addv("id", dict.getCode())
|
||||||
|
.addv("type", "caseFilingResult")
|
||||||
|
.addv("count", 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 立案结果需展示在委员会确认承办单位之前,反馈评价统一固定到看板末尾。
|
||||||
|
List<NutMap> feedbackNodes = taskNodes.stream()
|
||||||
|
.filter(taskNode -> "feedback".equals(taskNode.getString("id")))
|
||||||
|
.toList();
|
||||||
|
taskNodes.removeIf(taskNode -> "feedback".equals(taskNode.getString("id")));
|
||||||
|
int committeeFilingUnitIndex = taskNodes.size();
|
||||||
|
for (int i = 0; i < taskNodes.size(); i++) {
|
||||||
|
if ("committeeFilingUnit".equals(taskNodes.get(i).getString("id"))) {
|
||||||
|
committeeFilingUnitIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
taskNodes.addAll(committeeFilingUnitIndex, caseFilingResultNodes);
|
||||||
|
nodes.addAll(taskNodes);
|
||||||
|
nodes.addAll(feedbackNodes);
|
||||||
|
|
||||||
|
Map<String, Long> categoryCounts = countDashboardCategories(sessionId);
|
||||||
|
Map<String, NutMap> taskProposalCounts = countDashboardTaskProposals(sessionId);
|
||||||
|
|
||||||
|
for (NutMap node : nodes) {
|
||||||
|
if (node.getString("type").equals("task")) {
|
||||||
|
NutMap taskCount = taskProposalCounts.get(node.getString("id"));
|
||||||
|
node.put("todoCount", taskCount == null ? 0 : taskCount.getLong("todoCount", 0L));
|
||||||
|
node.put("doneCount", taskCount == null ? 0 : taskCount.getLong("doneCount", 0L));
|
||||||
|
} else if (node.getString("type").equals("total")) {
|
||||||
|
node.put("count", categoryCounts.getOrDefault("total", 0L));
|
||||||
|
} else if (node.getString("type").equals("caseFilingResult")) {
|
||||||
|
node.put("count", categoryCounts.getOrDefault(node.getString("id"), 0L));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询看板提案列表,统一使用附议完成后的提案范围,按提案ID去重。
|
||||||
|
* @param pageForm 分页和白名单排序参数
|
||||||
|
* @param sessionId 教代会届次ID;为空时返回空列表
|
||||||
|
* @param selectNodeId 节点编码或立案结果字典编码
|
||||||
|
* @param selectNodeType task、total、caseFilingResult;为空时查询总数列表
|
||||||
|
* @param selectNodeMode done 查询已办任务,其余值查询待办任务
|
||||||
|
* @return 含 list 和 totalCount 的分页结果
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Pagination pageDashboardData(PageForm pageForm, String sessionId, String selectNodeId,
|
||||||
|
String selectNodeType, String selectNodeMode) {
|
||||||
|
Sql sql = Sqls.create("""
|
||||||
|
SELECT
|
||||||
|
info.*,
|
||||||
|
type.name AS typeName,
|
||||||
|
tcs.fullName AS sessionName,
|
||||||
|
tcd.`name` AS delegationName,
|
||||||
|
ins.id AS instanceId,
|
||||||
|
ins.businessNo,
|
||||||
|
ins.state instanceState,
|
||||||
|
ins.variable instanceVariable,
|
||||||
|
ins.processDefineId instanceProcessDefineId,
|
||||||
|
t.displayName curTaskName,
|
||||||
|
GROUP_CONCAT(DISTINCT CASE WHEN pru.isMaster = 1 THEN pru.unitName END) AS masterUnitName,
|
||||||
|
GROUP_CONCAT(DISTINCT CASE WHEN pru.isMaster = 0 THEN pru.unitName END) AS slaveUnitNames
|
||||||
|
FROM
|
||||||
|
proposal_info info
|
||||||
|
LEFT JOIN proposal_type type on type.id = info.typeId
|
||||||
|
LEFT JOIN teacher_congress_session tcs on tcs.id = info.sessionId
|
||||||
|
LEFT JOIN teacher_congress_delegation tcd on tcd.id = info.delegationId
|
||||||
|
LEFT JOIN teacher_congress_delegate tcde on tcde.loginName = info.createUserLoginName
|
||||||
|
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||||
|
LEFT JOIN proposal_reply_unit pru ON pru.proposalId = info.id
|
||||||
|
LEFT JOIN wf_process_task t ON t.processInstanceId = ins.id AND t.taskState = @taskState
|
||||||
|
$condition
|
||||||
|
""");
|
||||||
|
Cnd cnd = buildDashboardCondition(sessionId);
|
||||||
|
cnd.groupBy("info.id");
|
||||||
|
|
||||||
|
// 默认显示进行中的任务
|
||||||
|
sql.setParam("taskState", ProcessTaskStateEnum.DOING.getCode());
|
||||||
|
|
||||||
|
if (StrUtil.isNotBlank(selectNodeType) && StrUtil.isNotBlank(selectNodeId)) {
|
||||||
|
switch (selectNodeType) {
|
||||||
|
case "task":
|
||||||
|
cnd.and("t.taskName", "=", selectNodeId);
|
||||||
|
|
||||||
|
if (!"done".equals(selectNodeMode)) {
|
||||||
|
sql.setParam("taskState", ProcessTaskStateEnum.DOING.getCode());
|
||||||
|
} else {
|
||||||
|
sql.setParam("taskState", ProcessTaskStateEnum.FINISHED.getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "total":
|
||||||
|
break;
|
||||||
|
case "caseFilingResult":
|
||||||
|
cnd.and("info.caseFilingResult", "=", selectNodeId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 只接受白名单排序字段,复用现有分页能力。
|
||||||
|
applySafePageOrder(cnd, pageForm, DASHBOARD_ORDER_COLUMNS);
|
||||||
|
sql.setCondition(cnd);
|
||||||
|
return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统计看板总数及立案结果;一次按结果分组后求和,确保卡片与列表口径一致。
|
||||||
|
* @param sessionId 教代会届次ID
|
||||||
|
* @return total 为提案总数,其他键为立案结果编码
|
||||||
|
*/
|
||||||
|
private Map<String, Long> countDashboardCategories(String sessionId) {
|
||||||
|
Sql sql = Sqls.create("SELECT info.caseFilingResult, COUNT(1) AS proposalCount FROM proposal_info info $condition");
|
||||||
|
Cnd cnd = buildDashboardCondition(sessionId);
|
||||||
|
cnd.groupBy("info.caseFilingResult");
|
||||||
|
sql.setCondition(cnd);
|
||||||
|
Map<String, Long> counts = new HashMap<>();
|
||||||
|
long total = 0L;
|
||||||
|
for (NutMap row : listMap(sql)) {
|
||||||
|
long count = row.getLong("proposalCount", 0L);
|
||||||
|
total += count;
|
||||||
|
if (StrUtil.isNotBlank(row.getString("caseFilingResult"))) {
|
||||||
|
counts.put(row.getString("caseFilingResult"), count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
counts.put("total", total);
|
||||||
|
return counts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建看板统一范围:迁入提案按参考业务阶段排除草稿、附议阶段;新提案按实际WF任务判断。
|
||||||
|
* 历史迁入实例可能缺少当前任务,不能仅因缺任务而漏算已进入审核的历史提案。
|
||||||
|
* 新WF提案的旧 stateCode 不随每个节点更新,必须读取有效审核任务,并排除已退回撰写/附议的实例。
|
||||||
|
* @param sessionId 届次ID;清空选择时返回空范围,避免跨届次查询
|
||||||
|
* @return 仅包含筛选条件、不包含排序和分组的 Cnd
|
||||||
|
*/
|
||||||
|
private Cnd buildDashboardCondition(String sessionId) {
|
||||||
|
Cnd cnd = Cnd.where("info.sessionId", "=", StrUtil.blankToDefault(sessionId, ""));
|
||||||
|
cnd.and(new Static("""
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1 FROM wf_process_instance scopeIns
|
||||||
|
WHERE scopeIns.businessNo = info.id
|
||||||
|
AND (
|
||||||
|
(JSON_UNQUOTE(JSON_EXTRACT(scopeIns.variable, '$.legacyV3')) = 'true' AND info.stateCode >= 200)
|
||||||
|
OR (
|
||||||
|
COALESCE(JSON_UNQUOTE(JSON_EXTRACT(scopeIns.variable, '$.legacyV3')), 'false') <> 'true'
|
||||||
|
AND EXISTS (
|
||||||
|
SELECT 1 FROM wf_process_task scopeTask
|
||||||
|
WHERE scopeTask.processInstanceId = scopeIns.id
|
||||||
|
AND scopeTask.taskName NOT IN ('startTask', 'invite', 'second')
|
||||||
|
AND scopeTask.taskState IN (10, 20)
|
||||||
|
)
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM wf_process_task earlyTask
|
||||||
|
WHERE earlyTask.processInstanceId = scopeIns.id
|
||||||
|
AND earlyTask.taskName IN ('startTask', 'invite', 'second')
|
||||||
|
AND earlyTask.taskState = 10
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
"""));
|
||||||
|
return cnd;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按提案ID去重统计数据看板的流程节点数量。
|
* 按提案ID去重统计数据看板的流程节点数量。
|
||||||
* 同一提案因撤回、退回等再次经过同一节点时,任务表会保留多条已办记录;
|
* 同一提案因撤回、退回等再次经过同一节点时,任务表会保留多条已办记录;
|
||||||
@@ -524,10 +758,11 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
|||||||
FROM wf_process_task t
|
FROM wf_process_task t
|
||||||
INNER JOIN wf_process_instance ins ON ins.id = t.processInstanceId
|
INNER JOIN wf_process_instance ins ON ins.id = t.processInstanceId
|
||||||
INNER JOIN proposal_info info ON info.id = ins.businessNo
|
INNER JOIN proposal_info info ON info.id = ins.businessNo
|
||||||
WHERE info.sessionId = @sessionId
|
$condition
|
||||||
GROUP BY t.taskName
|
|
||||||
""");
|
""");
|
||||||
sql.setParam("sessionId", sessionId);
|
Cnd cnd = buildDashboardCondition(sessionId);
|
||||||
|
cnd.groupBy("t.taskName");
|
||||||
|
sql.setCondition(cnd);
|
||||||
sql.setParam("doingState", ProcessTaskStateEnum.DOING.getCode());
|
sql.setParam("doingState", ProcessTaskStateEnum.DOING.getCode());
|
||||||
sql.setParam("finishedState", ProcessTaskStateEnum.FINISHED.getCode());
|
sql.setParam("finishedState", ProcessTaskStateEnum.FINISHED.getCode());
|
||||||
List<NutMap> taskCounts = listMap(sql);
|
List<NutMap> taskCounts = listMap(sql);
|
||||||
|
|||||||
@@ -206,6 +206,15 @@ layout("/layouts/platform.html"){
|
|||||||
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT" :value="row.caseFilingResult"></dict-tag>
|
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT" :value="row.caseFilingResult"></dict-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<!-- 是否重点复用立案类型字段;未立案与类型未填写分开展示,避免空值被误认为普通提案。 -->
|
||||||
|
<el-table-column label="是否重点" prop="caseFilingType" sortable="custom" width="110">
|
||||||
|
<template slot-scope="{row}">
|
||||||
|
<dict-tag v-if="row.caseFilingResult === 'CONFIRM_FILING' && row.caseFilingType"
|
||||||
|
:options="dict.type.PROPOSAL_CASE_FILING_TYPE" :value="row.caseFilingType"></dict-tag>
|
||||||
|
<span v-else-if="!row.caseFilingResult || row.caseFilingResult === 'CONFIRM_FILING'">未确定</span>
|
||||||
|
<span v-else>否</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column label="是否并案" prop="isConsolidation" sortable="custom" width="100">
|
<el-table-column label="是否并案" prop="isConsolidation" sortable="custom" width="100">
|
||||||
<template scope="{row}">
|
<template scope="{row}">
|
||||||
<el-tag size="mini" v-if="row.isConsolidation" type="success">是</el-tag>
|
<el-tag size="mini" v-if="row.isConsolidation" type="success">是</el-tag>
|
||||||
@@ -241,7 +250,7 @@ layout("/layouts/platform.html"){
|
|||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
el: '#app',
|
el: '#app',
|
||||||
dicts: ["PROPOSAL_TYPE", "PROPOSAL_CASE_FILING_RESULT"],
|
dicts: ["PROPOSAL_TYPE", "PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE"],
|
||||||
components: {
|
components: {
|
||||||
"proposal-info": PROPOSAL_INFO
|
"proposal-info": PROPOSAL_INFO
|
||||||
},
|
},
|
||||||
@@ -252,6 +261,8 @@ layout("/layouts/platform.html"){
|
|||||||
nodes: [],
|
nodes: [],
|
||||||
nodeDisplayModes: {}, // 存储每个节点的显示模式
|
nodeDisplayModes: {}, // 存储每个节点的显示模式
|
||||||
pageForm: {
|
pageForm: {
|
||||||
|
sessionId: null,
|
||||||
|
selectNodeMode: "todo",
|
||||||
selectNodeId: null,
|
selectNodeId: null,
|
||||||
selectNodeType: null,
|
selectNodeType: null,
|
||||||
pageSize: 5
|
pageSize: 5
|
||||||
@@ -268,6 +279,10 @@ layout("/layouts/platform.html"){
|
|||||||
|
|
||||||
// 届次改变
|
// 届次改变
|
||||||
sessionChange() {
|
sessionChange() {
|
||||||
|
// 切换届次后回到总数卡片,避免沿用上一届次的分类筛选。
|
||||||
|
this.$set(this.pageForm, "selectNodeId", null)
|
||||||
|
this.$set(this.pageForm, "selectNodeType", null)
|
||||||
|
this.$set(this.pageForm, "selectNodeMode", "todo")
|
||||||
this.getNodes()
|
this.getNodes()
|
||||||
this.doSearch()
|
this.doSearch()
|
||||||
},
|
},
|
||||||
@@ -276,8 +291,8 @@ layout("/layouts/platform.html"){
|
|||||||
listSession() {
|
listSession() {
|
||||||
this.$axios.post("/platform/proposal/common/listSession").then((res) => {
|
this.$axios.post("/platform/proposal/common/listSession").then((res) => {
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
this.sessionOptions = res.data
|
this.$set(this, "sessionOptions", res.data || [])
|
||||||
if (this.sessionOptions) {
|
if (this.sessionOptions.length) {
|
||||||
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
|
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
|
||||||
this.getNodes()
|
this.getNodes()
|
||||||
this.doSearch()
|
this.doSearch()
|
||||||
@@ -290,7 +305,7 @@ layout("/layouts/platform.html"){
|
|||||||
getNodes() {
|
getNodes() {
|
||||||
this.$axios.post('/platform/proposal/dashboard/listNode', {sessionId: this.pageForm.sessionId}).then(res => {
|
this.$axios.post('/platform/proposal/dashboard/listNode', {sessionId: this.pageForm.sessionId}).then(res => {
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
this.nodes = res.data
|
this.$set(this, "nodes", res.data || [])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -303,9 +318,9 @@ layout("/layouts/platform.html"){
|
|||||||
|
|
||||||
// 节点选择
|
// 节点选择
|
||||||
selectNode(node, index) {
|
selectNode(node, index) {
|
||||||
this.pageForm.selectNodeId = node.id
|
this.$set(this.pageForm, "selectNodeId", node.id)
|
||||||
this.pageForm.selectNodeType = node.type
|
this.$set(this.pageForm, "selectNodeType", node.type)
|
||||||
this.pageForm.selectNodeMode = this.getNodeDisplayMode(node.id)
|
this.$set(this.pageForm, "selectNodeMode", this.getNodeDisplayMode(node.id))
|
||||||
this.doSearch()
|
this.doSearch()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -297,10 +297,11 @@ layout("/layouts/platform.html"){
|
|||||||
{{memberNumberData.memberNum}}
|
{{memberNumberData.memberNum}}
|
||||||
<span style="font-size: 14px"> 人</span>
|
<span style="font-size: 14px"> 人</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="stat-meta" v-loading="loading.memberNumber">-->
|
<div class="stat-meta" style="text-align: right" v-loading="loading.memberNumber">
|
||||||
<!-- 年同比 {{memberNumberData.ratio}} -->
|
年同比 {{memberNumberData.ratio}} 
|
||||||
<!-- <i :class="memberNumberData.diff >= 0 ? 'el-icon-top trend-up' : 'el-icon-bottom trend-down'"></i>-->
|
<i v-if="memberNumberData.diff > 0" class="el-icon-top trend-up"></i>
|
||||||
<!-- </div>-->
|
<i v-else-if="memberNumberData.diff < 0" class="el-icon-bottom trend-down"></i>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card stats-card">
|
<div class="card stats-card">
|
||||||
@@ -393,8 +394,8 @@ layout("/layouts/platform.html"){
|
|||||||
memberNumberData: {
|
memberNumberData: {
|
||||||
memberNum: "--",
|
memberNum: "--",
|
||||||
lastYearMemberNum: "--",
|
lastYearMemberNum: "--",
|
||||||
ratio: "0.0%",
|
ratio: "—",
|
||||||
diff: 0
|
diff: null
|
||||||
},
|
},
|
||||||
memberPercentage: "--",
|
memberPercentage: "--",
|
||||||
unionMember: []
|
unionMember: []
|
||||||
@@ -403,23 +404,39 @@ layout("/layouts/platform.html"){
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/**
|
/**
|
||||||
* 会员数
|
* 无需传参;接口返回 memberNum 当前会员数和 lastYearMemberNum 去年归档会员数。
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>} 更新会员数、同比及涨跌方向,请求结束后关闭加载状态。
|
||||||
*/
|
*/
|
||||||
async getMemberNumber() {
|
getMemberNumber() {
|
||||||
this.loading.memberNumber = true
|
this.$set(this.loading, "memberNumber", true)
|
||||||
this.$axios.post("/platform/member/info/board/memberNumber").then((resp) => {
|
return this.$axios.post("/platform/member/info/board/memberNumber").then((resp) => {
|
||||||
if (resp.code === 0) {
|
if (resp.code === 0) {
|
||||||
const {
|
const data = resp.data || {}
|
||||||
data: { memberNum, lastYearMemberNum }
|
// 兼容数字字符串,但不把空值、布尔值或异常人数转换成有效的零人数。
|
||||||
} = resp
|
const memberNum = typeof data.memberNum === "number" || (typeof data.memberNum === "string" && data.memberNum.trim() !== "") ? Number(data.memberNum) : NaN
|
||||||
const diff = memberNum - lastYearMemberNum
|
const lastYearMemberNum = typeof data.lastYearMemberNum === "number" || (typeof data.lastYearMemberNum === "string" && data.lastYearMemberNum.trim() !== "") ? Number(data.lastYearMemberNum) : NaN
|
||||||
const ratio = (lastYearMemberNum ? (Math.abs(diff) / lastYearMemberNum) * 100 : (diff / 1) * 10).toFixed(2) + " %"
|
const validMemberNum = Number.isSafeInteger(memberNum) && memberNum >= 0
|
||||||
this.memberNumberData = { memberNum, lastYearMemberNum, diff, ratio }
|
const validLastYearMemberNum = Number.isSafeInteger(lastYearMemberNum) && lastYearMemberNum >= 0
|
||||||
this.loading.memberNumber = false
|
let diff = null
|
||||||
|
let ratio = "—"
|
||||||
|
// 去年为零或没有归档人数时无法计算同比;仅在基数有效且大于零时显示涨跌。
|
||||||
|
if (validMemberNum && validLastYearMemberNum && lastYearMemberNum > 0) {
|
||||||
|
diff = memberNum - lastYearMemberNum
|
||||||
|
// 先按万分比对涨跌幅绝对值四舍五入,再恢复负号,避免 4.525% 被直接格式化成 4.52%。
|
||||||
|
const changePercent = Math.round(Math.abs(diff) * 10000 / lastYearMemberNum) / 100
|
||||||
|
ratio = diff === 0 ? "持平" : (diff < 0 && changePercent > 0 ? "-" : "") + changePercent.toFixed(2) + " %"
|
||||||
|
}
|
||||||
|
this.$set(this, "memberNumberData", {
|
||||||
|
memberNum: validMemberNum ? memberNum : "--",
|
||||||
|
lastYearMemberNum: validLastYearMemberNum ? lastYearMemberNum : "--",
|
||||||
|
diff: diff,
|
||||||
|
ratio: ratio
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
this.$message.warning(resp.msg)
|
this.$message.warning(resp.msg)
|
||||||
}
|
}
|
||||||
|
}).finally(() => {
|
||||||
|
this.$set(this.loading, "memberNumber", false)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@@ -484,18 +501,23 @@ layout("/layouts/platform.html"){
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 会员占比
|
* 无需传参;接口 data 为 0~1 的会员比例,兼容数值字符串后用于水波图。
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>} 完成比例校验和图表更新,并在请求结束时关闭加载状态。
|
||||||
*/
|
*/
|
||||||
async getMemberPercentage() {
|
getMemberPercentage() {
|
||||||
this.loading.memberPercentage = true
|
this.$set(this.loading, "memberPercentage", true)
|
||||||
this.$axios.post("/platform/member/info/board/memberPercentage").then((resp) => {
|
return this.$axios.post("/platform/member/info/board/memberPercentage").then((resp) => {
|
||||||
this.loading.memberPercentage = false
|
|
||||||
if (resp.code === 0) {
|
if (resp.code === 0) {
|
||||||
const { data } = resp
|
const { data } = resp
|
||||||
this.memberPercentage = data.toFixed(2)
|
// 空值、非数值和超出比例范围的数据不能作为 0% 展示;合法的零值需要保留。
|
||||||
|
const percent = typeof data === "number" || (typeof data === "string" && data.trim() !== "") ? Number(data) : NaN
|
||||||
|
if (!Number.isFinite(percent) || percent < 0 || percent > 1) {
|
||||||
|
this.$message.warning("会员占比数据异常,请稍后重试")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$set(this, "memberPercentage", percent.toFixed(2))
|
||||||
if (chart.memberPercentageChart) {
|
if (chart.memberPercentageChart) {
|
||||||
chart.memberPercentageChart.changeData(data)
|
chart.memberPercentageChart.changeData(percent)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
chart.memberPercentageChart = new G2Plot.Liquid("memberPercentageChart", {
|
chart.memberPercentageChart = new G2Plot.Liquid("memberPercentageChart", {
|
||||||
@@ -507,13 +529,17 @@ layout("/layouts/platform.html"){
|
|||||||
length: 128
|
length: 128
|
||||||
},
|
},
|
||||||
autoFit: true,
|
autoFit: true,
|
||||||
percent: data,
|
percent: percent,
|
||||||
color: '#217050',
|
color: '#217050',
|
||||||
statistic: {
|
statistic: {
|
||||||
content: {
|
content: {
|
||||||
style: {
|
style: {
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fill: '#fff', // 白色文字
|
// 深色文字配浅色描边,确保低水位白底和高水位绿底上的百分比均可读。
|
||||||
|
fill: '#1f2937',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
stroke: '#fff',
|
||||||
|
lineWidth: 0.5,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -522,6 +548,8 @@ layout("/layouts/platform.html"){
|
|||||||
} else {
|
} else {
|
||||||
this.$message.warning(resp.msg)
|
this.$message.warning(resp.msg)
|
||||||
}
|
}
|
||||||
|
}).finally(() => {
|
||||||
|
this.$set(this.loading, "memberPercentage", false)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user