feat: 对图片的兼容处理
This commit is contained in:
@@ -4,6 +4,17 @@
|
|||||||
<view v-if="entry.type === 'text'" class="content-body-text">
|
<view v-if="entry.type === 'text'" class="content-body-text">
|
||||||
{{ entry.value }}
|
{{ entry.value }}
|
||||||
</view>
|
</view>
|
||||||
|
<view v-else-if="entry.type === 'image'" class="content-body-image-card">
|
||||||
|
<image
|
||||||
|
class="content-body-image"
|
||||||
|
:src="entry.value.image_id"
|
||||||
|
mode="widthFix"
|
||||||
|
@click="handlePreviewClick(entry.value.image_id)"
|
||||||
|
/>
|
||||||
|
<view v-if="entry.value.caption" class="content-body-image-caption">
|
||||||
|
{{ entry.value.caption }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
<view v-else-if="entry.type === 'list'" class="content-body-list-card">
|
<view v-else-if="entry.type === 'list'" class="content-body-list-card">
|
||||||
<view
|
<view
|
||||||
v-for="(item, index) in entry.value"
|
v-for="(item, index) in entry.value"
|
||||||
@@ -41,18 +52,33 @@ const isObjectValue = (value) => {
|
|||||||
return value !== null && typeof value === "object" && !Array.isArray(value);
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const sanitizeValue = (value) => {
|
const parseJsonStringValue = (value) => {
|
||||||
if (isArrayValue(value)) {
|
if (typeof value !== "string") return value;
|
||||||
return value.map((item) => sanitizeValue(item));
|
|
||||||
|
const text = value.trim();
|
||||||
|
if (!/^[\[{]/.test(text)) return value;
|
||||||
|
|
||||||
|
try {
|
||||||
|
return JSON.parse(text);
|
||||||
|
} catch (e) {
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
if (isObjectValue(value)) {
|
};
|
||||||
return Object.keys(value).reduce((result, key) => {
|
|
||||||
|
const sanitizeValue = (value) => {
|
||||||
|
const parsedValue = parseJsonStringValue(value);
|
||||||
|
|
||||||
|
if (isArrayValue(parsedValue)) {
|
||||||
|
return parsedValue.map((item) => sanitizeValue(item));
|
||||||
|
}
|
||||||
|
if (isObjectValue(parsedValue)) {
|
||||||
|
return Object.keys(parsedValue).reduce((result, key) => {
|
||||||
if (IGNORED_FIELD_KEYS.includes(key)) return result;
|
if (IGNORED_FIELD_KEYS.includes(key)) return result;
|
||||||
result[key] = sanitizeValue(value[key]);
|
result[key] = sanitizeValue(parsedValue[key]);
|
||||||
return result;
|
return result;
|
||||||
}, {});
|
}, {});
|
||||||
}
|
}
|
||||||
return value;
|
return parsedValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasDisplayValue = (value) => {
|
const hasDisplayValue = (value) => {
|
||||||
@@ -79,10 +105,27 @@ const formatLeafValue = (value) => {
|
|||||||
return String(value);
|
return String(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isImageValue = (value) => {
|
||||||
|
return isObjectValue(value) && hasDisplayValue(value.image_id);
|
||||||
|
};
|
||||||
|
|
||||||
|
const createImageEntry = (key, value) => ({
|
||||||
|
key,
|
||||||
|
type: "image",
|
||||||
|
value: {
|
||||||
|
image_id: formatLeafValue(value.image_id).trim(),
|
||||||
|
caption: hasDisplayValue(value.caption) ? formatLeafValue(value.caption) : "",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const renderFieldEntries = computed(() => {
|
const renderFieldEntries = computed(() => {
|
||||||
if (isIgnoredField.value || !hasDisplayValue(props.value)) return [];
|
if (isIgnoredField.value || !hasDisplayValue(props.value)) return [];
|
||||||
|
|
||||||
const value = sanitizeValue(props.value);
|
const value = sanitizeValue(props.value);
|
||||||
|
if (isImageValue(value)) {
|
||||||
|
return [createImageEntry(props.fieldKey, value)];
|
||||||
|
}
|
||||||
|
|
||||||
if (isArrayValue(value)) {
|
if (isArrayValue(value)) {
|
||||||
return [{
|
return [{
|
||||||
key: props.fieldKey,
|
key: props.fieldKey,
|
||||||
@@ -96,6 +139,9 @@ const renderFieldEntries = computed(() => {
|
|||||||
.filter((key) => hasDisplayValue(value[key]))
|
.filter((key) => hasDisplayValue(value[key]))
|
||||||
.map((key) => {
|
.map((key) => {
|
||||||
const entryValue = value[key];
|
const entryValue = value[key];
|
||||||
|
if (isImageValue(entryValue)) {
|
||||||
|
return createImageEntry(key, entryValue);
|
||||||
|
}
|
||||||
if (isArrayValue(entryValue)) {
|
if (isArrayValue(entryValue)) {
|
||||||
return {
|
return {
|
||||||
key,
|
key,
|
||||||
@@ -120,6 +166,14 @@ const renderFieldEntries = computed(() => {
|
|||||||
|
|
||||||
const isIgnoredField = computed(() => IGNORED_FIELD_KEYS.includes(props.fieldKey));
|
const isIgnoredField = computed(() => IGNORED_FIELD_KEYS.includes(props.fieldKey));
|
||||||
const shouldRenderField = computed(() => renderFieldEntries.value.length > 0);
|
const shouldRenderField = computed(() => renderFieldEntries.value.length > 0);
|
||||||
|
|
||||||
|
const handlePreviewClick = (imageUrl) => {
|
||||||
|
uni.previewImage({
|
||||||
|
current: imageUrl,
|
||||||
|
urls: [imageUrl],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@@ -136,6 +190,26 @@ const shouldRenderField = computed(() => renderFieldEntries.value.length > 0);
|
|||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content-body-image-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-body-image {
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #f3f4f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-body-image-caption {
|
||||||
|
color: #6b7280;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
.content-body-list-card {
|
.content-body-list-card {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
Reference in New Issue
Block a user