绩效看板等修改

This commit is contained in:
2026-01-12 10:10:51 +08:00
parent 7c379ea877
commit 5b8d440ff3
17 changed files with 549 additions and 200 deletions

View File

@@ -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 = "";
}

View File

@@ -160,4 +160,9 @@ public class ZtProductController {
public Result projectTeamById(@RequestBody ZtProjectQo qo){ public Result projectTeamById(@RequestBody ZtProjectQo qo){
return Result.success(this.ztProductService.productTeamByPid(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));
}
} }

View File

@@ -2,21 +2,25 @@ package com.sa.zentao.dao;
import com.alibaba.excel.annotation.ExcelIgnore; import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.metadata.data.HyperlinkData;
import com.alibaba.excel.metadata.data.WriteCellData; import com.alibaba.excel.metadata.data.WriteCellData;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.sa.zentao.entity.ZtProject;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NonNull; import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* <p> * <p>
@@ -28,6 +32,7 @@ import java.util.List;
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
@Slf4j
public class ZtStoryUserDTO implements Serializable { public class ZtStoryUserDTO implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -50,6 +55,8 @@ public class ZtStoryUserDTO implements Serializable {
*/ */
@ExcelProperty(value = "关联研发需求",index =4) @ExcelProperty(value = "关联研发需求",index =4)
private String storyList; private String storyList;
@ExcelIgnore
private Set<ZtProject> execList;
@ExcelProperty(value = "状态",index =5) @ExcelProperty(value = "状态",index =5)
private String status; private String status;
@@ -281,10 +288,30 @@ public class ZtStoryUserDTO implements Serializable {
//1.需要 2.不需要 //1.需要 2.不需要
@ExcelIgnore @ExcelIgnore
private Integer needImprove; private Integer needImprove;
/**
* 需求背景
*/
@ExcelIgnore
private String storyBackground;
/** /**
* 产品用户 * 产品用户
*/ */
@ExcelIgnore @ExcelIgnore
private String productUser; private String productUser;
public void setLinkUrl(String baseUrl) {
String reName = this.getTitle();
String reUrl = baseUrl + "/#/product-user-story-info/" + this.getId();
WriteCellData<String> 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);
}
}
} }

View File

@@ -229,4 +229,5 @@ public class ZtStoryUser implements Serializable {
* 产品用户 * 产品用户
*/ */
private String productUser; private String productUser;
} }

View File

@@ -31,5 +31,6 @@ public class ZtStoryUserspec implements Serializable {
private String files; private String files;
private String storyBackground;
} }

View File

@@ -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;
}
}

View File

@@ -57,4 +57,6 @@ public interface IZtProductService extends IService<ZtProduct> {
List<ZtProduct> productListByProgramName(String programName); List<ZtProduct> productListByProgramName(String programName);
PageInfo<ZtProjectDTO> getExecutionByProductId(ZtProjectQo qo);
} }

View File

