feat: 增加商品组件
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<view v-if="shouldRenderField" class="parsed-value">
|
||||
<image v-if="shouldRenderContentImage" class="content-body-image" :src="contentImageUrl"
|
||||
<image v-if="shouldRenderContentImage" class="content-body-image content-body-image-bottom" :src="contentImageUrl"
|
||||
mode="widthFix" @click="handlePreviewClick(contentImageUrl)" />
|
||||
|
||||
<template v-else-if="shouldRenderSpotLocate">
|
||||
@@ -26,6 +26,47 @@
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<template v-else-if="shouldRenderCommodityList">
|
||||
<view class="detail-action-zone">
|
||||
<view class="detail-action-label">相关票务</view>
|
||||
<scroll-view class="detail-product-scroll" scroll-x>
|
||||
<view class="detail-product-row">
|
||||
<view
|
||||
v-for="commodity in commodityItems"
|
||||
:key="commodity.commodity_id || commodity.commodity_name"
|
||||
class="detail-product-card"
|
||||
>
|
||||
<image
|
||||
v-if="commodity.commodity_photo"
|
||||
class="detail-product-image"
|
||||
:src="commodity.commodity_photo"
|
||||
mode="aspectFill"
|
||||
@click="handlePreviewClick(commodity.commodity_photo)"
|
||||
/>
|
||||
<view class="detail-product-body">
|
||||
<view v-if="commodity.commodity_tag" class="detail-product-tag">
|
||||
{{ commodity.commodity_tag }}
|
||||
</view>
|
||||
<view v-if="commodity.commodity_name" class="detail-product-name">
|
||||
{{ commodity.commodity_name }}
|
||||
</view>
|
||||
<view v-if="commodity.commodity_price" class="detail-product-price">
|
||||
<text class="detail-product-currency">¥</text>{{ commodity.commodity_price }}
|
||||
</view>
|
||||
<button
|
||||
v-if="commodity.commodity_id"
|
||||
class="detail-buy-button"
|
||||
@click.stop="openCommodityDetail(commodity)"
|
||||
>
|
||||
立即购买
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<template v-for="entry in renderFieldEntries" :key="entry.key">
|
||||
<view v-if="entry.type === 'text'" class="content-body-text">
|
||||
@@ -42,6 +83,9 @@
|
||||
|
||||
<view v-else-if="entry.type === 'list'" class="content-body-list-card" :style="contentBodyListCardStyle">
|
||||
<view v-for="(item, index) in entry.value" :key="index" class="content-body-list-item">
|
||||
<view v-if="entry.value.length > 1" class="content-body-list-marker" :style="contentBodyListTextStyle">
|
||||
{{ formatListMarker(index) }}
|
||||
</view>
|
||||
<view class="content-body-list-text" :style="contentBodyListTextStyle">
|
||||
{{ formatLeafValue(item) }}
|
||||
</view>
|
||||
@@ -104,6 +148,17 @@ const formatLeafValue = (value) => {
|
||||
return formatLongTextDisplayValue(value, IGNORED_FIELD_KEYS);
|
||||
};
|
||||
|
||||
const LIST_MARKERS = [
|
||||
"①", "②", "③", "④", "⑤",
|
||||
"⑥", "⑦", "⑧", "⑨", "⑩",
|
||||
"⑪", "⑫", "⑬", "⑭", "⑮",
|
||||
"⑯", "⑰", "⑱", "⑲", "⑳",
|
||||
];
|
||||
|
||||
const formatListMarker = (index) => {
|
||||
return LIST_MARKERS[index] || `${index + 1}.`;
|
||||
};
|
||||
|
||||
const toTrimmedText = (value) => {
|
||||
if (value === undefined || value === null) return "";
|
||||
return String(value).trim();
|
||||
@@ -131,9 +186,13 @@ const createImageEntry = (key, value) => ({
|
||||
|
||||
/// ======== Render Logic ========
|
||||
const isIgnoredField = computed(() => IGNORED_FIELD_KEYS.includes(props.fieldKey));
|
||||
const isContentImageField = computed(() => props.fieldKey === LONG_TEXT_KEYS.contentImage);
|
||||
const isContentImageField = computed(() =>
|
||||
props.fieldKey === LONG_TEXT_KEYS.contentImage ||
|
||||
props.fieldKey === LONG_TEXT_KEYS.sceneImage
|
||||
);
|
||||
const isSpotLocateField = computed(() => props.fieldKey === LONG_TEXT_KEYS.spotLocate);
|
||||
const isQuestionSuggestField = computed(() => props.fieldKey === LONG_TEXT_KEYS.questionSuggest);
|
||||
const isCommodityListField = computed(() => props.fieldKey === LONG_TEXT_KEYS.commodityList);
|
||||
|
||||
const displayValue = computed(() => sanitizeValue(props.value));
|
||||
|
||||
@@ -161,6 +220,21 @@ const questionSuggestItems = computed(() => {
|
||||
: [];
|
||||
});
|
||||
|
||||
const commodityItems = computed(() => {
|
||||
if (!isArrayValue(displayValue.value)) return [];
|
||||
|
||||
return displayValue.value
|
||||
.filter((item) => isObjectValue(item))
|
||||
.map((commodity) => ({
|
||||
commodity_id: toTrimmedText(commodity.commodity_id),
|
||||
commodity_name: toTrimmedText(commodity.commodity_name),
|
||||
commodity_price: toTrimmedText(commodity.commodity_price),
|
||||
commodity_tag: toTrimmedText(commodity.commodity_tag),
|
||||
commodity_photo: toTrimmedText(commodity.commodity_photo),
|
||||
}))
|
||||
.filter((commodity) => hasDisplayValue(commodity));
|
||||
});
|
||||
|
||||
const shouldRenderContentImage = computed(() => {
|
||||
return isContentImageField.value && !!contentImageUrl.value;
|
||||
});
|
||||
@@ -173,6 +247,10 @@ const shouldRenderQuestionSuggest = computed(() => {
|
||||
return isQuestionSuggestField.value && questionSuggestItems.value.length > 0;
|
||||
});
|
||||
|
||||
const shouldRenderCommodityList = computed(() => {
|
||||
return isCommodityListField.value && commodityItems.value.length > 0;
|
||||
});
|
||||
|
||||
/// 其他字段走通用渲染逻辑
|
||||
const renderFieldEntries = computed(() => {
|
||||
if (isIgnoredField.value || !hasDisplayValue(props.value)) return [];
|
||||
@@ -226,7 +304,8 @@ const shouldRenderField = computed(() => {
|
||||
if (
|
||||
shouldRenderContentImage.value ||
|
||||
shouldRenderSpotLocate.value ||
|
||||
shouldRenderQuestionSuggest.value
|
||||
shouldRenderQuestionSuggest.value ||
|
||||
shouldRenderCommodityList.value
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
@@ -265,6 +344,13 @@ const sendReply = (item) => {
|
||||
uni.$emit(SEND_MESSAGE_CONTENT_TEXT, item);
|
||||
};
|
||||
|
||||
const openCommodityDetail = (commodity) => {
|
||||
if (!commodity.commodity_id) return;
|
||||
uni.navigateTo({
|
||||
url: `/pages/goods/index?commodityId=${commodity.commodity_id}`,
|
||||
});
|
||||
};
|
||||
|
||||
const handlePreviewClick = (imageUrl) => {
|
||||
uni.previewImage({
|
||||
current: imageUrl,
|
||||
|
||||
Reference in New Issue
Block a user