| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738 |
- <!--
- 用途:配送方式配置页面
- 谁用:供货商管理员
- 解决什么问题:配置送货、自取、跑腿、快递、物流等配送方式的起送条件、计费规则、说明项等。
- -->
- <template>
- <view class="sh-method-page app-content">
- <!-- 顶部 Tab 切换 -->
- <view class="tab-bar">
- <view
- v-for="(tab, index) in tabs"
- :key="index"
- class="tab-item"
- :class="{ active: tabIndex === index }"
- @click="changeTab(index)"
- >
- {{ tab.name }}
- </view>
- </view>
- <!-- 配置表单区域 -->
- <scroll-view scroll-y class="form-scroll">
- <view class="form-container">
- <!-- 别名 -->
- <tui-list-cell class="line-cell" :hover="false">
- <view class="tui-title">别名</view>
- <input type="text" v-model="form.alias" class="tui-input" placeholder="请填写别名" />
- </tui-list-cell>
- <!-- 状态 -->
- <tui-list-cell class="line-cell" :hover="false">
- <view class="tui-title">状态</view>
- <view class="btn-group">
- <button
- class="admin-button-com middle"
- :class="[form.status == 1 ? 'blue' : 'default']"
- @click="form.status = 1"
- >
- 启用
- </button>
- <button
- class="admin-button-com middle"
- :class="[form.status == 0 ? 'blue' : 'default']"
- @click="form.status = 0"
- style="margin-left: 20upx;"
- >
- 禁用
- </button>
- </view>
- </tui-list-cell>
- <!-- 顺序 -->
- <tui-list-cell class="line-cell" :hover="false">
- <view class="tui-title">顺序</view>
- <input type="number" v-model="form.sort" class="tui-input" placeholder="请填写顺序" />
- </tui-list-cell>
- <!-- 送货 / 快递 特有字段 -->
- <block v-if="tabIndex === 0 || tabIndex === 3">
- <tui-list-cell class="line-cell" :hover="false">
- <view class="tui-title">最低消费金额</view>
- <input type="digit" v-model="form.minAmount" class="tui-input" placeholder="不限制填0" />
- </tui-list-cell>
- <tui-list-cell class="line-cell" :hover="false">
- <view class="tui-title">最低消费数量</view>
- <input type="number" v-model="form.minNum" class="tui-input" placeholder="不限制填0" />
- </tui-list-cell>
- <tui-list-cell class="line-cell" :hover="false">
- <view class="tui-title">不满条件</view>
- <view class="btn-group">
- <button
- class="admin-button-com middle"
- :class="[form.unMeet == 0 ? 'blue' : 'default']"
- @click="form.unMeet = 0"
- >
- 收运费
- </button>
- <button
- class="admin-button-com middle"
- :class="[form.unMeet == 2 ? 'blue' : 'default']"
- @click="form.unMeet = 2"
- style="margin-left: 10upx;"
- >
- 收包装费
- </button>
- <button
- class="admin-button-com middle"
- :class="[form.unMeet == 1 ? 'blue' : 'default']"
- @click="form.unMeet = 1"
- style="margin-left: 10upx;"
- >
- 不能买
- </button>
- </view>
- </tui-list-cell>
- <tui-list-cell class="line-cell" :hover="false" v-if="form.unMeet != 1">
- <view class="tui-title">{{ form.unMeet == 2 ? '包装费' : '运费' }}</view>
- <input type="digit" v-model="form.unMeetFee" class="tui-input" placeholder="请填写金额" />
- </tui-list-cell>
- </block>
- <!-- 跑腿 特有字段 -->
- <block v-if="tabIndex === 2">
- <!-- 满减规则 -->
- <view class="section-header">
- <text class="section-title">满减规则</text>
- <button class="admin-button-com mini blue" @click="addReduceRule">添加</button>
- </view>
- <view class="rule-list" v-if="form.reduceRules && form.reduceRules.length > 0">
- <view class="rule-card" v-for="(rule, index) in form.reduceRules" :key="index">
- <view class="rule-row">
- <text class="rule-label">需</text>
- <input type="number" v-model="rule.meetNum" class="rule-input" placeholder="0" />
- <text class="rule-label">扎,且</text>
- <input type="digit" v-model="rule.meetAmount" class="rule-input-large" placeholder="0.00" />
- <text class="rule-label">元,</text>
- <input type="digit" v-model="rule.freeKm" class="rule-input-large" placeholder="0" />
- <text class="rule-label">公里内免跑腿费</text>
- </view>
- <button class="admin-button-com mini default rule-del-btn" @click="removeReduceRule(index)">
- 删除
- </button>
- </view>
- </view>
- <view class="no-data-tip" v-else>暂无满减规则</view>
- <view class="notice-text">
- 不符合满减规则时,将通过跑腿计算运费,跑腿无法使用时,将使用自定义计费
- </view>
- <!-- 自定义计费 -->
- <view class="section-header">
- <text class="section-title">自定义计费</text>
- </view>
- <tui-list-cell class="line-cell" :hover="false">
- <view class="tui-title">起步价</view>
- <view class="input-row">
- <input type="digit" v-model="form.startKm" class="tui-input-sm" placeholder="0" />
- <text class="unit-text">km内</text>
- <input type="digit" v-model="form.startPrice" class="tui-input-sm" placeholder="0.00" />
- <text class="unit-text">元</text>
- </view>
- </tui-list-cell>
- <tui-list-cell class="line-cell" :hover="false">
- <view class="tui-title">超出起步</view>
- <view class="input-row">
- <text class="unit-text">每公里加</text>
- <input type="digit" v-model="form.perKmPrice" class="tui-input-sm" placeholder="0.00" />
- <text class="unit-text">元</text>
- </view>
- </tui-list-cell>
- <tui-list-cell class="line-cell" :hover="false">
- <view class="tui-title">临时涨价</view>
- <view class="input-row">
- <input type="digit" v-model="form.changeRate" class="tui-input-sm" placeholder="0" />
- <text class="unit-text">%</text>
- </view>
- </tui-list-cell>
- </block>
- <!-- 物流 特有字段 -->
- <block v-if="tabIndex === 4">
- <tui-list-cell class="line-cell" :hover="false">
- <view class="tui-title">配送物流</view>
- <button class="admin-button-com middle blue" @click="manageWl">添加 / 管理</button>
- </tui-list-cell>
- </block>
- <!-- 说明项区域圈起来 -->
- <view class="explain-section-wrapper">
- <view class="section-header no-margin">
- <text class="section-title">说明</text>
- <button class="admin-button-com mini blue" @click="addExplain">添加</button>
- </view>
- <view class="explain-list" v-if="form.explains && form.explains.length > 0">
- <view class="explain-card" v-for="(exp, index) in form.explains" :key="index">
- <textarea
- v-model="exp.explain"
- class="explain-textarea"
- placeholder="最多50字"
- maxlength="50"
- :class="[
- exp.color == 2 ? 'text-red' : '',
- exp.color == 3 ? 'text-blue' : '',
- exp.fontWeight == 2 ? 'text-bold' : ''
- ]"
- />
- <view class="explain-actions">
- <view class="action-group">
- <button
- class="admin-button-com mini"
- :class="[exp.color == 1 ? 'blue' : 'default']"
- @click="setExplainColor(index, 1)"
- >
- 黑色
- </button>
- <button
- class="admin-button-com mini"
- :class="[exp.color == 2 ? 'blue' : 'default']"
- @click="setExplainColor(index, 2)"
- style="margin-left: 10upx;"
- >
- 红色
- </button>
- <button
- class="admin-button-com mini"
- :class="[exp.color == 3 ? 'blue' : 'default']"
- @click="setExplainColor(index, 3)"
- style="margin-left: 10upx;"
- >
- 蓝色
- </button>
- </view>
- <view class="action-group" style="margin-left: 20upx;">
- <button
- class="admin-button-com mini"
- :class="[exp.fontWeight == 1 ? 'blue' : 'default']"
- @click="setExplainWeight(index, 1)"
- >
- 常规
- </button>
- <button
- class="admin-button-com mini"
- :class="[exp.fontWeight == 2 ? 'blue' : 'default']"
- @click="setExplainWeight(index, 2)"
- style="margin-left: 10upx;"
- >
- 加粗
- </button>
- </view>
- <button class="admin-button-com mini default explain-del-btn" @click="removeExplain(index)">
- 删除
- </button>
- </view>
- </view>
- </view>
- <view class="no-data-tip" v-else>暂无说明项</view>
- </view>
- </view>
- </scroll-view>
- <!-- 底部保存按钮 -->
- <view class="footer-btn-wrap">
- <button class="admin-button-com big blue" @click="submitSave">保存</button>
- </view>
- </view>
- </template>
- <script>
- import TuiListCell from "@/components/plugin/list-cell";
- import { getShMethodConfig, saveShMethodConfig } from "@/api/sh-method";
- export default {
- name: "shMethod",
- components: {
- TuiListCell
- },
- data() {
- return {
- tabs: [
- { name: "送货", value: 0 },
- { name: "自取", value: 1 },
- { name: "跑腿", value: 2 },
- { name: "快递", value: 3 },
- { name: "物流", value: 4 }
- ],
- tabIndex: 0,
- form: {
- id: 0,
- style: 0,
- alias: "",
- status: 1,
- sort: 0,
- minAmount: 0.00,
- minNum: 0,
- unMeet: 0,
- unMeetFee: 0.00,
- startKm: 0.00,
- startPrice: 0.00,
- perKmPrice: 0.00,
- changeRate: 0.00,
- explains: [],
- reduceRules: []
- }
- };
- },
- onLoad() {
- this.loadConfig(0);
- },
- methods: {
- /**
- * 切换 Tab
- * @param {number} index - 选中的 Tab 索引
- */
- changeTab(index) {
- if (this.tabIndex === index) return;
- this.tabIndex = index;
- this.loadConfig(index);
- },
- /**
- * 加载当前配送方式配置
- * @param {number} style - 配送类型 (0-4)
- */
- loadConfig(style) {
- uni.showLoading({ title: "加载中" });
- getShMethodConfig({ style })
- .then(res => {
- uni.hideLoading();
- if (res.code == 1 && res.data) {
- const data = res.data;
- this.form = {
- id: data.id || 0,
- style: style,
- alias: data.alias || "",
- status: data.status != null ? Number(data.status) : 1,
- sort: data.sort != null ? Number(data.sort) : 0,
- minAmount: data.minAmount != null ? parseFloat(data.minAmount) : 0.00,
- minNum: data.minNum != null ? Number(data.minNum) : 0,
- unMeet: data.unMeet != null ? Number(data.unMeet) : 0,
- unMeetFee: data.unMeetFee != null ? parseFloat(data.unMeetFee) : 0.00,
- startKm: data.startKm != null ? parseFloat(data.startKm) : 0.00,
- startPrice: data.startPrice != null ? parseFloat(data.startPrice) : 0.00,
- perKmPrice: data.perKmPrice != null ? parseFloat(data.perKmPrice) : 0.00,
- changeRate: data.changeRate != null ? parseFloat(data.changeRate) : 0.00,
- explains: (data.explains || []).map(exp => ({
- ...exp,
- color: exp.color != null ? Number(exp.color) : 1,
- fontWeight: exp.fontWeight != null ? Number(exp.fontWeight) : 1
- })),
- reduceRules: data.reduceRules || []
- };
- } else {
- this.$msg(res.msg || "加载失败");
- }
- })
- .catch(err => {
- uni.hideLoading();
- this.$msg("加载失败,请重试");
- });
- },
- /**
- * 添加满减规则
- */
- addReduceRule() {
- this.form.reduceRules.push({
- meetNum: 0,
- meetAmount: 0.00,
- freeKm: 0,
- sort: this.form.reduceRules.length
- });
- },
- /**
- * 删除满减规则
- * @param {number} index - 规则索引
- */
- removeReduceRule(index) {
- this.form.reduceRules.splice(index, 1);
- },
- /**
- * 添加说明项
- */
- addExplain() {
- this.form.explains.push({
- explain: "",
- color: 1, // 1: 黑色, 2: 红色, 3: 蓝色
- fontWeight: 1, // 1: 常规, 2: 加粗
- sort: this.form.explains.length
- });
- },
- /**
- * 删除说明项
- * @param {number} index - 说明索引
- */
- removeExplain(index) {
- this.$util.confirmModal({ content: "确认删除该说明吗?" }, () => {
- this.form.explains.splice(index, 1);
- });
- },
- /**
- * 设置说明项颜色
- * @param {number} index - 说明项索引
- * @param {number} color - 颜色值 (1: 黑色, 2: 红色, 3: 蓝色)
- */
- setExplainColor(index, color) {
- const exp = this.form.explains[index];
- if (exp) {
- exp.color = color;
- // 强制触发 Vue 2 数组/对象响应式更新
- this.$set(this.form.explains, index, { ...exp });
- }
- },
- /**
- * 设置说明项字重
- * @param {number} index - 说明项索引
- * @param {number} fontWeight - 字重值 (1: 常规, 2: 加粗)
- */
- setExplainWeight(index, fontWeight) {
- const exp = this.form.explains[index];
- if (exp) {
- exp.fontWeight = fontWeight;
- // 强制触发 Vue 2 数组/对象响应式更新
- this.$set(this.form.explains, index, { ...exp });
- }
- },
- /**
- * 跳转至物流管理
- */
- manageWl() {
- this.$util.pageTo({ url: "/admin/shop/wl" });
- },
- /**
- * 保存当前配置
- */
- submitSave() {
- if (this.$util.isEmpty(this.form.alias)) {
- this.$msg("请填写别名");
- return;
- }
- // 验证说明项内容
- for (let i = 0; i < this.form.explains.length; i++) {
- if (this.$util.isEmpty(this.form.explains[i].explain)) {
- this.$msg(`请填写第 ${i + 1} 条说明内容`);
- return;
- }
- }
- uni.showLoading({ title: "保存中" });
- saveShMethodConfig(this.form)
- .then(res => {
- uni.hideLoading();
- if (res.code == 1) {
- this.$msg("保存成功");
- // 重新加载配置刷新数据
- this.loadConfig(this.tabIndex);
- } else {
- this.$msg(res.msg || "保存失败");
- }
- })
- .catch(err => {
- uni.hideLoading();
- this.$msg("保存失败,请重试");
- });
- }
- }
- };
- </script>
- <style lang="scss" scoped>
- .sh-method-page {
- display: flex;
- flex-direction: column;
- height: 100vh;
- background-color: #f5f5f5;
- }
- /* 顶部 Tab 栏 */
- .tab-bar {
- display: flex;
- background-color: #ffffff;
- border-bottom: 1upx solid #eeeeee;
- position: sticky;
- top: 0;
- z-index: 10;
- height: 90upx;
- align-items: center;
- }
- .tab-item {
- flex: 1;
- text-align: center;
- font-size: 34upx;
- color: #666666;
- height: 90upx;
- line-height: 90upx;
- position: relative;
- transition: all 0.2s ease;
- font-weight: bold;
- &.active {
- color: #3385ff;
- font-weight: bold;
- &::after {
- content: "";
- position: absolute;
- bottom: 0;
- left: 50%;
- transform: translateX(-50%);
- width: 40upx;
- height: 4upx;
- background-color: #3385ff;
- border-radius: 2upx;
- }
- }
- }
- /* 表单区域 */
- .form-scroll {
- flex: 1;
- overflow: hidden;
- }
- .form-container {
- padding: 20upx 20upx 160upx 20upx;
- }
- .line-cell {
- background-color: #ffffff;
- border-radius: 12upx;
- margin-bottom: 20upx;
- }
- .tui-title {
- font-size: 28upx;
- color: #333333;
- width: 200upx;
- }
- .tui-input {
- flex: 1;
- font-size: 28upx;
- color: #333333;
- text-align: right;
- }
- .btn-group {
- display: flex;
- align-items: center;
- margin-left: auto;
- }
- /* 跑腿自定义计费输入行 */
- .input-row {
- display: flex;
- align-items: center;
- justify-content: flex-end;
- flex: 1;
- }
- .tui-input-sm {
- width: 120upx;
- height: 60upx;
- border: 1upx solid #dddddd;
- border-radius: 8upx;
- font-size: 26upx;
- text-align: center;
- color: #333333;
- background-color: #fafafa;
- }
- .unit-text {
- font-size: 26upx;
- color: #666666;
- margin: 0 10upx;
- }
- /* 模块标题 */
- .section-header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin: 30upx 10upx 15upx 10upx;
- }
- .section-title {
- font-size: 30upx;
- font-weight: bold;
- color: #333333;
- }
- /* 满减规则卡片 */
- .rule-list {
- margin-bottom: 20upx;
- }
- .rule-card {
- background-color: #ffffff;
- border-radius: 12upx;
- padding: 20upx;
- margin-bottom: 20upx;
- border: 1upx solid #eef2f9;
- }
- .rule-row {
- display: flex;
- align-items: center;
- flex-wrap: wrap;
- font-size: 26upx;
- color: #333333;
- }
- .rule-label {
- margin: 0 8upx;
- }
- .rule-input {
- width: 70upx;
- height: 50upx;
- border: 1upx solid #cccccc;
- border-radius: 6upx;
- text-align: center;
- font-size: 24upx;
- background-color: #fafafa;
- }
- .rule-input-large {
- width: 110upx;
- height: 50upx;
- border: 1upx solid #cccccc;
- border-radius: 6upx;
- text-align: center;
- font-size: 24upx;
- background-color: #fafafa;
- }
- .rule-del-btn {
- margin-top: 15upx;
- margin-left: auto;
- }
- /* 提示文字 */
- .notice-text {
- font-size: 24upx;
- color: #ff6900;
- line-height: 36upx;
- padding: 15upx 20upx;
- background-color: #fffaf5;
- border-radius: 8upx;
- border: 1upx solid #ffe8d6;
- margin: 20upx 10upx;
- }
- /* 说明项区域圈起来 */
- .explain-section-wrapper {
- background-color: #ffffff;
- border-radius: 12upx;
- padding: 24upx;
- margin-top: 30upx;
- border: 1upx solid #eef2f9;
- box-shadow: 0 2upx 8upx rgba(0, 0, 0, 0.02);
- }
- .no-margin {
- margin-top: 0 !important;
- margin-left: 0 !important;
- margin-right: 0 !important;
- margin-bottom: 20upx !important;
- }
- /* 说明卡片 */
- .explain-list {
- margin-bottom: 20upx;
- }
- .explain-card {
- background-color: #ffffff;
- border-radius: 12upx;
- padding: 20upx;
- margin-bottom: 20upx;
- border: 1upx solid #eef2f9;
- }
- .explain-textarea {
- width: 100%;
- height: 120upx;
- font-size: 30upx;
- color: #333333;
- background-color: #fafafa;
- border: 1upx solid #eeeeee;
- border-radius: 8upx;
- padding: 15upx;
- box-sizing: border-box;
- margin-bottom: 15upx;
- }
- .explain-actions {
- display: flex;
- align-items: center;
- justify-content: space-between;
- }
- .action-group {
- display: flex;
- align-items: center;
- }
- .explain-del-btn {
- margin-left: auto;
- }
- /* 文本样式控制 */
- .text-red {
- color: #ff3841 !important;
- }
- .text-blue {
- color: #3385ff !important;
- }
- .text-bold {
- font-weight: bold !important;
- }
- .no-data-tip {
- font-size: 26upx;
- color: #999999;
- text-align: center;
- padding: 40upx 0;
- }
- /* 底部保存按钮 */
- .footer-btn-wrap {
- position: fixed;
- bottom: 0;
- left: 0;
- right: 0;
- background-color: #ffffff;
- padding: 20upx 30upx;
- border-top: 1upx solid #eeeeee;
- z-index: 10;
- display: flex;
- justify-content: flex-end; /* 居右边 */
- }
- .footer-btn-wrap .admin-button-com.big {
- width: 350upx !important; /* 按钮长一些 */
- margin: 0 !important; /* 清除默认居中 margin */
- }
- </style>
|