1171 lines
30 KiB
Vue
1171 lines
30 KiB
Vue
<template>
|
||
<view class="container">
|
||
<u-form ref="formRef" :model="form" :rules="rules" label-position="top">
|
||
<view class="card">
|
||
<u-form-item prop="useShops">
|
||
<view class="switch-wrap">
|
||
<view class="top">
|
||
<text class="t">可用门店</text>
|
||
</view>
|
||
<view class="info">
|
||
<view class="ipt" v-if="isMainShop()">
|
||
<my-shop-select-w v-model:useType="form.useShopType" v-model:selShops="form.useShops"></my-shop-select-w>
|
||
</view>
|
||
<view class="ipt" v-else>
|
||
<u-radio-group v-model="form.useShopType">
|
||
<u-radio label="仅本店" name="only"></u-radio>
|
||
</u-radio-group>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</u-form-item>
|
||
</view>
|
||
<view class="card">
|
||
<u-form-item prop="packageName">
|
||
<view class="switch-wrap">
|
||
<view class="top">
|
||
<text class="t">套餐名称</text>
|
||
</view>
|
||
<view class="info">
|
||
<view class="ipt">
|
||
<u-input placeholder="请输入" :maxlength="30" v-model="form.packageName"></u-input>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</u-form-item>
|
||
<u-form-item>
|
||
<view class="switch-wrap">
|
||
<view class="top">
|
||
<text class="t">套餐描述</text>
|
||
</view>
|
||
<view class="info">
|
||
<view class="ipt">
|
||
<u-textarea placeholder="请输入" :maxlength="50" v-model="form.description"></u-textarea>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</u-form-item>
|
||
</view>
|
||
<view class="card">
|
||
<u-form-item prop="images">
|
||
<view class="switch-wrap">
|
||
<view class="top column">
|
||
<text class="t">套餐图片</text>
|
||
<text class="tips">*建议优先选择jpg格式,并且最好控制在500kb内</text>
|
||
</view>
|
||
<view class="info">
|
||
<my-upload-imgs v-model="form.images"></my-upload-imgs>
|
||
</view>
|
||
</view>
|
||
</u-form-item>
|
||
</view>
|
||
<view class="card">
|
||
<u-form-item prop="originPrice">
|
||
<view class="switch-wrap">
|
||
<view class="top">
|
||
<text class="t">原价</text>
|
||
</view>
|
||
<view class="info">
|
||
<view class="ipt">
|
||
<u-input v-model="form.originPrice" placeholder="请输入" @change="originalPriceInput">
|
||
<template #suffix>
|
||
<text>元</text>
|
||
</template>
|
||
</u-input>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</u-form-item>
|
||
<u-form-item prop="price">
|
||
<view class="switch-wrap">
|
||
<view class="top">
|
||
<text class="t">价格</text>
|
||
</view>
|
||
<view class="info">
|
||
<view class="ipt">
|
||
<u-input v-model="form.price" placeholder="请输入" @change="groupPriceInput">
|
||
<template #suffix>
|
||
<text>元</text>
|
||
</template>
|
||
</u-input>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</u-form-item>
|
||
</view>
|
||
<view class="card">
|
||
<u-form-item prop="packageContent">
|
||
<view class="switch-wrap">
|
||
<view class="top">
|
||
<text class="t">选择商品</text>
|
||
</view>
|
||
<view class="info">
|
||
<view class="package-wrap">
|
||
<view class="list">
|
||
<view class="item" v-for="(item, index) in form.packageContent" :key="index">
|
||
<view class="header">
|
||
<text class="t">第{{ index + 1 }}组菜品</text>
|
||
<view class="del" @click="form.packageContent.splice(index, 1)">
|
||
<u-icon name="minus-circle-fill" color="red" size="14"></u-icon>
|
||
<text class="t">删除套餐组</text>
|
||
</view>
|
||
</view>
|
||
<view class="input-wrap">
|
||
<view class="ipt">
|
||
<u-input v-model="item.name" :maxlength="20" placeholder="请输入菜品组名"></u-input>
|
||
</view>
|
||
<view class="btn" @click="showGoodsDialogHandle(index)">
|
||
<u-icon name="plus-circle-fill" color="#318AFE"></u-icon>
|
||
<text class="t">导入商品</text>
|
||
</view>
|
||
<view class="btn" @click="addGoodsHandle(item)">
|
||
<u-icon name="plus" color="#318AFE"></u-icon>
|
||
<text class="t">添加商品</text>
|
||
</view>
|
||
</view>
|
||
<view class="table-wrap">
|
||
<view class="tab-head">
|
||
<view class="tr">
|
||
<view class="td">
|
||
<text class="t">名称</text>
|
||
</view>
|
||
<view class="td">
|
||
<text class="t">价格</text>
|
||
</view>
|
||
<view class="td">
|
||
<text class="t">数量</text>
|
||
</view>
|
||
<view class="td">
|
||
<text class="t">操作</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="tb-body">
|
||
<view class="tr" v-for="(val, i) in item.packageProducts" :key="i">
|
||
<view class="td">
|
||
<u-input v-model="val.name" placeholder="商品名称"></u-input>
|
||
</view>
|
||
<view class="td">
|
||
<u-input
|
||
v-model="val.price"
|
||
placeholder="价格"
|
||
:maxlength="8"
|
||
@change="
|
||
(e) =>
|
||
mySetTimeout(() => {
|
||
val.price = filterNumberInput(e);
|
||
}, 50)
|
||
"
|
||
></u-input>
|
||
</view>
|
||
<view class="td">
|
||
<u-input
|
||
v-model="val.num"
|
||
placeholder="数量"
|
||
:maxlength="8"
|
||
@change="
|
||
(e) =>
|
||
mySetTimeout(() => {
|
||
val.num = filterNumberInput(e, 1);
|
||
}, 50)
|
||
"
|
||
></u-input>
|
||
</view>
|
||
<view class="td">
|
||
<text class="del" @click="item.packageProducts.splice(i, 1)">删除</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="empty" v-if="item.packageProducts.length == 0">
|
||
<text class="t">请添加商品</text>
|
||
</view>
|
||
</view>
|
||
<view class="select_num_wrap">
|
||
<view class="label">
|
||
<text class="t">套餐{{ item.packageProducts.length }}选{{ item.num }}</text>
|
||
</view>
|
||
<view class="ipt">
|
||
<u-input
|
||
v-model="item.num"
|
||
placeholder="请输入"
|
||
:maxlength="8"
|
||
@change="
|
||
(e) =>
|
||
mySetTimeout(() => {
|
||
item.num = filterNumberInput(e, 1);
|
||
}, 50)
|
||
"
|
||
></u-input>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="package-wrap-btn" @click="addGroupHandle">
|
||
<view class="btn">
|
||
<u-icon name="plus" color="#318AFE"></u-icon>
|
||
<text class="t">添加菜品组</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</u-form-item>
|
||
</view>
|
||
<view class="card">
|
||
<u-form-item prop="useWeeks">
|
||
<view class="switch-wrap">
|
||
<view class="top column">
|
||
<text class="t">可用周期</text>
|
||
</view>
|
||
<view class="info">
|
||
<view class="ipt">
|
||
<my-week-sel v-model="form.useWeeks"></my-week-sel>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</u-form-item>
|
||
<u-form-item prop="useTimes">
|
||
<view class="switch-wrap">
|
||
<view class="top column">
|
||
<text class="t">指定时间段</text>
|
||
</view>
|
||
<view class="info">
|
||
<view class="ipt">
|
||
<my-hour-area :showType="false" v-model:startValue="startValue" v-model:endValue="endValue"></my-hour-area>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</u-form-item>
|
||
</view>
|
||
<view class="card">
|
||
<u-form-item>
|
||
<view class="switch-wrap">
|
||
<view class="top">
|
||
<text class="t">其他使用说明</text>
|
||
</view>
|
||
<view class="info">
|
||
<view class="ipt">
|
||
<u-textarea placeholder="请输入" :maxlength="50" v-model="form.otherDesc"></u-textarea>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</u-form-item>
|
||
</view>
|
||
<view class="card">
|
||
<u-form-item prop="tieredDiscount">
|
||
<view class="switch-wrap">
|
||
<view class="top">
|
||
<view class="two">
|
||
<text class="t">分享优惠阶梯</text>
|
||
<view class="tips">如果没有分享裂变需求可以不设置,最多三级</view>
|
||
</view>
|
||
<view>
|
||
<u-button type="primary" :disabled="!form.price" v-if="form.tieredDiscount.length < 3" @click="addStepHandle">
|
||
{{ form.price ? '添加方案' : '请添加价格' }}
|
||
</u-button>
|
||
</view>
|
||
</view>
|
||
<view class="info">
|
||
<view class="step-wrap">
|
||
<view class="table-wrap">
|
||
<view class="tab-head">
|
||
<view class="tr">
|
||
<view class="td">
|
||
<text class="t">分享人数</text>
|
||
</view>
|
||
<view class="td">
|
||
<text class="t">价格(元)</text>
|
||
</view>
|
||
<view class="td">
|
||
<text class="t">操作</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="tb-body">
|
||
<view class="tr" v-for="(val, i) in form.tieredDiscount" :key="i">
|
||
<view class="td">
|
||
<text class="t">{{ val.peopleNum }}</text>
|
||
</view>
|
||
<view class="td">
|
||
<text class="t">{{ val.price }}</text>
|
||
</view>
|
||
<view class="td">
|
||
<text class="edit" @click="editorStepFormHandle(i)">编辑</text>
|
||
<text class="del" @click="form.tieredDiscount.splice(i, 1)">删除</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="empty" v-if="form.tieredDiscount.length == 0">
|
||
<text class="t">请添加阶梯</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</u-form-item>
|
||
</view>
|
||
<view class="card">
|
||
<u-form-item prop="expireHours">
|
||
<view class="switch-wrap">
|
||
<view class="top column">
|
||
<text class="t">分享期限(小时)</text>
|
||
</view>
|
||
<view class="info">
|
||
<view class="ipt">
|
||
<u-input v-model="form.expireHours" placeholder="最小不低于1小时,最大不超过72小时" @change="groupTimeoutHourInput"></u-input>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</u-form-item>
|
||
</view>
|
||
<view class="card">
|
||
<u-form-item>
|
||
<view class="switch-wrap">
|
||
<view class="top">
|
||
<text class="t">上架状态</text>
|
||
<u-switch v-model="form.onlineStatus" :active-value="1" :inactive-value="0"></u-switch>
|
||
</view>
|
||
</view>
|
||
</u-form-item>
|
||
</view>
|
||
<view class="card">
|
||
<u-form-item>
|
||
<view class="switch-wrap">
|
||
<view class="top column">
|
||
<text class="t">商品详情</text>
|
||
<text class="tips">*建议优先选择jpg格式,并且最好控制在500kb内</text>
|
||
</view>
|
||
<view class="info">
|
||
<my-upload-imgs v-model="form.detailImages"></my-upload-imgs>
|
||
</view>
|
||
</view>
|
||
</u-form-item>
|
||
</view>
|
||
</u-form>
|
||
<my-footer-btn showCancel type="horizontal" @confirm="submitHandle" @cancel="backHandle"></my-footer-btn>
|
||
<u-popup :show="showStepDialog" mode="center" closeable :safe-area-inset-bottom="false" @close="stepDialogReset">
|
||
<view class="add-step-wrap">
|
||
<view class="title">
|
||
<text class="t">
|
||
{{ stepFormType == 'add' ? '添加阶梯' : '编辑阶梯' }}
|
||
</text>
|
||
</view>
|
||
<view class="content">
|
||
<u-form ref="stepFormRef" :model="stepForm" :rules="stepFormRules" :label-width="0">
|
||
<u-form-item prop="peopleNum">
|
||
<view class="switch-wrap">
|
||
<view class="top column">
|
||
<text class="t">分享人数</text>
|
||
</view>
|
||
<view class="info">
|
||
<view class="ipt">
|
||
<u-input
|
||
v-model="stepForm.peopleNum"
|
||
placeholder="请输入分享人数"
|
||
:maxlength="8"
|
||
@change="
|
||
(e) =>
|
||
mySetTimeout(() => {
|
||
stepForm.peopleNum = filterNumberInput(e, 1);
|
||
}, 50)
|
||
"
|
||
>
|
||
<template #suffix>
|
||
<text>人</text>
|
||
</template>
|
||
</u-input>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</u-form-item>
|
||
<u-form-item prop="price">
|
||
<view class="switch-wrap">
|
||
<view class="top column">
|
||
<text class="t">价格</text>
|
||
</view>
|
||
<view class="info">
|
||
<view class="ipt">
|
||
<u-input
|
||
v-model="stepForm.price"
|
||
placeholder="请输入价格"
|
||
:maxlength="8"
|
||
@change="
|
||
(e) =>
|
||
mySetTimeout(() => {
|
||
stepForm.price = filterNumberInput(e);
|
||
}, 50)
|
||
"
|
||
>
|
||
<template #suffix>
|
||
<text>元</text>
|
||
</template>
|
||
</u-input>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</u-form-item>
|
||
</u-form>
|
||
</view>
|
||
<view class="footer-btn-wrap">
|
||
<view class="btn">
|
||
<u-button style="width: 100%" @click="showStepDialog = false">取消</u-button>
|
||
</view>
|
||
<view class="btn">
|
||
<u-button type="primary" style="width: 100%" @click="stepFormSubmitHandle">确定</u-button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</u-popup>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import _ from 'lodash';
|
||
import { ref } from 'vue';
|
||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||
import { filterNumberInput } from '@/utils/index.js';
|
||
import { packageAddEdit } from '@/http/api/ware.js';
|
||
import { isMainShop } from '@/store/account.js';
|
||
|
||
// 封装全局定时器,适配多端
|
||
const mySetTimeout = (fn, delay) => {
|
||
if (typeof uni !== 'undefined') {
|
||
return setTimeout(fn, delay); // 小程序
|
||
} else {
|
||
return window.setTimeout(fn, delay); // H5
|
||
}
|
||
};
|
||
|
||
const type = ref('add'); // add添加商品 editor编辑商品
|
||
const formRef = ref(null);
|
||
const startValue = ref('');
|
||
const endValue = ref('');
|
||
const form = ref({
|
||
id: '',
|
||
useShopType: 'only', // only-仅本店 all全部 /custom 指定
|
||
useShops: [], // 可用门店(指定门店时存储门店ID,逗号分隔)
|
||
packageName: '', // 套餐名称
|
||
description: '', // 商品描述
|
||
images: [], // 商品图片(多个用逗号分隔)
|
||
originPrice: '', // 原价
|
||
price: '', // 售价
|
||
packageContent: [], // 套餐内容
|
||
useTimes: '', // 可用时段:08:00~21:30
|
||
useWeeks: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'], // 可用周期: [周一,周二]
|
||
otherDesc: '', // 其他描述
|
||
tieredDiscount: [], // 阶梯优惠
|
||
expireHours: '', // 分享期限(小时)不低于1小时,最大72小时
|
||
onlineStatus: 1, // 上架状态(0下架 1上架)
|
||
detailImages: [] // 商品详情图片(多个用逗号分隔)
|
||
});
|
||
|
||
const rules = ref({
|
||
useShops: [
|
||
{
|
||
trigger: ['change'],
|
||
message: '请选择可用门店',
|
||
validator: (rule, value, callback) => {
|
||
if (form.value.useShopType == 'custom' && form.value.useShops.length == 0) {
|
||
return false;
|
||
} else {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
],
|
||
packageName: [
|
||
{
|
||
required: true,
|
||
trigger: ['blur'],
|
||
message: '请输入',
|
||
validator: (rule, value, callback) => {
|
||
if (form.value.packageName === '') {
|
||
return false;
|
||
} else {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
],
|
||
images: [
|
||
{
|
||
required: true,
|
||
trigger: ['blur'],
|
||
message: '请选择商品图片',
|
||
validator: (rule, value, callback) => {
|
||
if (form.value.images.length == 0) {
|
||
return false;
|
||
} else {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
],
|
||
originPrice: [
|
||
{
|
||
required: true,
|
||
trigger: ['blur'],
|
||
message: '请输入',
|
||
validator: (rule, value, callback) => {
|
||
if (form.value.originPrice === '') {
|
||
return false;
|
||
} else {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
],
|
||
price: [
|
||
{
|
||
required: true,
|
||
trigger: ['blur'],
|
||
message: '请输入',
|
||
validator: (rule, value, callback) => {
|
||
if (form.value.price === '') {
|
||
return false;
|
||
} else {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
],
|
||
packageContent: [
|
||
{
|
||
required: true,
|
||
message: '请检查',
|
||
trigger: ['blur'],
|
||
validator: (rule, value, callback) => {
|
||
if (form.value.packageContent.length == 0) {
|
||
uni.showToast({
|
||
title: `请添加菜品组`,
|
||
icon: 'none'
|
||
});
|
||
return false;
|
||
} else {
|
||
let checkPass = true;
|
||
let errorMsg = '';
|
||
for (const [groupIndex, item] of form.value.packageContent.entries()) {
|
||
// 1. 校验菜品组名
|
||
if (item.name === '') {
|
||
errorMsg = `请输入第${groupIndex + 1}组的菜品组名`;
|
||
checkPass = false;
|
||
break; // 终止循环,只提示第一个错误
|
||
}
|
||
|
||
// 2. 校验该组是否添加商品
|
||
if (item.packageProducts.length === 0) {
|
||
errorMsg = `请给第${groupIndex + 1}组添加商品`;
|
||
checkPass = false;
|
||
break;
|
||
}
|
||
|
||
// 3. 校验组内商品(嵌套 entries() 获取商品索引)
|
||
let productError = false;
|
||
for (const [productIndex, val] of item.packageProducts.entries()) {
|
||
// 3.1 商品名称为空
|
||
if (val.name === '') {
|
||
errorMsg = `请输入第${groupIndex + 1}组菜品的第${productIndex + 1}项的商品名称`;
|
||
productError = true;
|
||
break;
|
||
}
|
||
// 3.2 商品价格为空
|
||
if (val.price === '') {
|
||
errorMsg = `请输入第${groupIndex + 1}组菜品的第${productIndex + 1}项的商品价格`;
|
||
productError = true;
|
||
break;
|
||
}
|
||
}
|
||
// 商品校验失败,终止整体循环
|
||
if (productError) {
|
||
checkPass = false;
|
||
break;
|
||
}
|
||
|
||
if (item.num === '') {
|
||
errorMsg = `请给第${groupIndex + 1}组输入几选几`;
|
||
checkPass = false;
|
||
break;
|
||
}
|
||
if (item.num > item.packageProducts.length) {
|
||
errorMsg = `第${groupIndex + 1}组几选几输入有误,最大${item.packageProducts.length}`;
|
||
checkPass = false;
|
||
break;
|
||
}
|
||
}
|
||
if (!checkPass) {
|
||
uni.showToast({
|
||
title: errorMsg,
|
||
icon: 'none'
|
||
});
|
||
}
|
||
return checkPass;
|
||
}
|
||
}
|
||
}
|
||
],
|
||
useWeeks: [
|
||
{
|
||
required: true,
|
||
trigger: ['blur'],
|
||
message: '请选择可用周期',
|
||
validator: (rule, value, callback) => {
|
||
if (form.value.useWeeks.length === 0) {
|
||
return false;
|
||
} else {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
],
|
||
useTimes: [
|
||
{
|
||
required: true,
|
||
trigger: ['blur'],
|
||
message: '请选择指定时间段',
|
||
validator: (rule, value, callback) => {
|
||
if (form.value.useTimes === '') {
|
||
return false;
|
||
} else {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
],
|
||
expireHours: [
|
||
{
|
||
trigger: ['blur'],
|
||
validator: (rule, value, callback) => {
|
||
if (form.value.tieredDiscount.length && form.value.expireHours === '') {
|
||
return callback(new Error('请输入分享期限'));
|
||
} else if (form.value.expireHours > 72) {
|
||
return callback(new Error('最大不超过72小时'));
|
||
} else {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
]
|
||
});
|
||
|
||
// 套餐组对象
|
||
const packageContentItem = ref({
|
||
name: '',
|
||
num: 1,
|
||
packageProducts: []
|
||
});
|
||
|
||
// 套餐组商品对象
|
||
const packageProductsItem = ref({
|
||
name: '',
|
||
price: '',
|
||
num: 1
|
||
});
|
||
|
||
// 添加套餐组
|
||
function addGroupHandle() {
|
||
form.value.packageContent.push(_.cloneDeep(packageContentItem.value));
|
||
}
|
||
|
||
// 添加商品
|
||
function addGoodsHandle(item) {
|
||
item.packageProducts.push(_.cloneDeep(packageProductsItem.value));
|
||
}
|
||
|
||
// 显示导入商品弹窗
|
||
const portGoodsIndex = ref(0);
|
||
function showGoodsDialogHandle(index) {
|
||
portGoodsIndex.value = index;
|
||
uni.navigateTo({
|
||
url: '/pageMarket/packagePopularize/selectGoods'
|
||
});
|
||
}
|
||
|
||
// 选择的商品
|
||
function selectProduceHandle() {
|
||
let obj = uni.getStorageSync('packageSelectGoods');
|
||
if (obj && obj.name) {
|
||
let data = _.cloneDeep(packageProductsItem.value);
|
||
data.name = obj.name;
|
||
data.price = obj.price;
|
||
form.value.packageContent[portGoodsIndex.value].packageProducts.push(data);
|
||
}
|
||
}
|
||
|
||
// ============= 添加阶梯 start
|
||
|
||
const addStepIndex = ref(0);
|
||
const showStepDialog = ref(false);
|
||
const stepFormRef = ref(null);
|
||
const stepForm = ref({
|
||
peopleNum: '',
|
||
price: ''
|
||
});
|
||
const stepFormType = ref('add');
|
||
const stepFormRules = ref({
|
||
peopleNum: [
|
||
{
|
||
required: true,
|
||
validator: (rule, value, callback) => {
|
||
if (addStepIndex.value == 1 && +stepForm.value.peopleNum <= +form.value.tieredDiscount[0].peopleNum) {
|
||
return callback(new Error('二阶段价格分享人数不可小于一阶段分享人数'));
|
||
} else if (addStepIndex.value == 2 && +stepForm.value.peopleNum <= +form.value.tieredDiscount[1].peopleNum) {
|
||
return callback(new Error('三阶段价格分享人数不可小于二阶段分享人数'));
|
||
} else {
|
||
return callback();
|
||
}
|
||
},
|
||
trigger: ['blur']
|
||
}
|
||
],
|
||
price: [
|
||
{
|
||
required: true,
|
||
validator: (rule, value, callback) => {
|
||
// 1. 空值校验(优先处理)
|
||
if (stepForm.value.price.trim() === '') {
|
||
return callback(new Error('请输入价格'));
|
||
}
|
||
|
||
// 统一转数值(避免字符串比较问题)
|
||
const currentPrice = +stepForm.value.price;
|
||
const originPrice = +form.value.price;
|
||
// 解构阶梯价格(转数值)
|
||
const [firstPrice, secondPrice, thirdPrice] = form.value.tieredDiscount.map((item) => +item.price);
|
||
|
||
// 2. 新增模式(原有逻辑不变)
|
||
if (stepFormType.value === 'add') {
|
||
if (addStepIndex.value === 0 && currentPrice > originPrice) {
|
||
return callback(new Error(`一阶段价格不可大于商品售价¥${originPrice}`));
|
||
} else if (addStepIndex.value === 1 && currentPrice >= firstPrice) {
|
||
return callback(new Error('二阶段价格不可大于等于一阶段价格'));
|
||
} else if (addStepIndex.value === 2 && currentPrice >= secondPrice) {
|
||
return callback(new Error('三阶段价格不可大于等于二阶段价格'));
|
||
} else {
|
||
return callback(); // 校验通过
|
||
}
|
||
}
|
||
// 3. 编辑模式(新增逻辑:瞻前顾后)
|
||
else if (stepFormType.value === 'editor') {
|
||
// 编辑第一阶段
|
||
if (addStepIndex.value === 0) {
|
||
// 规则:不大于原价 + 不小于第二阶段(若第二阶段存在)
|
||
if (currentPrice > originPrice) {
|
||
return callback(new Error(`一阶段价格不可大于商品售价¥${form.value.originPrice}`));
|
||
} else if (secondPrice && currentPrice <= secondPrice) {
|
||
// 第二阶段有值时,第一阶段需大于第二阶段
|
||
return callback(new Error('一阶段价格不可小于等于二阶段价格'));
|
||
} else {
|
||
return callback();
|
||
}
|
||
}
|
||
// 编辑第二阶段
|
||
else if (addStepIndex.value === 1) {
|
||
// 规则:不小于第一阶段 + 不大于第三阶段(若第三阶段存在)
|
||
const errors = [];
|
||
if (currentPrice >= firstPrice) {
|
||
errors.push('二阶段价格不可大于等于一阶段价格');
|
||
}
|
||
if (thirdPrice && currentPrice <= thirdPrice) {
|
||
// 第三阶段有值时,第二阶段需大于第三阶段
|
||
errors.push('二阶段价格不可小于等于三阶段价格');
|
||
}
|
||
if (errors.length > 0) {
|
||
return callback(new Error(errors.join(';')));
|
||
} else {
|
||
return callback();
|
||
}
|
||
}
|
||
// 编辑第三阶段
|
||
else if (addStepIndex.value === 2) {
|
||
// 规则:仅校验不大于等于第二阶段(和新增一致)
|
||
if (currentPrice >= secondPrice) {
|
||
return callback(new Error('三阶段价格不可大于等于二阶段价格'));
|
||
} else {
|
||
return callback();
|
||
}
|
||
}
|
||
}
|
||
// 兜底:无匹配模式时校验通过
|
||
else {
|
||
return callback();
|
||
}
|
||
},
|
||
trigger: ['blur']
|
||
}
|
||
]
|
||
});
|
||
|
||
// 显示添加阶梯
|
||
function addStepHandle() {
|
||
stepFormType.value = 'add';
|
||
showStepDialog.value = true;
|
||
addStepIndex.value = form.value.tieredDiscount.length;
|
||
}
|
||
|
||
// 编辑优惠阶梯
|
||
function editorStepFormHandle(index) {
|
||
stepFormType.value = 'editor';
|
||
showStepDialog.value = true;
|
||
addStepIndex.value = index;
|
||
|
||
stepForm.value.peopleNum = form.value.tieredDiscount[index].peopleNum;
|
||
stepForm.value.price = form.value.tieredDiscount[index].price;
|
||
}
|
||
|
||
// 关闭dialog后初始化stepForm
|
||
function stepDialogReset() {
|
||
stepForm.value.peopleNum = '';
|
||
stepForm.value.price = '';
|
||
stepFormRef.value.resetFields();
|
||
}
|
||
|
||
// 确认添加阶段
|
||
function stepFormSubmitHandle() {
|
||
stepFormRef.value
|
||
.validate()
|
||
.then(() => {
|
||
console.log('stepFormType.value', stepFormType.value);
|
||
console.log('addStepIndex.value', addStepIndex.value);
|
||
if (stepFormType.value == 'add') {
|
||
form.value.tieredDiscount.push(_.cloneDeep(stepForm.value));
|
||
} else {
|
||
form.value.tieredDiscount[addStepIndex.value] = _.cloneDeep(stepForm.value);
|
||
}
|
||
showStepDialog.value = false;
|
||
})
|
||
.catch(() => {});
|
||
}
|
||
|
||
// ============= 添加阶梯end
|
||
|
||
// 原价
|
||
function originalPriceInput(e) {
|
||
setTimeout(() => {
|
||
form.value.originPrice = filterNumberInput(e);
|
||
}, 50);
|
||
}
|
||
|
||
// 拼团价
|
||
function groupPriceInput(e) {
|
||
setTimeout(() => {
|
||
form.value.price = filterNumberInput(e);
|
||
}, 50);
|
||
}
|
||
|
||
// 成团期限
|
||
function groupTimeoutHourInput(e) {
|
||
setTimeout(() => {
|
||
form.value.expireHours = filterNumberInput(e, 1);
|
||
}, 50);
|
||
}
|
||
|
||
// 保存商品
|
||
function submitHandle() {
|
||
if (startValue.value && endValue.value) {
|
||
form.value.useTimes = `${startValue.value}~${endValue.value}`;
|
||
}
|
||
console.log(form.value);
|
||
formRef.value
|
||
.validate()
|
||
.then(async () => {
|
||
try {
|
||
uni.showLoading({
|
||
title: '保存中...',
|
||
mask: true
|
||
});
|
||
const data = { ...form.value };
|
||
if (form.value.useShops.length) {
|
||
data.useShops = form.value.useShops.join(',');
|
||
} else {
|
||
data.useShops = '';
|
||
}
|
||
await packageAddEdit(data);
|
||
setTimeout(() => {
|
||
uni.showToast({
|
||
title: '保存成功',
|
||
icon: 'none'
|
||
});
|
||
}, 300);
|
||
setTimeout(() => {
|
||
uni.navigateBack();
|
||
}, 1000);
|
||
} catch (error) {
|
||
console.log(error);
|
||
}
|
||
uni.hideLoading();
|
||
})
|
||
.catch(() => {});
|
||
}
|
||
|
||
function backHandle() {
|
||
uni.navigateBack();
|
||
}
|
||
|
||
// 从本地获取商品信息
|
||
function getLocalGoods() {
|
||
let packageGoods = uni.getStorageSync('packageGoods');
|
||
if (packageGoods && packageGoods.id) {
|
||
form.value = packageGoods;
|
||
|
||
if (form.value.useShops !== '') {
|
||
form.value.useShops = form.value.useShops.split(',');
|
||
} else {
|
||
form.value.useShops = [];
|
||
}
|
||
|
||
if (packageGoods.useTimes !== '') {
|
||
let times = packageGoods.useTimes.split('~');
|
||
startValue.value = times[0];
|
||
endValue.value = times[1];
|
||
}
|
||
}
|
||
}
|
||
|
||
onShow(() => {
|
||
// 从本地获取选择的商品
|
||
selectProduceHandle();
|
||
});
|
||
|
||
onLoad((options) => {
|
||
uni.setStorageSync('packageSelectGoods', '');
|
||
if (options.type && options.type == 'editor') {
|
||
type.value = options.type;
|
||
uni.setNavigationBarTitle({
|
||
title: '编辑商品'
|
||
});
|
||
getLocalGoods();
|
||
} else {
|
||
type.value = 'add';
|
||
}
|
||
});
|
||
</script>
|
||
|
||
<style>
|
||
page {
|
||
background-color: #f8f8f8;
|
||
}
|
||
</style>
|
||
<style scoped lang="scss">
|
||
.container {
|
||
padding: 28upx;
|
||
}
|
||
.card {
|
||
background-color: #fff;
|
||
border-radius: 20px;
|
||
padding: 28upx;
|
||
&:not(:last-child) {
|
||
margin-bottom: 28upx;
|
||
}
|
||
}
|
||
.switch-wrap {
|
||
flex: 1;
|
||
width: 100%;
|
||
.top {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
&.column {
|
||
align-items: flex-start;
|
||
flex-direction: column;
|
||
}
|
||
.two {
|
||
display: flex;
|
||
flex-direction: column;
|
||
padding-right: 28upx;
|
||
}
|
||
.t {
|
||
font-size: 32upx;
|
||
color: #333;
|
||
font-weight: bold;
|
||
}
|
||
.tips {
|
||
font-size: 24upx;
|
||
color: #666;
|
||
}
|
||
}
|
||
.info {
|
||
padding-top: 16upx;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16upx;
|
||
.i {
|
||
font-size: 28upx;
|
||
color: #666;
|
||
}
|
||
.ipt {
|
||
flex: 1;
|
||
}
|
||
.t {
|
||
font-size: 24upx;
|
||
color: #666;
|
||
}
|
||
.package-wrap {
|
||
flex: 1;
|
||
.list {
|
||
.item {
|
||
border: 1px solid #ececec;
|
||
border-radius: 12upx;
|
||
padding: 20upx;
|
||
&:not(:first-child) {
|
||
margin-top: 28upx;
|
||
}
|
||
.header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding-bottom: 20upx;
|
||
.t {
|
||
font-size: 28upx;
|
||
color: #333;
|
||
}
|
||
.del {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12upx;
|
||
}
|
||
}
|
||
.input-wrap {
|
||
display: flex;
|
||
gap: 20upx;
|
||
padding-bottom: 20upx;
|
||
.btn {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12upx;
|
||
.t {
|
||
color: #318afe;
|
||
}
|
||
}
|
||
}
|
||
.table-wrap {
|
||
padding-bottom: 20upx;
|
||
margin-bottom: 20upx;
|
||
.tab-head {
|
||
background-color: #f8f8f8;
|
||
}
|
||
.tr {
|
||
display: flex;
|
||
gap: 12upx;
|
||
padding: 20upx;
|
||
border-bottom: 1px solid #ececec;
|
||
.td {
|
||
flex: 1;
|
||
&:nth-child(1) {
|
||
flex: 2;
|
||
}
|
||
&:last-child {
|
||
flex: 0.5;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
}
|
||
.t {
|
||
font-size: 28upx;
|
||
color: #333;
|
||
}
|
||
.del {
|
||
color: red;
|
||
font-size: 28upx;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.select_num_wrap {
|
||
padding-bottom: 28upx;
|
||
.label {
|
||
padding-bottom: 20upx;
|
||
.t {
|
||
color: #333;
|
||
font-size: 32upx;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.package-wrap-btn {
|
||
display: flex;
|
||
justify-content: center;
|
||
padding-top: 28upx;
|
||
.btn {
|
||
display: flex;
|
||
gap: 8upx;
|
||
align-items: center;
|
||
.t {
|
||
font-size: 28upx;
|
||
color: #318afe;
|
||
font-weight: bold;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.step-wrap {
|
||
flex: 1;
|
||
.table-wrap {
|
||
padding-bottom: 20upx;
|
||
margin-bottom: 20upx;
|
||
.tab-head {
|
||
background-color: #f8f8f8;
|
||
}
|
||
.tr {
|
||
display: flex;
|
||
gap: 12upx;
|
||
padding: 20upx;
|
||
border-bottom: 1px solid #ececec;
|
||
.td {
|
||
flex: 1;
|
||
display: flex;
|
||
gap: 20upx;
|
||
align-items: center;
|
||
&:last-child {
|
||
flex: 0.6;
|
||
}
|
||
.t {
|
||
font-size: 28upx;
|
||
color: #333;
|
||
}
|
||
.edit {
|
||
color: #318afe;
|
||
font-size: 28upx;
|
||
}
|
||
.del {
|
||
color: red;
|
||
font-size: 28upx;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.empty {
|
||
padding: 28upx 0;
|
||
display: flex;
|
||
justify-content: center;
|
||
.t {
|
||
font-size: 28upx;
|
||
color: #999;
|
||
}
|
||
}
|
||
.add-step-wrap {
|
||
width: 80vw;
|
||
.title {
|
||
padding: 28upx;
|
||
.t {
|
||
font-size: 32upx;
|
||
font-weight: bold;
|
||
}
|
||
}
|
||
.content {
|
||
padding: 0 28upx 28upx;
|
||
}
|
||
.footer-btn-wrap {
|
||
display: flex;
|
||
padding: 0 28upx 28upx;
|
||
gap: 28upx;
|
||
.btn {
|
||
flex: 1;
|
||
}
|
||
}
|
||
}
|
||
</style>
|