fix(缺陷管理): 修复缺陷管理相关bug
This commit is contained in:
parent
51c199264c
commit
868a1a38cb
|
@ -40,10 +40,11 @@ import {
|
|||
UpdateProjectTemplateUrl,
|
||||
} from '@/api/requrls/setting/template';
|
||||
|
||||
import { TableQueryParams } from '@/models/common';
|
||||
import { CommonList, TableQueryParams } from '@/models/common';
|
||||
import type {
|
||||
ActionTemplateManage,
|
||||
AddOrUpdateField,
|
||||
OrdTemplateManagement,
|
||||
OrdWorkStatus,
|
||||
SeneType,
|
||||
SetStateType,
|
||||
|
@ -56,7 +57,9 @@ import type {
|
|||
*/
|
||||
// 获取模板列表(组织)
|
||||
export function getOrganizeTemplateList(params: TableQueryParams) {
|
||||
return MSR.get({ url: `${GetOrganizeTemplateUrl}/${params.organizationId}/${params.scene}` });
|
||||
return MSR.get({
|
||||
url: `${GetOrganizeTemplateUrl}/${params.organizationId}/${params.scene}`,
|
||||
});
|
||||
}
|
||||
// 获取模板详情(组织)
|
||||
export function getOrganizeTemplateInfo(id: string) {
|
||||
|
@ -180,7 +183,9 @@ export function getProjectFieldDetail(id: string) {
|
|||
*/
|
||||
// 获取模板列表(项目)
|
||||
export function getProjectTemplateList(params: TableQueryParams) {
|
||||
return MSR.get({ url: `${GetProjectTemplateUrl}/${params.projectId}/${params.scene}` });
|
||||
return MSR.get({
|
||||
url: `${GetProjectTemplateUrl}/${params.projectId}/${params.scene}`,
|
||||
});
|
||||
}
|
||||
// 获取模板详情(项目)
|
||||
export function getProjectTemplateInfo(id: string) {
|
||||
|
|
|
@ -19,6 +19,11 @@ export default defineComponent({
|
|||
type: Boolean as PropType<boolean>,
|
||||
default: false,
|
||||
},
|
||||
uploadImage: {
|
||||
type: Function,
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
default: (file: File) => Promise<any>,
|
||||
},
|
||||
},
|
||||
emits: {
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
|
@ -26,7 +31,7 @@ export default defineComponent({
|
|||
delete: (value: string) => true, // 删除评论
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const { commentList, disabled } = toRefs(props);
|
||||
const { commentList, disabled, uploadImage } = toRefs(props);
|
||||
const currentItem = reactive<{ id: string; commentType: CommentType; commentStatus: string }>({
|
||||
id: '',
|
||||
commentType: 'ADD',
|
||||
|
@ -123,6 +128,7 @@ export default defineComponent({
|
|||
onUpdate:noticeUserIds={(ids: string[]) => {
|
||||
noticeUserIds.value = ids;
|
||||
}}
|
||||
uploadImage={uploadImage.value}
|
||||
onCancel={() => resetCurrentItem()}
|
||||
{...item}
|
||||
/>
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
<MsRichText
|
||||
v-model:raw="currentContent"
|
||||
v-model:commentIds="commentIds"
|
||||
:upload-image="props.uploadImage"
|
||||
class="w-full"
|
||||
placeholder="ms.comment.enterPlaceHolderTip"
|
||||
/>
|
||||
|
@ -46,6 +47,7 @@
|
|||
const props = defineProps<{
|
||||
isShowAvatar: boolean; // 是否显示评论人头像
|
||||
isUseBottom: boolean; // 是否被用于底部
|
||||
uploadImage?: (file: File) => Promise<any>;
|
||||
}>();
|
||||
|
||||
const currentContent = defineModel<string>('defaultValue', { default: '' });
|
||||
|
|
|
@ -52,6 +52,12 @@
|
|||
</a-popover>
|
||||
</div>
|
||||
</template>
|
||||
<template #status="{ record }">
|
||||
<MsTag v-if="record.status === 'PASSED'" type="success" theme="light">{{
|
||||
t('project.commonScript.testsPass')
|
||||
}}</MsTag>
|
||||
<MsTag v-else>{{ t('project.commonScript.draft') }}</MsTag>
|
||||
</template>
|
||||
<template #enable="{ record }">
|
||||
<MsTag v-if="record.enable" type="success" theme="light">{{ t('project.commonScript.testsPass') }}</MsTag>
|
||||
<MsTag v-else>{{ t('project.commonScript.draft') }}</MsTag>
|
||||
|
@ -136,8 +142,8 @@
|
|||
},
|
||||
{
|
||||
title: 'project.commonScript.enable',
|
||||
dataIndex: 'enable',
|
||||
slotName: 'enable',
|
||||
dataIndex: 'status',
|
||||
slotName: 'status',
|
||||
showInTable: true,
|
||||
width: 150,
|
||||
showDrag: true,
|
||||
|
|
|
@ -171,6 +171,7 @@
|
|||
|
||||
function handleParamTableChange(resultArr: any[], isInit?: boolean) {
|
||||
innerParams.value = [...resultArr];
|
||||
form.value.params = JSON.stringify([...resultArr]);
|
||||
if (!isInit) {
|
||||
emit('change');
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
{{ null }}
|
||||
</template>
|
||||
<template #content>
|
||||
<img class="h-[247px] w-[398px]" :src="previewIcon" />
|
||||
<img class="h-full w-full" :src="previewIcon" />
|
||||
</template>
|
||||
<span class="cursor-pointer text-[rgb(var(--primary-5))]">{{ t('project.menu.preview') }}</span>
|
||||
</a-popover>
|
||||
|
|
|
@ -164,7 +164,8 @@ const Image = TiptapImage.extend<ExtensionOptions & ImageOptions>({
|
|||
),
|
||||
title: t('editor.extensions.image.open_link'),
|
||||
action: () => {
|
||||
window.open(editor.getAttributes(Image.name).src, '_blank');
|
||||
const newWindow = window.open('');
|
||||
newWindow?.document.write(`<img src="${editor.getAttributes(Image.name).src}">`);
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -116,6 +116,7 @@ export interface ActionTemplateManage {
|
|||
customFields?: CustomField[];
|
||||
fieldType?: string;
|
||||
systemFields?: Record<string, any>[];
|
||||
enablePlatformDefault?: boolean;
|
||||
internal?: boolean; // 是否为系统模板
|
||||
platForm?: string;
|
||||
[key: string]: any;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
:page-change="props.pageChange"
|
||||
show-full-screen
|
||||
unmount-on-close
|
||||
:mask="false"
|
||||
@loaded="loadedBug"
|
||||
>
|
||||
<template #titleRight="{ loading }">
|
||||
|
@ -78,7 +79,7 @@
|
|||
</MsButton>
|
||||
</div>
|
||||
</template>
|
||||
<template #default>
|
||||
<template #default="{ loading }">
|
||||
<div ref="wrapperRef" class="h-full bg-white">
|
||||
<MsSplitBox
|
||||
ref="wrapperRef"
|
||||
|
@ -124,15 +125,20 @@
|
|||
</template>
|
||||
<template #second>
|
||||
<div class="rightWrapper p-[24px]">
|
||||
<div class="mb-4 font-medium">
|
||||
<strong>
|
||||
{{ t('bugManagement.detail.basicInfo') }}
|
||||
</strong>
|
||||
</div>
|
||||
<!-- 自定义字段开始 -->
|
||||
<div style="display: inline-block; width: 100%; word-wrap: break-word">
|
||||
<div class="inline-block w-full break-words">
|
||||
<a-skeleton v-if="loading" class="w-full" :loading="loading" :animation="true">
|
||||
<a-space direction="vertical" class="w-[100%]" size="large">
|
||||
<a-skeleton-line :rows="14" :line-height="30" :line-spacing="30" />
|
||||
</a-space>
|
||||
</a-skeleton>
|
||||
<div v-if="!loading" class="mb-4 font-medium">
|
||||
<strong>
|
||||
{{ t('bugManagement.detail.basicInfo') }}
|
||||
</strong>
|
||||
</div>
|
||||
<MsFormCreate
|
||||
v-if="formRules.length"
|
||||
v-if="!loading"
|
||||
ref="formCreateRef"
|
||||
v-model:form-item="formItem"
|
||||
v-model:api="fApi"
|
||||
|
@ -141,34 +147,37 @@
|
|||
:option="options"
|
||||
@change="handelFormCreateChange"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 自定义字段结束 -->
|
||||
<div v-if="!isPlatformDefaultTemplate" class="baseItem">
|
||||
<a-form
|
||||
:model="{}"
|
||||
:label-col-props="{
|
||||
span: 9,
|
||||
}"
|
||||
:wrapper-col-props="{
|
||||
span: 15,
|
||||
}"
|
||||
label-align="left"
|
||||
content-class="tags-class"
|
||||
<!-- 自定义字段结束 -->
|
||||
<div
|
||||
v-if="!isPlatformDefaultTemplate && hasAnyPermission(['PROJECT_BUG:READ+UPDATE']) && !loading"
|
||||
class="baseItem"
|
||||
>
|
||||
<a-form-item field="tags" :label="t('system.orgTemplate.tags')">
|
||||
<MsTagsInput
|
||||
v-model:model-value="tags"
|
||||
:disabled="!hasAnyPermission(['PROJECT_BUG:READ+UPDATE'])"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<a-form
|
||||
:model="{}"
|
||||
:label-col-props="{
|
||||
span: 9,
|
||||
}"
|
||||
:wrapper-col-props="{
|
||||
span: 15,
|
||||
}"
|
||||
label-align="left"
|
||||
content-class="tags-class"
|
||||
>
|
||||
<a-form-item field="tags" :label="t('system.orgTemplate.tags')">
|
||||
<MsTagsInput
|
||||
v-model:model-value="tags"
|
||||
:disabled="!hasAnyPermission(['PROJECT_BUG:READ+UPDATE'])"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- <span class="label"> {{ t('bugManagement.detail.tag') }}</span>-->
|
||||
<!-- <span style="width: 200px">-->
|
||||
<!-- <MsTag v-for="item of tags" :key="item"> {{ item }} </MsTag>-->
|
||||
<!-- </span>-->
|
||||
<!-- <span class="label"> {{ t('bugManagement.detail.tag') }}</span>-->
|
||||
<!-- <span style="width: 200px">-->
|
||||
<!-- <MsTag v-for="item of tags" :key="item"> {{ item }} </MsTag>-->
|
||||
<!-- </span>-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 内置基础信息结束 -->
|
||||
</div>
|
||||
</template>
|
||||
|
@ -178,6 +187,7 @@
|
|||
v-if="activeTab === 'comment'"
|
||||
:content="commentContent"
|
||||
is-show-avatar
|
||||
:upload-image="handleUploadImage"
|
||||
is-use-bottom
|
||||
:notice-user-ids="noticeUserIds"
|
||||
@publish="publishHandler"
|
||||
|
@ -211,6 +221,7 @@
|
|||
import {
|
||||
createOrUpdateComment,
|
||||
deleteSingleBug,
|
||||
editorUploadFile,
|
||||
followBug,
|
||||
getBugDetail,
|
||||
getTemplateById,
|
||||
|
@ -218,9 +229,11 @@
|
|||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useModal from '@/hooks/useModal';
|
||||
import { useAppStore } from '@/store';
|
||||
import useUserStore from '@/store/modules/user';
|
||||
import { characterLimit } from '@/utils';
|
||||
import { hasAnyPermission } from '@/utils/permission';
|
||||
|
||||
import type { CustomFieldItem } from '@/models/bug-management';
|
||||
import { BugEditCustomField, BugEditFormObject, BugTemplateRequest } from '@/models/bug-management';
|
||||
import { SelectValue } from '@/models/projectManagement/menuManagement';
|
||||
import { RouteEnum } from '@/enums/routeEnum';
|
||||
|
@ -245,7 +258,6 @@
|
|||
pagination: MsPaginationI; // 分页器对象
|
||||
pageChange: (page: number) => Promise<void>; // 分页变更函数
|
||||
}>();
|
||||
|
||||
const caseCount = ref(0);
|
||||
const appStore = useAppStore();
|
||||
const commentContent = ref('');
|
||||
|
@ -258,35 +270,44 @@
|
|||
const showDrawerVisible = defineModel<boolean>('visible', { default: false });
|
||||
const bugDetailTabRef = ref();
|
||||
const isPlatformDefaultTemplate = ref(false);
|
||||
|
||||
const rowLength = ref<number>(0);
|
||||
const activeTab = ref<string>('detail');
|
||||
|
||||
const detailInfo = ref<Record<string, any>>({ match: [] }); // 存储当前详情信息,通过loadBug 获取
|
||||
const tags = ref([]);
|
||||
const platformSystemFields = ref<BugEditCustomField[]>([]); // 平台系统字段
|
||||
|
||||
const userStore = useUserStore();
|
||||
// 处理表单格式
|
||||
const getFormRules = (arr: BugEditCustomField[], valueObj: BugEditFormObject) => {
|
||||
formRules.value = [];
|
||||
const memberType = ['MEMBER', 'MULTIPLE_MEMBER'];
|
||||
if (Array.isArray(arr) && arr.length) {
|
||||
formRules.value = arr.map((item: any) => {
|
||||
let initValue = valueObj[item.fieldId];
|
||||
const initOptions = item.options ? item.options : JSON.parse(item.platformOptionJson);
|
||||
if (memberType.includes(item.type)) {
|
||||
if (item.defaultValue === 'CREATE_USER' || item.defaultValue.includes('CREATE_USER')) {
|
||||
initValue = item.type === 'MEMBER' ? userStore.id : [userStore.id];
|
||||
}
|
||||
}
|
||||
return {
|
||||
type: item.type,
|
||||
name: item.fieldId,
|
||||
label: item.fieldName,
|
||||
value: valueObj[item.fieldId],
|
||||
options: item.platformOptionJson ? JSON.parse(item.platformOptionJson) : item.options,
|
||||
value: initValue,
|
||||
options: initOptions,
|
||||
required: item.required as boolean,
|
||||
platformPlaceHolder: item.platformPlaceHolder,
|
||||
props: {
|
||||
modelValue: valueObj[item.fieldId],
|
||||
options: item.platformOptionJson ? JSON.parse(item.platformOptionJson) : item.options,
|
||||
modelValue: initValue,
|
||||
options: initOptions,
|
||||
disabled: !hasAnyPermission(['PROJECT_BUG:READ+UPDATE']),
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
||||
const currentCustomFields = ref<CustomFieldItem[]>([]);
|
||||
|
||||
const templateChange = async (v: SelectValue, valueObj: BugEditFormObject, request: BugTemplateRequest) => {
|
||||
if (v) {
|
||||
|
@ -313,25 +334,50 @@
|
|||
};
|
||||
async function loadedBug(detail: BugEditFormObject) {
|
||||
detailInfo.value = { ...detail };
|
||||
const { templateId } = detail;
|
||||
|
||||
const { templateId } = detailInfo.value;
|
||||
// 是否平台默认模板
|
||||
isPlatformDefaultTemplate.value = detail.platformDefault;
|
||||
// TAG 赋值
|
||||
tags.value = detail.tags || [];
|
||||
caseCount.value = detail.linkCaseCount;
|
||||
const tmpObj = { status: detail.status };
|
||||
if (detail.customFields && Array.isArray(detail.customFields)) {
|
||||
caseCount.value = detailInfo.value.linkCaseCount;
|
||||
const tmpObj = { status: detailInfo.value.status };
|
||||
// 初始化自定义字段
|
||||
const customFieldsRes = await getTemplateById({
|
||||
projectId: appStore.currentProjectId,
|
||||
id: templateId,
|
||||
fromStatusId: detail.status,
|
||||
platformBugKey: detail.platformBugId,
|
||||
});
|
||||
currentCustomFields.value = customFieldsRes.customFields || [];
|
||||
if (detailInfo.value.customFields && Array.isArray(detailInfo.value.customFields)) {
|
||||
const MULTIPLE_TYPE = ['MULTIPLE_SELECT', 'MULTIPLE_INPUT', 'CHECKBOX', 'MULTIPLE_MEMBER'];
|
||||
const SINGRADIO_TYPE = ['RADIO', 'SELECT', 'MEMBER'];
|
||||
detail.customFields.forEach((item) => {
|
||||
if (item.type === 'MULTIPLE_SELECT' || item.type === 'MULTIPLE_INPUT' || item.type === 'CHECKBOX') {
|
||||
tmpObj[item.id] = JSON.parse(item.value);
|
||||
} else if (item.type === 'INT') {
|
||||
if (MULTIPLE_TYPE.includes(item.type)) {
|
||||
const multipleOptions =
|
||||
currentCustomFields.value.find((filed: any) => item.id === filed.fieldId)?.options || [];
|
||||
// 如果该值在选项中已经被删除掉
|
||||
const optionsIds = (multipleOptions || []).map((e: any) => e.value);
|
||||
if (item.type !== 'MULTIPLE_INPUT') {
|
||||
const currentDefaultValue = optionsIds.filter((e: any) => JSON.parse(item.value).includes(e));
|
||||
tmpObj[item.id] = currentDefaultValue;
|
||||
} else {
|
||||
tmpObj[item.id] = JSON.parse(item.value);
|
||||
}
|
||||
} else if (item.type === 'INT' || item.type === 'FLOAT') {
|
||||
tmpObj[item.id] = Number(item.value);
|
||||
} else if (item.type === 'CASCADER') {
|
||||
const arr = JSON.parse(item.value);
|
||||
if (arr && arr instanceof Array && arr.length > 0) {
|
||||
tmpObj[item.id] = arr[arr.length - 1];
|
||||
}
|
||||
} else if (SINGRADIO_TYPE.includes(item.type)) {
|
||||
const multipleOptions =
|
||||
currentCustomFields.value.find((filed: any) => item.id === filed.fieldId)?.options || [];
|
||||
// 如果该值在选项中已经被删除掉
|
||||
const optionsIds = (multipleOptions || []).map((e: any) => e.value);
|
||||
const currentDefaultValue = optionsIds.find((e: any) => item.value === e) || '';
|
||||
tmpObj[item.id] = currentDefaultValue;
|
||||
} else {
|
||||
tmpObj[item.id] = item.value;
|
||||
}
|
||||
|
@ -534,6 +580,13 @@
|
|||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleUploadImage(file: File) {
|
||||
const { data } = await editorUploadFile({
|
||||
fileList: [file],
|
||||
});
|
||||
return data;
|
||||
}
|
||||
watch(
|
||||
() => showDrawerVisible.value,
|
||||
(val) => {
|
||||
|
@ -542,11 +595,6 @@
|
|||
}
|
||||
}
|
||||
);
|
||||
watchEffect(() => {
|
||||
if (props.detailIndex) {
|
||||
activeTab.value = 'detail';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
|
|
@ -151,7 +151,7 @@
|
|||
<div class="min-w-[250px] overflow-auto">
|
||||
<a-skeleton v-if="isLoading" :loading="isLoading" :animation="true">
|
||||
<a-space direction="vertical" class="w-full" size="large">
|
||||
<a-skeleton-line :rows="rowLength" :line-height="30" :line-spacing="30" />
|
||||
<a-skeleton-line :rows="12" :line-height="30" :line-spacing="30" />
|
||||
</a-space>
|
||||
</a-skeleton>
|
||||
<a-form v-else :model="form" layout="vertical">
|
||||
|
@ -239,10 +239,12 @@
|
|||
import useVisit from '@/hooks/useVisit';
|
||||
import router from '@/router';
|
||||
import { useAppStore } from '@/store';
|
||||
import useUserStore from '@/store/modules/user';
|
||||
import { downloadByteFile } from '@/utils';
|
||||
import { scrollIntoView } from '@/utils/dom';
|
||||
import { findParents, Option } from '@/utils/recursion';
|
||||
|
||||
import type { CustomFieldItem } from '@/models/bug-management';
|
||||
import {
|
||||
BugEditCustomField,
|
||||
BugEditCustomFieldItem,
|
||||
|
@ -304,7 +306,7 @@
|
|||
const associatedDrawer = ref(false);
|
||||
const loading = ref(false);
|
||||
const acceptType = ref('none'); // 模块-上传文件类型
|
||||
|
||||
const userStore = useUserStore();
|
||||
const isEdit = computed(() => !!route.query.id && route.params.mode === 'edit');
|
||||
const bugId = computed(() => route.query.id || '');
|
||||
const isEditOrCopy = computed(() => !!bugId.value);
|
||||
|
@ -364,25 +366,34 @@
|
|||
// 处理表单格式
|
||||
const getFormRules = (arr: BugEditCustomField[]) => {
|
||||
formRules.value = [];
|
||||
const memberType = ['MEMBER', 'MULTIPLE_MEMBER'];
|
||||
|
||||
if (Array.isArray(arr) && arr.length) {
|
||||
formRules.value = arr.map((item: any) => {
|
||||
let initValue = item.defaultValue;
|
||||
const initOptions = item.options;
|
||||
if (memberType.includes(item.type)) {
|
||||
if (item.defaultValue === 'CREATE_USER' || item.defaultValue.includes('CREATE_USER')) {
|
||||
initValue = item.type === 'MEMBER' ? userStore.id : [userStore.id];
|
||||
}
|
||||
}
|
||||
return {
|
||||
type: item.type,
|
||||
name: item.fieldId,
|
||||
label: item.fieldName,
|
||||
value: item.defaultValue,
|
||||
options: item.platformOptionJson ? JSON.parse(item.platformOptionJson) : item.options,
|
||||
value: initValue,
|
||||
options: initOptions,
|
||||
required: item.required as boolean,
|
||||
platformPlaceHolder: item.platformPlaceHolder,
|
||||
props: {
|
||||
modelValue: item.defaultValue,
|
||||
options: item.platformOptionJson ? JSON.parse(item.platformOptionJson) : item.options,
|
||||
modelValue: initValue,
|
||||
options: initOptions,
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const currentCustomFields = ref<CustomFieldItem[]>([]);
|
||||
const templateChange = async (v: SelectValue, request?: BugTemplateRequest) => {
|
||||
if (v) {
|
||||
try {
|
||||
|
@ -392,6 +403,7 @@
|
|||
param = { ...param, ...request };
|
||||
}
|
||||
const res = await getTemplateById(param);
|
||||
currentCustomFields.value = res.customFields || [];
|
||||
await getFormRules(res.customFields);
|
||||
isLoading.value = false;
|
||||
isPlatformDefaultTemplate.value = res.platformDefault;
|
||||
|
@ -674,19 +686,39 @@
|
|||
tmpObj = { status: res.status };
|
||||
}
|
||||
if (customFields && Array.isArray(customFields)) {
|
||||
const MULTIPLE_TYPE = ['MULTIPLE_SELECT', 'MULTIPLE_INPUT', 'CHECKBOX', 'MULTIPLE_MEMBER'];
|
||||
const SINGRADIO_TYPE = ['RADIO', 'SELECT', 'MEMBER'];
|
||||
customFields.forEach((item) => {
|
||||
if (item.id === 'status' && isCopy.value) {
|
||||
// 复制时, 状态赋值为空
|
||||
tmpObj[item.id] = '';
|
||||
} else if (item.type === 'MULTIPLE_SELECT' || item.type === 'MULTIPLE_INPUT' || item.type === 'CHECKBOX') {
|
||||
tmpObj[item.id] = JSON.parse(item.value);
|
||||
} else if (item.type === 'INT') {
|
||||
// 多选类型需要过滤选项
|
||||
} else if (MULTIPLE_TYPE.includes(item.type)) {
|
||||
const multipleOptions =
|
||||
currentCustomFields.value.find((filed: any) => item.id === filed.fieldId)?.options || [];
|
||||
// 如果该值在选项中已经被删除掉
|
||||
const optionsIds = (multipleOptions || []).map((e: any) => e.value);
|
||||
if (item.type !== 'MULTIPLE_INPUT') {
|
||||
const currentDefaultValue = optionsIds.filter((e: any) => JSON.parse(item.value).includes(e));
|
||||
tmpObj[item.id] = currentDefaultValue;
|
||||
} else {
|
||||
tmpObj[item.id] = JSON.parse(item.value);
|
||||
}
|
||||
} else if (item.type === 'INT' || item.type === 'FLOAT') {
|
||||
tmpObj[item.id] = Number(item.value);
|
||||
} else if (item.type === 'CASCADER') {
|
||||
const arr = JSON.parse(item.value);
|
||||
if (arr && arr instanceof Array && arr.length > 0) {
|
||||
tmpObj[item.id] = arr[arr.length - 1];
|
||||
}
|
||||
// 单选多选项
|
||||
} else if (SINGRADIO_TYPE.includes(item.type)) {
|
||||
const multipleOptions =
|
||||
currentCustomFields.value.find((filed: any) => item.id === filed.fieldId)?.options || [];
|
||||
// 如果该值在选项中已经被删除掉
|
||||
const optionsIds = (multipleOptions || []).map((e: any) => e.value);
|
||||
const currentDefaultValue = optionsIds.find((e: any) => item.value === e) || '';
|
||||
tmpObj[item.id] = currentDefaultValue;
|
||||
} else {
|
||||
tmpObj[item.id] = item.value;
|
||||
}
|
||||
|
|
|
@ -226,8 +226,7 @@
|
|||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
|
||||
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||
import BatchEditModal from './components/batchEditModal.vue';
|
||||
import BugDetailDrawer from './components/bug-detail-drawer.vue';
|
||||
// import BugDetailDrawer from './components/bug-detail-drawer.vue';
|
||||
import TableFilter from '@/views/case-management/caseManagementFeature/components/tableFilter.vue';
|
||||
|
||||
import {
|
||||
|
@ -264,6 +263,8 @@
|
|||
const MsExportDrawer = defineAsyncComponent(() => import('@/components/pure/ms-export-drawer/index.vue'));
|
||||
const DeleteModal = defineAsyncComponent(() => import('./components/deleteModal.vue'));
|
||||
const MsBaseTable = defineAsyncComponent(() => import('@/components/pure/ms-table/base-table.vue'));
|
||||
const BatchEditModal = defineAsyncComponent(() => import('./components/batchEditModal.vue'));
|
||||
const BugDetailDrawer = defineAsyncComponent(() => import('./components/bug-detail-drawer.vue'));
|
||||
|
||||
const tableStore = useTableStore();
|
||||
const appStore = useAppStore();
|
||||
|
|
|
@ -87,7 +87,7 @@
|
|||
</MsButton>
|
||||
</div>
|
||||
</template>
|
||||
<template #default>
|
||||
<template #default="{ loading }">
|
||||
<div
|
||||
ref="wrapperRef"
|
||||
class="wrapperRef bg-white"
|
||||
|
@ -158,54 +158,61 @@
|
|||
</template>
|
||||
<template #second>
|
||||
<div class="rightWrapper h-full p-[24px]">
|
||||
<div class="mb-4 font-medium">{{ t('caseManagement.featureCase.basicInfo') }}</div>
|
||||
<div class="baseItem">
|
||||
<span class="label"> {{ t('caseManagement.featureCase.tableColumnModule') }}</span>
|
||||
<span class="w-[calc(100%-36%)]">
|
||||
<a-tree-select
|
||||
v-model="detailInfo.moduleId"
|
||||
:data="caseTree"
|
||||
class="w-full"
|
||||
:allow-search="true"
|
||||
:field-names="{
|
||||
title: 'name',
|
||||
key: 'id',
|
||||
children: 'children',
|
||||
}"
|
||||
:tree-props="{
|
||||
virtualListProps: {
|
||||
height: 200,
|
||||
},
|
||||
}"
|
||||
@change="handleChangeModule"
|
||||
></a-tree-select>
|
||||
</span>
|
||||
</div>
|
||||
<!-- 自定义字段开始 -->
|
||||
<MsFormCreate
|
||||
v-if="formRules.length"
|
||||
ref="formCreateRef"
|
||||
v-model:api="fApi"
|
||||
v-model:form-item="formItem"
|
||||
:form-rule="formRules"
|
||||
class="w-full"
|
||||
:option="options"
|
||||
@change="changeHandler"
|
||||
/>
|
||||
<!-- 自定义字段结束 -->
|
||||
<div class="baseItem">
|
||||
<span class="label"> {{ t('caseManagement.featureCase.tableColumnCreateUser') }}</span>
|
||||
<span class="value">{{ detailInfo?.createUserName }}</span>
|
||||
</div>
|
||||
<div class="baseItem">
|
||||
<span class="label"> {{ t('caseManagement.featureCase.tableColumnCreateTime') }}</span>
|
||||
<span class="value">{{ dayjs(detailInfo?.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
|
||||
</div>
|
||||
<div class="baseItem">
|
||||
<span class="label"> {{ t('caseManagement.featureCase.tableColumnTag') }}</span>
|
||||
<span class="value">
|
||||
<MsTag v-for="item of detailInfo.tags" :key="item"> {{ item }} </MsTag>
|
||||
</span>
|
||||
<a-skeleton v-if="loading" class="w-full" :loading="loading" :animation="true">
|
||||
<a-space direction="vertical" class="w-[100%]" size="large">
|
||||
<a-skeleton-line :rows="14" :line-height="30" :line-spacing="30" />
|
||||
</a-space>
|
||||
</a-skeleton>
|
||||
<div v-else>
|
||||
<div class="mb-4 font-medium">{{ t('caseManagement.featureCase.basicInfo') }}</div>
|
||||
<div class="baseItem">
|
||||
<span class="label"> {{ t('caseManagement.featureCase.tableColumnModule') }}</span>
|
||||
<span class="w-[calc(100%-36%)]">
|
||||
<a-tree-select
|
||||
v-model="detailInfo.moduleId"
|
||||
:data="caseTree"
|
||||
class="w-full"
|
||||
:allow-search="true"
|
||||
:field-names="{
|
||||
title: 'name',
|
||||
key: 'id',
|
||||
children: 'children',
|
||||
}"
|
||||
:tree-props="{
|
||||
virtualListProps: {
|
||||
height: 200,
|
||||
},
|
||||
}"
|
||||
@change="handleChangeModule"
|
||||
></a-tree-select>
|
||||
</span>
|
||||
</div>
|
||||
<!-- 自定义字段开始 -->
|
||||
<MsFormCreate
|
||||
v-if="formRules.length"
|
||||
ref="formCreateRef"
|
||||
v-model:api="fApi"
|
||||
v-model:form-item="formItem"
|
||||
:form-rule="formRules"
|
||||
class="w-full"
|
||||
:option="options"
|
||||
@change="changeHandler"
|
||||
/>
|
||||
<!-- 自定义字段结束 -->
|
||||
<div class="baseItem">
|
||||
<span class="label"> {{ t('caseManagement.featureCase.tableColumnCreateUser') }}</span>
|
||||
<span class="value">{{ detailInfo?.createUserName }}</span>
|
||||
</div>
|
||||
<div class="baseItem">
|
||||
<span class="label"> {{ t('caseManagement.featureCase.tableColumnCreateTime') }}</span>
|
||||
<span class="value">{{ dayjs(detailInfo?.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
|
||||
</div>
|
||||
<div class="baseItem">
|
||||
<span class="label"> {{ t('caseManagement.featureCase.tableColumnTag') }}</span>
|
||||
<span class="value">
|
||||
<MsTag v-for="item of detailInfo.tags" :key="item"> {{ item }} </MsTag>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -217,6 +224,7 @@
|
|||
:is-active="isActive"
|
||||
is-show-avatar
|
||||
is-use-bottom
|
||||
:upload-image="handleUploadImage"
|
||||
@publish="publishHandler"
|
||||
@cancel="cancelPublish"
|
||||
/>
|
||||
|
@ -248,6 +256,7 @@
|
|||
import {
|
||||
createCommentList,
|
||||
deleteCaseRequest,
|
||||
editorUploadFile,
|
||||
followerCaseRequest,
|
||||
getCaseDetail,
|
||||
getCaseModuleTree,
|
||||
|
@ -622,6 +631,13 @@
|
|||
onMounted(() => {
|
||||
settingDrawerRef.value.getTabModule();
|
||||
});
|
||||
|
||||
async function handleUploadImage(file: File) {
|
||||
const { data } = await editorUploadFile({
|
||||
fileList: [file],
|
||||
});
|
||||
return data;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
|
|
@ -695,7 +695,6 @@
|
|||
|
||||
const filterConfigList = ref<FilterFormItem[]>([]);
|
||||
const searchCustomFields = ref<FilterFormItem[]>([]);
|
||||
const scrollWidth = ref<number>(3400);
|
||||
const memberOptions = ref<{ label: string; value: string }[]>([]);
|
||||
const updateUserFilters = ref<string[]>([]);
|
||||
const createUserFilters = ref<string[]>([]);
|
||||
|
|
|
@ -10,9 +10,15 @@
|
|||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div id="magnifier"></div>
|
||||
<!-- 用例评论 -->
|
||||
<div v-show="activeComment === 'caseComment'">
|
||||
<MsComment :comment-list="commentList" @delete="handleDelete" @update-or-add="handleUpdateOrAdd" />
|
||||
<MsComment
|
||||
:upload-image="handleUploadImage"
|
||||
:comment-list="commentList"
|
||||
@delete="handleDelete"
|
||||
@update-or-add="handleUpdateOrAdd"
|
||||
/>
|
||||
<MsEmpty v-if="commentList.length === 0" />
|
||||
</div>
|
||||
|
||||
|
@ -74,6 +80,7 @@
|
|||
import {
|
||||
addOrUpdateCommentList,
|
||||
deleteCommentList,
|
||||
editorUploadFile,
|
||||
getCommentList,
|
||||
getReviewCommentList,
|
||||
} from '@/api/modules/case-management/featureCase';
|
||||
|
@ -211,6 +218,13 @@
|
|||
// }
|
||||
// );
|
||||
|
||||
async function handleUploadImage(file: File) {
|
||||
const { data } = await editorUploadFile({
|
||||
fileList: [file],
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getAllCommentList();
|
||||
});
|
||||
|
@ -220,4 +234,14 @@
|
|||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped lang="less">
|
||||
#magnifier {
|
||||
position: absolute;
|
||||
display: none;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
border: 1px solid red;
|
||||
background-size: contain;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -157,8 +157,8 @@
|
|||
},
|
||||
{
|
||||
title: 'project.commonScript.createUser',
|
||||
slotName: 'createUser',
|
||||
dataIndex: 'createUser',
|
||||
slotName: 'createUserName',
|
||||
dataIndex: 'createUserName',
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
showDrag: true,
|
||||
|
@ -278,7 +278,8 @@
|
|||
async function saveHandler(form: AddOrUpdateCommonScript) {
|
||||
try {
|
||||
confirmLoading.value = true;
|
||||
const { status } = form;
|
||||
const { status, params } = form;
|
||||
paramsList.value = JSON.parse(params);
|
||||
const paramTableList = paramsList.value.slice(0, -1);
|
||||
const paramsObj: AddOrUpdateCommonScript = {
|
||||
...form,
|
||||
|
|
|
@ -53,7 +53,9 @@
|
|||
</template>
|
||||
<template #name="{ record }">
|
||||
<div class="flex items-center">
|
||||
<span v-if="record.enablePlatformDefault" class="one-line-text ml-2">{{ record.name }}</span>
|
||||
<span
|
||||
v-else
|
||||
class="one-line-text ml-2 cursor-pointer text-[rgb(var(--primary-5))]"
|
||||
@click="previewDetail(record.id)"
|
||||
>{{ record.name }}</span
|
||||
|
@ -237,7 +239,9 @@
|
|||
const searchFiled = async () => {
|
||||
try {
|
||||
totalList.value = await getProjectTemplateList({ projectId: currentProjectId.value, scene });
|
||||
const filterData = totalList.value.filter((item: OrdTemplateManagement) => item.name.includes(keyword.value));
|
||||
const filterData: OrdTemplateManagement[] = totalList.value.filter((item: OrdTemplateManagement) =>
|
||||
item.name.includes(keyword.value)
|
||||
);
|
||||
setProps({ data: filterData });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
|
|
@ -676,35 +676,29 @@
|
|||
.wrapper-preview {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
|
||||
.preview-left {
|
||||
width: 100%;
|
||||
border-right: 1px solid var(--color-text-n8);
|
||||
}
|
||||
|
||||
.preview-right {
|
||||
padding-top: 8px;
|
||||
width: 428px;
|
||||
min-width: 428px;
|
||||
|
||||
.customWrapper {
|
||||
position: relative;
|
||||
margin-bottom: 4px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 6px;
|
||||
@apply flex flex-col justify-between;
|
||||
|
||||
.form {
|
||||
padding: 8px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.form.activeStyle {
|
||||
border-color: rgb(var(--primary-5));
|
||||
background: var(--color-text-n9);
|
||||
}
|
||||
|
||||
.action {
|
||||
position: absolute;
|
||||
top: -12px;
|
||||
|
@ -713,29 +707,24 @@
|
|||
background: white;
|
||||
opacity: 0;
|
||||
@apply flex items-center justify-end;
|
||||
|
||||
.actionList {
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
@apply flex items-center justify-center;
|
||||
}
|
||||
|
||||
.required > .arco-checkbox {
|
||||
padding: 2px 4px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 4px 10px -1px rgba(100 100 102/ 15%);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border: 1px solid var(--color-text-n8);
|
||||
background: var(--color-text-n9);
|
||||
}
|
||||
|
||||
&:hover > .action {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&:hover > .action > .actionList {
|
||||
color: rgb(var(--primary-5));
|
||||
box-shadow: 0 4px 10px -1px rgba(100 100 102/ 15%);
|
||||
|
@ -743,19 +732,16 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.hoverStyle {
|
||||
.customWrapper:hover > .form {
|
||||
border-color: var(--color-text-n8) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.activeStyle {
|
||||
.customWrapper:hover .form {
|
||||
border-color: rgb(var(--primary-5));
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.selfClass) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
@ -787,7 +773,6 @@
|
|||
border: 1px solid rgba(var(--primary-5));
|
||||
background-color: var(--color-text-n9);
|
||||
}
|
||||
|
||||
:deep(.apiFieldIdClass) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
|
|
@ -185,9 +185,13 @@
|
|||
|
||||
// 是否展示日期或数值
|
||||
const showDateOrNumber = computed(() => {
|
||||
if (getFieldType(fieldForm.value.type)[0]) {
|
||||
selectFormat.value = getFieldType(fieldForm.value.type)[0]?.value;
|
||||
if (fieldForm.value.type) return getFieldType(fieldForm.value.type);
|
||||
// if (getFieldType(fieldForm.value.type)[0]) {
|
||||
// selectFormat.value = getFieldType(fieldForm.value.type)[0]?.value;
|
||||
// if (fieldForm.value.type) return getFieldType(fieldForm.value.type);
|
||||
// }
|
||||
selectFormat.value = getFieldType(fieldForm.value.type)[0]?.value;
|
||||
if (fieldForm.value.type) {
|
||||
return getFieldType(fieldForm.value.type);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -75,16 +75,16 @@
|
|||
@confirm="handleOk(record)"
|
||||
>
|
||||
<MsButton
|
||||
v-if="!record.internal && hasAnyPermission(props.updatePermission)"
|
||||
v-if="!record.templateRequired && hasAnyPermission(props.updatePermission)"
|
||||
:disabled="record.internal"
|
||||
class="!mr-0"
|
||||
>{{ t('system.orgTemplate.edit') }}</MsButton
|
||||
></MsPopConfirm
|
||||
>
|
||||
|
||||
<a-divider v-if="!record.internal" class="h-[12px]" direction="vertical" />
|
||||
<a-divider v-if="!record.templateRequired" class="h-[12px]" direction="vertical" />
|
||||
<MsTableMoreAction
|
||||
v-if="!record.internal"
|
||||
v-if="!record.templateRequired"
|
||||
v-permission="props.deletePermission"
|
||||
:list="moreActions"
|
||||
@select="(item) => handleMoreActionSelect(item, record)"
|
||||
|
|
Loading…
Reference in New Issue