add: 增加生日有礼页面

This commit is contained in:
YeMingfei666 2025-10-15 15:47:58 +08:00
parent 056992c8a0
commit 36e14ed434
7 changed files with 604 additions and 2 deletions

View File

@ -0,0 +1,35 @@
import request from "@/utils/request";
import { Market_BaseUrl } from "@/api/config";
const baseURL = Market_BaseUrl + "/admin/birthdayGift";
const API = {
getConfig(params: any) {
return request<any>({
url: `${baseURL}`,
method: "get",
params
});
},
editConfig(data: any) {
return request<any>({
url: `${baseURL}`,
method: "post",
data
});
},
getRecord(params: any) {
return request<any>({
url: `${baseURL}/record`,
method: "get",
params
});
},
getSummary(params: any) {
return request<any>({
url: `${baseURL}/summary`,
method: "get",
params
});
},
}
export default API;

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -0,0 +1,79 @@
<template>
<div>
<div v-for="(item, index) in modelValue" :key="index" class="flex gap-4 mb-2">
<el-select v-model="item.id" placeholder="请选择优惠券" @change="changeCoupon($event, index)">
<el-option
v-for="coupon in couponList"
:key="coupon.id"
:label="coupon.title"
:value="coupon.id"
/>
</el-select>
<el-input v-model="item.num" placeholder="请输入数量">
<template #append>每人/</template>
</el-input>
<div>
<el-link
:underline="false"
type="danger"
class="no-wrap"
@click="modelValue.splice(index, 1)"
>
删除
</el-link>
</div>
</div>
<div class="flex">
<div class="flex gap-1 cursor-pointer" @click="addCoupon()">
<el-icon color="#3F9EFF">
<CirclePlus />
</el-icon>
<el-link :underline="false" type="primary" class="no-wrap">新增券</el-link>
</div>
</div>
</div>
</template>
<script setup>
import couponApi from "@/api/market/coupon";
import { ref, reactive, onMounted } from "vue";
const modelValue = defineModel({
type: Array,
default: () => [],
});
//
const couponList = ref([]);
function addCoupon() {
if (!modelValue.value) {
modelValue.value = [
{
num: 1,
id: null,
title: "",
},
];
return;
}
modelValue.value.push({
num: 1,
id: null,
title: "",
});
console.log(modelValue.value);
}
onMounted(() => {
couponApi.getList({ size: 999 }).then((res) => {
if (res) {
couponList.value = res.records || [];
}
});
});
function changeCoupon(e, index) {
const coupon = couponList.value.find((item) => item.id === e);
modelValue.value[index].id = coupon.id;
modelValue.value[index].title = coupon.title;
}
</script>

View File

