diff --git a/shopxo/app/plugins/vr_ticket/config.json b/shopxo/app/plugins/vr_ticket/config.json index b611c83..e441d22 100644 --- a/shopxo/app/plugins/vr_ticket/config.json +++ b/shopxo/app/plugins/vr_ticket/config.json @@ -47,6 +47,9 @@ "plugins_service_goods_save_thing_end": [ "app\\plugins\\vr_ticket\\hook\\AdminGoodsSaveHandle" ], + "plugins_service_goods_base_forbid_operate_data": [ + "app\\plugins\\vr_ticket\\hook\\AdminGoodsSaveForbid" + ], "plugins_css_data": [ "app\\plugins\\vr_ticket\\hook\\ViewGoodsCss" ], diff --git a/shopxo/app/plugins/vr_ticket/hook/AdminGoodsSave.php b/shopxo/app/plugins/vr_ticket/hook/AdminGoodsSave.php index fd2d314..157111e 100644 --- a/shopxo/app/plugins/vr_ticket/hook/AdminGoodsSave.php +++ b/shopxo/app/plugins/vr_ticket/hook/AdminGoodsSave.php @@ -360,6 +360,50 @@ class AdminGoodsSave } }; + // ── 商品类型 site_type 锁定控制(票务商品专用) ── + // 票务商品的结算/拆单/加购流程强依赖"虚拟"商品类型(value=3)。 + // · isTicket=true → 强制 site_type=3(虚拟),并 disabled 该 select + // · isTicket=false → 恢复可选,但不修改当前值(保留用户上次选择) + // 注:解除 disabled 时仅移除本插件添加的标记,避免破坏其他钩子的禁用控制 + const SITE_TYPE_VIRTUAL_VALUE = 3; // 商品类型 = 虚拟 + const syncSiteTypeLock = (locked) => { + const select = document.querySelector('select[name="site_type"]'); + if (!select) return; + + if (locked) { + // 强制选中"虚拟" + select.value = String(SITE_TYPE_VIRTUAL_VALUE); + // 标记并禁用(仅在尚未禁用时操作,避免覆盖其他钩子的禁用) + if (!select.hasAttribute('data-vr-ticket-locked')) { + select.setAttribute('data-vr-ticket-locked', '1'); + // 记录原始 disabled 状态以便恢复 + if (select.hasAttribute('disabled')) { + select.setAttribute('data-vr-ticket-prev-disabled', '1'); + } else { + select.removeAttribute('data-vr-ticket-prev-disabled'); + } + select.setAttribute('disabled', 'disabled'); + } + // 触发 chosen 更新以反映新选中项 + if (window.$ && $.fn.chosen && $(select).data('chosen')) { + $(select).trigger('chosen:updated'); + } + } else { + // 解除禁用(仅解除本插件添加的) + if (select.getAttribute('data-vr-ticket-locked') === '1') { + select.removeAttribute('data-vr-ticket-locked'); + if (!select.hasAttribute('data-vr-ticket-prev-disabled')) { + select.removeAttribute('disabled'); + } else { + select.removeAttribute('data-vr-ticket-prev-disabled'); + } + } + if (window.$ && $.fn.chosen && $(select).data('chosen')) { + $(select).trigger('chosen:updated'); + } + } + }; + // ── 原生字段强制必填控制(票务商品专用) ── // 当 isTicket 勾选时:强制 batch_number_expire、coding、produce_region 为必填 // 当 isTicket 取消时:恢复原始状态(仅移除插件添加的 required) @@ -483,6 +527,8 @@ class AdminGoodsSave watch(isTicket, (val) => { applyTicketRequired(val); + // 票务商品时锁定 site_type 为"虚拟";取消时解锁 + syncSiteTypeLock(val); if (val) { // 票务商品模式:替换城市下拉选项 replaceCityOptions(); diff --git a/shopxo/app/plugins/vr_ticket/hook/AdminGoodsSaveForbid.php b/shopxo/app/plugins/vr_ticket/hook/AdminGoodsSaveForbid.php new file mode 100644 index 0000000..d2aab05 --- /dev/null +++ b/shopxo/app/plugins/vr_ticket/hook/AdminGoodsSaveForbid.php @@ -0,0 +1,66 @@ + 0) { + // 编辑场景下若 goods 未传完整,回查数据库(防御性兜底) + $itemType = Db::name('Goods')->where('id', $goodsId)->value('item_type'); + $isTicket = ($itemType === 'ticket'); + } + + // 票务商品 → 禁用 site_type(商品类型),强制锁定为"虚拟" + if ($isTicket && !in_array('site_type', $data, true)) { + $data[] = 'site_type'; + } + } +} diff --git a/shopxo/app/plugins/vr_ticket/hook/AdminGoodsSaveHandle.php b/shopxo/app/plugins/vr_ticket/hook/AdminGoodsSaveHandle.php index f83db49..a9b3798 100644 --- a/shopxo/app/plugins/vr_ticket/hook/AdminGoodsSaveHandle.php +++ b/shopxo/app/plugins/vr_ticket/hook/AdminGoodsSaveHandle.php @@ -26,6 +26,12 @@ class AdminGoodsSaveHandle $params['data']['item_type'] = 'ticket'; $params['data']['is_exist_many_spec'] = 1; + // ── 服务端强制锁定 site_type ── + // 票务商品的结算/拆单/加购流程强依赖"虚拟"商品类型(value=3)。 + // 即使前端绕过 disabled 控件或被恶意构造请求提交其他值, + // 这里也强制覆盖为 3,确保数据完整性。 + $params['data']['site_type'] = 3; + $base64Config = $postParams['vr_goods_config_base64'] ?? ''; if (!empty($base64Config)) { $jsonStr = base64_decode($base64Config);