diff --git a/common/js/form-platform-mixin.js b/common/js/form-platform-mixin.js index 4e229a3..ba4580a 100644 --- a/common/js/form-platform-mixin.js +++ b/common/js/form-platform-mixin.js @@ -37,8 +37,7 @@ export default { computed: { /** * 当前运行平台标识(与后端 formConfig.terminal 键名对齐) - * 后端在 formConfig.terminal 下挂的差异化配置键:h5 / weapp / mp-harmony / app - * 这里返回的 key 必须与后端设计器输出的 terminal 字段名一致 + * 后端 terminal 键:h5 / weapp / harmony / app / mp-alipay / mp-baidu / mp-toutiao */ platform() { // #ifdef H5 @@ -69,8 +68,8 @@ export default { }, /** * 后端键名 → 内部 platform 名 兼容层 - * 不同后端序列化路径可能用 mp-weixin / wechat / mp-harmony 等不同的 key, - * 在这里统一映射到内部 platform 名,避免 config() 里到处写 if/else。 + * canonical 与 platform() 返回值一致;别名为兼容 DB 旧 app_type(upgrade-to-ai-agent.sql) + * 及 uniapp / 设计器的历史命名。键名严格区分大小写。 */ platformAliases() { return { @@ -80,7 +79,15 @@ export default { 'wechat': 'weapp', 'harmony': 'harmony', 'app': 'app', - 'app-plus': 'app' + 'app-plus': 'app', + 'mp-alipay': 'mp-alipay', + 'aliapp': 'mp-alipay', + 'alipay': 'mp-alipay', + 'mp-baidu': 'mp-baidu', + 'baiduapp': 'mp-baidu', + 'baidu': 'mp-baidu', + 'mp-toutiao': 'mp-toutiao', + 'toutiao': 'mp-toutiao' }; }, /** diff --git a/common/js/goods_detail_base.js b/common/js/goods_detail_base.js index b37dc85..5600656 100644 --- a/common/js/goods_detail_base.js +++ b/common/js/goods_detail_base.js @@ -79,7 +79,7 @@ export default { }, methods: { // 处理商品详情数据 - handleGoodsSkuData() { + async handleGoodsSkuData() { // 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); @@ -186,7 +186,7 @@ export default { // this.getBarrageData(); if (this.addonIsExist.form) { - this.getGoodsForm(); + await this.getGoodsForm(); } }, /** @@ -321,17 +321,54 @@ export default { }, /** * 获取商品表单 + * 后端 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。 */ - getGoodsForm() { - this.$api.sendRequest({ + async getGoodsForm() { + const res = await this.$api.sendRequest({ url: "/form/api/form/goodsform", data: { goods_id: this.goodsSkuDetail.goods_id }, - success: res => { - if (res.code == 0 && res.data) this.$set(this.goodsSkuDetail, 'goods_form', res.data); - } + async: false }); + 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) + ); } }, /** diff --git a/common/js/util-navigate.js b/common/js/util-navigate.js index 025272f..017f1fd 100644 --- a/common/js/util-navigate.js +++ b/common/js/util-navigate.js @@ -701,13 +701,15 @@ export function _safeEncodeForPlatform(v) { // 微信小程序: split on '&' / '=' 解析 url,但不 decode value 给 onLoad。 // - 中文 / 字母 / 数字 → 原样保留(否则 onLoad 拿到 %xx 乱码) - // - `&` `=` `?` `#` 空格 → 必须 encode(否则 query 边界被破坏, src 等含 URL 的字段被截断) + // - `&` `=` `?` `#` 空格 → 必须 encode(否则 query 边界被破坏, src 等含 URL 的字段被截断,webview 打不开) if (platform === 'mp-weixin') { return _encodeUrlDelimiters(once); } - // 鸿蒙元服务: 整体 encode url(包括中文和已编码的 %xx)。 + // 鸿蒙元服务: uni.navigateTo 内部整体 encode url(把中文、& 等都 encode)。 // JS 侧完全不 encode,直接返回 decode roundtrip 后的原文,让鸿蒙原生做唯一一次 encode。 + // (再 encode 会双重编码 → onLoad 拿到 %E6%B2%99%E5%8F%91 乱码) + // webview URL 含 & 时, JS 不 encode,鸿蒙原生 encode 后 & 变 %26,webview 能正常打开。 if (platform === 'mp-harmony') { return once; } diff --git a/components-diy/diy-form.vue b/components-diy/diy-form.vue index 7e0caa7..b2c5d47 100644 --- a/components-diy/diy-form.vue +++ b/components-diy/diy-form.vue @@ -182,6 +182,9 @@ export default { labelColor: pick('labelColor', 'label_color'), requiredColor: pick('requiredColor', 'required_color'), checkedColor: pick('checkedColor', 'checked_color'), + // 占位符:遗漏会被 ns-newform SCSS 默认值回退覆盖 + placeholderColor: pick('placeholderColor', 'placeholder_color'), + placeholderFontSize: pick('placeholderFontSize', 'placeholder_font_size'), submitText: pick('submitText', 'submit_text'), submitColor: pick('submitColor', 'submit_color'), submitBgColor: pick('submitBgColor', 'submit_bg_color'), diff --git a/pages_goods/detail.vue b/pages_goods/detail.vue index 46335b0..7cf20c8 100644 --- a/pages_goods/detail.vue +++ b/pages_goods/detail.vue @@ -411,7 +411,12 @@ --> - + @@ -545,6 +550,21 @@ export default { nsGoodsPromotion }, mixins: [base, detail, scroll], + computed: { + // diy-form raw 模式 value:banner/tip 由独立列归一化后的 goods_form_* 提供, + // 与 formdata.vue 的 diyValue 同源;本页 :show-submit="false" 走外部"确定"按钮提交。 + formDiyValue() { + const sku = this.goodsSkuDetail || {}; + return { + jsonData: sku.goods_form || [], + formConfig: sku.goods_form_config || {}, + show_banner: sku.goods_form_show_banner === true, + form_banner: sku.goods_form_banner || '', + show_tip: sku.goods_form_show_tip === true, + form_tip: sku.goods_form_tip || '' + }; + } + }, methods: { /** * 发送商品信息到智能客服 diff --git a/pages_goods/public/js/detail.js b/pages_goods/public/js/detail.js index a04d65f..38ecf59 100644 --- a/pages_goods/public/js/detail.js +++ b/pages_goods/public/js/detail.js @@ -24,9 +24,10 @@ export default { membercard: null, // 会员卡信息 hackReset: true, - cardOff: false, - informationform:[]//留言表单 - + cardOff: false + // 留言表单数据不再在 data() 维护:detail.vue 的 computed formDiyValue + // 直接从 goodsSkuDetail.goods_form / goods_form_config / goods_form_* 实时读取并打包成 + // diy-form raw 模式期望的 value 结构。 } }, computed: { @@ -156,7 +157,7 @@ export default { }; // 处理商品数据 - this.handleGoodsSkuData(); + await this.handleGoodsSkuData(); // 限时折扣 if (this.goodsSkuDetail.promotion_type == 1 && this.addonIsExist.discount) { @@ -221,7 +222,6 @@ export default { //商品留言打开 showinformation(){ - this.informationform = this.goodsSkuDetail.goods_form this.$refs.informationPopup.open(); }, //商品留言关闭 @@ -230,18 +230,18 @@ export default { }, //保存商品留言 saveubfirnation(){ - //缺少 + // ref 指向 :diy-form 只暴露 getFormData() 方法,无 formData 属性 if (!this.$refs.form.verify()) return; - + // uni.setStorageSync('goodFormData', { // goods_id: this.goodsSkuDetail.goods_id, - // form_data: this.$refs.form.formData + // form_data: this.$refs.form.getFormData() // }); this.$api.sendRequest({ url: '/api/goods/information', data: { goods_id: this.goodsSkuDetail.goods_id, - form_data: JSON.stringify(this.$refs.form.formData) + form_data: JSON.stringify(this.$refs.form.getFormData()) }, success: res => { var data = res.data; diff --git a/tests/util-navigate.test.js b/tests/util-navigate.test.js index 99ac79a..5292ae0 100644 --- a/tests/util-navigate.test.js +++ b/tests/util-navigate.test.js @@ -240,8 +240,9 @@ test('_safeEncodeForPlatform: H5 / 华为快应用 → 主动 encode', () => { } }); -test('_safeEncodeForPlatform: 鸿蒙元服务 → JS 侧不做 encode', () => { - // 2026-07-17 修正(二次): 鸿蒙整体 encode url, JS 完全不 encode +test('_safeEncodeForPlatform: 鸿蒙元服务 → JS 侧不做 encode(让平台去做)', () => { + // 2026-07-17 修正: 鸿蒙整体 encode url, JS 完全不 encode + // (再 encode 会双重编码; webview src 含 & 时,鸿蒙原生 encode 会自动变 %26,webview 能正常打开) const nav = loadNavInSandbox(); const api = nav.createNavigateApi({ platform: 'mp-harmony' }); const r = api._safeEncodeForPlatform('a&b');