@ -0,0 +1,132 @@
<template>
<div>
<el-dialog title="添加赠券" v-model="show" @close="reset" width="60%">
<el-form :model="form" label-width="120px">
<el-form-item label="用户类型">
<el-radio-group v-model="form.userType">
<el-radio v-for="(item, index) in userTypes" :key="index" :value="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="发放时间">
<el-radio-group v-model="form.deliverDate">
<el-radio v-for="(item, index) in deliverDates" :key="index" :value="item.value">
{{ item.label }}
</el-radio>
<el-input
v-if="form.deliverDate === 'advance'"
style="width: 180px"
:step="1"
:min="1"
v-model="form.deliverTime"
placeholder="请输入提前天数"
>
<template #append></template>
</el-input>
</el-radio-group>
</el-form-item>
<el-form-item label="选择优惠券">
<CouponLists v-model="form.couponInfoList" />
</el-form-item>
</el-form>
<div style="text-align: right; margin-top: 20px">
<el-button @click="close">取消</el-button>
<el-button type="primary" @click="submit">{{ isedit ? "更新" : "提交" }}</el-button>
</div>
</el-dialog>
</div>
</template>
<script setup>
import CouponLists from "./coup-lists.vue";
import { userTypes } from "@/views/marketing_center/data.js";
import { ref, toRaw } from "vue";
import { ElMessage } from "element-plus";
//
const show = ref(false);
//
const deliverDates = ref([
{ value: "mouth", label: "生日前一天" },
{ value: "day", label: "当天" },
{ value: "advance", label: "提前" },
]);
//
const form = ref({
userType: "all",
deliverTime: 1,
deliverDate: "mouth",
couponInfoList: [],
});
//
function reset() {
form.value = {
userType: "all",
deliverTime: 1,
deliverDate: "mouth",
couponInfoList: [],
};
}
const emits = defineEmits(["submitSuccess"]);
//
function submit() {
if (!form.value.couponInfoList.length) {
ElMessage.error("请选择优惠券");
return;
}
const ispass = form.value.couponInfoList.every((item) => item.num && item.id);
if (!ispass) {
ElMessage.error("请选择优惠券并输入数量");
return;
}
const submitData = { ...form.value };
if (submitData.deliverDate !== "advance") {
if (submitData.deliverDate === "day") {
submitData.deliverTime = 0;
}
if (submitData.deliverDate === "mouth") {
submitData.deliverTime = 1;
}
} else {
//
submitData.deliverDate = "day";
submitData.deliverTime = submitData.deliverTime * -1;
}
emits("submitSuccess", submitData, dataIndex);
// API
close();
}
let isedit = ref(false);
let dataIndex = null;
function open(data, index) {
data = toRaw(data);
console.log("data", data);
console.log("index", index);
if (data) {
if (data.deliverDate == "day" && data.deliverTime) {
data.deliverDate = "advance";
data.deliverTime = Math.abs(data.deliverTime);
}
form.value = data;
isedit.value = true;
dataIndex = index;
} else {
isedit.value = false;
dataIndex = null;
}
console.log(data);
show.value = true;
}
function close() {
show.value = false;
reset();
}
defineExpose({ open, close, reset, submit });
</script>

View File

@ -0,0 +1,125 @@
<template>
<div>
<el-form inline>
<el-form-item label="状态">
<el-select v-model="query.status" placeholder="请选择状态" style="width: 380px">
<el-option label="已发放" value="1"></el-option>
<el-option label="未发放" value="0"></el-option>
</el-select>
</el-form-item>
<el-form-item label="">
<el-input v-model="query.key" placeholder="请输入关键词" clearable @clear="handleSearch">
<template #prepend>
<el-select v-model="query.userType" placeholder="名称" style="width: 80px">
<el-option label="名称" value="name"></el-option>
</el-select>
</template>
</el-input>
</el-form-item>
<el-form-item label="">
<el-button type="primary" @click="handleSearch">搜索</el-button>
</el-form-item>
</el-form>
<div class="m-t-[10px]">
<div class="flex items-center gap-[40px]">
<div class="p-[30px] border-[1px] border-solid border-[#D9D9D9] rounded-[10px]">
<p class="color-[#4F535A]">发放总数量{{ summary.totalNum || 0 }}</p>
<p class="m-t-[12px] font-size-[24px] font-500 color-[#12161e]">
{{ summary.totalNum || 0 }}
</p>
</div>
<div class="p-[30px] border-[1px] border-solid border-[#D9D9D9] rounded-[10px]">
<p class="color-[#4F535A]">已使用优惠券</p>
<p class="m-t-[12px] font-size-[24px] font-500 color-[#12161e]">
{{ summary.usedNum || 0 }}
</p>
</div>
</div>
</div>
<div class="m-t-[20px]"></div>
<el-table :data="tableData.records" stripe>
<el-table-column label="Id" prop="id"></el-table-column>
<el-table-column label="用户">
<template #default="scope">
<div>
<el-link :underline="false" type="primary" class="no-wrap">
{{ scope.row.nickName }}
</el-link>
</div>
<div>
<el-link :underline="false" type="primary" class="no-wrap">
{{ scope.row.phone }}
</el-link>
</div>
</template>
</el-table-column>
<el-table-column label="生日日期" prop="birthday"></el-table-column>
<el-table-column label="赠送优惠券" prop="usedCouponList">
<template #default="scope">
<div class="flex gap-[10px]" v-for="item in scope.row.couponList" :key="item.id">
<span>{{ item.couponName }}</span>
<span>{{ item.num }}</span>
</div>
</template>
</el-table-column>
<el-table-column label="赠送时间" prop="createTime"></el-table-column>
<el-table-column label="已使用优惠券" prop="usedCouponList">
<template #default="scope">
<div class="flex gap-[10px]" v-for="item in scope.row.usedCouponList" :key="item.id">
<span>{{ item.couponName }}</span>
<span>{{ item.num }}</span>
</div>
</template>
</el-table-column>
</el-table>
<el-pagination
layout="total, sizes, prev, pager, next, jumper"
:total="tableData.totalRow"
:page-size="query.size"
@current-change="getData"
@size-change="getData"
/>
</div>
</template>
<script setup>
import { ref, reactive, watch, onMounted } from "vue";
import birthdayGiftApi from "@/api/market/birthdayGift";
const query = reactive({
status: "",
page: 1,
size: 10,
key: "",
});
const tableData = reactive({
records: [],
totalRow: 0,
});
function handleSearch() {
console.log(query);
query.page = 1;
getData();
}
const summary = ref({});
function getData() {
birthdayGiftApi.getRecord(query).then((res) => {
res.totalRow = res.totalRow * 1;
Object.assign(tableData, res);
});
birthdayGiftApi.getSummary(query).then((res) => {
console.log(res);
summary.value = res || {};
});
}
onMounted(getData);
</script>
<style scoped lang="scss">
:deep(.el-table th.el-table__cell) {
background-color: #f8f8f8;
}
</style>

