猫妈狗爸伴宠师小程序后端代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

802 lines
29 KiB

<template>
<div class="app-container">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>价格配置管理</span>
<el-button style="float: right; padding: 3px 0" type="text" @click="handleSave">保存配置</el-button>
</div>
<el-form ref="priceForm" :model="priceConfig" :rules="rules" label-width="120px">
<!-- 基础价格配置 -->
<el-divider content-position="left">基础价格配置</el-divider>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="普通价格" prop="basePrice.normal">
<el-input-number
v-model="priceConfig.basePrice.normal"
:min="0"
:precision="2"
placeholder="请输入普通价格">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="节假日价格" prop="basePrice.holiday">
<el-input-number
v-model="priceConfig.basePrice.holiday"
:min="0"
:precision="2"
placeholder="请输入节假日价格">
</el-input-number>
</el-form-item>
</el-col>
<!-- <el-col :span="8">
<el-form-item label="每公里费用" prop="basePrice.perKm">
<el-input-number
v-model="priceConfig.basePrice.perKm"
:min="0"
:precision="2"
placeholder="请输入每公里费用">
</el-input-number>
</el-form-item>
</el-col> -->
</el-row>
<!-- 会员折扣配置 -->
<el-divider content-position="left">会员折扣配置</el-divider>
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="新晋家长折扣" prop="memberDiscount.new">
<el-input-number
v-model="priceConfig.memberDiscount.new"
:min="0"
:max="1"
:precision="2"
:step="0.05"
placeholder="折扣率">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="普卡会员折扣" prop="memberDiscount.regular">
<el-input-number
v-model="priceConfig.memberDiscount.regular"
:min="0"
:max="1"
:precision="2"
:step="0.05"
placeholder="折扣率">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="银卡会员折扣" prop="memberDiscount.silver">
<el-input-number
v-model="priceConfig.memberDiscount.silver"
:min="0"
:max="1"
:precision="2"
:step="0.05"
placeholder="折扣率">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="金卡会员折扣" prop="memberDiscount.gold">
<el-input-number
v-model="priceConfig.memberDiscount.gold"
:min="0"
:max="1"
:precision="2"
:step="0.05"
placeholder="折扣率">
</el-input-number>
</el-form-item>
</el-col>
</el-row>
<!-- 提前熟悉费用配置 -->
<el-divider content-position="left">提前熟悉费用配置</el-divider>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="基础价格" prop="preFamiliarize.price">
<el-input-number
v-model="priceConfig.preFamiliarize.price"
:min="0"
:precision="2"
placeholder="基础价格">
</el-input-number>
</el-form-item>
</el-col>
</el-row>
<!-- 多次服务费用配置 -->
<el-divider content-position="left">多次服务费用配置</el-divider>
<el-row :gutter="20">
<el-col :span="12">
<el-card class="box-card" style="margin-bottom: 20px;">
<div slot="header">
<span>一天两次服务</span>
</div>
<el-form-item label="基础费用" prop="multiService.two.price">
<el-input-number
v-model="priceConfig.multiService.two.price"
:min="0"
:precision="2"
placeholder="基础费用">
</el-input-number>
</el-form-item>
</el-card>
</el-col>
<el-col :span="12">
<el-card class="box-card" style="margin-bottom: 20px;">
<div slot="header">
<span>一天三次服务</span>
</div>
<el-form-item label="基础费用" prop="multiService.three.price">
<el-input-number
v-model="priceConfig.multiService.three.price"
:min="0"
:precision="2"
placeholder="基础费用">
</el-input-number>
</el-form-item>
</el-card>
</el-col>
</el-row>
<!-- 宠物额外费用配置 -->
<el-divider content-position="left">宠物额外费用配置</el-divider>
<el-row :gutter="20">
<el-col :span="6">
<el-card class="box-card" style="margin-bottom: 20px;">
<div slot="header">
<span>大型犬</span>
</div>
<el-form-item label="基础费用" prop="petExtra.largeDog.price" label-width="80px">
<el-input-number
v-model="priceConfig.petExtra.largeDog.price"
:min="0"
:precision="2"
placeholder="基础费用">
</el-input-number>
</el-form-item>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="box-card" style="margin-bottom: 20px;">
<div slot="header">
<span>中型犬</span>
</div>
<el-form-item label="基础费用" prop="petExtra.mediumDog.price" label-width="80px">
<el-input-number
v-model="priceConfig.petExtra.mediumDog.price"
:min="0"
:precision="2"
placeholder="基础费用">
</el-input-number>
</el-form-item>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="box-card" style="margin-bottom: 20px;">
<div slot="header">
<span>小型犬</span>
</div>
<el-form-item label="基础费用" prop="petExtra.smallDog.price" label-width="80px">
<el-input-number
v-model="priceConfig.petExtra.smallDog.price"
:min="0"
:precision="2"
placeholder="基础费用">
</el-input-number>
</el-form-item>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="box-card" style="margin-bottom: 20px;">
<div slot="header">
<span>猫</span>
</div>
<el-form-item label="基础费用" prop="petExtra.cat.price" label-width="80px">
<el-input-number
v-model="priceConfig.petExtra.cat.price"
:min="0"
:precision="2"
placeholder="基础费用">
</el-input-number>
</el-form-item>
</el-card>
</el-col>
</el-row>
<!-- 免费宠物数量配置 -->
<el-divider content-position="left">免费宠物数量配置</el-divider>
<el-row :gutter="20">
<el-col :span="24">
<el-alert
title="免费宠物数量配置说明"
type="info"
:closable="false"
show-icon>
<div slot="description">
配置每种宠物类型的免费数量,超出免费数量的宠物将按照对应的额外费用收费。
<br>例如:配置猫免费3只,用户有5只猫时,前3只免费,后2只按猫的额外费用收费。
</div>
</el-alert>
</el-col>
</el-row>
<!-- 免费宠物数量配置表格 -->
<el-card class="box-card" style="margin-bottom: 20px;">
<div slot="header">
<span>免费宠物数量配置</span>
</div>
<el-row :gutter="20">
<el-col :span="6">
<el-card class="box-card" style="margin-bottom: 20px;">
<div slot="header">
<span>猫</span>
</div>
<el-form-item label="免费数量" prop="freePetConfig.cat.freeCount" label-width="80px">
<el-input-number
v-model="priceConfig.freePetConfig.cat.freeCount"
:min="0"
placeholder="免费数量">
</el-input-number>
</el-form-item>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="box-card" style="margin-bottom: 20px;">
<div slot="header">
<span>小型犬</span>
</div>
<el-form-item label="免费数量" prop="freePetConfig.smallDog.freeCount" label-width="80px">
<el-input-number
v-model="priceConfig.freePetConfig.smallDog.freeCount"
:min="0"
placeholder="免费数量">
</el-input-number>
</el-form-item>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="box-card" style="margin-bottom: 20px;">
<div slot="header">
<span>中型犬</span>
</div>
<el-form-item label="免费数量" prop="freePetConfig.mediumDog.freeCount" label-width="80px">
<el-input-number
v-model="priceConfig.freePetConfig.mediumDog.freeCount"
:min="0"
placeholder="免费数量">
</el-input-number>
</el-form-item>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="box-card" style="margin-bottom: 20px;">
<div slot="header">
<span>大型犬</span>
</div>
<el-form-item label="免费数量" prop="freePetConfig.largeDog.freeCount" label-width="80px">
<el-input-number
v-model="priceConfig.freePetConfig.largeDog.freeCount"
:min="0"
placeholder="免费数量">
</el-input-number>
</el-form-item>
</el-card>
</el-col>
</el-row>
</el-card>
<!-- 节假日配置 -->
<el-divider content-position="left">节假日配置</el-divider>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="单个添加">
<el-date-picker
v-model="newHolidayDate"
type="date"
placeholder="选择日期"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
style="width: 100%">
</el-date-picker>
</el-form-item>
<el-button type="primary" size="small" @click="addHoliday" :disabled="!newHolidayDate">添加节假日</el-button>
</el-col>
<el-col :span="12">
<el-form-item label="批量添加">
<el-date-picker
v-model="batchHolidayDates"
type="dates"
placeholder="选择多个日期"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
style="width: 100%">
</el-date-picker>
</el-form-item>
<el-button type="success" size="small" @click="addBatchHolidays" :disabled="!batchHolidayDates || batchHolidayDates.length === 0">批量添加</el-button>
</el-col>
</el-row>
<!-- 节假日列表展示 -->
<el-card class="box-card" style="margin-bottom: 20px;">
<div slot="header">
<span>已配置的节假日列表 (共{{ holidayDates.length }}个)</span>
<el-button style="float: right; padding: 3px 0" type="text" @click="clearAllHolidays">清空所有</el-button>
</div>
<div v-if="holidayDates.length === 0" style="text-align: center; color: #999; padding: 20px;">
暂无配置的节假日
</div>
<div v-else>
<div v-for="(dates, month) in groupedHolidayDates" :key="month" style="margin-bottom: 20px;">
<h4 style="margin: 0 0 10px 0; color: #409EFF; border-bottom: 1px solid #EBEEF5; padding-bottom: 5px;">
{{ month }} ({{ dates.length }}个)
</h4>
<el-tag
v-for="date in dates"
:key="date"
closable
@close="removeHoliday(date)"
style="margin: 5px;">
{{ formatDate(date) }}
</el-tag>
</div>
</div>
</el-card>
<!-- 城市差异化配置 -->
<el-divider content-position="left">城市差异化配置</el-divider>
<el-row :gutter="20">
<el-col :span="24">
<el-alert
title="城市价格倍率配置说明"
type="info"
:closable="false"
show-icon>
<div slot="description">
各城市的价格倍率配置,用户下单时会根据其地址所在城市自动应用对应的倍率。
<br>例如:北京用户下单时,所有价格会自动乘以1.2倍。
</div>
</el-alert>
</el-col>
</el-row>
<!-- 城市价格倍率配置 -->
<el-card class="box-card" style="margin-bottom: 20px;">
<div slot="header">
<span>城市价格倍率配置</span>
<el-button style="float: right; padding: 3px 0" type="text" @click="addCity">添加城市</el-button>
</div>
<el-row :gutter="20">
<el-col :span="6" v-for="(rate, city) in priceConfig.cityConfig.priceRates" :key="city">
<el-form-item :label="getCityName(city)" :prop="`cityConfig.priceRates.${city}`">
<div style="display: flex; align-items: center;">
<el-input-number
v-model="priceConfig.cityConfig.priceRates[city]"
:min="0.5"
:max="2"
:precision="2"
:step="0.05"
size="mini"
style="flex: 1; margin-right: 8px;">
</el-input-number>
<el-button
v-if="city !== 'default'"
type="danger"
size="mini"
icon="el-icon-delete"
@click="removeCity(city)">
</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
</el-card>
</el-form>
<div style="text-align: center; margin-top: 20px;">
<el-button type="primary" @click="handleSave" :loading="saveLoading">保存配置</el-button>
<el-button @click="handleReset">重置</el-button>
</div>
</el-card>
</div>
</template>
<script>
import { listAppletConfig, getAppletConfig, addAppletConfig, updateAppletConfig } from "@/api/model/AppletConfig";
export default {
name: "PriceConfig",
data() {
return {
saveLoading: false,
holidayDates: [],
newHolidayDate: null,
batchHolidayDates: [],
// 价格配置数据
priceConfig: {
// 基础价格配置
basePrice: {
normal: 75, // 普通价格
holiday: 85, // 节假日价格
perKm: 3 // 每公里费用
},
// 会员折扣配置
memberDiscount: {
'new': 0.95, // 新晋家长9.5折
'regular': 0.9, // 普卡会员9折
'silver': 0.88, // 银卡会员8.8折
'gold': 0.85 // 金卡会员8.5折
},
// 提前熟悉费用配置
preFamiliarize: {
price: 40 // 基础价格
},
// 多次服务费用配置
multiService: {
two: {
price: 45 // 一天两次基础费用
},
three: {
price: 130 // 一天三次基础费用
}
},
// 宠物额外费用配置
petExtra: {
largeDog: {
price: 40 // 大型犬基础费用
},
mediumDog: {
price: 30 // 中型犬基础费用
},
smallDog: {
price: 15 // 小型犬基础费用
},
cat: {
price: 10 // 猫基础费用
}
},
// 免费宠物数量配置
freePetConfig: {
cat: {
freeCount: 3 // 猫免费数量
},
smallDog: {
freeCount: 2 // 小型犬免费数量
},
mediumDog: {
freeCount: 1 // 中型犬免费数量
},
largeDog: {
freeCount: 0 // 大型犬免费数量
}
},
// 节假日配置 - 后台配置的节假日列表
holidays: [
// 示例数据,实际从后台获取
'2024-07-15', '2024-07-16', '2024-07-17',
'2024-10-01', '2024-10-02', '2024-10-03'
],
// 城市差异化配置
cityConfig: {
priceRates: {
'北京': 1.2,
'上海': 1.15,
'广州': 1.1,
'深圳': 1.15,
'default': 1.0
}
}
},
// 表单验证规则
rules: {
'basePrice.normal': [
{ required: true, message: '请输入普通价格', trigger: 'blur' }
],
'basePrice.holiday': [
{ required: true, message: '请输入节假日价格', trigger: 'blur' }
],
'basePrice.perKm': [
{ required: true, message: '请输入每公里费用', trigger: 'blur' }
],
'freePetConfig.cat.freeCount': [
{ required: true, message: '请输入猫咪免费数量', trigger: 'blur' },
{ type: 'number', min: 0, message: '免费数量不能小于0', trigger: 'blur' }
],
'freePetConfig.smallDog.freeCount': [
{ required: true, message: '请输入小型犬免费数量', trigger: 'blur' },
{ type: 'number', min: 0, message: '免费数量不能小于0', trigger: 'blur' }
],
'freePetConfig.mediumDog.freeCount': [
{ required: true, message: '请输入中型犬免费数量', trigger: 'blur' },
{ type: 'number', min: 0, message: '免费数量不能小于0', trigger: 'blur' }
],
'freePetConfig.largeDog.freeCount': [
{ required: true, message: '请输入大型犬免费数量', trigger: 'blur' },
{ type: 'number', min: 0, message: '免费数量不能小于0', trigger: 'blur' }
]
}
};
},
created() {
this.getPriceConfig();
},
computed: {
// 按月份分组的节假日日期
groupedHolidayDates() {
const groups = {};
const sortedDates = [...this.holidayDates].sort();
sortedDates.forEach(date => {
const month = this.getMonthName(date);
if (!groups[month]) {
groups[month] = [];
}
groups[month].push(date);
});
return groups;
}
},
methods: {
// 获取价格配置
async getPriceConfig() {
try {
// 查询价格配置参数
const response = await listAppletConfig({ paramCode: 'price_config' });
if (response.rows && response.rows.length > 0) {
const config = response.rows[0];
if (config.paramValueText) {
const savedConfig = JSON.parse(config.paramValueText);
// 合并配置,确保新字段有默认值
this.priceConfig = {
...this.priceConfig,
...savedConfig
};
// 确保freePetConfig字段存在
if (!this.priceConfig.freePetConfig) {
this.priceConfig.freePetConfig = {
cat: { freeCount: 3 },
smallDog: { freeCount: 2 },
mediumDog: { freeCount: 1 },
largeDog: { freeCount: 0 }
};
}
// 设置节假日日期
this.holidayDates = this.priceConfig.holidays || [];
}
}
} catch (error) {
console.error('获取价格配置失败:', error);
this.$message.error('获取价格配置失败');
}
},
// 保存配置
async handleSave() {
try {
this.$refs.priceForm.validate(async (valid) => {
if (valid) {
this.saveLoading = true;
// 更新节假日列表
this.priceConfig.holidays = this.holidayDates;
// 准备保存的数据
const saveData = {
paramCode: 'price_config',
paramValue: '价格配置',
paramValueText: JSON.stringify(this.priceConfig, null, 2)
};
// 查询是否已存在配置
const response = await listAppletConfig({ paramCode: 'price_config' });
if (response.rows && response.rows.length > 0) {
// 更新现有配置
saveData.id = response.rows[0].id;
await updateAppletConfig(saveData);
} else {
// 新增配置
await addAppletConfig(saveData);
}
this.$message.success('价格配置保存成功');
this.saveLoading = false;
}
});
} catch (error) {
console.error('保存价格配置失败:', error);
this.$message.error('保存价格配置失败');
this.saveLoading = false;
}
},
// 重置配置
handleReset() {
this.$confirm('确定要重置所有配置吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.getPriceConfig();
this.$message.success('配置已重置');
});
},
// 获取城市名称
getCityName(city) {
if (city === 'default') {
return '默认';
}
return city;
},
// 添加城市
addCity() {
this.$prompt('请输入城市名称', '添加城市', {
confirmButtonText: '确定',
cancelButtonText: '取消',
inputPattern: /^[\u4e00-\u9fa5]+$/,
inputErrorMessage: '请输入中文城市名称'
}).then(({ value }) => {
if (this.priceConfig.cityConfig.priceRates[value]) {
this.$message.warning('该城市已存在');
return;
}
this.$set(this.priceConfig.cityConfig.priceRates, value, 1.0);
this.$message.success('城市添加成功');
}).catch(() => {
// 用户取消
});
},
// 删除城市
removeCity(city) {
this.$confirm(`确定要删除城市"${this.getCityName(city)}"吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$delete(this.priceConfig.cityConfig.priceRates, city);
this.$message.success('城市删除成功');
}).catch(() => {
// 用户取消
});
},
// 添加节假日
addHoliday() {
if (!this.newHolidayDate) {
this.$message.warning('请先选择日期');
return;
}
if (this.holidayDates.includes(this.newHolidayDate)) {
this.$message.warning('该日期已存在');
return;
}
this.holidayDates.push(this.newHolidayDate);
this.newHolidayDate = null;
this.$message.success('节假日添加成功');
},
// 删除节假日
removeHoliday(date) {
const index = this.holidayDates.indexOf(date);
if (index > -1) {
this.holidayDates.splice(index, 1);
this.$message.success('节假日删除成功');
}
},
// 清空所有节假日
clearAllHolidays() {
this.$confirm('确定要清空所有节假日吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.holidayDates = [];
this.$message.success('所有节假日已清空');
}).catch(() => {
// 用户取消
});
},
// 格式化日期显示
formatDate(dateStr) {
const date = new Date(dateStr);
const month = date.getMonth() + 1;
const day = date.getDate();
const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
const weekday = weekdays[date.getDay()];
return `${month}${day}日(${weekday})`;
},
// 获取月份名称
getMonthName(dateStr) {
const date = new Date(dateStr);
const year = date.getFullYear();
const month = date.getMonth() + 1;
return `${year}${month}`;
},
// 批量添加节假日
addBatchHolidays() {
if (!this.batchHolidayDates || this.batchHolidayDates.length === 0) {
this.$message.warning('请先选择要添加的日期');
return;
}
let addedCount = 0;
let duplicateCount = 0;
this.batchHolidayDates.forEach(date => {
if (!this.holidayDates.includes(date)) {
this.holidayDates.push(date);
addedCount++;
} else {
duplicateCount++;
}
});
this.batchHolidayDates = [];
if (addedCount > 0) {
this.$message.success(`成功添加${addedCount}个节假日`);
}
if (duplicateCount > 0) {
this.$message.warning(`${duplicateCount}个日期已存在,已跳过`);
}
}
}
};
</script>
<style scoped>
.box-card {
margin-bottom: 20px;
}
.el-divider {
margin: 20px 0;
}
.el-form-item {
margin-bottom: 18px;
}
.small-img {
width: 50px;
height: 50px;
}
.circle-img {
border-radius: 50%;
}
.dialog-form-one .el-form-item {
width: 100%;
}
.dialog-form-one .el-form-item .el-form-item__content {
width: calc(100% - 120px);
}
.dialog-form-one .el-form-item .el-input,
.dialog-form-one .el-form-item .el-select {
width: 100%;
}
</style>