Merge remote-tracking branch 'origin/master'

This commit is contained in:
ye1023
2026-05-06 09:13:35 +08:00
67 changed files with 4696 additions and 645 deletions
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>jeecg-boot-module</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>${jeecgProjectVersion}</version>
</parent>
<artifactId>jeecg-module-flow</artifactId>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-base-core</artifactId>
</dependency>
<dependency>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-system-local-api</artifactId>
</dependency>
<dependency>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-module-bpm-flowable</artifactId>
<version>3.8.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-system-biz</artifactId>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,17 @@
package org.jeecg;
//TIP 要<b>运行</b>代码,请按 <shortcut actionId="Run"/> 或
// 点击装订区域中的 <icon src="AllIcons.Actions.Execute"/> 图标。
public class Main {
public static void main(String[] args) {
//TIP 当文本光标位于高亮显示的文本处时按 <shortcut actionId="ShowIntentionActions"/>
// 查看 IntelliJ IDEA 建议如何修正。
System.out.printf("Hello and welcome!");
for (int i = 1; i <= 5; i++) {
//TIP 按 <shortcut actionId="Debug"/> 开始调试代码。我们已经设置了一个 <icon src="AllIcons.Debugger.Db_set_breakpoint"/> 断点
// 但您始终可以通过按 <shortcut actionId="ToggleLineBreakpoint"/> 添加更多断点。
System.out.println("i = " + i);
}
}
}
@@ -0,0 +1,33 @@
package org.jeecg.xispeak;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "flow-biz")
public class XiSpeakConfig {
/**
* 对应 yml 中的 xi-speak 节点
* Spring 会自动将中划线命名映射为驼峰命名
*/
private XiSpeakProperties xiSpeak;
@Data
public static class XiSpeakProperties {
/** 对应 bg-dept-id */
private String bgDeptId;
/** 对应 ld-role-id */
private String ldRoleId;
/** 对应 need-sdw-approve-code */
private String needSdwApproveCode;
/** 对应 json-data-key */
private String jsonDataKey;
/** 对应 impl-dept-key */
private String implDeptKey;
/** 对应impl-dept-collection-used*/
private String implDeptCollectionUsedKey;
}
}
@@ -0,0 +1,129 @@
package org.jeecg.xispeak;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.util.StringUtils;
import org.flowable.engine.RuntimeService;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Component("xiSpeakFlow")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class XiSpeakFlow {
private final XiSpeakConfig xiSpeakConfig;
private final ISysBaseAPI iSysBaseAPI;
private final RuntimeService runtimeService;
public List<String> getBgDeptLdUserIdList() {
// 1. 安全获取配置,防止 NPE
XiSpeakConfig.XiSpeakProperties props = xiSpeakConfig.getXiSpeak();
if (props == null || !StringUtils.hasText(props.getBgDeptId())) {
log.error("流程配置缺失: [flow-biz.xi-speak.bg-dept-id] 未在 YAML 中定义");
return Collections.emptyList();
}
// 2. 调用接口获取数据
log.info("正在查询部门: {} 下的角色: {} 的用户列表", props.getBgDeptId(), props.getLdRoleId());
List<String> userList = iSysBaseAPI.getUsersListByDeptIdAndRoleIdLocalApi(
props.getBgDeptId(),
props.getLdRoleId()
);
log.info("查询到的用户为: {}", userList);
return userList;
}
public Integer getNeedSdwApproval(Object jsonData) {
XiSpeakConfig.XiSpeakProperties props = xiSpeakConfig.getXiSpeak();
if (jsonData == null || org.apache.commons.lang.StringUtils.isBlank(props.getNeedSdwApproveCode())) {
return 0;
}
String codeName = props.getNeedSdwApproveCode();
if (org.apache.commons.lang.StringUtils.isBlank(codeName)) return 0;
try {
JSONObject data;
if (jsonData instanceof JSONObject) {
data = (JSONObject) jsonData;
} else if (jsonData instanceof String) {
if (org.apache.commons.lang.StringUtils.isBlank((String) jsonData)) {
return 0;
}
data = JSONObject.parseObject((String) jsonData);
} else {
data = JSONObject.parseObject(JSONObject.toJSONString(jsonData));
}
log.info("needSdwApproval结果为{}", data.getInteger(codeName));
return data == null ? 0 : data.getInteger(codeName);
} catch (Exception e) {
log.warn("getJsondata parse failed, codeName={}, jsonData={}", codeName, jsonData, e);
return 0;
}
}
public List<String> getImplDeptLdsList(String deptId) {
return iSysBaseAPI.getUsersListByDeptIdAndRoleIdLocalApi(deptId, xiSpeakConfig.getXiSpeak().getLdRoleId());
}
public int getListSize(String jsonData){
if (org.apache.commons.lang3.StringUtils.isEmpty(jsonData)) {
return 0;
}
return Math.toIntExact(Arrays.stream(jsonData.split(","))
.map(String::trim)
.filter(org.apache.commons.lang3.StringUtils::isNotEmpty)
.count());
}
// List<String> getImplDeptWorker(String JG_LOCAL_PROCESS_ID,String deptId){
// runtimeService.get
// }
public Integer getImplDeptNums(String jsonData) {
String codeName = xiSpeakConfig.getXiSpeak().getImplDeptKey();
if (jsonData == null || org.apache.commons.lang.StringUtils.isEmpty(codeName)) {
return 0;
}
// 1. 统一转成 JSONObject
JSONObject json;
json = JSON.parseObject((String) jsonData);
if (json == null || !json.containsKey(codeName)) {
return 0;
}
// 2. 获取原始对象进行兼容性处理
Object value = json.get(codeName);
if (value == null) {
return 0;
}
List<String> resultList = new ArrayList<>();
if (value instanceof Collection) {
// 情况 A: 本身就是集合/JSON数组
resultList.addAll(json.getJSONArray(codeName).toJavaList(String.class));
} else if (value instanceof String) {
// 情况 B: 是逗号分隔的字符串 "ID1,ID2,ID3"
String str = (String) value;
if (org.apache.commons.lang.StringUtils.isNotEmpty(str)) {
// 使用 split 拆分,并过滤掉空格和空字符串
String[] split = str.split(",");
for (String s : split) {
if (org.apache.commons.lang.StringUtils.isNotEmpty(s.trim())) {
resultList.add(s.trim());
}
}
}
}
return resultList.size();
}
}
@@ -0,0 +1,118 @@
package org.jeecg.modules.extbpm.listener.execution;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.modules.extbpm.process.common.expression.FlowNodeExpression;
import lombok.RequiredArgsConstructor;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.extbpm.process.common.WorkFlowGlobals;
import org.jeecg.xispeak.XiSpeakConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
@Component("AfterSDWApproveHqListener")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class AfterSDWApproveHqListener implements ExecutionListener {
private static final long serialVersionUID = 1L;
private final FlowNodeExpression flowNodeExpression;
@Autowired
private RuntimeService runtimeService;
private final XiSpeakConfig xiSpeakConfig;
@Override
public void notify(DelegateExecution execution) {
XiSpeakConfig.XiSpeakProperties props = xiSpeakConfig.getXiSpeak();
//RuntimeService runtimeService = SpringContextUtils.getBean(RuntimeService.class);
String mainProcessId = (String)execution.getProcessInstanceId();
String url = (String)execution.getVariable(WorkFlowGlobals.BPM_FORM_CONTENT_URL);
// 打印主流程里所有的变量名,看看有没有 json_data
Map<String, Object> variables = runtimeService.getVariables(execution.getRootProcessInstanceId());
log.info("主流程中的所有变量名: " + variables.keySet());
// 打印当前执行流的所有变量名
log.info("当前执行流的所有变量名: " + execution.getVariables().keySet());
String bizTitle = (String)runtimeService.getVariable(mainProcessId,WorkFlowGlobals.BPM_BIZ_TITLE);
if(org.apache.commons.lang.StringUtil.isEmpty(url)) {
url = (String)runtimeService.getVariable(mainProcessId,WorkFlowGlobals.BPM_FORM_CONTENT_URL);
String mobileUrl = (String)runtimeService.getVariable(mainProcessId,WorkFlowGlobals.BPM_FORM_CONTENT_URL_MOBILE);
execution.setVariable(WorkFlowGlobals.BPM_FORM_CONTENT_URL, url);
execution.setVariable(WorkFlowGlobals.BPM_FORM_CONTENT_URL_MOBILE, mobileUrl);
}
// 1. 获取主流程中的 json_data 对象(可能是 String 或 JSONObject
Object jsonDataObj = (String)runtimeService.getVariable(mainProcessId,props.getJsonDataKey());
if (oConvertUtils.isNotEmpty(jsonDataObj)) {
String json_data = jsonDataObj.toString();
try {
// 2. 调用表达式解析工具获取特定字段的字符串内容
String jsonStr = flowNodeExpression.getJsondatastring(json_data, props.getImplDeptKey());
// 3. 只有当字段存在且内容不为空时,才进行解析
if (oConvertUtils.isNotEmpty(jsonStr)) {
List<String> deptIds = Arrays.stream(jsonStr.split(","))
.map(String::trim) // 去掉可能存在的空格
.filter(s -> !s.isEmpty()) // 过滤掉空字符串
.collect(Collectors.toList());
if (deptIds != null && !deptIds.isEmpty()) {
// 4. 将提取出的 List 存入子流程变量(供多实例 Collection 使用)
execution.setVariable( props.getImplDeptKey(), deptIds);
log.info("子流程变量 deptIdList 注入成功: " + deptIds);
}
}
} catch (Exception e) {
log.error("解析 JSON 字段 pending_depts_id 失败: ", e);
}
}
//获取主表数据id
String businessKey = (String)runtimeService.getVariable(mainProcessId, WorkFlowGlobals.BPM_DATA_ID);
//获取主表的设计表单数据ID
String BPM_DES_DATA_ID = oConvertUtils.getString(runtimeService.getVariable(mainProcessId, WorkFlowGlobals.BPM_DES_DATA_ID));
//获取主表表名
String tableName = (String)runtimeService.getVariable(mainProcessId,WorkFlowGlobals.BPM_FORM_KEY);
execution.setVariable(WorkFlowGlobals.BPM_FORM_KEY, tableName);
//--update--begin------author:scott-----date:20210512-----for:出差借款子流程,加载表单数据为空问题---------
//log.info("----------传入子流程的数据ID--------------: "+execution.getVariable(WorkFlowGlobals.DATA_ID));
if(oConvertUtils.isNotEmpty(execution.getVariable(WorkFlowGlobals.DATA_ID))){
execution.setVariable(WorkFlowGlobals.BPM_DATA_ID, execution.getVariable(WorkFlowGlobals.DATA_ID));
//如果是设计器表单,则还需要设置设计表单数据ID
if(oConvertUtils.isNotEmpty(BPM_DES_DATA_ID)){
execution.setVariable(WorkFlowGlobals.BPM_DES_DATA_ID, execution.getVariable(WorkFlowGlobals.DATA_ID));
}
}else{
//未传入id值,则获取主表数据id给子流程【online表单需要】
execution.setVariable(WorkFlowGlobals.BPM_DATA_ID, businessKey);
//如果是设计器表单,则还需要设置设计表单数据ID
if(oConvertUtils.isNotEmpty(BPM_DES_DATA_ID)){
execution.setVariable(WorkFlowGlobals.BPM_DES_DATA_ID, BPM_DES_DATA_ID);
}
}
//--update--end------author:scott-----date:20210512-----for:出差借款子流程,加载表单数据为空问题---------
//子流程实例set业务号和主流程保持一致
runtimeService.updateBusinessKey(execution.getProcessInstanceId(), businessKey);
}
}
@@ -0,0 +1,8 @@
flow-biz:
xi-speak:
bg-dept-id: "2044677604785229826"
ld-role-id: "2044680793306591234"
need-sdw-approve-code: "needSdwApproval"
json-data-key: "json_data"
impl-dept-key: "implDept"
impl-dept-collection-used-key: "impl_dept_id"
@@ -0,0 +1,117 @@
package org.jeecg.modules.extbpm.listener.execution;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtil;
import org.jeecg.modules.extbpm.process.common.expression.FlowNodeExpression;
import com.alibaba.fastjson.JSON;
import lombok.RequiredArgsConstructor;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.extbpm.process.common.WorkFlowGlobals;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
@Component("embeddedSubProcessHqStartListener")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class EmbeddedSubProcessHqStartListener implements ExecutionListener {
private static final long serialVersionUID = 1L;
private final FlowNodeExpression flowNodeExpression;
@Autowired
private RuntimeService runtimeService;
@Override
public void notify(DelegateExecution execution) {
//RuntimeService runtimeService = SpringContextUtils.getBean(RuntimeService.class);
String mainProcessId = (String)execution.getProcessInstanceId();
String url = (String)execution.getVariable(WorkFlowGlobals.BPM_FORM_CONTENT_URL);
// 打印主流程里所有的变量名,看看有没有 json_data
Map<String, Object> variables = runtimeService.getVariables(execution.getRootProcessInstanceId());
log.info("主流程中的所有变量名: " + variables.keySet());
// 打印当前执行流的所有变量名
log.info("当前执行流的所有变量名: " + execution.getVariables().keySet());
String bizTitle = (String)runtimeService.getVariable(mainProcessId,WorkFlowGlobals.BPM_BIZ_TITLE);
if(org.apache.commons.lang.StringUtil.isEmpty(url)) {
url = (String)runtimeService.getVariable(mainProcessId,WorkFlowGlobals.BPM_FORM_CONTENT_URL);
String mobileUrl = (String)runtimeService.getVariable(mainProcessId,WorkFlowGlobals.BPM_FORM_CONTENT_URL_MOBILE);
execution.setVariable(WorkFlowGlobals.BPM_FORM_CONTENT_URL, url);
execution.setVariable(WorkFlowGlobals.BPM_FORM_CONTENT_URL_MOBILE, mobileUrl);
}
// 1. 获取主流程中的 json_data 对象(可能是 String 或 JSONObject
Object jsonDataObj = (String)runtimeService.getVariable(mainProcessId,"json_data");
if (oConvertUtils.isNotEmpty(jsonDataObj)) {
String json_data = jsonDataObj.toString();
try {
// 2. 调用表达式解析工具获取特定字段的字符串内容
String jsonStr = flowNodeExpression.getJsondatastring(json_data, "implDept");
// 3. 只有当字段存在且内容不为空时,才进行解析
if (oConvertUtils.isNotEmpty(jsonStr)) {
List<String> deptIds = Arrays.stream(jsonStr.split(","))
.map(String::trim) // 去掉可能存在的空格
.filter(s -> !s.isEmpty()) // 过滤掉空字符串
.collect(Collectors.toList());
if (deptIds != null && !deptIds.isEmpty()) {
// 4. 将提取出的 List 存入子流程变量(供多实例 Collection 使用)
execution.setVariable("pending_depts_id", deptIds);
log.info("子流程变量 deptIdList 注入成功: " + deptIds);
}
}
} catch (Exception e) {
log.error("解析 JSON 字段 pending_depts_id 失败: ", e);
}
}
//获取主表数据id
String businessKey = (String)runtimeService.getVariable(mainProcessId, WorkFlowGlobals.BPM_DATA_ID);
//获取主表的设计表单数据ID
String BPM_DES_DATA_ID = oConvertUtils.getString(runtimeService.getVariable(mainProcessId, WorkFlowGlobals.BPM_DES_DATA_ID));
//获取主表表名
String tableName = (String)runtimeService.getVariable(mainProcessId,WorkFlowGlobals.BPM_FORM_KEY);
execution.setVariable(WorkFlowGlobals.BPM_FORM_KEY, tableName);
//--update--begin------author:scott-----date:20210512-----for:出差借款子流程,加载表单数据为空问题---------
//log.info("----------传入子流程的数据ID--------------: "+execution.getVariable(WorkFlowGlobals.DATA_ID));
if(oConvertUtils.isNotEmpty(execution.getVariable(WorkFlowGlobals.DATA_ID))){
execution.setVariable(WorkFlowGlobals.BPM_DATA_ID, execution.getVariable(WorkFlowGlobals.DATA_ID));
//如果是设计器表单,则还需要设置设计表单数据ID
if(oConvertUtils.isNotEmpty(BPM_DES_DATA_ID)){
execution.setVariable(WorkFlowGlobals.BPM_DES_DATA_ID, execution.getVariable(WorkFlowGlobals.DATA_ID));
}
}else{
//未传入id值,则获取主表数据id给子流程【online表单需要】
execution.setVariable(WorkFlowGlobals.BPM_DATA_ID, businessKey);
//如果是设计器表单,则还需要设置设计表单数据ID
if(oConvertUtils.isNotEmpty(BPM_DES_DATA_ID)){
execution.setVariable(WorkFlowGlobals.BPM_DES_DATA_ID, BPM_DES_DATA_ID);
}
}
//--update--end------author:scott-----date:20210512-----for:出差借款子流程,加载表单数据为空问题---------
//子流程实例set业务号和主流程保持一致
runtimeService.updateBusinessKey(execution.getProcessInstanceId(), businessKey);
}
}
@@ -0,0 +1,61 @@
package org.jeecg.modules.extbpm.listener.execution;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import org.jeecg.modules.extbpm.process.common.WorkFlowGlobals;
import org.jeecg.modules.extbpm.process.common.expression.FlowNodeExpression;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@Slf4j
@Component("subProcessSelectUserListener")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class SubProcessSelectUserListener implements ExecutionListener {
private final FlowNodeExpression flowNodeExpression;
@Autowired
private RuntimeService runtimeService;
@Override
public void notify(DelegateExecution execution) {
String mainProcessId = (String) execution.getProcessInstanceId();
String url = (String)execution.getVariable(WorkFlowGlobals.BPM_FORM_CONTENT_URL);
// 打印主流程里所有的变量名,看看有没有 json_data
Map<String, Object> variables = runtimeService.getVariables(execution.getRootProcessInstanceId());
log.info("主流程中的所有变量名: " + variables.keySet());
// 打印当前执行流的所有变量名
log.info("当前执行流的所有变量名: " + execution.getVariables().keySet());
// 1. 获取原生组件选中的处理人 (假设 Key 为 assigneeUserIdList)
Object selectedValue = execution.getVariable("assigneeUserIdList");
List<String> list = new ArrayList<>();
if (selectedValue instanceof String) {
// 如果是逗号分隔的字符串,拆分
list = Arrays.asList(((String) selectedValue).split(","));
} else if (selectedValue instanceof List) {
list = (List<String>) selectedValue;
}
// 2. 如果没选人,给个默认值防止报错,或者抛出业务异常
if (list.isEmpty()) {
throw new RuntimeException("请选择下一步处理人!");
}
// 3. 关键:将这个 List 存入局部变量,供下一节点的 Multi-instance 读取
// 使用 setVariableLocal 确保并行子流程互不干扰
execution.setVariableLocal("internal_collection", list);
}
}
@@ -201,4 +201,10 @@ public final class WorkFlowGlobals {
* 流程信号启动类型:按钮触发
*/
public static String START_BUTTON_EVENT = "buttonEvent";
/**
* 用于加载json_data字段的键名
*/
public static String JSON_DATA = "json_data";
public static String PENDING_DEPTS_ID = "pending_depts_id";
}
@@ -1,6 +1,7 @@
package org.jeecg.modules.extbpm.process.common.expression;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -81,6 +82,144 @@ public class FlowNodeExpression {
}
}
/**
* 根据字段名称在json_data内查询对应list或set的长度
* ${flowNodeExpression.getJsonDataSizeByCodeName(json_data,"pending_depts_id")}
*
* @param jsonData
* @param codeName
* @return
*/
public Integer getJsonDataSizeByCodeNameStr(Object jsonData, String codeName){
if (jsonData == null || StringUtils.isEmpty(codeName)) {
return 0;
}
// 1. 统一转成 JSONObject
JSONObject json;
if (jsonData instanceof String) {
json = JSON.parseObject((String) jsonData);
} else if (jsonData instanceof JSONObject) {
json = (JSONObject) jsonData;
} else {
return 0;
}
if (json == null || !json.containsKey(codeName)) {
return 0;
}
// 2. 获取原始对象进行兼容性处理
Object value = json.get(codeName);
if (value == null) {
return 0;
}
List<String> resultList = new ArrayList<>();
if (value instanceof Collection) {
// 情况 A: 本身就是集合/JSON数组
resultList.addAll(json.getJSONArray(codeName).toJavaList(String.class));
} else if (value instanceof String) {
// 情况 B: 是逗号分隔的字符串 "ID1,ID2,ID3"
String str = (String) value;
if (StringUtils.isNotEmpty(str)) {
// 使用 split 拆分,并过滤掉空格和空字符串
String[] split = str.split(",");
for (String s : split) {
if (StringUtils.isNotEmpty(s.trim())) {
resultList.add(s.trim());
}
}
}
}
return resultList.size();
}
/**
* 根据字段名称在json_data内查询对应list或set的长度
* ${flowNodeExpression.getJsonDataSizeByCodeName(json_data,"pending_depts_id")}
*
* @param jsonData
* @param codeName
* @return
*/
public Integer getJsonDataSizeByCodeNameObj(Object jsonData, String codeName){
if (jsonData == null || StringUtils.isEmpty(codeName)) {
return 0;
}
// 1. 统一转成 JSONObject
JSONObject json;
if (jsonData instanceof String) {
json = JSON.parseObject((String) jsonData);
} else if (jsonData instanceof JSONObject) {
json = (JSONObject) jsonData;
} else {
return 0;
}
if (json == null || !json.containsKey(codeName)) {
return 0;
}
// 2. 获取原始对象进行兼容性处理
Object value = json.get(codeName);
if (value == null) {
return 0;
}
List<String> resultList = new ArrayList<>();
if (value instanceof Collection) {
// 情况 A: 本身就是集合/JSON数组
resultList.addAll(json.getJSONArray(codeName).toJavaList(String.class));
} else if (value instanceof String) {
// 情况 B: 是逗号分隔的字符串 "ID1,ID2,ID3"
String str = (String) value;
if (StringUtils.isNotEmpty(str)) {
// 使用 split 拆分,并过滤掉空格和空字符串
String[] split = str.split(",");
for (String s : split) {
if (StringUtils.isNotEmpty(s.trim())) {
resultList.add(s.trim());
}
}
}
}
return resultList.size();
}
/**
* 优雅地从 JSON 对象中提取 List
*/
private List<String> getListFromJsonByCodeName(JSONObject json, String key) {
if (json == null || !json.containsKey(key)) {
return Collections.emptyList();
}
Object value = json.get(key);
if (value == null) {
return Collections.emptyList();
}
// 如果本身就是 JSONArrayCollection 子类)
if (value instanceof Collection) {
return ((JSONArray) value).toJavaList(String.class);
}
// 如果是逗号分隔的字符串
if (value instanceof String && StringUtils.isNotBlank((String) value)) {
return Arrays.stream(((String) value).split(","))
.map(String::trim)
.filter(StringUtils::isNotBlank)
.collect(Collectors.toList());
}
return Collections.emptyList();
}
/**
* 根据字段名称取json_data查询对应业务表单的数据
* ${flowNodeExpression.getJsondatastring(jsonData,'supDeptleaderid')}
@@ -90,7 +229,19 @@ public class FlowNodeExpression {
* @return roleId
*/
public List<String> getUsersListByJson(Object jsonData, String deptKeyName, String roleId) {
return ISysBaseAPI.getUsersListByJsonLocalAPI(jsonData,deptKeyName,roleId);
return ISysBaseAPI.getUsersListByJsonLocalAPI(jsonData, deptKeyName, roleId);
}
/**
* 根据部门id角色id获取用户列表
* ${flowNodeExpression.getUsersListByDeptIdAndRoleId(deptId,roleId)}
*
* @param deptId
* @param roleId
* @return roleId
*/
public List<String> getUsersListByDeptIdAndRoleId(String deptId, String roleId) {
return sysbase.getUsersListByDeptIdAndRoleIdLocalApi(deptId, roleId);
}
/**
+4
View File
@@ -21,6 +21,10 @@
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-module-bpm-flowable</artifactId>
</dependency>
<dependency>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-system-local-api</artifactId>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,17 @@
package org.jeecg;
//TIP 要<b>运行</b>代码,请按 <shortcut actionId="Run"/> 或
// 点击装订区域中的 <icon src="AllIcons.Actions.Execute"/> 图标。
public class Main {
public static void main(String[] args) {
//TIP 当文本光标位于高亮显示的文本处时按 <shortcut actionId="ShowIntentionActions"/>
// 查看 IntelliJ IDEA 建议如何修正。
System.out.printf("Hello and welcome!");
for (int i = 1; i <= 5; i++) {
//TIP 按 <shortcut actionId="Debug"/> 开始调试代码。我们已经设置了一个 <icon src="AllIcons.Debugger.Db_set_breakpoint"/> 断点
// 但您始终可以通过按 <shortcut actionId="ToggleLineBreakpoint"/> 添加更多断点。
System.out.println("i = " + i);
}
}
}
@@ -21,6 +21,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.modules.demo.bgpartymatter.entity.BgPartymatter;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
@@ -0,0 +1,168 @@
package org.jeecg.modules.bg.xispeak.controller.feedback;
import java.util.Arrays;
import java.util.List;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.bg.xispeak.entity.BgXiSpeakFeedback;
import org.jeecg.modules.bg.xispeak.service.IBgXiSpeakFeedbackService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.jeecg.common.system.base.controller.JeecgController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.fastjson.JSON;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.apache.shiro.authz.annotation.RequiresPermissions;
/**
* @Description: 习总书记重要讲话反馈表
* @Author: jeecg-boot
* @Date: 2026-04-28
* @Version: V1.0
*/
@Tag(name="习总书记重要讲话反馈表")
@RestController
@RequestMapping("/bg/xispeak/bgXiSpeak")
@Slf4j
public class BgXiSpeakFeedbackController extends JeecgController<BgXiSpeakFeedback, IBgXiSpeakFeedbackService> {
@Autowired
private IBgXiSpeakFeedbackService bgXiSpeakFeedbackService;
/**
* 分页列表查询
*
* @param bgXiSpeakFeedback
* @param pageNo
* @param pageSize
* @param req
* @return
*/
@Operation(summary="习总书记重要讲话反馈表-分页列表查询")
@GetMapping(value = "/listBgXiSpeakFeedbackByMainId")
public Result<IPage<BgXiSpeakFeedback>> queryPageList(BgXiSpeakFeedback bgXiSpeakFeedback,
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<BgXiSpeakFeedback> queryWrapper = QueryGenerator.initQueryWrapper(bgXiSpeakFeedback, req.getParameterMap());
Page<BgXiSpeakFeedback> page = new Page<BgXiSpeakFeedback>(pageNo, pageSize);
IPage<BgXiSpeakFeedback> pageList = bgXiSpeakFeedbackService.page(page, queryWrapper);
return Result.OK(pageList);
}
/**
* 添加
*
* @param bgXiSpeakFeedback
* @return
*/
@AutoLog(value = "习总书记重要讲话反馈表-添加")
@Operation(summary="习总书记重要讲话反馈表-添加")
@PostMapping(value = "/addBgXiSpeakFeedback")
public Result<String> add(@RequestBody BgXiSpeakFeedback bgXiSpeakFeedback) {
bgXiSpeakFeedbackService.save(bgXiSpeakFeedback);
return Result.OK("添加成功!");
}
/**
* 编辑
*
* @param bgXiSpeakFeedback
* @return
*/
@AutoLog(value = "习总书记重要讲话反馈表-编辑")
@Operation(summary="习总书记重要讲话反馈表-编辑")
@PostMapping(value = "/editBgXiSpeakFeedback")
public Result<String> edit(@RequestBody BgXiSpeakFeedback bgXiSpeakFeedback) {
bgXiSpeakFeedbackService.updateById(bgXiSpeakFeedback);
return Result.OK("编辑成功!");
}
/**
* 通过id删除
*
* @param id
* @return
*/
@AutoLog(value = "习总书记重要讲话反馈表-通过id删除")
@Operation(summary="习总书记重要讲话反馈表-通过id删除")
@DeleteMapping(value = "/deleteBgXiSpeakFeedback")
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
bgXiSpeakFeedbackService.removeById(id);
return Result.OK("删除成功!");
}
/**
* 批量删除
*
* @param ids
* @return
*/
@AutoLog(value = "习总书记重要讲话反馈表-批量删除")
@Operation(summary="习总书记重要讲话反馈表-批量删除")
@DeleteMapping(value = "/deleteBatchBgXiSpeakFeedback")
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
this.bgXiSpeakFeedbackService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}
/**
* 通过id查询
*
* @param id
* @return
*/
@Operation(summary="习总书记重要讲话反馈表-通过id查询")
@GetMapping(value = "/queryBgXiSpeakFeedbackById")
public Result<BgXiSpeakFeedback> queryById(@RequestParam(name="id",required=true) String id) {
BgXiSpeakFeedback bgXiSpeakFeedback = bgXiSpeakFeedbackService.getById(id);
if(bgXiSpeakFeedback==null) {
return Result.error("未找到对应数据");
}
return Result.OK(bgXiSpeakFeedback);
}
/**
* 导出excel
*
* @param request
* @param bgXiSpeakFeedback
*/
@RequestMapping(value = "/exportBgXiSpeakFeedback")
public ModelAndView exportXls(HttpServletRequest request, BgXiSpeakFeedback bgXiSpeakFeedback) {
return super.exportXls(request, bgXiSpeakFeedback, BgXiSpeakFeedback.class, "习总书记重要讲话反馈表");
}
/**
* 通过excel导入数据
*
* @param request
* @param response
* @return
*/
@RequestMapping(value = "/importBgXiSpeakFeedback", method = RequestMethod.POST)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response, @PathVariable("mainId") String mainId) {
return super.importExcel(request, response, BgXiSpeakFeedback.class);
}
}
@@ -157,4 +157,12 @@ public class BgXiSpeak implements Serializable {
@Excel(name = "督办次数", width = 15)
@Schema(description = "督办次数")
private java.lang.Integer supervisionCount;
/**dw领导userId字段*/
@Excel(name = "领导userId字段", width = 15)
@Schema(description = "领导userId字段")
private java.lang.String sdwLeaderList;
/**dw领导userId字段*/
@Excel(name = "是否需要sdw审批", width = 15)
@Schema(description = "是否需要sdw审批")
private java.lang.Integer needSdwApproval;
}
@@ -0,0 +1,84 @@
package org.jeecg.modules.bg.xispeak.entity;
import java.io.Serializable;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import org.jeecgframework.poi.excel.annotation.Excel;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* @Description: 习总书记重要讲话反馈表
* @Author: jeecg-boot
* @Date: 2026-04-28
* @Version: V1.0
*/
@Data
@TableName("bg_xi_speak_feedback")
@Schema(description="习总书记重要讲话反馈表")
public class BgXiSpeakFeedback implements Serializable {
private static final long serialVersionUID = 1L;
/**主键*/
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
private java.lang.String id;
/**创建人*/
@Schema(description = "创建人")
private java.lang.String createBy;
/**创建日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "创建日期")
private java.util.Date createTime;
/**更新人*/
@Schema(description = "更新人")
private java.lang.String updateBy;
/**更新日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "更新日期")
private java.util.Date updateTime;
/**所属部门*/
@Schema(description = "所属部门")
private java.lang.String sysOrgCode;
/**反馈部门id*/
@Excel(name = "反馈部门id", width = 15)
@Schema(description = "反馈部门id")
private java.lang.String responDeptid;
/**反馈部门名称*/
@Excel(name = "反馈部门名称", width = 15)
@Schema(description = "反馈部门名称")
private java.lang.String responDeptname;
/**反馈人id*/
@Excel(name = "反馈人id", width = 15)
@Schema(description = "反馈人id")
private java.lang.String responPersonid;
/**反馈人姓名*/
@Excel(name = "反馈人姓名", width = 15)
@Schema(description = "反馈人姓名")
private java.lang.String responPersonname;
/**反馈时间*/
@Excel(name = "反馈时间", width = 15, format = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "反馈时间")
private java.util.Date responTime;
/**落实情况*/
@Excel(name = "落实情况", width = 15)
@Schema(description = "落实情况")
private java.lang.String implStatus;
/**完成状态*/
@Excel(name = "完成状态", width = 15)
@Schema(description = "完成状态")
private java.lang.String completionStatus;
/**外键*/
@Excel(name = "外键", width = 15)
@Schema(description = "外键")
private java.lang.String mainId;
}
@@ -0,0 +1,16 @@
package org.jeecg.modules.bg.xispeak.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.jeecg.modules.bg.xispeak.entity.BgXiSpeakFeedback;
/**
* @Description: 习总书记重要讲话反馈表
* @Author: jeecg-boot
* @Date: 2026-04-28
* @Version: V1.0
*/
@Mapper
public interface BgXiSpeakFeedbackMapper extends BaseMapper<BgXiSpeakFeedback> {
}
@@ -0,0 +1,14 @@
package org.jeecg.modules.bg.xispeak.service;
import org.jeecg.modules.bg.xispeak.entity.BgXiSpeakFeedback;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @Description: 习总书记重要讲话反馈表
* @Author: jeecg-boot
* @Date: 2026-04-28
* @Version: V1.0
*/
public interface IBgXiSpeakFeedbackService extends IService<BgXiSpeakFeedback> {
}
@@ -0,0 +1,19 @@
package org.jeecg.modules.bg.xispeak.service.impl;
import org.jeecg.modules.bg.xispeak.entity.BgXiSpeakFeedback;
import org.jeecg.modules.bg.xispeak.mapper.BgXiSpeakFeedbackMapper;
import org.jeecg.modules.bg.xispeak.service.IBgXiSpeakFeedbackService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
/**
* @Description: 习总书记重要讲话反馈表
* @Author: jeecg-boot
* @Date: 2026-04-28
* @Version: V1.0
*/
@Service
public class BgXiSpeakFeedbackServiceImpl extends ServiceImpl<BgXiSpeakFeedbackMapper, BgXiSpeakFeedback> implements IBgXiSpeakFeedbackService {
}
@@ -7,7 +7,6 @@ import org.jeecg.modules.demo.bgpartymatter.entity.BgPartymatterFeedback;
import org.jeecg.modules.demo.bgpartymatter.mapper.BgPartymatterFeedbackMapper;
import org.jeecg.modules.demo.bgpartymatter.mapper.BgPartymatterMapper;
import org.jeecg.modules.demo.bgpartymatter.service.IBgPartymatterService;
import org.jeecg.modules.test.mapper.TestSonTableMapper;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
@@ -0,0 +1,546 @@
package org.jeecg.modules.demo.tasklist.controller;
import java.io.UnsupportedEncodingException;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.HashMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.jeecg.common.system.vo.LoginUser;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.query.QueryRuleEnum;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.demo.tasklist.entity.TaskListDetial;
import org.jeecg.modules.demo.tasklist.entity.TaskListPermission;
import org.jeecg.modules.demo.tasklist.entity.TaskListFavorite;
import org.jeecg.modules.demo.tasklist.entity.TaskList;
import org.jeecg.modules.demo.tasklist.vo.TaskListPage;
import org.jeecg.modules.demo.tasklist.vo.CreateTaskListReq;
import org.jeecg.modules.demo.tasklist.vo.CreateTaskListGroupReq;
import org.jeecg.modules.demo.tasklist.vo.MoveTaskListReq;
import org.jeecg.modules.demo.tasklist.vo.AddCollaboratorReq;
import org.jeecg.modules.demo.tasklist.vo.CollaboratorVO;
import org.jeecg.modules.demo.tasklist.service.ITaskListService;
import org.jeecg.modules.demo.tasklist.service.ITaskListDetialService;
import org.jeecg.modules.demo.tasklist.service.ITaskListPermissionService;
import org.jeecg.modules.demo.tasklist.service.ITaskListFavoriteService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import com.alibaba.fastjson.JSON;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.apache.shiro.authz.annotation.RequiresPermissions;
/**
* @Description: 任务清单表
* @Author: jeecg-boot
* @Date: 2026-04-24
* @Version: V1.0
*/
@Tag(name="任务清单表")
@RestController
@RequestMapping("/tasklist/taskList")
@Slf4j
public class TaskListController {
@Autowired
private ITaskListService taskListService;
@Autowired
private ITaskListDetialService taskListDetialService;
@Autowired
private ITaskListPermissionService taskListPermissionService;
@Autowired
private ITaskListFavoriteService taskListFavoriteService;
/**
* 分页列表查询
*
* @param taskList
* @param pageNo
* @param pageSize
* @param req
* @return
*/
//@AutoLog(value = "任务清单表-分页列表查询")
@Operation(summary="任务清单表-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<TaskList>> queryPageList(TaskList taskList,
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<TaskList> queryWrapper = QueryGenerator.initQueryWrapper(taskList, req.getParameterMap());
Page<TaskList> page = new Page<TaskList>(pageNo, pageSize);
IPage<TaskList> pageList = taskListService.page(page, queryWrapper);
return Result.OK(pageList);
}
/**
* 添加
*
* @param taskListPage
* @return
*/
@AutoLog(value = "任务清单表-添加")
@Operation(summary="任务清单表-添加")
@RequiresPermissions("tasklist:task_list:add")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody TaskListPage taskListPage) {
TaskList taskList = new TaskList();
BeanUtils.copyProperties(taskListPage, taskList);
taskListService.saveMain(taskList, taskListPage.getTaskListDetialList(),taskListPage.getTaskListPermissionList(),taskListPage.getTaskListFavoriteList());
return Result.OK("添加成功!");
}
/**
* 编辑
*
* @param taskListPage
* @return
*/
@AutoLog(value = "任务清单表-编辑")
@Operation(summary="任务清单表-编辑")
@RequiresPermissions("tasklist:task_list:edit")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<String> edit(@RequestBody TaskListPage taskListPage) {
TaskList taskList = new TaskList();
BeanUtils.copyProperties(taskListPage, taskList);
TaskList taskListEntity = taskListService.getById(taskList.getId());
if(taskListEntity==null) {
return Result.error("未找到对应数据");
}
taskListService.updateMain(taskList, taskListPage.getTaskListDetialList(),taskListPage.getTaskListPermissionList(),taskListPage.getTaskListFavoriteList());
return Result.OK("编辑成功!");
}
/**
* 通过id删除
*
* @param id
* @return
*/
@AutoLog(value = "任务清单表-通过id删除")
@Operation(summary="任务清单表-通过id删除")
@RequiresPermissions("tasklist:task_list:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
taskListService.delMain(id);
return Result.OK("删除成功!");
}
/**
* 批量删除
*
* @param ids
* @return
*/
@AutoLog(value = "任务清单表-批量删除")
@Operation(summary="任务清单表-批量删除")
@RequiresPermissions("tasklist:task_list:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
this.taskListService.delBatchMain(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}
/**
* 通过id查询
*
* @param id
* @return
*/
//@AutoLog(value = "任务清单表-通过id查询")
@Operation(summary="任务清单表-通过id查询")
@GetMapping(value = "/queryById")
public Result<TaskList> queryById(@RequestParam(name="id",required=true) String id) {
TaskList taskList = taskListService.getById(id);
if(taskList==null) {
return Result.error("未找到对应数据");
}
return Result.OK(taskList);
}
@AutoLog(value = "任务清单表-新建任务清单")
@Operation(summary = "新建任务清单")
@PostMapping(value = "/addTaskList")
public Result<String> addTaskList(@RequestBody CreateTaskListReq req) {
try {
String id = taskListService.createTaskList(req);
return Result.OK("创建成功!", id);
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
@AutoLog(value = "任务清单表-新建任务清单分组")
@Operation(summary = "新建任务清单分组")
@PostMapping(value = "/addTaskListGroup")
public Result<String> addTaskListGroup(@RequestBody CreateTaskListGroupReq req) {
try {
String id = taskListService.createTaskListGroup(req);
return Result.OK("创建成功!", id);
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
@AutoLog(value = "任务清单表-拖拽移动任务清单")
@Operation(summary = "拖拽移动任务清单")
@PostMapping(value = "/moveTaskList")
public Result<String> moveTaskList(@RequestBody MoveTaskListReq req) {
try {
taskListService.moveTaskList(req);
return Result.OK("移动成功!");
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
@AutoLog(value = "任务清单表-拖拽移动分组")
@Operation(summary = "拖拽移动分组")
@PostMapping(value = "/moveGroup")
public Result<String> moveGroup(@RequestBody Map<String, Object> params) {
try {
String groupId = (String) params.get("groupId");
Integer sortOrder = params.get("sortOrder") != null ? ((Number) params.get("sortOrder")).intValue() : null;
taskListService.moveGroup(groupId, sortOrder);
return Result.OK("移动成功!");
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
@AutoLog(value = "任务清单表-获取当前用户收藏列表")
@Operation(summary = "获取当前用户收藏列表")
@GetMapping(value = "/myFavorites")
public Result<List<TaskListFavorite>> myFavorites() {
List<TaskListFavorite> list = taskListService.getMyFavorites();
return Result.OK(list);
}
@AutoLog(value = "任务清单表-删除任务清单")
@Operation(summary = "删除任务清单(所有者操作)")
@PostMapping(value = "/deleteTaskList")
public Result<String> deleteTaskList(@RequestBody Map<String, String> params) {
try {
taskListService.deleteTaskList(params.get("id"));
return Result.OK("删除成功!");
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
@AutoLog(value = "任务清单表-移除收藏")
@Operation(summary = "从收藏栏移除")
@PostMapping(value = "/removeFavorite")
public Result<String> removeFavorite(@RequestBody Map<String, String> params) {
try {
taskListService.removeFavorite(params.get("favoriteId"));
return Result.OK("移除成功!");
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
@AutoLog(value = "任务清单表-添加到收藏")
@Operation(summary = "添加清单到收藏栏")
@PostMapping(value = "/addToFavorites")
public Result<String> addToFavorites(@RequestBody Map<String, String> params) {
try {
taskListService.addToFavorites(params.get("taskListId"), params.get("pid"));
return Result.OK("添加成功!");
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
@AutoLog(value = "任务清单表-移除分组")
@Operation(summary = "从收藏栏移除分组及子项")
@PostMapping(value = "/removeFavoriteGroup")
public Result<String> removeFavoriteGroup(@RequestBody Map<String, String> params) {
try {
taskListService.removeFavoriteGroup(params.get("groupId"));
return Result.OK("移除成功!");
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
@AutoLog(value = "任务清单表-重命名分组")
@Operation(summary = "重命名任务清单分组")
@PostMapping(value = "/renameGroup")
public Result<String> renameGroup(@RequestBody Map<String, String> params) {
try {
taskListService.renameGroup(params.get("groupId"), params.get("newName"));
return Result.OK("重命名成功!");
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
@AutoLog(value = "任务清单表-重命名清单")
@Operation(summary = "重命名任务清单")
@PostMapping(value = "/renameTaskList")
public Result<String> renameTaskList(@RequestBody Map<String, String> params) {
try {
taskListService.renameTaskList(params.get("taskListId"), params.get("newName"));
return Result.OK("重命名成功!");
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
@AutoLog(value = "任务清单表-获取我所有的清单")
@Operation(summary = "获取我所有的清单")
@GetMapping(value = "/myOwnLists")
public Result<List<TaskList>> myOwnLists() {
List<TaskList> list = taskListService.getMyOwnLists();
return Result.OK(list);
}
@AutoLog(value = "任务清单表-获取所有清单")
@Operation(summary = "获取所有清单")
@GetMapping(value = "/allLists")
public Result<List<TaskList>> getAllLists() {
return Result.OK(taskListService.getAllLists());
}
@AutoLog(value = "任务清单表-获取我协作的清单")
@Operation(summary = "获取我协作的清单")
@GetMapping(value = "/myCollabLists")
public Result<List<TaskList>> myCollabLists() {
List<TaskList> list = taskListService.getMyCollabLists();
return Result.OK(list);
}
@AutoLog(value = "任务清单表-获取协作人列表")
@Operation(summary = "获取清单协作人列表")
@GetMapping(value = "/getCollaborators")
public Result<List<CollaboratorVO>> getCollaborators(@RequestParam(name="taskListId", required=true) String taskListId) {
List<CollaboratorVO> list = taskListService.getCollaborators(taskListId);
return Result.OK(list);
}
@AutoLog(value = "任务清单表-添加协作人")
@Operation(summary = "添加协作人")
@PostMapping(value = "/addCollaborator")
public Result<String> addCollaborator(@RequestBody AddCollaboratorReq req) {
try {
taskListService.addCollaborator(req);
return Result.OK("添加成功!");
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
@AutoLog(value = "任务清单表-移除协作人")
@Operation(summary = "移除协作人")
@PostMapping(value = "/removeCollaborator")
public Result<String> removeCollaborator(@RequestBody Map<String, String> params) {
try {
taskListService.removeCollaborator(params.get("permissionId"));
return Result.OK("移除成功!");
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
@AutoLog(value = "任务清单表-修改协作人权限")
@Operation(summary = "修改协作人权限")
@PostMapping(value = "/updateCollaboratorPermission")
public Result<String> updateCollaboratorPermission(@RequestBody Map<String, String> params) {
try {
taskListService.updateCollaboratorPermission(params.get("permissionId"), params.get("permission"));
return Result.OK("修改成功!");
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
@AutoLog(value = "任务清单表-获取当前用户对清单的权限")
@Operation(summary = "获取当前用户对清单的权限")
@GetMapping(value = "/getMyPermission")
public Result<String> getMyPermission(@RequestParam(name="taskListId", required=true) String taskListId) {
String permission = taskListService.getMyPermission(taskListId);
return Result.OK("查询成功", permission);
}
/**
* 通过id查询
*
* @param id
* @return
*/
//@AutoLog(value = "任务清单详情表通过主表ID查询")
@Operation(summary="任务清单详情表主表ID查询")
@GetMapping(value = "/queryTaskListDetialByMainId")
public Result<List<TaskListDetial>> queryTaskListDetialListByMainId(@RequestParam(name="id",required=true) String id) {
List<TaskListDetial> taskListDetialList = taskListDetialService.selectByMainId(id);
return Result.OK(taskListDetialList);
}
/**
* 通过id查询
*
* @param id
* @return
*/
//@AutoLog(value = "任务清单权限表通过主表ID查询")
@Operation(summary="任务清单权限表主表ID查询")
@GetMapping(value = "/queryTaskListPermissionByMainId")
public Result<List<TaskListPermission>> queryTaskListPermissionListByMainId(@RequestParam(name="id",required=true) String id) {
List<TaskListPermission> taskListPermissionList = taskListPermissionService.selectByMainId(id);
return Result.OK(taskListPermissionList);
}
/**
* 通过id查询
*
* @param id
* @return
*/
//@AutoLog(value = "任务清单收藏表通过主表ID查询")
@Operation(summary="任务清单收藏表主表ID查询")
@GetMapping(value = "/queryTaskListFavoriteByMainId")
public Result<List<TaskListFavorite>> queryTaskListFavoriteListByMainId(@RequestParam(name="id",required=true) String id) {
List<TaskListFavorite> taskListFavoriteList = taskListFavoriteService.selectByMainId(id);
return Result.OK(taskListFavoriteList);
}
/**
* 导出excel
*
* @param request
* @param taskList
*/
@RequiresPermissions("tasklist:task_list:exportXls")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, TaskList taskList) {
// Step.1 组装查询条件查询数据
QueryWrapper<TaskList> queryWrapper = QueryGenerator.initQueryWrapper(taskList, request.getParameterMap());
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
//配置选中数据查询条件
String selections = request.getParameter("selections");
if(oConvertUtils.isNotEmpty(selections)) {
List<String> selectionList = Arrays.asList(selections.split(","));
queryWrapper.in("id",selectionList);
}
//Step.2 获取导出数据
List<TaskList> taskListList = taskListService.list(queryWrapper);
// Step.3 组装pageList
List<TaskListPage> pageList = new ArrayList<TaskListPage>();
for (TaskList main : taskListList) {
TaskListPage vo = new TaskListPage();
BeanUtils.copyProperties(main, vo);
List<TaskListDetial> taskListDetialList = taskListDetialService.selectByMainId(main.getId());
vo.setTaskListDetialList(taskListDetialList);
List<TaskListPermission> taskListPermissionList = taskListPermissionService.selectByMainId(main.getId());
vo.setTaskListPermissionList(taskListPermissionList);
List<TaskListFavorite> taskListFavoriteList = taskListFavoriteService.selectByMainId(main.getId());
vo.setTaskListFavoriteList(taskListFavoriteList);
pageList.add(vo);
}
// Step.4 AutoPoi 导出Excel
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
mv.addObject(NormalExcelConstants.FILE_NAME, "任务清单表列表");
mv.addObject(NormalExcelConstants.CLASS, TaskListPage.class);
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("任务清单表数据", "导出人:"+sysUser.getRealname(), "任务清单表"));
mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
return mv;
}
/**
* 通过excel导入数据
*
* @param request
* @param response
* @return
*/
@RequiresPermissions("tasklist:task_list:importExcel")
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
// 获取上传文件对象
MultipartFile file = entity.getValue();
ImportParams params = new ImportParams();
params.setTitleRows(2);
params.setHeadRows(1);
params.setNeedSave(true);
try {
List<TaskListPage> list = ExcelImportUtil.importExcel(file.getInputStream(), TaskListPage.class, params);
for (TaskListPage page : list) {
TaskList po = new TaskList();
BeanUtils.copyProperties(page, po);
taskListService.saveMain(po, page.getTaskListDetialList(),page.getTaskListPermissionList(),page.getTaskListFavoriteList());
}
return Result.OK("文件导入成功!数据行数:" + list.size());
} catch (Exception e) {
log.error(e.getMessage(),e);
return Result.error("文件导入失败:"+e.getMessage());
} finally {
try {
file.getInputStream().close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return Result.OK("文件导入失败!");
}
@AutoLog(value = "任务清单表-我负责的任务")
@Operation(summary = "获取当前用户负责的任务")
@GetMapping(value = "/myResponsibleTasks")
public Result<List<TaskListDetial>> myResponsibleTasks() {
List<TaskListDetial> list = taskListService.myResponsibleTasks();
return Result.OK(list);
}
@AutoLog(value = "任务清单表-我关注的任务")
@Operation(summary = "获取当前用户关注的任务")
@GetMapping(value = "/myFollowedTasks")
public Result<List<TaskListDetial>> myFollowedTasks() {
List<TaskListDetial> list = taskListService.myFollowedTasks();
return Result.OK(list);
}
@AutoLog(value = "任务清单表-获取当前用户密级")
@Operation(summary = "获取当前用户密级")
@GetMapping(value = "/getCurrentUserSecurityLevel")
public Result<Integer> getCurrentUserSecurityLevel() {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
Integer level = loginUser.getUserSecurityLevel();
if (level == null) {
level = 3;
}
return Result.OK("查询成功", level);
}
}
@@ -0,0 +1,135 @@
package org.jeecg.modules.demo.tasklist.controller;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.demo.tasklist.entity.TaskListDetial;
import org.jeecg.modules.demo.tasklist.service.ITaskListDetialService;
import org.jeecg.modules.demo.tasklist.vo.CreateTaskReq;
import org.jeecg.modules.demo.tasklist.vo.MoveTaskReq;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import java.util.Map;
@Slf4j
@RestController
@RequestMapping("/tasklist/taskListDetial")
public class TaskListDetialController {
@Autowired
private ITaskListDetialService taskListDetialService;
@PostMapping(value = "/add")
public Result<TaskListDetial> add(@RequestBody CreateTaskReq req) {
try {
TaskListDetial result = taskListDetialService.createTask(req);
return Result.OK(result);
} catch (RuntimeException e) {
log.error(e.getMessage(), e);
return Result.error(e.getMessage());
}
}
@PostMapping(value = "/edit")
public Result<?> edit(@RequestBody TaskListDetial task) {
try {
taskListDetialService.editTask(task);
return Result.OK("编辑成功");
} catch (RuntimeException e) {
log.error(e.getMessage(), e);
return Result.error(e.getMessage());
}
}
@DeleteMapping(value = "/delete")
public Result<?> delete(@RequestParam(name = "id") String id) {
try {
taskListDetialService.deleteTask(id);
return Result.OK("删除成功");
} catch (RuntimeException e) {
log.error(e.getMessage(), e);
return Result.error(e.getMessage());
}
}
@GetMapping(value = "/listByMainId")
public Result<List<TaskListDetial>> listByMainId(@RequestParam(name = "mainId") String mainId) {
List<TaskListDetial> list = taskListDetialService.queryTopLevelByMainId(mainId);
return Result.OK(list);
}
@GetMapping(value = "/listAllByMainId")
public Result<List<TaskListDetial>> listAllByMainId(@RequestParam(name = "mainId") String mainId) {
List<TaskListDetial> list = taskListDetialService.queryAllByMainId(mainId);
return Result.OK(list);
}
@PostMapping(value = "/toggleStatus")
public Result<?> toggleStatus(@RequestBody Map<String, String> body) {
try {
String id = body.get("id");
taskListDetialService.toggleStatus(id);
return Result.OK("操作成功");
} catch (RuntimeException e) {
log.error(e.getMessage(), e);
return Result.error(e.getMessage());
}
}
@PostMapping(value = "/moveTask")
public Result<?> moveTask(@RequestBody MoveTaskReq req) {
try {
taskListDetialService.moveTask(req);
return Result.OK("移动成功");
} catch (RuntimeException e) {
log.error(e.getMessage(), e);
return Result.error(e.getMessage());
}
}
@PostMapping(value = "/moveTaskGroup")
public Result<?> moveTaskGroup(@RequestBody Map<String, Object> params) {
try {
String taskGroupId = (String) params.get("taskGroupId");
Integer targetSortOrder = params.get("targetSortOrder") != null ? ((Number) params.get("targetSortOrder")).intValue() : null;
taskListDetialService.moveTaskGroup(taskGroupId, targetSortOrder);
return Result.OK("移动成功");
} catch (RuntimeException e) {
log.error(e.getMessage(), e);
return Result.error(e.getMessage());
}
}
@PostMapping(value = "/follow")
public Result<?> follow(@RequestBody Map<String, String> body) {
try {
String id = body.get("id");
taskListDetialService.followTask(id);
return Result.OK("关注成功");
} catch (RuntimeException e) {
log.error(e.getMessage(), e);
return Result.error(e.getMessage());
}
}
@PostMapping(value = "/unfollow")
public Result<?> unfollow(@RequestBody Map<String, String> body) {
try {
String id = body.get("id");
taskListDetialService.unfollowTask(id);
return Result.OK("取消关注成功");
} catch (RuntimeException e) {
log.error(e.getMessage(), e);
return Result.error(e.getMessage());
}
}
@GetMapping(value = "/loadSubTasks")
public Result<List<TaskListDetial>> loadSubTasks(
@RequestParam(name = "parentTaskId") String parentTaskId,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "20") Integer pageSize) {
List<TaskListDetial> list = taskListDetialService.loadSubTasks(parentTaskId, pageNo, pageSize);
return Result.OK(list);
}
}
@@ -0,0 +1,87 @@
package org.jeecg.modules.demo.tasklist.entity;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableField;
import org.jeecg.common.constant.ProvinceCityArea;
import org.jeecg.common.util.SpringContextUtils;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.jeecg.common.aspect.annotation.Dict;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* @Description: 任务清单表
* @Author: jeecg-boot
* @Date: 2026-04-24
* @Version: V1.0
*/
@Schema(description="任务清单表")
@Data
@TableName("task_list")
public class TaskList implements Serializable {
private static final long serialVersionUID = 1L;
/**主键*/
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
private java.lang.String id;
/**创建人*/
@Schema(description = "创建人")
private java.lang.String createBy;
/**创建日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "创建日期")
private java.util.Date createTime;
/**更新人*/
@Schema(description = "更新人")
private java.lang.String updateBy;
/**更新日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "更新日期")
private java.util.Date updateTime;
/**所属部门*/
@Schema(description = "所属部门")
private java.lang.String sysOrgCode;
/**清单名称*/
@Excel(name = "清单名称", width = 15)
@Schema(description = "清单名称")
private java.lang.String tasklistName;
/**删除标识*/
@Excel(name = "删除标识", width = 15)
@Schema(description = "删除标识")
@TableLogic
private java.lang.String delFlag;
@TableField(exist = false)
@Schema(description = "所有者名称")
private java.lang.String ownerName;
@TableField(exist = false)
@Schema(description = "协作者名称")
private java.lang.String collaboratorNames;
/**密级: 1=非密, 2=内部, 3=秘密, 4=机密*/
@Excel(name = "密级", width = 15)
@Schema(description = "密级:1=非密,2=内部,3=秘密,4=机密")
private java.lang.Integer secretLevel;
/**密级文本*/
@Excel(name = "密级文本", width = 15)
@Schema(description = "密级文本")
private java.lang.String secretText;
@TableField(exist = false)
@Schema(description = "创建时间字符串")
private java.lang.String createTimeStr;
}
@@ -0,0 +1,172 @@
package org.jeecg.modules.demo.tasklist.entity;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableField;
import org.jeecg.common.constant.ProvinceCityArea;
import org.jeecg.common.util.SpringContextUtils;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import org.jeecgframework.poi.excel.annotation.Excel;
import java.util.Date;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.UnsupportedEncodingException;
/**
* @Description: 任务清单详情表
* @Author: jeecg-boot
* @Date: 2026-04-24
* @Version: V1.0
*/
@Schema(description="任务清单详情表")
@Data
@TableName("task_list_detial")
public class TaskListDetial implements Serializable {
private static final long serialVersionUID = 1L;
/**主键*/
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
private java.lang.String id;
/**创建人*/
@Schema(description = "创建人")
private java.lang.String createBy;
@TableField(exist = false)
@Schema(description = "创建人名称")
private java.lang.String createByName;
/**创建日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "创建日期")
private java.util.Date createTime;
/**更新人*/
@Schema(description = "更新人")
private java.lang.String updateBy;
/**更新日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "更新日期")
private java.util.Date updateTime;
/**所属部门*/
@Schema(description = "所属部门")
private java.lang.String sysOrgCode;
/**主表ID*/
@Schema(description = "主表ID")
private java.lang.String mainId;
/**父节点ID*/
@Excel(name = "父节点ID", width = 15)
@Schema(description = "父节点ID")
private java.lang.String pid;
/**是否有子节点*/
@Excel(name = "是否有子节点", width = 15)
@Schema(description = "是否有子节点")
private java.lang.String hasChild;
/**排序号*/
@Excel(name = "排序号", width = 15)
@Schema(description = "排序号")
private java.lang.Integer sortOrder;
/**任务名称*/
@Excel(name = "任务名称", width = 15)
@Schema(description = "任务名称")
private java.lang.String taskName;
/**任务描述*/
@Excel(name = "任务描述", width = 15)
@Schema(description = "任务描述")
private java.lang.String taskDesc;
/**优先级*/
@Excel(name = "优先级", width = 15, dicCode = "task_priority")
@Schema(description = "优先级")
private java.lang.String priority;
/**完成状态*/
@Excel(name = "完成状态", width = 15)
@Schema(description = "完成状态")
private java.lang.Integer taskStatus;
/**负责人ID*/
@Excel(name = "负责人ID", width = 15)
@Schema(description = "负责人ID")
private java.lang.String assigneeId;
/**负责人*/
@Excel(name = "负责人", width = 15)
@Schema(description = "负责人")
private java.lang.String assigneeName;
/**关注人ID*/
@Excel(name = "关注人ID", width = 15)
@Schema(description = "关注人ID")
private java.lang.String followersId;
/**关注人*/
@Excel(name = "关注人", width = 15)
@Schema(description = "关注人")
private java.lang.String followersName;
/**分配人ID*/
@Excel(name = "分配人ID", width = 15)
@Schema(description = "分配人ID")
private java.lang.String assignId;
/**分配人*/
@Excel(name = "分配人", width = 15)
@Schema(description = "分配人")
private java.lang.String assignName;
/**开始时间*/
@Excel(name = "开始时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "开始时间")
private java.util.Date startTime;
/**结束时间*/
@Excel(name = "结束时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "结束时间")
private java.util.Date endTime;
/**完成时间*/
@Excel(name = "完成时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "完成时间")
private java.util.Date completeTime;
/**类型*/
@Excel(name = "类型", width = 15)
@Schema(description = "类型")
private java.lang.String type;
/**子任务数*/
@Excel(name = "子任务数", width = 15)
@Schema(description = "子任务数")
private java.lang.Integer subTaskCount;
/**子任务完成数*/
@Excel(name = "子任务完成数", width = 15)
@Schema(description = "子任务完成数")
private java.lang.Integer completedSubTaskCount;
/**参与人ID*/
@Excel(name = "参与人ID", width = 15)
@Schema(description = "参与人ID")
private java.lang.String participantId;
/**参与人*/
@Excel(name = "参与人", width = 15)
@Schema(description = "参与人")
private java.lang.String participantName;
/**其他事项说明*/
@Excel(name = "其他事项说明", width = 15)
@Schema(description = "其他事项说明")
private java.lang.String remark;
/**是否默认分组*/
@Excel(name = "是否默认分组", width = 15, dicCode = "is_default")
@Schema(description = "是否默认分组(1=是,0=否)")
private java.lang.Integer isDefault;
/**来源清单名称*/
@TableField(exist = false)
@Schema(description = "来源清单名称")
private java.lang.String listName;
/**当前用户对清单的权限*/
@TableField(exist = false)
@Schema(description = "当前用户对该清单的权限(1=所有者,2=可编辑,3=只读)")
private java.lang.String myPermission;
/**删除标识*/
@Excel(name = "删除标识", width = 15)
@Schema(description = "删除标识")
@TableLogic
private java.lang.String delFlag;
}
@@ -0,0 +1,98 @@
package org.jeecg.modules.demo.tasklist.entity;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableField;
import org.jeecg.common.constant.ProvinceCityArea;
import org.jeecg.common.util.SpringContextUtils;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import org.jeecgframework.poi.excel.annotation.Excel;
import java.util.Date;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.UnsupportedEncodingException;
/**
* @Description: 任务清单收藏表
* @Author: jeecg-boot
* @Date: 2026-04-24
* @Version: V1.0
*/
@Schema(description="任务清单收藏表")
@Data
@TableName("task_list_favorite")
public class TaskListFavorite implements Serializable {
private static final long serialVersionUID = 1L;
/**主键*/
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
private java.lang.String id;
/**创建人*/
@Schema(description = "创建人")
private java.lang.String createBy;
/**创建日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "创建日期")
private java.util.Date createTime;
/**更新人*/
@Schema(description = "更新人")
private java.lang.String updateBy;
/**更新日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "更新日期")
private java.util.Date updateTime;
/**所属部门*/
@Schema(description = "所属部门")
private java.lang.String sysOrgCode;
/**主表ID*/
@Schema(description = "主表ID")
private java.lang.String mainId;
/**任务清单(分组)名称*/
@Excel(name = "任务清单(分组)名称", width = 15)
@Schema(description = "任务清单(分组)名称")
private java.lang.String tasklistName;
/**用户ID*/
@Excel(name = "用户ID", width = 15)
@Schema(description = "用户ID")
private java.lang.String userId;
/**类型(0是分组,1是清单)*/
@Excel(name = "类型(0是分组,1是清单)", width = 15)
@Schema(description = "类型(0是分组,1是清单)")
private java.lang.String type;
/**父节点ID*/
@Excel(name = "父节点ID", width = 15)
@Schema(description = "父节点ID")
private java.lang.String pid;
/**是否有子节点*/
@Excel(name = "是否有子节点", width = 15)
@Schema(description = "是否有子节点")
private java.lang.String hasChild;
/**排序*/
@Excel(name = "排序", width = 15)
@Schema(description = "排序")
private java.lang.Integer sortOrder;
/**删除标识*/
@Excel(name = "删除标识", width = 15)
@Schema(description = "删除标识")
@TableLogic
private java.lang.String delFlag;
@TableField(exist = false)
@Schema(description = "清单密级")
private java.lang.Integer secretLevel;
@TableField(exist = false)
@Schema(description = "清单密级文本")
private java.lang.String secretText;
@TableField(exist = false)
@Schema(description = "当前用户对该清单的权限")
private java.lang.String permission;
}
@@ -1,8 +1,6 @@
package org.jeecg.modules.test.entity;
package org.jeecg.modules.demo.tasklist.entity;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@@ -14,52 +12,60 @@ import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.jeecg.common.aspect.annotation.Dict;
import java.util.Date;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.UnsupportedEncodingException;
/**
* @Description: test
* @Description: 任务清单权限表
* @Author: jeecg-boot
* @Date: 2026-04-03
* @Date: 2026-04-24
* @Version: V1.0
*/
@Schema(description="test")
@Schema(description="任务清单权限表")
@Data
@TableName("test_main_table")
public class TestMainTable implements Serializable {
@TableName("task_list_permission")
public class TaskListPermission implements Serializable {
private static final long serialVersionUID = 1L;
/**主键*/
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
private String id;
private java.lang.String id;
/**创建人*/
@Schema(description = "创建人")
private String createBy;
private java.lang.String createBy;
/**创建日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "创建日期")
private Date createTime;
private java.util.Date createTime;
/**更新人*/
@Schema(description = "更新人")
private String updateBy;
private java.lang.String updateBy;
/**更新日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "更新日期")
private Date updateTime;
private java.util.Date updateTime;
/**所属部门*/
@Schema(description = "所属部门")
private String sysOrgCode;
/**a字段*/
@Excel(name = "a字段", width = 15)
@Schema(description = "a字段")
private String fieldA;
/**b字段*/
@Excel(name = "b字段", width = 15)
@Schema(description = "b字段")
private String fieldB;
@TableLogic(value = "0", delval = "1")
private int delFlag = 0;
private java.lang.String sysOrgCode;
/**主表ID*/
@Schema(description = "主表ID")
private java.lang.String mainId;
/**用户ID*/
@Excel(name = "用户ID", width = 15)
@Schema(description = "用户ID")
private java.lang.String userId;
/**权限类型*/
@Excel(name = "权限类型", width = 15, dicCode = "collaboration_permission")
@Dict(dicCode = "collaboration_permission")
@Schema(description = "权限类型")
private java.lang.String permission;
/**删除标识*/
@Excel(name = "删除标识", width = 15)
@Schema(description = "删除标识")
@TableLogic
private java.lang.String delFlag;
}
@@ -0,0 +1,63 @@
package org.jeecg.modules.demo.tasklist.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.jeecg.modules.demo.tasklist.entity.TaskListDetial;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface TaskListDetialMapper extends BaseMapper<TaskListDetial> {
boolean deleteByMainId(@Param("mainId") String mainId);
List<TaskListDetial> selectByMainId(@Param("mainId") String mainId);
void shiftSortOrderUp(@Param("mainId") String mainId, @Param("pid") String pid, @Param("fromSort") Integer fromSort);
void shiftSortOrderDown(@Param("mainId") String mainId, @Param("pid") String pid, @Param("fromSort") Integer fromSort);
Integer getMaxSortOrder(@Param("mainId") String mainId, @Param("pid") String pid);
int appendFollower(@Param("taskId") String taskId, @Param("userId") String userId, @Param("userName") String userName);
int removeFollower(@Param("taskId") String taskId, @Param("userId") String userId, @Param("userName") String userName);
int toggleTaskStatus(@Param("taskId") String taskId, @Param("updateBy") String updateBy, @Param("newStatus") Integer newStatus, @Param("completeTime") java.util.Date completeTime);
List<TaskListDetial> selectAllByMainId(@Param("mainId") String mainId);
List<TaskListDetial> selectTopLevelByMainId(@Param("mainId") String mainId);
List<TaskListDetial> selectSubTasksByPage(@Param("parentId") String parentId, @Param("offset") Integer offset, @Param("pageSize") Integer pageSize);
void updatePidAndSort(@Param("id") String id, @Param("pid") String pid, @Param("sortOrder") Integer sortOrder);
List<TaskListDetial> selectChildrenByPid(@Param("pid") String pid);
void resetPidToNull(@Param("pid") String pid, @Param("mainId") String mainId);
void incrementSubTaskCount(@Param("parentId") String parentId);
void decrementSubTaskCount(@Param("parentId") String parentId);
void incrementCompletedSubTaskCount(@Param("parentId") String parentId);
void decrementCompletedSubTaskCount(@Param("parentId") String parentId);
void updateHasChild(@Param("parentId") String parentId, @Param("hasChild") String hasChild);
void shiftSortOrderUpForGroup(@Param("mainId") String mainId, @Param("fromSort") Integer fromSort);
void shiftSortOrderDownForGroup(@Param("mainId") String mainId, @Param("fromSort") Integer fromSort);
Integer getMaxSortOrderForGroup(@Param("mainId") String mainId);
void updateSortOrder(@Param("id") String id, @Param("sortOrder") Integer sortOrder);
Integer countChildrenByPid(@Param("pid") String pid);
List<TaskListDetial> selectByAssigneeId(@Param("assigneeId") String assigneeId, @Param("userId") String userId);
List<TaskListDetial> selectByFollowersId(@Param("followersId") String followersId, @Param("userId") String userId);
void appendAssigner(@Param("taskId") String taskId, @Param("userId") String userId, @Param("userName") String userName);
}
@@ -0,0 +1,49 @@
package org.jeecg.modules.demo.tasklist.mapper;
import java.util.List;
import org.jeecg.modules.demo.tasklist.entity.TaskListFavorite;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
/**
* @Description: 任务清单收藏表
* @Author: jeecg-boot
* @Date: 2026-04-24
* @Version: V1.0
*/
public interface TaskListFavoriteMapper extends BaseMapper<TaskListFavorite> {
/**
* 通过主表id删除子表数据
*
* @param mainId 主表id
* @return boolean
*/
public boolean deleteByMainId(@Param("mainId") String mainId);
/**
* 通过主表id查询子表数据
*
* @param mainId 主表id
* @return List<TaskListFavorite>
*/
public List<TaskListFavorite> selectByMainId(@Param("mainId") String mainId);
Integer selectMaxSortOrder(@Param("userId") String userId, @Param("pid") String pid);
Integer selectMaxSortOrderByType(@Param("userId") String userId, @Param("pid") String pid, @Param("type") String type);
void shiftSortOrderUp(@Param("userId") String userId, @Param("pid") String pid, @Param("fromSort") Integer fromSort);
void shiftSortOrderDown(@Param("userId") String userId, @Param("pid") String pid, @Param("fromSort") Integer fromSort);
void shiftSortOrderUpByType(@Param("userId") String userId, @Param("type") String type, @Param("fromSort") Integer fromSort);
void shiftSortOrderDownByType(@Param("userId") String userId, @Param("type") String type, @Param("fromSort") Integer fromSort);
Integer countChildrenByPid(@Param("userId") String userId, @Param("pid") String pid);
void updatePidAndSort(@Param("id") String id, @Param("pid") String pid, @Param("sortOrder") Integer sortOrder);
void updateSortOrder(@Param("id") String id, @Param("sortOrder") Integer sortOrder);
}
@@ -0,0 +1,28 @@
package org.jeecg.modules.demo.tasklist.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.jeecg.modules.demo.tasklist.entity.TaskList;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @Description: 任务清单表
* @Author: jeecg-boot
* @Date: 2026-04-24
* @Version: V1.0
*/
public interface TaskListMapper extends BaseMapper<TaskList> {
/**
* 查询当前用户可见的所有清单(包含部门、所有者、协作者、任务负责人/参与人维度)
* @param userId 当前用户ID
* @param userSecLevel 当前用户密级
* @param orgCode 当前用户部门编码
* @return 可见清单列表
*/
List<TaskList> selectVisibleLists(@Param("userId") String userId,
@Param("userSecLevel") Integer userSecLevel,
@Param("orgCode") String orgCode);
}
@@ -1,17 +1,17 @@
package org.jeecg.modules.test.mapper;
package org.jeecg.modules.demo.tasklist.mapper;
import java.util.List;
import org.jeecg.modules.test.entity.TestSonTable;
import org.jeecg.modules.demo.tasklist.entity.TaskListPermission;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
/**
* @Description: test
* @Description: 任务清单权限表
* @Author: jeecg-boot
* @Date: 2026-04-03
* @Date: 2026-04-24
* @Version: V1.0
*/
public interface TestSonTableMapper extends BaseMapper<TestSonTable> {
public interface TaskListPermissionMapper extends BaseMapper<TaskListPermission> {
/**
* 通过主表id删除子表数据
@@ -25,7 +25,7 @@ public interface TestSonTableMapper extends BaseMapper<TestSonTable> {
* 通过主表id查询子表数据
*
* @param mainId 主表id
* @return List<TestSonTable>
* @return List<TaskListPermission>
*/
public List<TestSonTable> selectByMainId(@Param("mainId") String mainId);
public List<TaskListPermission> selectByMainId(@Param("mainId") String mainId);
}
@@ -0,0 +1,192 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.jeecg.modules.demo.tasklist.mapper.TaskListDetialMapper">
<delete id="deleteByMainId" parameterType="java.lang.String">
DELETE FROM task_list_detial WHERE main_id = #{mainId}
</delete>
<select id="selectByMainId" parameterType="java.lang.String" resultType="org.jeecg.modules.demo.tasklist.entity.TaskListDetial">
SELECT * FROM task_list_detial WHERE main_id = #{mainId}
</select>
<update id="shiftSortOrderUp">
UPDATE task_list_detial
SET sort_order = sort_order + 1
WHERE main_id = #{mainId} AND del_flag = '0'
AND (pid = #{pid} OR (#{pid} IS NULL AND pid IS NULL))
AND sort_order >= #{fromSort}
</update>
<update id="shiftSortOrderDown">
UPDATE task_list_detial
SET sort_order = sort_order - 1
WHERE main_id = #{mainId} AND del_flag = '0'
AND (pid = #{pid} OR (#{pid} IS NULL AND pid IS NULL))
AND sort_order > #{fromSort}
</update>
<select id="getMaxSortOrder" resultType="java.lang.Integer">
SELECT IFNULL(MAX(sort_order), 0)
FROM task_list_detial
WHERE main_id = #{mainId} AND del_flag = '0'
AND (pid = #{pid} OR (#{pid} IS NULL AND pid IS NULL))
</select>
<update id="appendFollower">
UPDATE task_list_detial
SET followers_id = CONCAT(IFNULL(followers_id, ''), ',', #{userId}),
followers_name = CONCAT(IFNULL(followers_name, ''), ',', #{userName})
WHERE id = #{taskId} AND del_flag = '0'
AND (followers_id IS NULL OR followers_id NOT LIKE CONCAT('%', #{userId}, '%'))
</update>
<update id="removeFollower">
UPDATE task_list_detial
SET followers_id = TRIM(BOTH ',' FROM REPLACE(CONCAT(',', followers_id, ','), CONCAT(',', #{userId}, ','), ',')),
followers_name = TRIM(BOTH ',' FROM REPLACE(CONCAT(',', followers_name, ','), CONCAT(',', #{userName}, ','), ','))
WHERE id = #{taskId} AND del_flag = '0'
</update>
<update id="toggleTaskStatus">
UPDATE task_list_detial
SET task_status = #{newStatus},
complete_time = #{completeTime},
update_by = #{updateBy}, update_time = NOW()
WHERE id = #{taskId} AND del_flag = '0'
</update>
<select id="selectAllByMainId" resultType="org.jeecg.modules.demo.tasklist.entity.TaskListDetial">
SELECT * FROM task_list_detial
WHERE main_id = #{mainId} AND del_flag = '0'
ORDER BY sort_order ASC
</select>
<select id="selectTopLevelByMainId" resultType="org.jeecg.modules.demo.tasklist.entity.TaskListDetial">
SELECT * FROM task_list_detial
WHERE main_id = #{mainId} AND del_flag = '0'
AND (
type = '0'
OR (type = '1' AND (pid IS NULL OR EXISTS (
SELECT 1 FROM task_list_detial g WHERE g.id = task_list_detial.pid AND g.type = '0' AND g.del_flag = '0'
)))
)
ORDER BY sort_order ASC
</select>
<select id="selectSubTasksByPage" resultType="org.jeecg.modules.demo.tasklist.entity.TaskListDetial">
SELECT * FROM task_list_detial
WHERE pid = #{parentId} AND type = '1' AND del_flag = '0'
ORDER BY sort_order ASC
LIMIT #{offset}, #{pageSize}
</select>
<update id="updatePidAndSort">
UPDATE task_list_detial
SET pid = #{pid}, sort_order = #{sortOrder}
WHERE id = #{id}
</update>
<select id="selectChildrenByPid" resultType="org.jeecg.modules.demo.tasklist.entity.TaskListDetial">
SELECT * FROM task_list_detial
WHERE pid = #{pid} AND del_flag = '0'
</select>
<update id="resetPidToNull">
UPDATE task_list_detial
SET pid = NULL
WHERE pid = #{pid} AND main_id = #{mainId} AND del_flag = '0'
</update>
<update id="incrementSubTaskCount">
UPDATE task_list_detial SET sub_task_count = IFNULL(sub_task_count, 0) + 1, has_child = '1'
WHERE id = #{parentId}
</update>
<update id="decrementSubTaskCount">
UPDATE task_list_detial SET sub_task_count = GREATEST(IFNULL(sub_task_count, 1) - 1, 0)
WHERE id = #{parentId}
</update>
<update id="incrementCompletedSubTaskCount">
UPDATE task_list_detial SET completed_sub_task_count = IFNULL(completed_sub_task_count, 0) + 1
WHERE id = #{parentId}
</update>
<update id="decrementCompletedSubTaskCount">
UPDATE task_list_detial SET completed_sub_task_count = GREATEST(IFNULL(completed_sub_task_count, 1) - 1, 0)
WHERE id = #{parentId}
</update>
<update id="updateHasChild">
UPDATE task_list_detial SET has_child = #{hasChild} WHERE id = #{parentId}
</update>
<update id="shiftSortOrderUpForGroup">
UPDATE task_list_detial
SET sort_order = sort_order + 1
WHERE main_id = #{mainId} AND del_flag = '0'
AND type = '0'
AND (pid IS NULL OR pid = '')
AND sort_order >= #{fromSort}
</update>
<update id="shiftSortOrderDownForGroup">
UPDATE task_list_detial
SET sort_order = sort_order - 1
WHERE main_id = #{mainId} AND del_flag = '0'
AND type = '0'
AND (pid IS NULL OR pid = '')
AND sort_order > #{fromSort}
</update>
<select id="getMaxSortOrderForGroup" resultType="java.lang.Integer">
SELECT IFNULL(MAX(sort_order), 0)
FROM task_list_detial
WHERE main_id = #{mainId} AND del_flag = '0'
AND type = '0'
AND (pid IS NULL OR pid = '')
</select>
<update id="updateSortOrder">
UPDATE task_list_detial SET sort_order = #{sortOrder} WHERE id = #{id}
</update>
<select id="countChildrenByPid" resultType="java.lang.Integer">
SELECT COUNT(*) FROM task_list_detial
WHERE pid = #{pid} AND del_flag = '0'
</select>
<select id="selectByAssigneeId" resultType="org.jeecg.modules.demo.tasklist.entity.TaskListDetial">
SELECT d.*,
t.tasklist_name AS listName,
p.permission AS myPermission
FROM task_list_detial d
LEFT JOIN task_list t ON d.main_id = t.id AND t.del_flag = '0'
LEFT JOIN task_list_permission p ON d.main_id = p.main_id
AND p.user_id = #{userId} AND p.del_flag = '0'
WHERE d.type = '1' AND d.del_flag = '0'
AND d.assignee_id LIKE CONCAT('%', #{assigneeId}, '%')
</select>
<select id="selectByFollowersId" resultType="org.jeecg.modules.demo.tasklist.entity.TaskListDetial">
SELECT d.*,
t.tasklist_name AS listName,
p.permission AS myPermission
FROM task_list_detial d
LEFT JOIN task_list t ON d.main_id = t.id AND t.del_flag = '0'
LEFT JOIN task_list_permission p ON d.main_id = p.main_id
AND p.user_id = #{userId} AND p.del_flag = '0'
WHERE d.type = '1' AND d.del_flag = '0'
AND d.followers_id LIKE CONCAT('%', #{followersId}, '%')
</select>
<update id="appendAssigner">
UPDATE task_list_detial
SET assign_id = TRIM(BOTH ',' FROM CONCAT(IFNULL(assign_id, ''), ',', #{userId})),
assign_name = TRIM(BOTH ',' FROM CONCAT(IFNULL(assign_name, ''), ',', #{userName}))
WHERE id = #{taskId} AND del_flag = '0'
AND (assign_id IS NULL OR assign_id NOT LIKE CONCAT('%', #{userId}, '%'))
</update>
</mapper>
@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.jeecg.modules.demo.tasklist.mapper.TaskListFavoriteMapper">
<delete id="deleteByMainId" parameterType="java.lang.String">
DELETE
FROM task_list_favorite
WHERE
main_id = #{mainId} </delete>
<select id="selectByMainId" parameterType="java.lang.String" resultType="org.jeecg.modules.demo.tasklist.entity.TaskListFavorite">
SELECT *
FROM task_list_favorite
WHERE
main_id = #{mainId} </select>
<select id="selectMaxSortOrder" resultType="java.lang.Integer">
SELECT IFNULL(MAX(sort_order), 0)
FROM task_list_favorite
WHERE user_id = #{userId} AND del_flag = '0'
AND (pid = #{pid} OR (#{pid} IS NULL AND pid IS NULL))
</select>
<select id="selectMaxSortOrderByType" resultType="java.lang.Integer">
SELECT IFNULL(MAX(sort_order), 0)
FROM task_list_favorite
WHERE user_id = #{userId} AND del_flag = '0'
AND type = #{type}
AND (pid = #{pid} OR (#{pid} IS NULL AND pid IS NULL))
</select>
<update id="shiftSortOrderUp">
UPDATE task_list_favorite
SET sort_order = sort_order + 1
WHERE user_id = #{userId} AND del_flag = '0'
AND (pid = #{pid} OR (#{pid} IS NULL AND pid IS NULL))
AND sort_order >= #{fromSort}
</update>
<update id="shiftSortOrderDown">
UPDATE task_list_favorite
SET sort_order = sort_order - 1
WHERE user_id = #{userId} AND del_flag = '0'
AND (pid = #{pid} OR (#{pid} IS NULL AND pid IS NULL))
AND sort_order > #{fromSort}
</update>
<update id="shiftSortOrderUpByType">
UPDATE task_list_favorite
SET sort_order = sort_order + 1
WHERE user_id = #{userId} AND del_flag = '0'
AND type = #{type}
AND pid IS NULL
AND sort_order >= #{fromSort}
</update>
<update id="shiftSortOrderDownByType">
UPDATE task_list_favorite
SET sort_order = sort_order - 1
WHERE user_id = #{userId} AND del_flag = '0'
AND type = #{type}
AND pid IS NULL
AND sort_order > #{fromSort}
</update>
<select id="countChildrenByPid" resultType="java.lang.Integer">
SELECT COUNT(*)
FROM task_list_favorite
WHERE user_id = #{userId} AND del_flag = '0'
AND (pid = #{pid} OR (#{pid} IS NULL AND pid IS NULL))
</select>
<update id="updatePidAndSort">
UPDATE task_list_favorite
SET pid = #{pid}, sort_order = #{sortOrder}
WHERE id = #{id}
</update>
<update id="updateSortOrder">
UPDATE task_list_favorite SET sort_order = #{sortOrder} WHERE id = #{id}
</update>
</mapper>
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.jeecg.modules.demo.tasklist.mapper.TaskListMapper">
<select id="selectVisibleLists" resultType="org.jeecg.modules.demo.tasklist.entity.TaskList">
SELECT DISTINCT t.*
FROM task_list t
WHERE t.del_flag = '0'
AND (
-- 条件1:同一部门的人能看到互相创建的清单
-- 注意:task_list.create_by 存的是 username,所以用 u.username 匹配
<if test="orgCode != null and orgCode != ''">
EXISTS (
SELECT 1 FROM sys_user u
WHERE u.username = t.create_by
AND u.org_code = #{orgCode}
)
OR
</if>
-- 条件2:当前用户是所有者(permission=1
EXISTS (
SELECT 1 FROM task_list_permission p
WHERE p.main_id = t.id
AND p.user_id = #{userId}
AND p.permission = '1'
AND p.del_flag = '0'
)
-- 条件3:当前用户是协作者(permission=2/3
OR EXISTS (
SELECT 1 FROM task_list_permission p
WHERE p.main_id = t.id
AND p.user_id = #{userId}
AND p.permission IN ('2', '3')
AND p.del_flag = '0'
)
-- 条件4:清单中某任务的负责人/参与人是当前用户
OR EXISTS (
SELECT 1 FROM task_list_detial d
WHERE d.main_id = t.id
AND d.del_flag = '0'
AND (
d.assignee_id LIKE CONCAT('%', #{userId}, '%')
OR d.participant_id LIKE CONCAT('%', #{userId}, '%')
)
)
)
-- 条件5:密级过滤(用户密级数值 > 清单密级数值才能看到)
AND (
t.secret_level IS NULL
OR t.secret_level &lt; #{userSecLevel}
)
ORDER BY t.create_time ASC
</select>
</mapper>
@@ -1,16 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.jeecg.modules.test.mapper.TestSonTableMapper">
<mapper namespace="org.jeecg.modules.demo.tasklist.mapper.TaskListPermissionMapper">
<delete id="deleteByMainId" parameterType="java.lang.String">
DELETE
FROM test_son_table
FROM task_list_permission
WHERE
main_table_id = #{mainId} </delete>
main_id = #{mainId} </delete>
<select id="selectByMainId" parameterType="java.lang.String" resultType="org.jeecg.modules.test.entity.TestSonTable">
<select id="selectByMainId" parameterType="java.lang.String" resultType="org.jeecg.modules.demo.tasklist.entity.TaskListPermission">
SELECT *
FROM test_son_table
FROM task_list_permission
WHERE
main_table_id = #{mainId} </select>
main_id = #{mainId} </select>
</mapper>
@@ -0,0 +1,43 @@
package org.jeecg.modules.demo.tasklist.service;
import org.jeecg.modules.demo.tasklist.entity.TaskListDetial;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
import org.jeecg.modules.demo.tasklist.vo.CreateTaskReq;
import org.jeecg.modules.demo.tasklist.vo.MoveTaskReq;
public interface ITaskListDetialService extends IService<TaskListDetial> {
List<TaskListDetial> selectByMainId(String mainId);
TaskListDetial createTask(CreateTaskReq req);
void editTask(TaskListDetial task);
void deleteTask(String taskId);
List<TaskListDetial> queryAllByMainId(String mainId);
List<TaskListDetial> queryTopLevelByMainId(String mainId);
void toggleStatus(String taskId);
void moveTask(MoveTaskReq req);
void moveTaskGroup(String taskGroupId, Integer targetSortOrder);
/**
* 纯排序重算:将任务/分组移到同级第 targetPosition 个位置
* 不包含权限校验和副作用处理,由调用方负责
*/
void reorderTaskItem(String movedId, String mainId, String pid,
Integer targetPosition, String newPid, boolean isGroup);
void followTask(String taskId);
void unfollowTask(String taskId);
List<TaskListDetial> loadSubTasks(String parentTaskId, Integer pageNo, Integer pageSize);
void ensureDefaultGroup(String mainId);
}
@@ -0,0 +1,45 @@
package org.jeecg.modules.demo.tasklist.service;
import org.jeecg.modules.demo.tasklist.entity.TaskListFavorite;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* @Description: 任务清单收藏表
* @Author: jeecg-boot
* @Date: 2026-04-24
* @Version: V1.0
*/
public interface ITaskListFavoriteService extends IService<TaskListFavorite> {
/**
* 通过主表id查询子表数据
*
* @param mainId 主表id
* @return List<TaskListFavorite>
*/
public List<TaskListFavorite> selectByMainId(String mainId);
Integer getMaxSortOrder(String userId, String pid);
Integer getMaxSortOrderByType(String userId, String pid, String type);
void shiftSortOrderUp(String userId, String pid, Integer fromSort);
void shiftSortOrderDown(String userId, String pid, Integer fromSort);
void shiftSortOrderUpByType(String userId, String type, Integer fromSort);
void shiftSortOrderDownByType(String userId, String type, Integer fromSort);
Integer countChildren(String userId, String pid);
void updatePidAndSort(String favoriteId, String pid, Integer sortOrder);
/**
* 纯排序重算:将指定记录移到同级第 targetPosition 个位置
* 不包含权限校验和副作用处理,由调用方负责
*/
void reorderItem(String movedId, String userId, String pid, String type,
Integer targetPosition, String newPid);
}
@@ -0,0 +1,22 @@
package org.jeecg.modules.demo.tasklist.service;
import org.jeecg.modules.demo.tasklist.entity.TaskListPermission;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* @Description: 任务清单权限表
* @Author: jeecg-boot
* @Date: 2026-04-24
* @Version: V1.0
*/
public interface ITaskListPermissionService extends IService<TaskListPermission> {
/**
* 通过主表id查询子表数据
*
* @param mainId 主表id
* @return List<TaskListPermission>
*/
public List<TaskListPermission> selectByMainId(String mainId);
}
@@ -0,0 +1,100 @@
package org.jeecg.modules.demo.tasklist.service;
import org.jeecg.modules.demo.tasklist.entity.TaskListDetial;
import org.jeecg.modules.demo.tasklist.entity.TaskListPermission;
import org.jeecg.modules.demo.tasklist.entity.TaskListFavorite;
import org.jeecg.modules.demo.tasklist.entity.TaskList;
import org.jeecg.modules.demo.tasklist.vo.CreateTaskListReq;
import org.jeecg.modules.demo.tasklist.vo.CreateTaskListGroupReq;
import org.jeecg.modules.demo.tasklist.vo.MoveTaskListReq;
import org.jeecg.modules.demo.tasklist.vo.AddCollaboratorReq;
import org.jeecg.modules.demo.tasklist.vo.CollaboratorVO;
import com.baomidou.mybatisplus.extension.service.IService;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
/**
* @Description: 任务清单表
* @Author: jeecg-boot
* @Date: 2026-04-24
* @Version: V1.0
*/
public interface ITaskListService extends IService<TaskList> {
/**
* 添加一对多
*
* @param taskList
* @param taskListDetialList
* @param taskListPermissionList
* @param taskListFavoriteList
*/
public void saveMain(TaskList taskList,List<TaskListDetial> taskListDetialList,List<TaskListPermission> taskListPermissionList,List<TaskListFavorite> taskListFavoriteList) ;
/**
* 修改一对多
*
* @param taskList
* @param taskListDetialList
* @param taskListPermissionList
* @param taskListFavoriteList
*/
public void updateMain(TaskList taskList,List<TaskListDetial> taskListDetialList,List<TaskListPermission> taskListPermissionList,List<TaskListFavorite> taskListFavoriteList);
/**
* 删除一对多
*
* @param id
*/
public void delMain (String id);
/**
* 批量删除一对多
*
* @param idList
*/
public void delBatchMain (Collection<? extends Serializable> idList);
String createTaskList(CreateTaskListReq req);
String createTaskListGroup(CreateTaskListGroupReq req);
void moveTaskList(MoveTaskListReq req);
void moveGroup(String groupId, Integer sortOrder);
List<TaskListFavorite> getMyFavorites();
void deleteTaskList(String taskListId);
void removeFavorite(String favoriteId);
void removeFavoriteGroup(String groupId);
void renameGroup(String groupId, String newName);
void renameTaskList(String taskListId, String newName);
List<TaskList> getMyOwnLists();
List<TaskList> getAllLists();
List<TaskList> getMyCollabLists();
List<CollaboratorVO> getCollaborators(String taskListId);
void addCollaborator(AddCollaboratorReq req);
void removeCollaborator(String permissionId);
void updateCollaboratorPermission(String permissionId, String newPermission);
String getMyPermission(String taskListId);
void addToFavorites(String taskListId, String pid);
List<TaskListDetial> myResponsibleTasks();
List<TaskListDetial> myFollowedTasks();
}
@@ -0,0 +1,629 @@
package org.jeecg.modules.demo.tasklist.service.impl;
import org.jeecg.modules.demo.tasklist.entity.TaskList;
import org.jeecg.modules.demo.tasklist.entity.TaskListDetial;
import org.jeecg.modules.demo.tasklist.entity.TaskListPermission;
import org.jeecg.modules.demo.tasklist.mapper.TaskListDetialMapper;
import org.jeecg.modules.demo.tasklist.mapper.TaskListMapper;
import org.jeecg.modules.demo.tasklist.mapper.TaskListPermissionMapper;
import org.jeecg.modules.demo.tasklist.service.ITaskListDetialService;
import org.jeecg.modules.demo.tasklist.vo.CreateTaskReq;
import org.jeecg.modules.demo.tasklist.vo.MoveTaskReq;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.oConvertUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
import java.util.Set;
@Service
public class TaskListDetialServiceImpl extends ServiceImpl<TaskListDetialMapper, TaskListDetial> implements ITaskListDetialService {
@Autowired
private TaskListDetialMapper taskListDetialMapper;
@Autowired
private TaskListMapper taskListMapper;
@Autowired
private TaskListPermissionMapper taskListPermissionMapper;
@Autowired
private ISysBaseAPI sysBaseAPI;
@Override
public List<TaskListDetial> selectByMainId(String mainId) {
return taskListDetialMapper.selectByMainId(mainId);
}
@Override
@Transactional(rollbackFor = Exception.class)
public TaskListDetial createTask(CreateTaskReq req) {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String userId = loginUser.getId();
String permission = getPermission(req.getMainId(), userId);
if (permission == null) {
throw new RuntimeException("无权限在此清单中创建任务");
}
if ("3".equals(permission)) {
throw new RuntimeException("可阅读者无法创建任务");
}
if ("1".equals(req.getType()) && oConvertUtils.isEmpty(req.getPid())) {
ensureDefaultGroup(req.getMainId());
TaskListDetial defaultGroup = findDefaultGroup(req.getMainId());
if (defaultGroup != null) {
req.setPid(defaultGroup.getId());
}
}
TaskListDetial entity = new TaskListDetial();
entity.setMainId(req.getMainId());
entity.setTaskName(req.getTaskName());
entity.setTaskDesc(req.getTaskDesc());
entity.setPriority(req.getPriority());
entity.setType(req.getType() != null ? req.getType() : "1");
entity.setPid(normalizePid(req.getPid()));
entity.setTaskStatus(0);
entity.setSubTaskCount(0);
entity.setCompletedSubTaskCount(0);
entity.setHasChild("0");
entity.setDelFlag("0");
entity.setSysOrgCode(loginUser.getOrgCode());
if ("1".equals(req.getType()) && oConvertUtils.isNotEmpty(req.getAssigneeId())) {
entity.setAssigneeId(req.getAssigneeId());
entity.setAssigneeName(translateUserIdsToNames(req.getAssigneeId()));
entity.setAssignId(userId);
entity.setAssignName(loginUser.getRealname());
}
if (req.getStartTime() != null) {
entity.setStartTime(req.getStartTime());
}
if (req.getEndTime() != null) {
entity.setEndTime(req.getEndTime());
}
if (req.getSortOrder() != null) {
taskListDetialMapper.shiftSortOrderUp(req.getMainId(), normalizePid(req.getPid()), req.getSortOrder());
entity.setSortOrder(req.getSortOrder());
} else {
Integer maxSort = taskListDetialMapper.getMaxSortOrder(req.getMainId(), normalizePid(req.getPid()));
entity.setSortOrder(maxSort + 1);
}
taskListDetialMapper.insert(entity);
if ("1".equals(entity.getType()) && oConvertUtils.isNotEmpty(entity.getPid())) {
TaskListDetial parent = taskListDetialMapper.selectById(entity.getPid());
if (parent != null && "1".equals(parent.getType())) {
taskListDetialMapper.incrementSubTaskCount(parent.getId());
}
}
return entity;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void editTask(TaskListDetial task) {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String userId = loginUser.getId();
TaskListDetial existing = taskListDetialMapper.selectById(task.getId());
if (existing == null) {
throw new RuntimeException("任务不存在");
}
String permission = getPermission(existing.getMainId(), userId);
if (permission == null) {
throw new RuntimeException("无权限编辑此任务");
}
if ("3".equals(permission)) {
String assigneeId = existing.getAssigneeId();
if (oConvertUtils.isEmpty(assigneeId) || !assigneeId.contains(userId)) {
throw new RuntimeException("可阅读者只能编辑自己负责的任务");
}
task.setAssigneeId(existing.getAssigneeId());
task.setAssigneeName(existing.getAssigneeName());
}
TaskList taskListEntity = taskListMapper.selectById(existing.getMainId());
if (taskListEntity != null) {
Integer listSecLevel = taskListEntity.getSecretLevel();
if (listSecLevel == null) {
listSecLevel = 1;
}
if (task.getAssigneeId() != null) {
String filtered = filterUsersBySecLevel(task.getAssigneeId(), listSecLevel);
if (!Objects.equals(filtered, task.getAssigneeId())) {
log.warn(String.format("editTask 密级过滤: 清单[%s] 负责人 原始[%s] 过滤后[%s]",
taskListEntity.getId(), task.getAssigneeId(), filtered));
}
task.setAssigneeId(filtered);
if (oConvertUtils.isEmpty(filtered)) {
task.setAssigneeName("");
}
}
if (task.getParticipantId() != null) {
String filtered = filterUsersBySecLevel(task.getParticipantId(), listSecLevel);
if (!Objects.equals(filtered, task.getParticipantId())) {
log.warn(String.format("editTask 密级过滤: 清单[%s] 参与人 原始[%s] 过滤后[%s]",
taskListEntity.getId(), task.getParticipantId(), filtered));
}
task.setParticipantId(filtered);
if (oConvertUtils.isEmpty(filtered)) {
task.setParticipantName("");
}
}
if (task.getFollowersId() != null) {
String filtered = filterUsersBySecLevel(task.getFollowersId(), listSecLevel);
if (!Objects.equals(filtered, task.getFollowersId())) {
log.warn(String.format("editTask 密级过滤: 清单[%s] 关注人 原始[%s] 过滤后[%s]",
taskListEntity.getId(), task.getFollowersId(), filtered));
}
task.setFollowersId(filtered);
if (oConvertUtils.isEmpty(filtered)) {
task.setFollowersName("");
}
}
}
if (task.getAssigneeId() != null) {
if (oConvertUtils.isNotEmpty(task.getAssigneeId()) && oConvertUtils.isEmpty(task.getAssigneeName())) {
task.setAssigneeName(translateUserIdsToNames(task.getAssigneeId()));
}
if (oConvertUtils.isEmpty(task.getAssigneeId())) {
task.setAssigneeName("");
}
}
if (task.getParticipantId() != null) {
if (oConvertUtils.isNotEmpty(task.getParticipantId()) && oConvertUtils.isEmpty(task.getParticipantName())) {
task.setParticipantName(translateUserIdsToNames(task.getParticipantId()));
}
if (oConvertUtils.isEmpty(task.getParticipantId())) {
task.setParticipantName("");
}
}
if (task.getFollowersId() != null) {
if (oConvertUtils.isNotEmpty(task.getFollowersId()) && oConvertUtils.isEmpty(task.getFollowersName())) {
task.setFollowersName(translateUserIdsToNames(task.getFollowersId()));
}
if (oConvertUtils.isEmpty(task.getFollowersId())) {
task.setFollowersName("");
}
}
boolean clearStartTime = task.getStartTime() == null && existing.getStartTime() != null;
boolean clearEndTime = task.getEndTime() == null && existing.getEndTime() != null;
taskListDetialMapper.updateById(task);
if (clearStartTime || clearEndTime) {
UpdateWrapper<TaskListDetial> uw = new UpdateWrapper<>();
uw.eq("id", task.getId());
if (clearStartTime) uw.set("start_time", null);
if (clearEndTime) uw.set("end_time", null);
taskListDetialMapper.update(null, uw);
}
taskListDetialMapper.appendAssigner(task.getId(), userId, loginUser.getRealname());
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteTask(String taskId) {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String userId = loginUser.getId();
TaskListDetial existing = taskListDetialMapper.selectById(taskId);
if (existing == null) {
throw new RuntimeException("任务不存在");
}
String permission = getPermission(existing.getMainId(), userId);
if (permission == null) {
throw new RuntimeException("无权限删除此任务");
}
if ("3".equals(permission)) {
throw new RuntimeException("可阅读者无法删除任务");
}
if ("0".equals(existing.getType()) && existing.getIsDefault() != null && existing.getIsDefault() == 1) {
throw new RuntimeException("默认分组不能删除");
}
if ("0".equals(existing.getType())) {
taskListDetialMapper.resetPidToNull(taskId, existing.getMainId());
}
List<TaskListDetial> children = taskListDetialMapper.selectChildrenByPid(taskId);
for (TaskListDetial child : children) {
deleteTaskRecursive(child);
}
taskListDetialMapper.deleteById(taskId);
if (oConvertUtils.isNotEmpty(existing.getPid())) {
TaskListDetial parent = taskListDetialMapper.selectById(existing.getPid());
if (parent != null && "1".equals(parent.getType())) {
taskListDetialMapper.decrementSubTaskCount(parent.getId());
if (existing.getTaskStatus() != null && existing.getTaskStatus() == 1) {
taskListDetialMapper.decrementCompletedSubTaskCount(parent.getId());
}
Integer childCount = taskListDetialMapper.countChildrenByPid(parent.getId());
if (childCount == null || childCount == 0) {
taskListDetialMapper.updateHasChild(parent.getId(), "0");
}
}
}
}
private void deleteTaskRecursive(TaskListDetial task) {
List<TaskListDetial> children = taskListDetialMapper.selectChildrenByPid(task.getId());
for (TaskListDetial child : children) {
deleteTaskRecursive(child);
}
taskListDetialMapper.deleteById(task.getId());
}
@Override
public List<TaskListDetial> queryAllByMainId(String mainId) {
List<TaskListDetial> list = taskListDetialMapper.selectAllByMainId(mainId);
fillCreateByName(list);
return list;
}
@Override
public List<TaskListDetial> queryTopLevelByMainId(String mainId) {
List<TaskListDetial> list = taskListDetialMapper.selectTopLevelByMainId(mainId);
fillCreateByName(list);
return list;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void toggleStatus(String taskId) {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String userId = loginUser.getId();
TaskListDetial existing = taskListDetialMapper.selectById(taskId);
if (existing == null) {
throw new RuntimeException("任务不存在");
}
String permission = getPermission(existing.getMainId(), userId);
if (permission == null) {
throw new RuntimeException("无权限操作此任务");
}
if ("3".equals(permission)) {
String assigneeId = existing.getAssigneeId();
if (oConvertUtils.isEmpty(assigneeId) || !assigneeId.contains(userId)) {
throw new RuntimeException("可阅读者只能操作自己负责的任务");
}
}
int oldStatus = existing.getTaskStatus() != null ? existing.getTaskStatus() : 0;
int newStatus = oldStatus == 0 ? 1 : 0;
java.util.Date completeTime = oldStatus == 0 ? new java.util.Date() : null;
taskListDetialMapper.toggleTaskStatus(taskId, loginUser.getUsername(), newStatus, completeTime);
if (oConvertUtils.isNotEmpty(existing.getPid())) {
TaskListDetial parent = taskListDetialMapper.selectById(existing.getPid());
if (parent != null && "1".equals(parent.getType())) {
if (oldStatus == 0) {
taskListDetialMapper.incrementCompletedSubTaskCount(parent.getId());
} else {
taskListDetialMapper.decrementCompletedSubTaskCount(parent.getId());
}
}
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void moveTask(MoveTaskReq req) {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String userId = loginUser.getId();
TaskListDetial task = taskListDetialMapper.selectById(req.getTaskId());
if (task == null) {
throw new RuntimeException("任务不存在");
}
String permission = getPermission(task.getMainId(), userId);
if (permission == null) {
throw new RuntimeException("无权限移动此任务");
}
if ("3".equals(permission)) {
throw new RuntimeException("可阅读者无法移动任务");
}
String oldPid = normalizePid(task.getPid());
String newPid = normalizePid(req.getTargetPid());
boolean pidChanged = (oldPid == null && newPid != null) || (oldPid != null && !oldPid.equals(newPid));
// 调用纯排序方法
reorderTaskItem(req.getTaskId(), task.getMainId(), oldPid, req.getTargetSortOrder(), newPid, false);
// 仅在 pid 变更时更新父子计数
if (pidChanged) {
// 清除旧父任务的副作用
if (oConvertUtils.isNotEmpty(oldPid)) {
TaskListDetial oldParent = taskListDetialMapper.selectById(oldPid);
if (oldParent != null && "1".equals(oldParent.getType())) {
taskListDetialMapper.decrementSubTaskCount(oldPid);
Integer childCount = taskListDetialMapper.countChildrenByPid(oldPid);
if (childCount == null || childCount == 0) {
taskListDetialMapper.updateHasChild(oldPid, "0");
}
}
}
// 设置新父任务的副作用
if (oConvertUtils.isNotEmpty(newPid)) {
TaskListDetial newParent = taskListDetialMapper.selectById(newPid);
if (newParent != null && "1".equals(newParent.getType())) {
taskListDetialMapper.incrementSubTaskCount(newPid);
}
taskListDetialMapper.updateHasChild(newPid, "1");
}
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void moveTaskGroup(String taskGroupId, Integer targetSortOrder) {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String userId = loginUser.getId();
TaskListDetial group = taskListDetialMapper.selectById(taskGroupId);
if (group == null || !"0".equals(group.getType())) {
throw new RuntimeException("分组不存在");
}
String mainId = group.getMainId();
String permission = getPermission(mainId, userId);
if (permission == null || "3".equals(permission)) {
throw new RuntimeException("无权限移动此分组");
}
reorderTaskItem(taskGroupId, mainId, null, targetSortOrder, null, true);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void reorderTaskItem(String movedId, String mainId, String pid,
Integer targetPosition, String newPid, boolean isGroup) {
TaskListDetial moved = taskListDetialMapper.selectById(movedId);
if (moved == null) {
throw new RuntimeException("记录不存在");
}
// 当 newPid 有值时使用 newPid(跨组移动),否则使用 pid(同组内移动)
// 关键:newPid="" 表示拖到根级别,此时应设为 null
String effectiveNewPid;
if (newPid != null) {
effectiveNewPid = newPid.isEmpty() ? null : newPid;
} else {
effectiveNewPid = pid;
}
LambdaQueryWrapper<TaskListDetial> query = new LambdaQueryWrapper<>();
query.eq(TaskListDetial::getMainId, mainId);
query.eq(TaskListDetial::getDelFlag, "0");
if (isGroup) {
query.eq(TaskListDetial::getType, "0");
query.and(w -> w.isNull(TaskListDetial::getPid).or().eq(TaskListDetial::getPid, ""));
} else {
if (effectiveNewPid != null) {
query.eq(TaskListDetial::getPid, effectiveNewPid);
} else {
query.isNull(TaskListDetial::getPid);
}
}
query.ne(TaskListDetial::getId, movedId);
query.orderByAsc(TaskListDetial::getSortOrder);
List<TaskListDetial> siblings = taskListDetialMapper.selectList(query);
int pos = targetPosition != null ? targetPosition : siblings.size() + 1;
pos = Math.max(1, Math.min(pos, siblings.size() + 1));
int sort = 1;
for (int i = 0; i < siblings.size(); i++) {
if (sort == pos) {
sort++;
}
TaskListDetial sibling = siblings.get(i);
if (!sibling.getSortOrder().equals(sort)) {
taskListDetialMapper.updateSortOrder(sibling.getId(), sort);
}
sort++;
}
taskListDetialMapper.updatePidAndSort(movedId, effectiveNewPid, pos);
}
@Override
public void followTask(String taskId) {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String userId = loginUser.getId();
String userName = loginUser.getRealname();
taskListDetialMapper.appendFollower(taskId, userId, userName);
}
@Override
public void unfollowTask(String taskId) {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String userId = loginUser.getId();
String userName = loginUser.getRealname();
taskListDetialMapper.removeFollower(taskId, userId, userName);
}
@Override
public List<TaskListDetial> loadSubTasks(String parentTaskId, Integer pageNo, Integer pageSize) {
if (pageNo == null || pageNo < 1) pageNo = 1;
if (pageSize == null || pageSize < 1) pageSize = 20;
int offset = (pageNo - 1) * pageSize;
List<TaskListDetial> list = taskListDetialMapper.selectSubTasksByPage(parentTaskId, offset, pageSize);
fillCreateByName(list);
return list;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void ensureDefaultGroup(String mainId) {
TaskListDetial defaultGroup = findDefaultGroup(mainId);
if (defaultGroup == null) {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
TaskListDetial group = new TaskListDetial();
group.setMainId(mainId);
group.setTaskName("默认分组");
group.setType("0");
group.setPid(null);
group.setSortOrder(0);
group.setIsDefault(1);
group.setHasChild("0");
group.setSubTaskCount(0);
group.setCompletedSubTaskCount(0);
group.setDelFlag("0");
taskListDetialMapper.insert(group);
}
}
private TaskListDetial findDefaultGroup(String mainId) {
LambdaQueryWrapper<TaskListDetial> query = new LambdaQueryWrapper<>();
query.eq(TaskListDetial::getMainId, mainId);
query.eq(TaskListDetial::getType, "0");
query.eq(TaskListDetial::getIsDefault, 1);
query.last("LIMIT 1");
TaskListDetial result = taskListDetialMapper.selectOne(query);
if (result != null) {
return result;
}
query = new LambdaQueryWrapper<>();
query.eq(TaskListDetial::getMainId, mainId);
query.eq(TaskListDetial::getType, "0");
query.isNull(TaskListDetial::getIsDefault);
query.orderByAsc(TaskListDetial::getSortOrder);
query.last("LIMIT 1");
result = taskListDetialMapper.selectOne(query);
if (result != null) {
result.setIsDefault(1);
taskListDetialMapper.updateById(result);
}
return result;
}
private String getPermission(String mainId, String userId) {
LambdaQueryWrapper<TaskListPermission> query = new LambdaQueryWrapper<>();
query.eq(TaskListPermission::getMainId, mainId);
query.eq(TaskListPermission::getUserId, userId);
TaskListPermission perm = taskListPermissionMapper.selectOne(query);
return perm != null ? perm.getPermission() : null;
}
private String normalizePid(String pid) {
return oConvertUtils.isNotEmpty(pid) ? pid : null;
}
private void fillCreateByName(List<TaskListDetial> list) {
if (list == null || list.isEmpty()) {
return;
}
for (TaskListDetial task : list) {
if (oConvertUtils.isNotEmpty(task.getCreateBy())) {
List<com.alibaba.fastjson.JSONObject> users = sysBaseAPI.queryUsersByUsernames(task.getCreateBy());
if (users != null && !users.isEmpty()) {
task.setCreateByName(users.get(0).getString("realname"));
}
}
if (oConvertUtils.isNotEmpty(task.getAssigneeId()) && oConvertUtils.isEmpty(task.getAssigneeName())) {
task.setAssigneeName(translateUserIdsToNames(task.getAssigneeId()));
}
if (oConvertUtils.isNotEmpty(task.getParticipantId()) && oConvertUtils.isEmpty(task.getParticipantName())) {
task.setParticipantName(translateUserIdsToNames(task.getParticipantId()));
}
if (oConvertUtils.isNotEmpty(task.getFollowersId()) && oConvertUtils.isEmpty(task.getFollowersName())) {
task.setFollowersName(translateUserIdsToNames(task.getFollowersId()));
}
}
}
private String translateUserIdsToNames(String ids) {
if (oConvertUtils.isEmpty(ids)) {
return null;
}
String[] idArr = ids.split(",");
StringBuilder names = new StringBuilder();
for (String id : idArr) {
if (oConvertUtils.isNotEmpty(id)) {
LoginUser user = sysBaseAPI.getUserById(id.trim());
if (user != null) {
if (names.length() > 0) {
names.append(",");
}
names.append(user.getRealname());
}
}
}
return names.length() > 0 ? names.toString() : null;
}
private String mergeIds(String existingIds, String newIds) {
Set<String> idSet = new LinkedHashSet<>();
if (oConvertUtils.isNotEmpty(existingIds)) {
for (String id : existingIds.split(",")) {
String trimmed = id.trim();
if (oConvertUtils.isNotEmpty(trimmed)) {
idSet.add(trimmed);
}
}
}
if (oConvertUtils.isNotEmpty(newIds)) {
for (String id : newIds.split(",")) {
String trimmed = id.trim();
if (oConvertUtils.isNotEmpty(trimmed)) {
idSet.add(trimmed);
}
}
}
return idSet.isEmpty() ? null : String.join(",", idSet);
}
private String filterUsersBySecLevel(String userIds, Integer listSecLevel) {
if (oConvertUtils.isEmpty(userIds)) return userIds;
if (listSecLevel == null) {
listSecLevel = 1;
}
String[] ids = userIds.split(",");
java.util.List<String> validIds = new java.util.ArrayList<>();
for (String id : ids) {
LoginUser user = sysBaseAPI.getUserById(id.trim());
if (user == null) {
continue;
}
Integer userSecLevel = user.getUserSecurityLevel();
if (userSecLevel == null) {
userSecLevel = 3;
}
if (userSecLevel > listSecLevel) {
validIds.add(id.trim());
}
}
return String.join(",", validIds);
}
}
@@ -0,0 +1,122 @@
package org.jeecg.modules.demo.tasklist.service.impl;
import org.jeecg.modules.demo.tasklist.entity.TaskListFavorite;
import org.jeecg.modules.demo.tasklist.mapper.TaskListFavoriteMapper;
import org.jeecg.modules.demo.tasklist.service.ITaskListFavoriteService;
import org.springframework.stereotype.Service;
import java.util.List;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.transaction.annotation.Transactional;
/**
* @Description: 任务清单收藏表
* @Author: jeecg-boot
* @Date: 2026-04-24
* @Version: V1.0
*/
@Service
public class TaskListFavoriteServiceImpl extends ServiceImpl<TaskListFavoriteMapper, TaskListFavorite> implements ITaskListFavoriteService {
@Autowired
private TaskListFavoriteMapper taskListFavoriteMapper;
@Override
public List<TaskListFavorite> selectByMainId(String mainId) {
return taskListFavoriteMapper.selectByMainId(mainId);
}
@Override
public Integer getMaxSortOrder(String userId, String pid) {
Integer max = taskListFavoriteMapper.selectMaxSortOrder(userId, pid);
return max != null ? max : 0;
}
@Override
public Integer getMaxSortOrderByType(String userId, String pid, String type) {
Integer max = taskListFavoriteMapper.selectMaxSortOrderByType(userId, pid, type);
return max != null ? max : 0;
}
@Override
public void shiftSortOrderUp(String userId, String pid, Integer fromSort) {
taskListFavoriteMapper.shiftSortOrderUp(userId, pid, fromSort);
}
@Override
public void shiftSortOrderDown(String userId, String pid, Integer fromSort) {
taskListFavoriteMapper.shiftSortOrderDown(userId, pid, fromSort);
}
@Override
public void shiftSortOrderUpByType(String userId, String type, Integer fromSort) {
taskListFavoriteMapper.shiftSortOrderUpByType(userId, type, fromSort);
}
@Override
public void shiftSortOrderDownByType(String userId, String type, Integer fromSort) {
taskListFavoriteMapper.shiftSortOrderDownByType(userId, type, fromSort);
}
@Override
public Integer countChildren(String userId, String pid) {
return taskListFavoriteMapper.countChildrenByPid(userId, pid);
}
@Override
public void updatePidAndSort(String favoriteId, String pid, Integer sortOrder) {
taskListFavoriteMapper.updatePidAndSort(favoriteId, pid, sortOrder);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void reorderItem(String movedId, String userId, String pid, String type,
Integer targetPosition, String newPid) {
TaskListFavorite moved = taskListFavoriteMapper.selectById(movedId);
if (moved == null) {
throw new RuntimeException("记录不存在");
}
// 当 newPid 有值时使用 newPid(跨组移动),否则使用 pid(同组内移动)
// 关键:newPid="" 表示拖到根级别(无分组),此时应设为 null
String effectiveNewPid;
if (newPid != null) {
effectiveNewPid = newPid.isEmpty() ? null : newPid;
} else {
effectiveNewPid = pid;
}
LambdaQueryWrapper<TaskListFavorite> query = new LambdaQueryWrapper<>();
query.eq(TaskListFavorite::getUserId, userId);
query.eq(TaskListFavorite::getDelFlag, "0");
if (type != null) {
query.eq(TaskListFavorite::getType, type);
}
if (effectiveNewPid != null) {
query.eq(TaskListFavorite::getPid, effectiveNewPid);
} else {
query.isNull(TaskListFavorite::getPid);
}
query.ne(TaskListFavorite::getId, movedId);
query.orderByAsc(TaskListFavorite::getSortOrder);
List<TaskListFavorite> siblings = taskListFavoriteMapper.selectList(query);
int pos = targetPosition != null ? targetPosition : siblings.size() + 1;
pos = Math.max(1, Math.min(pos, siblings.size() + 1));
int sort = 1;
for (int i = 0; i < siblings.size(); i++) {
if (sort == pos) {
sort++;
}
TaskListFavorite sibling = siblings.get(i);
if (!sibling.getSortOrder().equals(sort)) {
taskListFavoriteMapper.updateSortOrder(sibling.getId(), sort);
}
sort++;
}
taskListFavoriteMapper.updatePidAndSort(movedId, effectiveNewPid, pos);
}
}
@@ -0,0 +1,27 @@
package org.jeecg.modules.demo.tasklist.service.impl;
import org.jeecg.modules.demo.tasklist.entity.TaskListPermission;
import org.jeecg.modules.demo.tasklist.mapper.TaskListPermissionMapper;
import org.jeecg.modules.demo.tasklist.service.ITaskListPermissionService;
import org.springframework.stereotype.Service;
import java.util.List;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
/**
* @Description: 任务清单权限表
* @Author: jeecg-boot
* @Date: 2026-04-24
* @Version: V1.0
*/
@Service
public class TaskListPermissionServiceImpl extends ServiceImpl<TaskListPermissionMapper, TaskListPermission> implements ITaskListPermissionService {
@Autowired
private TaskListPermissionMapper taskListPermissionMapper;
@Override
public List<TaskListPermission> selectByMainId(String mainId) {
return taskListPermissionMapper.selectByMainId(mainId);
}
}
@@ -0,0 +1,862 @@
package org.jeecg.modules.demo.tasklist.service.impl;
import org.jeecg.modules.demo.tasklist.entity.TaskList;
import org.jeecg.modules.demo.tasklist.entity.TaskListDetial;
import org.jeecg.modules.demo.tasklist.entity.TaskListPermission;
import org.jeecg.modules.demo.tasklist.entity.TaskListFavorite;
import org.jeecg.modules.demo.tasklist.mapper.TaskListDetialMapper;
import org.jeecg.modules.demo.tasklist.mapper.TaskListPermissionMapper;
import org.jeecg.modules.demo.tasklist.mapper.TaskListFavoriteMapper;
import org.jeecg.modules.demo.tasklist.mapper.TaskListMapper;
import org.jeecg.modules.demo.tasklist.service.ITaskListService;
import org.jeecg.modules.demo.tasklist.service.ITaskListFavoriteService;
import org.jeecg.modules.demo.tasklist.vo.CreateTaskListReq;
import org.jeecg.modules.demo.tasklist.vo.CreateTaskListGroupReq;
import org.jeecg.modules.demo.tasklist.vo.MoveTaskListReq;
import org.jeecg.modules.demo.tasklist.vo.AddCollaboratorReq;
import org.jeecg.modules.demo.tasklist.vo.CollaboratorVO;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.vo.LoginUser;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Collection;
import java.util.Objects;
/**
* @Description: 任务清单表
* @Author: jeecg-boot
* @Date: 2026-04-24
* @Version: V1.0
*/
@Service
public class TaskListServiceImpl extends ServiceImpl<TaskListMapper, TaskList> implements ITaskListService {
@Autowired
private TaskListMapper taskListMapper;
@Autowired
private TaskListDetialMapper taskListDetialMapper;
@Autowired
private TaskListPermissionMapper taskListPermissionMapper;
@Autowired
private TaskListFavoriteMapper taskListFavoriteMapper;
@Autowired
private ITaskListFavoriteService taskListFavoriteService;
@Autowired
private ISysBaseAPI sysBaseAPI;
@Override
@Transactional(rollbackFor = Exception.class)
public void saveMain(TaskList taskList, List<TaskListDetial> taskListDetialList,List<TaskListPermission> taskListPermissionList,List<TaskListFavorite> taskListFavoriteList) {
taskListMapper.insert(taskList);
if(taskListDetialList!=null && taskListDetialList.size()>0) {
for(TaskListDetial entity:taskListDetialList) {
//外键设置
entity.setMainId(taskList.getId());
taskListDetialMapper.insert(entity);
}
}
if(taskListPermissionList!=null && taskListPermissionList.size()>0) {
for(TaskListPermission entity:taskListPermissionList) {
//外键设置
entity.setMainId(taskList.getId());
taskListPermissionMapper.insert(entity);
}
}
if(taskListFavoriteList!=null && taskListFavoriteList.size()>0) {
for(TaskListFavorite entity:taskListFavoriteList) {
//外键设置
entity.setMainId(taskList.getId());
taskListFavoriteMapper.insert(entity);
}
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateMain(TaskList taskList,List<TaskListDetial> taskListDetialList,List<TaskListPermission> taskListPermissionList,List<TaskListFavorite> taskListFavoriteList) {
taskListMapper.updateById(taskList);
//1.先删除子表数据
taskListDetialMapper.deleteByMainId(taskList.getId());
taskListPermissionMapper.deleteByMainId(taskList.getId());
taskListFavoriteMapper.deleteByMainId(taskList.getId());
//2.子表数据重新插入
if(taskListDetialList!=null && taskListDetialList.size()>0) {
for(TaskListDetial entity:taskListDetialList) {
//外键设置
entity.setMainId(taskList.getId());
taskListDetialMapper.insert(entity);
}
}
if(taskListPermissionList!=null && taskListPermissionList.size()>0) {
for(TaskListPermission entity:taskListPermissionList) {
//外键设置
entity.setMainId(taskList.getId());
taskListPermissionMapper.insert(entity);
}
}
if(taskListFavoriteList!=null && taskListFavoriteList.size()>0) {
for(TaskListFavorite entity:taskListFavoriteList) {
//外键设置
entity.setMainId(taskList.getId());
taskListFavoriteMapper.insert(entity);
}
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void delMain(String id) {
taskListDetialMapper.deleteByMainId(id);
taskListPermissionMapper.deleteByMainId(id);
taskListFavoriteMapper.deleteByMainId(id);
taskListMapper.deleteById(id);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void delBatchMain(Collection<? extends Serializable> idList) {
for(Serializable id:idList) {
taskListDetialMapper.deleteByMainId(id.toString());
taskListPermissionMapper.deleteByMainId(id.toString());
taskListFavoriteMapper.deleteByMainId(id.toString());
taskListMapper.deleteById(id);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public String createTaskList(CreateTaskListReq req) {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String userId = loginUser.getId();
Integer userSecLevel = loginUser.getUserSecurityLevel();
if (userSecLevel == null) {
userSecLevel = 3;
}
if (req.getSecretLevel() != null && req.getSecretLevel() >= userSecLevel) {
throw new RuntimeException("您无权创建该密级的清单");
}
if (oConvertUtils.isNotEmpty(req.getPid())) {
TaskListFavorite groupFav = taskListFavoriteMapper.selectById(req.getPid());
if (groupFav == null || !"0".equals(groupFav.getType()) || !userId.equals(groupFav.getUserId())) {
throw new RuntimeException("目标分组不存在或无权限");
}
}
TaskList taskList = new TaskList();
taskList.setTasklistName(req.getTasklistName());
taskList.setSecretLevel(req.getSecretLevel());
taskList.setSecretText(getSecretText(req.getSecretLevel()));
taskListMapper.insert(taskList);
TaskListDetial defaultGroup = new TaskListDetial();
defaultGroup.setMainId(taskList.getId());
defaultGroup.setTaskName("默认分组");
defaultGroup.setType("0");
defaultGroup.setPid(null);
defaultGroup.setSortOrder(0);
defaultGroup.setIsDefault(1);
defaultGroup.setHasChild("0");
defaultGroup.setSubTaskCount(0);
defaultGroup.setCompletedSubTaskCount(0);
defaultGroup.setDelFlag("0");
taskListDetialMapper.insert(defaultGroup);
TaskListPermission permission = new TaskListPermission();
permission.setMainId(taskList.getId());
permission.setUserId(userId);
permission.setPermission("1");
taskListPermissionMapper.insert(permission);
if (oConvertUtils.isNotEmpty(req.getPid())) {
TaskListFavorite parentFav = new TaskListFavorite();
parentFav.setId(req.getPid());
parentFav.setHasChild("1");
taskListFavoriteMapper.updateById(parentFav);
}
return taskList.getId();
}
@Override
@Transactional(rollbackFor = Exception.class)
public String createTaskListGroup(CreateTaskListGroupReq req) {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String userId = loginUser.getId();
Integer sortOrder = 1;
taskListFavoriteMapper.shiftSortOrderUpByType(userId, "0", sortOrder);
TaskListFavorite favorite = new TaskListFavorite();
favorite.setMainId(null);
favorite.setUserId(userId);
favorite.setType("0");
favorite.setPid(null);
favorite.setHasChild("0");
favorite.setSortOrder(sortOrder);
favorite.setTasklistName(req.getTasklistName());
taskListFavoriteMapper.insert(favorite);
return favorite.getId();
}
@Override
@Transactional(rollbackFor = Exception.class)
public void moveTaskList(MoveTaskListReq req) {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String userId = loginUser.getId();
TaskListFavorite favorite = taskListFavoriteMapper.selectById(req.getFavoriteId());
if (favorite == null || !userId.equals(favorite.getUserId())) {
throw new RuntimeException("无权限操作此记录");
}
if ("0".equals(favorite.getType())) {
throw new RuntimeException("分组不支持移动操作");
}
String oldPid = normalizePid(favorite.getPid());
String newPid = null;
if (req.getTargetGroupId() != null) {
if (oConvertUtils.isNotEmpty(req.getTargetGroupId())) {
TaskListFavorite targetGroup = taskListFavoriteMapper.selectById(req.getTargetGroupId());
if (targetGroup == null || !"0".equals(targetGroup.getType()) || !userId.equals(targetGroup.getUserId())) {
throw new RuntimeException("目标分组不存在或无权限");
}
newPid = normalizePid(req.getTargetGroupId());
} else {
newPid = "";
}
}
// 调用纯排序方法
taskListFavoriteService.reorderItem(req.getFavoriteId(), userId, oldPid, "1", req.getSortOrder(), newPid);
// 维护旧父节点 hasChild
if (oConvertUtils.isNotEmpty(oldPid) && !oldPid.equals(newPid)) {
Integer remainCount = taskListFavoriteService.countChildren(userId, oldPid);
if (remainCount == null || remainCount == 0) {
TaskListFavorite oldParent = new TaskListFavorite();
oldParent.setId(oldPid);
oldParent.setHasChild("0");
taskListFavoriteMapper.updateById(oldParent);
}
}
// 维护新父节点 hasChild
if (oConvertUtils.isNotEmpty(newPid)) {
TaskListFavorite newParent = new TaskListFavorite();
newParent.setId(newPid);
newParent.setHasChild("1");
taskListFavoriteMapper.updateById(newParent);
}
}
@Override
public List<TaskListFavorite> getMyFavorites() {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String userId = loginUser.getId();
Integer userSecLevel = loginUser.getUserSecurityLevel();
if (userSecLevel == null) {
userSecLevel = 3;
}
QueryWrapper<TaskListFavorite> query = new QueryWrapper<>();
query.eq("user_id", userId);
query.eq("del_flag", "0");
query.orderByAsc("type");
query.orderByAsc("sort_order");
List<TaskListFavorite> favorites = taskListFavoriteMapper.selectList(query);
List<String> mainIds = new java.util.ArrayList<>();
for (TaskListFavorite fav : favorites) {
if ("1".equals(fav.getType()) && fav.getMainId() != null) {
mainIds.add(fav.getMainId());
}
}
java.util.Map<String, TaskList> listMap = new java.util.HashMap<>();
if (!mainIds.isEmpty()) {
List<TaskList> lists = taskListMapper.selectBatchIds(mainIds);
for (TaskList tl : lists) {
listMap.put(tl.getId(), tl);
}
}
List<TaskListFavorite> result = new java.util.ArrayList<>();
for (TaskListFavorite fav : favorites) {
if ("1".equals(fav.getType()) && fav.getMainId() != null) {
TaskList tl = listMap.get(fav.getMainId());
if (tl == null) continue;
Integer listSecLevel = tl.getSecretLevel() != null ? tl.getSecretLevel() : 1;
if (userSecLevel <= listSecLevel) {
continue;
}
fav.setTasklistName(tl.getTasklistName());
fav.setSecretLevel(tl.getSecretLevel());
fav.setSecretText(tl.getSecretText());
LambdaQueryWrapper<TaskListPermission> permQuery = new LambdaQueryWrapper<>();
permQuery.eq(TaskListPermission::getMainId, fav.getMainId());
permQuery.eq(TaskListPermission::getUserId, userId);
TaskListPermission perm = taskListPermissionMapper.selectOne(permQuery);
if (perm != null) {
fav.setPermission(perm.getPermission());
}
result.add(fav);
} else {
result.add(fav);
}
}
return result;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteTaskList(String taskListId) {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String userId = loginUser.getId();
LambdaQueryWrapper<TaskListPermission> permCheck = new LambdaQueryWrapper<>();
permCheck.eq(TaskListPermission::getMainId, taskListId);
permCheck.eq(TaskListPermission::getUserId, userId);
permCheck.eq(TaskListPermission::getPermission, "1");
Long count = taskListPermissionMapper.selectCount(permCheck);
if (count == 0) {
throw new RuntimeException("仅所有者可删除任务清单");
}
taskListMapper.deleteById(taskListId);
LambdaQueryWrapper<TaskListDetial> detailQuery = new LambdaQueryWrapper<>();
detailQuery.eq(TaskListDetial::getMainId, taskListId);
taskListDetialMapper.delete(detailQuery);
LambdaQueryWrapper<TaskListPermission> permQuery = new LambdaQueryWrapper<>();
permQuery.eq(TaskListPermission::getMainId, taskListId);
taskListPermissionMapper.delete(permQuery);
LambdaQueryWrapper<TaskListFavorite> favQuery = new LambdaQueryWrapper<>();
favQuery.eq(TaskListFavorite::getMainId, taskListId);
List<TaskListFavorite> favs = taskListFavoriteMapper.selectList(favQuery);
for (TaskListFavorite fav : favs) {
String favUserId = fav.getUserId();
taskListFavoriteMapper.deleteById(fav.getId());
if (fav.getPid() != null) {
Integer remainCount = taskListFavoriteService.countChildren(favUserId, fav.getPid());
if (remainCount == 0) {
TaskListFavorite parentUpdate = new TaskListFavorite();
parentUpdate.setId(fav.getPid());
parentUpdate.setHasChild("0");
taskListFavoriteMapper.updateById(parentUpdate);
}
}
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void removeFavorite(String favoriteId) {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String userId = loginUser.getId();
TaskListFavorite fav = taskListFavoriteMapper.selectById(favoriteId);
if (fav == null || !userId.equals(fav.getUserId())) {
throw new RuntimeException("无权限操作此记录");
}
taskListFavoriteMapper.deleteById(favoriteId);
if (fav.getPid() != null) {
Integer remainCount = taskListFavoriteService.countChildren(userId, fav.getPid());
if (remainCount == 0) {
TaskListFavorite parentUpdate = new TaskListFavorite();
parentUpdate.setId(fav.getPid());
parentUpdate.setHasChild("0");
taskListFavoriteMapper.updateById(parentUpdate);
}
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void removeFavoriteGroup(String groupId) {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String userId = loginUser.getId();
TaskListFavorite groupFav = taskListFavoriteMapper.selectById(groupId);
if (groupFav == null || !userId.equals(groupFav.getUserId()) || !"0".equals(groupFav.getType())) {
throw new RuntimeException("分组不存在或无权限");
}
taskListFavoriteMapper.deleteById(groupId);
LambdaQueryWrapper<TaskListFavorite> childQuery = new LambdaQueryWrapper<>();
childQuery.eq(TaskListFavorite::getPid, groupId);
childQuery.eq(TaskListFavorite::getUserId, userId);
List<TaskListFavorite> children = taskListFavoriteMapper.selectList(childQuery);
for (TaskListFavorite child : children) {
taskListFavoriteMapper.deleteById(child.getId());
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void renameGroup(String groupId, String newName) {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String userId = loginUser.getId();
TaskListFavorite groupFav = taskListFavoriteMapper.selectById(groupId);
if (groupFav == null || !userId.equals(groupFav.getUserId()) || !"0".equals(groupFav.getType())) {
throw new RuntimeException("分组不存在或无权限");
}
groupFav.setTasklistName(newName);
taskListFavoriteMapper.updateById(groupFav);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void moveGroup(String groupId, Integer sortOrder) {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String userId = loginUser.getId();
TaskListFavorite group = taskListFavoriteMapper.selectById(groupId);
if (group == null || !userId.equals(group.getUserId()) || !"0".equals(group.getType())) {
throw new RuntimeException("分组不存在或无权限");
}
taskListFavoriteService.reorderItem(groupId, userId, null, "0", sortOrder, null);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void renameTaskList(String taskListId, String newName) {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String userId = loginUser.getId();
TaskList taskList = taskListMapper.selectById(taskListId);
if (taskList == null) {
throw new RuntimeException("清单不存在");
}
LambdaQueryWrapper<TaskListPermission> permQuery = new LambdaQueryWrapper<>();
permQuery.eq(TaskListPermission::getMainId, taskListId);
permQuery.eq(TaskListPermission::getUserId, userId);
permQuery.in(TaskListPermission::getPermission, "1", "2");
boolean hasPermission = taskListPermissionMapper.exists(permQuery);
if (!hasPermission) {
throw new RuntimeException("清单不存在或无权限");
}
taskList.setTasklistName(newName);
taskListMapper.updateById(taskList);
LambdaQueryWrapper<TaskListFavorite> favQuery = new LambdaQueryWrapper<>();
favQuery.eq(TaskListFavorite::getMainId, taskListId);
List<TaskListFavorite> favs = taskListFavoriteMapper.selectList(favQuery);
for (TaskListFavorite fav : favs) {
fav.setTasklistName(newName);
taskListFavoriteMapper.updateById(fav);
}
}
@Override
public List<TaskList> getMyOwnLists() {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String userId = loginUser.getId();
Integer userSecLevel = loginUser.getUserSecurityLevel();
if (userSecLevel == null) {
userSecLevel = 3;
}
final Integer finalUserSecLevel = userSecLevel;
LambdaQueryWrapper<TaskListPermission> permQuery = new LambdaQueryWrapper<>();
permQuery.eq(TaskListPermission::getUserId, userId);
permQuery.eq(TaskListPermission::getPermission, "1");
List<TaskListPermission> perms = taskListPermissionMapper.selectList(permQuery);
List<String> mainIds = perms.stream().map(TaskListPermission::getMainId).collect(java.util.stream.Collectors.toList());
if (mainIds.isEmpty()) {
return java.util.Collections.emptyList();
}
LambdaQueryWrapper<TaskList> query = new LambdaQueryWrapper<>();
query.in(TaskList::getId, mainIds);
query.and(w -> w.lt(TaskList::getSecretLevel, finalUserSecLevel).or().isNull(TaskList::getSecretLevel));
query.orderByAsc(TaskList::getCreateTime);
return enrichListSummaries(taskListMapper.selectList(query));
}
@Override
public List<TaskList> getAllLists() {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String userId = loginUser.getId();
Integer userSecLevel = loginUser.getUserSecurityLevel();
if (userSecLevel == null) {
userSecLevel = 3;
}
String orgCode = loginUser.getOrgCode();
List<TaskList> lists = taskListMapper.selectVisibleLists(userId, userSecLevel, orgCode);
return enrichListSummaries(lists);
}
@Override
public List<TaskList> getMyCollabLists() {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String userId = loginUser.getId();
Integer userSecLevel = loginUser.getUserSecurityLevel();
if (userSecLevel == null) {
userSecLevel = 3;
}
final Integer finalUserSecLevel = userSecLevel;
LambdaQueryWrapper<TaskListPermission> permQuery = new LambdaQueryWrapper<>();
permQuery.eq(TaskListPermission::getUserId, userId);
permQuery.ne(TaskListPermission::getPermission, "1");
List<TaskListPermission> perms = taskListPermissionMapper.selectList(permQuery);
List<String> mainIds = perms.stream().map(TaskListPermission::getMainId).collect(java.util.stream.Collectors.toList());
if (mainIds.isEmpty()) {
return java.util.Collections.emptyList();
}
LambdaQueryWrapper<TaskList> query = new LambdaQueryWrapper<>();
query.in(TaskList::getId, mainIds);
query.and(w -> w.lt(TaskList::getSecretLevel, finalUserSecLevel).or().isNull(TaskList::getSecretLevel));
query.orderByAsc(TaskList::getCreateTime);
return enrichListSummaries(taskListMapper.selectList(query));
}
private String normalizePid(String pid) {
return oConvertUtils.isNotEmpty(pid) ? pid : null;
}
private List<TaskList> enrichListSummaries(List<TaskList> lists) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for (TaskList list : lists) {
if (list.getCreateTime() != null) {
list.setCreateTimeStr(sdf.format(list.getCreateTime()));
}
LambdaQueryWrapper<TaskListPermission> ownerQuery = new LambdaQueryWrapper<>();
ownerQuery.eq(TaskListPermission::getMainId, list.getId());
ownerQuery.eq(TaskListPermission::getPermission, "1");
TaskListPermission owner = taskListPermissionMapper.selectOne(ownerQuery);
if (owner != null) {
LoginUser ownerUser = sysBaseAPI.getUserById(owner.getUserId());
if (ownerUser != null) {
list.setOwnerName(ownerUser.getRealname());
}
}
LambdaQueryWrapper<TaskListPermission> collabQuery = new LambdaQueryWrapper<>();
collabQuery.eq(TaskListPermission::getMainId, list.getId());
collabQuery.ne(TaskListPermission::getPermission, "1");
List<TaskListPermission> collabs = taskListPermissionMapper.selectList(collabQuery);
if (!collabs.isEmpty()) {
List<String> collabUserIds = collabs.stream().map(TaskListPermission::getUserId).collect(java.util.stream.Collectors.toList());
List<String> collabNames = new java.util.ArrayList<>();
for (String collabUserId : collabUserIds) {
LoginUser collabUser = sysBaseAPI.getUserById(collabUserId);
if (collabUser != null && collabUser.getRealname() != null) {
collabNames.add(collabUser.getRealname());
}
}
list.setCollaboratorNames(String.join(", ", collabNames));
}
}
return lists;
}
@Override
public List<CollaboratorVO> getCollaborators(String taskListId) {
LambdaQueryWrapper<TaskListPermission> query = new LambdaQueryWrapper<>();
query.eq(TaskListPermission::getMainId, taskListId);
query.orderByAsc(TaskListPermission::getCreateTime);
List<TaskListPermission> perms = taskListPermissionMapper.selectList(query);
List<CollaboratorVO> result = new java.util.ArrayList<>();
for (TaskListPermission perm : perms) {
CollaboratorVO vo = new CollaboratorVO();
vo.setPermissionId(perm.getId());
vo.setUserId(perm.getUserId());
vo.setPermission(perm.getPermission());
LoginUser user = sysBaseAPI.getUserById(perm.getUserId());
if (user != null) {
vo.setUsername(user.getRealname());
}
result.add(vo);
}
return result;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void addCollaborator(AddCollaboratorReq req) {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String currentUserId = loginUser.getId();
LambdaQueryWrapper<TaskListPermission> ownerCheck = new LambdaQueryWrapper<>();
ownerCheck.eq(TaskListPermission::getMainId, req.getTaskListId());
ownerCheck.eq(TaskListPermission::getUserId, currentUserId);
ownerCheck.eq(TaskListPermission::getPermission, "1");
Long ownerCount = taskListPermissionMapper.selectCount(ownerCheck);
if (ownerCount == 0) {
throw new RuntimeException("仅所有者可添加协作人");
}
if (!"2".equals(req.getPermission()) && !"3".equals(req.getPermission())) {
throw new RuntimeException("权限类型无效,仅支持可阅读(2)或可编辑(3)");
}
TaskList taskList = taskListMapper.selectById(req.getTaskListId());
if (taskList == null) {
throw new RuntimeException("清单不存在");
}
LoginUser targetUser = sysBaseAPI.getUserById(req.getUserId());
if (targetUser == null) {
throw new RuntimeException("用户不存在");
}
Integer targetUserSecLevel = targetUser.getUserSecurityLevel();
Integer listSecLevel = taskList.getSecretLevel();
if (listSecLevel == null) {
listSecLevel = 1;
}
if (targetUserSecLevel == null) {
targetUserSecLevel = 3;
}
if (targetUserSecLevel <= listSecLevel) {
throw new RuntimeException("该用户密级不足,无法添加为协作人");
}
LambdaQueryWrapper<TaskListPermission> existCheck = new LambdaQueryWrapper<>();
existCheck.eq(TaskListPermission::getMainId, req.getTaskListId());
existCheck.eq(TaskListPermission::getUserId, req.getUserId());
Long existCount = taskListPermissionMapper.selectCount(existCheck);
if (existCount > 0) {
throw new RuntimeException("该用户已是协作人");
}
TaskListPermission permission = new TaskListPermission();
permission.setMainId(req.getTaskListId());
permission.setUserId(req.getUserId());
permission.setPermission(req.getPermission());
taskListPermissionMapper.insert(permission);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void removeCollaborator(String permissionId) {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String currentUserId = loginUser.getId();
TaskListPermission perm = taskListPermissionMapper.selectById(permissionId);
if (perm == null) {
throw new RuntimeException("权限记录不存在");
}
if ("1".equals(perm.getPermission())) {
throw new RuntimeException("不能移除所有者");
}
LambdaQueryWrapper<TaskListPermission> ownerCheck = new LambdaQueryWrapper<>();
ownerCheck.eq(TaskListPermission::getMainId, perm.getMainId());
ownerCheck.eq(TaskListPermission::getUserId, currentUserId);
ownerCheck.eq(TaskListPermission::getPermission, "1");
Long ownerCount = taskListPermissionMapper.selectCount(ownerCheck);
if (ownerCount == 0) {
throw new RuntimeException("仅所有者可移除协作人");
}
taskListPermissionMapper.deleteById(permissionId);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateCollaboratorPermission(String permissionId, String newPermission) {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String currentUserId = loginUser.getId();
TaskListPermission perm = taskListPermissionMapper.selectById(permissionId);
if (perm == null) {
throw new RuntimeException("权限记录不存在");
}
if ("1".equals(perm.getPermission())) {
throw new RuntimeException("不能修改所有者权限");
}
if (!"2".equals(newPermission) && !"3".equals(newPermission)) {
throw new RuntimeException("权限类型无效");
}
LambdaQueryWrapper<TaskListPermission> ownerCheck = new LambdaQueryWrapper<>();
ownerCheck.eq(TaskListPermission::getMainId, perm.getMainId());
ownerCheck.eq(TaskListPermission::getUserId, currentUserId);
ownerCheck.eq(TaskListPermission::getPermission, "1");
Long ownerCount = taskListPermissionMapper.selectCount(ownerCheck);
if (ownerCount == 0) {
throw new RuntimeException("仅所有者可修改协作人权限");
}
TaskListPermission update = new TaskListPermission();
update.setId(permissionId);
update.setPermission(newPermission);
taskListPermissionMapper.updateById(update);
}
@Override
public String getMyPermission(String taskListId) {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String userId = loginUser.getId();
LambdaQueryWrapper<TaskListPermission> query = new LambdaQueryWrapper<>();
query.eq(TaskListPermission::getMainId, taskListId);
query.eq(TaskListPermission::getUserId, userId);
TaskListPermission perm = taskListPermissionMapper.selectOne(query);
return perm != null ? perm.getPermission() : null;
}
@Override
public void addToFavorites(String taskListId, String pid) {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
String userId = loginUser.getId();
Integer userSecLevel = loginUser.getUserSecurityLevel();
if (userSecLevel == null) {
userSecLevel = 3;
}
TaskList taskList = taskListMapper.selectById(taskListId);
if (taskList == null) {
throw new RuntimeException("清单不存在");
}
Integer listSecLevel = taskList.getSecretLevel();
if (listSecLevel == null) {
listSecLevel = 1;
}
if (userSecLevel <= listSecLevel) {
throw new RuntimeException("您无权收藏该密级的清单");
}
LambdaQueryWrapper<TaskListFavorite> existCheck = new LambdaQueryWrapper<>();
existCheck.eq(TaskListFavorite::getMainId, taskListId);
existCheck.eq(TaskListFavorite::getUserId, userId);
existCheck.eq(TaskListFavorite::getType, "1");
existCheck.eq(TaskListFavorite::getDelFlag, "0");
TaskListFavorite existFav = taskListFavoriteMapper.selectOne(existCheck);
if (existFav != null) {
throw new RuntimeException("该清单已在收藏中");
}
LambdaQueryWrapper<TaskListFavorite> reactivateCheck = new LambdaQueryWrapper<>();
reactivateCheck.eq(TaskListFavorite::getMainId, taskListId);
reactivateCheck.eq(TaskListFavorite::getUserId, userId);
reactivateCheck.eq(TaskListFavorite::getType, "1");
reactivateCheck.eq(TaskListFavorite::getDelFlag, "1");
TaskListFavorite softDeletedFav = taskListFavoriteMapper.selectOne(reactivateCheck);
if (softDeletedFav != null) {
UpdateWrapper<TaskListFavorite> uw = new UpdateWrapper<>();
uw.eq("id", softDeletedFav.getId());
uw.set("del_flag", "0");
taskListFavoriteMapper.update(null, uw);
if (softDeletedFav.getPid() != null) {
TaskListFavorite parentUpdate = new TaskListFavorite();
parentUpdate.setId(softDeletedFav.getPid());
parentUpdate.setHasChild("1");
taskListFavoriteMapper.updateById(parentUpdate);
}
return;
}
String normalizedPid = oConvertUtils.isNotEmpty(pid) ? pid : null;
if (normalizedPid != null) {
TaskListFavorite groupFav = taskListFavoriteMapper.selectById(normalizedPid);
if (groupFav == null || !"0".equals(groupFav.getType()) || !userId.equals(groupFav.getUserId())) {
throw new RuntimeException("目标分组不存在或无权限");
}
}
Integer maxSort = taskListFavoriteService.getMaxSortOrderByType(userId, normalizedPid, "1");
TaskListFavorite favorite = new TaskListFavorite();
favorite.setMainId(taskListId);
favorite.setUserId(userId);
favorite.setType("1");
favorite.setPid(normalizedPid);
favorite.setHasChild("0");
favorite.setSortOrder(maxSort + 1);
favorite.setTasklistName(taskList.getTasklistName());
taskListFavoriteMapper.insert(favorite);
if (normalizedPid != null) {
TaskListFavorite parentFav = new TaskListFavorite();
parentFav.setId(normalizedPid);
parentFav.setHasChild("1");
taskListFavoriteMapper.updateById(parentFav);
}
}
@Override
public List<TaskListDetial> myResponsibleTasks() {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
return taskListDetialMapper.selectByAssigneeId(loginUser.getId(), loginUser.getId());
}
@Override
public List<TaskListDetial> myFollowedTasks() {
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
return taskListDetialMapper.selectByFollowersId(loginUser.getId(), loginUser.getId());
}
private String getSecretText(Integer level) {
if (level == null) return "非密";
switch (level) {
case 1: return "非密";
case 2: return "内部";
case 3: return "秘密";
case 4: return "机密";
default: return "非密";
}
}
private String filterUsersBySecLevel(String userIds, Integer listSecLevel) {
if (oConvertUtils.isEmpty(userIds)) return userIds;
if (listSecLevel == null) {
listSecLevel = 1;
}
String[] ids = userIds.split(",");
java.util.List<String> validIds = new java.util.ArrayList<>();
for (String id : ids) {
LoginUser user = sysBaseAPI.getUserById(id.trim());
if (user == null) {
continue;
}
Integer userSecLevel = user.getUserSecurityLevel();
if (userSecLevel == null) {
userSecLevel = 3;
}
if (userSecLevel > listSecLevel) {
validIds.add(id.trim());
}
}
return String.join(",", validIds);
}
}
@@ -0,0 +1,18 @@
package org.jeecg.modules.demo.tasklist.vo;
import lombok.Data;
import io.swagger.v3.oas.annotations.media.Schema;
@Data
@Schema(description = "添加协作人请求")
public class AddCollaboratorReq {
@Schema(description = "清单ID")
private String taskListId;
@Schema(description = "被添加的用户ID")
private String userId;
@Schema(description = "权限类型: 2=可编辑 3=可阅读")
private String permission;
}
@@ -0,0 +1,21 @@
package org.jeecg.modules.demo.tasklist.vo;
import lombok.Data;
import io.swagger.v3.oas.annotations.media.Schema;
@Data
@Schema(description = "协作人信息")
public class CollaboratorVO {
@Schema(description = "权限记录ID")
private String permissionId;
@Schema(description = "用户ID")
private String userId;
@Schema(description = "用户姓名")
private String username;
@Schema(description = "权限类型: 1=所有者 2=可编辑 3=可阅读")
private String permission;
}
@@ -0,0 +1,12 @@
package org.jeecg.modules.demo.tasklist.vo;
import lombok.Data;
import io.swagger.v3.oas.annotations.media.Schema;
@Data
@Schema(description = "创建任务清单分组请求")
public class CreateTaskListGroupReq {
@Schema(description = "分组名称")
private String tasklistName;
}
@@ -0,0 +1,21 @@
package org.jeecg.modules.demo.tasklist.vo;
import lombok.Data;
import io.swagger.v3.oas.annotations.media.Schema;
@Data
@Schema(description = "创建任务清单请求")
public class CreateTaskListReq {
@Schema(description = "清单名称")
private String tasklistName;
@Schema(description = "父分组ID(可选,不传则放在根级别)")
private String pid;
@Schema(description = "目标排序位置(可选,不传则追加到末尾)")
private Integer sortOrder;
@Schema(description = "密级:1=非密,2=内部,3=秘密,4=机密")
private Integer secretLevel;
}
@@ -0,0 +1,45 @@
package org.jeecg.modules.demo.tasklist.vo;
import lombok.Data;
import io.swagger.v3.oas.annotations.media.Schema;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
@Data
@Schema(description = "创建任务请求")
public class CreateTaskReq {
@Schema(description = "所属清单ID")
private String mainId;
@Schema(description = "任务名称")
private String taskName;
@Schema(description = "任务描述")
private String taskDesc;
@Schema(description = "优先级")
private String priority;
@Schema(description = "类型:0=任务分组,1=普通任务")
private String type;
@Schema(description = "父节点ID(分组ID或父任务ID,为空则归入默认分组)")
private String pid;
@Schema(description = "负责人ID")
private String assigneeId;
@Schema(description = "开始时间")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private java.util.Date startTime;
@Schema(description = "结束时间")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private java.util.Date endTime;
@Schema(description = "排序号(指定则在指定位置插入)")
private Integer sortOrder;
}
@@ -0,0 +1,18 @@
package org.jeecg.modules.demo.tasklist.vo;
import lombok.Data;
import io.swagger.v3.oas.annotations.media.Schema;
@Data
@Schema(description = "拖拽移动任务清单请求")
public class MoveTaskListReq {
@Schema(description = "被移动的清单对应的 favorite 记录ID")
private String favoriteId;
@Schema(description = "目标分组ID(null 或空字符串表示移动到根级别)")
private String targetGroupId;
@Schema(description = "目标位置排序号(可选,不传则追加到末尾)")
private Integer sortOrder;
}
@@ -0,0 +1,18 @@
package org.jeecg.modules.demo.tasklist.vo;
import lombok.Data;
import io.swagger.v3.oas.annotations.media.Schema;
@Data
@Schema(description = "拖拽移动任务请求")
public class MoveTaskReq {
@Schema(description = "任务ID")
private String taskId;
@Schema(description = "目标父节点ID(分组ID或父任务ID,为空表示移入默认分组)")
private String targetPid;
@Schema(description = "目标位置排序号(可选,不传则追加到末尾)")
private Integer targetSortOrder;
}
@@ -0,0 +1,18 @@
package org.jeecg.modules.demo.tasklist.vo;
import lombok.Data;
import io.swagger.v3.oas.annotations.media.Schema;
@Data
@Schema(description = "子任务分页请求")
public class SubTaskPageReq {
@Schema(description = "父任务ID")
private String parentTaskId;
@Schema(description = "页码,默认1")
private Integer pageNo = 1;
@Schema(description = "每页条数,默认20")
private Integer pageSize = 20;
}
@@ -0,0 +1,82 @@
package org.jeecg.modules.demo.tasklist.vo;
import java.util.List;
import org.jeecg.modules.demo.tasklist.entity.TaskList;
import org.jeecg.modules.demo.tasklist.entity.TaskListDetial;
import org.jeecg.modules.demo.tasklist.entity.TaskListPermission;
import org.jeecg.modules.demo.tasklist.entity.TaskListFavorite;
import lombok.Data;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.jeecgframework.poi.excel.annotation.ExcelEntity;
import org.jeecgframework.poi.excel.annotation.ExcelCollection;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import org.jeecg.common.aspect.annotation.Dict;
import org.jeecg.common.constant.ProvinceCityArea;
import org.jeecg.common.util.SpringContextUtils;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* @Description: 任务清单表
* @Author: jeecg-boot
* @Date: 2026-04-24
* @Version: V1.0
*/
@Data
@Schema(description="任务清单表")
public class TaskListPage {
/**主键*/
@Schema(description = "主键")
private java.lang.String id;
/**创建人*/
@Schema(description = "创建人")
private java.lang.String createBy;
/**创建日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "创建日期")
private java.util.Date createTime;
/**更新人*/
@Schema(description = "更新人")
private java.lang.String updateBy;
/**更新日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "更新日期")
private java.util.Date updateTime;
/**所属部门*/
@Schema(description = "所属部门")
private java.lang.String sysOrgCode;
/**清单名称*/
@Excel(name = "清单名称", width = 15)
@Schema(description = "清单名称")
private java.lang.String tasklistName;
/**删除标识*/
@Excel(name = "删除标识", width = 15)
@Schema(description = "删除标识")
private java.lang.String delFlag;
@ExcelCollection(name="任务清单详情表")
@Schema(description = "任务清单详情表")
private List<TaskListDetial> taskListDetialList;
@ExcelCollection(name="任务清单权限表")
@Schema(description = "任务清单权限表")
private List<TaskListPermission> taskListPermissionList;
/**密级: 1=非密, 2=内部, 3=秘密, 4=机密*/
@Excel(name = "密级", width = 15)
@Schema(description = "密级:1=非密,2=内部,3=秘密,4=机密")
private java.lang.Integer secretLevel;
/**密级文本*/
@Excel(name = "密级文本", width = 15)
@Schema(description = "密级文本")
private java.lang.String secretText;
@ExcelCollection(name="任务清单收藏表")
@Schema(description = "任务清单收藏表")
private List<TaskListFavorite> taskListFavoriteList;
}
@@ -1,270 +0,0 @@
package org.jeecg.modules.test.controller;
import java.io.UnsupportedEncodingException;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.HashMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.jeecg.common.system.vo.LoginUser;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.query.QueryRuleEnum;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.test.entity.TestSonTable;
import org.jeecg.modules.test.entity.TestMainTable;
import org.jeecg.modules.test.vo.TestMainTablePage;
import org.jeecg.modules.test.service.ITestMainTableService;
import org.jeecg.modules.test.service.ITestSonTableService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import com.alibaba.fastjson.JSON;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.apache.shiro.authz.annotation.RequiresPermissions;
/**
* @Description: test
* @Author: jeecg-boot
* @Date: 2026-04-03
* @Version: V1.0
*/
@Tag(name="test")
@RestController
@RequestMapping("/test/testMainTable")
@Slf4j
public class TestMainTableController {
@Autowired
private ITestMainTableService testMainTableService;
@Autowired
private ITestSonTableService testSonTableService;
/**
* 分页列表查询
*
* @param testMainTable
* @param pageNo
* @param pageSize
* @param req
* @return
*/
//@AutoLog(value = "test-分页列表查询")
@Operation(summary="test-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<TestMainTable>> queryPageList(TestMainTable testMainTable,
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<TestMainTable> queryWrapper = QueryGenerator.initQueryWrapper(testMainTable, req.getParameterMap());
Page<TestMainTable> page = new Page<TestMainTable>(pageNo, pageSize);
IPage<TestMainTable> pageList = testMainTableService.page(page, queryWrapper);
return Result.OK(pageList);
}
/**
* 添加
*
* @param testMainTablePage
* @return
*/
@AutoLog(value = "test-添加")
@Operation(summary="test-添加")
@RequiresPermissions("test:test_main_table:add")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody TestMainTablePage testMainTablePage) {
TestMainTable testMainTable = new TestMainTable();
BeanUtils.copyProperties(testMainTablePage, testMainTable);
testMainTableService.saveMain(testMainTable, testMainTablePage.getTestSonTableList());
return Result.OK("添加成功!");
}
/**
* 编辑
*
* @param testMainTablePage
* @return
*/
@AutoLog(value = "test-编辑")
@Operation(summary="test-编辑")
@RequiresPermissions("test:test_main_table:edit")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<String> edit(@RequestBody TestMainTablePage testMainTablePage) {
TestMainTable testMainTable = new TestMainTable();
BeanUtils.copyProperties(testMainTablePage, testMainTable);
TestMainTable testMainTableEntity = testMainTableService.getById(testMainTable.getId());
if(testMainTableEntity==null) {
return Result.error("未找到对应数据");
}
testMainTableService.updateMain(testMainTable, testMainTablePage.getTestSonTableList());
return Result.OK("编辑成功!");
}
/**
* 通过id删除
*
* @param id
* @return
*/
@AutoLog(value = "test-通过id删除")
@Operation(summary="test-通过id删除")
@RequiresPermissions("test:test_main_table:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
testMainTableService.delMain(id);
return Result.OK("删除成功!");
}
/**
* 批量删除
*
* @param ids
* @return
*/
@AutoLog(value = "test-批量删除")
@Operation(summary="test-批量删除")
@RequiresPermissions("test:test_main_table:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
this.testMainTableService.delBatchMain(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}
/**
* 通过id查询
*
* @param id
* @return
*/
//@AutoLog(value = "test-通过id查询")
@Operation(summary="test-通过id查询")
@GetMapping(value = "/queryById")
public Result<TestMainTable> queryById(@RequestParam(name="id",required=true) String id) {
TestMainTable testMainTable = testMainTableService.getById(id);
if(testMainTable==null) {
return Result.error("未找到对应数据");
}
return Result.OK(testMainTable);
}
/**
* 通过id查询
*
* @param id
* @return
*/
//@AutoLog(value = "test通过主表ID查询")
@Operation(summary="test主表ID查询")
@GetMapping(value = "/queryTestSonTableByMainId")
public Result<List<TestSonTable>> queryTestSonTableListByMainId(@RequestParam(name="id",required=true) String id) {
List<TestSonTable> testSonTableList = testSonTableService.selectByMainId(id);
return Result.OK(testSonTableList);
}
/**
* 导出excel
*
* @param request
* @param testMainTable
*/
@RequiresPermissions("test:test_main_table:exportXls")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, TestMainTable testMainTable) {
// Step.1 组装查询条件查询数据
QueryWrapper<TestMainTable> queryWrapper = QueryGenerator.initQueryWrapper(testMainTable, request.getParameterMap());
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
//配置选中数据查询条件
String selections = request.getParameter("selections");
if(oConvertUtils.isNotEmpty(selections)) {
List<String> selectionList = Arrays.asList(selections.split(","));
queryWrapper.in("id",selectionList);
}
//Step.2 获取导出数据
List<TestMainTable> testMainTableList = testMainTableService.list(queryWrapper);
// Step.3 组装pageList
List<TestMainTablePage> pageList = new ArrayList<TestMainTablePage>();
for (TestMainTable main : testMainTableList) {
TestMainTablePage vo = new TestMainTablePage();
BeanUtils.copyProperties(main, vo);
List<TestSonTable> testSonTableList = testSonTableService.selectByMainId(main.getId());
vo.setTestSonTableList(testSonTableList);
pageList.add(vo);
}
// Step.4 AutoPoi 导出Excel
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
mv.addObject(NormalExcelConstants.FILE_NAME, "test列表");
mv.addObject(NormalExcelConstants.CLASS, TestMainTablePage.class);
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("test数据", "导出人:"+sysUser.getRealname(), "test"));
mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
return mv;
}
/**
* 通过excel导入数据
*
* @param request
* @param response
* @return
*/
@RequiresPermissions("test:test_main_table:importExcel")
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
// 获取上传文件对象
MultipartFile file = entity.getValue();
ImportParams params = new ImportParams();
params.setTitleRows(2);
params.setHeadRows(1);
params.setNeedSave(true);
try {
List<TestMainTablePage> list = ExcelImportUtil.importExcel(file.getInputStream(), TestMainTablePage.class, params);
for (TestMainTablePage page : list) {
TestMainTable po = new TestMainTable();
BeanUtils.copyProperties(page, po);
testMainTableService.saveMain(po, page.getTestSonTableList());
}
return Result.OK("文件导入成功!数据行数:" + list.size());
} catch (Exception e) {
log.error(e.getMessage(),e);
return Result.error("文件导入失败:"+e.getMessage());
} finally {
try {
file.getInputStream().close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return Result.OK("文件导入失败!");
}
}
@@ -1,62 +0,0 @@
package org.jeecg.modules.test.entity;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableLogic;
import org.jeecg.common.constant.ProvinceCityArea;
import org.jeecg.common.util.SpringContextUtils;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import org.jeecgframework.poi.excel.annotation.Excel;
import java.util.Date;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.UnsupportedEncodingException;
/**
* @Description: test
* @Author: jeecg-boot
* @Date: 2026-04-03
* @Version: V1.0
*/
@Schema(description="test")
@Data
@TableName("test_son_table")
public class TestSonTable implements Serializable {
private static final long serialVersionUID = 1L;
/**主键*/
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
private String id;
/**创建人*/
@Schema(description = "创建人")
private String createBy;
/**创建日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "创建日期")
private Date createTime;
/**更新人*/
@Schema(description = "更新人")
private String updateBy;
/**更新日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "更新日期")
private Date updateTime;
/**所属部门*/
@Schema(description = "所属部门")
private String sysOrgCode;
/**字段c*/
@Excel(name = "字段c", width = 15)
@Schema(description = "字段c")
private String fieldC;
/**主表id*/
@Schema(description = "主表id")
private String mainTableId;
@TableLogic(value = "0", delval = "1")
private int delFlag = 0;
}
@@ -1,17 +0,0 @@
package org.jeecg.modules.test.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.jeecg.modules.test.entity.TestMainTable;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @Description: test
* @Author: jeecg-boot
* @Date: 2026-04-03
* @Version: V1.0
*/
public interface TestMainTableMapper extends BaseMapper<TestMainTable> {
}
@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.jeecg.modules.test.mapper.TestMainTableMapper">
</mapper>
@@ -1,48 +0,0 @@
package org.jeecg.modules.test.service;
import org.jeecg.modules.test.entity.TestSonTable;
import org.jeecg.modules.test.entity.TestMainTable;
import com.baomidou.mybatisplus.extension.service.IService;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
/**
* @Description: test
* @Author: jeecg-boot
* @Date: 2026-04-03
* @Version: V1.0
*/
public interface ITestMainTableService extends IService<TestMainTable> {
/**
* 添加一对多
*
* @param testMainTable
* @param testSonTableList
*/
public void saveMain(TestMainTable testMainTable,List<TestSonTable> testSonTableList) ;
/**
* 修改一对多
*
* @param testMainTable
* @param testSonTableList
*/
public void updateMain(TestMainTable testMainTable,List<TestSonTable> testSonTableList);
/**
* 删除一对多
*
* @param id
*/
public void delMain (String id);
/**
* 批量删除一对多
*
* @param idList
*/
public void delBatchMain (Collection<? extends Serializable> idList);
}
@@ -1,22 +0,0 @@
package org.jeecg.modules.test.service;
import org.jeecg.modules.test.entity.TestSonTable;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* @Description: test
* @Author: jeecg-boot
* @Date: 2026-04-03
* @Version: V1.0
*/
public interface ITestSonTableService extends IService<TestSonTable> {
/**
* 通过主表id查询子表数据
*
* @param mainId 主表id
* @return List<TestSonTable>
*/
public List<TestSonTable> selectByMainId(String mainId);
}
@@ -1,83 +0,0 @@
package org.jeecg.modules.test.service.impl;
import org.jeecg.common.aspect.annotation.CascadeDelete;
import org.jeecg.common.aspect.annotation.SonTable;
import org.jeecg.modules.test.entity.TestMainTable;
import org.jeecg.modules.test.entity.TestSonTable;
import org.jeecg.modules.test.mapper.TestSonTableMapper;
import org.jeecg.modules.test.mapper.TestMainTableMapper;
import org.jeecg.modules.test.service.ITestMainTableService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.util.List;
import java.util.Collection;
import org.jeecg.common.aspect.annotation.AutoLog;
/**
* @Description: test
* @Author: jeecg-boot
* @Date: 2026-04-03
* @Version: V1.0
*/
@Service
public class TestMainTableServiceImpl extends ServiceImpl<TestMainTableMapper, TestMainTable> implements ITestMainTableService {
@Autowired
private TestMainTableMapper testMainTableMapper;
@Autowired
private TestSonTableMapper testSonTableMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public void saveMain(TestMainTable testMainTable, List<TestSonTable> testSonTableList) {
testMainTableMapper.insert(testMainTable);
if(testSonTableList!=null && testSonTableList.size()>0) {
for(TestSonTable entity:testSonTableList) {
//外键设置
entity.setMainTableId(testMainTable.getId());
testSonTableMapper.insert(entity);
}
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateMain(TestMainTable testMainTable,List<TestSonTable> testSonTableList) {
testMainTableMapper.updateById(testMainTable);
//1.先删除子表数据
testSonTableMapper.deleteByMainId(testMainTable.getId());
//2.子表数据重新插入
if(testSonTableList!=null && testSonTableList.size()>0) {
for(TestSonTable entity:testSonTableList) {
//外键设置
entity.setMainTableId(testMainTable.getId());
testSonTableMapper.insert(entity);
}
}
}
@Override
@Transactional(rollbackFor = Exception.class)
@CascadeDelete(sons = {
// 配置子表1:Mapper类 + 子表中关联主表的字段名
@SonTable(mapper = TestSonTableMapper.class, joinColumn = "main_table_id"),
})
public void delMain(String id) {
testMainTableMapper.deleteById(id);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void delBatchMain(Collection<? extends Serializable> idList) {
for(Serializable id:idList) {
testSonTableMapper.deleteByMainId(id.toString());
testMainTableMapper.deleteById(id);
}
}
}
@@ -1,27 +0,0 @@
package org.jeecg.modules.test.service.impl;
import org.jeecg.modules.test.entity.TestSonTable;
import org.jeecg.modules.test.mapper.TestSonTableMapper;
import org.jeecg.modules.test.service.ITestSonTableService;
import org.springframework.stereotype.Service;
import java.util.List;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
/**
* @Description: test
* @Author: jeecg-boot
* @Date: 2026-04-03
* @Version: V1.0
*/
@Service
public class TestSonTableServiceImpl extends ServiceImpl<TestSonTableMapper, TestSonTable> implements ITestSonTableService {
@Autowired
private TestSonTableMapper testSonTableMapper;
@Override
public List<TestSonTable> selectByMainId(String mainId) {
return testSonTableMapper.selectByMainId(mainId);
}
}
@@ -1,64 +0,0 @@
package org.jeecg.modules.test.vo;
import java.util.List;
import org.jeecg.modules.test.entity.TestMainTable;
import org.jeecg.modules.test.entity.TestSonTable;
import lombok.Data;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.jeecgframework.poi.excel.annotation.ExcelEntity;
import org.jeecgframework.poi.excel.annotation.ExcelCollection;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import org.jeecg.common.aspect.annotation.Dict;
import org.jeecg.common.constant.ProvinceCityArea;
import org.jeecg.common.util.SpringContextUtils;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* @Description: test
* @Author: jeecg-boot
* @Date: 2026-04-03
* @Version: V1.0
*/
@Data
@Schema(description="test")
public class TestMainTablePage {
/**主键*/
@Schema(description = "主键")
private String id;
/**创建人*/
@Schema(description = "创建人")
private String createBy;
/**创建日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "创建日期")
private Date createTime;
/**更新人*/
@Schema(description = "更新人")
private String updateBy;
/**更新日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "更新日期")
private Date updateTime;
/**所属部门*/
@Schema(description = "所属部门")
private String sysOrgCode;
/**a字段*/
@Excel(name = "a字段", width = 15)
@Schema(description = "a字段")
private String fieldA;
/**b字段*/
@Excel(name = "b字段", width = 15)
@Schema(description = "b字段")
private String fieldB;
@ExcelCollection(name="test")
@Schema(description = "test")
private List<TestSonTable> testSonTableList;
}
@@ -564,4 +564,6 @@ public interface ISysBaseAPI extends CommonAPI {
String updateBusinessId(String businessId, List<String> deliverablesList);
List<String> getUsersListByJsonLocalAPI(Object jsonData, String deptKeyName, String roleId);
List<String> getUsersListByDeptIdAndRoleIdLocalApi(String deptId, String roleId);
}
@@ -545,10 +545,10 @@ public class SysUserController {
*/
@RequestMapping(value = "/queryUserByDeptAndROle", method = RequestMethod.GET)
@Operation(summary = "根据角色ID,部门ID以及用户密级查询当前用户列表", description = "原生用户查询逻辑加上密级筛选以及角色筛选") // 2. 接口描述
public Result<List<SysUser>> queryUserByDeptAndROle(DeptRoleVO deptRoleVO
public Result<List<String>> queryUserByDeptAndROle(DeptRoleVO deptRoleVO
) {
try {
List<SysUser> sysUserList = sysUserService.queryUserByDeptAndROle(
List<String> sysUserList = sysUserService.queryUserByDeptAndROle(
deptRoleVO.getDeptId(),
deptRoleVO.getRoleId(),
deptRoleVO.getSecretLevel()
@@ -495,5 +495,5 @@ public interface ISysUserService extends IService<SysUser> {
*/
void updatePasswordNotBindPhone(String oldPassword, String password, String username);
List<SysUser> queryUserByDeptAndROle(@NotBlank(message = "deptId不为空") String deptId, @NotBlank(message = "角色id不为空") String roleId, @NotBlank(message = "secretLevel不为空") Integer secretLevel);
List<String> queryUserByDeptAndROle(@NotBlank(message = "deptId不为空") String deptId, @NotBlank(message = "角色id不为空") String roleId, @NotBlank(message = "secretLevel不为空") Integer secretLevel);
}
@@ -2100,6 +2100,7 @@ public class SysBaseApiImpl implements ISysBaseAPI {
return "";
}
@Override
public List<String> getUsersListByJsonLocalAPI(Object jsonData, String deptKeyName, String roleId) {
if (jsonData == null || StringUtils.isEmpty(deptKeyName) || StringUtils.isEmpty(roleId)) {
return Collections.emptyList();
@@ -2126,7 +2127,21 @@ public class SysBaseApiImpl implements ISysBaseAPI {
return Collections.emptyList();
}
List<SysUser> sysUserList = sysUserService.queryUserByDeptAndROle(
List<String> sysUserList = sysUserService.queryUserByDeptAndROle(
deptId,
roleId,
UserSecretLevel.SECRET_LEVEL_NONE
);
return Optional.ofNullable(sysUserList)
.orElse(Collections.emptyList())
.stream()
.collect(Collectors.toList());
}
@Override
public List<String> getUsersListByDeptIdAndRoleIdLocalApi(String deptId, String roleId){
List<String> sysUserList = sysUserService.queryUserByDeptAndROle(
deptId,
roleId,
UserSecretLevel.SECRET_LEVEL_NONE
@@ -2135,7 +2150,6 @@ public class SysBaseApiImpl implements ISysBaseAPI {
return Optional.ofNullable(sysUserList)
.orElse(Collections.emptyList())
.stream()
.map(SysUser::getUsername)
.collect(Collectors.toList());
}
}
@@ -2416,7 +2416,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
}
@Override
public List<SysUser> queryUserByDeptAndROle(@NotBlank(message = "deptId不为空") String deptId, @NotBlank(message = "角色id不为空") String roleId, @NotBlank(message = "secretLevel不为空") Integer secretLevel){
return sysUserMapper.queryUserByDeptAndROle(deptId,roleId,secretLevel);
public List<String> queryUserByDeptAndROle(@NotBlank(message = "deptId不为空") String deptId, @NotBlank(message = "角色id不为空") String roleId, @NotBlank(message = "secretLevel不为空") Integer secretLevel){
return sysUserMapper.queryUserByDeptAndROle(deptId,roleId,secretLevel).stream().map(SysUser::getUsername).collect(Collectors.toList()) ;
}
}
@@ -27,6 +27,10 @@
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-module-supervision</artifactId>
</dependency>
<dependency>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-module-flow</artifactId>
</dependency>
<!-- flyway 数据库自动升级 -->
<dependency>
@@ -40,6 +40,9 @@ public class JeecgSystemApplication extends SpringBootServletInitializer {
"Swagger文档: \thttp://" + ip + ":" + port + path + "/doc.html\n" +
"----------------------------------------------------------");
// 检查是否有 xiSpeakFlow 这个 Bean
boolean exists = application.containsBean("xiSpeakFlow");
System.out.println("★★★ xiSpeakFlow 是否加载成功: " + exists);
}
}