|
|
@@ -1,232 +1,2007 @@
|
|
|
<template>
|
|
|
<view class="boardset-flowert">
|
|
|
- <view class="flower-input_box">
|
|
|
- <view class="flower-open_box">
|
|
|
- <view @tap="checkCurrent(1)">
|
|
|
- <view class="desc">订单金额</view>
|
|
|
- <div class="flower-unit_box">
|
|
|
- <text :class="{selected:checkType == 1}">{{price}}</text>
|
|
|
- </div>
|
|
|
+ <view class="register-main">
|
|
|
+ <scroll-view class="register-left-scroll" scroll-y :enable-back-to-top="false">
|
|
|
+ <view class="flower-input_box">
|
|
|
+ <view class="flower-input_box-wrap">
|
|
|
+ <view
|
|
|
+ class="discount-entry"
|
|
|
+ @tap.stop="openDiscountPopup"
|
|
|
+ hover-class="discount-entry--hover"
|
|
|
+ >
|
|
|
+ <text class="discount-entry__glyph">折</text>
|
|
|
+ </view>
|
|
|
+ <view class="history-entry" @tap.stop="openCalcHistory" hover-class="history-entry--hover">
|
|
|
+ <view class="iconfont iconmingxi1 history-entry__icon"></view>
|
|
|
+ </view>
|
|
|
+ <!-- 计算器:多笔累加 -->
|
|
|
+ <view class="calc-section" :class="{ 'calc-section-active': keyboardTarget === 'calc' }" @tap="focusCalc">
|
|
|
+ <view class="calc-title">计算器</view>
|
|
|
+ <view class="calc-formula">
|
|
|
+ <block v-if="tokens.length === 0 && isEmptyCalcInput">
|
|
|
+ <text class="calc-placeholder">输入数字</text>
|
|
|
+ </block>
|
|
|
+ <view v-else class="calc-formula-inner">
|
|
|
+ <block v-for="(t, idx) in tokens" :key="'tok-' + idx">
|
|
|
+ <text v-if="t.type === 'num'" class="calc-num">{{ t.s }}</text>
|
|
|
+ <text v-else class="calc-op">{{ t.o }}</text>
|
|
|
+ </block>
|
|
|
+ <text v-if="!isEmptyCalcInput" class="calc-num">{{ calcInput }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="calc-total-row">
|
|
|
+ <text class="calc-total-label">订单金额</text>
|
|
|
+ <text class="calc-total-val">{{ formatMoney(stackDiscountedAmount) }}</text>
|
|
|
+ </view>
|
|
|
+ <view v-if="isDiscountActive" class="calc-discount-row">
|
|
|
+ <text class="calc-discount-label">{{ formatDiscountZheLabel(discountZhe) }}后</text>
|
|
|
+ <text class="calc-discount-val">{{ formatMoney(stackDiscountedAmount) }}</text>
|
|
|
+ </view>
|
|
|
+ <view
|
|
|
+ class="gather-pin-entry"
|
|
|
+ :class="{ 'gather-pin-entry--on': gatheringPinTop }"
|
|
|
+ @tap.stop="toggleGatheringPin"
|
|
|
+ hover-class="gather-pin-entry--hover"
|
|
|
+ >
|
|
|
+ <view class="iconfont iconzhiding gather-pin-entry__icon"></view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="rcv-pay-block">
|
|
|
+ <view class="rcv-pay-title">收款方式</view>
|
|
|
+ <view class="rcv-item-list_box">
|
|
|
+ <view
|
|
|
+ v-for="item in optHasPayList"
|
|
|
+ :key="'hp-' + item.id"
|
|
|
+ class="rcv-item-chip"
|
|
|
+ :data-hpid="String(item.id)"
|
|
|
+ :class="{ active: selHasPay === item.id }"
|
|
|
+ @tap.stop="onHasPayChipTap"
|
|
|
+ >
|
|
|
+ {{ item.name }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="rcv-customer-line">
|
|
|
+ <text class="rcv-customer-line__name">{{ customerDisplayName }}</text>
|
|
|
+ </view>
|
|
|
+ <view v-if="selHasPay === 1" class="rcv-sub-block">
|
|
|
+ <view class="rcv-pay-title rcv-pay-title-sub">请选择线下收款方式</view>
|
|
|
+ <view class="rcv-item-list_box">
|
|
|
+ <view
|
|
|
+ v-for="item in optPayWayList"
|
|
|
+ :key="'pw-' + item.id"
|
|
|
+ class="rcv-item-chip"
|
|
|
+ :data-pwid="String(item.id)"
|
|
|
+ :class="{ active: selPayWay === item.id }"
|
|
|
+ @tap.stop="onPayWayChipTap"
|
|
|
+ >
|
|
|
+ {{ item.name }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="pay-amount-row" v-if="showCashPayCols">
|
|
|
+ <view class="flower-open_box pay-amount-col">
|
|
|
+ <view @tap="checkCurrent(2)">
|
|
|
+ <view class="desc">收现金</view>
|
|
|
+ <view class="flower-unit_box">
|
|
|
+ <text :class="{ selected: keyboardTarget !== 'calc' && checkType == 2 }">{{ formatMoney(cash) }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="flower-open_box pay-amount-col">
|
|
|
+ <view class="pay-change-inner">
|
|
|
+ <view class="desc pay-change-desc">
|
|
|
+ <text v-if="Number(zl) > 0" class="change-label-ok">找零</text>
|
|
|
+ <text v-else-if="Number(zl) < 0" class="change-label-bad">还差</text>
|
|
|
+ <text v-else class="change-label-neutral">找零</text>
|
|
|
+ </view>
|
|
|
+ <view class="flower-unit_box flower-unit_box-change">
|
|
|
+ <text v-if="Number(zl) > 0" class="change-hint-ok">{{ formatChangeAmount(zl) }}</text>
|
|
|
+ <text v-else-if="Number(zl) < 0" class="change-hint-bad">{{ formatChangeAmount(-zl) }}</text>
|
|
|
+ <text v-else class="change-hint-neutral">—</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="pay-submit-row">
|
|
|
+ <view class="pay-submit-btn pay-submit-btn-stash" @tap.stop="stashCurrent">暂存</view>
|
|
|
+ <view class="pay-submit-btn" @tap.stop="submitCashierPay">提交</view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </scroll-view>
|
|
|
+ <view class="register-right">
|
|
|
+ <view class="keyboard-body_box">
|
|
|
+ <view class="numpad">
|
|
|
+ <view class="numpad-grid-wrap">
|
|
|
+ <view class="numpad-digits">
|
|
|
+ <view class="numpad-row">
|
|
|
+ <view class="numpad-key" data-char="1" @tap="onNumpadTap">1</view>
|
|
|
+ <view class="numpad-key" data-char="2" @tap="onNumpadTap">2</view>
|
|
|
+ <view class="numpad-key" data-char="3" @tap="onNumpadTap">3</view>
|
|
|
+ </view>
|
|
|
+ <view class="numpad-row">
|
|
|
+ <view class="numpad-key" data-char="4" @tap="onNumpadTap">4</view>
|
|
|
+ <view class="numpad-key" data-char="5" @tap="onNumpadTap">5</view>
|
|
|
+ <view class="numpad-key" data-char="6" @tap="onNumpadTap">6</view>
|
|
|
+ </view>
|
|
|
+ <view class="numpad-row">
|
|
|
+ <view class="numpad-key" data-char="7" @tap="onNumpadTap">7</view>
|
|
|
+ <view class="numpad-key" data-char="8" @tap="onNumpadTap">8</view>
|
|
|
+ <view class="numpad-key" data-char="9" @tap="onNumpadTap">9</view>
|
|
|
+ </view>
|
|
|
+ <view class="numpad-row">
|
|
|
+ <view class="numpad-key numpad-key-muted" data-char="." @tap="onNumpadTap">.</view>
|
|
|
+ <view class="numpad-key" data-char="0" @tap="onNumpadTap">0</view>
|
|
|
+ <view class="numpad-key" data-char="00" @tap="onNumpadTap">00</view>
|
|
|
+ </view>
|
|
|
+ <view class="numpad-row numpad-row-actions">
|
|
|
+ <view class="numpad-key numpad-key-action numpad-key-action-dual" @tap.stop="cancel">
|
|
|
+ <text class="numpad-key-text">取消</text>
|
|
|
+ </view>
|
|
|
+ <view class="numpad-key numpad-key-danger numpad-key-action-dual" data-action="backspace" @tap="onNumpadTap">
|
|
|
+ <text class="numpad-key-text">删除</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="numpad-op-col">
|
|
|
+ <view class="numpad-key numpad-key-op" data-action="calc-mul" @tap="onNumpadTap">×</view>
|
|
|
+ <view class="numpad-key numpad-key-op" data-action="calc-add" @tap="onNumpadTap">+</view>
|
|
|
+ <view class="numpad-key numpad-key-op" data-action="calc-sub" @tap="onNumpadTap">−</view>
|
|
|
+ <view class="numpad-key numpad-key-op" data-action="calc-div" @tap="onNumpadTap">÷</view>
|
|
|
+ <view class="numpad-key numpad-key-op numpad-key-op-muted" data-action="calc-clear" @tap="onNumpadTap">清空</view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
</view>
|
|
|
- <input class="goods-name" v-model="name" placeholder="商品名称" placeholder-class="grey-color" />
|
|
|
- <view class="flower-open_box">
|
|
|
- <view @tap="checkCurrent(2)" style="position:relative;">
|
|
|
- <view class="desc">
|
|
|
- 收现金
|
|
|
+ </view>
|
|
|
+ <uni-popup ref="calcHistoryPopup" type="center" background-color="#ffffff" @change="onCalcHistoryPopupChange">
|
|
|
+ <view class="calc-history-popup">
|
|
|
+ <view class="calc-history-popup-hd">
|
|
|
+ <text class="calc-history-popup-title">历史记录</text>
|
|
|
+ <text class="calc-history-popup-close" @tap.stop="onHistoryPopupCloseTap">关闭</text>
|
|
|
+ </view>
|
|
|
+ <scroll-view scroll-y class="calc-history-popup-body">
|
|
|
+ <view
|
|
|
+ v-for="(row, idx) in calcHistory"
|
|
|
+ :key="row.id || 'hist-' + idx"
|
|
|
+ class="history-item"
|
|
|
+ >
|
|
|
+ <view class="history-item-body" :data-idx="idx" @tap.stop="onHistoryRowTap">
|
|
|
+ <view class="history-line">
|
|
|
+ <text class="history-time">{{ row.timeLabel }}</text>
|
|
|
+ <text class="history-total">合计 {{ formatMoney(row.total) }}</text>
|
|
|
+ </view>
|
|
|
+ <text class="history-detail">{{ row.detailText }}</text>
|
|
|
+ </view>
|
|
|
+ <text class="history-del" :data-idx="idx" @tap.stop="onHistoryDeleteTap">删除</text>
|
|
|
</view>
|
|
|
- <view style="position:absolute;top:20upx;left:95upx;width:300upx;text-align:left;font-size:13upx;">
|
|
|
- <text v-if="Number(zl)>0" style="color:green;">找零 {{zl}}</text>
|
|
|
- <text style="color:red;" v-if="Number(zl)<0">还差 {{-zl}}</text>
|
|
|
+ <view v-if="calcHistory.length === 0" class="history-empty">暂无记录</view>
|
|
|
+ </scroll-view>
|
|
|
+ </view>
|
|
|
+ </uni-popup>
|
|
|
+ <uni-popup ref="discountPopup" type="center" background-color="#ffffff" @change="onDiscountPopupChange">
|
|
|
+ <view class="calc-history-popup discount-popup">
|
|
|
+ <view class="calc-history-popup-hd">
|
|
|
+ <text class="calc-history-popup-title">选择折扣</text>
|
|
|
+ <text class="calc-history-popup-close" @tap.stop="onDiscountPopupCloseTap">关闭</text>
|
|
|
+ </view>
|
|
|
+ <view class="discount-popup-toolbar">
|
|
|
+ <view class="discount-custom-row">
|
|
|
+ <input
|
|
|
+ class="discount-custom-input"
|
|
|
+ v-model="customZheInput"
|
|
|
+ type="text"
|
|
|
+ placeholder="如 8.8(八点八折)"
|
|
|
+ confirm-type="done"
|
|
|
+ />
|
|
|
+ <view class="discount-custom-add-btn" @tap.stop="addCustomDiscountZhe">添加</view>
|
|
|
</view>
|
|
|
- <div class="flower-unit_box">
|
|
|
- <text :class="{selected:checkType == 2}">{{cash}}</text>
|
|
|
- </div>
|
|
|
+ <text v-if="customDiscountZheList.length > 0" class="discount-toolbar-hint">
|
|
|
+ 已保存 {{ customDiscountZheList.length }} 条,点下方选用;无折扣不参与打折
|
|
|
+ </text>
|
|
|
+ <text v-else class="discount-toolbar-hint discount-toolbar-hint--muted">无默认折扣,请先输入数字点「添加」</text>
|
|
|
</view>
|
|
|
+ <scroll-view scroll-y enable-flex="true" class="calc-history-popup-body discount-popup-body-scroll">
|
|
|
+ <view
|
|
|
+ class="discount-option"
|
|
|
+ :class="{ 'discount-option--active': isZheActive(10) }"
|
|
|
+ data-zhe="10"
|
|
|
+ @tap.stop="onDiscountRowPickTap"
|
|
|
+ >
|
|
|
+ <text class="discount-option-text">无折扣</text>
|
|
|
+ <text v-if="isZheActive(10)" class="discount-option-check">✓</text>
|
|
|
+ </view>
|
|
|
+ <view
|
|
|
+ v-for="(z, cidx) in customDiscountZheList"
|
|
|
+ :key="'d-' + cidx + '-' + z"
|
|
|
+ class="discount-option discount-option--with-del"
|
|
|
+ :class="{ 'discount-option--active': isZheActive(z) }"
|
|
|
+ >
|
|
|
+ <view class="discount-option-main" :data-zhe="String(z)" @tap.stop="onDiscountRowPickTap">
|
|
|
+ <text class="discount-option-text">{{ formatDiscountRowLabel(z) }}</text>
|
|
|
+ <text v-if="isZheActive(z)" class="discount-option-check">✓</text>
|
|
|
+ </view>
|
|
|
+ <text class="discount-option-del" :data-cidx="String(cidx)" @tap.stop="onCustomDiscountDeleteTap">删除</text>
|
|
|
+ </view>
|
|
|
+ </scroll-view>
|
|
|
</view>
|
|
|
- </view>
|
|
|
- <view class="keyboard-body_box">
|
|
|
- <VKeyboard ref="keyboard" :pointIsShow="true" :digital="true" :disorderly="false" @typing="typing" @enter="enter" @cancel="cancel"> </VKeyboard>
|
|
|
- </view>
|
|
|
+ </uni-popup>
|
|
|
</view>
|
|
|
</template>
|
|
|
<script>
|
|
|
-import VKeyboard from '@/components/vKeyboard/VKeyboard.vue'
|
|
|
+const CALC_HISTORY_STORAGE_KEY = 'ghsPad_selectPrice_calcHistory'
|
|
|
+const DISCOUNT_CUSTOM_STORAGE_KEY = 'ghsPad_selectPrice_customDiscountZhe'
|
|
|
+const DISCOUNT_SELECTED_STORAGE_KEY = 'ghsPad_selectPrice_discountZhe'
|
|
|
+/** 计算器弹层置顶:须在 console.vue 中使用同名常量 */
|
|
|
+const GATHERING_PIN_TOP_STORAGE_KEY = 'ghsPad_selectPrice_gatheringPinTop'
|
|
|
export default {
|
|
|
- name:'selectPrice',
|
|
|
- components:{ VKeyboard },
|
|
|
+ name: 'selectPrice',
|
|
|
+ props: {
|
|
|
+ customId: {
|
|
|
+ type: Number,
|
|
|
+ default: 0
|
|
|
+ },
|
|
|
+ customName: {
|
|
|
+ type: String,
|
|
|
+ default: ''
|
|
|
+ }
|
|
|
+ },
|
|
|
data() {
|
|
|
return {
|
|
|
- price:0,
|
|
|
- checkType:1,
|
|
|
- fillType:1,
|
|
|
- name:'',
|
|
|
- cash:0
|
|
|
- };
|
|
|
- },
|
|
|
- mounted(){
|
|
|
- this.activeKeyboard()
|
|
|
+ price: 0,
|
|
|
+ checkType: 3,
|
|
|
+ keyboardTarget: 'calc',
|
|
|
+ name: '',
|
|
|
+ cash: 0,
|
|
|
+ /** 表达式:数字与运算符交替,运算符一点即显示 */
|
|
|
+ tokens: [],
|
|
|
+ calcInput: '',
|
|
|
+ calcHistory: [],
|
|
|
+ maxHistory: 20,
|
|
|
+ /** 通过代码调用 uni-popup.close 时为 true,避免与遮罩关闭的 @change 重复播点击音 */
|
|
|
+ _historyPopupCloseByApi: false,
|
|
|
+ /** 10 = 无折扣,9 = 九折,实付 = 合计 × (zhe/10) */
|
|
|
+ discountZhe: 10,
|
|
|
+ customDiscountZheList: [],
|
|
|
+ customZheInput: '',
|
|
|
+ _discountPopupCloseByApi: false,
|
|
|
+ selHasPay: 0,
|
|
|
+ selPayWay: 0,
|
|
|
+ /** 与 settlePop:扫码(0)、赊账(2)、线下(1),无余额 */
|
|
|
+ optHasPayList: [
|
|
|
+ { name: '扫码', id: 0 },
|
|
|
+ { name: '赊账', id: 2 },
|
|
|
+ { name: '线下', id: 1 }
|
|
|
+ ],
|
|
|
+ optPayWayList: [
|
|
|
+ { name: '线下微信', id: 0 },
|
|
|
+ { name: '线下支付宝', id: 1 },
|
|
|
+ { name: '现金', id: 4 },
|
|
|
+ { name: '银行卡', id: 5 }
|
|
|
+ ],
|
|
|
+ /** 计算器置顶:persist 见 GATHERING_PIN_TOP_STORAGE_KEY */
|
|
|
+ gatheringPinTop: false
|
|
|
+ }
|
|
|
},
|
|
|
- computed:{
|
|
|
- zl(){
|
|
|
+ computed: {
|
|
|
+ /** 当前选客名称(供赊账等场景识别) */
|
|
|
+ customerDisplayName() {
|
|
|
+ const n = (this.customName || '').trim()
|
|
|
+ if (n) {
|
|
|
+ return n
|
|
|
+ }
|
|
|
+ if (Number(this.customId) > 0) {
|
|
|
+ return '—'
|
|
|
+ }
|
|
|
+ return '未选择客户'
|
|
|
+ },
|
|
|
+ isEmptyCalcInput() {
|
|
|
+ return this.$util.isEmpty(this.calcInput)
|
|
|
+ },
|
|
|
+ stackTotal() {
|
|
|
+ const { nums, ops } = this.buildEvalState()
|
|
|
+ if (!nums.length) {
|
|
|
+ return 0
|
|
|
+ }
|
|
|
+ const r = this.evalExpr(nums, ops)
|
|
|
+ return isNaN(r) ? 0 : r
|
|
|
+ },
|
|
|
+ discountRate() {
|
|
|
+ const z = Number(this.discountZhe)
|
|
|
+ if (isNaN(z) || z <= 0) {
|
|
|
+ return 1
|
|
|
+ }
|
|
|
+ return Math.min(10, Math.max(0.01, z)) / 10
|
|
|
+ },
|
|
|
+ stackDiscountedAmount() {
|
|
|
+ const raw = Number(this.stackTotal)
|
|
|
+ if (isNaN(raw)) {
|
|
|
+ return 0
|
|
|
+ }
|
|
|
+ return parseFloat((raw * this.discountRate).toFixed(2))
|
|
|
+ },
|
|
|
+ isDiscountActive() {
|
|
|
+ return Number(this.discountZhe) < 10 - 1e-6
|
|
|
+ },
|
|
|
+ zl() {
|
|
|
+ if (!(this.selHasPay === 1 && this.selPayWay === 4)) {
|
|
|
+ return 0
|
|
|
+ }
|
|
|
let amount = 0
|
|
|
- if(Number(this.cash) > 0 && Number(this.price) > 0){
|
|
|
+ if (Number(this.cash) > 0 && Number(this.price) > 0) {
|
|
|
amount = Number(this.cash) - Number(this.price)
|
|
|
amount = parseFloat(amount.toFixed(2))
|
|
|
}
|
|
|
return Number(amount)
|
|
|
- }
|
|
|
+ },
|
|
|
+ showCashPayCols() {
|
|
|
+ return this.selHasPay === 1 && this.selPayWay === 4
|
|
|
+ },
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ stackDiscountedAmount: {
|
|
|
+ handler(v) {
|
|
|
+ if (this.keyboardTarget === 'calc') {
|
|
|
+ const n = parseFloat(Number(v).toFixed(2))
|
|
|
+ this.price = isNaN(n) ? 0 : n
|
|
|
+ }
|
|
|
+ },
|
|
|
+ immediate: true,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.loadCalcHistoryFromStorage()
|
|
|
+ this.loadDiscountFromStorage()
|
|
|
+ this.loadGatheringPinFromStorage()
|
|
|
},
|
|
|
methods: {
|
|
|
- checkCurrent(n){
|
|
|
+ loadGatheringPinFromStorage() {
|
|
|
+ try {
|
|
|
+ const v = uni.getStorageSync(GATHERING_PIN_TOP_STORAGE_KEY)
|
|
|
+ this.gatheringPinTop = v === true || v === 1 || v === '1' || String(v) === 'true'
|
|
|
+ } catch (e) {
|
|
|
+ this.gatheringPinTop = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ persistGatheringPinTop() {
|
|
|
+ try {
|
|
|
+ if (this.gatheringPinTop) {
|
|
|
+ uni.setStorageSync(GATHERING_PIN_TOP_STORAGE_KEY, '1')
|
|
|
+ } else {
|
|
|
+ uni.removeStorageSync(GATHERING_PIN_TOP_STORAGE_KEY)
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.warn('[selectPrice] persistGatheringPinTop', e)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ toggleGatheringPin() {
|
|
|
+ this.tapVoice()
|
|
|
+ this.gatheringPinTop = !this.gatheringPinTop
|
|
|
+ this.persistGatheringPinTop()
|
|
|
+ },
|
|
|
+ loadCalcHistoryFromStorage() {
|
|
|
+ try {
|
|
|
+ const raw = uni.getStorageSync(CALC_HISTORY_STORAGE_KEY)
|
|
|
+ if (raw === undefined || raw === null || raw === '') {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const list = typeof raw === 'string' ? JSON.parse(raw) : raw
|
|
|
+ if (!Array.isArray(list) || !list.length) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const max = this.maxHistory
|
|
|
+ this.calcHistory = list.slice(0, max).map((row, i) => this.normalizeHistoryRow(row, i))
|
|
|
+ } catch (e) {
|
|
|
+ console.warn('[selectPrice] loadCalcHistoryFromStorage', e)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ normalizeHistoryRow(row, idx) {
|
|
|
+ const r = row && typeof row === 'object' ? row : {}
|
|
|
+ const id =
|
|
|
+ r.id != null && String(r.id) !== ''
|
|
|
+ ? String(r.id)
|
|
|
+ : 'hist-' + Date.now() + '-' + idx
|
|
|
+ return {
|
|
|
+ id,
|
|
|
+ tokens: Array.isArray(r.tokens) ? r.tokens : null,
|
|
|
+ addends: Array.isArray(r.addends) ? r.addends : null,
|
|
|
+ calcInput: r.calcInput != null ? String(r.calcInput) : '',
|
|
|
+ total: r.total,
|
|
|
+ timeLabel: r.timeLabel != null ? String(r.timeLabel) : '--:--',
|
|
|
+ detailText: r.detailText != null ? String(r.detailText) : '',
|
|
|
+ cashSnapshot: r.cashSnapshot,
|
|
|
+ priceSnapshot: r.priceSnapshot,
|
|
|
+ orderOnly: !!r.orderOnly,
|
|
|
+ source: r.source === 'stash' ? 'stash' : 'submit',
|
|
|
+ discountZhe:
|
|
|
+ r.discountZhe != null && r.discountZhe !== '' && !isNaN(Number(r.discountZhe))
|
|
|
+ ? parseFloat(Number(r.discountZhe).toFixed(2))
|
|
|
+ : undefined,
|
|
|
+ }
|
|
|
+ },
|
|
|
+ persistCalcHistoryToStorage() {
|
|
|
+ try {
|
|
|
+ uni.setStorageSync(CALC_HISTORY_STORAGE_KEY, JSON.stringify(this.calcHistory))
|
|
|
+ } catch (e) {
|
|
|
+ console.warn('[selectPrice] persistCalcHistoryToStorage', e)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ loadDiscountFromStorage() {
|
|
|
+ try {
|
|
|
+ const customRaw = uni.getStorageSync(DISCOUNT_CUSTOM_STORAGE_KEY)
|
|
|
+ if (customRaw !== undefined && customRaw !== null && customRaw !== '') {
|
|
|
+ const parsed = typeof customRaw === 'string' ? JSON.parse(customRaw) : customRaw
|
|
|
+ if (Array.isArray(parsed)) {
|
|
|
+ this.customDiscountZheList = parsed
|
|
|
+ .map((x) => Number(x))
|
|
|
+ .filter((n) => !isNaN(n) && n > 0 && n < 10 - 1e-6)
|
|
|
+ .map((n) => parseFloat(n.toFixed(2)))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const sel = uni.getStorageSync(DISCOUNT_SELECTED_STORAGE_KEY)
|
|
|
+ if (sel !== undefined && sel !== null && sel !== '') {
|
|
|
+ const z = Number(sel)
|
|
|
+ if (!isNaN(z) && z > 0 && z <= 10) {
|
|
|
+ this.discountZhe = parseFloat(z.toFixed(2))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.normalizeDiscountSelectionToCustomOrNone()
|
|
|
+ } catch (e) {
|
|
|
+ console.warn('[selectPrice] loadDiscountFromStorage', e)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /** 仅允许无折扣(10)或自定义列表中的折数 */
|
|
|
+ normalizeDiscountSelectionToCustomOrNone() {
|
|
|
+ const z = Number(this.discountZhe)
|
|
|
+ if (isNaN(z)) {
|
|
|
+ this.discountZhe = 10
|
|
|
+ this.persistDiscountSelected()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (z >= 10 - 1e-6) {
|
|
|
+ this.discountZhe = 10
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const ok = this.customDiscountZheList.some((x) => Math.abs(Number(x) - z) < 1e-4)
|
|
|
+ if (!ok) {
|
|
|
+ this.discountZhe = 10
|
|
|
+ this.persistDiscountSelected()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ persistDiscountSelected() {
|
|
|
+ try {
|
|
|
+ uni.setStorageSync(DISCOUNT_SELECTED_STORAGE_KEY, String(this.discountZhe))
|
|
|
+ } catch (e) {
|
|
|
+ console.warn('[selectPrice] persistDiscountSelected', e)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ persistCustomDiscountList() {
|
|
|
+ try {
|
|
|
+ uni.setStorageSync(DISCOUNT_CUSTOM_STORAGE_KEY, JSON.stringify(this.customDiscountZheList))
|
|
|
+ } catch (e) {
|
|
|
+ console.warn('[selectPrice] persistCustomDiscountList', e)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /** 当前结算恢复为无折扣(不删除自定义折扣列表) */
|
|
|
+ resetActiveDiscountToNone() {
|
|
|
+ this.discountZhe = 10
|
|
|
+ this.persistDiscountSelected()
|
|
|
+ },
|
|
|
+ formatDiscountZheLabel(z) {
|
|
|
+ const n = Number(z)
|
|
|
+ if (isNaN(n) || n >= 10 - 1e-6) {
|
|
|
+ return ''
|
|
|
+ }
|
|
|
+ return parseFloat(n.toFixed(2)) + '折'
|
|
|
+ },
|
|
|
+ formatDiscountRowLabel(z) {
|
|
|
+ const n = Number(z)
|
|
|
+ if (isNaN(n)) {
|
|
|
+ return '—'
|
|
|
+ }
|
|
|
+ return parseFloat(n.toFixed(2)) + '折'
|
|
|
+ },
|
|
|
+ isZheActive(z) {
|
|
|
+ const a = Number(this.discountZhe)
|
|
|
+ const b = Number(z)
|
|
|
+ if (isNaN(a) || isNaN(b)) {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ return Math.abs(a - b) < 1e-4
|
|
|
+ },
|
|
|
+ openDiscountPopup() {
|
|
|
+ this.tapVoice()
|
|
|
+ this.$refs.discountPopup && this.$refs.discountPopup.open()
|
|
|
+ },
|
|
|
+ onDiscountPopupCloseTap() {
|
|
|
+ this.tapVoice()
|
|
|
+ this.closeDiscountPopup()
|
|
|
+ },
|
|
|
+ closeDiscountPopup() {
|
|
|
+ this._discountPopupCloseByApi = true
|
|
|
+ this.$refs.discountPopup && this.$refs.discountPopup.close()
|
|
|
+ },
|
|
|
+ onDiscountPopupChange(e) {
|
|
|
+ if (!e || e.show !== false) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (this._discountPopupCloseByApi) {
|
|
|
+ this._discountPopupCloseByApi = false
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.tapVoice()
|
|
|
+ },
|
|
|
+ /** 微信小程序 data-event-opts 对 @tap 带参编译易报错,统一用 dataset 取参 */
|
|
|
+ onDiscountRowPickTap(e) {
|
|
|
+ const ds = e.currentTarget.dataset || {}
|
|
|
+ const z = Number(ds.zhe)
|
|
|
+ if (isNaN(z)) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.pickDiscountZhe(z)
|
|
|
+ },
|
|
|
+ onCustomDiscountDeleteTap(e) {
|
|
|
+ const ds = e.currentTarget.dataset || {}
|
|
|
+ const idx = Number(ds.cidx)
|
|
|
+ if (isNaN(idx)) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.removeCustomDiscountByIndex(idx)
|
|
|
+ },
|
|
|
+ pickDiscountZhe(z) {
|
|
|
+ this.tapVoice()
|
|
|
+ const n = Number(z)
|
|
|
+ if (isNaN(n) || n <= 0 || n > 10) {
|
|
|
+ this.$msg('折扣无效')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (n < 10 - 1e-6) {
|
|
|
+ const ok = this.customDiscountZheList.some((x) => Math.abs(Number(x) - n) < 1e-4)
|
|
|
+ if (!ok) {
|
|
|
+ this.$msg('请先从列表选择或添加该折扣')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.discountZhe = parseFloat(n.toFixed(2))
|
|
|
+ this.persistDiscountSelected()
|
|
|
+ this.closeDiscountPopup()
|
|
|
+ },
|
|
|
+ addCustomDiscountZhe() {
|
|
|
+ this.tapVoice()
|
|
|
+ const raw = String(this.customZheInput || '').trim()
|
|
|
+ if (!raw) {
|
|
|
+ this.$msg('请输入折扣')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const n = parseFloat(raw)
|
|
|
+ if (isNaN(n) || n <= 0 || n > 10) {
|
|
|
+ this.$msg('请输入 0.1~10 的数值(如 8.8)')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const rounded = parseFloat(n.toFixed(2))
|
|
|
+ if (rounded >= 10 - 1e-6) {
|
|
|
+ this.$msg('无需添加,请直接选「无折扣」')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (this.customDiscountZheList.some((x) => Math.abs(x - rounded) < 1e-4)) {
|
|
|
+ this.$msg('该折扣已在列表中')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.customDiscountZheList = [rounded].concat(this.customDiscountZheList)
|
|
|
+ this.persistCustomDiscountList()
|
|
|
+ this.customZheInput = ''
|
|
|
+ this.$msg('已添加')
|
|
|
+ },
|
|
|
+ removeCustomDiscountByIndex(cidx) {
|
|
|
+ const idx = Number(cidx)
|
|
|
+ if (isNaN(idx) || idx < 0 || idx >= this.customDiscountZheList.length) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.tapVoice()
|
|
|
+ const removed = this.customDiscountZheList[idx]
|
|
|
+ this.customDiscountZheList = this.customDiscountZheList.filter((_, i) => i !== idx)
|
|
|
+ this.persistCustomDiscountList()
|
|
|
+ if (this.isZheActive(removed)) {
|
|
|
+ this.discountZhe = 10
|
|
|
+ this.persistDiscountSelected()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /** 全页可点区域统一按键音(依赖 $util.hitVoice) */
|
|
|
+ tapVoice() {
|
|
|
this.$util.hitVoice()
|
|
|
+ },
|
|
|
+ /** 构造用于求值的数字列与运算符列(末尾仅挂运算符、无下一操作数时不参与运算) */
|
|
|
+ buildEvalState() {
|
|
|
+ const nums = []
|
|
|
+ const ops = []
|
|
|
+ for (let i = 0; i < this.tokens.length; i++) {
|
|
|
+ const t = this.tokens[i]
|
|
|
+ if (t.type === 'num') {
|
|
|
+ const v = Number(t.s)
|
|
|
+ if (!isNaN(v)) {
|
|
|
+ nums.push(v)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ ops.push(t.o)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const hasTrailingOp =
|
|
|
+ this.tokens.length > 0 &&
|
|
|
+ this.tokens[this.tokens.length - 1].type === 'op'
|
|
|
+ const ci = this.calcInput
|
|
|
+ const hasPartial =
|
|
|
+ ci &&
|
|
|
+ !this.$util.isEmpty(ci) &&
|
|
|
+ ci !== '.' &&
|
|
|
+ !isNaN(parseFloat(ci))
|
|
|
+
|
|
|
+ let evalNums = nums.slice()
|
|
|
+ let evalOps = ops.slice()
|
|
|
+
|
|
|
+ if (hasPartial) {
|
|
|
+ const c = parseFloat(ci)
|
|
|
+ if (!isNaN(c) && c > 0) {
|
|
|
+ evalNums.push(parseFloat(c.toFixed(2)))
|
|
|
+ }
|
|
|
+ } else if (hasTrailingOp && evalOps.length > 0) {
|
|
|
+ evalOps = evalOps.slice(0, -1)
|
|
|
+ }
|
|
|
+
|
|
|
+ while (evalOps.length > 0 && evalNums.length <= evalOps.length) {
|
|
|
+ evalOps.pop()
|
|
|
+ }
|
|
|
+ return { nums: evalNums, ops: evalOps }
|
|
|
+ },
|
|
|
+ opToInternal(o) {
|
|
|
+ if (o === '×') {
|
|
|
+ return '*'
|
|
|
+ }
|
|
|
+ if (o === '÷') {
|
|
|
+ return '/'
|
|
|
+ }
|
|
|
+ if (o === '−') {
|
|
|
+ return '-'
|
|
|
+ }
|
|
|
+ return '+'
|
|
|
+ },
|
|
|
+ /** 先 ×÷ 再 +− */
|
|
|
+ evalExpr(nums, ops) {
|
|
|
+ if (!nums.length) {
|
|
|
+ return 0
|
|
|
+ }
|
|
|
+ const nArr = nums.map((x) => Number(x))
|
|
|
+ const oArr = ops.map((o) => this.opToInternal(o))
|
|
|
+ while (oArr.length > nArr.length - 1) {
|
|
|
+ oArr.pop()
|
|
|
+ }
|
|
|
+ if (nArr.length === 1) {
|
|
|
+ return parseFloat(nArr[0].toFixed(2))
|
|
|
+ }
|
|
|
+ if (oArr.length !== nArr.length - 1) {
|
|
|
+ return nArr[0] || 0
|
|
|
+ }
|
|
|
+ let i = 0
|
|
|
+ while (i < oArr.length) {
|
|
|
+ if (oArr[i] === '*' || oArr[i] === '/') {
|
|
|
+ const a = nArr[i]
|
|
|
+ const b = nArr[i + 1]
|
|
|
+ if (oArr[i] === '/' && b === 0) {
|
|
|
+ return NaN
|
|
|
+ }
|
|
|
+ const r = oArr[i] === '*' ? a * b : a / b
|
|
|
+ nArr.splice(i, 2, r)
|
|
|
+ oArr.splice(i, 1)
|
|
|
+ } else {
|
|
|
+ i++
|
|
|
+ }
|
|
|
+ }
|
|
|
+ let s = nArr[0]
|
|
|
+ for (let k = 0; k < oArr.length; k++) {
|
|
|
+ const b = nArr[k + 1]
|
|
|
+ if (oArr[k] === '+') {
|
|
|
+ s += b
|
|
|
+ } else {
|
|
|
+ s -= b
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return parseFloat(s.toFixed(2))
|
|
|
+ },
|
|
|
+ cloneTokens(arr) {
|
|
|
+ return arr.map((t) =>
|
|
|
+ t.type === 'num' ? { type: 'num', s: t.s } : { type: 'op', o: t.o }
|
|
|
+ )
|
|
|
+ },
|
|
|
+ getExprDisplayString(includePartial) {
|
|
|
+ let s = ''
|
|
|
+ this.tokens.forEach((t) => {
|
|
|
+ s += t.type === 'num' ? t.s : t.o
|
|
|
+ })
|
|
|
+ if (includePartial && !this.$util.isEmpty(this.calcInput)) {
|
|
|
+ s += this.calcInput
|
|
|
+ }
|
|
|
+ return s
|
|
|
+ },
|
|
|
+ legacyAddendsToTokens(addends) {
|
|
|
+ const tokens = []
|
|
|
+ if (!addends || !addends.length) {
|
|
|
+ return tokens
|
|
|
+ }
|
|
|
+ addends.forEach((raw, i) => {
|
|
|
+ const v = Number(raw)
|
|
|
+ if (i === 0) {
|
|
|
+ tokens.push({ type: 'num', s: String(Math.abs(v)) })
|
|
|
+ } else {
|
|
|
+ tokens.push({ type: 'op', o: v >= 0 ? '+' : '−' })
|
|
|
+ tokens.push({ type: 'num', s: String(Math.abs(v)) })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return tokens
|
|
|
+ },
|
|
|
+ pressCalcOp(displayOp) {
|
|
|
+ if (!this.ensureCalcModeForOps()) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (!this.$util.isEmpty(this.calcInput) && this.calcInput !== '.') {
|
|
|
+ const n = Number(this.calcInput)
|
|
|
+ if (isNaN(n) || n <= 0) {
|
|
|
+ this.$msg('请输入有效金额')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const fs = parseFloat(n.toFixed(2))
|
|
|
+ this.tokens.push({ type: 'num', s: String(fs) })
|
|
|
+ this.calcInput = ''
|
|
|
+ }
|
|
|
+ const last = this.tokens.length > 0 ? this.tokens[this.tokens.length - 1] : null
|
|
|
+ if (last && last.type === 'op') {
|
|
|
+ last.o = displayOp
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (last && last.type === 'num') {
|
|
|
+ this.tokens.push({ type: 'op', o: displayOp })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.$msg('请先输入数字')
|
|
|
+ },
|
|
|
+ ensureCalcModeForOps() {
|
|
|
+ if (this.keyboardTarget !== 'calc') {
|
|
|
+ this.$msg('请先在左侧点击「金额累加」')
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ return true
|
|
|
+ },
|
|
|
+ formatMoney(n) {
|
|
|
+ const x = Number(n)
|
|
|
+ if (isNaN(x)) {
|
|
|
+ return '0.00'
|
|
|
+ }
|
|
|
+ return x.toFixed(2)
|
|
|
+ },
|
|
|
+ /** 找零/差额展示:不保留小数点后多余的 0 */
|
|
|
+ formatChangeAmount(n) {
|
|
|
+ const x = Number(n)
|
|
|
+ if (isNaN(x)) {
|
|
|
+ return '0'
|
|
|
+ }
|
|
|
+ const s = (Math.round(x * 100) / 100).toFixed(2)
|
|
|
+ return parseFloat(s).toString()
|
|
|
+ },
|
|
|
+ focusCalc() {
|
|
|
+ this.tapVoice()
|
|
|
+ this.keyboardTarget = 'calc'
|
|
|
+ this.checkType = 3
|
|
|
+ },
|
|
|
+ checkCurrent(n) {
|
|
|
+ this.tapVoice()
|
|
|
this.checkType = n
|
|
|
- this.fillType = n
|
|
|
+ this.keyboardTarget = n === 1 ? 'order' : 'cash'
|
|
|
},
|
|
|
- cancel(){
|
|
|
- this.$util.hitVoice()
|
|
|
+ onHasPayChipTap(e) {
|
|
|
+ const ds = e.currentTarget.dataset || {}
|
|
|
+ const v = ds.hpid
|
|
|
+ if (v === undefined || v === '') {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const val = Number(v)
|
|
|
+ if (isNaN(val)) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.applySelHasPay(val)
|
|
|
+ },
|
|
|
+ onPayWayChipTap(e) {
|
|
|
+ const ds = e.currentTarget.dataset || {}
|
|
|
+ const v = ds.pwid
|
|
|
+ if (v === undefined || v === '') {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const val = Number(v)
|
|
|
+ if (isNaN(val)) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.applySelPayWay(val)
|
|
|
+ },
|
|
|
+ applySelHasPay(val) {
|
|
|
+ this.tapVoice()
|
|
|
+ this.selHasPay = val
|
|
|
+ this.cash = 0
|
|
|
+ if (Number(val) !== 1) {
|
|
|
+ this.selPayWay = 0
|
|
|
+ }
|
|
|
+ this.blurCashIfNoColumn()
|
|
|
+ },
|
|
|
+ applySelPayWay(val) {
|
|
|
+ this.tapVoice()
|
|
|
+ this.selPayWay = val
|
|
|
+ if (Number(val) !== 4) {
|
|
|
+ this.cash = 0
|
|
|
+ } else {
|
|
|
+ this.checkCurrent(2)
|
|
|
+ }
|
|
|
+ this.blurCashIfNoColumn()
|
|
|
+ },
|
|
|
+ blurCashIfNoColumn() {
|
|
|
+ if (this.keyboardTarget === 'cash' && !this.showCashPayCols) {
|
|
|
+ this.focusCalc()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ openCalcHistory() {
|
|
|
+ this.tapVoice()
|
|
|
+ this.$refs.calcHistoryPopup && this.$refs.calcHistoryPopup.open()
|
|
|
+ },
|
|
|
+ onHistoryPopupCloseTap() {
|
|
|
+ this.tapVoice()
|
|
|
+ this.closeCalcHistory()
|
|
|
+ },
|
|
|
+ closeCalcHistory() {
|
|
|
+ this._historyPopupCloseByApi = true
|
|
|
+ this.$refs.calcHistoryPopup && this.$refs.calcHistoryPopup.close()
|
|
|
+ },
|
|
|
+ onCalcHistoryPopupChange(e) {
|
|
|
+ if (!e || e.show !== false) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (this._historyPopupCloseByApi) {
|
|
|
+ this._historyPopupCloseByApi = false
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.tapVoice()
|
|
|
+ },
|
|
|
+ onHistoryRowTap(e) {
|
|
|
+ this.tapVoice()
|
|
|
+ const idx = Number(e.currentTarget.dataset.idx)
|
|
|
+ if (isNaN(idx) || idx < 0) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const row = this.calcHistory[idx]
|
|
|
+ this.applyHistoryRow(row)
|
|
|
+ this.closeCalcHistory()
|
|
|
+ },
|
|
|
+ onHistoryDeleteTap(e) {
|
|
|
+ this.tapVoice()
|
|
|
+ const idx = Number(e.currentTarget.dataset.idx)
|
|
|
+ if (isNaN(idx) || idx < 0 || idx >= this.calcHistory.length) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.calcHistory.splice(idx, 1)
|
|
|
+ this.persistCalcHistoryToStorage()
|
|
|
+ },
|
|
|
+ pushHistorySnapshot(total, opts) {
|
|
|
+ opts = opts || {}
|
|
|
+ const now = new Date()
|
|
|
+ const hh = String(now.getHours())
|
|
|
+ const m = now.getMinutes() < 10 ? '0' + now.getMinutes() : String(now.getMinutes())
|
|
|
+ const timeLabel = hh + ':' + m
|
|
|
+ const hasCalc =
|
|
|
+ this.tokens.length > 0 ||
|
|
|
+ (this.calcInput != null && !this.$util.isEmpty(this.calcInput))
|
|
|
+ const orderOnly =
|
|
|
+ opts.orderOnly !== undefined
|
|
|
+ ? !!opts.orderOnly
|
|
|
+ : !hasCalc
|
|
|
+ const expr = this.getExprDisplayString(true)
|
|
|
+ let detailText = orderOnly
|
|
|
+ ? '订单 ' + this.formatMoney(total)
|
|
|
+ : expr || '订单 ' + this.formatMoney(total)
|
|
|
+ if (!orderOnly && hasCalc && this.isDiscountActive && expr) {
|
|
|
+ detailText =
|
|
|
+ expr +
|
|
|
+ '(原价' +
|
|
|
+ this.formatMoney(this.stackTotal) +
|
|
|
+ ' ' +
|
|
|
+ this.formatDiscountZheLabel(this.discountZhe) +
|
|
|
+ '→' +
|
|
|
+ this.formatMoney(total) +
|
|
|
+ ')'
|
|
|
+ }
|
|
|
+ const row = this.normalizeHistoryRow(
|
|
|
+ {
|
|
|
+ id: Date.now() + '-' + Math.random().toString(16).slice(2, 10),
|
|
|
+ tokens: this.cloneTokens(this.tokens),
|
|
|
+ calcInput: this.calcInput != null ? String(this.calcInput) : '',
|
|
|
+ total,
|
|
|
+ timeLabel,
|
|
|
+ detailText,
|
|
|
+ cashSnapshot: Number(this.cash) || 0,
|
|
|
+ priceSnapshot: Number(this.price) || 0,
|
|
|
+ orderOnly,
|
|
|
+ source: opts.source === 'stash' ? 'stash' : 'submit',
|
|
|
+ discountZhe: parseFloat(Number(this.discountZhe).toFixed(2)),
|
|
|
+ },
|
|
|
+ 0
|
|
|
+ )
|
|
|
+ this.calcHistory.unshift(row)
|
|
|
+ if (this.calcHistory.length > this.maxHistory) {
|
|
|
+ this.calcHistory.pop()
|
|
|
+ }
|
|
|
+ this.persistCalcHistoryToStorage()
|
|
|
+ },
|
|
|
+ stashCurrent() {
|
|
|
+ this.tapVoice()
|
|
|
+ const hasCalc =
|
|
|
+ this.tokens.length > 0 ||
|
|
|
+ (this.calcInput != null && !this.$util.isEmpty(this.calcInput))
|
|
|
+ const st = this.stackTotal
|
|
|
+ const orderP = Number(this.price)
|
|
|
+ let total = null
|
|
|
+ let orderOnly = false
|
|
|
+ if (hasCalc) {
|
|
|
+ if (!Number.isFinite(st) || isNaN(st) || st <= 0) {
|
|
|
+ this.$msg('请先完成有效算式后再暂存')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const payable = this.stackDiscountedAmount
|
|
|
+ if (!Number.isFinite(payable) || isNaN(payable) || payable <= 0) {
|
|
|
+ this.$msg('请先完成有效算式后再暂存')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ total = payable
|
|
|
+ orderOnly = false
|
|
|
+ } else if (!isNaN(orderP) && orderP > 0) {
|
|
|
+ total = orderP
|
|
|
+ orderOnly = true
|
|
|
+ } else {
|
|
|
+ this.$msg('没有可暂存的内容')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.pushHistorySnapshot(total, { source: 'stash', orderOnly })
|
|
|
+ this.$msg('已暂存')
|
|
|
+ this.clearStack()
|
|
|
+ this.keyboardTarget = 'calc'
|
|
|
+ this.checkType = 3
|
|
|
+ },
|
|
|
+ clearStack() {
|
|
|
+ this.tokens = []
|
|
|
+ this.calcInput = ''
|
|
|
+ this.resetActiveDiscountToNone()
|
|
|
+ },
|
|
|
+ /** 从历史记录还原折扣(不写全局折扣 storage,避免覆盖用户默认偏好) */
|
|
|
+ restoreHistoryDiscountFromRow(row) {
|
|
|
+ let z = 10
|
|
|
+ const raw = row && row.discountZhe
|
|
|
+ if (raw != null && raw !== '' && !isNaN(Number(raw))) {
|
|
|
+ const n = Number(raw)
|
|
|
+ if (n > 0 && n <= 10) {
|
|
|
+ z = parseFloat(n.toFixed(2))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (z >= 10 - 1e-6) {
|
|
|
+ this.discountZhe = 10
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const ok = this.customDiscountZheList.some((x) => Math.abs(Number(x) - z) < 1e-4)
|
|
|
+ this.discountZhe = ok ? z : 10
|
|
|
+ },
|
|
|
+ applyHistoryRow(row) {
|
|
|
+ if (!row) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.restoreHistoryDiscountFromRow(row)
|
|
|
+ const ci = row.calcInput != null ? String(row.calcInput) : ''
|
|
|
+ const hasTok = row.tokens && row.tokens.length > 0
|
|
|
+ const hasLegacy = row.addends && row.addends.length
|
|
|
+
|
|
|
+ const restoreCash = () => {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ if (row.cashSnapshot != null && !isNaN(Number(row.cashSnapshot))) {
|
|
|
+ this.cash = Number(row.cashSnapshot)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ if (hasLegacy) {
|
|
|
+ this.tokens = this.legacyAddendsToTokens(row.addends)
|
|
|
+ this.calcInput = ci
|
|
|
+ this.keyboardTarget = 'calc'
|
|
|
+ this.checkType = 3
|
|
|
+ restoreCash()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (hasTok) {
|
|
|
+ this.tokens = this.cloneTokens(row.tokens)
|
|
|
+ this.calcInput = ci
|
|
|
+ this.keyboardTarget = 'calc'
|
|
|
+ this.checkType = 3
|
|
|
+ restoreCash()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (!this.$util.isEmpty(ci)) {
|
|
|
+ this.tokens = []
|
|
|
+ this.calcInput = ci
|
|
|
+ this.keyboardTarget = 'calc'
|
|
|
+ this.checkType = 3
|
|
|
+ restoreCash()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const orderAmt =
|
|
|
+ row.priceSnapshot != null && !isNaN(Number(row.priceSnapshot)) && Number(row.priceSnapshot) > 0
|
|
|
+ ? Number(row.priceSnapshot)
|
|
|
+ : Number(row.total)
|
|
|
+ if (!isNaN(orderAmt) && orderAmt > 0) {
|
|
|
+ this.tokens = []
|
|
|
+ this.calcInput = ''
|
|
|
+ this.price = orderAmt
|
|
|
+ this.cash =
|
|
|
+ row.cashSnapshot != null && !isNaN(Number(row.cashSnapshot))
|
|
|
+ ? Number(row.cashSnapshot)
|
|
|
+ : 0
|
|
|
+ this.keyboardTarget = 'order'
|
|
|
+ this.checkType = 1
|
|
|
+ return
|
|
|
+ }
|
|
|
+ },
|
|
|
+ cancel() {
|
|
|
+ this.tapVoice()
|
|
|
this.$emit('cancelSelectPrice')
|
|
|
},
|
|
|
- activeKeyboard() {
|
|
|
- this.$refs.keyboard.activate();
|
|
|
+ onNumpadTap(e) {
|
|
|
+ this.tapVoice()
|
|
|
+ const ds = e.currentTarget.dataset || {}
|
|
|
+ const action = ds.action
|
|
|
+ const char = ds.char
|
|
|
+ if (action === 'calc-add') {
|
|
|
+ this.pressCalcOp('+')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (action === 'calc-sub') {
|
|
|
+ this.pressCalcOp('−')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (action === 'calc-mul') {
|
|
|
+ this.pressCalcOp('×')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (action === 'calc-div') {
|
|
|
+ this.pressCalcOp('÷')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (action === 'calc-clear') {
|
|
|
+ this.clearStack()
|
|
|
+ this.keyboardTarget = 'calc'
|
|
|
+ this.checkType = 3
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (action === 'backspace') {
|
|
|
+ this.typing({ backspace: true })
|
|
|
+ } else if (char !== undefined && char !== null && char !== '') {
|
|
|
+ this.typing({ backspace: false, char: String(char) })
|
|
|
+ }
|
|
|
},
|
|
|
typing(e) {
|
|
|
+ const field = this.keyboardTarget
|
|
|
if (e.backspace) {
|
|
|
- if(this.fillType == 1){
|
|
|
- if(this.checkType == 1){
|
|
|
- this.price = ''
|
|
|
- }else{
|
|
|
- if (this.price.length > 0) {
|
|
|
- this.price = this.price.substring(0, this.price.length - 1)
|
|
|
+ if (field === 'calc') {
|
|
|
+ if (this.calcInput && String(this.calcInput).length > 0) {
|
|
|
+ this.calcInput = String(this.calcInput).substring(0, String(this.calcInput).length - 1)
|
|
|
+ } else if (this.tokens.length > 0) {
|
|
|
+ const last = this.tokens[this.tokens.length - 1]
|
|
|
+ if (last.type === 'op') {
|
|
|
+ this.tokens.pop()
|
|
|
+ } else if (last.s.length > 1) {
|
|
|
+ last.s = String(last.s).substring(0, String(last.s).length - 1)
|
|
|
+ } else {
|
|
|
+ this.tokens.pop()
|
|
|
}
|
|
|
}
|
|
|
- }else if(this.fillType == 2){
|
|
|
- if(this.checkType == 2){
|
|
|
+ } else if (field === 'order') {
|
|
|
+ if (this.checkType === 1) {
|
|
|
+ this.price = ''
|
|
|
+ } else if (String(this.price).length > 0) {
|
|
|
+ this.price = String(this.price).substring(0, String(this.price).length - 1)
|
|
|
+ }
|
|
|
+ } else if (field === 'cash') {
|
|
|
+ if (!this.showCashPayCols) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (this.checkType === 2) {
|
|
|
this.cash = ''
|
|
|
- }else{
|
|
|
- if (this.cash.length > 0) {
|
|
|
- this.cash = this.cash.substring(0, this.cash.length - 1)
|
|
|
+ } else if (String(this.cash).length > 0) {
|
|
|
+ this.cash = String(this.cash).substring(0, String(this.cash).length - 1)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ const ch = e.char
|
|
|
+ if (field === 'calc') {
|
|
|
+ if (this.$util.isEmpty(this.calcInput) || this.checkType === 3) {
|
|
|
+ this.calcInput = ch
|
|
|
+ } else {
|
|
|
+ if (ch === '.' && String(this.calcInput).indexOf('.') >= 0) {
|
|
|
+ return
|
|
|
}
|
|
|
+ this.calcInput += ch
|
|
|
}
|
|
|
- }else{
|
|
|
-
|
|
|
- }
|
|
|
- }else {
|
|
|
- if(this.fillType == 1){
|
|
|
- if(this.$util.isEmpty(this.price) || this.checkType == 1) {
|
|
|
- this.price = e.char
|
|
|
- }else {
|
|
|
- this.price += e.char
|
|
|
+ } else if (field === 'order') {
|
|
|
+ if (this.$util.isEmpty(this.price) || this.checkType === 1) {
|
|
|
+ this.price = ch
|
|
|
+ } else {
|
|
|
+ if (ch === '.' && String(this.price).indexOf('.') >= 0) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.price += ch
|
|
|
}
|
|
|
- }else if(this.fillType == 2){
|
|
|
- if(this.$util.isEmpty(this.cash) || this.checkType == 2) {
|
|
|
- this.cash = e.char
|
|
|
- }else {
|
|
|
- this.cash += e.char
|
|
|
+ } else if (field === 'cash') {
|
|
|
+ if (!this.showCashPayCols) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (this.$util.isEmpty(this.cash) || this.checkType === 2) {
|
|
|
+ this.cash = ch
|
|
|
+ } else {
|
|
|
+ if (ch === '.' && String(this.cash).indexOf('.') >= 0) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.cash += ch
|
|
|
}
|
|
|
- }else{
|
|
|
-
|
|
|
}
|
|
|
}
|
|
|
this.checkType = 0
|
|
|
},
|
|
|
- enter() {
|
|
|
- if(Number(this.price) <= 0) {
|
|
|
- this.$msg('请填写金额')
|
|
|
+ submitCashierPay() {
|
|
|
+ this._submitCashierPayCore()
|
|
|
+ },
|
|
|
+ _submitCashierPayCore() {
|
|
|
+ this.tapVoice()
|
|
|
+ if (this.keyboardTarget === 'calc') {
|
|
|
+ const st = this.stackTotal
|
|
|
+ if (!Number.isFinite(st) || isNaN(st)) {
|
|
|
+ this.$msg('算式无效(如除数为 0)')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.price = this.stackDiscountedAmount
|
|
|
+ }
|
|
|
+ const p = Number(this.price)
|
|
|
+ if (isNaN(p) || p <= 0) {
|
|
|
+ this.$msg('订单金额须大于 0')
|
|
|
return
|
|
|
}
|
|
|
- this.$emit('confirmSelectPrice', {price:Number(this.price),name:this.name,cash:Number(this.cash)})
|
|
|
- }
|
|
|
- }
|
|
|
+ if (this.selHasPay === 2 && (!this.customId || Number(this.customId) <= 0)) {
|
|
|
+ this.$msg('请先选择客户')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (this.showCashPayCols) {
|
|
|
+ const cx = Number(this.cash) || 0
|
|
|
+ if (cx <= 0) {
|
|
|
+ this.$msg('请输入收到的现金金额')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (Number(this.zl) < 0) {
|
|
|
+ this.$msg('现金不足')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const hasCalc =
|
|
|
+ this.tokens.length > 0 ||
|
|
|
+ (this.calcInput != null && !this.$util.isEmpty(this.calcInput))
|
|
|
+ const cashSubmit = this.showCashPayCols ? (Number(this.cash) || 0) : 0
|
|
|
+ const emitHasPay = this.selHasPay
|
|
|
+ const emitPayWay = this.selHasPay === 1 ? this.selPayWay : 0
|
|
|
+ this.pushHistorySnapshot(p, {
|
|
|
+ source: 'submit',
|
|
|
+ orderOnly: !hasCalc,
|
|
|
+ })
|
|
|
+ this.$emit('zjGathering', {
|
|
|
+ price: p,
|
|
|
+ name: this.name,
|
|
|
+ cash: cashSubmit,
|
|
|
+ hasPay: emitHasPay,
|
|
|
+ payWay: emitPayWay
|
|
|
+ })
|
|
|
+ this.price = 0
|
|
|
+ this.checkType = 3
|
|
|
+ this.keyboardTarget = 'calc'
|
|
|
+ this.cash = 0
|
|
|
+ this.selHasPay = 0
|
|
|
+ this.selPayWay = 0
|
|
|
+ this.tokens = []
|
|
|
+ this.calcInput = ''
|
|
|
+ this.resetActiveDiscountToNone()
|
|
|
+ },
|
|
|
+ },
|
|
|
}
|
|
|
</script>
|
|
|
<style lang="scss" scoped>
|
|
|
-.pay-style{
|
|
|
- text-align:center;
|
|
|
- margin-top:10upx;
|
|
|
+.pay-style {
|
|
|
+ text-align: center;
|
|
|
+ margin-top: 10upx;
|
|
|
button {
|
|
|
- width:80upx;
|
|
|
- height:30upx;
|
|
|
- font-size:12upx;
|
|
|
- display:inline-block;
|
|
|
- color:#777575;
|
|
|
+ width: 80upx;
|
|
|
+ height: 30upx;
|
|
|
+ font-size: 12upx;
|
|
|
+ display: inline-block;
|
|
|
+ color: #777575;
|
|
|
}
|
|
|
- button:first-child{
|
|
|
- margin-right:8upx;
|
|
|
+ button:first-child {
|
|
|
+ margin-right: 8upx;
|
|
|
}
|
|
|
- .selected{
|
|
|
- color:#3385FF;
|
|
|
- border:1upx solid #3385FF;
|
|
|
+ .selected {
|
|
|
+ color: #09c567;
|
|
|
+ border: 1upx solid #09c567;
|
|
|
}
|
|
|
}
|
|
|
-.grey-color{
|
|
|
- color:#d1cfcf;
|
|
|
+.grey-color {
|
|
|
+ color: #d1cfcf;
|
|
|
}
|
|
|
.boardset-flowert {
|
|
|
- width:34vw;
|
|
|
- height: 90vh;
|
|
|
+ width: 91vw;
|
|
|
+ height: 99vh;
|
|
|
+ max-height: 960px;
|
|
|
background-color: #ffffff;
|
|
|
margin: 0 auto;
|
|
|
border-radius: 5upx;
|
|
|
padding: 10upx;
|
|
|
- overflow-y: auto;
|
|
|
+ overflow: hidden;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
box-sizing: border-box;
|
|
|
- & .flower-input_box {
|
|
|
+
|
|
|
+ .register-main {
|
|
|
flex: 1;
|
|
|
- & .flower-title {
|
|
|
- text-align: center;
|
|
|
- color: #333333;
|
|
|
- font-size: 14upx;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: stretch;
|
|
|
+ min-height: 0;
|
|
|
+ }
|
|
|
+ .register-left-scroll {
|
|
|
+ flex: 6;
|
|
|
+ min-width: 0;
|
|
|
+ width: 0;
|
|
|
+ height: 100%;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding-right: 10upx;
|
|
|
+ }
|
|
|
+ .register-right {
|
|
|
+ flex: 5;
|
|
|
+ min-width: 0;
|
|
|
+ width: 0;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding-left: 10upx;
|
|
|
+ border-left: 1upx solid #e8e8e8;
|
|
|
+ }
|
|
|
+ .flower-input_box {
|
|
|
+ padding-bottom: 16upx;
|
|
|
+ }
|
|
|
+ .flower-input_box-wrap {
|
|
|
+ position: relative;
|
|
|
+ }
|
|
|
+ .discount-entry {
|
|
|
+ position: absolute;
|
|
|
+ top: 6upx;
|
|
|
+ left: 6upx;
|
|
|
+ z-index: 3;
|
|
|
+ width: 44upx;
|
|
|
+ height: 44upx;
|
|
|
+ padding: 0;
|
|
|
+ margin: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ border-radius: 8upx;
|
|
|
+ background: rgba(255, 251, 245, 0.98);
|
|
|
+ border: 1upx solid #f0dcc8;
|
|
|
+ box-sizing: border-box;
|
|
|
+ pointer-events: auto;
|
|
|
+ }
|
|
|
+ .discount-entry--hover {
|
|
|
+ opacity: 0.82;
|
|
|
+ }
|
|
|
+ .discount-entry__glyph {
|
|
|
+ font-size: 17upx;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #d97706;
|
|
|
+ line-height: 1;
|
|
|
+ }
|
|
|
+ .history-entry {
|
|
|
+ position: absolute;
|
|
|
+ top: 6upx;
|
|
|
+ right: 6upx;
|
|
|
+ z-index: 3;
|
|
|
+ width: 44upx;
|
|
|
+ height: 44upx;
|
|
|
+ padding: 0;
|
|
|
+ margin: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ border-radius: 8upx;
|
|
|
+ background: rgba(248, 255, 248, 0.95);
|
|
|
+ border: 1upx solid #c8ecd8;
|
|
|
+ box-sizing: border-box;
|
|
|
+ pointer-events: auto;
|
|
|
+ }
|
|
|
+ .history-entry--hover {
|
|
|
+ opacity: 0.82;
|
|
|
+ }
|
|
|
+ .history-entry__icon {
|
|
|
+ font-size: 22upx;
|
|
|
+ color: #09c567;
|
|
|
+ line-height: 1;
|
|
|
+ }
|
|
|
+ .rcv-pay-block {
|
|
|
+ margin-top: 10upx;
|
|
|
+ padding: 10upx 8upx 8upx;
|
|
|
+ border: 1upx solid #eeeeee;
|
|
|
+ border-radius: 6upx;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+ .rcv-pay-title {
|
|
|
+ font-size: 12upx;
|
|
|
+ color: #333333;
|
|
|
+ text-align: left;
|
|
|
+ margin-bottom: 6upx;
|
|
|
+ }
|
|
|
+ .rcv-pay-title-sub {
|
|
|
+ margin-top: 8upx;
|
|
|
+ }
|
|
|
+ .rcv-sub-block {
|
|
|
+ margin-top: 4upx;
|
|
|
+ }
|
|
|
+ .rcv-item-list_box {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: flex-start;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ padding-bottom: 2upx;
|
|
|
+ }
|
|
|
+ .rcv-item-chip {
|
|
|
+ min-width: 78upx;
|
|
|
+ padding-left: 6upx;
|
|
|
+ padding-right: 6upx;
|
|
|
+ height: 26upx;
|
|
|
+ text-align: center;
|
|
|
+ line-height: 26upx;
|
|
|
+ font-size: 10upx;
|
|
|
+ border: 1upx solid #eeeeee;
|
|
|
+ margin-right: 6upx;
|
|
|
+ margin-bottom: 6upx;
|
|
|
+ margin-top: 0;
|
|
|
+ color: #333333;
|
|
|
+ border-radius: 3upx;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+ .rcv-item-chip:first-child {
|
|
|
+ margin-left: 0;
|
|
|
+ }
|
|
|
+ .rcv-item-chip.active {
|
|
|
+ background-color: #09c567;
|
|
|
+ color: #ffffff;
|
|
|
+ border-color: #09c567;
|
|
|
+ }
|
|
|
+ .rcv-customer-line {
|
|
|
+ font-size: 13upx;
|
|
|
+ margin-bottom: 4upx;
|
|
|
+ margin-top: 2upx;
|
|
|
+ }
|
|
|
+ .rcv-customer-line__name {
|
|
|
+ color:black;
|
|
|
+ font-weight: bold;
|
|
|
+ }
|
|
|
+ .rcv-customer-line__amt {
|
|
|
+ color: #3385ff;
|
|
|
+ font-weight: bold;
|
|
|
+ margin-left:20upx;
|
|
|
+ }
|
|
|
+ .pay-amount-row {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ margin-top: 10upx;
|
|
|
+ align-items: flex-start;
|
|
|
+ }
|
|
|
+ .pay-amount-col {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+ margin-top: 0;
|
|
|
+ & + .pay-amount-col {
|
|
|
+ margin-left: 8upx;
|
|
|
}
|
|
|
- & .flower-ratio{
|
|
|
- text-align: center;
|
|
|
- color: #CCCCCC;
|
|
|
- font-size: 9upx;
|
|
|
- margin-bottom:10upx;
|
|
|
- margin-top:6upx;
|
|
|
+ }
|
|
|
+ .pay-change-desc {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ }
|
|
|
+ .change-label-ok {
|
|
|
+ font-size: 13upx;
|
|
|
+ color: #09c567;
|
|
|
+ }
|
|
|
+ .change-label-bad {
|
|
|
+ font-size: 13upx;
|
|
|
+ color: #e54545;
|
|
|
+ }
|
|
|
+ .change-label-neutral {
|
|
|
+ font-size: 13upx;
|
|
|
+ color: #cccccc;
|
|
|
+ }
|
|
|
+ .change-hint-ok {
|
|
|
+ font-size: 15upx;
|
|
|
+ color: #09c567;
|
|
|
+ }
|
|
|
+ .change-hint-bad {
|
|
|
+ font-size: 15upx;
|
|
|
+ color: #e54545;
|
|
|
+ }
|
|
|
+ .change-hint-neutral {
|
|
|
+ font-size: 15upx;
|
|
|
+ color: #cccccc;
|
|
|
+ }
|
|
|
+ .flower-unit_box-change {
|
|
|
+ min-height: 25upx;
|
|
|
+ }
|
|
|
+ .pay-submit-row {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ margin-top: 12upx;
|
|
|
+ align-items: stretch;
|
|
|
+ }
|
|
|
+ .pay-submit-row .pay-submit-btn {
|
|
|
+ flex: 1;
|
|
|
+ }
|
|
|
+ .pay-submit-row .pay-submit-btn + .pay-submit-btn {
|
|
|
+ margin-left: 8upx;
|
|
|
+ }
|
|
|
+ .pay-submit-btn {
|
|
|
+ text-align: center;
|
|
|
+ font-size: 16upx;
|
|
|
+ padding: 14upx 16upx;
|
|
|
+ background: #09c567;
|
|
|
+ color: #ffffff;
|
|
|
+ border-radius: 8upx;
|
|
|
+ border: 1upx solid #09c567;
|
|
|
+ font-weight: 600;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+ .pay-submit-btn-secondary {
|
|
|
+ background: #f7f7f7;
|
|
|
+ color: #333333;
|
|
|
+ border-color: #dddddd;
|
|
|
+ font-weight: 500;
|
|
|
+ }
|
|
|
+ .pay-submit-btn-stash {
|
|
|
+ background: #ffffff;
|
|
|
+ color: #09c567;
|
|
|
+ border-color: #09c567;
|
|
|
+ font-weight: 600;
|
|
|
+ }
|
|
|
+ .pay-submit-btn:active {
|
|
|
+ opacity: 0.9;
|
|
|
+ }
|
|
|
+ .calc-section {
|
|
|
+ position: relative;
|
|
|
+ border: 1upx solid #eeeeee;
|
|
|
+ border-radius: 6upx;
|
|
|
+ padding: 10upx;
|
|
|
+ margin-top: 0;
|
|
|
+ margin-bottom: 10upx;
|
|
|
+ &.calc-section-active {
|
|
|
+ border-color: #09c567;
|
|
|
+ background: #f8fff8;
|
|
|
}
|
|
|
- & .set-residue_box {
|
|
|
- font-size: 12upx;
|
|
|
- color: #CCCCCC;
|
|
|
- margin-top: 10upx;
|
|
|
- text-align: left;
|
|
|
+ }
|
|
|
+ .gather-pin-entry {
|
|
|
+ position: absolute;
|
|
|
+ left: 8upx;
|
|
|
+ bottom: 8upx;
|
|
|
+ z-index: 2;
|
|
|
+ width: 40upx;
|
|
|
+ height: 40upx;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ border-radius: 8upx;
|
|
|
+ background: rgba(250, 250, 250, 0.98);
|
|
|
+ border: 1upx solid #dddddd;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+ .gather-pin-entry--on {
|
|
|
+ border-color: #09c567;
|
|
|
+ background: rgba(240, 255, 245, 0.95);
|
|
|
+ }
|
|
|
+ .gather-pin-entry--hover {
|
|
|
+ opacity: 0.85;
|
|
|
+ }
|
|
|
+ .gather-pin-entry__icon {
|
|
|
+ font-size: 20upx;
|
|
|
+ color: #999999;
|
|
|
+ line-height: 1;
|
|
|
+ }
|
|
|
+ .gather-pin-entry--on .gather-pin-entry__icon {
|
|
|
+ color: #09c567;
|
|
|
+ }
|
|
|
+ .calc-title {
|
|
|
+ text-align: center;
|
|
|
+ font-size: 13upx;
|
|
|
+ color: #333333;
|
|
|
+ margin-bottom: 8upx;
|
|
|
+ }
|
|
|
+ .calc-formula {
|
|
|
+ min-height: 36upx;
|
|
|
+ font-size: 14upx;
|
|
|
+ color: #333333;
|
|
|
+ text-align: center;
|
|
|
+ line-height: 1.4;
|
|
|
+ word-break: break-all;
|
|
|
+ }
|
|
|
+ .calc-formula-inner {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ }
|
|
|
+ .calc-placeholder {
|
|
|
+ font-size: 12upx;
|
|
|
+ color: #999999;
|
|
|
+ }
|
|
|
+ .calc-num {
|
|
|
+ color: #333333;
|
|
|
+ }
|
|
|
+ .calc-op {
|
|
|
+ color: #09c567;
|
|
|
+ }
|
|
|
+ .calc-total-row {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ margin-top: 10upx;
|
|
|
+ }
|
|
|
+ .calc-total-label {
|
|
|
+ font-size: 12upx;
|
|
|
+ color: #999999;
|
|
|
+ margin-right: 8upx;
|
|
|
+ }
|
|
|
+ .calc-total-val {
|
|
|
+ font-size: 16upx;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #09c567;
|
|
|
+ }
|
|
|
+ .calc-discount-row {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ margin-top: 6upx;
|
|
|
+ }
|
|
|
+ .calc-discount-label {
|
|
|
+ font-size: 11upx;
|
|
|
+ color: #d97706;
|
|
|
+ margin-right: 8upx;
|
|
|
+ }
|
|
|
+ .calc-discount-val {
|
|
|
+ font-size: 15upx;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #d97706;
|
|
|
+ }
|
|
|
+ .calc-btn-row {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ margin-top: 10upx;
|
|
|
+ & + .calc-btn-row {
|
|
|
+ margin-top: 8upx;
|
|
|
}
|
|
|
- .goods-name{
|
|
|
- border:1upx solid #EEEEEE;
|
|
|
- width:150upx;
|
|
|
- margin:10upx auto 0 auto;
|
|
|
- height:30upx;
|
|
|
- font-size:15upx;
|
|
|
- text-align:center;
|
|
|
+ }
|
|
|
+ .calc-btn-row-single .calc-btn {
|
|
|
+ flex: 1;
|
|
|
+ }
|
|
|
+ .calc-btn {
|
|
|
+ flex: 1;
|
|
|
+ text-align: center;
|
|
|
+ font-size: 12upx;
|
|
|
+ padding: 8upx 4upx;
|
|
|
+ border: 1upx solid #dddddd;
|
|
|
+ border-radius: 4upx;
|
|
|
+ color: #333333;
|
|
|
+ background: #fafafa;
|
|
|
+ & + .calc-btn {
|
|
|
+ margin-left: 8upx;
|
|
|
}
|
|
|
}
|
|
|
- & .flower-open_box {
|
|
|
+ .calc-btn-primary {
|
|
|
+ background: #09c567;
|
|
|
+ color: #ffffff;
|
|
|
+ border-color: #09c567;
|
|
|
+ }
|
|
|
+ .calc-history-popup {
|
|
|
+ width: 45vw;
|
|
|
+ max-width: 300upx;
|
|
|
+ max-height: 82vh;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ box-sizing: border-box;
|
|
|
+ border-radius: 8upx;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+ .calc-history-popup-hd {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 12upx 16upx;
|
|
|
+ border-bottom: 1upx solid #eeeeee;
|
|
|
+ flex-shrink: 0;
|
|
|
+ }
|
|
|
+ .calc-history-popup-title {
|
|
|
+ font-size: 15upx;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #333333;
|
|
|
+ }
|
|
|
+ .calc-history-popup-close {
|
|
|
+ font-size: 13upx;
|
|
|
+ color: #09c567;
|
|
|
+ padding: 4upx 8upx;
|
|
|
+ }
|
|
|
+ .calc-history-popup-body {
|
|
|
+ height: 480upx;
|
|
|
+ max-height: 64vh;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+ .history-item {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ padding: 8upx 6upx;
|
|
|
+ border-bottom: 1upx solid #f0f0f0;
|
|
|
+ }
|
|
|
+ .history-item-body {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+ }
|
|
|
+ .history-del {
|
|
|
+ flex-shrink: 0;
|
|
|
+ font-size: 11upx;
|
|
|
+ color: #e54545;
|
|
|
+ padding: 4upx 8upx;
|
|
|
+ margin-left: 6upx;
|
|
|
+ }
|
|
|
+ .history-line {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ justify-content: space-between;
|
|
|
+ margin-bottom: 4upx;
|
|
|
+ }
|
|
|
+ .history-time {
|
|
|
+ font-size: 11upx;
|
|
|
+ color: #999999;
|
|
|
+ }
|
|
|
+ .history-total {
|
|
|
+ font-size: 11upx;
|
|
|
+ color: #09c567;
|
|
|
+ }
|
|
|
+ .history-detail {
|
|
|
+ font-size: 11upx;
|
|
|
+ color: #666666;
|
|
|
+ word-break: break-all;
|
|
|
+ }
|
|
|
+ .history-empty {
|
|
|
+ text-align: center;
|
|
|
+ font-size: 11upx;
|
|
|
+ color: #cccccc;
|
|
|
+ padding: 16upx 0;
|
|
|
+ }
|
|
|
+ .discount-popup {
|
|
|
+ width: 52vw;
|
|
|
+ max-width: 400upx;
|
|
|
+ }
|
|
|
+ .discount-popup-toolbar {
|
|
|
+ flex-shrink: 0;
|
|
|
+ padding: 10upx 12upx 12upx;
|
|
|
+ border-bottom: 1upx solid #f0f0f0;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+ .discount-custom-row {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+ .discount-custom-input {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+ height: 36upx;
|
|
|
+ line-height: 36upx;
|
|
|
+ padding: 0 10upx;
|
|
|
+ font-size: 13upx;
|
|
|
+ border: 1upx solid #dddddd;
|
|
|
+ border-radius: 6upx;
|
|
|
+ background: #ffffff;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+ .discount-custom-add-btn {
|
|
|
+ flex-shrink: 0;
|
|
|
+ margin-left: 8upx;
|
|
|
+ padding: 0 14upx;
|
|
|
+ height: 36upx;
|
|
|
+ line-height: 36upx;
|
|
|
+ font-size: 13upx;
|
|
|
+ color: #ffffff;
|
|
|
+ background: #09c567;
|
|
|
+ border-radius: 6upx;
|
|
|
+ text-align: center;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+ .discount-toolbar-hint {
|
|
|
+ display: block;
|
|
|
+ font-size: 11upx;
|
|
|
+ color: #09c567;
|
|
|
+ line-height: 1.4;
|
|
|
+ padding: 8upx 4upx 0;
|
|
|
+ }
|
|
|
+ .discount-toolbar-hint--muted {
|
|
|
+ color: #999999;
|
|
|
+ }
|
|
|
+ .discount-popup-body-scroll {
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 10upx 12upx 12upx;
|
|
|
+ }
|
|
|
+ .discount-option {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 12upx 10upx;
|
|
|
+ border: 1upx solid #eeeeee;
|
|
|
+ border-radius: 6upx;
|
|
|
+ margin-bottom: 8upx;
|
|
|
+ background: #fafafa;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+ .discount-option--active {
|
|
|
+ border-color: #09c567;
|
|
|
+ background: #f0fff4;
|
|
|
+ }
|
|
|
+ .discount-option-text {
|
|
|
+ font-size: 14upx;
|
|
|
+ color: #333333;
|
|
|
+ }
|
|
|
+ .discount-option-check {
|
|
|
+ font-size: 14upx;
|
|
|
+ color: #09c567;
|
|
|
+ font-weight: bold;
|
|
|
+ }
|
|
|
+ .discount-option--with-del {
|
|
|
+ padding-right: 6upx;
|
|
|
+ }
|
|
|
+ .discount-option-main {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
display: flex;
|
|
|
+ flex-direction: row;
|
|
|
align-items: center;
|
|
|
- margin-top:10upx;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding-right: 8upx;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+ .discount-option-del {
|
|
|
+ flex-shrink: 0;
|
|
|
+ font-size: 11upx;
|
|
|
+ color: #e54545;
|
|
|
+ padding: 4upx 8upx;
|
|
|
+ }
|
|
|
+ .flower-open_box {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-top: 10upx;
|
|
|
justify-content: center;
|
|
|
& > view {
|
|
|
- width:90upx;
|
|
|
+ width: 100%;
|
|
|
+ box-sizing: border-box;
|
|
|
& .desc {
|
|
|
text-align: center;
|
|
|
font-size: 13upx;
|
|
|
margin-bottom: 5upx;
|
|
|
- color:#CCCCCC;
|
|
|
+ color: #cccccc;
|
|
|
}
|
|
|
& .flower-unit_box {
|
|
|
display: flex;
|
|
|
- font-size:15upx;
|
|
|
+ font-size: 15upx;
|
|
|
align-items: center;
|
|
|
- justify-content:center;
|
|
|
+ justify-content: center;
|
|
|
border-bottom: 1px solid #eee;
|
|
|
- & > text{
|
|
|
- height:25upx;
|
|
|
+ & > text {
|
|
|
+ height: 25upx;
|
|
|
}
|
|
|
- .selected{
|
|
|
- background:blue;
|
|
|
- color:white;
|
|
|
+ .selected {
|
|
|
+ background: blue;
|
|
|
+ color: white;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- .switch-button{
|
|
|
+ .flower-open_box.pay-amount-col {
|
|
|
+ margin-top: 0;
|
|
|
+ }
|
|
|
+ .switch-button {
|
|
|
display: flex;
|
|
|
justify-content: center;
|
|
|
width: 35upx;
|
|
|
height: 35upx;
|
|
|
position: absolute;
|
|
|
- top:70upx;
|
|
|
- left:14vw;
|
|
|
+ top: 70upx;
|
|
|
+ left: 14vw;
|
|
|
.change-unit {
|
|
|
width: 35upx;
|
|
|
height: 35upx;
|
|
|
}
|
|
|
}
|
|
|
- & .keyboard-body_box {
|
|
|
+ .keyboard-body_box {
|
|
|
flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ padding-top: 0;
|
|
|
+ border-top: none;
|
|
|
overflow: hidden;
|
|
|
}
|
|
|
}
|
|
|
+.keyboard-body_box .numpad {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ min-height: 0;
|
|
|
+}
|
|
|
+.numpad {
|
|
|
+ width: 100%;
|
|
|
+ background: #ececec;
|
|
|
+ border-radius: 8upx;
|
|
|
+ padding: 8upx;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+.numpad-grid-wrap {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: stretch;
|
|
|
+ min-height: 0;
|
|
|
+}
|
|
|
+.numpad-digits {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ min-height: 0;
|
|
|
+}
|
|
|
+.numpad-digits .numpad-row {
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+.numpad-op-col {
|
|
|
+ width: 26%;
|
|
|
+ flex-shrink: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ margin-left: 8upx;
|
|
|
+}
|
|
|
+.numpad-op-col .numpad-key {
|
|
|
+ margin-left: 0;
|
|
|
+}
|
|
|
+.numpad-op-col .numpad-key-op {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ min-height: 44upx;
|
|
|
+ line-height: normal;
|
|
|
+ font-size: 22upx;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+.numpad-op-col .numpad-key-op + .numpad-key-op {
|
|
|
+ margin-top: 8upx;
|
|
|
+}
|
|
|
+.numpad-key-op-muted {
|
|
|
+ font-size: 13upx;
|
|
|
+ font-weight: 600;
|
|
|
+ background: #e8e8e8;
|
|
|
+ color: #333333;
|
|
|
+ box-shadow: 0 2upx 0 #bdbdbd;
|
|
|
+}
|
|
|
+.keyboard-body_box .numpad-op-col .numpad-key-op {
|
|
|
+ min-height: 0;
|
|
|
+}
|
|
|
+.keyboard-body_box .numpad-row {
|
|
|
+ flex: 1;
|
|
|
+ min-height: 40upx;
|
|
|
+}
|
|
|
+.numpad-row {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ margin-top: 8upx;
|
|
|
+ &:first-child {
|
|
|
+ margin-top: 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+.keyboard-body_box .numpad-key {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ height: auto;
|
|
|
+ min-height: 44upx;
|
|
|
+ line-height: normal;
|
|
|
+}
|
|
|
+.numpad-key {
|
|
|
+ flex: 1;
|
|
|
+ margin-left: 8upx;
|
|
|
+ height: 44upx;
|
|
|
+ line-height: 44upx;
|
|
|
+ text-align: center;
|
|
|
+ font-size: 18upx;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #222222;
|
|
|
+ background: #ffffff;
|
|
|
+ border-radius: 8upx;
|
|
|
+ box-shadow: 0 2upx 0 #c8c8c8;
|
|
|
+ &:first-child {
|
|
|
+ margin-left: 0;
|
|
|
+ }
|
|
|
+ &:active {
|
|
|
+ background: #e8e8e8;
|
|
|
+ box-shadow: 0 1upx 0 #bbbbbb;
|
|
|
+ }
|
|
|
+}
|
|
|
+.numpad-key-muted {
|
|
|
+ font-size: 22upx;
|
|
|
+ font-weight: 400;
|
|
|
+ color: #555555;
|
|
|
+}
|
|
|
+.numpad-key-text {
|
|
|
+ font-size: 14upx;
|
|
|
+}
|
|
|
+.numpad-row-actions {
|
|
|
+ margin-top: 10upx;
|
|
|
+}
|
|
|
+.numpad-key-action-dual {
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+.numpad-key-delete-only {
|
|
|
+ flex: 1;
|
|
|
+ margin-left: 0;
|
|
|
+}
|
|
|
+.numpad-key-wide {
|
|
|
+ flex: 1.2;
|
|
|
+}
|
|
|
+.numpad-key-danger {
|
|
|
+ background: #ffeded;
|
|
|
+ color: #cc4444;
|
|
|
+ box-shadow: 0 2upx 0 #ddb8b8;
|
|
|
+}
|
|
|
+.numpad-key-action {
|
|
|
+ font-size: 14upx;
|
|
|
+ background: #f7f7f7;
|
|
|
+}
|
|
|
+.numpad-key-ok {
|
|
|
+ background: #09c567;
|
|
|
+ color: #ffffff;
|
|
|
+ font-weight: 600;
|
|
|
+ box-shadow: 0 2upx 0 #078a4a;
|
|
|
+}
|
|
|
+.numpad-key-ok:active {
|
|
|
+ background: #08b35d;
|
|
|
+}
|
|
|
</style>
|