View File

@ -1,3 +1,217 @@
<template>
<div>生日有礼</div>
</template>
<div class="m-4 bg-white p-4">
<HeaderCard
name="生日有礼"
intro="用户生日管理设置"
icon="birthdayGift"
showSwitch
v-model:isOpen="basicForm.isEnable"
></HeaderCard>
<el-tabs class="mt-4" v-model="activeTab" type="border-card">
<el-tab-pane :label="item.label" v-for="item in configs" :key="item.name" :name="item.name">
<template v-if="item.name == 'basic'">
<el-form ref="form" :model="basicForm">
<div class="u-m-b-10">
<el-button type="primary" @click="refDialogPlans.open()">添加</el-button>
</div>
<el-form-item label="">
<el-table :data="basicForm.configList" border style="width: 60%">
<el-table-column label="用户类型" align="center">
<template #default="scope">
{{ returnUserType(scope.row.userType) }}
</template>
</el-table-column>
<el-table-column label="赠送优惠券" align="center">
<template #default="scope">
<div v-for="item in scope.row.couponInfoList" :key="item.id">
<span>{{ item.title }}</span>
<span class="m-l-4">{{ item.num }} </span>
</div>
</template>
</el-table-column>
<el-table-column prop="is_auto_renew" label="发放时间" align="center">
<template #default="scope">
{{ returnDeliverDate(scope.row) }}
</template>
</el-table-column>
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button type="text" @click="editPlan(scope.row, scope.$index)">
编辑
</el-button>
<el-button type="text" style="color: red" @click="deletePlan(scope.row)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
<el-form-item label="短信祝福">
<el-switch
v-model="basicForm.sendSms"
:active-value="1"
:inactive-value="0"
></el-switch>
<span class="color-666 font-size-[12px] m-l-4">
开启后将会在用户生日当天发送祝福短信
</span>
</el-form-item>
<el-form-item label="短信内容">
<span class="color-666 font-size-[14px]">
亲爱的{用户昵称}[店铺名称]祝您生日快乐感谢您一直的陪伴为您准备了{num}张超值优惠券已经放入账户愿我们的礼物能为您增添一份喜悦
</span>
</el-form-item>
</el-form>
<div class="flex mt-10 justify-center gap-10">
<el-button
style="width: 100px"
type="primary"
@click="basicSubmit"
size="large"
v-if="shopInfo.isHeadShop"
>
保存
</el-button>
<el-button @click="close" style="width: 100px" size="large">取消</el-button>
</div>
</template>
<template v-if="item.name == 'record'">
<recordLists :recordList="recordList"></recordLists>
</template>
</el-tab-pane>
</el-tabs>
<DialogPlans ref="refDialogPlans" @submitSuccess="submitSuccess"></DialogPlans>
</div>
</template>
<script setup>
import { returnUserType } from "@/views/marketing_center/data.js";
import shopApi from "@/api/account/shop";
import birthdayGiftApi from "@/api/market/birthdayGift";
import HeaderCard from "../components/headerCard.vue";
import DialogPlans from "./components/dialog-plans.vue";
import recordLists from "./components/record-lists.vue";
import { ref, reactive, watch, toRaw, getCurrentInstance, onMounted } from "vue";
import { ElMessage } from "element-plus";
import { useRouter } from "vue-router";
const shopInfo = ref("");
const inputStyle = {
width: "340px",
};
const router = useRouter();
const refDialogPlans = ref();
const configs = [
{ name: "basic", label: "基础设置" },
{ name: "record", label: "发放记录" },
];
const activeTab = ref("basic");
const basicForm = reactive({
isEnable: 0,
sendSms: 0,
templateId: "",
configList: [],
});
function editPlan(row, index) {
refDialogPlans.value.open(toRaw(row), index);
}
function returnDeliverDate(row) {
if (row.deliverDate === "advance") {
return "提前" + row.deliverTime + "天";
}
if (row.deliverDate === "day") {
if (row.deliverTime != 0) {
return "提前" + Math.abs(row.deliverTime) + "天";
}
return "当天";
}
if (row.deliverDate === "mouth") {
return "生日前一天";
}
}
function deletePlan(row) {
const index = basicForm.configList.indexOf(row);
if (index > -1) {
basicForm.configList.splice(index, 1);
}
}
function submitSuccess(plans, index) {
if (!basicForm.configList) {
basicForm.configList = [];
}
if (index !== null && index !== undefined) {
basicForm.configList[index] = plans;
return;
}
basicForm.configList.push(plans);
}
//
function basicSubmit() {
const data = toRaw(basicForm);
console.log(data);
birthdayGiftApi.editConfig(data).then((res) => {
ElMessage.success("保存成功");
});
}
async function init() {
birthdayGiftApi.getConfig().then((res) => {
res.configList = res.configList || [];
Object.assign(basicForm, res);
basicForm.isEnable = basicForm.isEnable;
});
}
//
function getLocalShopInfo() {
shopInfo.value = JSON.parse(localStorage.getItem("userInfo"));
}
onMounted(() => {
init();
getLocalShopInfo();
});
//
function totalCount(arr) {
return arr.reduce((total, item) => {
return total + item.num * 1;
}, 0);
}
//
function levelExperienceValueMin(index, level) {
if (index == 0) {
return 0;
}
return levels.value[index - 1].experienceValue + 1;
}
//
function close() {
router.back();
}
//
function levelTabChange(index) {}
</script>
<style lang="scss" scoped>
:deep(.el-tabs--border-card) {
border: none;
}
:deep(.el-tabs--border-card > .el-tabs__header) {
border: none;
padding: 4px;
}
:deep(.el-tabs--border-card > .el-tabs__header .el-tabs__item) {
border: none;
}
:deep(.el-tabs--border-card > .el-tabs__header .el-tabs__item.is-active) {
border: none;
}
</style>

View File

@ -0,0 +1,17 @@
export const userTypes = [
{
label: "全部用户",
value: "all",
},
{
label: "非会员用户",
value: "non_vip",
},
{
label: "仅会员用户",
value: "vip",
},
];
export const returnUserType = (type) => {
return userTypes.find((item) => item.value === type)?.label;
};