diff --git a/src/main/java/com/sa/zentao/constants/ExportConstants.java b/src/main/java/com/sa/zentao/constants/ExportConstants.java
new file mode 100644
index 0000000..70e20dd
--- /dev/null
+++ b/src/main/java/com/sa/zentao/constants/ExportConstants.java
@@ -0,0 +1,37 @@
+package com.sa.zentao.constants;
+
+/**
+ * 导出相关常量
+ */
+public class ExportConstants {
+
+ /**
+ * 导出最大记录数
+ */
+ public static final int MAX_EXPORT_SIZE = 1000000;
+
+ /**
+ * Excel sheet 名称
+ */
+ public static final String SHEET_NAME = "sheet1";
+
+ /**
+ * URL 编码空格
+ */
+ public static final String URL_SPACE_ENCODE = "%20";
+
+ /**
+ * 字符串分隔符
+ */
+ public static final String STRING_SEPARATOR = ":";
+
+ /**
+ * ID 分隔符
+ */
+ public static final String ID_SEPARATOR = ",";
+
+ /**
+ * 逗号替换为空字符串
+ */
+ public static final String COMMA_REPLACE = "";
+}
\ No newline at end of file
diff --git a/src/main/java/com/sa/zentao/controller/ZtProductController.java b/src/main/java/com/sa/zentao/controller/ZtProductController.java
index a359f87..76d3293 100644
--- a/src/main/java/com/sa/zentao/controller/ZtProductController.java
+++ b/src/main/java/com/sa/zentao/controller/ZtProductController.java
@@ -160,4 +160,9 @@ public class ZtProductController {
public Result projectTeamById(@RequestBody ZtProjectQo qo){
return Result.success(this.ztProductService.productTeamByPid(qo));
}
+
+ @RequestMapping(value = "/getExecutionByProductId", method = RequestMethod.POST, produces = "application/json; charset=UTF-8")
+ public Result getExecutionByProductId(@RequestBody ZtProjectQo qo){
+ return Result.success(ztProductService.getExecutionByProductId(qo));
+ }
}
diff --git a/src/main/java/com/sa/zentao/dao/ZtStoryUserDTO.java b/src/main/java/com/sa/zentao/dao/ZtStoryUserDTO.java
index 0ce81ab..715f30c 100644
--- a/src/main/java/com/sa/zentao/dao/ZtStoryUserDTO.java
+++ b/src/main/java/com/sa/zentao/dao/ZtStoryUserDTO.java
@@ -2,21 +2,25 @@ package com.sa.zentao.dao;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.metadata.data.HyperlinkData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
+import com.sa.zentao.entity.ZtProject;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NonNull;
+import lombok.extern.slf4j.Slf4j;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
+import java.util.Set;
/**
*
@@ -28,6 +32,7 @@ import java.util.List;
*/
@Data
@EqualsAndHashCode(callSuper = false)
+@Slf4j
public class ZtStoryUserDTO implements Serializable {
private static final long serialVersionUID = 1L;
@@ -50,6 +55,8 @@ public class ZtStoryUserDTO implements Serializable {
*/
@ExcelProperty(value = "关联研发需求",index =4)
private String storyList;
+ @ExcelIgnore
+ private Set execList;
@ExcelProperty(value = "状态",index =5)
private String status;
@@ -281,10 +288,30 @@ public class ZtStoryUserDTO implements Serializable {
//1.需要 2.不需要
@ExcelIgnore
private Integer needImprove;
-
+ /**
+ * 需求背景
+ */
+ @ExcelIgnore
+ private String storyBackground;
/**
* 产品用户
*/
@ExcelIgnore
private String productUser;
+
+ public void setLinkUrl(String baseUrl) {
+ String reName = this.getTitle();
+ String reUrl = baseUrl + "/#/product-user-story-info/" + this.getId();
+ WriteCellData hyperlink = new WriteCellData<>(reName);
+ HyperlinkData hyperlinkData = new HyperlinkData();
+ try {
+ hyperlinkData.setAddress(reUrl.replace(" ", "%20"));
+ hyperlinkData.setHyperlinkType(HyperlinkData.HyperlinkType.URL);
+ hyperlink.setHyperlinkData(hyperlinkData);
+ this.setUrl(hyperlink);
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ this.setUrl(null);
+ }
+ }
}
diff --git a/src/main/java/com/sa/zentao/entity/ZtStoryUser.java b/src/main/java/com/sa/zentao/entity/ZtStoryUser.java
index a5c83bf..25c633d 100644
--- a/src/main/java/com/sa/zentao/entity/ZtStoryUser.java
+++ b/src/main/java/com/sa/zentao/entity/ZtStoryUser.java
@@ -229,4 +229,5 @@ public class ZtStoryUser implements Serializable {
* 产品用户
*/
private String productUser;
+
}
diff --git a/src/main/java/com/sa/zentao/entity/ZtStoryUserspec.java b/src/main/java/com/sa/zentao/entity/ZtStoryUserspec.java
index 005bdb6..11b99cb 100644
--- a/src/main/java/com/sa/zentao/entity/ZtStoryUserspec.java
+++ b/src/main/java/com/sa/zentao/entity/ZtStoryUserspec.java
@@ -31,5 +31,6 @@ public class ZtStoryUserspec implements Serializable {
private String files;
+ private String storyBackground;
}
diff --git a/src/main/java/com/sa/zentao/enums/KanbanColumnType.java b/src/main/java/com/sa/zentao/enums/KanbanColumnType.java
new file mode 100644
index 0000000..4a69c44
--- /dev/null
+++ b/src/main/java/com/sa/zentao/enums/KanbanColumnType.java
@@ -0,0 +1,49 @@
+package com.sa.zentao.enums;
+
+public enum KanbanColumnType {
+
+ // 需求看板列类型
+ STORY_BACKLOG("backlog", "待办"),
+ STORY_DEVELOPING("developing", "研发中"),
+ STORY_DEVELOPED("developed", "研发完毕"),
+ STORY_TESTING("testing", "测试中"),
+ STORY_TESTED("tested", "测试完毕"),
+ STORY_RELEASED("released", "已发布"),
+ STORY_VERIFIED("verified", "已验收"),
+ STORY_CLOSED("closed", "已关闭"),
+
+ // Bug看板列类型
+ BUG_UNCONFIRMED("unconfirmed", "未确认"),
+ BUG_CONFIRMED("confirmed", "已确认"),
+ BUG_RESOLVED("resolved", "已解决"),
+ BUG_CLOSED("closed", "已关闭"),
+
+ // 任务看板列类型
+ TASK_WAIT("wait", "等待"),
+ TASK_DEVELOPING("developing", "进行中"),
+ TASK_DEVELOPED("developed", "已完成"),
+ TASK_CANCEL("cancel", "已取消"),
+ TASK_CLOSED("closed", "已关闭"),
+
+ // 通用列类型
+ WAIT("wait", "等待"),
+ DOING("doing", "进行中"),
+ DONE("done", "已完成"),
+ CLOSED("closed", "已关闭");
+
+ private String value;
+ private String desc;
+
+ private KanbanColumnType(String value, String desc) {
+ this.value = value;
+ this.desc = desc;
+ }
+
+ public String getValue() {
+ return this.value;
+ }
+
+ public String getDesc() {
+ return this.desc;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/sa/zentao/service/IZtProductService.java b/src/main/java/com/sa/zentao/service/IZtProductService.java
index aad25c0..7a5794b 100644
--- a/src/main/java/com/sa/zentao/service/IZtProductService.java
+++ b/src/main/java/com/sa/zentao/service/IZtProductService.java
@@ -57,4 +57,6 @@ public interface IZtProductService extends IService {
List productListByProgramName(String programName);
+ PageInfo getExecutionByProductId(ZtProjectQo qo);
+
}
diff --git a/src/main/java/com/sa/zentao/service/impl/FestivalConfigServiceImpl.java b/src/main/java/com/sa/zentao/service/impl/FestivalConfigServiceImpl.java
index c4c67e9..2fa66b5 100644
--- a/src/main/java/com/sa/zentao/service/impl/FestivalConfigServiceImpl.java
+++ b/src/main/java/com/sa/zentao/service/impl/FestivalConfigServiceImpl.java
@@ -46,7 +46,9 @@ public class FestivalConfigServiceImpl extends ServiceImpl festivalConfigs = this.baseMapper.selectList(new QueryWrapper().lambda().eq(FestivalConfig::getName, qo.getName()).
+ List festivalConfigs = this.baseMapper.selectList(new QueryWrapper().lambda()
+ .eq(FestivalConfig::getYear,qo.getYear())
+ .eq(FestivalConfig::getName, qo.getName()).
eq(FestivalConfig::getDeleteFlag, DeleteFlagEnum.USED));
if(!CollectionUtils.isEmpty(festivalConfigs)){
throw new BusinessException("已存在");
diff --git a/src/main/java/com/sa/zentao/service/impl/IZtCountService.java b/src/main/java/com/sa/zentao/service/impl/IZtCountService.java
index b1dad68..f7fe31f 100644
--- a/src/main/java/com/sa/zentao/service/impl/IZtCountService.java
+++ b/src/main/java/com/sa/zentao/service/impl/IZtCountService.java
@@ -741,7 +741,11 @@ public class IZtCountService {
for (ZtUser u : ztUsers) {
List approvalList = this.taskService.itApprovalByUserName(u.getNickname(), firstDayOfMonth, lastDayOfMonth);
- if (u.getAccount().equals("liyuyan")) {
+ if (u.getAccount().equals("weidongxia")||u.getUserType() == UserType.CPJL) {
+ ZtProjectQo ztProjectQo =new ZtProjectQo();
+ ztProjectQo.setDate(qo.getDate());
+ result.add(buildCPJLScore(u, userMap , ztProjectQo,approvalList, firstDayOfMonth, lastDayOfMonth, taskList, d,pids));
+ }else if (u.getAccount().equals("liyuyan")) {
result.add(buildXMZLScore(u, approvalList, firstDayOfMonth, lastDayOfMonth, taskList, d));
} else if ("liushengqing".equals(u.getAccount())) {
result.add(buildUiScore(u, approvalList, firstDayOfMonth, lastDayOfMonth, taskList, d));
@@ -1209,7 +1213,6 @@ public class IZtCountService {
dto.setProductProjectOnTimeRateScore(BigDecimal.valueOf(productProjectOnTimeRateScore));
-
List allBugList = this.bugService.list(new QueryWrapper().lambda().select(SFunctionColums.bugColumes())
.eq(ZtBug::getOpenedby, u.getAccount())
.in(ZtBug::getBugType,"releaseBug","prod")
@@ -1239,6 +1242,7 @@ public class IZtCountService {
}
dto.setBugScore(bugScore>20?BigDecimal.ZERO:BigDecimal.valueOf((20 - bugScore)));
}
+ dto.setProductBugRate(dto.getBugScore());
//线上重大
dto.setSeriousBug(BigDecimal.valueOf(allBugList.stream().filter(o -> Arrays.asList(1).contains(o.getSeverity())).count()));
//线上轻微
@@ -1504,6 +1508,7 @@ public class IZtCountService {
Date thisDay = new Date();
thisDay.setMonth(date.getMonth());
thisDay.setDate(date.getDate());
+ thisDay.setYear(date.getYear());
thisDay.setHours(17);
thisDay.setMinutes(30);
thisDay.setSeconds(0);
@@ -2287,7 +2292,7 @@ public class IZtCountService {
//需求准确性
dataMap.put("accurateDemand", performanceDTO.getAccurateDemand()==null?"0": performanceDTO.getAccurateDemand().toString());
//项目准时率
- dataMap.put("productProjectOnTimeRateScore",performanceDTO.getProductProjectOnTimeRateScore()==null?"0": performanceDTO.getProductProjectOnTimeRateScore().multiply(BigDecimal.valueOf(100)).toString());
+ dataMap.put("productProjectOnTimeRateScore",performanceDTO.getProductProjectOnTimeRateScore()==null?"0": performanceDTO.getProductProjectOnTimeRateScore().toString());
//线上Bug得分 缺陷
dataMap.put("bugScope", performanceDTO.getBugScore()==null?"0": performanceDTO.getBugScore().toString());
//开发分配工时
diff --git a/src/main/java/com/sa/zentao/service/impl/ZtKanbanlaneServiceImpl.java b/src/main/java/com/sa/zentao/service/impl/ZtKanbanlaneServiceImpl.java
index 00b8440..6047c09 100644
--- a/src/main/java/com/sa/zentao/service/impl/ZtKanbanlaneServiceImpl.java
+++ b/src/main/java/com/sa/zentao/service/impl/ZtKanbanlaneServiceImpl.java
@@ -317,12 +317,15 @@ public class ZtKanbanlaneServiceImpl extends ServiceImpl carIds = new ArrayList<>(Arrays.asList(cell.getCards().split(",")));
if(carIds.contains(bussId.toString())){
thisZtKanbancell=cell;
- continue;
+ break;
}
}
List carIds = new ArrayList<>(Arrays.asList(thisZtKanbancell.getCards().split(",")));
- carIds.remove(bussId.toString());
+ while (carIds.contains(bussId.toString())) {
+ carIds.remove(bussId.toString());
+ }
+
if(CollectionUtils.isEmpty(carIds)){
thisZtKanbancell.setCards("");
diff --git a/src/main/java/com/sa/zentao/service/impl/ZtMeetingServiceImpl.java b/src/main/java/com/sa/zentao/service/impl/ZtMeetingServiceImpl.java
index db22a79..a9c562b 100644
--- a/src/main/java/com/sa/zentao/service/impl/ZtMeetingServiceImpl.java
+++ b/src/main/java/com/sa/zentao/service/impl/ZtMeetingServiceImpl.java
@@ -88,17 +88,17 @@ public class ZtMeetingServiceImpl extends ServiceImpl sMap=getUserStoryMap(list);
for (ZtMeetingDTO d:list) {
- StringBuilder b=new StringBuilder();
- if(!StringUtils.isEmpty(d.getUsers())){
- String[] split = d.getUsers().split(",");
- for (String s:split) {
- ZtUser ztUser = userMap.get(s);
- if(ztUser!=null){
- b.append(ztUser.getNickname()).append(",");
- }
- }
- d.setUsersName(b.toString());
- }
+// StringBuilder b=new StringBuilder();
+// if(!StringUtils.isEmpty(d.getUsers())){
+// String[] split = d.getUsers().split(",");
+// for (String s:split) {
+// ZtUser ztUser = userMap.get(s);
+// if(ztUser!=null){
+// b.append(ztUser.getNickname()).append(",");
+// }
+// }
+// d.setUsersName(b.toString());
+// }
StringBuilder storyStr=new StringBuilder();
if(!StringUtils.isEmpty( d.getStoryIds())){
String[] split = d.getStoryIds().split(",");
diff --git a/src/main/java/com/sa/zentao/service/impl/ZtProductServiceImpl.java b/src/main/java/com/sa/zentao/service/impl/ZtProductServiceImpl.java
index 7697576..00345f8 100644
--- a/src/main/java/com/sa/zentao/service/impl/ZtProductServiceImpl.java
+++ b/src/main/java/com/sa/zentao/service/impl/ZtProductServiceImpl.java
@@ -1,6 +1,7 @@
package com.sa.zentao.service.impl;
import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
@@ -687,4 +688,63 @@ public class ZtProductServiceImpl extends ServiceImpl getExecutionByProductId(ZtProjectQo qo) {
+ Integer productId = qo.getProductId();
+ if (productId == null || productId == 0) {
+ throw new BusinessException("产品ID不能为空");
+ }
+
+ // 查询产品关联的项目
+ List projectproductlist = this.projectproductService.list(
+ new QueryWrapper().lambda()
+ .eq(ZtProjectproduct::getProduct, productId)
+ );
+
+ if (CollectionUtils.isEmpty(projectproductlist)) {
+ return new PageInfo<>();
+ }
+
+ // 获取项目ID列表
+ List projectIds = projectproductlist.stream()
+ .map(ZtProjectproduct::getProject)
+ .collect(Collectors.toList());
+
+ // 查询项目关联的迭代
+ List executionprojectList = this.executionprojectService.list(
+ new QueryWrapper().lambda()
+ .in(ZtExecutionproject::getProject, projectIds)
+ );
+
+ if (CollectionUtils.isEmpty(executionprojectList)) {
+ return new PageInfo<>();
+ }
+
+ // 获取迭代ID列表
+ List executionIds = executionprojectList.stream()
+ .map(ZtExecutionproject::getExecution)
+ .collect(Collectors.toList());
+
+ // 分页查询迭代,按ID倒序排列
+ com.github.pagehelper.Page page = PageHelper.startPage(qo.getCurrentPage(), qo.getPageSize());
+ LambdaQueryWrapper queryWrapper = new QueryWrapper().lambda()
+ .in(ZtProject::getId, executionIds);
+
+ // 添加名称搜索
+ if (!StringUtils.isEmpty(qo.getName())) {
+ queryWrapper.like(ZtProject::getName, qo.getName());
+ }
+
+ queryWrapper.orderByDesc(ZtProject::getId);
+
+ List executionList = this.projectService.list(queryWrapper);
+
+ // 转换为DTO
+ List dtoList = BeanCopyUtil.copyListProperties(executionList, ZtProjectDTO::new);
+
+ PageInfo ztProjectDTOPageInfo = new PageInfo<>(dtoList);
+ ztProjectDTOPageInfo.setTotal(page.getTotal());
+ return ztProjectDTOPageInfo;
+ }
}
diff --git a/src/main/java/com/sa/zentao/service/impl/ZtStoryServiceImpl.java b/src/main/java/com/sa/zentao/service/impl/ZtStoryServiceImpl.java
index eabe37d..bd5955b 100644
--- a/src/main/java/com/sa/zentao/service/impl/ZtStoryServiceImpl.java
+++ b/src/main/java/com/sa/zentao/service/impl/ZtStoryServiceImpl.java
@@ -1057,7 +1057,7 @@ public class ZtStoryServiceImpl extends ServiceImpl impl
ztStory.setLasteditedby(RiskUserThreadLocal.get().getName());
this.baseMapper.updateById(ztStory);
actionService.addAction(ActionType.XQ, ActionStatus.ASSIGNTOPRODUCTUSER, ztStory.getId(), ztStory.getProduct() + "", null, null,
- RiskUserThreadLocal.get().getName(), "", "");
+ RiskUserThreadLocal.get().getName(), "", dto.getAssignedTo());
}
@Override
@@ -1071,7 +1071,7 @@ public class ZtStoryServiceImpl extends ServiceImpl impl
ztStory.setLasteditedby(RiskUserThreadLocal.get().getName());
this.baseMapper.updateById(ztStory);
actionService.addAction(ActionType.XQ, ActionStatus.ASSIGNTOTESTUSER, ztStory.getId(), ztStory.getProduct() + "", null, null,
- RiskUserThreadLocal.get().getName(), "", "");
+ RiskUserThreadLocal.get().getName(), "", dto.getAssignedTo());
}
private List searchBug(SearchQo qo) {
diff --git a/src/main/java/com/sa/zentao/service/impl/ZtStoryUserServiceImpl.java b/src/main/java/com/sa/zentao/service/impl/ZtStoryUserServiceImpl.java
index f91bf89..a5b83f0 100644
--- a/src/main/java/com/sa/zentao/service/impl/ZtStoryUserServiceImpl.java
+++ b/src/main/java/com/sa/zentao/service/impl/ZtStoryUserServiceImpl.java
@@ -19,10 +19,7 @@ import com.sa.zentao.qo.StoryQo;
import com.sa.zentao.qo.ZtProjectQo;
import com.sa.zentao.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.sa.zentao.utils.BeanCopyUtil;
-import com.sa.zentao.utils.BeanCopyUtilCallBack;
-import com.sa.zentao.utils.SendEmail;
-import com.sa.zentao.utils.VxMessageUtils;
+import com.sa.zentao.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
@@ -81,6 +78,9 @@ public class ZtStoryUserServiceImpl extends ServiceImpl().lambda().eq(ZtStoryUserspec::getStory, id));
+ ZtStoryUserspec spec = this.storyUserspecService.getOne(new QueryWrapper().lambda().eq(ZtStoryUserspec::getStory, id).last(" limit 1"));
if (spec == null) {
spec = new ZtStoryUserspec();
spec.setStory(id);
@@ -229,6 +230,7 @@ public class ZtStoryUserServiceImpl extends ServiceImpl().lambda().eq(ZtStoryUserspec::getStory, id)
.set(ZtStoryUserspec::getSpec, dto.getSpec())
.set(ZtStoryUserspec::getVerify, dto.getVerify())
+ .set(ZtStoryUserspec::getStoryBackground, dto.getStoryBackground())
.set(ZtStoryUserspec::getFiles, dto.getFileUrl())
);
}
@@ -246,13 +250,12 @@ public class ZtStoryUserServiceImpl extends ServiceImpl> getKanban(Integer productId) {
List ztStoryUsers = this.baseMapper.selectList(new QueryWrapper()
- .lambda().select(ZtStoryUser::getId,ZtStoryUser::getPri,ZtStoryUser::getTitle,ZtStoryUser::getStage,ZtStoryUser::getStatus,ZtStoryUser::getOpenedby,ZtStoryUser::getOpeneddate,ZtStoryUser::getLastediteddate,ZtStoryUser::getProductUser)
+ .lambda().select(ZtStoryUser::getId, ZtStoryUser::getPri, ZtStoryUser::getTitle, ZtStoryUser::getStage, ZtStoryUser::getStatus, ZtStoryUser::getOpenedby, ZtStoryUser::getOpeneddate, ZtStoryUser::getLastediteddate, ZtStoryUser::getProductUser)
.eq(ZtStoryUser::getProduct, productId).orderByDesc(ZtStoryUser::getId));
Map> map = new HashMap<>();
Map stringZtUserMap = this.userService.userMapByIds(null);
@@ -261,12 +264,12 @@ public class ZtStoryUserServiceImpl extends ServiceImpl"active".equals(o.getStatus())).collect(Collectors.toList()));
- map.put("unconfirmed",ztStoryUserDTOS.stream().filter(o->"unconfirmed".equals(o.getStatus())).collect(Collectors.toList()));
- map.put("waitcommunicate",ztStoryUserDTOS.stream().filter(o->"waitcommunicate".equals(o.getStatus())).collect(Collectors.toList()));
- map.put("waitdesign",ztStoryUserDTOS.stream().filter(o->"waitdesign".equals(o.getStatus())).collect(Collectors.toList()));
- map.put("designdoing",ztStoryUserDTOS.stream().filter(o->"designdoing".equals(o.getStatus())).collect(Collectors.toList()));
+ map.put("active", ztStoryUserDTOS.stream().filter(o -> "active".equals(o.getStatus())).collect(Collectors.toList()));
+ map.put("unconfirmed", ztStoryUserDTOS.stream().filter(o -> "unconfirmed".equals(o.getStatus())).collect(Collectors.toList()));
+ map.put("waitcommunicate", ztStoryUserDTOS.stream().filter(o -> "waitcommunicate".equals(o.getStatus())).collect(Collectors.toList()));
+ map.put("waitdesign", ztStoryUserDTOS.stream().filter(o -> "waitdesign".equals(o.getStatus())).collect(Collectors.toList()));
+ map.put("designdoing", ztStoryUserDTOS.stream().filter(o -> "designdoing".equals(o.getStatus())).collect(Collectors.toList()));
- map.put("designdone",ztStoryUserDTOS.stream().filter(o->"designdone".equals(o.getStatus())).collect(Collectors.toList()));
- map.put("storyunconfirmed",ztStoryUserDTOS.stream().filter(o->"storyunconfirmed".equals(o.getStatus())).collect(Collectors.toList()));
- map.put("confirmed",ztStoryUserDTOS.stream().filter(o->"confirmed".equals(o.getStatus())).collect(Collectors.toList()));
+ map.put("designdone", ztStoryUserDTOS.stream().filter(o -> "designdone".equals(o.getStatus())).collect(Collectors.toList()));
+ map.put("storyunconfirmed", ztStoryUserDTOS.stream().filter(o -> "storyunconfirmed".equals(o.getStatus())).collect(Collectors.toList()));
+ map.put("confirmed", ztStoryUserDTOS.stream().filter(o -> "confirmed".equals(o.getStatus())).collect(Collectors.toList()));
return map;
}
@@ -298,18 +301,18 @@ public class ZtStoryUserServiceImpl extends ServiceImpl pIds = this.projectService.authProductList();
- if(CollectionUtils.isEmpty(pIds)&&CollectionUtils.isEmpty(qo.getStoryIds())){
+ if (CollectionUtils.isEmpty(pIds) && CollectionUtils.isEmpty(qo.getStoryIds())) {
return new PageInfo();
}
- if(qo.getProductId()!=null&&qo.getProductId()!=0){
+ if (qo.getProductId() != null && qo.getProductId() != 0) {
qo.setProductIds(Arrays.asList(qo.getProductId()));
- }else{
+ } else {
qo.setProductIds(pIds);
}
- if(!CollectionUtils.isEmpty(qo.getStatusList())&&qo.getStatusList().contains("unconfirmed")) {
+ if (!CollectionUtils.isEmpty(qo.getStatusList()) && qo.getStatusList().contains("unconfirmed")) {
qo.getStatusList().addAll(Arrays.asList("unconfirmed",
- "waitcommunicate","waitdesign","designdoing","designdone","storyunconfirmed"));
+ "waitcommunicate", "waitdesign", "designdoing", "designdone", "storyunconfirmed"));
}
Page page = PageHelper.startPage(qo.getCurrentPage(), qo.getPageSize());
@@ -320,7 +323,9 @@ public class ZtStoryUserServiceImpl extends ServiceImpl userMap = this.userService.userMapByIds(null);
- Map> storyUserMap = getStoryUserMap(list);
+ Map> storyMap = getStoryMap(list);
+ //story - exec
+ Map> execMap= getExecMap(storyMap);
Map> rMap = getReviewMap(list);
for (ZtStoryUserDTO d : list) {
@@ -369,31 +374,77 @@ public class ZtStoryUserServiceImpl extends ServiceImpl ztStories = storyUserMap.get(d.getId());
+ List ztStories = storyMap.get(d.getId());
if (!CollectionUtils.isEmpty(ztStories)) {
- d.setStoryList(ztStories.stream().map(o ->o.getId()+":"+o.getTitle()).collect(Collectors.joining(",")));
- d.setSList(CollectionUtils.isEmpty(ztStories)?null:BeanCopyUtil.copyListProperties(ztStories,ZtStoryDTO::new));
- }
-
-
- String reName = d.getTitle();
- String reUrl = url+"/#/product-user-story-info/"+d.getId();
- WriteCellData hyperlink = new WriteCellData<>(reName);
- HyperlinkData hyperlinkData = new HyperlinkData();
- try {
- hyperlinkData.setAddress(reUrl.replace(" ", "%20"));
- hyperlinkData.setHyperlinkType(HyperlinkData.HyperlinkType.URL);
- hyperlink.setHyperlinkData(hyperlinkData);
- d.setUrl(hyperlink );
- } catch (Exception e) {
- log.error(e.getMessage(), e);
- d.setUrl(null );
+ for (ZtStory story:ztStories){
+ List execList = execMap.get(story.getId());
+ if(!CollectionUtils.isEmpty(execList)){
+ if(CollectionUtils.isEmpty(d.getExecList())){
+ d.setExecList(new HashSet<>());
+ }
+ d.getExecList().addAll(execList);
+ }
}
+ d.setStoryList(ztStories.stream().map(o -> o.getId() + ":" + o.getTitle()).collect(Collectors.joining(",")));
+ d.setSList(CollectionUtils.isEmpty(ztStories) ? null : BeanCopyUtil.copyListProperties(ztStories, ZtStoryDTO::new));
+ }
+ d.setLinkUrl(url);
}
}
return new PageInfo(list);
}
+ private Map> getExecMap(Map> storyMap) {
+ if(storyMap==null||storyMap.isEmpty()){
+ return new HashMap<>();
+ }
+ // 收集到指定类型的列表(比如ArrayList),还可扩展去重、排序等
+ List storyList = storyMap.values()
+ .stream()
+ .filter(list -> list != null)
+ .flatMap(List::stream)
+ // 自定义收集器:指定ArrayList,还可加.distinct()去重
+ .collect(Collectors.toCollection(ArrayList::new));
+ if(CollectionUtils.isEmpty(storyList)){
+ return new HashMap<>();
+ }
+ List list = this.projectstoryService.list(new QueryWrapper().lambda()
+ .eq(ZtProjectstory::getType,ProjectTypeEnums.execution.getValue())
+ .in(ZtProjectstory::getStory, storyList.stream().map(o -> o.getId()).collect(Collectors.toUnmodifiableList())));
+ if(CollectionUtils.isEmpty(list)){
+ return new HashMap<>();
+ }
+ List ztExecList = this.projectService.listByIds(list.stream().map(o -> o.getProject()).collect(Collectors.toUnmodifiableList()));
+ if(CollectionUtils.isEmpty(list)){
+ return new HashMap<>();
+ }
+ // 第一步:先构建 projectId -> ZtProject 的映射(方便快速查找)
+ Map projectIdToProjectMap = ztExecList.stream()
+ .collect(Collectors.toMap(
+ ZtProject::getId, // key:项目ID
+ project -> project, // value:项目对象
+ (existing, replacement) -> existing // 处理重复projectId的情况,保留原有值
+ ));
+
+ // 第二步:按story分组,收集对应的ZtProject列表
+ Map> storyToProjectsMap = list.stream()
+ .collect(Collectors.groupingBy(
+ ZtProjectstory::getStory, // 分组key:story字段
+ // 分组value:将每个ZtProjectstory对应的project转换成ZtProject,并收集为列表
+ Collectors.mapping(
+ projectStory -> projectIdToProjectMap.get(projectStory.getProject()),
+ // 过滤掉null(防止projectId不存在的情况),并收集为List
+ Collectors.filtering(
+ project -> project != null,
+ Collectors.toList()
+ )
+ )
+ ));
+
+ // 最终返回这个Map(你可以根据需要调整返回逻辑)
+ return storyToProjectsMap;
+ }
+
@Override
@Transactional
public void changeStatus(ZtStoryUserDTO dto) {
@@ -420,8 +471,8 @@ public class ZtStoryUserServiceImpl extends ServiceImpl ztStories = this.baseMapper.selectList(eq);
if (CollectionUtils.isEmpty(ztStories)) {
@@ -461,7 +512,7 @@ public class ZtStoryUserServiceImpl extends ServiceImpl> storyUserMap = getStoryUserMap(Arrays.asList(dto));
+ Map> storyUserMap = getStoryMap(Arrays.asList(dto));
List ztStories = storyUserMap.get(d.getId());
if (!CollectionUtils.isEmpty(ztStories)) {
dto.setStoryList(ztStories.stream().map(o -> o.getTitle()).collect(Collectors.joining(",")));
@@ -615,8 +661,9 @@ public class ZtStoryUserServiceImpl extends ServiceImpl list = this.storyService.list(new QueryWrapper().lambda().eq(ZtStory::getUserStory, dto.getId()));
if (!CollectionUtils.isEmpty(list)) {
List storyDTOList = BeanCopyUtil.copyListProperties(list, ZtStoryDTO::new);
- if (!CollectionUtils.isEmpty(storyDTOList)) {
+ Map> execMap= getExecMap(list.stream().collect(Collectors.groupingBy(ZtStory::getId)));
+ if (!CollectionUtils.isEmpty(storyDTOList)) {
for (ZtStoryDTO storyDTO : storyDTOList) {
ztUser = userMap.get(storyDTO.getAssignedTo());
if (ztUser != null) {
@@ -626,10 +673,19 @@ public class ZtStoryUserServiceImpl extends ServiceImpl execList = execMap.get(storyDTO.getId());
+ if(!CollectionUtils.isEmpty(execList)){
+ if(CollectionUtils.isEmpty(dto.getExecList())){
+ dto.setExecList(new HashSet<>());
+ }
+ dto.getExecList().addAll(execList);
+ }
}
dto.setSList(storyDTOList);
}
+ //story - exec
+
}
List tasks = this.storyUserTaskService.list(new QueryWrapper().lambda().eq(ZtStoryUserTask::getUserStoryId, dto.getId()));
if (!CollectionUtils.isEmpty(tasks)) {
@@ -651,10 +707,11 @@ public class ZtStoryUserServiceImpl extends ServiceImpl specList = this.storyUserspecService.list(new QueryWrapper().lambda().eq(ZtStoryUserspec::getStory, dto.getId()));
- if(!CollectionUtils.isEmpty(specList)){
+ if (!CollectionUtils.isEmpty(specList)) {
ZtStoryUserspec ztStoryUserspec = specList.get(0);
dto.setSpec(ztStoryUserspec.getSpec());
dto.setVerify(ztStoryUserspec.getVerify());
+ dto.setStoryBackground(ztStoryUserspec.getStoryBackground());
}
return dto;
@@ -707,7 +764,6 @@ public class ZtStoryUserServiceImpl extends ServiceImpl storyList = this.storyService.list(new QueryWrapper().lambda()
.ne(ZtStory::getStatus, "closed").in(ZtStory::getStage, StoryStageEnums.beforeStatus(7)).eq(ZtStory::getUserStory, id));
- if(!CollectionUtils.isEmpty(storyList)){
- return ;
+ if (!CollectionUtils.isEmpty(storyList)) {
+ return;
}
}
storyUser.setStatus(status.getCode());
@@ -823,7 +879,7 @@ public class ZtStoryUserServiceImpl extends ServiceImpl> getStoryUserMap(List list) {
+ private Map> getStoryMap(List list) {
List ids = list.stream().map(o -> o.getId()).collect(Collectors.toList());
List list1 = storyService.list(new QueryWrapper().lambda().in(ZtStory::getUserStory, ids));
@@ -930,16 +986,19 @@ public class ZtStoryUserServiceImpl extends ServiceImpl impleme
ZtStory ztStory = this.storyService.getById(story);
if (ztStory != null) {
dto.setStoryName(ztStory.getTitle());
+ dto.setInnerYsFlag(ztStory.getInnerYsFlag());
}
}
@@ -578,8 +579,8 @@ public class ZtTaskServiceImpl extends ServiceImpl impleme
if (story != null && story != 0) {
ZtStory ztStory = this.storyService.getById(story);
// wait 初始化 projected 已立项 developing 研发中 developed 研发完毕 testing 测试中 tested
- if (!Arrays.asList("wait", "projected", "developing", "developed", "testing", "tested",StoryStageEnums.productWaitVerified.getValue()
- ,StoryStageEnums.productVerified.getValue()).contains(ztStory.getStage())) {
+ if (!Arrays.asList("wait", "projected", "developing", "developed", "testing", "tested", StoryStageEnums.productWaitVerified.getValue()
+ , StoryStageEnums.productVerified.getValue()).contains(ztStory.getStage())) {
throw new BusinessException("当前状态无法添加任务");
}
if (ztStory.getStatus().equals("closed")) {
@@ -1037,7 +1038,7 @@ public class ZtTaskServiceImpl extends ServiceImpl impleme
StringUtils.isEmpty(finishBy) ? RiskUserThreadLocal.get().getName() : finishBy, dto.getDeliverContent(), null);
if (ztTask.getStory() != null && ztTask.getStory() != 0) {
ZtStory ztStory = this.storyService.getById(ztTask.getStory());
- if(ztStory!=null){
+ if (ztStory != null) {
ztStory.setDeliverContent(dto.getDeliverContent());
ztStory.setLasteditedby(RiskUserThreadLocal.get().getName());
ztStory.setLastediteddate(new Date());
@@ -1054,40 +1055,41 @@ public class ZtTaskServiceImpl extends ServiceImpl impleme
actionService.addAction(ActionType.RW, ActionStatus.WC, dto.getId(), projectproduct == null ? null : projectproduct.getProduct().toString(), projectproduct == null ? null : projectproduct.getProject(), ztTask.getExecution(),
StringUtils.isEmpty(finishBy) ? RiskUserThreadLocal.get().getName() : finishBy, "", null);
- if (ztTask.getExecution() != null && ztTask.getExecution() != 0) {
- if (StringUtils.isEmpty(dto.getTabType())) {
- kanbanlaneService.changeStatus(ztTask.getExecution(), ztTask.getId(), "task", "developed");
- } else {
- KanbanQo qo = new KanbanQo();
- qo.setStatusType(dto.getStatusType());
- qo.setTabType(dto.getTabType());
- qo.setId(dto.getId());
- qo.setFromId(dto.getFromId());
- qo.setToId(dto.getToId());
- kanbanlaneService.changeStatus(qo);
- }
+ if (ztTask.getExecution() != null && ztTask.getExecution() != 0) {
+ if (StringUtils.isEmpty(dto.getTabType())) {
+ kanbanlaneService.changeStatus(ztTask.getExecution(), ztTask.getId(), "task", "developed");
+ } else {
+ KanbanQo qo = new KanbanQo();
+ qo.setStatusType(dto.getStatusType());
+ qo.setTabType(dto.getTabType());
+ qo.setId(dto.getId());
+ qo.setFromId(dto.getFromId());
+ qo.setToId(dto.getToId());
+ kanbanlaneService.changeStatus(qo);
}
- // devel 开发 request 需求 test
- //如果有一个开发任务进行中,并且所有的测试任务还没有开始,需求的研发阶段为“研发中”
- //如果所有的开发任务已经完成,并且所有的测试任务还没有开始,则为“研发完毕"
- //如果有一个测试任务进行中,则视为“测试中”
- //如果所有的测试任务已经结束,但还有一些开发任务没有结束,则视为"测试中"
- //如果所有的测试任务已经结束,并且所有的开发任务已经结束,则视为"测试完毕"
+ }
+ // devel 开发 request 需求 test
+ //如果有一个开发任务进行中,并且所有的测试任务还没有开始,需求的研发阶段为“研发中”
+ //如果所有的开发任务已经完成,并且所有的测试任务还没有开始,则为“研发完毕"
+ //如果有一个测试任务进行中,则视为“测试中”
+ //如果所有的测试任务已经结束,但还有一些开发任务没有结束,则视为"测试中"
+ //如果所有的测试任务已经结束,并且所有的开发任务已经结束,则视为"测试完毕"
// pause 暂停 cancel取消 closed 关闭 done 完成 wait reviewing待评审 doing
// devel 开发 request 需求 test
- String type = ztTask.getType();
- if (ztTask.getStory() != null && ztTask.getStory() != 0) {
- this.storyService.taskFinishChangeStatus(ztTask.getStory(), finishBy, TaskType.transferType(type), false);
- }
- if (ztTask.getFeedback() != null && ztTask.getFeedback() != 0) {
- this.storyFeedbackService.feedbackFinished(ztTask.getFeedback(), ztTask.getFeedbackRemark());
- }
- if (ztTask.getStory() != null && ztTask.getStory() != 0 && ObjectUtil.equal(dto.getInnerYsFlag(), 1)) {
- ZtStoryDTO qo = new ZtStoryDTO();
- qo.setId(ztTask.getStory());
- this.storyService.testSubmitVerified(qo);
- }
+ String type = ztTask.getType();
+ if (ztTask.getStory() != null && ztTask.getStory() != 0) {
+ this.storyService.taskFinishChangeStatus(ztTask.getStory(), finishBy, TaskType.transferType(type), false);
+ }
+ if (ztTask.getFeedback() != null && ztTask.getFeedback() != 0) {
+ this.storyFeedbackService.feedbackFinished(ztTask.getFeedback(), ztTask.getFeedbackRemark());
+ }
+// if (ztTask.getStory() != null && ztTask.getStory() != 0 && ObjectUtil.equal(dto.getInnerYsFlag(), 1)) {
+// ZtStoryDTO qo = new ZtStoryDTO();
+// qo.setId(ztTask.getStory());
+// this.storyService.testSubmitVerified(qo);
+// }
}
+
@Override
@Transactional
public void closeTask(ZtTaskDTO dto) {
diff --git a/src/main/java/com/sa/zentao/utils/KanbanStageMapping.java b/src/main/java/com/sa/zentao/utils/KanbanStageMapping.java
new file mode 100644
index 0000000..4deb181
--- /dev/null
+++ b/src/main/java/com/sa/zentao/utils/KanbanStageMapping.java
@@ -0,0 +1,87 @@
+package com.sa.zentao.utils;
+
+import com.sa.zentao.enums.KanbanColumnType;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 看板阶段映射工具类
+ * 用于将业务阶段映射到看板列类型
+ */
+public class KanbanStageMapping {
+
+ /**
+ * 需求阶段到看板列的映射
+ */
+ private static final Map STORY_STAGE_MAP = new HashMap<>();
+
+ /**
+ * 任务状态到看板列的映射
+ */
+ private static final Map TASK_STATUS_MAP = new HashMap<>();
+
+ static {
+ // 初始化需求阶段映射
+ STORY_STAGE_MAP.put("closed", KanbanColumnType.STORY_CLOSED);
+ STORY_STAGE_MAP.put("wait", KanbanColumnType.STORY_BACKLOG);
+ STORY_STAGE_MAP.put("projected", KanbanColumnType.STORY_BACKLOG);
+ STORY_STAGE_MAP.put("developing", KanbanColumnType.STORY_DEVELOPING);
+ STORY_STAGE_MAP.put("developed", KanbanColumnType.STORY_DEVELOPED);
+ STORY_STAGE_MAP.put("testing", KanbanColumnType.STORY_TESTING);
+ STORY_STAGE_MAP.put("tested", KanbanColumnType.STORY_TESTED);
+ STORY_STAGE_MAP.put("released", KanbanColumnType.STORY_RELEASED);
+ STORY_STAGE_MAP.put("verified", KanbanColumnType.STORY_VERIFIED);
+
+ // 初始化任务状态映射
+ TASK_STATUS_MAP.put("wait", KanbanColumnType.TASK_WAIT);
+ TASK_STATUS_MAP.put("reviewing", KanbanColumnType.TASK_WAIT);
+ TASK_STATUS_MAP.put("draft", KanbanColumnType.TASK_WAIT);
+ TASK_STATUS_MAP.put("doing", KanbanColumnType.TASK_DEVELOPING);
+ TASK_STATUS_MAP.put("done", KanbanColumnType.TASK_DEVELOPED);
+ TASK_STATUS_MAP.put("cancel", KanbanColumnType.TASK_CANCEL);
+ TASK_STATUS_MAP.put("closed", KanbanColumnType.TASK_CLOSED);
+ }
+
+ /**
+ * 根据需求阶段获取看板列类型
+ *
+ * @param stage 需求阶段
+ * @return 看板列类型
+ */
+ public static KanbanColumnType getStoryColumnByStage(String stage) {
+ return STORY_STAGE_MAP.getOrDefault(stage, KanbanColumnType.STORY_BACKLOG);
+ }
+
+ /**
+ * 根据任务状态获取看板列类型
+ *
+ * @param status 任务状态
+ * @return 看板列类型
+ */
+ public static KanbanColumnType getTaskColumnByStatus(String status) {
+ return TASK_STATUS_MAP.getOrDefault(status, KanbanColumnType.TASK_WAIT);
+ }
+
+ /**
+ * 获取需求阶段对应的看板列值
+ *
+ * @param stage 需求阶段
+ * @return 看板列值
+ */
+ public static String getStoryColumnValue(String stage) {
+ KanbanColumnType columnType = getStoryColumnByStage(stage);
+ return columnType.getValue();
+ }
+
+ /**
+ * 获取任务状态对应的看板列值
+ *
+ * @param status 任务状态
+ * @return 看板列值
+ */
+ public static String getTaskColumnValue(String status) {
+ KanbanColumnType columnType = getTaskColumnByStatus(status);
+ return columnType.getValue();
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/mapper/ZtStoryMapper.xml b/src/main/resources/mapper/ZtStoryMapper.xml
index 4c17f7f..17a62db 100644
--- a/src/main/resources/mapper/ZtStoryMapper.xml
+++ b/src/main/resources/mapper/ZtStoryMapper.xml
@@ -64,7 +64,7 @@