1076 lines
31 KiB
Vue
1076 lines
31 KiB
Vue
<template>
|
||
<el-dialog
|
||
v-model="dialogVisible"
|
||
:title="titleOptions.title"
|
||
width="80%"
|
||
top="4vh"
|
||
@closed="closedReset"
|
||
>
|
||
<div class="scroll" ref="scrollRef">
|
||
<el-form
|
||
ref="formRef"
|
||
:model="form"
|
||
:rules="formRules"
|
||
label-width="160px"
|
||
class="dialog-form"
|
||
>
|
||
<el-form-item :label="titleOptions.name" prop="title">
|
||
<el-input
|
||
v-model="form.title"
|
||
:maxlength="20"
|
||
placeholder="请输入优惠券名称"
|
||
style="width: 300px"
|
||
/>
|
||
</el-form-item>
|
||
<div v-if="form.couponType == 1">
|
||
<el-form-item label="使用门槛" prop="fullAmount">
|
||
<div class="center">
|
||
<el-input
|
||
v-model="form.fullAmount"
|
||
placeholder="请输入使用门槛"
|
||
style="width: 240px"
|
||
input-style="text-align: center;"
|
||
:maxlength="8"
|
||
@input="(e) => (form.fullAmount = filterNumberInput(e))"
|
||
>
|
||
<template #prepend>满</template>
|
||
<template #append>元</template>
|
||
</el-input>
|
||
<el-input
|
||
v-model="form.discountAmount"
|
||
placeholder="请输入满减金额"
|
||
style="width: 240px"
|
||
input-style="text-align: center;"
|
||
:maxlength="8"
|
||
@input="(e) => (form.discountAmount = filterNumberInput(e))"
|
||
>
|
||
<template #prepend>减</template>
|
||
<template #append>元</template>
|
||
</el-input>
|
||
</div>
|
||
</el-form-item>
|
||
</div>
|
||
<div v-if="form.couponType == 2">
|
||
<el-form-item label="使用门槛" prop="fullAmount2">
|
||
<div class="center">
|
||
<el-input
|
||
v-model="form.fullAmount"
|
||
placeholder="请输入使用门槛"
|
||
style="width: 200px"
|
||
input-style="text-align: center;"
|
||
:maxlength="8"
|
||
@input="(e) => (form.fullAmount = filterNumberInput(e))"
|
||
>
|
||
<template #prepend>满</template>
|
||
<template #append>可用</template>
|
||
</el-input>
|
||
</div>
|
||
</el-form-item>
|
||
<el-form-item label="可用商品">
|
||
<el-radio-group v-model="goodsType">
|
||
<el-radio label="全部商品可用" :value="1"></el-radio>
|
||
<el-radio label="部分商品可用" :value="2"></el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
<el-form-item prop="goodsType" v-if="goodsType == 2">
|
||
<el-cascader
|
||
v-model="goodsTypeCascaderValue"
|
||
:options="goodsList"
|
||
:props="cascaderProps"
|
||
:show-all-levels="false"
|
||
:max-collapse-tags="3"
|
||
collapse-tags
|
||
clearable
|
||
style="width: 300px"
|
||
@change="selectFoodsConfirm"
|
||
></el-cascader>
|
||
</el-form-item>
|
||
<el-form-item label="使用规则">
|
||
<el-radio-group v-model="form.useRule">
|
||
<el-radio label="从最低价开始抵扣" value="price_asc"></el-radio>
|
||
<el-radio label="从最高价开始抵扣" value="price_desc"></el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
<el-form-item label="可抵扣商品件数" prop="discountNum">
|
||
<el-input
|
||
v-model="form.discountNum"
|
||
placeholder="请输入可抵扣商品件数"
|
||
style="width: 200px"
|
||
@input="discountNumInput"
|
||
/>
|
||
</el-form-item>
|
||
</div>
|
||
<div v-if="form.couponType == 3">
|
||
<el-form-item label="折扣" prop="discountRate">
|
||
<el-input
|
||
v-model="form.discountRate"
|
||
placeholder="输入折扣(%)"
|
||
style="width: 200px"
|
||
@input="discountRateInput"
|
||
/>
|
||
</el-form-item>
|
||
<el-form-item label="使用门槛" prop="fullAmount2">
|
||
<div class="center">
|
||
<el-input
|
||
v-model="form.fullAmount"
|
||
placeholder="请输入使用门槛"
|
||
style="width: 300px"
|
||
input-style="text-align: center;"
|
||
:maxlength="8"
|
||
@input="(e) => (form.fullAmount = filterNumberInput(e))"
|
||
>
|
||
<template #prepend>满</template>
|
||
<template #append>可用</template>
|
||
</el-input>
|
||
</div>
|
||
</el-form-item>
|
||
<el-form-item label="可抵扣最大金额" prop="maxDiscountAmount">
|
||
<div class="center">
|
||
<el-input
|
||
v-model="form.maxDiscountAmount"
|
||
placeholder="请输入金额"
|
||
style="width: 200px"
|
||
:maxlength="8"
|
||
@input="(e) => (form.maxDiscountAmount = filterNumberInput(e))"
|
||
>
|
||
<template #append>可用</template>
|
||
</el-input>
|
||
</div>
|
||
</el-form-item>
|
||
</div>
|
||
<div v-if="form.couponType == 4 || form.couponType == 6">
|
||
<el-form-item label="可用商品">
|
||
<el-radio-group v-model="goodsType">
|
||
<el-radio label="全部商品可用" :value="1"></el-radio>
|
||
<el-radio label="部分商品可用" :value="2"></el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
<el-form-item prop="goodsType" v-if="goodsType == 2">
|
||
<el-cascader
|
||
v-model="goodsTypeCascaderValue"
|
||
:options="goodsList"
|
||
:props="cascaderProps"
|
||
:show-all-levels="false"
|
||
:max-collapse-tags="3"
|
||
collapse-tags
|
||
clearable
|
||
style="width: 300px"
|
||
@change="selectFoodsConfirm"
|
||
></el-cascader>
|
||
</el-form-item>
|
||
<el-form-item label="使用规则">
|
||
<el-radio-group v-model="form.useRule">
|
||
<el-radio label="从最低价开始抵扣" value="price_asc"></el-radio>
|
||
<el-radio label="从最高价开始抵扣" value="price_desc"></el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
</div>
|
||
<div v-if="form.couponType == 6"></div>
|
||
<div class="title">指定设置</div>
|
||
<el-form-item
|
||
label="选择门店"
|
||
prop="useShopType"
|
||
v-if="shopInfo.isHeadShop && shopInfo.shopType != 'only'"
|
||
>
|
||
<el-radio-group v-model="form.useShopType">
|
||
<el-radio label="仅本店可用" value="only"></el-radio>
|
||
<el-radio label="全部门店" value="all"></el-radio>
|
||
<el-radio label="指定门店可用" value="custom"></el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
<el-form-item label="选择门店" v-if="form.useShopType == 'custom'">
|
||
<el-select
|
||
v-model="shops"
|
||
multiple
|
||
clearable
|
||
placeholder="请选择门店"
|
||
@change="shopsChange"
|
||
style="width: 300px"
|
||
>
|
||
<el-option
|
||
:label="item.shopName"
|
||
:value="item.id"
|
||
v-for="item in branchList"
|
||
:key="item.id"
|
||
></el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
<div v-if="form.couponType != 2 && form.couponType != 4 && form.couponType != 6">
|
||
<el-form-item label="指定门槛商品" prop="goodsType">
|
||
<el-radio-group v-model="goodsType" @change="goodRadioChnage">
|
||
<el-radio label="全部商品可用" :value="1"></el-radio>
|
||
<el-radio label="部分商品可用" :value="2"></el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
<el-form-item v-if="goodsType == 2">
|
||
<el-cascader
|
||
v-model="goodsTypeCascaderValue"
|
||
:options="goodsList"
|
||
:props="cascaderProps"
|
||
:show-all-levels="false"
|
||
:max-collapse-tags="3"
|
||
collapse-tags
|
||
clearable
|
||
style="width: 300px"
|
||
@change="selectFoodsConfirm"
|
||
></el-cascader>
|
||
</el-form-item>
|
||
</div>
|
||
<el-form-item label="可使用类型" prop="useType">
|
||
<el-checkbox-group v-model="form.useType">
|
||
<el-checkbox value="dine" label="堂食" />
|
||
<el-checkbox value="pickup" label="自取" />
|
||
<el-checkbox value="deliv" label="配送" />
|
||
<el-checkbox value="express" label="快递" />
|
||
</el-checkbox-group>
|
||
</el-form-item>
|
||
<div class="title">时效设置</div>
|
||
<el-form-item label="有效期类型">
|
||
<el-radio-group v-model="form.validType">
|
||
<el-radio label="领券后有效期内可用" value="fixed"></el-radio>
|
||
<el-radio label="固定有效期范围内可用" value="custom"></el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
<el-form-item label="有效期" prop="validDays">
|
||
<el-input
|
||
v-model="form.validDays"
|
||
placeholder="请输入有效期"
|
||
style="width: 200px"
|
||
:maxlength="5"
|
||
v-if="form.validType == 'fixed'"
|
||
input-style="text-align: center;"
|
||
@input="validDaysInput"
|
||
>
|
||
<template #append>天</template>
|
||
</el-input>
|
||
<div style="width: 200px">
|
||
<el-date-picker
|
||
v-model="validityScope"
|
||
type="daterange"
|
||
range-separator="至"
|
||
start-placeholder="开始时间"
|
||
end-placeholder="结束时间"
|
||
v-if="form.validType == 'custom'"
|
||
@change="validityScopeChange"
|
||
/>
|
||
</div>
|
||
</el-form-item>
|
||
<el-form-item
|
||
label="隔天生效"
|
||
prop="daysToTakeEffect"
|
||
v-if="form.validType == 'fixed'"
|
||
>
|
||
<div class="center">
|
||
<el-input
|
||
v-model="form.daysToTakeEffect"
|
||
placeholder="请输入隔天生效日期"
|
||
style="width: 300px"
|
||
input-style="text-align: center;"
|
||
:maxlength="5"
|
||
@input="daysToTakeEffectInput"
|
||
>
|
||
<template #prepend>隔</template>
|
||
<template #append>天生效</template>
|
||
</el-input>
|
||
<el-tooltip
|
||
class="box-item"
|
||
effect="dark"
|
||
:content="`领取后${form.daysToTakeEffect}天后的0点0分生效`"
|
||
placement="top-start"
|
||
>
|
||
<el-icon size="18">
|
||
<QuestionFilled />
|
||
</el-icon>
|
||
</el-tooltip>
|
||
</div>
|
||
</el-form-item>
|
||
<el-form-item label="可用周期" prop="useDays">
|
||
<el-checkbox-group v-model="form.useDays">
|
||
<el-checkbox value="周一" label="周一" />
|
||
<el-checkbox value="周二" label="周二" />
|
||
<el-checkbox value="周三" label="周三" />
|
||
<el-checkbox value="周四" label="周四" />
|
||
<el-checkbox value="周五" label="周五" />
|
||
<el-checkbox value="周六" label="周六" />
|
||
<el-checkbox value="周七" label="周日" />
|
||
</el-checkbox-group>
|
||
</el-form-item>
|
||
<el-form-item label="指定时间段">
|
||
<el-radio-group v-model="form.useTimeType">
|
||
<el-radio label="全时段可用" value="all"></el-radio>
|
||
<el-radio label="指定时间段可用" value="custom"></el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
<el-form-item v-if="form.useTimeType == 'custom'" prop="useTimeType">
|
||
<div style="width: 200px">
|
||
<el-time-picker
|
||
v-model="useTimeScope"
|
||
is-range
|
||
range-separator="至"
|
||
start-placeholder="开始时间"
|
||
end-placeholder="结束时间"
|
||
@change="useTimeScopeChange"
|
||
/>
|
||
</div>
|
||
</el-form-item>
|
||
<div class="title">发放设置</div>
|
||
<el-form-item label="发放设置">
|
||
<el-radio-group v-model="form.getType">
|
||
<el-radio label="用户不可自行领取" value="no"></el-radio>
|
||
<el-radio label="用户可自行在小程序领取" value="yes"></el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
<el-form-item label="用户领取方式" v-if="form.getType == 'yes'" prop="getMode">
|
||
<el-checkbox-group v-model="form.getMode">
|
||
<el-checkbox value="home" label="首页-优惠券" />
|
||
<el-checkbox value="eat" label="点餐页-自动弹出" />
|
||
<el-checkbox value="order" label="订单支付页面" />
|
||
</el-checkbox-group>
|
||
</el-form-item>
|
||
<el-form-item label="总发放数量" prop="giveNum">
|
||
<div class="column">
|
||
<div class="center">
|
||
<el-switch v-model="infiniteGiveNum" @change="infiniteGiveNumChange" />
|
||
<span>关闭则为无限制</span>
|
||
</div>
|
||
<div v-if="infiniteGiveNum" style="margin-top: 10px">
|
||
<el-input
|
||
v-model="form.giveNum"
|
||
placeholder="请输入总发放数量"
|
||
style="width: 200px"
|
||
input-style="text-align: center;"
|
||
:maxlength="5"
|
||
@input="giveNumInput"
|
||
>
|
||
<template #append>张</template>
|
||
</el-input>
|
||
</div>
|
||
</div>
|
||
</el-form-item>
|
||
<div class="title">限量设置</div>
|
||
<el-form-item label="可领取用户">
|
||
<el-radio-group v-model="form.getUserType">
|
||
<el-radio label="全部用户可领" value="all"></el-radio>
|
||
<el-radio label="仅新用户可领取一张" value="new"></el-radio>
|
||
<el-radio label="仅会员可领取" value="vip"></el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
<el-form-item label="每人限领量" prop="getLimit">
|
||
<el-input
|
||
v-model="form.getLimit"
|
||
placeholder="请输入每人限领量"
|
||
style="width: 200px"
|
||
input-style="text-align: center;"
|
||
:maxlength="5"
|
||
@input="getLimitInput"
|
||
>
|
||
<template #append>张</template>
|
||
</el-input>
|
||
</el-form-item>
|
||
<el-form-item label="每人每日使用限量">
|
||
<div class="column">
|
||
<div class="center">
|
||
<el-radio-group
|
||
v-model="infiniteUseLimit"
|
||
@change="infiniteUseLimitChange"
|
||
>
|
||
<el-radio label="无限制" :value="true"></el-radio>
|
||
<el-radio label="每日限用" :value="false"></el-radio>
|
||
</el-radio-group>
|
||
</div>
|
||
</div>
|
||
</el-form-item>
|
||
<el-form-item label="限用数量" v-if="!infiniteUseLimit" prop="useLimit">
|
||
<el-input
|
||
v-model="form.useLimit"
|
||
placeholder="需小于或等于每人限领量"
|
||
style="width: 255px"
|
||
input-style="text-align: center;"
|
||
:maxlength="5"
|
||
@input="useLimitInput"
|
||
>
|
||
<template #append>张/每人1天</template>
|
||
</el-input>
|
||
</el-form-item>
|
||
<div class="title">其他设置</div>
|
||
<el-form-item label="与限时折扣同享">
|
||
<div class="column">
|
||
<div class="center">
|
||
<el-switch
|
||
v-model="form.discountShare"
|
||
:active-value="1"
|
||
:inactive-value="0"
|
||
/>
|
||
<span>开启后,计算门槛时将会计入已折扣的商品</span>
|
||
</div>
|
||
</div>
|
||
</el-form-item>
|
||
<el-form-item label="与会员价/会员折扣同享">
|
||
<div class="column">
|
||
<div class="center">
|
||
<el-switch
|
||
v-model="form.vipPriceShare"
|
||
:active-value="1"
|
||
:inactive-value="0"
|
||
/>
|
||
<span>开启后,计算门槛时将会计入已享受会员价/会员折扣的商品</span>
|
||
</div>
|
||
</div>
|
||
</el-form-item>
|
||
<el-form-item label="与其他优惠券同享" v-if="form.couponType == 2">
|
||
<div class="column">
|
||
<div class="center">
|
||
<el-switch
|
||
v-model="form.otherCouponShare"
|
||
:active-value="1"
|
||
:inactive-value="0"
|
||
/>
|
||
<span>开启后,可与其他优惠券同时使用</span>
|
||
</div>
|
||
</div>
|
||
</el-form-item>
|
||
<div class="title">规则附加说明</div>
|
||
<el-form-item label-width="0">
|
||
<div class="column">
|
||
<div class="item">
|
||
<el-input
|
||
type="textarea"
|
||
:rows="4"
|
||
maxlength="250"
|
||
v-model="form.ruleDetails"
|
||
placeholder="填写内容"
|
||
></el-input>
|
||
</div>
|
||
<div class="item textarea-num">
|
||
{{ form.ruleDetails.length }}/250字内,单文本
|
||
</div>
|
||
</div>
|
||
</el-form-item>
|
||
</el-form>
|
||
</div>
|
||
<template #footer>
|
||
<div
|
||
class="dialog-footer"
|
||
v-if="(shopInfo.isHeadShop && shopInfo.shopType != 'only') || !form.syncId"
|
||
>
|
||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||
<el-button type="primary" :loading="loading" @click="submitHandle">确 定</el-button>
|
||
</div>
|
||
</template>
|
||
</el-dialog>
|
||
</template>
|
||
|
||
<script setup>
|
||
import _ from "lodash";
|
||
import { dayjs } from "element-plus";
|
||
import { ref, reactive, onMounted } from "vue";
|
||
import { filterNumberInput } from "@/utils";
|
||
import { getBranchPage, getProductList, getCategoryList, addCoupon } from "@/api/coupon/index.js";
|
||
|
||
const shopInfo = ref("");
|
||
const dialogVisible = ref(false);
|
||
|
||
const titleOptions = reactive({
|
||
name: "优惠券名称",
|
||
title: "添加优惠券",
|
||
couponTypeList: [
|
||
{
|
||
value: 1,
|
||
label: "满减券",
|
||
},
|
||
{
|
||
value: 2,
|
||
label: "商品兑换券",
|
||
},
|
||
{
|
||
value: 3,
|
||
label: "折扣券",
|
||
},
|
||
{
|
||
value: 4,
|
||
label: "第二件半价券",
|
||
},
|
||
{
|
||
value: 5,
|
||
label: "消费送券",
|
||
},
|
||
{
|
||
value: 6,
|
||
label: "买一送一券",
|
||
},
|
||
{
|
||
value: 7,
|
||
label: "固定价格券",
|
||
},
|
||
{
|
||
value: 8,
|
||
label: "免配送费券",
|
||
},
|
||
],
|
||
});
|
||
|
||
const cascaderProps = ref({
|
||
multiple: true,
|
||
emitPath: false,
|
||
value: "id",
|
||
label: "name",
|
||
});
|
||
|
||
// 选择指定商品
|
||
const goodsType = ref(1);
|
||
const goodsTypeCascaderValue = ref([]);
|
||
function selectFoodsConfirm(e) {
|
||
console.log(JSON.stringify(e));
|
||
form.value.foods = e.join(",");
|
||
}
|
||
|
||
// 切换商品类型
|
||
function goodRadioChnage(e) {
|
||
console.log(e);
|
||
form.value.foods = '';
|
||
goodsTypeCascaderValue.value = [];
|
||
}
|
||
|
||
// 选择的店铺列表
|
||
const shops = ref([]);
|
||
function shopsChange(e) {
|
||
form.value.useShops = e.join(",");
|
||
}
|
||
// 有效期时间
|
||
const validityScope = ref([]);
|
||
function validityScopeChange(e) {
|
||
console.log("validityScopeChange===", e);
|
||
if (e && e.length) {
|
||
form.value.validStartTime = dayjs(e[0]).format("YYYY-MM-DD 00:00:00");
|
||
form.value.validEndTime = dayjs(e[1]).format("YYYY-MM-DD 23:59:59");
|
||
} else {
|
||
form.value.validStartTime = "";
|
||
form.value.validEndTime = "";
|
||
}
|
||
}
|
||
// 可用时间
|
||
const useTimeScope = ref([]);
|
||
function useTimeScopeChange(e) {
|
||
console.log("useTimeScopeChange===", e);
|
||
if (e && e.length) {
|
||
form.value.useStartTime = dayjs(e[0]).format("HH:mm:00");
|
||
form.value.useEndTime = dayjs(e[1]).format("HH:mm:00");
|
||
} else {
|
||
form.value.useStartTime = "";
|
||
form.value.useEndTime = "";
|
||
}
|
||
}
|
||
|
||
// 是否为无限数量
|
||
const infiniteFlagNum = ref(-10086);
|
||
const infiniteGiveNum = ref(true);
|
||
function infiniteGiveNumChange(e) {
|
||
if (!e) {
|
||
form.value.giveNum = infiniteFlagNum.value;
|
||
} else {
|
||
form.value.giveNum = "";
|
||
}
|
||
}
|
||
// 是否为无限每人领取限量
|
||
const infiniteUseLimit = ref(true);
|
||
function infiniteUseLimitChange(e) {
|
||
if (e) {
|
||
form.value.useLimit = infiniteFlagNum.value;
|
||
} else {
|
||
form.value.useLimit = "";
|
||
}
|
||
}
|
||
|
||
const formRef = ref(null);
|
||
const form = ref({
|
||
id: "",
|
||
shopId: "",
|
||
syncId: "",
|
||
couponType: 1, // 1-满减券,2-商品兑换券,3-折扣券,4-第二件半价券,5-消费送券,6-买一送一券,7-固定价格券,8-免配送费券
|
||
title: "", // 券名称
|
||
fullAmount: "", // 使用门槛
|
||
discountAmount: "", // 使用门槛:减多少金额
|
||
useShopType: "only", // only-仅本店 all-所有门店,custom-指定门店
|
||
useShops: "", // id字符串拼接
|
||
goodsType: 1, // 1=全部商品参与计算门槛 2=部分商品参与计算门槛
|
||
foods: "", // 指定门槛商品 id拼接
|
||
useType: ["dine"], // 可使用类型:dine堂食/pickup自取/deliv配送/express快递
|
||
validType: "fixed", // 有效期类型:fixed(固定时间),custom(自定义时间)
|
||
validDays: "", // 有效期(天)
|
||
validStartTime: "", // 有效期开始时间
|
||
validEndTime: "", // 有效期结束时间
|
||
daysToTakeEffect: 0, // 隔天生效
|
||
useDays: ["周一", "周二", "周三", "周四", "周五", "周六", "周七"], // 可用周期,如:'周一','周二','周三' , '周四' , '周五', '周六' , '周七'
|
||
useTimeType: "all", // 可用时间段类型:all-全时段,custom-指定时段
|
||
useStartTime: "", // 可用开始时间
|
||
useEndTime: "", // 可用结束时间
|
||
getType: "no", // 发放设置:不可自行领取/no,可领取/yes
|
||
getMode: ["eat"], // 用户领取方式 home/首页-优惠券 eat/点餐页-自动弹出 order/订单支付页面
|
||
giveNum: "", // 总发放数量,-10086为不限量
|
||
getUserType: "all", // 可领取用户:全部/all,新用户一次/new,仅会员/vip
|
||
getLimit: 1, // 每人领取限量,-10086为不限量
|
||
useLimit: -10086, // 每人每日使用限量,-10086为不限量
|
||
discountShare: 1, // 与限时折扣同享:0-否,1-是
|
||
vipPriceShare: 1, // 与会员价同享:0-否,1-是
|
||
ruleDetails: "", // 附加规则说明
|
||
status: 1, // 状态:0-禁用,1-启用
|
||
useNum: "", // 已使用数量
|
||
leftNum: "", // 剩余数量
|
||
discountRate: "", // 折扣%
|
||
maxDiscountAmount: "", // 可抵扣最大金额 元
|
||
useRule: "price_asc", // 使用规则:price_asc-价格低到高,price_desc-高到低
|
||
discountNum: 1, // 抵扣数量
|
||
otherCouponShare: 1, // 与其它优惠共享:0-否,1-是
|
||
});
|
||
|
||
// 初始化
|
||
const resetForm = ref(null);
|
||
function reset() {
|
||
goodsType.value = 1;
|
||
goodsTypeCascaderValue.value = [];
|
||
shops.value = [];
|
||
validityScope.value = [];
|
||
useTimeScope.value = [];
|
||
infiniteGiveNum.value = true;
|
||
infiniteUseLimit.value = true;
|
||
form.value = { ...resetForm.value };
|
||
}
|
||
|
||
// 自定义校验使用门槛
|
||
const fullAmountValidate = (rule, value, callback) => {
|
||
if (form.value.fullAmount < 0) {
|
||
callback(new Error("请输入使用门槛"));
|
||
} else if (form.value.discountAmount <= 0) {
|
||
callback(new Error("请输入满减金额"));
|
||
} else {
|
||
callback();
|
||
}
|
||
};
|
||
const fullAmountValidate2 = (rule, value, callback) => {
|
||
console.log(form.value.fullAmount);
|
||
if (form.value.fullAmount < 0 || form.value.fullAmount === "") {
|
||
callback(new Error("请输入使用门槛"));
|
||
} else {
|
||
callback();
|
||
}
|
||
};
|
||
|
||
// 自定义校验选择门店
|
||
const useShopTypeValidate = (rule, value, callback) => {
|
||
if (form.value.useShopType == "custom" && form.value.useShops === "") {
|
||
callback(new Error("请选择门店"));
|
||
} else {
|
||
callback();
|
||
}
|
||
};
|
||
|
||
// 自定义校验使用门槛
|
||
const goodsTypeValidate = (rule, value, callback) => {
|
||
if (goodsType.value == 2 && form.value.foods === "") {
|
||
callback(new Error("请选择商品"));
|
||
} else {
|
||
callback();
|
||
}
|
||
};
|
||
|
||
// 自定义校验有效期类型
|
||
const validDaysValidate = (rule, value, callback) => {
|
||
if (form.value.validType == "fixed" && form.value.validDays === "") {
|
||
callback(new Error("请输入有效期"));
|
||
} else if (form.value.validType == "custom" && form.value.validStartTime === "") {
|
||
callback(new Error("请选择日期范围"));
|
||
} else {
|
||
callback();
|
||
}
|
||
};
|
||
|
||
// 自定义校验隔天生效
|
||
const daysToTakeEffectValidate = (rule, value, callback) => {
|
||
if (form.value.daysToTakeEffect < 0) {
|
||
callback(new Error("请输入大于等于0的值"));
|
||
} else {
|
||
callback();
|
||
}
|
||
};
|
||
|
||
// 自定义校验固定有效期范围内可用
|
||
const useTimeTypeValidate = (rule, value, callback) => {
|
||
if (!form.value.useStartTime) {
|
||
callback(new Error("请选择指定可用时间段"));
|
||
} else {
|
||
callback();
|
||
}
|
||
};
|
||
|
||
// 自定义校验每人限量
|
||
const giveNumValidate = (rule, value, callback) => {
|
||
if (form.value.giveNum <= 0 && infiniteGiveNum.value) {
|
||
callback(new Error("请输入总发放数量"));
|
||
} else {
|
||
callback();
|
||
}
|
||
};
|
||
|
||
// 自定义校验每人每日使用限量
|
||
const useLimitValidate = (rule, value, callback) => {
|
||
if (form.value.useLimit <= 0 && !infiniteUseLimit.value) {
|
||
callback(new Error("请输入每人每日使用限量"));
|
||
} else {
|
||
callback();
|
||
}
|
||
};
|
||
|
||
const formRules = reactive({
|
||
title: [{ required: true, message: "请输入优惠券名称", trigger: "blur" }],
|
||
fullAmount: [{ required: true, validator: fullAmountValidate, trigger: "blur" }],
|
||
fullAmount2: [
|
||
{
|
||
required: true,
|
||
validator: fullAmountValidate2,
|
||
trigger: "blur",
|
||
},
|
||
],
|
||
useShopType: [
|
||
{
|
||
validator: useShopTypeValidate,
|
||
trigger: "change",
|
||
},
|
||
],
|
||
goodsType: [
|
||
{
|
||
validator: goodsTypeValidate,
|
||
trigger: "change",
|
||
},
|
||
],
|
||
discountNum: [{ required: true, message: "请输入可抵扣商品件数", trigger: "blur" }],
|
||
discountRate: [{ required: true, message: "输入折扣(%)", trigger: "blur" }],
|
||
discountAmount: [{ required: true, message: "请输入使用门槛", trigger: "blur" }],
|
||
maxDiscountAmount: [{ required: true, message: "请输入金额", trigger: "blur" }],
|
||
useType: [{ required: true, message: "请选择可使用类型", trigger: "change" }],
|
||
validDays: [
|
||
{
|
||
required: true,
|
||
validator: validDaysValidate,
|
||
trigger: "change",
|
||
},
|
||
],
|
||
daysToTakeEffect: [
|
||
{
|
||
validator: daysToTakeEffectValidate,
|
||
trigger: "change",
|
||
},
|
||
],
|
||
useDays: [{ required: true, message: "请选择可用周期", trigger: "change" }],
|
||
useTimeType: [
|
||
{
|
||
validator: useTimeTypeValidate,
|
||
trigger: "change",
|
||
},
|
||
],
|
||
getMode: [{ required: true, message: "请选择用户领取方式", trigger: "change" }],
|
||
giveNum: [
|
||
{
|
||
validator: giveNumValidate,
|
||
trigger: "blur",
|
||
},
|
||
],
|
||
getLimit: [{ required: true, message: "请输入每人限领量", trigger: "blur" }],
|
||
useLimit: [
|
||
{
|
||
validator: useLimitValidate,
|
||
trigger: "blur",
|
||
},
|
||
],
|
||
});
|
||
|
||
// 开始提交
|
||
const emits = defineEmits(["success"]);
|
||
const loading = ref(false);
|
||
function submitHandle() {
|
||
formRef.value.validate(async (valid) => {
|
||
try {
|
||
if (valid) {
|
||
loading.value = true;
|
||
form.value.shopId = shopInfo.value.shopId;
|
||
await addCoupon(form.value);
|
||
emits("success");
|
||
dialogVisible.value = false;
|
||
}
|
||
} catch (err) {
|
||
console.log(err);
|
||
}
|
||
loading.value = false;
|
||
});
|
||
}
|
||
|
||
// 从本地获取商户信息
|
||
function getLocalShopInfo() {
|
||
shopInfo.value = JSON.parse(localStorage.getItem("userInfo"));
|
||
}
|
||
|
||
// 获取分店列表
|
||
const branchList = ref([]);
|
||
async function getBranchPageAjax() {
|
||
try {
|
||
const res = await getBranchPage();
|
||
branchList.value = res.records;
|
||
} catch (err) {
|
||
console.log(err);
|
||
}
|
||
}
|
||
|
||
// 获取商品列表
|
||
const goodsList = ref([]);
|
||
async function getProductListAjax() {
|
||
try {
|
||
const categorys = await getCategoryList();
|
||
const products = await getProductList();
|
||
goodsList.value = formatCategoryWithProducts(categorys, products);
|
||
} catch (err) {
|
||
console.log(err);
|
||
}
|
||
}
|
||
|
||
// 给分类组合相应的商品
|
||
function formatCategoryWithProducts(categories, products) {
|
||
// 步骤1:遍历所有分类,为每个分类匹配对应的商品
|
||
const allCategoriesWithProducts = categories.map((category) => {
|
||
// 匹配当前分类下的商品(通过category.id === product.categoryId关联)
|
||
const matchedProducts = products
|
||
.filter((product) => product.categoryId === category.id) // 关键:按分类ID匹配商品
|
||
.map((product) => ({
|
||
id: product.id,
|
||
name: product.name, // 提取商品的id和name
|
||
}));
|
||
|
||
// 组装单个分类的结构
|
||
return {
|
||
id: category.id,
|
||
name: category.name,
|
||
children: matchedProducts, // 该分类下的商品(空数组表示无商品)
|
||
};
|
||
});
|
||
|
||
// 步骤2:过滤掉“无商品”的分类(children为空数组的分类)
|
||
return allCategoriesWithProducts.filter((item) => item.children.length > 0);
|
||
}
|
||
|
||
// 显示弹窗
|
||
const scrollRef = ref(null);
|
||
function show(t, obj = null) {
|
||
nextTick(() => {
|
||
if (scrollRef.value) {
|
||
setTimeout(() => {
|
||
scrollRef.value.scrollTop = 0;
|
||
}, 50);
|
||
}
|
||
});
|
||
let m = titleOptions.couponTypeList.find((item) => item.value == t);
|
||
titleOptions.name = `${m.label}名称`;
|
||
if (obj && obj.id) {
|
||
titleOptions.title = `编辑${m.label}`;
|
||
|
||
form.value = { ...obj };
|
||
form.value.getMode = JSON.parse(form.value.getMode);
|
||
form.value.useDays = JSON.parse(form.value.useDays);
|
||
form.value.useType = JSON.parse(form.value.useType);
|
||
|
||
if (!!form.value.syncId) {
|
||
form.value.useShopType = "only";
|
||
}
|
||
|
||
if (form.value.foods != "") {
|
||
goodsType.value = 2;
|
||
goodsTypeCascaderValue.value = form.value.foods.split(",");
|
||
} else {
|
||
goodsType.value = 1;
|
||
}
|
||
|
||
if (form.value.useShops != "" && form.value.useShopType == "custom") {
|
||
shops.value = form.value.useShops.split(",");
|
||
}
|
||
|
||
if (form.value.validType == "custom") {
|
||
validityScope.value = [form.value.validStartTime, form.value.validEndTime];
|
||
}
|
||
|
||
if (form.value.useTimeType == "custom") {
|
||
useTimeScope.value = [
|
||
convertTimeToDate(form.value.useStartTime),
|
||
convertTimeToDate(form.value.useEndTime),
|
||
];
|
||
|
||
console.log(useTimeScope.value);
|
||
}
|
||
|
||
if (form.value.giveNum == infiniteFlagNum.value) {
|
||
infiniteGiveNum.value = false;
|
||
}
|
||
|
||
if (form.value.useLimit == infiniteFlagNum.value) {
|
||
infiniteUseLimit.value = true;
|
||
}
|
||
} else {
|
||
reset();
|
||
titleOptions.title = `添加${m.label}`;
|
||
}
|
||
form.value.couponType = t;
|
||
dialogVisible.value = true;
|
||
}
|
||
|
||
// 关闭后重置表单验证
|
||
function closedReset() {
|
||
formRef.value.resetFields();
|
||
}
|
||
|
||
/**
|
||
* 将时分秒字符串转换为完整日期格式
|
||
* @param {string} timeStr - 时分秒字符串,格式需为 HH:mm:ss(如 '00:53:00')
|
||
* @param {Object} options - 可选配置项
|
||
* @param {string} [options.customDate] - 自定义日期,格式为 YYYY-MM-DD(默认使用当前日期)
|
||
* @param {string} [options.format='YYYY-MM-DD HH:mm:ss'] - 输出的日期格式
|
||
* @returns {string|null} 转换后的日期字符串,失败时返回 null
|
||
*/
|
||
function convertTimeToDate(timeStr, options = {}) {
|
||
// 解构配置项,设置默认值
|
||
const { customDate, format = "YYYY-MM-DD HH:mm:ss" } = options;
|
||
|
||
// 1. 校验时分秒格式(必须为 HH:mm:ss,允许数字1-2位)
|
||
const timeRegex = /^\d{1,2}:\d{1,2}:\d{1,2}$/;
|
||
if (!timeRegex.test(timeStr)) {
|
||
console.error("时分秒格式错误,请使用 HH:mm:ss 格式(如 00:53:00)");
|
||
return null;
|
||
}
|
||
|
||
// 2. 确定日期部分(自定义日期或当前日期)
|
||
let datePart;
|
||
if (customDate) {
|
||
// 校验自定义日期格式
|
||
if (!dayjs(customDate, "YYYY-MM-DD", true).isValid()) {
|
||
console.error("自定义日期格式错误,请使用 YYYY-MM-DD 格式(如 2024-05-20)");
|
||
return null;
|
||
}
|
||
datePart = customDate;
|
||
} else {
|
||
// 使用当前日期(格式:YYYY-MM-DD)
|
||
datePart = dayjs().format("YYYY-MM-DD");
|
||
}
|
||
|
||
// 3. 组合日期和时分秒,生成完整日期对象
|
||
const fullDateTime = `${datePart} ${timeStr}`;
|
||
const dateObj = dayjs(fullDateTime);
|
||
|
||
// 4. 校验完整日期是否有效(如避免 2024-02-30 这种无效日期)
|
||
if (!dateObj.isValid()) {
|
||
console.error("生成的日期无效,请检查日期或时分秒是否合理");
|
||
return null;
|
||
}
|
||
|
||
// 5. 按指定格式返回日期字符串
|
||
return dateObj.format(format);
|
||
}
|
||
|
||
// input过滤
|
||
const time = 500;
|
||
const discountNumInput = _.debounce(function (value) {
|
||
form.value.discountNum = filterNumberInput(value, true);
|
||
if (form.value.discountNum == "") {
|
||
form.value.discountNum = 1;
|
||
}
|
||
}, time);
|
||
|
||
const discountRateInput = _.debounce(function (value) {
|
||
form.value.discountRate = filterNumberInput(value, true);
|
||
if (form.value.discountRate >= 100) {
|
||
form.value.discountRate = 100;
|
||
}
|
||
}, time);
|
||
|
||
const validDaysInput = _.debounce(function (value) {
|
||
form.value.validDays = filterNumberInput(value, true);
|
||
}, time);
|
||
|
||
const daysToTakeEffectInput = _.debounce(function (value) {
|
||
form.value.daysToTakeEffect = filterNumberInput(value, true);
|
||
if (form.value.daysToTakeEffect === "") {
|
||
form.value.daysToTakeEffect = 0;
|
||
}
|
||
}, time);
|
||
|
||
const giveNumInput = _.debounce(function (value) {
|
||
form.value.giveNum = filterNumberInput(value, true);
|
||
}, time);
|
||
|
||
const getLimitInput = _.debounce(function (value) {
|
||
form.value.getLimit = filterNumberInput(value, true);
|
||
if (form.value.getLimit == "") {
|
||
form.value.getLimit = 1;
|
||
}
|
||
}, time);
|
||
|
||
const useLimitInput = _.debounce(function (value) {
|
||
form.value.useLimit = filterNumberInput(value, true);
|
||
if (form.value.useLimit >= form.value.getLimit) {
|
||
form.value.useLimit = form.value.getLimit;
|
||
}
|
||
}, time);
|
||
|
||
defineExpose({
|
||
show,
|
||
});
|
||
|
||
onMounted(() => {
|
||
resetForm.value = { ...form.value };
|
||
getLocalShopInfo();
|
||
getBranchPageAjax();
|
||
getProductListAjax();
|
||
});
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.title {
|
||
color: #000;
|
||
padding: 14px;
|
||
background-color: #f8f8f8;
|
||
margin-bottom: 14px;
|
||
font-size: 16px;
|
||
}
|
||
|
||
.column {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
.item {
|
||
flex: 1;
|
||
}
|
||
}
|
||
.center {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
.scroll {
|
||
height: 76vh;
|
||
padding-bottom: 60px;
|
||
overflow-y: auto;
|
||
}
|
||
.dialog-footer {
|
||
position: relative;
|
||
&::after {
|
||
content: "";
|
||
width: 100%;
|
||
height: 60px;
|
||
position: absolute;
|
||
left: 0;
|
||
bottom: calc(100% + var(--el-dialog-padding-primary));
|
||
z-index: 9;
|
||
background: linear-gradient(to bottom, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1));
|
||
}
|
||
}
|
||
.textarea-num {
|
||
color: #999;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
}
|
||
</style>
|