feat(缺陷管理): 详情保存
This commit is contained in:
parent
1d71ba51d2
commit
e3730b3bba
|
@ -88,7 +88,13 @@
|
||||||
<template #title>
|
<template #title>
|
||||||
{{ t('bugManagement.detail.detail') }}
|
{{ t('bugManagement.detail.detail') }}
|
||||||
</template>
|
</template>
|
||||||
<BugDetailTab :allow-edit="true" :detail-info="detailInfo" @update-success="updateSuccess" />
|
<BugDetailTab
|
||||||
|
ref="bugDetailTabRef"
|
||||||
|
:form-item="formItem"
|
||||||
|
:allow-edit="true"
|
||||||
|
:detail-info="detailInfo"
|
||||||
|
@update-success="updateSuccess"
|
||||||
|
/>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane key="case">
|
<a-tab-pane key="case">
|
||||||
<template #title>
|
<template #title>
|
||||||
|
@ -118,7 +124,7 @@
|
||||||
:form-rule="formRules"
|
:form-rule="formRules"
|
||||||
class="w-full"
|
class="w-full"
|
||||||
:option="options"
|
:option="options"
|
||||||
@change="handleOK"
|
@change="handelFormCreateChange"
|
||||||
/>
|
/>
|
||||||
<!-- 自定义字段结束 -->
|
<!-- 自定义字段结束 -->
|
||||||
<div class="baseItem">
|
<div class="baseItem">
|
||||||
|
@ -154,6 +160,7 @@
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
|
import { debounce } from 'lodash-es';
|
||||||
|
|
||||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||||
import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
|
import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
|
||||||
|
@ -175,7 +182,6 @@
|
||||||
followBug,
|
followBug,
|
||||||
getBugDetail,
|
getBugDetail,
|
||||||
getTemplateById,
|
getTemplateById,
|
||||||
updateBug,
|
|
||||||
} from '@/api/modules/bug-management/index';
|
} from '@/api/modules/bug-management/index';
|
||||||
import useFullScreen from '@/hooks/useFullScreen';
|
import useFullScreen from '@/hooks/useFullScreen';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
@ -212,6 +218,7 @@
|
||||||
const formItem = ref<FormRuleItem[]>([]); // 表单项
|
const formItem = ref<FormRuleItem[]>([]); // 表单项
|
||||||
const currentProjectId = computed(() => appStore.currentProjectId);
|
const currentProjectId = computed(() => appStore.currentProjectId);
|
||||||
const showDrawerVisible = defineModel<boolean>('visible', { default: false });
|
const showDrawerVisible = defineModel<boolean>('visible', { default: false });
|
||||||
|
const bugDetailTabRef = ref();
|
||||||
|
|
||||||
const activeTab = ref<string | number>('detail');
|
const activeTab = ref<string | number>('detail');
|
||||||
|
|
||||||
|
@ -219,7 +226,7 @@
|
||||||
const tags = ref([]);
|
const tags = ref([]);
|
||||||
|
|
||||||
// 处理表单格式
|
// 处理表单格式
|
||||||
const getFormRules = (arr: BugEditCustomField[]) => {
|
const getFormRules = (arr: BugEditCustomField[], valueObj: BugEditFormObject) => {
|
||||||
formRules.value = [];
|
formRules.value = [];
|
||||||
if (Array.isArray(arr) && arr.length) {
|
if (Array.isArray(arr) && arr.length) {
|
||||||
formRules.value = arr.map((item) => {
|
formRules.value = arr.map((item) => {
|
||||||
|
@ -227,11 +234,11 @@
|
||||||
type: item.type,
|
type: item.type,
|
||||||
name: item.fieldId,
|
name: item.fieldId,
|
||||||
label: item.fieldName,
|
label: item.fieldName,
|
||||||
value: item.value,
|
value: valueObj[item.fieldId],
|
||||||
options: item.platformOptionJson ? JSON.parse(item.platformOptionJson) : item.options,
|
options: item.platformOptionJson ? JSON.parse(item.platformOptionJson) : item.options,
|
||||||
required: item.required as boolean,
|
required: item.required as boolean,
|
||||||
props: {
|
props: {
|
||||||
modelValue: item.value,
|
modelValue: valueObj[item.fieldId],
|
||||||
options: item.platformOptionJson ? JSON.parse(item.platformOptionJson) : item.options,
|
options: item.platformOptionJson ? JSON.parse(item.platformOptionJson) : item.options,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -239,11 +246,11 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const templateChange = async (v: SelectValue) => {
|
const templateChange = async (v: SelectValue, valueObj: BugEditFormObject) => {
|
||||||
if (v) {
|
if (v) {
|
||||||
try {
|
try {
|
||||||
const res = await getTemplateById({ projectId: appStore.currentProjectId, id: v });
|
const res = await getTemplateById({ projectId: appStore.currentProjectId, id: v });
|
||||||
getFormRules(res.customFields);
|
getFormRules(res.customFields, valueObj);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
@ -255,16 +262,14 @@
|
||||||
const { templateId } = detail;
|
const { templateId } = detail;
|
||||||
// tag 赋值
|
// tag 赋值
|
||||||
tags.value = detail.tags || [];
|
tags.value = detail.tags || [];
|
||||||
// 初始化自定义字段
|
|
||||||
await templateChange(templateId);
|
|
||||||
const tmpObj = {};
|
const tmpObj = {};
|
||||||
if (detail.customFields && Array.isArray(detail.customFields)) {
|
if (detail.customFields && Array.isArray(detail.customFields)) {
|
||||||
detail.customFields.forEach((item) => {
|
detail.customFields.forEach((item) => {
|
||||||
tmpObj[item.id] = item.value;
|
tmpObj[item.id] = item.value;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// 自定义字段赋值
|
// 初始化自定义字段
|
||||||
fApi.value.setValue(tmpObj);
|
await templateChange(templateId, tmpObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
const editLoading = ref<boolean>(false);
|
const editLoading = ref<boolean>(false);
|
||||||
|
@ -333,24 +338,9 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleOK = async () => {
|
const handelFormCreateChange = debounce(() => {
|
||||||
const values = await fApi.value.validate();
|
bugDetailTabRef.value?.handleSave();
|
||||||
if (values) {
|
}, 300);
|
||||||
const params = {
|
|
||||||
id: detailInfo.value.id,
|
|
||||||
projectId: currentProjectId.value,
|
|
||||||
...values,
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
await updateBug(params);
|
|
||||||
Message.success(t('common.editSuccess'));
|
|
||||||
detailDrawerRef.value?.initDetail();
|
|
||||||
} catch (error) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 表单配置项
|
// 表单配置项
|
||||||
const options = {
|
const options = {
|
||||||
|
|
|
@ -1,36 +1,36 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="p-[16px]">
|
<div class="relative p-[16px] pb-[16px]">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="header-title">{{ t('bugManagement.edit.content') }}</div>
|
<div class="header-title">{{ t('bugManagement.edit.content') }}</div>
|
||||||
<div v-if="!contentEditAble" v-permission="['PROJECT_BUG:READ+UPDATE']" class="header-action">
|
<div v-permission="['PROJECT_BUG:READ+UPDATE']" class="header-action">
|
||||||
<a-button type="text" @click="contentEditAble = true">
|
<a-button type="text" @click="contentEditAble = !contentEditAble">
|
||||||
<template #icon> <MsIconfont type="icon-icon_edit_outlined" /> </template>
|
<template #icon> <MsIconfont type="icon-icon_edit_outlined" /> </template>
|
||||||
{{ t('bugManagement.edit.contentEdit') }}
|
{{ t('bugManagement.edit.contentEdit') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-[8]" :class="{ 'max-h-[260px]': contentEditAble }">
|
<div class="mt-[16px]" :class="{ 'max-h-[260px]': contentEditAble }">
|
||||||
<MsRichText
|
<MsRichText
|
||||||
v-if="contentEditAble"
|
v-if="contentEditAble"
|
||||||
v-model:raw="form.content"
|
v-model:raw="form.description"
|
||||||
v-model:filed-ids="fileIds"
|
v-model:filed-ids="fileIds"
|
||||||
:disabled="!contentEditAble"
|
:disabled="!contentEditAble"
|
||||||
:placeholder="t('bugManagement.edit.contentPlaceholder')"
|
:placeholder="t('bugManagement.edit.contentPlaceholder')"
|
||||||
:upload-image="handleUploadImage"
|
:upload-image="handleUploadImage"
|
||||||
/>
|
/>
|
||||||
<div v-else v-dompurify-html="form?.content || '-'" class="text-[var(--color-text-3)]"></div>
|
<div v-else v-dompurify-html="form?.description || '-'" class="text-[var(--color-text-3)]"></div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="contentEditAble" class="flex justify-end">
|
<div v-if="contentEditAble" class="mt-[8px] flex justify-end">
|
||||||
<a-button type="secondary" @click="handleCancel">{{ t('common.cancel') }}</a-button>
|
<a-button type="secondary" @click="handleCancel">{{ t('common.cancel') }}</a-button>
|
||||||
<a-button class="ml-[12px]" type="primary" :loading="confirmLoading">
|
<a-button class="ml-[12px]" type="primary" :loading="confirmLoading" @click="handleSave">
|
||||||
{{ t('common.save') }}
|
{{ t('common.save') }}
|
||||||
</a-button></div
|
</a-button></div
|
||||||
>
|
>
|
||||||
<div v-if="props.allowEdit">
|
<div v-if="props.allowEdit">
|
||||||
<div class="font-medium text-[var(--color-text-1)]">
|
<div class="mt-[16px] font-medium text-[var(--color-text-1)]">
|
||||||
{{ t('bugManagement.edit.file') }}
|
{{ t('bugManagement.edit.file') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-1">
|
<div class="mt-[16px] pb-[4px]">
|
||||||
<a-dropdown position="tr" trigger="hover">
|
<a-dropdown position="tr" trigger="hover">
|
||||||
<a-button v-permission="['PROJECT_BUG:READ+UPDATE']" type="outline">
|
<a-button v-permission="['PROJECT_BUG:READ+UPDATE']" type="outline">
|
||||||
<template #icon> <icon-plus class="text-[14px]" /> </template
|
<template #icon> <icon-plus class="text-[14px]" /> </template
|
||||||
|
@ -162,6 +162,7 @@
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
|
|
||||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||||
|
import { FormRuleItem } from '@/components/pure/ms-form-create/types';
|
||||||
import MsIconfont from '@/components/pure/ms-icon-font/index.vue';
|
import MsIconfont from '@/components/pure/ms-icon-font/index.vue';
|
||||||
import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue';
|
import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue';
|
||||||
import MsFileList from '@/components/pure/ms-upload/fileList.vue';
|
import MsFileList from '@/components/pure/ms-upload/fileList.vue';
|
||||||
|
@ -171,6 +172,7 @@
|
||||||
|
|
||||||
import {
|
import {
|
||||||
checkFileIsUpdateRequest,
|
checkFileIsUpdateRequest,
|
||||||
|
createOrUpdateBug,
|
||||||
deleteFileOrCancelAssociation,
|
deleteFileOrCancelAssociation,
|
||||||
downloadFileRequest,
|
downloadFileRequest,
|
||||||
editorUploadFile,
|
editorUploadFile,
|
||||||
|
@ -180,14 +182,12 @@
|
||||||
updateFile,
|
updateFile,
|
||||||
uploadOrAssociationFile,
|
uploadOrAssociationFile,
|
||||||
} from '@/api/modules/bug-management';
|
} from '@/api/modules/bug-management';
|
||||||
import { updateCaseRequest } from '@/api/modules/case-management/featureCase';
|
|
||||||
import { getModules, getModulesCount } from '@/api/modules/project-management/fileManagement';
|
import { getModules, getModulesCount } from '@/api/modules/project-management/fileManagement';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import { useAppStore } from '@/store';
|
import { useAppStore } from '@/store';
|
||||||
import { downloadByteFile, sleep } from '@/utils';
|
import { downloadByteFile, sleep } from '@/utils';
|
||||||
import { scrollIntoView } from '@/utils/dom';
|
|
||||||
|
|
||||||
import { BugEditFormObject } from '@/models/bug-management';
|
import { BugEditCustomFieldItem, BugEditFormObject } from '@/models/bug-management';
|
||||||
import { AssociatedList, AttachFileInfo } from '@/models/caseManagement/featureCase';
|
import { AssociatedList, AttachFileInfo } from '@/models/caseManagement/featureCase';
|
||||||
import { TableQueryParams } from '@/models/common';
|
import { TableQueryParams } from '@/models/common';
|
||||||
|
|
||||||
|
@ -197,6 +197,7 @@
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
detailInfo: BugEditFormObject;
|
detailInfo: BugEditFormObject;
|
||||||
|
formItem: FormRuleItem[];
|
||||||
allowEdit?: boolean; // 是否允许编辑
|
allowEdit?: boolean; // 是否允许编辑
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
@ -224,7 +225,7 @@
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const form = ref({
|
const form = ref({
|
||||||
content: '',
|
description: '',
|
||||||
deleteLocalFileIds: [] as string[],
|
deleteLocalFileIds: [] as string[],
|
||||||
unLinkRefIds: [] as string[],
|
unLinkRefIds: [] as string[],
|
||||||
linkFileIds: [] as string[],
|
linkFileIds: [] as string[],
|
||||||
|
@ -251,36 +252,17 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const confirmLoading = ref<boolean>(false);
|
||||||
|
|
||||||
|
const initCurrentDetail = async (detail: BugEditFormObject) => {
|
||||||
|
const { attachments, description } = detail;
|
||||||
|
form.value.description = description;
|
||||||
|
handleFileFunc(attachments);
|
||||||
|
};
|
||||||
|
|
||||||
function handleCancel() {
|
function handleCancel() {
|
||||||
contentEditAble.value = false;
|
contentEditAble.value = false;
|
||||||
}
|
}
|
||||||
const confirmLoading = ref<boolean>(false);
|
|
||||||
|
|
||||||
// function handleOK() {
|
|
||||||
// caseFormRef.value?.validate().then(async (res: any) => {
|
|
||||||
// if (!res) {
|
|
||||||
// try {
|
|
||||||
// confirmLoading.value = true;
|
|
||||||
// await updateCaseRequest();
|
|
||||||
// Message.success(t('caseManagement.featureCase.editSuccess'));
|
|
||||||
// handleCancel();
|
|
||||||
// emit('updateSuccess');
|
|
||||||
// } catch (error) {
|
|
||||||
// // eslint-disable-next-line no-console
|
|
||||||
// console.log(error);
|
|
||||||
// } finally {
|
|
||||||
// confirmLoading.value = false;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return scrollIntoView(document.querySelector('.arco-form-item-message'), { block: 'center' });
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
const initCurrentDetail = async (detail: BugEditFormObject) => {
|
|
||||||
const { attachments, content } = detail;
|
|
||||||
form.value.content = content;
|
|
||||||
handleFileFunc(attachments);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 删除本地文件
|
// 删除本地文件
|
||||||
async function deleteFileHandler(item: MsFileItem) {
|
async function deleteFileHandler(item: MsFileItem) {
|
||||||
|
@ -311,16 +293,6 @@
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleChange(_fileList: MsFileItem[]) {
|
|
||||||
fileList.value = _fileList.map((e) => {
|
|
||||||
return {
|
|
||||||
...e,
|
|
||||||
enable: true, // 是否启用
|
|
||||||
local: true, // 是否本地文件
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 预览图片
|
// 预览图片
|
||||||
async function handlePreview(item: MsFileItem) {
|
async function handlePreview(item: MsFileItem) {
|
||||||
try {
|
try {
|
||||||
|
@ -471,10 +443,50 @@
|
||||||
},
|
},
|
||||||
{ deep: true }
|
{ deep: true }
|
||||||
);
|
);
|
||||||
|
// 保存操作
|
||||||
|
async function handleSave() {
|
||||||
|
try {
|
||||||
|
confirmLoading.value = true;
|
||||||
|
const { formItem } = props;
|
||||||
|
const customFields: BugEditCustomFieldItem[] = [];
|
||||||
|
if (formItem && formItem.length) {
|
||||||
|
formItem.forEach((item: FormRuleItem) => {
|
||||||
|
customFields.push({
|
||||||
|
id: item.field as string,
|
||||||
|
name: item.title as string,
|
||||||
|
type: item.sourceType as string,
|
||||||
|
value: item.value as string,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const tmpObj: BugEditFormObject = {
|
||||||
|
...form.value,
|
||||||
|
id: props.detailInfo.id,
|
||||||
|
projectId: currentProjectId.value,
|
||||||
|
templateId: props.detailInfo.templateId,
|
||||||
|
customFields,
|
||||||
|
};
|
||||||
|
// 执行保存操作
|
||||||
|
const res = await createOrUpdateBug({ request: tmpObj, fileList: fileList.value as unknown as File[] });
|
||||||
|
if (res) {
|
||||||
|
Message.success(t('common.updateSuccess'));
|
||||||
|
handleCancel();
|
||||||
|
emit('updateSuccess');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
} finally {
|
||||||
|
confirmLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
initCurrentDetail(props.detailInfo);
|
initCurrentDetail(props.detailInfo);
|
||||||
});
|
});
|
||||||
|
defineExpose({
|
||||||
|
handleSave,
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
@ -487,6 +499,9 @@
|
||||||
color: var(--color-text-1);
|
color: var(--color-text-1);
|
||||||
}
|
}
|
||||||
&-action {
|
&-action {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 6px;
|
||||||
color: rgb(var(--primary-7));
|
color: rgb(var(--primary-7));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -452,6 +452,7 @@
|
||||||
formRules.value = customFields.value.map((item: any) => {
|
formRules.value = customFields.value.map((item: any) => {
|
||||||
const multipleType = ['MULTIPLE_SELECT', 'CHECKBOX', 'MULTIPLE_MEMBER', 'MULTIPLE_INPUT'];
|
const multipleType = ['MULTIPLE_SELECT', 'CHECKBOX', 'MULTIPLE_MEMBER', 'MULTIPLE_INPUT'];
|
||||||
const currentDefaultValue = multipleType.includes(item.type) ? JSON.parse(item.defaultValue) : item.defaultValue;
|
const currentDefaultValue = multipleType.includes(item.type) ? JSON.parse(item.defaultValue) : item.defaultValue;
|
||||||
|
console.log('currentDefaultValue', currentDefaultValue);
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
type: item.type,
|
type: item.type,
|
||||||
|
|
Loading…
Reference in New Issue