feat(缺陷管理): 评论接口对接
This commit is contained in:
parent
4bc05648fc
commit
a81a8cba2b
|
@ -1,7 +1,9 @@
|
||||||
|
import { CommentParams } from '@/components/business/ms-comment/types';
|
||||||
|
|
||||||
import MSR from '@/api/http/index';
|
import MSR from '@/api/http/index';
|
||||||
import * as bugURL from '@/api/requrls/bug-management';
|
import * as bugURL from '@/api/requrls/bug-management';
|
||||||
|
|
||||||
import { BugEditFormObject, BugExportParams, BugListItem } from '@/models/bug-management';
|
import { BugEditFormObject, BugExportParams, BugListItem, CreateOrUpdateComment } from '@/models/bug-management';
|
||||||
import { AssociatedList } from '@/models/caseManagement/featureCase';
|
import { AssociatedList } from '@/models/caseManagement/featureCase';
|
||||||
import { CommonList, TableQueryParams, TemplateOption } from '@/models/common';
|
import { CommonList, TableQueryParams, TemplateOption } from '@/models/common';
|
||||||
|
|
||||||
|
@ -89,3 +91,19 @@ export function followBug(id: string, isFollow: boolean) {
|
||||||
}
|
}
|
||||||
return MSR.get({ url: `${bugURL.getFollowBugUrl}${id}` });
|
return MSR.get({ url: `${bugURL.getFollowBugUrl}${id}` });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 创建评论
|
||||||
|
export function createOrUpdateComment(data: CommentParams) {
|
||||||
|
if (data.id) {
|
||||||
|
return MSR.post({ url: bugURL.postUpdateCommentUrl, data });
|
||||||
|
}
|
||||||
|
return MSR.post({ url: bugURL.postCreateCommentUrl, data });
|
||||||
|
}
|
||||||
|
// 获取评论列表
|
||||||
|
export function getCommentList(bugId: string) {
|
||||||
|
return MSR.get({ url: `${bugURL.getCommentListUrl}${bugId}` });
|
||||||
|
}
|
||||||
|
// 删除评论
|
||||||
|
export function deleteComment(commentId: string) {
|
||||||
|
return MSR.get({ url: `${bugURL.getDeleteCommentUrl}${commentId}` });
|
||||||
|
}
|
||||||
|
|
|
@ -14,3 +14,7 @@ export const postAssociatedFileListUrl = '/bug/relate/case/page';
|
||||||
export const getBugDetailUrl = '/bug/detail/';
|
export const getBugDetailUrl = '/bug/detail/';
|
||||||
export const getFollowBugUrl = '/bug/follow/';
|
export const getFollowBugUrl = '/bug/follow/';
|
||||||
export const getUnFollowBugUrl = '/bug/unfollow/';
|
export const getUnFollowBugUrl = '/bug/unfollow/';
|
||||||
|
export const postUpdateCommentUrl = '/bug/comment/update';
|
||||||
|
export const postCreateCommentUrl = '/bug/comment/add';
|
||||||
|
export const getCommentListUrl = '/bug/comment/get/';
|
||||||
|
export const getDeleteCommentUrl = '/bug/comment/delete/';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-row gap-[8px]">
|
||||||
<MsAvatar avatar="default" />
|
<MsAvatar avatar="word" />
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<div class="text-[var(--color-text-1)]">{{ props.element.createUser }}</div>
|
<div class="text-[var(--color-text-1)]">{{ props.element.createUser }}</div>
|
||||||
<div v-dompurify-html="props.element.content" class="mt-[4px]"></div>
|
<div v-dompurify-html="props.element.content" class="mt-[4px]"></div>
|
||||||
|
@ -9,22 +9,26 @@
|
||||||
dayjs(props.element.updateTime).format('YYYY-MM-DD HH:mm:ss')
|
dayjs(props.element.updateTime).format('YYYY-MM-DD HH:mm:ss')
|
||||||
}}</div>
|
}}</div>
|
||||||
<div class="ml-[24px] flex flex-row gap-[16px]">
|
<div class="ml-[24px] flex flex-row gap-[16px]">
|
||||||
<div v-if="props.mode === 'parent'" class="comment-btn" @click="expendChange">
|
<div
|
||||||
|
v-if="props.mode === 'parent' && element.childComments?.length"
|
||||||
|
class="comment-btn"
|
||||||
|
@click="expendChange"
|
||||||
|
>
|
||||||
<MsIconfont type="icon-icon_comment_outlined" />
|
<MsIconfont type="icon-icon_comment_outlined" />
|
||||||
<span>{{ !expendComment ? t('comment.expendComment') : t('comment.collapseComment') }}</span>
|
<span>{{ !expendComment ? t('ms.comment.expendComment') : t('ms.comment.collapseComment') }}</span>
|
||||||
<span class="text-[var(--color-text-4)]">({{ element.children?.length }})</span>
|
<span class="text-[var(--color-text-4)]">({{ element.childComments?.length }})</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="comment-btn" @click="replyClick">
|
<div class="comment-btn" @click="replyClick">
|
||||||
<MsIconfont type="icon-icon_reply" />
|
<MsIconfont type="icon-icon_reply" />
|
||||||
<span>{{ t('comment.reply') }}</span>
|
<span>{{ t('ms.comment.reply') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="hasEditAuth" class="comment-btn" @click="editClick">
|
<div v-if="hasEditAuth" class="comment-btn" @click="editClick">
|
||||||
<MsIconfont type="icon-icon_edit_outlined" />
|
<MsIconfont type="icon-icon_edit_outlined" />
|
||||||
<span>{{ t('comment.edit') }}</span>
|
<span>{{ t('ms.comment.edit') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="hasEditAuth" class="comment-btn" @click="deleteClick">
|
<div v-if="hasEditAuth" class="comment-btn" @click="deleteClick">
|
||||||
<MsIconfont type="icon-icon_delete-trash_outlined" />
|
<MsIconfont type="icon-icon_delete-trash_outlined" />
|
||||||
<span>{{ t('comment.delete') }}</span>
|
<span>{{ t('ms.comment.delete') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -40,18 +44,21 @@
|
||||||
import MsIconfont from '@/components/pure/ms-icon-font/index.vue';
|
import MsIconfont from '@/components/pure/ms-icon-font/index.vue';
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
import useUserStore from '@/store/modules/user/index';
|
||||||
|
|
||||||
import { CommentItem } from './types';
|
import { CommentItem } from './types';
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
element: CommentItem; // 评论的具体内容
|
element: CommentItem; // 评论的具体内容
|
||||||
mode: 'parent' | 'child'; // 父级评论还是子级评论
|
mode: 'parent' | 'child'; // 父级评论还是子级评论
|
||||||
currentUserId: string; // 当前用户id
|
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
// 是否拥有编辑|删除权限
|
// 是否拥有编辑|删除权限
|
||||||
const hasEditAuth = computed(() => {
|
const hasEditAuth = computed(() => {
|
||||||
return props.element.commentUserInfo.id === props.currentUserId;
|
return props.element.commentUserInfo.id === userStore.id;
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
@ -78,8 +85,6 @@
|
||||||
const deleteClick = () => {
|
const deleteClick = () => {
|
||||||
emit('delete');
|
emit('delete');
|
||||||
};
|
};
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// eslint-disable-next-line no-shadow
|
||||||
|
|
||||||
import Item from './comment-item.vue';
|
import Item from './comment-item.vue';
|
||||||
import CommentInput from './input.vue';
|
import CommentInput from './input.vue';
|
||||||
|
|
||||||
|
@ -10,11 +12,6 @@ import message from '@arco-design/web-vue/es/message';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'MsComment',
|
name: 'MsComment',
|
||||||
props: {
|
props: {
|
||||||
currentUserId: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
|
|
||||||
commentList: {
|
commentList: {
|
||||||
type: Array as PropType<CommentItem[]>,
|
type: Array as PropType<CommentItem[]>,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
|
@ -22,12 +19,11 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
emits: {
|
emits: {
|
||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
updateOrAdd: (value: CommentParams) => true, // 更新或者新增评论
|
updateOrAdd: (value: CommentParams, cb: (result: boolean) => void) => true, // 更新或者新增评论
|
||||||
delete: (value: string, cb: (result: boolean) => void) => true, // 删除评论
|
delete: (value: string) => true, // 删除评论
|
||||||
},
|
},
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const { currentUserId } = toRefs(props);
|
const { commentList } = toRefs(props);
|
||||||
const commentList = ref<CommentItem[]>([]);
|
|
||||||
const currentItem = reactive<{ id: string; parentId: string }>({ id: '', parentId: '' });
|
const currentItem = reactive<{ id: string; parentId: string }>({ id: '', parentId: '' });
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { openModal } = useModal();
|
const { openModal } = useModal();
|
||||||
|
@ -38,27 +34,27 @@ export default defineComponent({
|
||||||
content,
|
content,
|
||||||
event: 'REPLAY',
|
event: 'REPLAY',
|
||||||
};
|
};
|
||||||
emit('updateOrAdd', params);
|
emit('updateOrAdd', params, (result: boolean) => {
|
||||||
|
if (result) {
|
||||||
|
message.success(t('common.publishSuccess'));
|
||||||
|
} else {
|
||||||
|
message.error(t('common.publishFail'));
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = (item: CommentItem) => {
|
const handleDelete = (item: CommentItem) => {
|
||||||
openModal({
|
openModal({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
title: t('comment.deleteConfirm'),
|
title: t('ms.comment.deleteConfirm'),
|
||||||
content: t('comment.deleteContent'),
|
content: t('ms.comment.deleteContent'),
|
||||||
okText: t('common.confirmClose'),
|
okText: t('common.confirmDelete'),
|
||||||
cancelText: t('common.cancel'),
|
cancelText: t('common.cancel'),
|
||||||
okButtonProps: {
|
okButtonProps: {
|
||||||
status: 'danger',
|
status: 'danger',
|
||||||
},
|
},
|
||||||
onBeforeOk: async () => {
|
onBeforeOk: async () => {
|
||||||
emit('delete', item.id, (result: boolean) => {
|
emit('delete', item.id);
|
||||||
if (result) {
|
|
||||||
message.success(t('common.deleteSuccess'));
|
|
||||||
} else {
|
|
||||||
message.error(t('common.deleteFail'));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
hideCancel: false,
|
hideCancel: false,
|
||||||
});
|
});
|
||||||
|
@ -81,7 +77,7 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
return list.map((item) => {
|
return list.map((item) => {
|
||||||
return (
|
return (
|
||||||
<div class="flex flex-col gap-[24px]">
|
<div class="flex flex-col">
|
||||||
<Item
|
<Item
|
||||||
onReply={() => {
|
onReply={() => {
|
||||||
currentItem.id = item.id;
|
currentItem.id = item.id;
|
||||||
|
@ -93,7 +89,6 @@ export default defineComponent({
|
||||||
}}
|
}}
|
||||||
onDelete={() => handleDelete(item)}
|
onDelete={() => handleDelete(item)}
|
||||||
mode={'child'}
|
mode={'child'}
|
||||||
currentUserId={currentUserId.value}
|
|
||||||
element={item}
|
element={item}
|
||||||
/>
|
/>
|
||||||
{item.id === currentItem.id && renderInput(item)}
|
{item.id === currentItem.id && renderInput(item)}
|
||||||
|
@ -105,13 +100,15 @@ export default defineComponent({
|
||||||
const renderParentList = (list: CommentItem[]) => {
|
const renderParentList = (list: CommentItem[]) => {
|
||||||
return list.map((item) => {
|
return list.map((item) => {
|
||||||
return (
|
return (
|
||||||
<Item mode={'parent'} onDelete={() => handleDelete(item)} currentUserId={currentUserId.value} element={item}>
|
<Item mode={'parent'} onDelete={() => handleDelete(item)} element={item}>
|
||||||
<div class="rounded border border-[var(--color-text-7)] p-[16px]">{renderChildrenList(item.children)}</div>
|
<div class="rounded border border-[var(--color-text-7)] p-[16px]">
|
||||||
|
{renderChildrenList(item.childComments)}
|
||||||
|
</div>
|
||||||
</Item>
|
</Item>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return () => <div class="ms-comment">{renderParentList(commentList.value)}</div>;
|
return () => <div class="ms-comment gap[24px] flex flex-col">{renderParentList(commentList.value)}</div>;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,4 +9,5 @@ const MsComment = Object.assign(_Comment, {
|
||||||
|
|
||||||
export type CommentInstance = InstanceType<typeof _Comment>;
|
export type CommentInstance = InstanceType<typeof _Comment>;
|
||||||
|
|
||||||
|
export { default as CommentInput } from './input.vue';
|
||||||
export default MsComment;
|
export default MsComment;
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
export default {
|
||||||
|
'ms.comment.expendComment': 'Expand comment',
|
||||||
|
'ms.comment.collapseComment': 'Collapse comment',
|
||||||
|
'ms.comment.edit': 'Edit',
|
||||||
|
'ms.comment.reply': 'Reply',
|
||||||
|
'ms.comment.delete': 'Delete',
|
||||||
|
'ms.comment.deleteConfirm': 'Are you sure you want to delete this comment?',
|
||||||
|
'ms.comment.deleteContent': 'After deletion, the comment cannot be replied to. Please proceed with caution.',
|
||||||
|
'ms.comment.enterPlaceHolderTip': 'Please enter a comment and press Enter to finish.',
|
||||||
|
};
|
|
@ -1,8 +0,0 @@
|
||||||
export default {
|
|
||||||
'comment.expendComment': 'Expand comment',
|
|
||||||
'comment.collapseComment': 'Collapse comment',
|
|
||||||
'comment.reply': 'Reply',
|
|
||||||
'comment.delete': 'Delete',
|
|
||||||
'comment.edit': 'Edit',
|
|
||||||
'comment.enterPlaceHolderTip': 'Please enter a comment and press enter to end',
|
|
||||||
};
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
export default {
|
||||||
|
'ms.comment.expendComment': '展开评论',
|
||||||
|
'ms.comment.collapseComment': '收起评论',
|
||||||
|
'ms.comment.edit': '编辑',
|
||||||
|
'ms.comment.reply': '回复',
|
||||||
|
'ms.comment.delete': '删除',
|
||||||
|
'ms.comment.deleteConfirm': '确认删除该评论吗?',
|
||||||
|
'ms.comment.deleteContent': '删除后,评论无法回复,请谨慎操作',
|
||||||
|
'ms.comment.enterPlaceHolderTip': '请输入评论,回车结束',
|
||||||
|
};
|
|
@ -1,10 +0,0 @@
|
||||||
export default {
|
|
||||||
'comment.expendComment': '展开评论',
|
|
||||||
'comment.collapseComment': '收起评论',
|
|
||||||
'comment.edit': '编辑',
|
|
||||||
'comment.reply': '回复',
|
|
||||||
'comment.delete': '删除',
|
|
||||||
'comment.deleteConfirm': '确认删除该评论吗?',
|
|
||||||
'comment.deleteContent': '删除后,评论无法回复,请谨慎操作',
|
|
||||||
'comment.enterPlaceHolderTip': '请输入评论,回车结束',
|
|
||||||
};
|
|
|
@ -14,7 +14,7 @@ export interface CommentItem {
|
||||||
commentUserInfo: CommentUserInfo; // 评论人用户信息
|
commentUserInfo: CommentUserInfo; // 评论人用户信息
|
||||||
replyUser?: string; // 回复人
|
replyUser?: string; // 回复人
|
||||||
notifier?: string; // 通知人
|
notifier?: string; // 通知人
|
||||||
children?: CommentItem[];
|
childComments?: CommentItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 仅评论: ’COMMENT‘; 评论并@: ’AT‘; 回复评论/回复并@: ’REPLAY‘;)
|
// 仅评论: ’COMMENT‘; 评论并@: ’AT‘; 回复评论/回复并@: ’REPLAY‘;)
|
||||||
|
@ -24,9 +24,11 @@ export interface WriteCommentProps {
|
||||||
id?: string; // 评论id
|
id?: string; // 评论id
|
||||||
parentId?: string; // 父级评论id
|
parentId?: string; // 父级评论id
|
||||||
event: commentEvent; // 评论事件
|
event: commentEvent; // 评论事件
|
||||||
bugId: string; // bug id
|
bugId?: string; // bug id
|
||||||
|
caseId?: string; // 用例id
|
||||||
}
|
}
|
||||||
export interface CommentParams extends WriteCommentProps {
|
export interface CommentParams extends WriteCommentProps {
|
||||||
content: string;
|
content: string;
|
||||||
replyUser?: string; // 回复人
|
replyUser?: string; // 回复人
|
||||||
|
notifiers?: string; // 通知人
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,4 +52,14 @@ export interface BugBatchUpdateFiledForm {
|
||||||
append: boolean;
|
append: boolean;
|
||||||
inputValue: string;
|
inputValue: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CreateOrUpdateComment {
|
||||||
|
id?: string;
|
||||||
|
bugId: string;
|
||||||
|
notifier: string;
|
||||||
|
replyUser: string;
|
||||||
|
parentId: string;
|
||||||
|
content: string;
|
||||||
|
event: string; // 任务事件(仅评论: ’COMMENT‘; 评论并@: ’AT‘; 回复评论/回复并@: ’REPLAY‘;)
|
||||||
|
}
|
||||||
export default {};
|
export default {};
|
||||||
|
|
|
@ -78,15 +78,25 @@
|
||||||
<template #first>
|
<template #first>
|
||||||
<div class="leftWrapper h-full">
|
<div class="leftWrapper h-full">
|
||||||
<div class="header h-[50px]">
|
<div class="header h-[50px]">
|
||||||
<a-tabs v-model:active-key="activeTab">
|
<a-tabs v-model:active-key="activeTab" lazy-load>
|
||||||
<a-tab-pane key="detail">
|
<a-tab-pane key="detail">
|
||||||
|
<template #title>
|
||||||
|
{{ t('bugManagement.detail.detail') }}
|
||||||
|
</template>
|
||||||
<BugDetailTab :detail-info="detailInfo" />
|
<BugDetailTab :detail-info="detailInfo" />
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane key="case">
|
<a-tab-pane key="case">
|
||||||
|
<template #title>
|
||||||
|
{{ t('bugManagement.detail.case') }}
|
||||||
|
<a-badge class="relative top-1 ml-1" :count="1000" :max-count="99" />
|
||||||
|
</template>
|
||||||
<BugCaseTab :detail-info="detailInfo" />
|
<BugCaseTab :detail-info="detailInfo" />
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane key="comment">
|
<a-tab-pane key="comment">
|
||||||
<MsComment />
|
<template #title>
|
||||||
|
{{ t('bugManagement.detail.comment') }}
|
||||||
|
</template>
|
||||||
|
<CommentTab ref="commentRef" bug-id="1070838426116099" />
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
</div>
|
</div>
|
||||||
|
@ -126,6 +136,13 @@
|
||||||
</template>
|
</template>
|
||||||
</MsSplitBox>
|
</MsSplitBox>
|
||||||
</div>
|
</div>
|
||||||
|
<CommentInput
|
||||||
|
v-if="activeTab === 'comment'"
|
||||||
|
:content="commentContent"
|
||||||
|
is-show-avatar
|
||||||
|
is-use-bottom
|
||||||
|
@publish="publishHandler"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</MsDetailDrawer>
|
</MsDetailDrawer>
|
||||||
</template>
|
</template>
|
||||||
|
@ -143,19 +160,20 @@
|
||||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||||
import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
|
import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
|
||||||
import type { MsPaginationI } from '@/components/pure/ms-table/type';
|
import type { MsPaginationI } from '@/components/pure/ms-table/type';
|
||||||
import MsComment from '@/components/business/ms-comment';
|
import { CommentInput } from '@/components/business/ms-comment';
|
||||||
|
import { CommentParams } from '@/components/business/ms-comment/types';
|
||||||
import MsDetailDrawer from '@/components/business/ms-detail-drawer/index.vue';
|
import MsDetailDrawer from '@/components/business/ms-detail-drawer/index.vue';
|
||||||
import { MsUserSelector } from '@/components/business/ms-user-selector';
|
import { MsUserSelector } from '@/components/business/ms-user-selector';
|
||||||
import BugCaseTab from './bugCaseTab.vue';
|
import BugCaseTab from './bugCaseTab.vue';
|
||||||
import BugDetailTab from './bugDetailTab.vue';
|
import BugDetailTab from './bugDetailTab.vue';
|
||||||
|
import CommentTab from './commentTab.vue';
|
||||||
|
|
||||||
import { deleteSingleBug, followBug, getBugDetail } from '@/api/modules/bug-management/index';
|
import { createOrUpdateComment, deleteSingleBug, followBug, getBugDetail } from '@/api/modules/bug-management/index';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useModal from '@/hooks/useModal';
|
import useModal from '@/hooks/useModal';
|
||||||
import { useAppStore } from '@/store';
|
import { useAppStore } from '@/store';
|
||||||
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
||||||
import useUserStore from '@/store/modules/user';
|
import { characterLimit } from '@/utils';
|
||||||
import { characterLimit, findNodeByKey } from '@/utils';
|
|
||||||
|
|
||||||
import type { CaseManagementTable, CustomAttributes, TabItemType } from '@/models/caseManagement/featureCase';
|
import type { CaseManagementTable, CustomAttributes, TabItemType } from '@/models/caseManagement/featureCase';
|
||||||
import { RouteEnum } from '@/enums/routeEnum';
|
import { RouteEnum } from '@/enums/routeEnum';
|
||||||
|
@ -165,7 +183,6 @@
|
||||||
const wrapperRef = ref();
|
const wrapperRef = ref();
|
||||||
const { isFullscreen, toggle } = useFullscreen(wrapperRef);
|
const { isFullscreen, toggle } = useFullscreen(wrapperRef);
|
||||||
const featureCaseStore = useFeatureCaseStore();
|
const featureCaseStore = useFeatureCaseStore();
|
||||||
const userStore = useUserStore();
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { openModal } = useModal();
|
const { openModal } = useModal();
|
||||||
|
|
||||||
|
@ -180,8 +197,9 @@
|
||||||
|
|
||||||
const emit = defineEmits(['update:visible']);
|
const emit = defineEmits(['update:visible']);
|
||||||
|
|
||||||
const userId = computed(() => userStore.userInfo.id);
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
|
const commentContent = ref('');
|
||||||
|
const commentRef = ref();
|
||||||
|
|
||||||
const currentProjectId = computed(() => appStore.currentProjectId);
|
const currentProjectId = computed(() => appStore.currentProjectId);
|
||||||
|
|
||||||
|
@ -200,13 +218,9 @@
|
||||||
function loadedBug(detail: CaseManagementTable) {
|
function loadedBug(detail: CaseManagementTable) {
|
||||||
detailInfo.value = { ...detail };
|
detailInfo.value = { ...detail };
|
||||||
customFields.value = detailInfo.value.customFields;
|
customFields.value = detailInfo.value.customFields;
|
||||||
|
detailInfo.value.id = '1070838426116099';
|
||||||
}
|
}
|
||||||
|
|
||||||
const moduleName = computed(() => {
|
|
||||||
return findNodeByKey<Record<string, any>>(featureCaseStore.caseTree, detailInfo.value?.moduleId as string, 'id')
|
|
||||||
?.name;
|
|
||||||
});
|
|
||||||
|
|
||||||
const editLoading = ref<boolean>(false);
|
const editLoading = ref<boolean>(false);
|
||||||
|
|
||||||
function updateSuccess() {
|
function updateSuccess() {
|
||||||
|
@ -331,6 +345,32 @@
|
||||||
}) as FormItem[];
|
}) as FormItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function publishHandler(currentContent: string) {
|
||||||
|
const regex = /data-id="([^"]*)"/g;
|
||||||
|
const matchesNotifier = currentContent.match(regex);
|
||||||
|
let notifiers = '';
|
||||||
|
if (matchesNotifier?.length) {
|
||||||
|
notifiers = matchesNotifier.map((match) => match.replace('data-id="', '').replace('"', '')).join(';');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
// TODO 本地测试
|
||||||
|
bugId: detailInfo.value.id || '1070838426116099',
|
||||||
|
notifier: notifiers,
|
||||||
|
replyUser: '',
|
||||||
|
parentId: '',
|
||||||
|
content: currentContent,
|
||||||
|
event: notifiers ? 'AT' : 'COMMENT', // 任务事件(仅评论: ’COMMENT‘; 评论并@: ’AT‘; 回复评论/回复并@: ’REPLAY‘;)
|
||||||
|
};
|
||||||
|
await createOrUpdateComment(params as CommentParams);
|
||||||
|
Message.success(t('common.publishSuccessfully'));
|
||||||
|
commentRef.value?.initData(detailInfo.value.id || '1070838426116099');
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => customFields.value,
|
() => customFields.value,
|
||||||
() => {
|
() => {
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
<template>
|
||||||
|
<MsComment :comment-list="commentList" @delete="handleDelete" @update-or-add="handleUpdate" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import MsComment from '@/components/business/ms-comment';
|
||||||
|
import { CommentItem, CommentParams } from '@/components/business/ms-comment/types';
|
||||||
|
|
||||||
|
import { createOrUpdateComment, deleteComment, getCommentList } from '@/api/modules/bug-management/index';
|
||||||
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
|
||||||
|
import message from '@arco-design/web-vue/es/message';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
bugId: string;
|
||||||
|
}>();
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const commentList = ref<CommentItem[]>([]);
|
||||||
|
|
||||||
|
const initData = async (bugId: string) => {
|
||||||
|
try {
|
||||||
|
commentList.value = (await getCommentList(bugId)) || [];
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = async (bugid: string) => {
|
||||||
|
try {
|
||||||
|
await deleteComment(bugid);
|
||||||
|
message.success(t('common.deleteSuccess'));
|
||||||
|
initData(bugid);
|
||||||
|
} catch (error) {
|
||||||
|
message.error(t('common.deleteFail'));
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleUpdate = async (item: CommentParams, cb: (result: boolean) => void) => {
|
||||||
|
try {
|
||||||
|
await createOrUpdateComment(item);
|
||||||
|
if (item.bugId) {
|
||||||
|
initData(item.bugId);
|
||||||
|
}
|
||||||
|
cb(true);
|
||||||
|
} catch (error) {
|
||||||
|
cb(false);
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (props.bugId) {
|
||||||
|
initData(props.bugId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
initData,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
/* Your component styles here */
|
||||||
|
</style>
|
|
@ -11,6 +11,7 @@
|
||||||
>
|
>
|
||||||
<template #headerRight>
|
<template #headerRight>
|
||||||
<a-select
|
<a-select
|
||||||
|
v-if="!isEdit"
|
||||||
v-model="form.templateId"
|
v-model="form.templateId"
|
||||||
class="w-[240px]"
|
class="w-[240px]"
|
||||||
:options="templateOption"
|
:options="templateOption"
|
||||||
|
|
|
@ -64,6 +64,9 @@ export default {
|
||||||
basicInfo: '基本信息',
|
basicInfo: '基本信息',
|
||||||
handleUser: '处理人',
|
handleUser: '处理人',
|
||||||
tag: '标签',
|
tag: '标签',
|
||||||
|
detail: '详情',
|
||||||
|
case: '用例',
|
||||||
|
comment: '评论',
|
||||||
},
|
},
|
||||||
batchUpdate: {
|
batchUpdate: {
|
||||||
attribute: '选择属性',
|
attribute: '选择属性',
|
||||||
|
|
Loading…
Reference in New Issue