mirror of
https://github.com/crmeb/CRMEB.git
synced 2026-10-28 13:31:04 +00:00
fix(订单详情): 自定义表单图片字段按类型回显并支持点击预览
This commit is contained in:
parent
ec156de42c
commit
f19125f7ae
@ -1365,15 +1365,19 @@ class CenterOrderController
|
||||
$detailExtend = $handler->getDetailExtend($productId);
|
||||
$productCustomForm = $detailExtend['custom_form'] ?? [];
|
||||
$fieldTitleMap = [];
|
||||
$fieldTypeMap = [];
|
||||
// 循环变量不得使用 $key:外层 $key 是订单确认缓存凭证,覆盖后 consumeOrderCache 会因类型错误崩溃
|
||||
foreach ($productCustomForm as $fieldKey => $fieldItem) {
|
||||
$fieldTitleMap['custom_field_' . $fieldKey] = $fieldItem['title'] ?? ('自定义字段' . ($fieldKey + 1));
|
||||
// 记录字段类型(管理端类型值 text/number/data/time/img 等),订单回显按类型渲染(图片字段展示缩略图)
|
||||
$fieldTypeMap['custom_field_' . $fieldKey] = $fieldItem['label'] ?? '';
|
||||
}
|
||||
$structured = [];
|
||||
foreach ($submittedCustomForm as $field => $value) {
|
||||
$structured[] = [
|
||||
'label' => $field,
|
||||
'title' => $fieldTitleMap[$field] ?? $field,
|
||||
'type' => $fieldTypeMap[$field] ?? '',
|
||||
'value' => $value,
|
||||
];
|
||||
}
|
||||
|
||||
@ -211,13 +211,13 @@
|
||||
<div class="section" v-if="data.custom_form && data.custom_form.length">
|
||||
<div class="title">表单信息</div>
|
||||
<ul class="list">
|
||||
<li class="item" :class="{ pic: item.label == 'img' }" v-for="(item, index) in data.custom_form" :key="index">
|
||||
<template v-if="item.label !== 'img'">
|
||||
<li class="item" :class="{ pic: isImageItem(item) }" v-for="(item, index) in data.custom_form" :key="index">
|
||||
<template v-if="!isImageItem(item)">
|
||||
<div>{{ item.title }}:{{ item.value }}</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div>{{ item.title }}:</div>
|
||||
<div v-for="(img, i) in item.value" :key="i" class="img">
|
||||
<div v-for="(img, i) in formImageUrls(item)" :key="i" class="img">
|
||||
<img v-viewer :src="img" alt="" />
|
||||
</div>
|
||||
</template>
|
||||
@ -288,6 +288,28 @@ function buildAddress(addr) {
|
||||
if (addr.postal_code) parts.push(`(${addr.postal_code})`);
|
||||
return parts.join('');
|
||||
}
|
||||
|
||||
// 图片扩展名判断
|
||||
const IMAGE_EXT_RE = /\.(jpe?g|png|gif|webp|bmp)(\?.*)?$/i;
|
||||
|
||||
/** 自定义表单字段值规范化为图片 URL 数组(兼容字符串单图 / 数组多图) */
|
||||
function formImageUrls(item) {
|
||||
if (!item || !item.value) return [];
|
||||
const list = Array.isArray(item.value) ? item.value : [item.value];
|
||||
return list.filter((v) => typeof v === 'string' && v.indexOf('http') === 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 图片字段判断:新订单 type=img,或存量订单无类型但值是图片链接
|
||||
* (新数据 label 是 custom_field_N,不能再按 label == 'img' 判断)
|
||||
*/
|
||||
function isImageItem(item) {
|
||||
if (!item) return false;
|
||||
if (item.type === 'img') return true;
|
||||
if (item.type) return false;
|
||||
const urls = formImageUrls(item);
|
||||
return urls.length > 0 && urls.every((v) => IMAGE_EXT_RE.test(v) || v.indexOf('/uploads/') !== -1);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@ -6,14 +6,27 @@
|
||||
<template>
|
||||
<view class="info-card custom-form-card" v-if="items && items.length > 0">
|
||||
<view class="card-title">{{ $t('自定义信息') }}</view>
|
||||
<view
|
||||
class="info-row acea-row row-between"
|
||||
v-for="(item, idx) in items"
|
||||
:key="idx"
|
||||
>
|
||||
<text class="info-label">{{ item.title || item.label }}:</text>
|
||||
<text class="info-value">{{ item.value }}</text>
|
||||
</view>
|
||||
<template v-for="(item, idx) in items" :key="idx">
|
||||
<!-- 图片字段:类型为 img,或存量订单无类型但值是图片链接 -->
|
||||
<view class="info-row info-row--block" v-if="isImageItem(item)">
|
||||
<view class="info-label">{{ item.title || item.label }}:</view>
|
||||
<view class="info-images">
|
||||
<image
|
||||
v-for="(url, i) in imageList(item)"
|
||||
:key="i"
|
||||
class="info-image"
|
||||
:src="url"
|
||||
mode="aspectFill"
|
||||
@click="previewImages(item, i)"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 文本字段:值跟随标签左对齐,长文本自动换行 -->
|
||||
<view class="info-row" v-else>
|
||||
<text class="info-label">{{ item.title || item.label }}:</text>
|
||||
<text class="info-value">{{ item.value }}</text>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@ -21,7 +34,7 @@
|
||||
/**
|
||||
* 自定义表单回显组件
|
||||
* 展示用户下单时填写的自定义字段
|
||||
* 字段结构:{title/label, value}
|
||||
* 字段结构:{title/label, type, value};type=img 为图片字段(存量订单无 type,按图片链接特征兜底)
|
||||
* 通过 componentKey='custom_form' 匹配 section.component
|
||||
*/
|
||||
export default {
|
||||
@ -45,12 +58,50 @@ const p = computed(() => (props.section && props.section.props) || {});
|
||||
const ctx = computed(() => (props.section && props.section._ctx) || {});
|
||||
/** 表单字段数组(后端下发在 section.props.items) */
|
||||
const items = computed(() => p.value.items || []);
|
||||
|
||||
/** 图片扩展名判断 */
|
||||
var IMAGE_EXT_RE = /\.(jpe?g|png|gif|webp|bmp)(\?.*)?$/i;
|
||||
|
||||
/** 规范化字段值为图片 URL 数组(字符串 / 数组均可) */
|
||||
function toUrlList(value) {
|
||||
if (!value) return [];
|
||||
var list = Array.isArray(value) ? value : [value];
|
||||
return list.filter(function (v) {
|
||||
return typeof v === 'string' && v.indexOf('http') === 0;
|
||||
});
|
||||
}
|
||||
|
||||
/** 是否图片字段:显式 type=img,或存量订单无类型但值为图片链接 */
|
||||
function isImageItem(item) {
|
||||
if (item.type === 'img') return true;
|
||||
if (item.type) return false;
|
||||
var urls = toUrlList(item.value);
|
||||
return urls.length > 0 && urls.every(function (v) {
|
||||
return IMAGE_EXT_RE.test(v) || v.indexOf('/uploads/') !== -1;
|
||||
});
|
||||
}
|
||||
|
||||
/** 图片字段的可展示 URL 列表 */
|
||||
function imageList(item) {
|
||||
return toUrlList(item.value);
|
||||
}
|
||||
|
||||
/** 点击预览大图 */
|
||||
function previewImages(item, index) {
|
||||
var urls = imageList(item);
|
||||
if (!urls.length) return;
|
||||
uni.previewImage({ urls: urls, current: index });
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.custom-form-card { margin: 20rpx; background: #fff; border-radius: 16rpx; padding: 30rpx; }
|
||||
.card-title { font-size: 30rpx; font-weight: bold; color: #333; margin-bottom: 20rpx; }
|
||||
.info-row { display: flex; justify-content: space-between; align-items: center; padding: 12rpx 0; font-size: 26rpx; }
|
||||
.info-row { display: flex; align-items: baseline; padding: 12rpx 0; font-size: 26rpx; }
|
||||
.info-label { color: #999; flex-shrink: 0; }
|
||||
.info-value { color: #333; text-align: right; }
|
||||
.info-value { color: #333; flex: 1; margin-left: 16rpx; line-height: 1.5; word-break: break-all; text-align: left; }
|
||||
/* 图片字段:标签在上、图片缩略图在下 */
|
||||
.info-row--block { display: block; padding: 12rpx 0; }
|
||||
.info-images { display: flex; flex-wrap: wrap; margin-top: 12rpx; }
|
||||
.info-image { width: 160rpx; height: 160rpx; border-radius: 12rpx; margin: 0 12rpx 12rpx 0; background: #f5f5f5; }
|
||||
</style>
|
||||
|
||||
@ -338,14 +338,17 @@
|
||||
</view>
|
||||
<view class="wrapper" v-if="customForm && customForm.length">
|
||||
<view class="item acea-row row-between" v-for="(item, index) in customForm" :key="index">
|
||||
<view class="upload" v-if="item.label == 'img'">
|
||||
<!-- 图片字段:新格式 type=img,或存量订单无类型但值是图片链接 -->
|
||||
<view class="upload" v-if="isImageFormItem(item)">
|
||||
<view class="diy-from-title">{{ item.title }}:</view>
|
||||
<view class="pictrue" v-for="(img, index) in item.value" :key="index">
|
||||
<image :src="img"></image>
|
||||
<view class="pictrue" v-for="(img, imgIndex) in formImageUrls(item)" :key="imgIndex">
|
||||
<image :src="img" @click="previewFormImages(item, imgIndex)"></image>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="item.label !== 'img'" class="diy-from-title">{{ item.title }}:</view>
|
||||
<view v-if="item.label !== 'img'" class="conter">{{ item.value }}</view>
|
||||
<template v-else>
|
||||
<view class="diy-from-title">{{ item.title }}:</view>
|
||||
<view class="conter">{{ item.value }}</view>
|
||||
</template>
|
||||
</view>
|
||||
<view class="copy-text" @click="copyText()">{{ $t(`复制`) }}</view>
|
||||
</view>
|
||||
@ -607,6 +610,30 @@ const { isLogin } = storeToRefs(appStore);
|
||||
// ---------- data ----------
|
||||
const imgHost = HTTP_REQUEST_URL;
|
||||
const customForm = ref(''); //自定义留言
|
||||
|
||||
/**
|
||||
* 自定义表单图片字段判断:新格式 type=img,或存量订单无类型但值是图片链接
|
||||
* (旧数据 label 存类型值,新数据 label 是 custom_field_N,不能再用 label 判断)
|
||||
*/
|
||||
const IMAGE_EXT_RE = /\.(jpe?g|png|gif|webp|bmp)(\?.*)?$/i;
|
||||
function formImageUrls(item) {
|
||||
if (!item || !item.value) return [];
|
||||
const list = Array.isArray(item.value) ? item.value : [item.value];
|
||||
return list.filter((v) => typeof v === 'string' && v.indexOf('http') === 0);
|
||||
}
|
||||
function isImageFormItem(item) {
|
||||
if (!item) return false;
|
||||
if (item.type === 'img') return true;
|
||||
if (item.type) return false;
|
||||
const urls = formImageUrls(item);
|
||||
return urls.length > 0 && urls.every((v) => IMAGE_EXT_RE.test(v) || v.indexOf('/uploads/') !== -1);
|
||||
}
|
||||
function previewFormImages(item, index) {
|
||||
const urls = formImageUrls(item);
|
||||
if (!urls.length) return;
|
||||
uni.previewImage({ urls, current: index });
|
||||
}
|
||||
|
||||
//二维码参数
|
||||
const codeShow = ref(false);
|
||||
const cid = ref('1');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user