| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930 |
- <!--
- 开单确认提交面板(常驻在购物车右侧,非弹窗)
- 由开单 POS 页四栏布局直接挂载,始终渲染;切换客户时刷新表单。
- UI/业务对齐 ghsApp affirm:配送、打折、付款与备注提交。
- -->
- <template>
- <aside class="order-commit-panel">
- <!-- 与购物车 .pos-cart-head 同高,保证右栏标题齐平 -->
- <div class="panel-head">确认提交</div>
- <!-- 中间可滚动:表单内容多,避免挤掉底部提交按钮 -->
- <div class="panel-scroll">
- <div class="commit-body">
- <!-- 当前门店/客户名称已移至顶栏展示,此处不再重复渲染;form.customName 仍用于提交 -->
- <!-- 批发商 pfLevel:同城/德邦等 -->
- <div class="accounts-list" v-if="currentShop.pfLevel && currentShop.pfLevel == 1">
- <span class="accounts-label">配送方式</span>
- <div class="accounts-center">
- <el-button :type="form.transType == 4 ? 'primary' : ''" size="small" @click="setTransType(4)">同城</el-button>
- <el-button :type="form.transType == 0 ? 'primary' : ''" size="small" @click="setTransType(0)">德邦</el-button>
- <el-button :type="form.transType == 1 ? 'primary' : ''" size="small" @click="setTransType(1)">顺丰</el-button>
- <el-button :type="form.transType == 2 ? 'primary' : ''" size="small" @click="setTransType(2)">冷链</el-button>
- <el-button :type="form.transType == 3 ? 'primary' : ''" size="small" @click="setTransType(3)">航空</el-button>
- <el-button :type="form.transType == 5 ? 'primary' : ''" size="small" @click="setTransType(5)">自取</el-button>
- </div>
- </div>
- <!-- 普通门店:自配送/自取/物流;跑腿选项暂隐藏,待同城能力稳定后再开 -->
- <div class="accounts-list" v-else>
- <span class="accounts-label">配送方式</span>
- <div class="accounts-center">
- <el-button :type="form.sendType == 0 ? 'primary' : ''" size="small" @click="setSendType(0)">自配送</el-button>
- <el-button :type="form.sendType == 1 ? 'primary' : ''" size="small" @click="setSendType(1)">自取</el-button>
- <el-button :type="form.sendType == 3 ? 'primary' : ''" size="small" @click="setSendType(3)">物流</el-button>
- </div>
- </div>
- <!-- 物流:手填 + 选物流 -->
- <div class="accounts-list" v-if="form.sendType == 3 && !(currentShop.pfLevel && currentShop.pfLevel == 1)">
- <span class="accounts-label">配送物流</span>
- <div class="accounts-center accounts-center--row">
- <el-input placeholder="请填写物流" v-model="form.wlName" style="flex:1;" />
- <el-button size="small" style="margin-left:8px;" @click="openWlPicker">选物流</el-button>
- </div>
- </div>
- <!-- 跑腿:开通同城则询价,否则仅手填运费 -->
- <template v-if="displaySendCost">
- <template v-if="form.sendType == 2 && openIntraCity == 1">
- <div class="accounts-list accounts-list--top">
- <span class="accounts-label">客户地址</span>
- <div class="accounts-center">
- <template v-if="!customInfo.long || !customInfo.lat || !customInfo.address">
- <span class="addr-warn">地址不完善,请先在客户资料中补全经纬度与地址</span>
- </template>
- <template v-else>
- <div>{{ customInfo.address }}</div>
- <div class="addr-sub">{{ customInfo.showAddress }}</div>
- </template>
- </div>
- </div>
- <div class="accounts-list accounts-list--top">
- <span class="accounts-label">跑腿报价</span>
- <div class="accounts-center">
- <div v-if="quotesLoading" class="quotes-tip">正在获取运费...</div>
- <div v-else-if="!deliveryQuotes.length" class="quotes-tip">
- <span v-if="!customInfo.long || !customInfo.lat || !customInfo.address">请先完善客户地址</span>
- <span v-else>暂无跑腿可用 <el-button type="text" @click="getDeliveryQuotes">重试</el-button></span>
- </div>
- <div v-else class="quotes-grid">
- <div
- v-for="(item, index) in deliveryQuotes"
- :key="index"
- class="quote-item"
- :class="{ active: selectedDeliveryIndex === index, disabled: item.isAble === false }"
- @click="selectDelivery(item, index)"
- >
- <div class="platform-name">{{ item.displayName || item.name }}</div>
- <div class="platform-price">{{ item.priceText }}元</div>
- <div v-if="item.type" class="platform-type">{{ item.type }}</div>
- </div>
- </div>
- </div>
- </div>
- <div class="accounts-list">
- <span class="accounts-label">距离</span>
- <div class="accounts-center" style="color:#3385ff;">
- <template v-if="showDistance > 100">{{ (showDistance / 1000).toFixed(1) }}公里</template>
- <template v-else>{{ showDistance || 0 }} 米</template>
- </div>
- </div>
- <div class="accounts-list">
- <span class="accounts-label">满减规则</span>
- <div class="accounts-center">
- <el-button :type="form.reductionRule == 0 ? 'primary' : ''" size="small" @click="form.reductionRule = 0">没有满减</el-button>
- <el-button :type="form.reductionRule == 1 ? 'primary' : ''" size="small" @click="form.reductionRule = 1">花材满减</el-button>
- </div>
- </div>
- <div class="accounts-list">
- <span class="accounts-label">运费</span>
- <div class="accounts-center">
- <el-input
- v-if="form.reductionRule == 1 && isHcMapRule()"
- placeholder="请填写运费"
- v-model="form.customSendCost"
- />
- <el-input v-else placeholder="请填写运费" v-model="form.sendCost" />
- </div>
- </div>
- <div class="accounts-list">
- <span class="accounts-label">叫跑腿</span>
- <div class="accounts-center">
- <el-checkbox :value="form.callErrand == 1" @change="v => form.callErrand = v ? 1 : 0">
- 开单后直接叫跑腿
- </el-checkbox>
- </div>
- </div>
- <div class="accounts-list" v-if="form.callErrand == 1">
- <span class="accounts-label">取件时间</span>
- <div class="accounts-center">
- <el-date-picker
- v-model="pickupTimeValue"
- type="datetime"
- value-format="yyyy-MM-dd HH:mm"
- placeholder="立即取件可用当前时间"
- style="width:100%;"
- @change="onPickupTimeChange"
- />
- </div>
- </div>
- <div class="accounts-list" v-if="form.callErrand == 1">
- <span class="accounts-label">重量</span>
- <div class="accounts-center">
- <el-input v-model="form.weight" placeholder="公斤" type="number" @change="debounceQuotes" />
- </div>
- </div>
- <div class="accounts-list" v-if="form.callErrand == 1">
- <span class="accounts-label">跑腿备注</span>
- <div class="accounts-center">
- <el-input v-model="form.deliveryRemark" placeholder="跑腿备注" />
- </div>
- </div>
- </template>
- <div class="accounts-list" v-else>
- <span class="accounts-label">运费</span>
- <div class="accounts-center">
- <el-input placeholder="请填写运费,留空免运费" v-model="form.sendCost" />
- </div>
- </div>
- </template>
- <div class="accounts-list" v-if="displayPackCost">
- <span class="accounts-label">打包费</span>
- <div class="accounts-center">
- <el-input placeholder="打包费" v-model="form.packCost" />
- </div>
- </div>
- <div class="accounts-list">
- <span class="accounts-label">付款方式</span>
- <div class="accounts-center">
- <el-button :type="form.hasPay == 2 ? 'primary' : ''" size="small" @click="form.hasPay = 2">挂账</el-button>
- <el-button :type="form.hasPay == 1 ? 'primary' : ''" size="small" @click="form.hasPay = 1">线下</el-button>
- <el-button
- v-if="Number(customBalance) > 0"
- :type="form.hasPay == 4 ? 'primary' : ''"
- size="small"
- @click="form.hasPay = 4"
- >余额</el-button>
- <el-button :type="form.hasPay == 0 ? 'primary' : ''" size="small" @click="form.hasPay = 0">扫码</el-button>
- </div>
- </div>
- <div class="accounts-list" v-if="Number(customBalance) > 0">
- <span class="accounts-label">客户余额</span>
- <div class="accounts-center" style="color:#3385ff;">¥{{ parseFloat(customBalance) }}</div>
- </div>
- <div class="accounts-list" v-if="form.hasPay == 1">
- <span class="accounts-label">线下方式</span>
- <div class="accounts-center">
- <el-button :type="form.payWay == 0 ? 'primary' : ''" size="small" @click="form.payWay = 0">线下微信</el-button>
- <el-button :type="form.payWay == 1 ? 'primary' : ''" size="small" @click="form.payWay = 1">线下支付宝</el-button>
- <el-button :type="form.payWay == 4 ? 'primary' : ''" size="small" @click="form.payWay = 4">现金</el-button>
- <el-button :type="form.payWay == 5 ? 'primary' : ''" size="small" @click="form.payWay = 5">银行卡</el-button>
- </div>
- </div>
- <div class="accounts-list">
- <span class="accounts-label">打印小票</span>
- <div class="accounts-center">
- <el-button :type="form.needPrint == 1 ? 'primary' : ''" size="small" @click="form.needPrint = 1">需要</el-button>
- <el-button :type="form.needPrint == 2 ? 'primary' : ''" size="small" @click="form.needPrint = 2">不要</el-button>
- </div>
- </div>
- <!-- 合计 + 打折(对齐 App) -->
- <div class="accounts-list">
- <span class="accounts-label">合计金额</span>
- <div class="accounts-center accounts-center--row">
- <span style="color:#3385ff;font-weight:700;">¥{{ parseFloat(finalPrice) }}</span>
- <el-button size="small" style="margin-left:12px;" @click="discountVisible = true">打折</el-button>
- <span v-if="discountValue > 0 && discountValue < 1" class="discount-tag">
- {{ (Number(discountValue) * 10).toFixed(1) }}折
- </span>
- </div>
- </div>
- <div class="accounts-list">
- <span class="accounts-label">{{ form.hasPay == 2 ? '应收金额' : '实收金额' }}</span>
- <div class="accounts-center">
- <el-input v-model="modifyPrice" clearable />
- </div>
- </div>
- <div class="accounts-list" v-if="modifyPrice > 0 && modifyPrice > finalPrice" style="color:red;font-weight:bold;">
- <span class="accounts-label">人工资材</span>
- <div class="accounts-center">¥{{ parseFloat((modifyPrice - finalPrice).toFixed(2)) }}</div>
- </div>
- <div class="accounts-list" v-if="modifyPrice > 0 && modifyPrice < finalPrice" style="color:green;font-weight:bold;">
- <span class="accounts-label">优惠金额</span>
- <div class="accounts-center">¥{{ parseFloat((finalPrice - modifyPrice).toFixed(2)) }}</div>
- </div>
- <div class="accounts-list">
- <span class="accounts-label">送货日期</span>
- <div class="accounts-center">
- <el-date-picker v-model="form.sendTimeWant" style="width: 100%" type="date" value-format="yyyy-MM-dd" placeholder="默认当天或隔天" />
- </div>
- </div>
- <div class="accounts-list">
- <span class="accounts-label">开单人员</span>
- <div class="accounts-center">
- <el-select style="width:100%" v-model="form.getStaffId" placeholder="请选择" @change="onStaffChange">
- <el-option v-for="item in staffList" :key="item.id" :label="item.name" :value="item.id" />
- </el-select>
- </div>
- </div>
- <div class="accounts-list">
- <span class="accounts-label">账单日期</span>
- <div class="accounts-center">
- <el-date-picker v-model="form.historyDate" style="width: 100%" type="date" value-format="yyyy-MM-dd" placeholder="默认当天" />
- </div>
- </div>
- <div class="accounts-list accounts-list--top">
- <span class="accounts-label">备注信息</span>
- <div class="accounts-center">
- <el-input type="textarea" :rows="2" placeholder="请输入内容" v-model="form.remark" />
- </div>
- </div>
- <div v-if="!$util.isEmpty(diffList)" class="diff-box">
- <div class="diff-title">以下花材开单价与系统售价不一致,确认提交吗?</div>
- <el-button type="primary" size="mini" @click="submitOrder(true)">确认差价(Ctrl+Alt+Enter)</el-button>
- <div v-for="(item, index) in diffList" :key="index" class="diff-line">
- {{ item.name }}
- 系统售价 <span class="g">¥{{ item.price ? parseFloat(item.price) : 0 }}</span>
- 你开价 <span class="r">¥{{ item.kdPrice ? parseFloat(item.kdPrice) : 0 }}</span>
- </div>
- </div>
- </div>
- </div>
- <!-- 底部固定提交:始终可见,不随表单滚动 -->
- <div class="panel-footer">
- <el-button type="primary" :loading="submitting" class="submit-btn" @click="submitOrder(false)">
- 确认提交(Ctrl+Enter)
- </el-button>
- <p class="tip">按 Tab 切到下一个,按空格选中</p>
- </div>
- <!-- 选物流:嵌套弹窗挂到 body,避免被侧栏裁剪 -->
- <el-dialog title="请选择物流" :visible.sync="wlPickerVisible" width="420px" append-to-body>
- <div v-loading="wlLoading">
- <el-button
- v-for="item in wlList"
- :key="item.id || item.name"
- size="small"
- :type="form.wlName === item.name ? 'primary' : 'default'"
- style="margin: 0 8px 8px 0;"
- @click="selectWl(item)"
- >{{ item.name }}</el-button>
- <div v-if="!wlLoading && !wlList.length" class="quotes-tip">暂无物流,请手填</div>
- </div>
- </el-dialog>
- <!-- 打折:1–9折 / 不打 / 自定义;append-to-body 保证遮罩盖住整页 -->
- <el-dialog title="选择打折" :visible.sync="discountVisible" width="440px" append-to-body>
- <div class="discount-box">
- <el-button
- v-for="(item, index) in discountList"
- :key="index"
- size="small"
- :type="discountValue === item.value ? 'primary' : 'default'"
- class="discount-btn"
- @click="setDiscount(item.value)"
- >{{ item.name }}</el-button>
- <div class="discount-custom">
- <span>自定义折扣</span>
- <el-input v-model="customDiscount" placeholder="85折请填0.85" style="width:160px;margin:0 8px;" />
- <el-button type="primary" size="small" @click="setCustomDiscount">确认</el-button>
- </div>
- </div>
- <span slot="footer">
- <el-button @click="discountVisible = false">取消</el-button>
- </span>
- </el-dialog>
- </aside>
- </template>
- <script>
- import dayjs from 'dayjs'
- export default {
- name: 'OrderCommitDialog',
- props: {
- customId: { type: [Number, String], default: 0 },
- customName: { type: String, default: '' },
- /** 当前开单门店名,与 POS 页「当前在 xxx」一致 */
- shopName: { type: String, default: '' },
- /** 当前客户已选花材 */
- selectList: { type: Array, default: () => [] },
- /** 商品合计(不含运费打包费) */
- goodsPrice: { type: [Number, String], default: 0 },
- book: { type: [Number, String], default: 0 },
- customBalance: { type: [Number, String], default: 0 }
- },
- data() {
- return {
- submitting: false,
- modifyPrice: 0,
- diffList: [],
- staffList: [],
- currentShop: { pfLevel: 0 },
- openIntraCity: 0,
- hcFreeKm: 0,
- hcMap: [],
- customInfo: {},
- deliveryQuotes: [],
- selectedDeliveryIndex: -1,
- selectedDeliveryData: null,
- showDistance: 0,
- quotesLoading: false,
- weightDebounceTimer: null,
- pickupTimeValue: '',
- wlPickerVisible: false,
- wlList: [],
- wlLoading: false,
- discountVisible: false,
- discountValue: 0,
- customDiscount: '',
- discountList: [
- { name: '1折', value: 0.1 },
- { name: '2折', value: 0.2 },
- { name: '3折', value: 0.3 },
- { name: '4折', value: 0.4 },
- { name: '5折', value: 0.5 },
- { name: '6折', value: 0.6 },
- { name: '7折', value: 0.7 },
- { name: '8折', value: 0.8 },
- { name: '9折', value: 0.9 },
- { name: '不打', value: 1 }
- ],
- form: {
- customId: 0,
- customName: '',
- sendType: 0,
- transType: 4,
- sendCost: '',
- customSendCost: 0,
- packCost: '',
- wlName: '',
- hasPay: 2,
- payWay: 0,
- needPrint: 1,
- getStaffId: 0,
- getStaffName: '',
- sendTimeWant: '',
- historyDate: '',
- remark: '',
- book: 0,
- dealPrice: 0,
- reductionRule: 0,
- callErrand: 0,
- weight: 1,
- deliveryRemark: ''
- }
- }
- },
- computed: {
- // 面板已隐藏「当前门店」行;仍保留计算,避免与 shopName/currentShop 同步逻辑脱节
- displayShopName() {
- if (this.shopName) return this.shopName
- const shop = this.currentShop || {}
- return shop.shopName || shop.name || '门店'
- },
- displayPackCost() {
- return this.currentShop.pfLevel && this.currentShop.pfLevel == 1
- },
- /** 是否展示运费区:跑腿 或 批发商配送(对齐 App displaySendCost) */
- displaySendCost() {
- if (this.form.sendType == 2) return true
- if (this.currentShop.pfLevel && this.currentShop.pfLevel == 1) return true
- return false
- },
- /** 扎数合计,用于花材满减规则 */
- totalBigCount() {
- let big = 0
- if (!this.$util.isEmpty(this.selectList)) {
- this.selectList.forEach(ele => {
- if (Number(ele.bigCount) > 0) big += Number(ele.bigCount)
- })
- }
- return big
- },
- /**
- * 合计 = 花材 + 运费(+打包费);运费规则对齐 affirm
- */
- finalPrice() {
- let finalPrice = Number(this.goodsPrice) || 0
- if (this.form.sendType == 2) {
- const sendCost = Number(this.form.sendCost) || 0
- if (this.form.reductionRule == 0) {
- finalPrice += sendCost
- } else if (this.form.reductionRule == 1) {
- if (this.isHcMapRule()) {
- finalPrice += Number(this.form.customSendCost) || 0
- } else {
- finalPrice += sendCost
- }
- }
- } else if (this.displaySendCost) {
- finalPrice += Number(this.form.sendCost) || 0
- }
- if (this.displayPackCost) {
- finalPrice += Number(this.form.packCost) || 0
- }
- return parseFloat(finalPrice.toFixed(2))
- }
- },
- watch: {
- /** 合计变化时同步应收;已打折则按折扣重算 */
- finalPrice(val) {
- const d = Number(this.discountValue)
- if (d > 0 && d <= 1) {
- this.modifyPrice = parseFloat((Number(val) * d).toFixed(2))
- } else {
- this.modifyPrice = val
- }
- },
- /** 切换客户时重置面板,避免沿用上一客户配送/付款等选项 */
- customId() {
- this.resetPanel()
- },
- customName(val) {
- this.form.customName = val || ''
- }
- },
- mounted() {
- this.resetPanel()
- },
- methods: {
- /**
- * 重置面板表单与询价状态
- * 用于:进页、切换客户、提交成功后;侧栏常驻,不再关弹窗
- */
- resetPanel() {
- this.diffList = []
- this.discountValue = 0
- this.customDiscount = ''
- this.deliveryQuotes = []
- this.selectedDeliveryIndex = -1
- this.selectedDeliveryData = null
- this.showDistance = 0
- this.customInfo = {}
- this.form.customId = this.customId
- this.form.customName = this.customName
- this.form.book = Number(this.book) || 0
- this.form.sendType = 0
- this.form.transType = 4
- this.form.hasPay = 2
- this.form.sendCost = ''
- this.form.customSendCost = 0
- this.form.packCost = ''
- this.form.wlName = ''
- this.form.remark = ''
- this.form.dealPrice = 0
- this.form.reductionRule = 0
- this.form.callErrand = 0
- this.form.weight = 1
- this.form.deliveryRemark = ''
- this.pickupTimeValue = dayjs().format('YYYY-MM-DD HH:mm')
- this.$nextTick(() => {
- this.modifyPrice = this.finalPrice
- })
- this.loadShopAndStaff()
- this.loadCustomDetail()
- },
- loadShopAndStaff() {
- const that = this
- this.$service.common.shopInfo().then(res => {
- that.currentShop = res.shopInfo || res.shop || { pfLevel: 0 }
- that.openIntraCity = res.openIntraCity != null ? Number(res.openIntraCity) : 0
- that.hcFreeKm = res.hcFreeKm != null ? Number(res.hcFreeKm) : 0
- try {
- that.hcMap = typeof res.hcMap === 'string' ? JSON.parse(res.hcMap) : (res.hcMap || [])
- } catch (e) {
- that.hcMap = []
- }
- const currentStaff = res.staff || {}
- that.$service.shopAdmin.getAllStaff().then(staffRes => {
- that.staffList = staffRes.list || []
- if (!that.$util.isEmpty(that.staffList)) {
- for (const ele of that.staffList) {
- if (currentStaff.id == ele.id) {
- that.form.getStaffId = ele.id
- that.form.getStaffName = ele.name
- }
- }
- }
- })
- })
- },
- /** 拉客户详情:默认物流名、地址(跑腿询价用) */
- loadCustomDetail() {
- if (!this.customId) return
- this.$service.custom.clientInfo({ id: this.customId }).then(res => {
- const info = res.custom || res.data || res || {}
- this.customInfo = info
- if (info.name) this.form.customName = info.name
- if (info.wlName) this.form.wlName = info.wlName
- }).catch(() => {})
- },
- setTransType(type) {
- this.form.transType = type
- },
- /**
- * 切换配送方式;选跑腿且开通同城时拉报价
- */
- setSendType(type) {
- this.form.sendType = type
- if (type !== 2) {
- this.form.sendCost = ''
- this.deliveryQuotes = []
- this.selectedDeliveryIndex = -1
- this.selectedDeliveryData = null
- } else if (this.openIntraCity == 1) {
- this.getDeliveryQuotes()
- }
- },
- openWlPicker() {
- this.wlPickerVisible = true
- this.wlLoading = true
- this.$service.wl.getAllWl().then(res => {
- this.wlList = res.list || (res.data && res.data.list) || []
- this.wlLoading = false
- }).catch(() => {
- this.wlLoading = false
- this.$message({ message: '获取物流列表失败', type: 'warning' })
- })
- },
- selectWl(item) {
- this.form.wlName = item.name
- this.wlPickerVisible = false
- },
- /** 花材满减是否命中(距离/扎数/金额) */
- isHcMapRule() {
- const distanceInMeters = Number(this.showDistance) || 0
- const freeKmInMeters = (Number(this.hcFreeKm) || 0) * 1000
- if (distanceInMeters < freeKmInMeters) return true
- const map = Array.isArray(this.hcMap) ? this.hcMap : []
- const flowerCount = this.totalBigCount
- const flowerPrice = Number(this.goodsPrice) || 0
- for (const rule of map) {
- const ruleNum = Number(rule.num) || 0
- const rulePrice = Number(rule.price) || 0
- const ruleDistance = (Number(rule.distance) || 0) * 1000
- if (flowerCount >= ruleNum && flowerPrice >= rulePrice && distanceInMeters <= ruleDistance) {
- return true
- }
- }
- return false
- },
- debounceQuotes() {
- if (this.weightDebounceTimer) clearTimeout(this.weightDebounceTimer)
- this.weightDebounceTimer = setTimeout(() => this.getDeliveryQuotes(), 400)
- },
- onPickupTimeChange() {
- if (this.openIntraCity == 1 && this.form.sendType == 2) {
- this.getDeliveryQuotes()
- }
- },
- /** 跑腿多平台询价(对齐 App getDeliveryQuotes) */
- getDeliveryQuotes() {
- if (!this.customInfo.long || !this.customInfo.lat || !this.customInfo.address) {
- return
- }
- this.quotesLoading = true
- this.deliveryQuotes = []
- this.selectedDeliveryIndex = -1
- this.selectedDeliveryData = null
- this.$service.delivery.quickOrderAllDeliveryQuotes({
- totalPrice: this.goodsPrice,
- weight: this.form.weight,
- remark: this.form.deliveryRemark,
- customId: this.customId,
- pickupTime: this.pickupTimeValue || dayjs().format('YYYY-MM-DD HH:mm')
- }).then(res => {
- this.quotesLoading = false
- const raw = res.deliveryList || (res.data && res.data.deliveryList) || []
- this.deliveryQuotes = raw
- .filter(item => item.isAble !== false)
- .map(item => {
- const price = item.price ? (item.price / 100).toFixed(1) : '0.0'
- let displayName = item.name || ''
- let bracketContent = ''
- if (displayName.indexOf('(') !== -1) {
- const parts = displayName.split('(')
- displayName = parts[0].trim()
- bracketContent = (parts[1] || '').replace(')', '')
- }
- if (item.en_name == 'didi' && bracketContent) {
- item.type = bracketContent
- }
- return {
- ...item,
- displayName,
- priceText: price,
- priceNumber: parseFloat(price),
- bracketContent
- }
- })
- const first = this.deliveryQuotes.findIndex(i => i.isAble !== false)
- if (first !== -1) this.selectDelivery(this.deliveryQuotes[first], first)
- }).catch(() => {
- this.quotesLoading = false
- this.deliveryQuotes = []
- this.$message({ message: '获取跑腿平台报价失败', type: 'warning' })
- })
- },
- selectDelivery(item, index) {
- if (item.isAble === false) return
- this.selectedDeliveryIndex = index
- this.selectedDeliveryData = item
- this.form.sendCost = item.priceNumber
- this.showDistance = item.distance || 0
- },
- onStaffChange(id) {
- const staff = this.staffList.find(s => s.id == id)
- if (staff) this.form.getStaffName = staff.name
- },
- /** 快捷折扣:modifyPrice = 合计 * 折扣 */
- setDiscount(num) {
- this.discountValue = Number(num)
- this.modifyPrice = parseFloat((Number(this.finalPrice) * Number(num)).toFixed(2))
- this.customDiscount = ''
- this.discountVisible = false
- },
- setCustomDiscount() {
- const value = parseFloat(this.customDiscount)
- if (isNaN(value) || value < 0 || value > 1) {
- this.$message({ message: '请输入0到1之间的有效折扣值', type: 'warning' })
- return
- }
- this.setDiscount(value)
- },
- /**
- * 提交订单;forceDealPrice 为差价二次确认
- * 成功后只重置面板并 emit success,不关侧栏(侧栏始终展示)
- * 父页可通过 $refs.commitPanel.submitOrder(false) 走快捷键提交
- */
- submitOrder(forceDealPrice) {
- const that = this
- if (!this.form.customId) {
- this.$message({ message: '请选择客户', type: 'warning' })
- return
- }
- if (this.$util.isEmpty(this.selectList)) {
- this.$message({ message: '请选择花材', type: 'warning' })
- return
- }
- if (this.form.sendType == 3 && this.$util.isEmpty(this.form.wlName)) {
- this.$message({ message: '请填写物流', type: 'warning' })
- return
- }
- if (Number(this.modifyPrice) <= 0) {
- this.$message({ message: '收款金额必须大于0', type: 'warning' })
- return
- }
- if (this.form.book == 1 && Number(this.form.sendCost) > 0) {
- this.$message({ message: '预订单不能填写运费', type: 'warning' })
- return
- }
- if (Number(this.customBalance) >= Number(this.modifyPrice) && this.form.hasPay == 2) {
- this.$message({ message: '余额充足,请用余额支付', type: 'warning' })
- return
- }
- if (this.form.hasPay == 4 && Number(this.customBalance) < Number(this.modifyPrice)) {
- this.$message({ message: '余额不足,无法余额支付', type: 'warning' })
- return
- }
- if (this.form.book == 1 && this.form.hasPay != 2) {
- this.$message({ message: '预订单只能选择挂账', type: 'warning' })
- return
- }
- if (this.form.callErrand == 1) {
- if (!this.customInfo.long || !this.customInfo.lat || !this.customInfo.address) {
- this.$message({ message: '客户地址不完整,不支持直接发跑腿', type: 'warning' })
- return
- }
- }
- const product = this.selectList.map(ele => {
- return {
- productId: ele.id,
- bigNum: ele.bigCount,
- smallNum: ele.smallCount || 0,
- classId: ele.classId || 0,
- itemId: ele.itemId,
- price: ele.userPrice,
- remark: ele.remark || ''
- }
- })
- const params = {
- ...this.form,
- product: JSON.stringify(product),
- modifyPrice: this.modifyPrice,
- newVersion: 1,
- dealPrice: forceDealPrice ? 1 : this.form.dealPrice
- }
- // 跑腿平台参数(对齐 affirm)
- if (this.form.sendType == 2 && this.selectedDeliveryData) {
- params.deliveryPlatform = this.selectedDeliveryData.en_name
- params.deliveryPrice = this.selectedDeliveryData.priceNumber
- params.deliveryDistance = this.showDistance
- params.deliveryBracketContent = this.selectedDeliveryData.bracketContent
- params.deliveryAllParams = this.selectedDeliveryData
- if (this.form.callErrand == 1) {
- params.pickupTime = this.pickupTimeValue || dayjs().format('YYYY-MM-DD HH:mm')
- }
- }
- let tip = '确认提交'
- if (this.form.hasPay == 1) tip = '确认线下付款?'
- else if (this.form.hasPay == 2) tip = '确认挂账?'
- else if (this.form.hasPay == 4) tip = '确认余额支付?'
- else if (this.form.hasPay == 0) tip = '确认扫码收款?'
- this.$confirm(tip, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => {
- that.submitting = true
- that.$service.order.orderCreate(params).then(data => {
- that.submitting = false
- if (data.respondType && data.respondType == 'priceError') {
- that.diffList = data.diff ? data.diff : []
- that.$message({ message: '请确认修改的价格', type: 'warning' })
- return
- }
- that.$notify({ title: '成功', message: '开单成功', type: 'success' })
- // 成功后重置表单,面板继续常驻;清车等由父页 onOrderSuccess 处理
- that.resetPanel()
- that.$emit('success', data)
- }).catch(() => {
- that.submitting = false
- })
- }).catch(() => {})
- }
- }
- }
- </script>
- <style lang="scss">
- /* 侧栏内嵌套弹窗无需改 el-dialog 全局高度 */
- </style>
- <style lang="scss" scoped>
- /* 右侧常驻面板:约 360px,与收窄后的购物车并列 */
- .order-commit-panel {
- flex-shrink: 0;
- width: 360px;
- max-width: 360px;
- background: #fff;
- border-left: 1px solid #ebeef5;
- display: flex;
- flex-direction: column;
- min-height: 0;
- height: 100%;
- box-sizing: border-box;
- }
- /* 与开单页 .pos-cart-head 统一 48px,避免两侧 header 高低不一 */
- .panel-head {
- flex-shrink: 0;
- box-sizing: border-box;
- height: 48px;
- min-height: 48px;
- display: flex;
- align-items: center;
- padding: 0 14px;
- font-size: 16px;
- line-height: 22px;
- font-weight: 700;
- color: #303133;
- border-bottom: 1px solid #ebeef5;
- }
- .panel-scroll {
- flex: 1;
- min-height: 0;
- overflow-y: auto;
- padding: 12px 12px 8px;
- }
- .panel-footer {
- flex-shrink: 0;
- padding: 10px 12px 14px;
- border-top: 1px solid #ebeef5;
- background: #fff;
- .submit-btn {
- width: 100%;
- height: 40px;
- font-size: 15px;
- }
- .tip {
- text-align: center;
- color: #999;
- margin: 8px 0 0;
- font-size: 12px;
- }
- }
- .commit-body {
- .accounts-list {
- display: flex;
- align-items: center;
- justify-content: flex-start;
- margin-bottom: 12px;
- font-size: 13px;
- color: #666;
- }
- .accounts-list--top {
- align-items: flex-start;
- }
- .accounts-label {
- flex-shrink: 0;
- width: 64px;
- line-height: 32px;
- }
- .accounts-center {
- flex: 1;
- min-width: 0;
- margin-left: 8px;
- text-align: left;
- }
- .accounts-center--row {
- display: flex;
- align-items: center;
- }
- .shop-name {
- font-weight: 700;
- color: #303133;
- }
- .addr-warn {
- color: #f56c6c;
- font-weight: 700;
- }
- .addr-sub {
- margin-top: 4px;
- color: #909399;
- font-size: 12px;
- }
- .discount-tag {
- margin-left: 8px;
- color: #3385ff;
- font-size: 13px;
- }
- .diff-box {
- text-align: left;
- margin-top: 12px;
- }
- .diff-title {
- color: red;
- font-weight: bold;
- margin-bottom: 8px;
- }
- .diff-line {
- color: #3385ff;
- margin-top: 4px;
- font-size: 12px;
- .g { color: green; font-weight: bold; margin-left: 4px; }
- .r { color: red; font-weight: bold; margin-left: 4px; }
- }
- .quotes-tip {
- color: #909399;
- font-size: 13px;
- }
- .quotes-grid {
- display: flex;
- flex-wrap: wrap;
- }
- .quote-item {
- width: calc(50% - 6px);
- margin: 0 6px 6px 0;
- padding: 8px;
- border: 1px solid #dcdfe6;
- border-radius: 4px;
- cursor: pointer;
- box-sizing: border-box;
- &.active {
- border-color: #3385ff;
- background: #ecf5ff;
- }
- &.disabled {
- opacity: 0.5;
- pointer-events: none;
- }
- .platform-name {
- font-weight: 600;
- color: #303133;
- }
- .platform-price {
- color: #3385ff;
- margin-top: 4px;
- }
- .platform-type {
- font-size: 12px;
- color: #909399;
- }
- }
- }
- .discount-box {
- .discount-btn {
- margin: 0 8px 8px 0;
- }
- .discount-custom {
- display: flex;
- align-items: center;
- margin-top: 12px;
- }
- }
- </style>
|