fix(缺陷管理): 富文本图片同步问题

This commit is contained in:
song-cc-rock 2024-03-19 19:26:35 +08:00 committed by Craftsman
parent 921d77bf48
commit a3aad0b82c
5 changed files with 40 additions and 17 deletions

View File

@ -3,6 +3,7 @@ package io.metersphere.plugin.platform.dto.reponse;
import lombok.Data; import lombok.Data;
import java.util.List; import java.util.List;
import java.util.Map;
@Data @Data
public class PlatformBugDTO extends MsSyncBugDTO { public class PlatformBugDTO extends MsSyncBugDTO {
@ -22,7 +23,9 @@ public class PlatformBugDTO extends MsSyncBugDTO {
private List<PlatformCustomFieldItemDTO> needSyncCustomFields; private List<PlatformCustomFieldItemDTO> needSyncCustomFields;
/** /**
* 缺陷同步需要下载的第三方富文本图片文件Key * 缺陷同步需要下载的第三方富文本图片{key: name}
* key: 唯一文件流获取的ID
* name: 文件名称
*/ */
private List<String> richTextImageKeys; private Map<String, String> richTextImageMap;
} }

View File

@ -2,6 +2,7 @@ package io.metersphere.plugin.platform.dto.reponse;
import lombok.Data; import lombok.Data;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -42,6 +43,6 @@ public class PlatformDemandDTO {
/** /**
* 自定义字段 * 自定义字段
*/ */
private Map<String, Object> customFields; private Map<String, Object> customFields = new HashMap<>();
} }
} }

View File

@ -103,8 +103,6 @@ public class BugService {
@Resource @Resource
protected TemplateMapper templateMapper; protected TemplateMapper templateMapper;
@Resource @Resource
private BugCommentMapper bugCommentMapper;
@Resource
private BugContentMapper bugContentMapper; private BugContentMapper bugContentMapper;
@Resource @Resource
private SqlSessionFactory sqlSessionFactory; private SqlSessionFactory sqlSessionFactory;
@ -1257,25 +1255,25 @@ public class BugService {
* @param platform 平台对象 * @param platform 平台对象
*/ */
private void syncRichTextToMs(PlatformBugDTO updateBug, Platform platform) { private void syncRichTextToMs(PlatformBugDTO updateBug, Platform platform) {
if (CollectionUtils.isNotEmpty(updateBug.getRichTextImageKeys())) { if (MapUtils.isNotEmpty(updateBug.getRichTextImageMap())) {
Map<String, String> richTextImageMap = updateBug.getRichTextImageMap();
// 同步第三方的富文本文件 // 同步第三方的富文本文件
updateBug.getRichTextImageKeys().forEach(key -> platform.getAttachmentContent(key, (in) -> { richTextImageMap.keySet().forEach(key -> platform.getAttachmentContent(key, (in) -> {
if (in == null) { if (in == null) {
return; return;
} }
String fileId = IDGenerator.nextStr(); String fileId = IDGenerator.nextStr();
// 第三方平台的图片下载命名为平台名称+随机数字 String fileName = updateBug.getPlatform() + "-" + richTextImageMap.get(key);
String fileName = updateBug.getPlatform() + "-" + IDGenerator.nextNum() + ".jpg";
byte[] bytes; byte[] bytes;
try { try {
// upload platform attachment to minio // 获取第三方平台附件流
bytes = in.readAllBytes(); bytes = in.readAllBytes();
// 第三方平台下载的图片默认不压缩 // 第三方平台下载的图片默认不压缩
FileCenter.getDefaultRepository().saveFile(bytes, buildBugFileRequest(updateBug.getProjectId(), updateBug.getId(), fileId, fileName)); FileCenter.getDefaultRepository().saveFile(bytes, buildBugFileRequest(updateBug.getProjectId(), updateBug.getId(), fileId, fileName));
} catch (Exception e) { } catch (Exception e) {
throw new MSException(e.getMessage()); throw new MSException(e.getMessage());
} }
// save bug attachment relation // 保存缺陷附件关系
BugLocalAttachment localAttachment = new BugLocalAttachment(); BugLocalAttachment localAttachment = new BugLocalAttachment();
localAttachment.setId(IDGenerator.nextStr()); localAttachment.setId(IDGenerator.nextStr());
localAttachment.setBugId(updateBug.getId()); localAttachment.setBugId(updateBug.getId());
@ -1286,7 +1284,7 @@ public class BugService {
localAttachment.setCreateUser("admin"); localAttachment.setCreateUser("admin");
localAttachment.setSource(BugAttachmentSourceType.RICH_TEXT.name()); localAttachment.setSource(BugAttachmentSourceType.RICH_TEXT.name());
bugLocalAttachmentMapper.insert(localAttachment); bugLocalAttachmentMapper.insert(localAttachment);
// 替换富文本中的临时URL为预览URL // 替换富文本中的临时URL, 注意: 第三方的图片附件暂未存储在压缩目录, 因此不支持压缩访问
updateBug.setDescription(updateBug.getDescription().replace("alt=\"" + key + "\"", "src=\"/bug/attachment/preview/md/" + updateBug.getProjectId() + "/" + fileId + "/false\"")); updateBug.setDescription(updateBug.getDescription().replace("alt=\"" + key + "\"", "src=\"/bug/attachment/preview/md/" + updateBug.getProjectId() + "/" + fileId + "/false\""));
})); }));
} }

View File

@ -2,7 +2,6 @@ import { markRaw } from 'vue';
import ImageView from './ImageView.vue'; import ImageView from './ImageView.vue';
import { PreviewEditorImageUrl } from '@/api/requrls/case-management/featureCase';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import type { ExtensionOptions, NodeBubbleMenu } from '../../types'; import type { ExtensionOptions, NodeBubbleMenu } from '../../types';
@ -13,9 +12,9 @@ import {
EditorState, EditorState,
isActive, isActive,
mergeAttributes, mergeAttributes,
ToolboxItem,
VueNodeViewRenderer, VueNodeViewRenderer,
} from '@halo-dev/richtext-editor'; } from '@halo-dev/richtext-editor';
import { ToolboxItem } from '@halo-dev/richtext-editor';
import type { ImageOptions } from '@tiptap/extension-image'; import type { ImageOptions } from '@tiptap/extension-image';
import TiptapImage from '@tiptap/extension-image'; import TiptapImage from '@tiptap/extension-image';
@ -102,6 +101,18 @@ const Image = TiptapImage.extend<ExtensionOptions & ImageOptions>({
}; };
}, },
}, },
// 第三方平台链接, 富文本双向同步时需要
psrc: {
default: undefined,
parseHTML: (element) => {
return element.getAttribute('psrc') || null;
},
renderHTML: (attributes) => {
return {
psrc: attributes.psrc,
};
},
},
}; };
}, },

