From 0deac9e9f46b31ca849af23d4e6c7185859c3196 Mon Sep 17 00:00:00 2001 From: "xinxin.wu" Date: Thu, 1 Aug 2024 14:07:10 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=A1=B9=E7=9B=AE&=E7=BB=84=E7=BB=87?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E8=81=94=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/config/vite.config.dev.ts | 10 ++++ frontend/src/api/modules/setting/template.ts | 11 +++- frontend/src/api/requrls/setting/template.ts | 8 +++ .../pure/ms-rich-text/MsRichText.vue | 10 ++-- frontend/src/models/setting/template.ts | 1 + .../components/templateManagement.vue | 3 ++ .../project-management/template/index.vue | 6 ++- .../template/components/addTemplate.vue | 21 +++++++- .../components/caseTemplateLeftContent.vue | 52 +++++++++++++++---- .../components/defectTemplateLeftContent.vue | 38 +++++++++++--- .../components/templateManagement.vue | 3 ++ .../template/components/viewTemplate.vue | 9 +++- .../setting/organization/template/index.vue | 6 ++- 13 files changed, 147 insertions(+), 31 deletions(-) diff --git a/frontend/config/vite.config.dev.ts b/frontend/config/vite.config.dev.ts index 7ead8b015c..db038b0f01 100644 --- a/frontend/config/vite.config.dev.ts +++ b/frontend/config/vite.config.dev.ts @@ -46,6 +46,16 @@ export default mergeConfig( changeOrigin: true, rewrite: (path: string) => path.replace(/^\/front\/test-plan\/report/, ''), }, + '/organization': { + target: process.env.VITE_DEV_DOMAIN, + changeOrigin: true, + rewrite: (path: string) => path.replace(/^\/front\/organization/, ''), + }, + '/project': { + target: process.env.VITE_DEV_DOMAIN, + changeOrigin: true, + rewrite: (path: string) => path.replace(/^\/front\/project/, ''), + }, '/plugin/image': { target: process.env.VITE_DEV_DOMAIN, changeOrigin: true, diff --git a/frontend/src/api/modules/setting/template.ts b/frontend/src/api/modules/setting/template.ts index 6e0bfc0b03..a5a6fa4fbf 100644 --- a/frontend/src/api/modules/setting/template.ts +++ b/frontend/src/api/modules/setting/template.ts @@ -26,6 +26,7 @@ import { OrdUpdateFlowStatusUrl, OrdUpdateStateFlowUrl, OrdWorkFlowUrl, + orgRichUploadImageUrl, ProjectCreateFlowStatusUrl, ProjectDeleteFlowStatusUrl, ProjectSetStateUrl, @@ -33,6 +34,7 @@ import { ProjectUpdateFlowStatusUrl, ProjectUpdateStateFlowUrl, ProjectWorkFlowUrl, + proRichUploadImageUrl, SetProjectTemplateUrl, UpdateFieldUrl, UpdateOrganizeTemplateUrl, @@ -40,11 +42,10 @@ import { UpdateProjectTemplateUrl, } from '@/api/requrls/setting/template'; -import { CommonList, TableQueryParams } from '@/models/common'; +import { TableQueryParams } from '@/models/common'; import type { ActionTemplateManage, AddOrUpdateField, - OrdTemplateManagement, OrdWorkStatus, SeneType, SetStateType, @@ -178,6 +179,12 @@ export function getProjectFieldDetail(id: string) { return MSR.get({ url: GetFieldProjectDetailUrl, params: id }); } +// 富文本编辑器上传图片文件 +export function editorUploadFile(data: { fileList: File[] }, mode: 'organization' | 'project') { + const url = mode === 'organization' ? orgRichUploadImageUrl : proRichUploadImageUrl; + return MSR.uploadFile({ url }, { fileList: data.fileList }, '', false); +} + /** * * 模板(项目) */ diff --git a/frontend/src/api/requrls/setting/template.ts b/frontend/src/api/requrls/setting/template.ts index 4bd8764d94..9539132a79 100644 --- a/frontend/src/api/requrls/setting/template.ts +++ b/frontend/src/api/requrls/setting/template.ts @@ -93,3 +93,11 @@ export const ProjectSetStateUrl = '/project/status/flow/setting/status/definitio export const ProjectStateSortUrl = '/project/status/flow/setting/status/sort'; // 更新状态流转 export const ProjectUpdateStateFlowUrl = '/project/status/flow/setting/status/flow/update'; +// 组织模板富文本图片链接 +export const orgRichUploadImageUrl = '/organization/template/upload/temp/img'; +// 项目模板富文本图片链接 +export const proRichUploadImageUrl = '/project/template/upload/temp/img'; +// 组织预览富文本图片 +export const previewOrgImageUrl = '/organization/template/img/preview'; +// 项目预览富文本图片 +export const previewProImageUrl = '/project/template/img/preview'; diff --git a/frontend/src/components/pure/ms-rich-text/MsRichText.vue b/frontend/src/components/pure/ms-rich-text/MsRichText.vue index ecbbfa393b..2594fadabc 100644 --- a/frontend/src/components/pure/ms-rich-text/MsRichText.vue +++ b/frontend/src/components/pure/ms-rich-text/MsRichText.vue @@ -12,6 +12,7 @@ * import rehypeStringify from 'rehype-stringify'; * return unified().use(rehypeParse).use(rehypeFormat).use(rehypeStringify).processSync(content.value); */ + import { useRoute } from 'vue-router'; import { useDebounceFn, useVModel } from '@vueuse/core'; import type { MsFileItem } from '@/components/pure/ms-upload/types'; @@ -20,7 +21,6 @@ import { editorUploadFile } from '@/api/modules/case-management/featureCase'; import { useI18n } from '@/hooks/useI18n'; import useLocale from '@/locale/useLocale'; - import { useAppStore } from '@/store'; import '@halo-dev/richtext-editor/dist/style.css'; import ExtensionImage from './extensions/image/index'; @@ -70,10 +70,8 @@ import type { queueAsPromised } from 'fastq'; import * as fastq from 'fastq'; - const appStore = useAppStore(); const { t } = useI18n(); - - // image drag and paste upload + const route = useRoute(); type Task = { file: File; process: (permalink: string, fileId: string) => void; @@ -122,8 +120,8 @@ } const uploadFileId = await props.uploadImage(arg.file); if (uploadFileId) { - // const permanentUrl = `${PreviewEditorImageUrl}/${appStore.currentProjectId}/${uploadFileId}/${true}`; - const permanentUrl = `${props.previewUrl}/${appStore.currentProjectId}/${uploadFileId}/${true}`; + const infoId = route.query.orgId && route.query.pId ? route.query.pId : route.query.orgId; + const permanentUrl = `${props.previewUrl}/${infoId}/${uploadFileId}/${true}`; arg.process(permanentUrl, uploadFileId); } } diff --git a/frontend/src/models/setting/template.ts b/frontend/src/models/setting/template.ts index d112ead3e2..ac96bd39a9 100644 --- a/frontend/src/models/setting/template.ts +++ b/frontend/src/models/setting/template.ts @@ -120,6 +120,7 @@ export interface ActionTemplateManage { enablePlatformDefault?: boolean; internal?: boolean; // 是否为系统模板 platForm?: string; + uploadImgFileIds: string[]; // 模板附件 [key: string]: any; } diff --git a/frontend/src/views/project-management/template/components/templateManagement.vue b/frontend/src/views/project-management/template/components/templateManagement.vue index 78928e3b2a..ee9fe1f761 100644 --- a/frontend/src/views/project-management/template/components/templateManagement.vue +++ b/frontend/src/views/project-management/template/components/templateManagement.vue @@ -315,6 +315,7 @@ router.push({ name: routeName.value, query: { + ...route.query, type: route.query.type, }, params: { @@ -328,6 +329,7 @@ router.push({ name: routeName.value, query: { + ...route.query, id, type: route.query.type, }, @@ -342,6 +344,7 @@ router.push({ name: routeName.value, query: { + ...route.query, id, type: route.query.type, }, diff --git a/frontend/src/views/project-management/template/index.vue b/frontend/src/views/project-management/template/index.vue index fa6a78412f..2cacdd5ff3 100644 --- a/frontend/src/views/project-management/template/index.vue +++ b/frontend/src/views/project-management/template/index.vue @@ -30,7 +30,7 @@ * @description 项目设置--模板 */ - import { useRouter } from 'vue-router'; + import { useRoute, useRouter } from 'vue-router'; import MsCard from '@/components/pure/ms-card/index.vue'; import MsCardList from '@/components/business/ms-card-list/index.vue'; @@ -43,12 +43,14 @@ import { getCardList } from '@/views/setting/organization/template/components/fieldSetting'; const router = useRouter(); + const route = useRoute(); const templateStore = useTemplateStore(); // 字段设置 const fieldSetting = (key: string) => { router.push({ name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_TEMPLATE_FIELD_SETTING, query: { + ...route.query, type: key, }, }); @@ -59,6 +61,7 @@ router.push({ name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT, query: { + ...route.query, type: key, }, }); @@ -69,6 +72,7 @@ router.push({ name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT_WORKFLOW, query: { + ...route.query, type: key, }, }); diff --git a/frontend/src/views/setting/organization/template/components/addTemplate.vue b/frontend/src/views/setting/organization/template/components/addTemplate.vue index 8fb1e5b40a..beee2cdc5e 100644 --- a/frontend/src/views/setting/organization/template/components/addTemplate.vue +++ b/frontend/src/views/setting/organization/template/components/addTemplate.vue @@ -56,8 +56,18 @@
- - + +
@@ -308,6 +318,7 @@ scopeId: props.mode === 'organization' ? currentOrgId.value : currentProjectId.value, enableThirdPart: false, platForm: '', + uploadImgFileIds: [], }; const initBugForm = { @@ -359,6 +370,9 @@ // 缺陷默认字段 const defaultBugForm = ref(cloneDeep(defaultTemplateBugDetail)); + const uploadBugImgFileIds = ref([]); + const uploadCaseImgFileIds = ref([]); + // 获取系统默认字段 function getSystemFields(form: Record) { const tempFormField: Record[] = []; @@ -397,6 +411,8 @@ const systemFields: Record[] = route.query.type === 'BUG' ? getSystemFields(defaultBugForm.value) : getSystemFields(defaultCaseForm.value); + const uploadImgFileIds = route.query.type === 'BUG' ? uploadBugImgFileIds.value : uploadCaseImgFileIds.value; + const { name, remark, enableThirdPart, id } = templateForm.value; return { id, @@ -407,6 +423,7 @@ scopeId: props.mode === 'organization' ? currentOrgId.value : currentProjectId.value, scene: route.query.type, systemFields, + uploadImgFileIds, }; } diff --git a/frontend/src/views/setting/organization/template/components/caseTemplateLeftContent.vue b/frontend/src/views/setting/organization/template/components/caseTemplateLeftContent.vue index 431fa7c9b2..24e1b7906f 100644 --- a/frontend/src/views/setting/organization/template/components/caseTemplateLeftContent.vue +++ b/frontend/src/views/setting/organization/template/components/caseTemplateLeftContent.vue @@ -20,7 +20,7 @@ v-model:raw="form.prerequisite" v-model:filed-ids="prerequisiteFileIds" :upload-image="handleUploadImage" - :preview-url="PreviewEditorImageUrl" + :preview-url="previewEditorImageUrl" :editable="!props.isDisabled" /> @@ -55,7 +55,7 @@ v-model:raw="form.textDescription" v-model:filed-ids="textDescriptionFileIds" :upload-image="handleUploadImage" - :preview-url="PreviewEditorImageUrl" + :preview-url="previewEditorImageUrl" :editable="!props.isDisabled" /> @@ -68,7 +68,7 @@ v-model:raw="form.expectedResult" v-model:filed-ids="expectedResultFileIds" :upload-image="handleUploadImage" - :preview-url="PreviewEditorImageUrl" + :preview-url="previewEditorImageUrl" :editable="!props.isDisabled" /> @@ -77,7 +77,7 @@ v-model:raw="form.description" v-model:filed-ids="descriptionFileIds" :upload-image="handleUploadImage" - :preview-url="PreviewEditorImageUrl" + :preview-url="previewEditorImageUrl" :editable="!props.isDisabled" /> @@ -95,8 +95,8 @@ import AddAttachment from '@/components/business/ms-add-attachment/index.vue'; import AddStep from '@/views/case-management/caseManagementFeature/components/addStep.vue'; - import { editorUploadFile } from '@/api/modules/case-management/featureCase'; - import { PreviewEditorImageUrl } from '@/api/requrls/case-management/featureCase'; + import { editorUploadFile } from '@/api/modules/setting/template'; + import { previewOrgImageUrl, previewProImageUrl } from '@/api/requrls/setting/template'; import { defaultTemplateCaseDetail } from '@/config/template'; import { useI18n } from '@/hooks/useI18n'; import { getGenerateId } from '@/utils'; @@ -107,12 +107,16 @@ const { t } = useI18n(); const props = defineProps<{ + mode: 'organization' | 'project'; isDisabled?: boolean; }>(); const form = defineModel('defaultForm', { default: defaultTemplateCaseDetail, }); + const uploadImgFileIds = defineModel('uploadImgFileIds', { + default: [], + }); const fileList = ref([]); @@ -177,13 +181,41 @@ } } ); - // TODO 上传需要接口 + // 上传图片 async function handleUploadImage(file: File) { - const { data } = await editorUploadFile({ - fileList: [file], - }); + const { data } = await editorUploadFile( + { + fileList: [file], + }, + props.mode + ); return data; } + + const previewEditorImageUrl = computed(() => + props.mode === 'organization' ? previewOrgImageUrl : previewProImageUrl + ); + + const fileIds = computed(() => { + return [ + ...prerequisiteFileIds.value, + ...textDescriptionFileIds.value, + ...expectedResultFileIds.value, + ...descriptionFileIds.value, + ]; + }); + + watch( + () => fileIds.value, + (val) => { + if (val) { + uploadImgFileIds.value = val; + } + }, + { + deep: true, + } + ); diff --git a/frontend/src/views/setting/organization/template/components/defectTemplateLeftContent.vue b/frontend/src/views/setting/organization/template/components/defectTemplateLeftContent.vue index 118a528620..c0952533c6 100644 --- a/frontend/src/views/setting/organization/template/components/defectTemplateLeftContent.vue +++ b/frontend/src/views/setting/organization/template/components/defectTemplateLeftContent.vue @@ -17,7 +17,7 @@ v-model:raw="form.description" v-model:filed-ids="descriptionFileIds" :upload-image="handleUploadImage" - :preview-url="EditorPreviewFileUrl" + :preview-url="previewEditorImageUrl" :editable="!props.isDisabled" /> @@ -34,8 +34,8 @@ import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue'; import AddAttachment from '@/components/business/ms-add-attachment/index.vue'; - import { editorUploadFile } from '@/api/modules/bug-management'; - import { EditorPreviewFileUrl } from '@/api/requrls/bug-management'; + import { editorUploadFile } from '@/api/modules/setting/template'; + import { previewOrgImageUrl, previewProImageUrl } from '@/api/requrls/setting/template'; import { defaultTemplateBugDetail } from '@/config/template'; import { useI18n } from '@/hooks/useI18n'; @@ -44,6 +44,7 @@ const { t } = useI18n(); const props = defineProps<{ + mode: 'organization' | 'project'; isDisabled?: boolean; }>(); @@ -53,16 +54,39 @@ default: defaultTemplateBugDetail, }); + const uploadImgFileIds = defineModel('uploadImgFileIds', { + default: [], + }); + // 富文本附件ID const descriptionFileIds = ref([]); - // TODO 上传图片需要接口 + // 上传图片 async function handleUploadImage(file: File) { - const { data } = await editorUploadFile({ - fileList: [file], - }); + const { data } = await editorUploadFile( + { + fileList: [file], + }, + props.mode + ); return data; } + + const previewEditorImageUrl = computed(() => + props.mode === 'organization' ? previewOrgImageUrl : previewProImageUrl + ); + + watch( + () => descriptionFileIds.value, + (val) => { + if (val) { + uploadImgFileIds.value = val; + } + }, + { + deep: true, + } + ); diff --git a/frontend/src/views/setting/organization/template/components/templateManagement.vue b/frontend/src/views/setting/organization/template/components/templateManagement.vue index 84c3c1eb36..48900e139e 100644 --- a/frontend/src/views/setting/organization/template/components/templateManagement.vue +++ b/frontend/src/views/setting/organization/template/components/templateManagement.vue @@ -238,6 +238,7 @@ router.push({ name: routeName.value, query: { + ...route.query, type: route.query.type, }, params: { @@ -251,6 +252,7 @@ router.push({ name: routeName.value, query: { + ...route.query, id, type: route.query.type, }, @@ -265,6 +267,7 @@ router.push({ name: routeName.value, query: { + ...route.query, id, type: route.query.type, }, diff --git a/frontend/src/views/setting/organization/template/components/viewTemplate.vue b/frontend/src/views/setting/organization/template/components/viewTemplate.vue index 4dd57e927b..bdaa8f971d 100644 --- a/frontend/src/views/setting/organization/template/components/viewTemplate.vue +++ b/frontend/src/views/setting/organization/template/components/viewTemplate.vue @@ -1,8 +1,13 @@