feat: 同城配送模块

This commit is contained in:
lzhizhao 2025-10-29 17:22:57 +08:00
parent ff60bd5719
commit 553bd5cd89
2 changed files with 648 additions and 1 deletions

View File

@ -727,5 +727,30 @@ export const mer_admin = {
params: query,
data: data
});
},
// ==================== 同城配送配置相关接口 ====================
/**
* 获取同城配送配置
* @param {object} data 查询参数
* @param {number} data.marketId 市场ID
* @returns {Promise}
*/
getCityDeliveryConfig: data => {
return $http.request({
method: "get",
url: `/merchant-api/city/delivery/config/detail`,
params: data
});
},
/**
* 保存同城配送配置
* @param {object} data 配置数据
* @returns {Promise}
*/
saveCityDeliveryConfig: data => {
return $http.post(`/merchant-api/city/delivery/config/save`, data);
}
};

View File

@ -1,3 +1,625 @@
<template>
<div>同城运费配置</div>
<div class="page-container">
<div class="form-container">
<el-form
ref="formRef"
:model="formModel"
:rules="formRules"
label-width="180px"
size="small"
>
<!-- 同城配送开关 -->
<div class="section-header">
<el-divider content-position="left">
<span class="section-title">同城配送开关</span>
</el-divider>
<el-button
type="text"
size="small"
class="help-btn"
@click="openDescModal('CityDeliverySwitch')"
>
<i class="el-icon-question"></i> 字段说明
</el-button>
</div>
<el-form-item label="是否开启同城配送" prop="isEnable">
<el-switch
v-model="formModel.isEnable"
:active-value="1"
:inactive-value="0"
active-text="已开启"
inactive-text="未开启"
/>
</el-form-item>
<!-- 基础配置 -->
<div class="section-header">
<el-divider content-position="left">
<span class="section-title">基础配置</span>
</el-divider>
<el-button
type="text"
size="small"
class="help-btn"
@click="openDescModal('Base')"
>
<i class="el-icon-question"></i> 字段说明
</el-button>
</div>
<el-form-item label="订单包装费" prop="orderPackagePrice">
<el-input
v-model="formModel.orderPackagePrice"
placeholder="请输入数字,支持两位小数"
style="width: 200px"
>
<template slot="append">/</template>
</el-input>
</el-form-item>
<el-form-item label="订单起送价" prop="minOrderPrice">
<el-input
v-model="formModel.minOrderPrice"
placeholder="请输入数字,支持两位小数"
style="width: 200px"
>
<template slot="append">/</template>
</el-input>
</el-form-item>
<el-form-item label="最大配送距离" prop="maxDeliveryDistance">
<el-input
v-model="formModel.maxDeliveryDistance"
placeholder="请输入数字"
style="width: 200px"
>
<template slot="append">公里</template>
</el-input>
</el-form-item>
<el-form-item label="承诺订单送达时间" prop="maxDeliveryTime">
<el-input
v-model="formModel.maxDeliveryTime"
placeholder="请输入数字"
style="width: 200px"
>
<template slot="append">小时以内</template>
</el-input>
</el-form-item>
<!-- 运费收益方 -->
<div class="section-header">
<el-divider content-position="left">
<span class="section-title">运费收益方</span>
</el-divider>
<el-button
type="text"
size="small"
class="help-btn"
@click="openDescModal('DeliveryProfitSide')"
>
<i class="el-icon-question"></i> 字段说明
</el-button>
</div>
<el-form-item label="运费收益方" prop="deliveryProfitSide">
<el-select
v-model="formModel.deliveryProfitSide"
placeholder="请选择运费收益方"
style="width: 200px"
>
<el-option label="市场经营者" :value="1" />
<el-option label="专员" :value="2" />
</el-select>
</el-form-item>
<!-- 运费计算 -->
<div class="section-header">
<el-divider content-position="left">
<span class="section-title">运费计算</span>
</el-divider>
<el-button
type="text"
size="small"
class="help-btn"
@click="openDescModal('SelfDeliver')"
>
<i class="el-icon-question"></i> 字段说明
</el-button>
</div>
<el-form-item label="运费模式" prop="deliveryPriceMode">
<el-select
v-model="formModel.deliveryPriceMode"
placeholder="请选择运费模式"
style="width: 200px"
>
<el-option label="距离运费" value="DISTANCE" />
<el-option label="固定运费" value="FIX" />
</el-select>
</el-form-item>
<template v-if="formModel.deliveryPriceMode === 'DISTANCE'">
<el-form-item label="配送起步价" prop="basicDeliveryDistance">
<el-input
v-model="formModel.basicDeliveryDistance"
placeholder="请输入数字"
style="width: 200px"
>
<template slot="append">公里内</template>
</el-input>
</el-form-item>
<el-form-item label="" prop="basicDeliveryPrice">
<el-input
v-model="formModel.basicDeliveryPrice"
placeholder="请输入数字,支持两位小数"
style="width: 200px"
>
<template slot="append"></template>
</el-input>
</el-form-item>
<el-form-item label="每+0.1公里加收" prop="addDeliveryPrice">
<el-input
v-model="formModel.addDeliveryPrice"
placeholder="请输入数字,支持两位小数"
style="width: 200px"
>
<template slot="append"></template>
</el-input>
</el-form-item>
</template>
<template v-if="formModel.deliveryPriceMode === 'FIX'">
<el-form-item label="配送费用" prop="fixDeliveryPrice">
<el-input
v-model="formModel.fixDeliveryPrice"
placeholder="请输入数字,支持两位小数"
style="width: 200px"
>
<template slot="append"></template>
</el-input>
</el-form-item>
</template>
<!-- 免运费条件 -->
<div class="section-header">
<el-divider content-position="left">
<span class="section-title">免运费条件</span>
</el-divider>
<el-button
type="text"
size="small"
class="help-btn"
@click="openDescModal('FreeDelivery')"
>
<i class="el-icon-question"></i> 字段说明
</el-button>
</div>
<el-form-item label="订单满额免运费" prop="isFreeDelivery">
<el-switch
v-model="formModel.isFreeDelivery"
:active-value="1"
:inactive-value="0"
active-text="已开启"
inactive-text="已关闭"
/>
</el-form-item>
<el-form-item
v-if="formModel.isFreeDelivery"
label="订单满"
prop="freeDeliveryOrderPrice"
>
<el-input
v-model="formModel.freeDeliveryOrderPrice"
placeholder="请输入数字"
style="width: 200px"
>
<template slot="append">免运费</template>
</el-input>
</el-form-item>
<el-form-item class="form-actions">
<el-button @click="handleCancel" size="medium">取消</el-button>
<el-button
type="primary"
@click="handleSubmit"
:loading="loading"
size="medium"
>
提交
</el-button>
</el-form-item>
</el-form>
</div>
<!-- 字段说明弹窗 -->
<el-dialog :title="descTitle" :visible.sync="descVisible" width="600px">
<el-descriptions :column="1" border>
<el-descriptions-item
v-for="(item, index) in descList"
:key="index"
:label="item.label"
:label-class-name="'desc-label'"
>
<div style="line-height: 1.6" v-html="item.desc"></div>
</el-descriptions-item>
</el-descriptions>
<div slot="footer">
<el-button type="primary" @click="descVisible = false">
知道了
</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { mer_admin } from "@/api/modules/mer_admin.js";
export default {
name: "CityDeliveryConfig",
data() {
//
const validatePrice = (rule, value, callback) => {
if (!value && value !== 0) {
callback(new Error("请输入价格"));
return;
}
const pattern = /^\d+(\.\d{1,2})?$/;
if (pattern.test(value)) {
callback();
} else {
callback(new Error("请输入数字,支持两位小数"));
}
};
//
const validateNumber = (rule, value, callback) => {
if (!value && value !== 0) {
callback(new Error("请输入数字"));
return;
}
if (/^\d+$/.test(value)) {
callback();
} else {
callback(new Error("请输入整数"));
}
};
return {
loading: false,
formModel: {
isEnable: 1,
id: undefined,
orderPackagePrice: "",
minOrderPrice: "",
maxDeliveryDistance: "",
maxDeliveryTime: "",
basicDeliveryDistance: "",
basicDeliveryPrice: "",
addDeliveryPrice: "",
fixDeliveryPrice: "",
deliveryPriceMode: "DISTANCE",
freeDeliveryOrderPrice: "",
deliveryProfitSide: "",
isFreeDelivery: 0
},
formRules: {
isEnable: [
{ required: true, message: "请选择是否开启", trigger: "change" }
],
orderPackagePrice: [
{ required: true, validator: validatePrice, trigger: "blur" }
],
minOrderPrice: [
{ required: true, validator: validatePrice, trigger: "blur" }
],
maxDeliveryDistance: [
{ required: true, validator: validateNumber, trigger: "blur" }
],
maxDeliveryTime: [
{ required: true, validator: validateNumber, trigger: "blur" }
],
deliveryProfitSide: [
{ required: true, message: "请选择运费收益方", trigger: "change" }
],
deliveryPriceMode: [
{ required: true, message: "请选择运费模式", trigger: "change" }
],
basicDeliveryDistance: [{ validator: validateNumber, trigger: "blur" }],
basicDeliveryPrice: [{ validator: validatePrice, trigger: "blur" }],
addDeliveryPrice: [{ validator: validatePrice, trigger: "blur" }],
fixDeliveryPrice: [{ validator: validatePrice, trigger: "blur" }],
freeDeliveryOrderPrice: [{ validator: validatePrice, trigger: "blur" }]
},
//
descVisible: false,
descTitle: "",
descList: []
};
},
computed: {
marketId() {
return this.$store.state.userData.marketId;
}
},
mounted() {
this.fetchData();
},
methods: {
//
async fetchData() {
try {
this.loading = true;
const res = await mer_admin.getCityDeliveryConfig({
marketId: this.marketId
});
console.log("同城配送配置返回:", res);
// res.data.data res.data
let data = null;
if (res.data && res.data.data !== undefined) {
data = res.data.data;
} else if (res.data) {
data = res.data;
}
console.log("同城配送配置数据:", data);
//
if (data && typeof data === "object" && data !== null) {
Object.assign(this.formModel, {
...data,
isEnable: Number(data.isEnable) || 0,
isFreeDelivery: Number(data.isFreeDelivery) || 0,
freeDeliveryOrderPrice:
data.freeDeliveryOrderPrice || data.freeDeliveryOrderPrice === 0
? data.freeDeliveryOrderPrice
: ""
});
} else {
console.log("暂无配置数据,使用默认值");
}
} catch (error) {
console.error("获取数据失败:", error);
this.$message.error("获取配置失败");
} finally {
this.loading = false;
}
},
//
handleSubmit() {
this.$refs.formRef.validate(async valid => {
if (!valid) return;
try {
this.loading = true;
const params = {
marketId: this.marketId,
...this.formModel
};
console.log("提交同城配送配置:", params);
const res = await mer_admin.saveCityDeliveryConfig(params);
console.log("保存返回:", res);
this.$message.success("保存成功");
this.fetchData();
} catch (error) {
console.error("保存失败:", error);
this.$message.error("保存失败");
} finally {
this.loading = false;
}
});
},
//
handleCancel() {
this.$confirm("退出将不对此页面内容进行保存,是否确认退出?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$router.go(-1);
})
.catch(() => {});
},
//
openDescModal(type) {
const descEnum = {
CityDeliverySwitch: {
title: "同城配送设置-同城配送开关-字段说明",
descList: [
{
label: "是否开启同城配送",
desc:
"开启后,顾客才可以选择【同城配送】方式下单;关闭后,所有顾客均无法选择【同城配送】方式下单。"
}
]
},
FreeDelivery: {
title: "同城配送设置-免运费条件-字段说明",
descList: [
{
label: "订单满额免运费",
desc: "开启后,顾客订单金额满足此条件,即可免运费。"
}
]
},
DeliveryProfitSide: {
title: "同城配送设置-运费收益方-字段说明",
descList: [
{
label: "运费收益方",
desc:
"顾客支付的运费,将由哪一方获得;若选择【市场经营者】,则顾客支付的运费,将由市场经营者获得;若选择【专员】,则顾客支付的运费,将由专员获得。"
}
]
},
Base: {
title: "同城配送设置-基础配置-字段说明",
descList: [
{
label: "订单包装费",
desc:
"通过【同城配送】方式下的订单,顾客需要为每个订单额外支付的包装费用。"
},
{
label: "订单起送价",
desc:
"订单的实付金额若不满足此条件,无法通过【同城配送】方式下订单。"
},
{
label: "订单配送费",
desc:
"通过【同城配送】方式下的订单,顾客需要为每个订单额外支付的配送费用。"
},
{
label: "最大配送距离",
desc:
"若顾客收货地址距离市场定位的距离超出此条件,将无法通过【同城配送】方式下单。"
},
{
label: "承诺订单送达时间",
desc:
"顾客通过【同城配送】方式下单后,承诺在此配置时间内送达,请根据实际情况配置。"
}
]
},
SelfDeliver: {
title: "同城配送设置-运费计算-字段说明",
descList: [
{
label: "配送起步价",
desc:
"配送费的起步价举例起步价为3公里内3元配送3公里内的订单在订单完成后将获得3元配送费。"
},
{
label: "每+0.1公里加收",
desc:
"配送距离超出起步价公里数每超出0.1公里加收的配送费举例起步价为3公里内3元每超出0.1公里加收0.3元配送一单3.5公里的订单在订单完成后将获得3+(3.5-3)/0.1*0.3=4.5元配送费。"
}
]
}
};
const config = descEnum[type];
this.descTitle = config.title;
this.descList = config.descList;
this.descVisible = true;
}
}
};
</script>
<style lang="scss" scoped>
.page-container {
padding: 0;
background-color: #f5f7fa;
min-height: 100vh;
}
.form-container {
background-color: #fff;
padding: 30px 40px;
margin: 0;
}
.section-header {
position: relative;
margin-top: 30px;
margin-bottom: 20px;
&:first-child {
margin-top: 0;
}
.el-divider {
margin: 0;
}
.section-title {
font-size: 16px;
font-weight: 600;
color: #303133;
}
.help-btn {
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
padding: 0;
color: #909399;
&:hover {
color: #409eff;
}
i {
margin-right: 4px;
}
}
}
::v-deep .el-form-item {
margin-bottom: 24px;
.el-form-item__label {
font-weight: 500;
color: #606266;
}
.el-form-item__content {
line-height: 32px;
}
}
.form-actions {
margin-top: 40px;
padding-top: 20px;
border-top: 1px solid #ebeef5;
::v-deep .el-form-item__content {
text-align: center;
}
.el-button {
min-width: 100px;
margin: 0 10px;
}
}
.desc-label {
width: 150px;
font-weight: 500;
}
::v-deep .el-descriptions-item__label {
font-weight: 500;
background-color: #fafafa;
}
::v-deep .el-switch {
.el-switch__label {
color: #606266;
font-weight: normal;
&.is-active {
color: #409eff;
}
}
}
</style>