@@ -46,7 +46,9 @@ public class FestivalConfigServiceImpl extends ServiceImpl<FestivalConfigMapper,
List<FestivalConfig> festivalConfigs = this.baseMapper.selectList(new QueryWrapper<FestivalConfig>().lambda().eq(FestivalConfig::getName, qo.getName()). List<FestivalConfig> festivalConfigs = this.baseMapper.selectList(new QueryWrapper<FestivalConfig>().lambda()
.eq(FestivalConfig::getYear,qo.getYear())
.eq(FestivalConfig::getName, qo.getName()).
eq(FestivalConfig::getDeleteFlag, DeleteFlagEnum.USED)); eq(FestivalConfig::getDeleteFlag, DeleteFlagEnum.USED));
if(!CollectionUtils.isEmpty(festivalConfigs)){ if(!CollectionUtils.isEmpty(festivalConfigs)){
throw new BusinessException("已存在"); throw new BusinessException("已存在");

View File

@@ -741,7 +741,11 @@ public class IZtCountService {
for (ZtUser u : ztUsers) { for (ZtUser u : ztUsers) {
List<ItApproval> approvalList = this.taskService.itApprovalByUserName(u.getNickname(), firstDayOfMonth, lastDayOfMonth); List<ItApproval> 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)); result.add(buildXMZLScore(u, approvalList, firstDayOfMonth, lastDayOfMonth, taskList, d));
} else if ("liushengqing".equals(u.getAccount())) { } else if ("liushengqing".equals(u.getAccount())) {
result.add(buildUiScore(u, approvalList, firstDayOfMonth, lastDayOfMonth, taskList, d)); result.add(buildUiScore(u, approvalList, firstDayOfMonth, lastDayOfMonth, taskList, d));
@@ -1209,7 +1213,6 @@ public class IZtCountService {
dto.setProductProjectOnTimeRateScore(BigDecimal.valueOf(productProjectOnTimeRateScore)); dto.setProductProjectOnTimeRateScore(BigDecimal.valueOf(productProjectOnTimeRateScore));
List<ZtBug> allBugList = this.bugService.list(new QueryWrapper<ZtBug>().lambda().select(SFunctionColums.bugColumes()) List<ZtBug> allBugList = this.bugService.list(new QueryWrapper<ZtBug>().lambda().select(SFunctionColums.bugColumes())
.eq(ZtBug::getOpenedby, u.getAccount()) .eq(ZtBug::getOpenedby, u.getAccount())
.in(ZtBug::getBugType,"releaseBug","prod") .in(ZtBug::getBugType,"releaseBug","prod")
@@ -1239,6 +1242,7 @@ public class IZtCountService {
} }
dto.setBugScore(bugScore>20?BigDecimal.ZERO:BigDecimal.valueOf((20 - bugScore))); 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())); 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(); Date thisDay = new Date();
thisDay.setMonth(date.getMonth()); thisDay.setMonth(date.getMonth());
thisDay.setDate(date.getDate()); thisDay.setDate(date.getDate());
thisDay.setYear(date.getYear());
thisDay.setHours(17); thisDay.setHours(17);
thisDay.setMinutes(30); thisDay.setMinutes(30);
thisDay.setSeconds(0); thisDay.setSeconds(0);
@@ -2287,7 +2292,7 @@ public class IZtCountService {
//需求准确性 //需求准确性
dataMap.put("accurateDemand", performanceDTO.getAccurateDemand()==null?"0": performanceDTO.getAccurateDemand().toString()); 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得分 缺陷 //线上Bug得分 缺陷
dataMap.put("bugScope", performanceDTO.getBugScore()==null?"0": performanceDTO.getBugScore().toString()); dataMap.put("bugScope", performanceDTO.getBugScore()==null?"0": performanceDTO.getBugScore().toString());
//开发分配工时 //开发分配工时

View File

@@ -317,12 +317,15 @@ public class ZtKanbanlaneServiceImpl extends ServiceImpl<ZtKanbanlaneMapper, ZtK
List<String> carIds = new ArrayList<>(Arrays.asList(cell.getCards().split(","))); List<String> carIds = new ArrayList<>(Arrays.asList(cell.getCards().split(",")));
if(carIds.contains(bussId.toString())){ if(carIds.contains(bussId.toString())){
thisZtKanbancell=cell; thisZtKanbancell=cell;
continue; break;
} }
} }
List<String> carIds = new ArrayList<>(Arrays.asList(thisZtKanbancell.getCards().split(","))); List<String> 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)){ if(CollectionUtils.isEmpty(carIds)){
thisZtKanbancell.setCards(""); thisZtKanbancell.setCards("");

View File

@@ -88,17 +88,17 @@ public class ZtMeetingServiceImpl extends ServiceImpl<ZtMeetingMapper, ZtMeeting
Map<Integer,ZtStoryUser> sMap=getUserStoryMap(list); Map<Integer,ZtStoryUser> sMap=getUserStoryMap(list);
for (ZtMeetingDTO d:list) { for (ZtMeetingDTO d:list) {
StringBuilder b=new StringBuilder(); // StringBuilder b=new StringBuilder();
if(!StringUtils.isEmpty(d.getUsers())){ // if(!StringUtils.isEmpty(d.getUsers())){
String[] split = d.getUsers().split(","); // String[] split = d.getUsers().split(",");
for (String s:split) { // for (String s:split) {
ZtUser ztUser = userMap.get(s); // ZtUser ztUser = userMap.get(s);
if(ztUser!=null){ // if(ztUser!=null){
b.append(ztUser.getNickname()).append(","); // b.append(ztUser.getNickname()).append(",");
} // }
} // }
d.setUsersName(b.toString()); // d.setUsersName(b.toString());
} // }
StringBuilder storyStr=new StringBuilder(); StringBuilder storyStr=new StringBuilder();
if(!StringUtils.isEmpty( d.getStoryIds())){ if(!StringUtils.isEmpty( d.getStoryIds())){
String[] split = d.getStoryIds().split(","); String[] split = d.getStoryIds().split(",");

View File

@@ -1,6 +1,7 @@
package com.sa.zentao.service.impl; package com.sa.zentao.service.impl;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.Page; import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
@@ -687,4 +688,63 @@ public class ZtProductServiceImpl extends ServiceImpl<ZtProductMapper, ZtProduct
return ztProjectDTOS.stream().collect(Collectors.groupingBy(ZtProductDTO::getProgram)); return ztProjectDTOS.stream().collect(Collectors.groupingBy(ZtProductDTO::getProgram));
} }
@Override
public PageInfo<ZtProjectDTO> getExecutionByProductId(ZtProjectQo qo) {
Integer productId = qo.getProductId();
if (productId == null || productId == 0) {
throw new BusinessException("产品ID不能为空");
}
// 查询产品关联的项目
List<ZtProjectproduct> projectproductlist = this.projectproductService.list(
new QueryWrapper<ZtProjectproduct>().lambda()
.eq(ZtProjectproduct::getProduct, productId)
);
if (CollectionUtils.isEmpty(projectproductlist)) {
return new PageInfo<>();
}
// 获取项目ID列表
List<Integer> projectIds = projectproductlist.stream()
.map(ZtProjectproduct::getProject)
.collect(Collectors.toList());
// 查询项目关联的迭代
List<ZtExecutionproject> executionprojectList = this.executionprojectService.list(
new QueryWrapper<ZtExecutionproject>().lambda()
.in(ZtExecutionproject::getProject, projectIds)
);
if (CollectionUtils.isEmpty(executionprojectList)) {
return new PageInfo<>();
}
// 获取迭代ID列表
List<Integer> executionIds = executionprojectList.stream()
.map(ZtExecutionproject::getExecution)
.collect(Collectors.toList());
// 分页查询迭代按ID倒序排列
com.github.pagehelper.Page<ZtProjectDTO> page = PageHelper.startPage(qo.getCurrentPage(), qo.getPageSize());
LambdaQueryWrapper<ZtProject> queryWrapper = new QueryWrapper<ZtProject>().lambda()
.in(ZtProject::getId, executionIds);
// 添加名称搜索
if (!StringUtils.isEmpty(qo.getName())) {
queryWrapper.like(ZtProject::getName, qo.getName());
}
queryWrapper.orderByDesc(ZtProject::getId);
List<ZtProject> executionList = this.projectService.list(queryWrapper);
// 转换为DTO
List<ZtProjectDTO> dtoList = BeanCopyUtil.copyListProperties(executionList, ZtProjectDTO::new);
PageInfo<ZtProjectDTO> ztProjectDTOPageInfo = new PageInfo<>(dtoList);
ztProjectDTOPageInfo.setTotal(page.getTotal());
return ztProjectDTOPageInfo;
}
} }

View File

@@ -1057,7 +1057,7 @@ public class ZtStoryServiceImpl extends ServiceImpl<ZtStoryMapper, ZtStory> impl
ztStory.setLasteditedby(RiskUserThreadLocal.get().getName()); ztStory.setLasteditedby(RiskUserThreadLocal.get().getName());
this.baseMapper.updateById(ztStory); this.baseMapper.updateById(ztStory);
actionService.addAction(ActionType.XQ, ActionStatus.ASSIGNTOPRODUCTUSER, ztStory.getId(), ztStory.getProduct() + "", null, null, actionService.addAction(ActionType.XQ, ActionStatus.ASSIGNTOPRODUCTUSER, ztStory.getId(), ztStory.getProduct() + "", null, null,
RiskUserThreadLocal.get().getName(), "", ""); RiskUserThreadLocal.get().getName(), "", dto.getAssignedTo());
} }
@Override @Override
@@ -1071,7 +1071,7 @@ public class ZtStoryServiceImpl extends ServiceImpl<ZtStoryMapper, ZtStory> impl
ztStory.setLasteditedby(RiskUserThreadLocal.get().getName()); ztStory.setLasteditedby(RiskUserThreadLocal.get().getName());
this.baseMapper.updateById(ztStory); this.baseMapper.updateById(ztStory);
actionService.addAction(ActionType.XQ, ActionStatus.ASSIGNTOTESTUSER, ztStory.getId(), ztStory.getProduct() + "", null, null, actionService.addAction(ActionType.XQ, ActionStatus.ASSIGNTOTESTUSER, ztStory.getId(), ztStory.getProduct() + "", null, null,
RiskUserThreadLocal.get().getName(), "", ""); RiskUserThreadLocal.get().getName(), "", dto.getAssignedTo());
} }
private List<SearchDTO> searchBug(SearchQo qo) { private List<SearchDTO> searchBug(SearchQo qo) {

View File

@@ -19,10 +19,7 @@ import com.sa.zentao.qo.StoryQo;
import com.sa.zentao.qo.ZtProjectQo; import com.sa.zentao.qo.ZtProjectQo;
import com.sa.zentao.service.*; import com.sa.zentao.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sa.zentao.utils.BeanCopyUtil; import com.sa.zentao.utils.*;
import com.sa.zentao.utils.BeanCopyUtilCallBack;
import com.sa.zentao.utils.SendEmail;
import com.sa.zentao.utils.VxMessageUtils;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
@@ -81,6 +78,9 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
@Autowired @Autowired
private VxService vxService; private VxService vxService;
@Autowired
private IZtProjectstoryService projectstoryService;
@Value("${file.backUrl}") @Value("${file.backUrl}")
private String url; private String url;
@@ -92,7 +92,7 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
this.baseMapper.insert(s); this.baseMapper.insert(s);
fileService.updateFile(dto.getFiles(), s.getId(), FileTypes.userStory); fileService.updateFile(dto.getFiles(), s.getId(), FileTypes.userStory);
ZtStoryUserspec spec= buildSpec(dto,s); ZtStoryUserspec spec = buildSpec(dto, s);
storyUserspecService.save(spec); storyUserspecService.save(spec);
actionService.addAction(ActionType.USERXQ, ActionStatus.XJ, s.getId(), dto.getProduct() + "", null, null, actionService.addAction(ActionType.USERXQ, ActionStatus.XJ, s.getId(), dto.getProduct() + "", null, null,
@@ -125,6 +125,7 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
spec.setSpec(dto.getSpec()); spec.setSpec(dto.getSpec());
spec.setVerify(dto.getVerify()); spec.setVerify(dto.getVerify());
spec.setFiles(dto.getFileUrl()); spec.setFiles(dto.getFileUrl());
spec.setStoryBackground(dto.getStoryBackground());
return spec; return spec;
} }
@@ -220,7 +221,7 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
ztStory.setVerify(null); ztStory.setVerify(null);
this.baseMapper.updateById(ztStory); this.baseMapper.updateById(ztStory);
ZtStoryUserspec spec = this.storyUserspecService.getOne(new QueryWrapper<ZtStoryUserspec>().lambda().eq(ZtStoryUserspec::getStory, id)); ZtStoryUserspec spec = this.storyUserspecService.getOne(new QueryWrapper<ZtStoryUserspec>().lambda().eq(ZtStoryUserspec::getStory, id).last(" limit 1"));
if (spec == null) { if (spec == null) {
spec = new ZtStoryUserspec(); spec = new ZtStoryUserspec();
spec.setStory(id); spec.setStory(id);
@@ -229,6 +230,7 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
spec.setSpec(dto.getSpec()); spec.setSpec(dto.getSpec());
spec.setVerify(dto.getVerify()); spec.setVerify(dto.getVerify());
spec.setFiles(dto.getFileUrl()); spec.setFiles(dto.getFileUrl());
spec.setStoryBackground(dto.getStoryBackground());
storyUserspecService.save(spec); storyUserspecService.save(spec);
} else { } else {
spec.setVersion(1); spec.setVersion(1);
@@ -236,9 +238,11 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
spec.setSpec(dto.getSpec()); spec.setSpec(dto.getSpec());
spec.setVerify(dto.getVerify()); spec.setVerify(dto.getVerify());
spec.setFiles(dto.getFileUrl()); spec.setFiles(dto.getFileUrl());
spec.setStoryBackground(dto.getStoryBackground());
storyUserspecService.update(new UpdateWrapper<ZtStoryUserspec>().lambda().eq(ZtStoryUserspec::getStory, id) storyUserspecService.update(new UpdateWrapper<ZtStoryUserspec>().lambda().eq(ZtStoryUserspec::getStory, id)
.set(ZtStoryUserspec::getSpec, dto.getSpec()) .set(ZtStoryUserspec::getSpec, dto.getSpec())
.set(ZtStoryUserspec::getVerify, dto.getVerify()) .set(ZtStoryUserspec::getVerify, dto.getVerify())
.set(ZtStoryUserspec::getStoryBackground, dto.getStoryBackground())
.set(ZtStoryUserspec::getFiles, dto.getFileUrl()) .set(ZtStoryUserspec::getFiles, dto.getFileUrl())
); );
} }
@@ -246,13 +250,12 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
fileService.updateFile(dto.getFiles(), ztStory.getId(), FileTypes.userStory); fileService.updateFile(dto.getFiles(), ztStory.getId(), FileTypes.userStory);
} }
@Override @Override
public Map<String, List<ZtStoryUserDTO>> getKanban(Integer productId) { public Map<String, List<ZtStoryUserDTO>> getKanban(Integer productId) {
List<ZtStoryUser> ztStoryUsers = this.baseMapper.selectList(new QueryWrapper<ZtStoryUser>() List<ZtStoryUser> ztStoryUsers = this.baseMapper.selectList(new QueryWrapper<ZtStoryUser>()
.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)); .eq(ZtStoryUser::getProduct, productId).orderByDesc(ZtStoryUser::getId));
Map<String, List<ZtStoryUserDTO>> map = new HashMap<>(); Map<String, List<ZtStoryUserDTO>> map = new HashMap<>();
Map<String, ZtUser> stringZtUserMap = this.userService.userMapByIds(null); Map<String, ZtUser> stringZtUserMap = this.userService.userMapByIds(null);
@@ -261,12 +264,12 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
@Override @Override
public void callBack(ZtStoryUser t, ZtStoryUserDTO s) { public void callBack(ZtStoryUser t, ZtStoryUserDTO s) {
ZtUser ztUser = stringZtUserMap.get(t.getOpenedby()); ZtUser ztUser = stringZtUserMap.get(t.getOpenedby());
if(ztUser!=null){ if (ztUser != null) {
s.setOpenedbyName(ztUser.getNickname()); s.setOpenedbyName(ztUser.getNickname());
s.setColor(ztUser.getColor()); s.setColor(ztUser.getColor());
} }
ztUser = stringZtUserMap.get(t.getProductUser()); ztUser = stringZtUserMap.get(t.getProductUser());
if(ztUser!=null){ if (ztUser != null) {
s.setProductUserName(ztUser.getNickname()); s.setProductUserName(ztUser.getNickname());
s.setProductUserColor(ztUser.getColor()); s.setProductUserColor(ztUser.getColor());
} }
@@ -274,15 +277,15 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
}); });
map.put("active",ztStoryUserDTOS.stream().filter(o->"active".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("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("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("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("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("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("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("confirmed", ztStoryUserDTOS.stream().filter(o -> "confirmed".equals(o.getStatus())).collect(Collectors.toList()));
return map; return map;
} }
@@ -298,18 +301,18 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
} }
List<Integer> pIds = this.projectService.authProductList(); List<Integer> pIds = this.projectService.authProductList();
if(CollectionUtils.isEmpty(pIds)&&CollectionUtils.isEmpty(qo.getStoryIds())){ if (CollectionUtils.isEmpty(pIds) && CollectionUtils.isEmpty(qo.getStoryIds())) {
return new PageInfo<ZtStoryUserDTO>(); return new PageInfo<ZtStoryUserDTO>();
} }
if(qo.getProductId()!=null&&qo.getProductId()!=0){ if (qo.getProductId() != null && qo.getProductId() != 0) {
qo.setProductIds(Arrays.asList(qo.getProductId())); qo.setProductIds(Arrays.asList(qo.getProductId()));
}else{ } else {
qo.setProductIds(pIds); 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", qo.getStatusList().addAll(Arrays.asList("unconfirmed",
"waitcommunicate","waitdesign","designdoing","designdone","storyunconfirmed")); "waitcommunicate", "waitdesign", "designdoing", "designdone", "storyunconfirmed"));
} }
Page<ZtStoryUserDTO> page = PageHelper.startPage(qo.getCurrentPage(), qo.getPageSize()); Page<ZtStoryUserDTO> page = PageHelper.startPage(qo.getCurrentPage(), qo.getPageSize());
@@ -320,7 +323,9 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
Map<String, ZtUser> userMap = this.userService.userMapByIds(null); Map<String, ZtUser> userMap = this.userService.userMapByIds(null);
Map<Integer, List<ZtStory>> storyUserMap = getStoryUserMap(list); Map<Integer, List<ZtStory>> storyMap = getStoryMap(list);
//story - exec
Map<Integer,List<ZtProject>> execMap= getExecMap(storyMap);
Map<Integer, List<ZtStoryreviewDTO>> rMap = getReviewMap(list); Map<Integer, List<ZtStoryreviewDTO>> rMap = getReviewMap(list);
for (ZtStoryUserDTO d : list) { for (ZtStoryUserDTO d : list) {
@@ -369,31 +374,77 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
d.setProductUserName(ztUser.getNickname()); d.setProductUserName(ztUser.getNickname());
} }
List<ZtStory> ztStories = storyUserMap.get(d.getId()); List<ZtStory> ztStories = storyMap.get(d.getId());
if (!CollectionUtils.isEmpty(ztStories)) { if (!CollectionUtils.isEmpty(ztStories)) {
d.setStoryList(ztStories.stream().map(o ->o.getId()+":"+o.getTitle()).collect(Collectors.joining(","))); for (ZtStory story:ztStories){
d.setSList(CollectionUtils.isEmpty(ztStories)?null:BeanCopyUtil.copyListProperties(ztStories,ZtStoryDTO::new)); List<ZtProject> execList = execMap.get(story.getId());
} if(!CollectionUtils.isEmpty(execList)){
if(CollectionUtils.isEmpty(d.getExecList())){
d.setExecList(new HashSet<>());
String reName = d.getTitle(); }
String reUrl = url+"/#/product-user-story-info/"+d.getId(); d.getExecList().addAll(execList);
WriteCellData<String> 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 );
} }
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<ZtStoryUserDTO>(list); return new PageInfo<ZtStoryUserDTO>(list);
} }
private Map<Integer, List<ZtProject>> getExecMap(Map<Integer, List<ZtStory>> storyMap) {
if(storyMap==null||storyMap.isEmpty()){
return new HashMap<>();
}
// 收集到指定类型的列表比如ArrayList还可扩展去重、排序等
List<ZtStory> 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<ZtProjectstory> list = this.projectstoryService.list(new QueryWrapper<ZtProjectstory>().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<ZtProject> ztExecList = this.projectService.listByIds(list.stream().map(o -> o.getProject()).collect(Collectors.toUnmodifiableList()));
if(CollectionUtils.isEmpty(list)){
return new HashMap<>();
}
// 第一步:先构建 projectId -> ZtProject 的映射(方便快速查找)
Map<Integer, ZtProject> projectIdToProjectMap = ztExecList.stream()
.collect(Collectors.toMap(
ZtProject::getId, // key项目ID
project -> project, // value项目对象
(existing, replacement) -> existing // 处理重复projectId的情况保留原有值
));
// 第二步按story分组收集对应的ZtProject列表
Map<Integer, List<ZtProject>> storyToProjectsMap = list.stream()
.collect(Collectors.groupingBy(
ZtProjectstory::getStory, // 分组keystory字段
// 分组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 @Override
@Transactional @Transactional
public void changeStatus(ZtStoryUserDTO dto) { public void changeStatus(ZtStoryUserDTO dto) {
@@ -420,8 +471,8 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
.eq(ZtStoryUser::getDeleted, "0") .eq(ZtStoryUser::getDeleted, "0")
.orderByDesc(ZtStoryUser::getId); .orderByDesc(ZtStoryUser::getId);
eq.select(ZtStoryUser::getId,ZtStoryUser::getTitle,ZtStoryUser::getProduct, eq.select(ZtStoryUser::getId, ZtStoryUser::getTitle, ZtStoryUser::getProduct,
ZtStoryUser::getOpenedby,ZtStoryUser::getAssignedto ZtStoryUser::getOpenedby, ZtStoryUser::getAssignedto
); );
List<ZtStoryUser> ztStories = this.baseMapper.selectList(eq); List<ZtStoryUser> ztStories = this.baseMapper.selectList(eq);
if (CollectionUtils.isEmpty(ztStories)) { if (CollectionUtils.isEmpty(ztStories)) {
@@ -461,7 +512,7 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
actionStatus = ActionStatus.PSBTG; actionStatus = ActionStatus.PSBTG;
} }
if (dto.getRevieweResult() != 1){ if (dto.getRevieweResult() != 1) {
ZtUser u = this.userService.getByAccount(ztStory.getOpenedby()); ZtUser u = this.userService.getByAccount(ztStory.getOpenedby());
if (u != null && !StringUtils.isEmpty(u.getEmail())) { if (u != null && !StringUtils.isEmpty(u.getEmail())) {
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();
@@ -486,7 +537,6 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
} }
lambda.set(ZtStoryreview::getReviewdate, new Date()); lambda.set(ZtStoryreview::getReviewdate, new Date());
lambda.eq(ZtStoryreview::getStory, ztStory.getId()); lambda.eq(ZtStoryreview::getStory, ztStory.getId());
lambda.eq(ZtStoryreview::getReviewer, RiskUserThreadLocal.get().getName()); lambda.eq(ZtStoryreview::getReviewer, RiskUserThreadLocal.get().getName());
@@ -527,10 +577,6 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
//添加action //添加action
actionService.addAction(ActionType.USERXQ, actionStatus, ztStory.getId(), ztStory.getProduct() + "", ztStory.getProject(), null, actionService.addAction(ActionType.USERXQ, actionStatus, ztStory.getId(), ztStory.getProduct() + "", ztStory.getProject(), null,
RiskUserThreadLocal.get().getName(), dto.getDesc(), ztStory.getAssignedto()); RiskUserThreadLocal.get().getName(), dto.getDesc(), ztStory.getAssignedto());
return null; return null;
} }
@@ -562,7 +608,7 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
if (ztUser != null) { if (ztUser != null) {
dto.setProductUserName(ztUser.getNickname()); dto.setProductUserName(ztUser.getNickname());
} }
Map<Integer, List<ZtStory>> storyUserMap = getStoryUserMap(Arrays.asList(dto)); Map<Integer, List<ZtStory>> storyUserMap = getStoryMap(Arrays.asList(dto));
List<ZtStory> ztStories = storyUserMap.get(d.getId()); List<ZtStory> ztStories = storyUserMap.get(d.getId());
if (!CollectionUtils.isEmpty(ztStories)) { if (!CollectionUtils.isEmpty(ztStories)) {
dto.setStoryList(ztStories.stream().map(o -> o.getTitle()).collect(Collectors.joining(","))); dto.setStoryList(ztStories.stream().map(o -> o.getTitle()).collect(Collectors.joining(",")));
@@ -615,8 +661,9 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
List<ZtStory> list = this.storyService.list(new QueryWrapper<ZtStory>().lambda().eq(ZtStory::getUserStory, dto.getId())); List<ZtStory> list = this.storyService.list(new QueryWrapper<ZtStory>().lambda().eq(ZtStory::getUserStory, dto.getId()));
if (!CollectionUtils.isEmpty(list)) { if (!CollectionUtils.isEmpty(list)) {
List<ZtStoryDTO> storyDTOList = BeanCopyUtil.copyListProperties(list, ZtStoryDTO::new); List<ZtStoryDTO> storyDTOList = BeanCopyUtil.copyListProperties(list, ZtStoryDTO::new);
if (!CollectionUtils.isEmpty(storyDTOList)) { Map<Integer,List<ZtProject>> execMap= getExecMap(list.stream().collect(Collectors.groupingBy(ZtStory::getId)));
if (!CollectionUtils.isEmpty(storyDTOList)) {
for (ZtStoryDTO storyDTO : storyDTOList) { for (ZtStoryDTO storyDTO : storyDTOList) {
ztUser = userMap.get(storyDTO.getAssignedTo()); ztUser = userMap.get(storyDTO.getAssignedTo());
if (ztUser != null) { if (ztUser != null) {
@@ -626,10 +673,19 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
if (ztUser != null) { if (ztUser != null) {
storyDTO.setOpenedbyName(ztUser.getNickname()); storyDTO.setOpenedbyName(ztUser.getNickname());
} }
List<ZtProject> 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); dto.setSList(storyDTOList);
} }
//story - exec
} }
List<ZtStoryUserTask> tasks = this.storyUserTaskService.list(new QueryWrapper<ZtStoryUserTask>().lambda().eq(ZtStoryUserTask::getUserStoryId, dto.getId())); List<ZtStoryUserTask> tasks = this.storyUserTaskService.list(new QueryWrapper<ZtStoryUserTask>().lambda().eq(ZtStoryUserTask::getUserStoryId, dto.getId()));
if (!CollectionUtils.isEmpty(tasks)) { if (!CollectionUtils.isEmpty(tasks)) {
@@ -651,10 +707,11 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
dto.setViews(rMap.get(d.getId())); dto.setViews(rMap.get(d.getId()));
List<ZtStoryUserspec> specList = this.storyUserspecService.list(new QueryWrapper<ZtStoryUserspec>().lambda().eq(ZtStoryUserspec::getStory, dto.getId())); List<ZtStoryUserspec> specList = this.storyUserspecService.list(new QueryWrapper<ZtStoryUserspec>().lambda().eq(ZtStoryUserspec::getStory, dto.getId()));
if(!CollectionUtils.isEmpty(specList)){ if (!CollectionUtils.isEmpty(specList)) {
ZtStoryUserspec ztStoryUserspec = specList.get(0); ZtStoryUserspec ztStoryUserspec = specList.get(0);
dto.setSpec(ztStoryUserspec.getSpec()); dto.setSpec(ztStoryUserspec.getSpec());
dto.setVerify(ztStoryUserspec.getVerify()); dto.setVerify(ztStoryUserspec.getVerify());
dto.setStoryBackground(ztStoryUserspec.getStoryBackground());
} }
return dto; return dto;
@@ -707,7 +764,6 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
} }
@Override @Override
public void changeStatus(Integer id, UserStoryEnums status) { public void changeStatus(Integer id, UserStoryEnums status) {
ZtStoryUser storyUser = this.baseMapper.selectById(id); ZtStoryUser storyUser = this.baseMapper.selectById(id);
@@ -730,24 +786,24 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
ZtProduct ztProduct = this.productService.getById(storyUser.getProduct()); ZtProduct ztProduct = this.productService.getById(storyUser.getProduct());
//需求已确认 //需求已确认
this.sendDesigndoneMessage(storyUser.getId(),ztProduct.getPo()); this.sendDesigndoneMessage(storyUser.getId(), ztProduct.getPo());
} }
if (UserStoryEnums.DQR == status) { if (UserStoryEnums.DQR == status) {
//提交交付物发送给创建人 //提交交付物发送给创建人
this.sendSubmitMessage(storyUser.getId(),storyUser.getOpenedby()); this.sendSubmitMessage(storyUser.getId(), storyUser.getOpenedby());
} }
if (UserStoryEnums.CFM == status&&oldStatus.equals("storyunconfirmed")) { if (UserStoryEnums.CFM == status && oldStatus.equals("storyunconfirmed")) {
ZtProduct ztProduct = this.productService.getById(storyUser.getProduct()); ZtProduct ztProduct = this.productService.getById(storyUser.getProduct());
//交付物确认 //交付物确认
this.sendConfirmMessage(storyUser.getId(),ztProduct.getPo()); this.sendConfirmMessage(storyUser.getId(), ztProduct.getPo());
} }
if(UserStoryEnums.RELEASED == status){ if (UserStoryEnums.RELEASED == status) {
//如果研发需求已经全部发布,那么就发布 //如果研发需求已经全部发布,那么就发布
// wait 初始化 projected 已立项 developing 研发中 developed 研发完毕 testing 测试中 tested // wait 初始化 projected 已立项 developing 研发中 developed 研发完毕 testing 测试中 tested
List<ZtStory> storyList = this.storyService.list(new QueryWrapper<ZtStory>().lambda() List<ZtStory> storyList = this.storyService.list(new QueryWrapper<ZtStory>().lambda()
.ne(ZtStory::getStatus, "closed").in(ZtStory::getStage, StoryStageEnums.beforeStatus(7)).eq(ZtStory::getUserStory, id)); .ne(ZtStory::getStatus, "closed").in(ZtStory::getStage, StoryStageEnums.beforeStatus(7)).eq(ZtStory::getUserStory, id));
if(!CollectionUtils.isEmpty(storyList)){ if (!CollectionUtils.isEmpty(storyList)) {
return ; return;
} }
} }
storyUser.setStatus(status.getCode()); storyUser.setStatus(status.getCode());
@@ -823,7 +879,7 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
this.baseMapper.updateById(storyUser); this.baseMapper.updateById(storyUser);
if(status==UserStoryEnums.CPYSJ){ if (status == UserStoryEnums.CPYSJ) {
//发送消息 //发送消息
} }
@@ -883,7 +939,7 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
@Override @Override
public void assignedToProductUser(ZtStoryUserDTO dto) { public void assignedToProductUser(ZtStoryUserDTO dto) {
ZtStoryUser ztStoryUser = this.baseMapper.selectById(dto.getId()); ZtStoryUser ztStoryUser = this.baseMapper.selectById(dto.getId());
if(ztStoryUser==null){ if (ztStoryUser == null) {
throw new BusinessException("未查询到数据"); throw new BusinessException("未查询到数据");
} }
ztStoryUser.setProductUser(dto.getAssignedto()); ztStoryUser.setProductUser(dto.getAssignedto());
@@ -892,7 +948,7 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
RiskUserThreadLocal.get().getName(), "", ""); RiskUserThreadLocal.get().getName(), "", "");
} }
private Map<Integer, List<ZtStory>> getStoryUserMap(List<ZtStoryUserDTO> list) { private Map<Integer, List<ZtStory>> getStoryMap(List<ZtStoryUserDTO> list) {
List<Integer> ids = list.stream().map(o -> o.getId()).collect(Collectors.toList()); List<Integer> ids = list.stream().map(o -> o.getId()).collect(Collectors.toList());
List<ZtStory> list1 = storyService.list(new QueryWrapper<ZtStory>().lambda().in(ZtStory::getUserStory, ids)); List<ZtStory> list1 = storyService.list(new QueryWrapper<ZtStory>().lambda().in(ZtStory::getUserStory, ids));
@@ -930,16 +986,19 @@ public class ZtStoryUserServiceImpl extends ServiceImpl<ZtStoryUserMapper, ZtSto
} }
} }
//发送消息给微信 产品已经设计 //发送消息给微信 产品已经设计
private void sendDesigndoneMessage(Integer id,String account) { private void sendDesigndoneMessage(Integer id, String account) {
this.vxService.sendMessageToVx(account, VxMessageUtils.storyUserMessage.designdoneMessage(id),new Date()); this.vxService.sendMessageToVx(account, VxMessageUtils.storyUserMessage.designdoneMessage(id), new Date());
} }
//发送消息给微信 提交交付物 //发送消息给微信 提交交付物
private void sendSubmitMessage(Integer id,String account) { private void sendSubmitMessage(Integer id, String account) {
this.vxService.sendMessageToVx(account, VxMessageUtils.storyUserMessage.submitMessage(id),new Date()); this.vxService.sendMessageToVx(account, VxMessageUtils.storyUserMessage.submitMessage(id), new Date());
} }
//确认交付物 //确认交付物
private void sendConfirmMessage(Integer id,String account) { private void sendConfirmMessage(Integer id, String account) {
this.vxService.sendMessageToVx(account, VxMessageUtils.storyUserMessage.sendConfirmMessage(id),new Date()); this.vxService.sendMessageToVx(account, VxMessageUtils.storyUserMessage.sendConfirmMessage(id), new Date());
} }
} }

View File

@@ -232,6 +232,7 @@ public class ZtTaskServiceImpl extends ServiceImpl<ZtTaskMapper, ZtTask> impleme
ZtStory ztStory = this.storyService.getById(story); ZtStory ztStory = this.storyService.getById(story);
if (ztStory != null) { if (ztStory != null) {
dto.setStoryName(ztStory.getTitle()); dto.setStoryName(ztStory.getTitle());
dto.setInnerYsFlag(ztStory.getInnerYsFlag());
} }
} }
@@ -578,8 +579,8 @@ public class ZtTaskServiceImpl extends ServiceImpl<ZtTaskMapper, ZtTask> impleme
if (story != null && story != 0) { if (story != null && story != 0) {
ZtStory ztStory = this.storyService.getById(story); ZtStory ztStory = this.storyService.getById(story);
// wait 初始化 projected 已立项 developing 研发中 developed 研发完毕 testing 测试中 tested // wait 初始化 projected 已立项 developing 研发中 developed 研发完毕 testing 测试中 tested
if (!Arrays.asList("wait", "projected", "developing", "developed", "testing", "tested",StoryStageEnums.productWaitVerified.getValue() if (!Arrays.asList("wait", "projected", "developing", "developed", "testing", "tested", StoryStageEnums.productWaitVerified.getValue()
,StoryStageEnums.productVerified.getValue()).contains(ztStory.getStage())) { , StoryStageEnums.productVerified.getValue()).contains(ztStory.getStage())) {
throw new BusinessException("当前状态无法添加任务"); throw new BusinessException("当前状态无法添加任务");
} }
if (ztStory.getStatus().equals("closed")) { if (ztStory.getStatus().equals("closed")) {
@@ -1037,7 +1038,7 @@ public class ZtTaskServiceImpl extends ServiceImpl<ZtTaskMapper, ZtTask> impleme
StringUtils.isEmpty(finishBy) ? RiskUserThreadLocal.get().getName() : finishBy, dto.getDeliverContent(), null); StringUtils.isEmpty(finishBy) ? RiskUserThreadLocal.get().getName() : finishBy, dto.getDeliverContent(), null);
if (ztTask.getStory() != null && ztTask.getStory() != 0) { if (ztTask.getStory() != null && ztTask.getStory() != 0) {
ZtStory ztStory = this.storyService.getById(ztTask.getStory()); ZtStory ztStory = this.storyService.getById(ztTask.getStory());
if(ztStory!=null){ if (ztStory != null) {
ztStory.setDeliverContent(dto.getDeliverContent()); ztStory.setDeliverContent(dto.getDeliverContent());
ztStory.setLasteditedby(RiskUserThreadLocal.get().getName()); ztStory.setLasteditedby(RiskUserThreadLocal.get().getName());
ztStory.setLastediteddate(new Date()); ztStory.setLastediteddate(new Date());
@@ -1054,40 +1055,41 @@ public class ZtTaskServiceImpl extends ServiceImpl<ZtTaskMapper, ZtTask> impleme
actionService.addAction(ActionType.RW, ActionStatus.WC, dto.getId(), projectproduct == null ? null : projectproduct.getProduct().toString(), projectproduct == null ? null : projectproduct.getProject(), ztTask.getExecution(), 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); StringUtils.isEmpty(finishBy) ? RiskUserThreadLocal.get().getName() : finishBy, "", null);
if (ztTask.getExecution() != null && ztTask.getExecution() != 0) { if (ztTask.getExecution() != null && ztTask.getExecution() != 0) {
if (StringUtils.isEmpty(dto.getTabType())) { if (StringUtils.isEmpty(dto.getTabType())) {
kanbanlaneService.changeStatus(ztTask.getExecution(), ztTask.getId(), "task", "developed"); kanbanlaneService.changeStatus(ztTask.getExecution(), ztTask.getId(), "task", "developed");
} else { } else {
KanbanQo qo = new KanbanQo(); KanbanQo qo = new KanbanQo();
qo.setStatusType(dto.getStatusType()); qo.setStatusType(dto.getStatusType());
qo.setTabType(dto.getTabType()); qo.setTabType(dto.getTabType());
qo.setId(dto.getId()); qo.setId(dto.getId());
qo.setFromId(dto.getFromId()); qo.setFromId(dto.getFromId());
qo.setToId(dto.getToId()); qo.setToId(dto.getToId());
kanbanlaneService.changeStatus(qo); kanbanlaneService.changeStatus(qo);
}
} }
// devel 开发 request 需求 test }
//如果有一个开发任务进行中,并且所有的测试任务还没有开始,需求的研发阶段为“研发中” // devel 开发 request 需求 test
//如果所有的开发任务已经完成,并且所有的测试任务还没有开始,为“研发完毕" //如果有一个开发任务进行中,并且所有的测试任务还没有开始,需求的研发阶段为“研发中”
//如果有一个测试任务进行中,则为“测试中” //如果所有的开发任务已经完成,并且所有的测试任务还没有开始,则为“研发完毕"
//如果所有的测试任务已经结束,但还有一些开发任务没有结束,则视为"测试中" //如果有一个测试任务进行中,则视为测试中
//如果所有的测试任务已经结束,并且所有的开发任务已经结束,则视为"测试完毕" //如果所有的测试任务已经结束,但还有一些开发任务没有结束,则视为"测试"
//如果所有的测试任务已经结束,并且所有的开发任务已经结束,则视为"测试完毕"
// pause 暂停 cancel取消 closed 关闭 done 完成 wait reviewing待评审 doing // pause 暂停 cancel取消 closed 关闭 done 完成 wait reviewing待评审 doing
// devel 开发 request 需求 test // devel 开发 request 需求 test
String type = ztTask.getType(); String type = ztTask.getType();
if (ztTask.getStory() != null && ztTask.getStory() != 0) { if (ztTask.getStory() != null && ztTask.getStory() != 0) {
this.storyService.taskFinishChangeStatus(ztTask.getStory(), finishBy, TaskType.transferType(type), false); this.storyService.taskFinishChangeStatus(ztTask.getStory(), finishBy, TaskType.transferType(type), false);
} }
if (ztTask.getFeedback() != null && ztTask.getFeedback() != 0) { if (ztTask.getFeedback() != null && ztTask.getFeedback() != 0) {
this.storyFeedbackService.feedbackFinished(ztTask.getFeedback(), ztTask.getFeedbackRemark()); this.storyFeedbackService.feedbackFinished(ztTask.getFeedback(), ztTask.getFeedbackRemark());
} }
if (ztTask.getStory() != null && ztTask.getStory() != 0 && ObjectUtil.equal(dto.getInnerYsFlag(), 1)) { // if (ztTask.getStory() != null && ztTask.getStory() != 0 && ObjectUtil.equal(dto.getInnerYsFlag(), 1)) {
ZtStoryDTO qo = new ZtStoryDTO(); // ZtStoryDTO qo = new ZtStoryDTO();
qo.setId(ztTask.getStory()); // qo.setId(ztTask.getStory());
this.storyService.testSubmitVerified(qo); // this.storyService.testSubmitVerified(qo);
} // }
} }
@Override @Override
@Transactional @Transactional
public void closeTask(ZtTaskDTO dto) { public void closeTask(ZtTaskDTO dto) {

View File

@@ -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<String, KanbanColumnType> STORY_STAGE_MAP = new HashMap<>();
/**
* 任务状态到看板列的映射
*/
private static final Map<String, KanbanColumnType> 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();
}
}

View File

@@ -64,7 +64,7 @@
</resultMap> </resultMap>
<select id="pageList" resultType="com.sa.zentao.dao.ZtStoryDTO"> <select id="pageList" resultType="com.sa.zentao.dao.ZtStoryDTO">
select select
s.id, s.id,
s.vision, s.vision,
@@ -147,78 +147,86 @@
s.test_user, s.test_user,
s.product_user s.product_user
from zt_story s from zt_story s
left join zt_story_user su on s.user_story = su.id left join zt_story_user su on s.user_story = su.id
left join zt_storyreview v on s.id = v.story and s.version = v.version left join zt_storyreview v on s.id = v.story and s.version = v.version
left join zt_story ps on s.parent = ps.id left join zt_story ps on s.parent = ps.id
where 1=1
and s.product = #{qo.productId}
<if test="qo.searchVal == 'ALL' ">
</if> <if test="qo.execution != null and qo.execution != '' ">
<if test="qo.searchVal == 'WGB' "> left join zt_projectstory pstory on s.id = pstory.story and pstory.type = 'execution'
and s.status != 'closed' </if>
</if> where 1=1
<if test="qo.searchVal != null and qo.searchVal == 'WDCP' "> and s.product = #{qo.productId}
and s.product_user = #{qo.userName} <if test="qo.execution != null and qo.execution != '' ">
</if> and pstory.project = #{qo.execution }
</if>
<if test="qo.searchVal != null and qo.searchVal == 'WCS' "> <if test="qo.searchVal == 'ALL' ">
and s.test_user = #{qo.userName}
</if>
<if test="qo.searchVal != null and qo.searchVal == 'ZGW' ">
and s.assignedTo= #{qo.userName}
</if>
<if test="qo.searchVal != null and qo.searchVal == 'WDCP' ">
and s.product_user= #{qo.userName}
</if>
<if test="qo.searchVal != null and qo.searchVal == 'WCJ' "> </if>
and s.openedBy= #{qo.userName} <if test="qo.searchVal == 'WGB' ">
</if> and s.status != 'closed'
</if>
<if test="qo.searchVal != null and qo.searchVal == 'WDCP' ">
and s.product_user = #{qo.userName}
</if>
<if test="qo.searchVal != null and qo.searchVal == 'YWPS' "> <if test="qo.searchVal != null and qo.searchVal == 'WCS' ">
and v.reviewer = #{qo.userName} and s.test_user = #{qo.userName}
and s.status ='reviewing' </if>
and v.result = '' <if test="qo.searchVal != null and qo.searchVal == 'ZGW' ">
</if> and s.assignedTo= #{qo.userName}
</if>
<if test="qo.searchVal != null and qo.searchVal == 'WDCP' ">
and s.product_user= #{qo.userName}
</if>
<if test="qo.searchVal != null and qo.searchVal == 'JH' "> <if test="qo.searchVal != null and qo.searchVal == 'WCJ' ">
and s.status = 'active' and s.openedBy= #{qo.userName}
</if> </if>
<if test="qo.searchVal != null and qo.searchVal == 'YGB' ">
and s.status = 'closed'
</if>
<if test="qo.searchVal != null and qo.searchVal == 'DGB' "> <if test="qo.searchVal != null and qo.searchVal == 'YWPS' ">
and s.stage = 'verified' and s.ys_flag =1 and v.reviewer = #{qo.userName}
</if> and s.status ='reviewing'
<if test="qo.searchVal != null and qo.searchVal == 'BGZ' "> and v.result = ''
and s.status = '11' </if>
</if>
<if test="qo.searchVal != null and qo.searchVal == 'WZP' "> <if test="qo.searchVal != null and qo.searchVal == 'JH' ">
and s.status = '11' and s.status = 'active'
</if> </if>
<if test="qo.searchVal != null and qo.searchVal == 'YGB' ">
and s.status = 'closed'
</if>
<if test="qo.searchVal != null and qo.searchVal == 'WYS' "> <if test="qo.searchVal != null and qo.searchVal == 'DGB' ">
and s.ys_user = #{qo.userName} and s.stage = 'verified' and s.ys_flag =1
</if> </if>
<if test="qo.searchVal != null and qo.searchVal == 'BGZ' ">
and s.status = '11'
</if>
<if test="qo.searchVal != null and qo.searchVal == 'WPS' "> <if test="qo.searchVal != null and qo.searchVal == 'WZP' ">
and s.reviewedBy like concat('%', #{qo.userName}, '%') and s.status = '11'
</if> </if>
<if test="qo.searchVal != null and qo.searchVal == 'WYS' ">
and s.ys_user = #{qo.userName}
</if>
<if test="qo.searchVal != null and qo.searchVal == 'WPS' ">
and s.reviewedBy like concat('%', #{qo.userName}, '%')
</if>
<if test="qo.searchVal != null and qo.searchVal == 'PSZ' "> <if test="qo.searchVal != null and qo.searchVal == 'PSZ' ">
and s.status = 'reviewing' and s.status = 'reviewing'
</if> </if>
<if test="qo.searchVal != null and qo.searchVal == 'DYS' "> <if test="qo.searchVal != null and qo.searchVal == 'DYS' ">
and ( s.stage = 'released' and ( s.stage = 'released'
and s.ys_flag =0) and s.ys_flag =0)
or (s.stage = 'verified' and s.ys_flag =2) or (s.stage = 'verified' and s.ys_flag =2)
</if> </if>
<if test="qo.name != null and qo.name != '' "> <if test="qo.name != null and qo.name != '' ">
and s.title like concat('%', #{qo.name}, '%') and s.title like concat('%', #{qo.name}, '%')
</if> </if>
@@ -227,24 +235,24 @@
</if> </if>
<if test="qo.testUser != null and qo.testUser != '' "> <if test="qo.testUser != null and qo.testUser != '' ">
and s.test_user like concat('%', #{qo.testUser}, '%') and s.test_user like concat('%', #{qo.testUser}, '%')
</if> </if>
<if test="qo.productUser != null and qo.productUser != '' "> <if test="qo.productUser != null and qo.productUser != '' ">
and s.product_user like concat('%', #{qo.productUser}, '%') and s.product_user like concat('%', #{qo.productUser}, '%')
</if> </if>
<if test="qo.id != null "> <if test="qo.id != null ">
and s.id = #{qo.id} and s.id = #{qo.id}
</if> </if>
<if test="qo.title != null and qo.title != '' "> <if test="qo.title != null and qo.title != '' ">
and s.title like concat('%', #{qo.title}, '%') and s.title like concat('%', #{qo.title}, '%')
</if> </if>
<if test="qo.productUser != null and qo.productUser != '' "> <if test="qo.productUser != null and qo.productUser != '' ">
and s.product_user like concat('%', #{qo.productUser}, '%') and s.product_user like concat('%', #{qo.productUser}, '%')
</if> </if>
<if test="qo.module != null and qo.module != '' "> <if test="qo.module != null and qo.module != '' ">
and s.module = #{qo.module} and s.module = #{qo.module}
</if> </if>
<if test="qo.assignedTo != null and qo.assignedTo != '' "> <if test="qo.assignedTo != null and qo.assignedTo != '' ">
and s.assignedTo = #{qo.assignedTo} and s.assignedTo = #{qo.assignedTo}
</if> </if>
@@ -263,6 +271,7 @@
and s.openedBy = #{qo.openedby} and s.openedBy = #{qo.openedby}
</if> </if>
<if test="qo.startDate !=null"> <if test="qo.startDate !=null">
and s.openedDate <![CDATA[>=]]> #{qo.startDate} and s.openedDate <![CDATA[>=]]> #{qo.startDate}
</if> </if>
@@ -294,14 +303,14 @@
#{id} #{id}
</foreach> </foreach>
</if> </if>
group by s.id group by s.id
<choose> <choose>
<when test="qo.orderName != '' and qo.orderName != null "> <when test="qo.orderName != '' and qo.orderName != null ">
<choose> <choose>
<when test="qo.orderSort != '' and qo.orderSort != null "> <when test="qo.orderSort != '' and qo.orderSort != null ">
order by s.${qo.orderName} ${qo.orderSort} order by s.${qo.orderName} ${qo.orderSort}
</when> </when>
<otherwise> <otherwise>
order by s.id desc order by s.id desc
@@ -312,7 +321,7 @@
order by s.id desc order by s.id desc
</otherwise> </otherwise>
</choose> </choose>
-- order by id desc -- order by id desc
</select> </select>
<select id="projectStoryPageList" resultType="com.sa.zentao.dao.ZtStoryDTO"> <select id="projectStoryPageList" resultType="com.sa.zentao.dao.ZtStoryDTO">
select s.id, select s.id,