fix(缺陷管理): 修复缺陷操作相关的通知问题

--bug=1036449 --user=宋昌昌 【项目管理】消息通知-批量编辑缺陷-未发送通知 https://www.tapd.cn/55049933/s/1467801
This commit is contained in:
song-cc-rock 2024-03-01 16:01:56 +08:00 committed by 刘瑞斌
parent 8265d5f21b
commit ceafebe073
5 changed files with 94 additions and 117 deletions

View File

@ -125,8 +125,8 @@ public class BugController {
@GetMapping("/delete/{id}") @GetMapping("/delete/{id}")
@Operation(summary = "缺陷管理-列表-删除缺陷") @Operation(summary = "缺陷管理-列表-删除缺陷")
@RequiresPermissions(PermissionConstants.PROJECT_BUG_DELETE) @RequiresPermissions(PermissionConstants.PROJECT_BUG_DELETE)
@Log(type = OperationLogType.DELETE, expression = "#msClass.deleteLog(#id)", msClass = BugLogService.class)
@SendNotice(taskType = NoticeConstants.TaskType.BUG_TASK, event = NoticeConstants.Event.DELETE, target = "#targetClass.getNoticeById(#id)", targetClass = BugNoticeService.class) @SendNotice(taskType = NoticeConstants.TaskType.BUG_TASK, event = NoticeConstants.Event.DELETE, target = "#targetClass.getNoticeById(#id)", targetClass = BugNoticeService.class)
@Log(type = OperationLogType.DELETE, expression = "#msClass.deleteLog(#id)", msClass = BugLogService.class)
public void delete(@PathVariable String id) { public void delete(@PathVariable String id) {
bugService.delete(id, SessionUtils.getUserId()); bugService.delete(id, SessionUtils.getUserId());
} }
@ -176,6 +176,7 @@ public class BugController {
@Operation(summary = "缺陷管理-列表-批量删除缺陷") @Operation(summary = "缺陷管理-列表-批量删除缺陷")
@RequiresPermissions(PermissionConstants.PROJECT_BUG_DELETE) @RequiresPermissions(PermissionConstants.PROJECT_BUG_DELETE)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project") @CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
@SendNotice(taskType = NoticeConstants.TaskType.BUG_TASK, event = NoticeConstants.Event.DELETE, target = "#targetClass.getBatchNoticeByRequest(#request)", targetClass = BugNoticeService.class)
public void batchDelete(@Validated @RequestBody BugBatchRequest request) { public void batchDelete(@Validated @RequestBody BugBatchRequest request) {
request.setUseTrash(false); request.setUseTrash(false);
bugService.batchDelete(request, SessionUtils.getUserId()); bugService.batchDelete(request, SessionUtils.getUserId());
@ -185,6 +186,7 @@ public class BugController {
@Operation(summary = "缺陷管理-列表-批量编辑缺陷") @Operation(summary = "缺陷管理-列表-批量编辑缺陷")
@RequiresPermissions(PermissionConstants.PROJECT_BUG_UPDATE) @RequiresPermissions(PermissionConstants.PROJECT_BUG_UPDATE)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project") @CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
@SendNotice(taskType = NoticeConstants.TaskType.BUG_TASK, event = NoticeConstants.Event.UPDATE, target = "#targetClass.getBatchNoticeByRequest(#request)", targetClass = BugNoticeService.class)
public void batchUpdate(@Validated @RequestBody BugBatchUpdateRequest request) { public void batchUpdate(@Validated @RequestBody BugBatchUpdateRequest request) {
request.setUseTrash(false); request.setUseTrash(false);
bugService.batchUpdate(request, SessionUtils.getUserId()); bugService.batchUpdate(request, SessionUtils.getUserId());

View File

@ -106,7 +106,7 @@ public class BugLogService {
* @param id 缺陷ID * @param id 缺陷ID
* @return 缺陷DTO * @return 缺陷DTO
*/ */
private BugDTO getOriginalValue(String id) { public BugDTO getOriginalValue(String id) {
// 缺陷基础信息 // 缺陷基础信息
BugDTO originalBug = new BugDTO(); BugDTO originalBug = new BugDTO();
Bug bug = bugMapper.selectByPrimaryKey(id); Bug bug = bugMapper.selectByPrimaryKey(id);

View File

@ -1,27 +1,19 @@
package io.metersphere.bug.service; package io.metersphere.bug.service;
import io.metersphere.bug.domain.Bug; import io.metersphere.bug.dto.request.BugBatchRequest;
import io.metersphere.bug.dto.request.BugEditRequest; import io.metersphere.bug.dto.request.BugEditRequest;
import io.metersphere.bug.dto.response.BugCustomFieldDTO; import io.metersphere.bug.dto.response.BugDTO;
import io.metersphere.bug.mapper.ExtBugCustomFieldMapper;
import io.metersphere.plugin.platform.dto.SelectOption; import io.metersphere.plugin.platform.dto.SelectOption;
import io.metersphere.system.domain.User; import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.system.dto.BugNoticeDTO; import io.metersphere.system.dto.BugNoticeDTO;
import io.metersphere.system.dto.sdk.OptionDTO; import io.metersphere.system.dto.sdk.OptionDTO;
import io.metersphere.system.mapper.UserMapper;
import io.metersphere.system.notice.NoticeModel;
import io.metersphere.system.notice.constants.NoticeConstants;
import io.metersphere.system.notice.utils.MessageTemplateUtils;
import io.metersphere.system.service.NoticeSendService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -35,15 +27,13 @@ public class BugNoticeService {
public static final String CUSTOM_HANDLE_USER = "处理人"; public static final String CUSTOM_HANDLE_USER = "处理人";
@Resource @Resource
private UserMapper userMapper; private BugService bugService;
@Resource
private BugLogService bugLogService;
@Resource @Resource
private BugCommonService bugCommonService; private BugCommonService bugCommonService;
@Resource @Resource
private BugStatusService bugStatusService; private BugStatusService bugStatusService;
@Resource
private NoticeSendService noticeSendService;
@Resource
private ExtBugCustomFieldMapper extBugCustomFieldMapper;
/** /**
* 获取缺陷通知 * 获取缺陷通知
@ -84,43 +74,46 @@ public class BugNoticeService {
} }
/** /**
* 发送删除缺陷通知 * 获取缺陷通知
* @param bug 缺陷 * @param id 缺陷ID
* @param currentUser 当前用户
*/ */
public void sendDeleteNotice(Bug bug, String currentUser) { public BugNoticeDTO getNoticeById(String id) {
Map<String, String> statusMap = getStatusMap(bug.getProjectId()); // 缺陷基础信息
Map<String, String> handlerMap = getHandleMap(bug.getProjectId()); BugDTO bugDTO = bugLogService.getOriginalValue(id);
// 缺陷相关内容 // 构建通知对象
BugNoticeDTO notice = new BugNoticeDTO(); BugNoticeDTO notice = new BugNoticeDTO();
notice.setTitle(bug.getTitle()); BeanUtils.copyBean(notice, bugDTO);
notice.setStatus(statusMap.get(bug.getStatus())); // 自定义字段解析{name: value}
notice.setHandleUser(handlerMap.get(bug.getHandleUser())); if (CollectionUtils.isNotEmpty(bugDTO.getCustomFields())) {
List<BugCustomFieldDTO> customFields = extBugCustomFieldMapper.getBugAllCustomFields(List.of(bug.getId()), bug.getProjectId()); List<OptionDTO> fields = new ArrayList<>();
List<OptionDTO> fields = customFields.stream().map(field -> { bugDTO.getCustomFields().forEach(field -> {
OptionDTO fieldDTO = new OptionDTO(); // 其他自定义字段
fieldDTO.setId(field.getName()); OptionDTO fieldDTO = new OptionDTO();
fieldDTO.setName(field.getValue()); fieldDTO.setId(field.getName());
return fieldDTO; fieldDTO.setName(field.getValue());
}).toList(); fields.add(fieldDTO);
notice.setCustomFields(fields); });
BeanMap beanMap = new BeanMap(notice); notice.setCustomFields(fields);
User user = userMapper.selectByPrimaryKey(currentUser); }
Map paramMap = new HashMap<>(beanMap); return notice;
paramMap.put(NoticeConstants.RelatedUser.OPERATOR, user.getName()); }
Map<String, String> defaultTemplateMap = MessageTemplateUtils.getDefaultTemplateMap();
String template = defaultTemplateMap.get(NoticeConstants.TemplateText.BUG_TASK_DELETE); /**
Map<String, String> defaultSubjectMap = MessageTemplateUtils.getDefaultTemplateSubjectMap(); * 获取批量操作的缺陷通知
String subject = defaultSubjectMap.get(NoticeConstants.TemplateText.BUG_TASK_DELETE); * @param request 批量请求参数
NoticeModel noticeModel = NoticeModel.builder().operator(currentUser) * @return 缺陷通知集合
.context(template).subject(subject).paramMap(paramMap).event(NoticeConstants.Event.DELETE).build(); */
noticeSendService.send(NoticeConstants.TaskType.BUG_TASK, noticeModel); public List<BugNoticeDTO> getBatchNoticeByRequest(BugBatchRequest request) {
List<BugNoticeDTO> notices = new ArrayList<>();
List<String> batchIds = bugService.getBatchIdsByRequest(request);
batchIds.forEach(id -> notices.add(getNoticeById(id)));
return notices;
} }
/** /**
* 获取状态集合 * 获取状态集合
* @param projectId 项目ID * @param projectId 项目ID
* @return * @return 状态集合
*/ */
private Map<String, String> getStatusMap(String projectId) { private Map<String, String> getStatusMap(String projectId) {
List<SelectOption> statusOption = bugStatusService.getHeaderStatusOption(projectId); List<SelectOption> statusOption = bugStatusService.getHeaderStatusOption(projectId);

View File

@ -91,8 +91,6 @@ import static io.metersphere.bug.enums.result.BugResultCode.NOT_LOCAL_BUG_ERROR;
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public class BugService { public class BugService {
private static int MAX_TAG_SIZE = 10;
@Resource @Resource
private BugMapper bugMapper; private BugMapper bugMapper;
@Resource @Resource
@ -118,8 +116,6 @@ public class BugService {
@Resource @Resource
private BaseTemplateCustomFieldService baseTemplateCustomFieldService; private BaseTemplateCustomFieldService baseTemplateCustomFieldService;
@Resource @Resource
private BugNoticeService bugNoticeService;
@Resource
private BugCommonService bugCommonService; private BugCommonService bugCommonService;
@Resource @Resource
private BugCustomFieldMapper bugCustomFieldMapper; private BugCustomFieldMapper bugCustomFieldMapper;
@ -162,6 +158,8 @@ public class BugService {
public static final Long INTERVAL_POS = 5000L; public static final Long INTERVAL_POS = 5000L;
private static final int MAX_TAG_SIZE = 10;
/** /**
* 缺陷列表查询 * 缺陷列表查询
* *
@ -178,12 +176,6 @@ public class BugService {
return buildExtraInfo(bugList); return buildExtraInfo(bugList);
} }
private void checkTagLength(List<String> tags) {
if (CollectionUtils.isNotEmpty(tags) && tags.size() > MAX_TAG_SIZE) {
throw new MSException(Translator.getWithArgs("bug_tags_size_large_than", String.valueOf(MAX_TAG_SIZE)));
}
}
/** /**
* 创建或编辑缺陷 * 创建或编辑缺陷
* *
@ -332,8 +324,6 @@ public class BugService {
clearAssociate(id, bug.getProjectId()); clearAssociate(id, bug.getProjectId());
bugMapper.deleteByPrimaryKey(id); bugMapper.deleteByPrimaryKey(id);
} }
// 发送通知
bugNoticeService.sendDeleteNotice(bug, currentUser);
} }
/** /**
@ -1511,4 +1501,14 @@ public class BugService {
Set<Object> keySet = ConcurrentHashMap.newKeySet(); Set<Object> keySet = ConcurrentHashMap.newKeySet();
return t -> keySet.add(function.apply(t)); return t -> keySet.add(function.apply(t));
} }
/**
* 校验TAG长度
* @param tags 标签集合
*/
private void checkTagLength(List<String> tags) {
if (CollectionUtils.isNotEmpty(tags) && tags.size() > MAX_TAG_SIZE) {
throw new MSException(Translator.getWithArgs("bug_tags_size_large_than", String.valueOf(MAX_TAG_SIZE)));
}
}
} }

View File

@ -123,53 +123,48 @@
</template> </template>
<script lang="ts" async setup> <script lang="ts" async setup>
import { useRoute } from 'vue-router'; import {useRoute} from 'vue-router';
import { useIntervalFn } from '@vueuse/core'; import {useIntervalFn} from '@vueuse/core';
import { Message, TableData } from '@arco-design/web-vue'; import {Message, TableData} from '@arco-design/web-vue';
import { MsAdvanceFilter, timeSelectOptions } from '@/components/pure/ms-advance-filter'; import {MsAdvanceFilter, timeSelectOptions} from '@/components/pure/ms-advance-filter';
import { BackEndEnum, FilterFormItem, FilterResult, FilterType } from '@/components/pure/ms-advance-filter/type'; import {BackEndEnum, FilterFormItem, FilterResult, FilterType} from '@/components/pure/ms-advance-filter/type';
import MsButton from '@/components/pure/ms-button/index.vue'; import MsButton from '@/components/pure/ms-button/index.vue';
import MsCard from '@/components/pure/ms-card/index.vue'; import MsCard from '@/components/pure/ms-card/index.vue';
import MsExportDrawer from '@/components/pure/ms-export-drawer/index.vue'; import MsExportDrawer from '@/components/pure/ms-export-drawer/index.vue';
import { MsExportDrawerMap, MsExportDrawerOption } from '@/components/pure/ms-export-drawer/types'; import {MsExportDrawerMap, MsExportDrawerOption} from '@/components/pure/ms-export-drawer/types';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue'; import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type'; import {BatchActionParams, BatchActionQueryParams, MsTableColumn} from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable'; import useTable from '@/components/pure/ms-table/useTable';
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue'; import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
import { ActionsItem } from '@/components/pure/ms-table-more-action/types'; import {ActionsItem} from '@/components/pure/ms-table-more-action/types';
import BatchEditModal from './components/batchEditModal.vue'; import BatchEditModal from './components/batchEditModal.vue';
import BugDetailDrawer from './components/bug-detail-drawer.vue'; import BugDetailDrawer from './components/bug-detail-drawer.vue';
import DeleteModal from './components/deleteModal.vue'; import DeleteModal from './components/deleteModal.vue';
import { import {
deleteBatchBug, deleteBatchBug,
deleteSingleBug, deleteSingleBug,
exportBug, exportBug,
getBugList, getBugList,
getCustomFieldHeader, getCustomFieldHeader,
getExportConfig, getExportConfig,
getSyncStatus, getSyncStatus,
syncBugEnterprise, syncBugEnterprise,
syncBugOpenSource, syncBugOpenSource,
} from '@/api/modules/bug-management'; } from '@/api/modules/bug-management';
import { useI18n } from '@/hooks/useI18n'; import {useI18n} from '@/hooks/useI18n';
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
import router from '@/router'; import router from '@/router';
import { useAppStore, useTableStore } from '@/store'; import {useAppStore, useTableStore} from '@/store';
import useLicenseStore from '@/store/modules/setting/license'; import useLicenseStore from '@/store/modules/setting/license';
import { import {customFieldDataToTableData, customFieldToColumns, downloadByteFile, tableParamsToRequestParams,} from '@/utils';
customFieldDataToTableData,
customFieldToColumns,
downloadByteFile,
tableParamsToRequestParams,
} from '@/utils';
import { BugEditCustomField, BugListItem } from '@/models/bug-management'; import {BugEditCustomField, BugListItem} from '@/models/bug-management';
import { RouteEnum } from '@/enums/routeEnum'; import {RouteEnum} from '@/enums/routeEnum';
import { TableKeyEnum } from '@/enums/tableEnum'; import {TableKeyEnum} from '@/enums/tableEnum';
const { t } = useI18n(); const { t } = useI18n();
const tableStore = useTableStore(); const tableStore = useTableStore();
const appStore = useAppStore(); const appStore = useAppStore();
@ -291,19 +286,7 @@
}, },
{ {
title: 'bugManagement.creator', title: 'bugManagement.creator',
slotName: 'createUserName', dataIndex: 'createUser',
dataIndex: 'createUserName',
width: 112,
showTooltip: true,
showDrag: true,
sortable: {
sortDirections: ['ascend', 'descend'],
sorter: true,
},
},
{
title: 'bugManagement.updateUser',
dataIndex: 'updateUserName',
width: 112, width: 112,
showTooltip: true, showTooltip: true,
showDrag: true, showDrag: true,
@ -324,7 +307,6 @@
}, },
{ {
title: 'bugManagement.updateUser', title: 'bugManagement.updateUser',
slotName: 'updateUserName',
dataIndex: 'updateUser', dataIndex: 'updateUser',
width: 112, width: 112,
showTooltip: true, showTooltip: true,