diff --git a/backend/modules/product/normal/Handler.php b/backend/modules/product/normal/Handler.php index b85baddc6..e45a187ed 100644 --- a/backend/modules/product/normal/Handler.php +++ b/backend/modules/product/normal/Handler.php @@ -558,15 +558,16 @@ class Handler extends BaseProductTypeHandler $sukKey = implode(',', array_values($detail)); $productValue[$sukKey] = [ - 'suk' => $sukKey, - 'price' => $sku['price'] ?? '0.00', - 'stock' => $sku['stock'] ?? 0, - 'image' => $sku['image'] ?? '', - 'unique' => $sku['unique_code'] ?? '', - 'cost' => $sku['cost'] ?? '0.00', - 'ot_price' => $sku['original_price'] ?? '0.00', - 'bar_code' => $sku['bar_code'] ?? '', - 'is_show' => $sku['is_show'] ?? 1, + 'suk' => $sukKey, + 'price' => $sku['price'] ?? '0.00', + 'vip_price' => $sku['vip_price'] ?? '0.00', + 'stock' => $sku['stock'] ?? 0, + 'image' => $sku['image'] ?? '', + 'unique' => $sku['unique_code'] ?? '', + 'cost' => $sku['cost'] ?? '0.00', + 'ot_price' => $sku['original_price'] ?? '0.00', + 'bar_code' => $sku['bar_code'] ?? '', + 'is_show' => $sku['is_show'] ?? 1, ]; } @@ -588,12 +589,13 @@ class Handler extends BaseProductTypeHandler ?: $normalSkuDao->getOne(['product_id' => $productId, 'is_show' => 1]); if (is_object($sku)) $sku = $sku->toArray(); - $skuPrice = $sku['price'] ?? '0.00'; - $skuStock = $sku['stock'] ?? 0; - $skuImage = $sku['image'] ?? ''; - $skuUnique = $sku['unique_code'] ?? ''; - $skuCost = $sku['cost'] ?? '0.00'; - $skuOtPrice = $sku['original_price'] ?? '0.00'; + $skuPrice = $sku['price'] ?? '0.00'; + $skuVipPrice = $sku['vip_price'] ?? '0.00'; + $skuStock = $sku['stock'] ?? 0; + $skuImage = $sku['image'] ?? ''; + $skuUnique = $sku['unique_code'] ?? ''; + $skuCost = $sku['cost'] ?? '0.00'; + $skuOtPrice = $sku['original_price'] ?? '0.00'; $productAttr = [ [ @@ -606,15 +608,16 @@ class Handler extends BaseProductTypeHandler ]; $productValue = [ '默认' => [ - 'suk' => '默认', - 'price' => $skuPrice, - 'stock' => $skuStock, - 'image' => $skuImage, - 'unique' => $skuUnique, - 'cost' => $skuCost, - 'ot_price' => $skuOtPrice, - 'bar_code' => '', - 'is_show' => 1, + 'suk' => '默认', + 'price' => $skuPrice, + 'vip_price' => $skuVipPrice, + 'stock' => $skuStock, + 'image' => $skuImage, + 'unique' => $skuUnique, + 'cost' => $skuCost, + 'ot_price' => $skuOtPrice, + 'bar_code' => '', + 'is_show' => 1, ], ]; diff --git a/backend/modules/product/virtual/Handler.php b/backend/modules/product/virtual/Handler.php index c935b6146..2ed3944ef 100644 --- a/backend/modules/product/virtual/Handler.php +++ b/backend/modules/product/virtual/Handler.php @@ -443,12 +443,13 @@ class Handler extends BaseProductTypeHandler } catch (\Throwable $e) { $center = null; } - $skuPrice = $center['price'] ?? '0.00'; - $skuStock = $center['stock'] ?? 0; - $skuImage = $center['image'] ?? ''; - $skuUnique = (string)$productId; - $skuCost = '0.00'; - $skuOtPrice = $center['price'] ?? '0.00'; + $skuPrice = $center['price'] ?? '0.00'; + $skuVipPrice = $center['vip_price'] ?? '0.00'; + $skuStock = $center['stock'] ?? 0; + $skuImage = $center['image'] ?? ''; + $skuUnique = (string)$productId; + $skuCost = '0.00'; + $skuOtPrice = $center['price'] ?? '0.00'; $productAttr = [ [ @@ -463,6 +464,7 @@ class Handler extends BaseProductTypeHandler '默认' => [ 'suk' => '默认', 'price' => $skuPrice, + 'vip_price' => $skuVipPrice, 'stock' => $skuStock, 'image' => $skuImage, 'unique' => $skuUnique, @@ -510,6 +512,7 @@ class Handler extends BaseProductTypeHandler $productValue[$suk] = [ 'suk' => $suk, 'price' => $sku['price'] ?? '0.00', + 'vip_price' => $sku['vip_price'] ?? '0.00', 'stock' => $sku['stock'] ?? 0, 'image' => $skuImage, 'unique' => (string)($sku['id'] ?? ''), diff --git a/frontend/admin/src/pages/plugin/normal/add/components/PriceCommission.vue b/frontend/admin/src/pages/plugin/normal/add/components/PriceCommission.vue index f89286bf1..604ede426 100644 --- a/frontend/admin/src/pages/plugin/normal/add/components/PriceCommission.vue +++ b/frontend/admin/src/pages/plugin/normal/add/components/PriceCommission.vue @@ -70,18 +70,6 @@ :max="9999999999" class="priceBox input-number-unit-class" class-unit="元" - @change="changeVipPrice(0, 'oneFormValidate')" - > - - @@ -100,20 +88,6 @@ class-unit="元" :model-value="manyVipPrice" @update:model-value="(val) => emit('update:manyVipPrice', val)" - @focus="emit('update:manyVipDiscount', undefined)" - > - - - 会员折扣: 批量设置 @@ -177,23 +151,6 @@ updateManyFormValue(scope.$index + 1, 'vip_price', val); } " - @change="changeVipPrice(scope.$index + 1)" - > - - @@ -233,19 +190,12 @@ const props = defineProps({ type: Number, default: undefined, }, - manyVipDiscount: { - type: Number, - default: undefined, - }, }); const emit = defineEmits([ 'checkAllGroupChange', - 'changeVipPrice', - 'changeDiscount', 'brokerageSetUp', 'update:manyVipPrice', - 'update:manyVipDiscount', 'update:manyFormValidate', ]); @@ -255,12 +205,6 @@ function checkAllGroupChange(val) { function onVipChange() { emit('checkAllGroupChange'); } -function changeVipPrice(index, type) { - emit('changeVipPrice', index, type); -} -function changeDiscount(index, type) { - emit('changeDiscount', index, type); -} function updateManyFormValue(index, key, value) { const newData = props.manyFormValidate.map((item, itemIndex) => itemIndex === index ? { ...item, [key]: value } : item, diff --git a/frontend/admin/src/pages/plugin/normal/add/index.vue b/frontend/admin/src/pages/plugin/normal/add/index.vue index 04cd877d7..80337b396 100644 --- a/frontend/admin/src/pages/plugin/normal/add/index.vue +++ b/frontend/admin/src/pages/plugin/normal/add/index.vue @@ -106,10 +106,7 @@ :columnsInstall="columnsInstall" :columnsInstal2="columnsInstal2" v-model:manyVipPrice="manyVipPrice" - v-model:manyVipDiscount="manyVipDiscount" @checkAllGroupChange="checkAllGroupChange" - @changeVipPrice="changeVipPrice" - @changeDiscount="changeDiscount" @brokerageSetUp="brokerageSetUp" > @@ -465,7 +462,6 @@ const picTit = ref(''); const tableIndex = ref(0); const ruleValidate = RuleValidate; const manyVipPrice = ref(undefined); -const manyVipDiscount = ref(undefined); const upload = reactive({ videoIng: false, // 是否显示进度条; }); @@ -486,12 +482,6 @@ const member = [ align: 'center', width: 95, }, - { - title: '会员折扣', - slot: 'vip_proportion', - align: 'center', - width: 95, - }, ]; const columnsInstalM = ref([]); const moveIndex = ref(''); @@ -794,10 +784,6 @@ function infoData(data, isCopy) { formValidate.value.cate_id = cate_id; if (data.attr) { oneFormValidate.value = [data.attr]; - oneFormValidate.value[0].vip_proportion = ( - (oneFormValidate.value[0].vip_price / oneFormValidate.value[0].price) * - 100 - ).toFixed(2); oneFormValidate.value[0].weight = data.weight ?? 0; oneFormValidate.value[0].volume = data.volume ?? 0; } @@ -887,19 +873,6 @@ function see(data, name, index) { goodsCoupon.value.isTemplate = true; goodsCoupon.value.tableList(3); } -// 修改分佣比例 -function changeDiscount(index, type = 'manyFormValidate') { - // 根据分佣比例 vip_proportion 修改会员价,写回数字(字符串会破坏 el-input-number 输入) - formTable(type)[index].vip_price = Number( - (formTable(type)[index].price * (formTable(type)[index].vip_proportion / 100)).toFixed(2), - ); -} -// 修改会员价 -function changeVipPrice(index, type = 'manyFormValidate') { - // 售价为 0 时无法反推折扣,置 0 防止 Infinity 被钳制成极大值写回 - const row = formTable(type)[index]; - row.vip_proportion = row.price > 0 ? Number(((row.vip_price / row.price) * 100).toFixed(2)) : 0; -} // 添加优惠券 function addGoodsCoupon(index, name) { tabIndex.value = index; @@ -1015,23 +988,13 @@ function userSearchs() { function addRule() { addattr.value.modal = true; } -// 批量设置会员价/会员折扣(商品页已不再设置佣金) +// 批量设置会员价(商品页已不再设置佣金/会员折扣) function brokerageSetUp() { - if (manyVipPrice.value == undefined && manyVipDiscount.value == undefined) { - return ElMessage.error('请填写会员价或会员折扣后进行批量添加'); - } - if (manyVipPrice.value != undefined && manyVipDiscount.value != undefined) { - return ElMessage.error('会员价和会员折扣只能二选一添加'); + if (!(manyVipPrice.value > 0)) { + return ElMessage.error('请填写会员价后进行批量添加'); } for (let val of manyFormValidate.value) { - if (manyVipPrice.value != undefined) { - val['vip_price'] = manyVipPrice.value; - // 售价为 0 时无法反推折扣,置 0 防止 Infinity - val['vip_proportion'] = val.price > 0 ? Number(((val.vip_price / val.price) * 100).toFixed(2)) : 0; - } else { - val['vip_proportion'] = manyVipDiscount.value; - val['vip_price'] = Number((val.price * (manyVipDiscount.value / 100)).toFixed(2)); - } + val.vip_price = manyVipPrice.value; } } // 批量设置会员价 diff --git a/frontend/admin/src/pages/plugin/virtual/product/Add.vue b/frontend/admin/src/pages/plugin/virtual/product/Add.vue index d5f2c14fc..8995b31f3 100644 --- a/frontend/admin/src/pages/plugin/virtual/product/Add.vue +++ b/frontend/admin/src/pages/plugin/virtual/product/Add.vue @@ -91,21 +91,16 @@ @getEditorContent="getEditorContent" > - + @@ -231,7 +226,7 @@ import goodsList from '@/components/goodsList/index'; import BasicInfo from '../../../../pages/product/productAdd/components/BasicInfo.vue'; import SpecStock from '../../../../pages/product/productAdd/components/SpecStock.vue'; import ProductDetail from '../../../../pages/product/productAdd/components/ProductDetail.vue'; -import PriceCommission from '../../../../pages/product/productAdd/components/PriceCommission.vue'; +import PriceCommission from './components/PriceCommission.vue'; import MarketingSetting from '../../../../pages/product/productAdd/components/MarketingSetting.vue'; import OtherSetting from '../../../../pages/product/productAdd/components/OtherSetting.vue'; import LogisticsSetting from '../../../../pages/product/productAdd/components/LogisticsSetting.vue'; @@ -281,7 +276,7 @@ const headTab = ref([ { tit: '基础信息', name: '1' }, { tit: '规格库存', name: '2' }, { tit: '商品详情', name: '3' }, - { tit: '会员价/佣金', name: '4' }, + { tit: '会员价', name: '4' }, { tit: '营销设置', name: '5' }, { tit: '其他设置', name: '6' }, ]); @@ -429,21 +424,11 @@ const dataLabel = ref([]); const labelShow = ref(false); const tagShow = ref(false); const activity = ref({ 默认: 'red', 秒杀: 'blue', 砍价: 'green', 拼团: 'yellow' }); -// 会员/佣金 -const manyBrokerage = ref(undefined); -const manyBrokerageTwo = ref(undefined); +// 会员价 const manyVipPrice = ref(undefined); -const manyVipDiscount = ref(undefined); const columnsInstall = ref([]); const columnsInstal2 = ref([]); -const rakeBack = [ - { title: '一级返佣(元)', slot: 'brokerage', align: 'center', width: 95 }, - { title: '二级返佣(元)', slot: 'brokerage_two', align: 'center', width: 95 }, -]; -const member = [ - { title: '会员价', slot: 'vip_price', align: 'center', width: 95 }, - { title: '会员折扣', slot: 'vip_proportion', align: 'center', width: 95 }, -]; +const member = [{ title: '会员价', slot: 'vip_price', align: 'center', width: 95 }]; const columnsInstalM = ref([]); // 商品标签 const goods_modals = ref(false); @@ -541,9 +526,9 @@ async function loadProduct() { } // 商品详情回显 contents.value = data.description || ''; - // 触发 checkAllGroup 构建会员价/佣金表格列 + // 触发 checkAllGroup 构建会员价表格列 setTimeout(() => { - checkAllGroup(formValidate.value.is_sub); + checkAllGroup(); }, 500); } catch (e) { ElMessage.error('加载商品信息失败'); @@ -1079,59 +1064,27 @@ function addGoodsCoupon(index, name) {} function getEditorContent(data) { content.value = data; } -// ----- 会员价/佣金 ----- +// ----- 会员价 ----- function checkAllGroupChange() { checkAllGroup(); } function checkAllGroup() { let endLength = attrs.value.length + 3; - const hasCommission = formValidate.value.is_sub == 1; const hasVip = formValidate.value.is_vip == 1; if (formValidate.value.spec_type === 0) { - if (hasCommission && hasVip) columnsInstall.value = columns2.slice(0, endLength).concat(rakeBack).concat(member); - else if (hasVip) columnsInstall.value = columns2.slice(0, endLength).concat(member); - else if (hasCommission) columnsInstall.value = columns2.slice(0, endLength).concat(rakeBack); - else columnsInstall.value = columns2.slice(0, endLength); + columnsInstall.value = hasVip ? columns2.slice(0, endLength).concat(member) : columns2.slice(0, endLength); } else { - if (hasCommission && hasVip) - columnsInstal2.value = columnsInstalM.value - .slice(0, endLength + 1) - .concat(rakeBack) - .concat(member); - else if (hasVip) columnsInstal2.value = columnsInstalM.value.slice(0, endLength).concat(member); - else if (hasCommission) columnsInstal2.value = columnsInstalM.value.slice(0, endLength).concat(rakeBack); - else columnsInstal2.value = columnsInstalM.value.slice(0, endLength); + columnsInstal2.value = hasVip + ? columnsInstalM.value.slice(0, endLength).concat(member) + : columnsInstalM.value.slice(0, endLength); } } -function changeDiscount(index, type = 'manyFormValidate') { - const list = type === 'oneFormValidate' ? oneFormValidate.value : manyFormValidate.value; - list[index].vip_price = (list[index].price * (list[index].vip_proportion / 100)).toFixed(2); -} -function changeVipPrice(index, type = 'manyFormValidate') { - const list = type === 'oneFormValidate' ? oneFormValidate.value : manyFormValidate.value; - list[index].vip_proportion = ((list[index].vip_price / list[index].price) * 100).toFixed(2); -} function brokerageSetUp() { - if (formValidate.value.is_sub == 1) { - if (manyBrokerage.value <= 0 || manyBrokerageTwo.value <= 0) return ElMessage.error('请填写返佣金额后进行批量添加'); - } - if (formValidate.value.is_vip == 1) { - if (manyVipPrice.value <= 0) return ElMessage.error('请填写会员价后进行批量添加'); - } - if (formValidate.value.is_sub == 1 && formValidate.value.is_vip == 1) { - if (manyBrokerage.value <= 0 || manyBrokerageTwo.value <= 0) return ElMessage.error('请填写完金额后进行批量添加'); - if (manyVipPrice.value > 0 && manyVipDiscount.value > 0) return ElMessage.error('会员价和会员折扣只能二选一添加'); + if (!(manyVipPrice.value > 0)) { + return ElMessage.error('请填写会员价后进行批量添加'); } for (let val of manyFormValidate.value) { - manyBrokerage.value !== undefined && (val['brokerage'] = manyBrokerage.value); - manyBrokerageTwo.value !== undefined && (val['brokerage_two'] = manyBrokerageTwo.value); - if (manyVipPrice.value !== undefined) { - val['vip_price'] = manyVipPrice.value; - val['vip_proportion'] = ((val.vip_price / val.price) * 100).toFixed(2); - } else if (manyVipDiscount.value !== undefined) { - val['vip_proportion'] = manyVipDiscount.value; - val['vip_price'] = (val.price * (manyVipDiscount.value / 100)).toFixed(2); - } + val.vip_price = manyVipPrice.value; } } // ----- 营销设置 ----- @@ -1255,8 +1208,8 @@ function handleSubmit() { if (!formValidate.value.cate_id.length) return ElMessage.warning('请选择商品分类'); if (!formValidate.value.slider_image.length) return ElMessage.warning('请上传商品图片'); - // 会员价/佣金验证 - if (formValidate.value.is_sub == 1 || formValidate.value.is_vip == 1) { + // 会员价验证 + if (formValidate.value.is_vip == 1) { let item; if (formValidate.value.spec_type === 0) { item = JSON.parse(JSON.stringify(oneFormValidate.value)); @@ -1264,11 +1217,9 @@ function handleSubmit() { item = JSON.parse(JSON.stringify(manyFormValidate.value)); item.shift(); } - if (formValidate.value.is_vip == 1) { - for (let i = 0; i < item.length; i++) { - if (item[i].vip_price === null || item[i].vip_price <= 0) { - return ElMessage.error('营销设置-会员价不能为空或0'); - } + for (let i = 0; i < item.length; i++) { + if (item[i].vip_price === null || item[i].vip_price <= 0) { + return ElMessage.error('会员价不能为空或0'); } } } @@ -1328,9 +1279,10 @@ function handleSubmit() { custom_form: formValidate.value.custom_form || [], coupon_ids: formValidate.value.coupon_ids || [], label_list: formValidate.value.label_list || [], - is_sub: formValidate.value.is_sub ?? 0, + // 网盘商品页不再设置分销,保存时统一关闭 + is_sub: 0, presale_time: formValidate.value.presale_time || [], - // VIP/佣金 + // 会员价 oneFormValidate: oneFormValidate.value || [], manyFormValidate: manyFormValidate.value || [], min_qty: formValidate.value.min_qty || 1, diff --git a/frontend/admin/src/pages/plugin/virtual/product/components/PriceCommission.vue b/frontend/admin/src/pages/plugin/virtual/product/components/PriceCommission.vue new file mode 100644 index 000000000..162ca74ed --- /dev/null +++ b/frontend/admin/src/pages/plugin/virtual/product/components/PriceCommission.vue @@ -0,0 +1,213 @@ + + + + diff --git a/frontend/uni-app/src/pages/goods_details/index.vue b/frontend/uni-app/src/pages/goods_details/index.vue index 7dc4719df..3e915b503 100644 --- a/frontend/uni-app/src/pages/goods_details/index.vue +++ b/frontend/uni-app/src/pages/goods_details/index.vue @@ -659,11 +659,13 @@ const modalRefs = { // ---------- computed ---------- const isShowPaidVip = computed(() => { - let s = - !is_money_level.value && - storeInfo.value.vip_price && - storeInfo.value.is_vip; - return !!s; + // 非付费会员才展示「开通 SVIP 预计省」;会员价来自 storeInfo 或 realPrice 的 member_price + const vipPrice = + Number(storeInfo.value.vip_price) || + Number(realPriceData.value.member_price) || + Number(realPriceData.value.vip_price) || + 0; + return !is_money_level.value && !!storeInfo.value.is_vip && vipPrice > 0; }); /** * 加购模式:cart(双按钮)| direct(单按钮直接下单) @@ -1106,7 +1108,11 @@ function ChangeAttr(res) { } function setRealPrice(productId, unique) { realPrice(productId, unique).then((res) => { - realPriceData.value = res.data; + // 统一补齐 vip_price,供 DIY 价格区 / 开通会员条使用(接口字段名为 member_price) + realPriceData.value = { + ...res.data, + vip_price: res.data.member_price || res.data.vip_price || 0, + }; attr.productSelect["price"] = res.data.real_price; attr.productSelect["vip_price"] = res.data.member_price; ot_price.value = res.data.ot_price; diff --git a/frontend/uni-app/src/subpackage/diyComponents/productInfo.vue b/frontend/uni-app/src/subpackage/diyComponents/productInfo.vue index 27f23710c..017060419 100644 --- a/frontend/uni-app/src/subpackage/diyComponents/productInfo.vue +++ b/frontend/uni-app/src/subpackage/diyComponents/productInfo.vue @@ -414,7 +414,7 @@ {{ $t(`预售结束后`) }} {{ productData.presale_day }} + >{{ $t(`预售结束后`) }} {{ productData.presale_day || 1 }} {{ $t(`天内发货`) }} @@ -470,7 +470,8 @@ const displayInfo = computed(() => { let price = props.priceData.price || "0.00"; let real_price = props.priceData.real_price || "0.00"; let ot_price = props.priceData.ot_price || "0.00"; - let vip_price = props.priceData.vip_price; + // real_price 接口字段为 member_price,详情 storeInfo/SKU 为 vip_price,两端兼容 + let vip_price = props.priceData.vip_price || props.priceData.member_price || 0; let stock = props.productData.stock || 0; let fsales = props.productData.fsales || 0; let unit_name = props.productData.unit_name || ""; @@ -481,14 +482,14 @@ const displayInfo = computed(() => { if (sku.price) price = sku.price; if (sku.real_price) price = sku.real_price; if (sku.ot_price) ot_price = sku.ot_price; - if (sku.vip_price) vip_price = sku.vip_price; + if (Number(sku.vip_price) > 0) vip_price = sku.vip_price; if (sku.stock || sku.stock === 0) stock = sku.stock; } } return { price, ot_price, - vip_price, + vip_price: Number(vip_price) > 0 ? vip_price : 0, stock, fsales, unit_name,