View File

@ -120,6 +120,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed } from 'vue';
import { FormInstance, Message } from '@arco-design/web-vue'; import { FormInstance, Message } from '@arco-design/web-vue';
import MsDrawer from '@/components/pure/ms-drawer/index.vue'; import MsDrawer from '@/components/pure/ms-drawer/index.vue';
@ -134,6 +135,7 @@
} from '@/api/modules/project-management/menuManagement'; } from '@/api/modules/project-management/menuManagement';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import { useAppStore } from '@/store'; import { useAppStore } from '@/store';
import useLicenseStore from '@/store/modules/setting/license';
import { PoolOption, SelectValue } from '@/models/projectManagement/menuManagement'; import { PoolOption, SelectValue } from '@/models/projectManagement/menuManagement';
import { MenuEnum } from '@/enums/commonEnum'; import { MenuEnum } from '@/enums/commonEnum';
@ -158,6 +160,7 @@
]); ]);
const appStore = useAppStore(); const appStore = useAppStore();
const licenseStore = useLicenseStore();
const currentProjectId = computed(() => appStore.currentProjectId); const currentProjectId = computed(() => appStore.currentProjectId);
const currentOrgId = computed(() => appStore.currentOrgId); const currentOrgId = computed(() => appStore.currentOrgId);
const platformDisabled = computed(() => platformOption.value.length === 0); const platformDisabled = computed(() => platformOption.value.length === 0);
@ -175,6 +178,9 @@
}); });
const okDisabled = computed(() => !form.PLATFORM_KEY); const okDisabled = computed(() => !form.PLATFORM_KEY);
const isXpack = computed(() => {
return licenseStore.hasLicense();
});
const fApi = ref<any>({}); const fApi = ref<any>({});
const emit = defineEmits<{ const emit = defineEmits<{
@ -255,7 +261,11 @@
await handlePlatformChange(res.platform_key); await handlePlatformChange(res.platform_key);
form.SYNC_ENABLE = res.sync_enable; form.SYNC_ENABLE = res.sync_enable;
form.PLATFORM_KEY = res.platform_key; form.PLATFORM_KEY = res.platform_key;
if (!isXpack.value) {
form.MECHANISM = 'increment';
} else {
form.MECHANISM = res.mechanism; form.MECHANISM = res.mechanism;
}
form.CRON_EXPRESSION = res.cron_expression; form.CRON_EXPRESSION = res.cron_expression;
} }
} catch (e) { } catch (e) {