Files
lucky_shop/common/js/goods_detail_base.js
ZF sun d605f4c9ea feat(goods-detail): 商品详情页主图/视频按后台「媒体显示顺序」切换
后台商品「高级设置」新增 media_order(1=主图在前 2=视频在前), 前端按其决定
商品详情页媒体区默认展示哪一个, 以及底部「图片/视频」切换按钮的排列顺序.

改动:
- goods-detail-view 组件:
  - 新增 applyMediaOrder() 按 media_order 决定默认展示主图还是视频
  - 新增 mediaOrderKey 计算属性 + watcher: 只在「媒体显示顺序/视频地址」
    变化时重新应用, 避免用户手动切到「视频」后被详情数据深层变更打回
  - 新增 mediaTabs 计算属性: 切换按钮顺序跟随配置
  - 切换按钮改用 switchMediaTab(), 切回主图时暂停视频
- common/js/goods_detail_base.js: 父级那行 switchMedia 赋值原本是死代码
  (父级无此 data 字段, 无模板读取), 改成与新规则一致, 避免两处规则打架
2026-10-21 16:35:47 +08:00

447 lines
15 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 商品详情业务
import htmlParser from '@/common/js/html-parser';
export default {
data() {
return {
skuId: 0,
goodsId: 0,
// 商品详情
goodsSkuDetail: {
goods_id: 0,
goods_service: []
},
preview: 0, //是否开启预览,0:不开启,1:开启
//评价
contactData: {
title: '',
path: '',
img: ''
},
shareQuery: '', // 分享参数
shareUrl: '', // 分享链接
source_member: 0, //分享人的id
chatRoomParams: {}, // 联系客服参数
isIphoneX: false, //判断手机是否是iphoneX以上
whetherCollection: 0,
posterParams: {}, //海报所需参数
shareImg: '',
navbarData: {
title: '',
topNavColor: "#ffffff",
topNavBg: false,
navBarSwitch: true, // 导航栏是否显示
textNavColor: "#333333",
moreLink: {
name: ""
},
navStyle: 1,
bgUrl: '',
textImgPosLink: 'left'
},
}
},
onLoad(data) {
//刷新多语言
this.$langConfig.refresh();
// #ifdef MP-ALIPAY
let options = my.getLaunchOptionsSync();
options.query && Object.assign(data, options.query);
// #endif
this.preview = data.preview || 0;
this.isIphoneX = this.$util.uniappIsIPhoneX();
if (data.source_member) {
uni.setStorageSync('source_member', data.source_member);
this.source_member = data.source_member;
}
//记录分享关系
if (this.storeToken && uni.getStorageSync('source_member')) {
this.$util.onSourceMember(uni.getStorageSync('source_member'));
}
// 小程序扫码进入
if (data.scene) {
var sceneParams = decodeURIComponent(data.scene);
sceneParams = sceneParams.split('&');
if (sceneParams.length) {
sceneParams.forEach(item => {
if (item.indexOf('m') != -1) uni.setStorageSync('source_member', item.split('-')[1]);
if (item.indexOf('is_test') != -1) uni.setStorageSync('is_test', 1);
});
}
}
},
onShow() {
},
methods: {
// 处理商品详情数据
async handleGoodsSkuData() {
// 鸿蒙兼容: 外层包 try/catch, 任何同步抛错都不会导致 page 整体空白
try {
if (this.goodsSkuDetail.config) {
this.navbarData.navBarSwitch = this.goodsSkuDetail.config.nav_bar_switch;
}
this.whetherCollection = this.goodsSkuDetail.is_collect; // 用户关注商品状态
this.modifyGoodsInfo();
// 初始化商品详情视图数据
try {
if (this.$refs && this.$refs.goodsDetailView) {
this.$refs.goodsDetailView.init({
sku_id: this.skuId,
goods_id: this.goodsSkuDetail.goods_id,
preview: this.preview,
source_member: this.source_member,
posterParams: this.posterParams,
posterApi: this.posterApi,
shareUrl: this.shareUrl,
goodsRoute: this.goodsRoute,
isVirtual: this.goodsSkuDetail.is_virtual,
deliveryType: this.goodsSkuDetail.express_type,
whetherCollection: this.goodsSkuDetail.is_collect,
evaluateConfig: this.goodsSkuDetail.evaluate_config,
evaluateList: this.goodsSkuDetail.evaluate_list,
evaluateCount: this.goodsSkuDetail.evaluate_count
});
}
} catch (e) {
console.error('goodsDetailView.init failed:', e);
}
//媒体
// 媒体显示顺序以后台商品「高级设置 → 媒体显示顺序」media_order 为准
// (1=主图在前 2=视频在前); 真正渲染媒体区的是 goods-detail-view 组件,
// 组件内部按同一规则切换, 这里保持一致避免两处规则打架
if (this.goodsSkuDetail.video_url) {
this.switchMedia = (Number(this.goodsSkuDetail.media_order) === 2) ? "video" : "img";
}
if (!Array.isArray(this.goodsSkuDetail.sku_images)) {
if (this.goodsSkuDetail.sku_images) this.goodsSkuDetail.sku_images = this.goodsSkuDetail.sku_images.split(",");
else this.goodsSkuDetail.sku_images = [];
}
// 多规格时合并主图
if (this.goodsSkuDetail.goods_spec_format && this.goodsSkuDetail.goods_image) {
if (!Array.isArray(this.goodsSkuDetail.goods_image)) this.goodsSkuDetail.goods_image = this.goodsSkuDetail.goods_image.split(",");
this.goodsSkuDetail.sku_images = this.goodsSkuDetail.goods_image.concat(this.goodsSkuDetail.sku_images);
}
let maxHeight = '';
let systemInfo = uni.getSystemInfoSync();
this.goodsSkuDetail.goods_image_list.forEach((item, index) => {
if (typeof item.pic_spec == "string")
item.pic_spec = item.pic_spec.split('*');
let ratio = item.pic_spec[0] / systemInfo.windowWidth;
item.pic_spec[0] = item.pic_spec[0] / ratio;
item.pic_spec[1] = item.pic_spec[1] / ratio;
if (!maxHeight || maxHeight > item.pic_spec[1]) {
maxHeight = item.pic_spec[1];
}
});
this.goodsSkuDetail.swiperHeight = maxHeight + 'px';
this.goodsSkuDetail.unit = this.goodsSkuDetail.unit || this.$lang('unit.piece');
// 当前商品SKU规格
if (this.goodsSkuDetail.sku_spec_format) this.goodsSkuDetail.sku_spec_format = JSON.parse(this.goodsSkuDetail.sku_spec_format);
// 商品属性
if (this.goodsSkuDetail.goods_attr_format) {
let goods_attr_format = JSON.parse(this.goodsSkuDetail.goods_attr_format);
this.goodsSkuDetail.goods_attr_format = this.$util.unique(goods_attr_format, "attr_id");
for (var i = 0; i < this.goodsSkuDetail.goods_attr_format.length; i++) {
for (var j = 0; j < goods_attr_format.length; j++) {
if (this.goodsSkuDetail.goods_attr_format[i].attr_id == goods_attr_format[j].attr_id && this.goodsSkuDetail.goods_attr_format[i].attr_value_id != goods_attr_format[j].attr_value_id) {
this.goodsSkuDetail.goods_attr_format[i].attr_value_name += "、" + goods_attr_format[j].attr_value_name;
}
}
}
}
// 商品SKU格式
if (this.goodsSkuDetail.goods_spec_format) this.goodsSkuDetail.goods_spec_format = JSON.parse(this.goodsSkuDetail.goods_spec_format);
// 商品详情
if (this.goodsSkuDetail.goods_content) this.goodsSkuDetail.goods_content = (this.goodsSkuDetail.goods_content);
// if (this.goodsSkuDetail.goods_content) this.goodsSkuDetail.goods_content = htmlParser(this.goodsSkuDetail.goods_content);
//商品服务
if (this.goodsSkuDetail.goods_service) {
for (let i in this.goodsSkuDetail.goods_service) {
this.goodsSkuDetail.goods_service[i]['icon'] = this.goodsSkuDetail.goods_service[i]['icon'] ? JSON.parse(this.goodsSkuDetail.goods_service[i]['icon']) : '';
}
}
this.contactData = {
title: this.goodsSkuDetail.sku_name,
path: this.shareUrl,
img: this.$util.img(this.goodsSkuDetail.sku_image, {
size: 'big'
})
};
try {
if (this.$refs && this.$refs.goodsPromotion) {
this.$refs.goodsPromotion.refresh(this.goodsSkuDetail.goods_promotion);
}
} catch (e) { console.error('goodsPromotion refresh failed:', e); }
// 性能优化: 商品表单(留言表单)仅在商品详情打开"立即留言"弹窗时才需要,
// 不再阻塞首次渲染。改为在后台并发请求, 用户真正打开弹窗时数据已就绪。
try {
this._goodsFormPromise = this.getGoodsForm();
} catch (e) {
console.error('getGoodsForm kicked off failed:', e);
}
} catch (e) {
console.error('handleGoodsSkuData failed:', e);
}
},
/**
* 刷新商品详情数据
* @param {Object} data
*/
refreshGoodsSkuDetail(data) {
this.goodsSkuDetail = Object.assign({}, this.goodsSkuDetail, data);
if (this.$refs.goodsPromotion) this.$refs.goodsPromotion.refresh(this.goodsSkuDetail.goods_promotion);
if (this.$refs.goodsDetailView) {
// 初始化商品详情视图数据
this.goodsSkuDetail.unit = this.goodsSkuDetail.unit || this.$lang('unit.piece');
// 解决轮播图数量不一致时,切换到第一个
if (this.swiperCurrent > this.goodsSkuDetail.sku_images.length) {
this.swiperAutoplay = true;
this.swiperCurrent = 1;
setTimeout(() => {
this.swiperAutoplay = false;
}, 40);
}
}
this.navbarData.title = this.goodsSkuDetail.goods_name.length > 9 ? this.goodsSkuDetail.goods_name.substr(0, 9) + "..." : this.goodsSkuDetail.goods_name;
this.$langConfig.title(this.navbarData.title);
if (this.goodsSkuDetail.membercard) {
this.membercard = this.goodsSkuDetail.membercard;
}
},
goodsDetailViewInit() {
// 初始化商品详情视图数据
if (this.$refs.goodsDetailView) this.$refs.goodsDetailView.init({
sku_id: this.skuId,
goods_id: this.goodsSkuDetail.goods_id,
preview: this.preview,
source_member: this.source_member,
posterParams: this.posterParams,
posterApi: this.posterApi,
shareUrl: this.shareUrl,
goodsRoute: this.goodsRoute,
isVirtual: this.goodsSkuDetail.is_virtual,
deliveryType: this.goodsSkuDetail.express_type,
whetherCollection: this.goodsSkuDetail.is_collect,
evaluateConfig: this.goodsSkuDetail.evaluate_config,
evaluateList: this.goodsSkuDetail.evaluate_list,
evaluateCount: this.goodsSkuDetail.evaluate_count
});
},
goHome() {
if (this.preview) return; // 开启预览,禁止任何操作和跳转
this.$util.redirectTo(this.$util.INDEX_PAGE_URL);
},
goCart() {
if (this.preview) return; // 开启预览,禁止任何操作和跳转
this.$util.redirectTo('/pages_goods/cart');
},
//-------------------------------------关注-------------------------------------
//更新商品信息
modifyGoodsInfo() {
if (this.preview) return; // 开启预览,禁止任何操作和跳转
//更新商品点击量
this.$api.sendRequest({
url: "/api/goods/modifyclicks",
data: {
sku_id: this.skuId
},
success: res => {
}
});
//添加足迹
this.$api.sendRequest({
url: "/api/goodsbrowse/add",
data: {
goods_id: this.goodsSkuDetail.goods_id,
sku_id: this.skuId
},
success: res => {
}
});
},
//-------------------------------------关注-------------------------------------
async editCollection() {
if (this.$refs.goodsDetailView) {
this.whetherCollection = await this.$refs.goodsDetailView.collection();
}
},
openSharePopup() {
if (this.$refs.goodsDetailView) {
this.$refs.goodsDetailView.openSharePopup();
}
},
//弹幕
getBarrageData() {
this.$api.sendRequest({
url: '/api/goods/goodsbarrage',
data: {
goods_id: this.goodsSkuDetail.goods_id
},
success: res => {
if (res.code == 0 && res.data) {
let barrageData = [];
for (let i in res.data.list) {
if (res.data.list[i]['title']) {
let title = res.data.list[i]['title'].substr(0, 1) + '*' + res.data.list[i]['title'].substr(res.data.list[i]['title'].length - 1, 1)
barrageData.push({
img: res.data.list[i]['img'] ? res.data.list[i]['img'] : this.$util.getDefaultImage().head,
title: title + '已下单'
});
}
}
this.goodsSkuDetail.barrageData = barrageData;
}
}
});
},
/**
* 设置公众号分享
*/
setPublicShare() {
let shareUrl = this.$config.h5Domain + this.shareUrl;
if (this.memberInfo && this.memberInfo.member_id) shareUrl += '&source_member=' + this.memberInfo.member_id;
this.$util.setPublicShare({
title: this.goodsSkuDetail.goods_name,
desc: '',
link: shareUrl,
imgUrl: typeof this.goodsSkuDetail.goods_image == 'object' ? this.goodsSkuDetail.goods_image[0] : this.goodsSkuDetail.goods_image.split(',')[0]
})
},
/**
* 获取商品表单
* 后端 goodsform 接口与 info() 对齐,返回 {json_data, form_config(camelCase),
* form_name, form_tip, form_banner, show_banner, show_tip}。
* 全部字段都落到 goodsSkuDetail 上:表单字段 / 样式 / banner / tip 元数据,
* 给 detail.vue 的 diy-form 直接消费。所有分支都做兜底初始化,避免下游拿到 undefined。
*/
async getGoodsForm() {
// 防御: sku 切换/数据未到时 goods_id 可能为 0/空, 此时直接走空数据分支,
// 避免后端拿到非法 goods_id 导致 4xx/5xx 后还把脏数据塞给前端。
if (!this.goodsSkuDetail || !this.goodsSkuDetail.goods_id) {
const emptyFn = () => {
this.$set(this.goodsSkuDetail, 'goods_form', []);
this.$set(this.goodsSkuDetail, 'goods_form_config', {});
this.$set(this.goodsSkuDetail, 'goods_form_name', '');
this.$set(this.goodsSkuDetail, 'goods_form_tip', '');
this.$set(this.goodsSkuDetail, 'goods_form_banner', '');
this.$set(this.goodsSkuDetail, 'goods_form_show_banner', false);
this.$set(this.goodsSkuDetail, 'goods_form_show_tip', false);
};
emptyFn();
return;
}
let res;
try {
res = await this.$api.sendRequest({
url: "/form/api/form/goodsform",
data: {
goods_id: this.goodsSkuDetail.goods_id,
format: 'object'
},
async: false
});
} catch (e) {
console.warn('getGoodsForm request failed', e);
res = null;
}
const empty = () => {
this.$set(this.goodsSkuDetail, 'goods_form', []);
this.$set(this.goodsSkuDetail, 'goods_form_config', {});
this.$set(this.goodsSkuDetail, 'goods_form_name', '');
this.$set(this.goodsSkuDetail, 'goods_form_tip', '');
this.$set(this.goodsSkuDetail, 'goods_form_banner', '');
this.$set(this.goodsSkuDetail, 'goods_form_show_banner', false);
this.$set(this.goodsSkuDetail, 'goods_form_show_tip', false);
};
if (!res || res.code != 0 || !res.data) {
empty();
return;
}
if (Array.isArray(res.data)) {
// 旧版扁平数组兼容
empty();
this.$set(this.goodsSkuDetail, 'goods_form', res.data);
return;
}
this.$set(this.goodsSkuDetail, 'goods_form', res.data.json_data || []);
this.$set(this.goodsSkuDetail, 'goods_form_config', res.data.form_config || {});
this.$set(this.goodsSkuDetail, 'goods_form_name', res.data.form_name || '');
this.$set(this.goodsSkuDetail, 'goods_form_tip', res.data.form_tip || '');
this.$set(this.goodsSkuDetail, 'goods_form_banner', res.data.form_banner || '');
// show_banner/show_tip 后端存 0/1,归一化 boolean
this.$set(
this.goodsSkuDetail,
'goods_form_show_banner',
res.data.show_banner == 1 ? true : (res.data.show_banner === 0 ? false : true)
);
this.$set(
this.goodsSkuDetail,
'goods_form_show_tip',
res.data.show_tip == 1 ? true : (res.data.show_tip === 0 ? false : true)
);
}
},
/**
* 自定义分享内容
* @param {Object} res
*/
onShareAppMessage(res) {
var path = this.shareUrl;
if (this.memberInfo && this.memberInfo.member_id) path += '&source_member=' + this.memberInfo.member_id;
return {
title: this.goodsSkuDetail.sku_name,
imageUrl: this.shareImg ? this.$util.img(this.shareImg) : this.$util.img(this.goodsSkuDetail.sku_image, {
size: 'big'
}),
path: path,
success: res => {
},
fail: res => {
}
};
},
// 分享到微信朋友圈
// #ifdef MP-WEIXIN
onShareTimeline() {
let query = this.shareQuery;
if (this.memberInfo && this.memberInfo.member_id) query += '&source_member=' + this.memberInfo.member_id;
return {
title: this.goodsSkuDetail.sku_name,
query: query,
imageUrl: this.$util.img(this.goodsSkuDetail.sku_image, {
size: 'big'
})
};
}
// #endif
}