|
|
@@ -9,7 +9,7 @@
|
|
|
<audio ref="noStockPlay"><source src="@/static/noStock.mp3" type="audio/mpeg"></audio>
|
|
|
<audio ref="successPlay"><source src="@/static/success1.mp3" type="audio/mpeg"></audio>
|
|
|
|
|
|
- <!-- 顶栏:左侧当前客户名,中间搜商品,右侧选客/快捷开单 -->
|
|
|
+ <!-- 顶栏整块居中:客户名 + 搜商品 + 选客/快捷开单 -->
|
|
|
<div class="pos-header">
|
|
|
<div class="pos-customer-name" :title="headerCustomerLabel">{{ headerCustomerLabel }}</div>
|
|
|
<div class="pos-search-wrap">
|
|
|
@@ -55,9 +55,10 @@
|
|
|
v-for="item in globalItemData"
|
|
|
:key="item.id"
|
|
|
class="pos-goods-card"
|
|
|
+ @click="openEditByCover(item)"
|
|
|
>
|
|
|
<div v-if="item.limitBuy > 0" class="pos-limit-tag">限购{{ item.limitBuy }}份</div>
|
|
|
- <div class="pos-goods-cover" @click="openEditByCover(item)">
|
|
|
+ <div class="pos-goods-cover">
|
|
|
<img :src="item.cover || item.bigCover" alt="" />
|
|
|
</div>
|
|
|
<div class="pos-goods-body">
|
|
|
@@ -74,20 +75,21 @@
|
|
|
<span class="spec">{{ formatSpec(item) }}</span>
|
|
|
<span v-if="goodsOrangeTag(item)" class="pos-orange-tag">{{ goodsOrangeTag(item) }}</span>
|
|
|
</div>
|
|
|
- <div class="pos-stepper">
|
|
|
+ <!-- 加减单独 stop,避免触发整卡弹窗 -->
|
|
|
+ <div class="pos-stepper" @click.stop>
|
|
|
<button
|
|
|
type="button"
|
|
|
class="pos-step-btn pos-step-btn--minus"
|
|
|
- @click.stop="stepItem(item, 'sub')"
|
|
|
+ @click="stepItem(item, 'sub')"
|
|
|
>−</button>
|
|
|
<div
|
|
|
class="pos-step-num"
|
|
|
- @click.stop="openEditByCover(item)"
|
|
|
+ @click="openEditByCover(item)"
|
|
|
>{{ displayCount(item) }}</div>
|
|
|
<button
|
|
|
type="button"
|
|
|
class="pos-step-btn pos-step-btn--plus"
|
|
|
- @click.stop="stepItem(item, 'add')"
|
|
|
+ @click="stepItem(item, 'add')"
|
|
|
>+</button>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -110,22 +112,27 @@
|
|
|
@click="openEditCart(row)"
|
|
|
>
|
|
|
<img class="pos-cart-cover" :src="row.cover || row.bigCover" alt="" />
|
|
|
- <div class="pos-cart-info">
|
|
|
- <div class="name">{{ row.name }}</div>
|
|
|
- <div class="sub">
|
|
|
- <template v-if="Number(row.bigCount) > 0">{{ row.bigCount }}{{ row.bigUnit || '扎' }}</template>
|
|
|
- <template v-if="Number(row.bigCount) > 0 && Number(row.smallCount) > 0">/</template>
|
|
|
- <template v-if="Number(row.smallCount) > 0">{{ row.smallCount }}{{ row.smallUnit || '支' }}</template>
|
|
|
- · ¥{{ parseFloat(row.userPrice) }}
|
|
|
+ <div class="pos-cart-main">
|
|
|
+ <div class="pos-cart-top">
|
|
|
+ <div class="name" :title="row.name">{{ row.name }}</div>
|
|
|
+ <div class="line-price">¥{{ lineAmount(row) }}</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- <div class="pos-cart-right">
|
|
|
- <div class="line-price">¥{{ lineAmount(row) }}</div>
|
|
|
- <div class="pos-stepper pos-stepper--sm" @click.stop>
|
|
|
- <el-button size="mini" type="primary" plain circle icon="el-icon-minus" @click="stepItem(row, 'sub')" />
|
|
|
- <!-- 点数量弹窗改量,与商品卡一致 -->
|
|
|
- <span class="num num--click" @click="openEditCart(row)">{{ displayCount(row) }}</span>
|
|
|
- <el-button size="mini" type="primary" circle icon="el-icon-plus" @click="stepItem(row, 'add')" />
|
|
|
+ <div class="pos-cart-mid">
|
|
|
+ <div class="unit-price">¥{{ parseFloat(row.userPrice) }}</div>
|
|
|
+ <div class="pos-stepper pos-stepper--sm" @click.stop>
|
|
|
+ <el-button size="mini" type="primary" plain circle icon="el-icon-minus" @click="stepItem(row, 'sub')" />
|
|
|
+ <span class="num num--click" @click="openEditCart(row)">{{ displayCount(row) }}</span>
|
|
|
+ <el-button size="mini" type="primary" circle icon="el-icon-plus" @click="stepItem(row, 'add')" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 查看财务时:成本/毛利挂在对应商品下方(对齐设计图) -->
|
|
|
+ <div
|
|
|
+ v-if="showFinance == 1"
|
|
|
+ class="pos-cart-finance"
|
|
|
+ :class="{ warn: Number(row.avCost) > Number(row.userPrice) && Number(row.bigCount) > 0 }"
|
|
|
+ >
|
|
|
+ 成本 ¥{{ row.avCost != null ? parseFloat(row.avCost) : 0 }}
|
|
|
+ 毛利 ¥{{ unitProfit(row) }}
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -135,8 +142,18 @@
|
|
|
合计: ¥ {{ allPrice }},{{ allCount.kind || 0 }}种,{{ allCount.bigLength || 0 }}扎
|
|
|
<template v-if="allCount.weight">,{{ allCount.weight }}公斤</template>
|
|
|
</div>
|
|
|
- <div class="sum-price">¥ {{ allPrice }}</div>
|
|
|
- <div class="shop-tip">当前在 {{ shopDisplayName }}</div>
|
|
|
+ <!-- 总价、当前在同一行;查看财务单独一行 -->
|
|
|
+ <div class="footer-main-row">
|
|
|
+ <div class="sum-price">¥ {{ allPrice }}</div>
|
|
|
+ <div class="shop-tip">当前在 {{ shopDisplayName }}</div>
|
|
|
+ </div>
|
|
|
+ <div v-if="hasFinance == 1" class="footer-finance" @click.stop>
|
|
|
+ <template v-if="showFinance == 1">
|
|
|
+ <span class="footer-finance-sum">成本 ¥{{ financeAvCost }},毛利 ¥{{ financeProfit }}</span>
|
|
|
+ <el-button type="text" class="cart-finance-link" @click="toggleFinance">关闭财务</el-button>
|
|
|
+ </template>
|
|
|
+ <el-button v-else type="text" class="cart-finance-link" @click="toggleFinance">查看财务</el-button>
|
|
|
+ </div>
|
|
|
<el-button type="primary" class="submit-btn" icon="el-icon-check" @click="openCommit">提交订单</el-button>
|
|
|
</div>
|
|
|
</aside>
|
|
|
@@ -225,7 +242,10 @@ export default {
|
|
|
editVisible: false,
|
|
|
editItem: {},
|
|
|
editMode: 'add',
|
|
|
- commitVisible: false
|
|
|
+ commitVisible: false,
|
|
|
+ /** 员工财务权限;购物车内查看成本毛利 */
|
|
|
+ hasFinance: 0,
|
|
|
+ showFinance: 0
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
|
@@ -236,11 +256,27 @@ export default {
|
|
|
return this.currentCustomName
|
|
|
}
|
|
|
return '未选客户'
|
|
|
+ },
|
|
|
+ /** 购物车总成本 */
|
|
|
+ financeAvCost() {
|
|
|
+ let avCost = 0
|
|
|
+ if (!this.$util.isEmpty(this.selectList)) {
|
|
|
+ this.selectList.forEach(item => {
|
|
|
+ const unitCost = item.avCost != null ? Number(item.avCost) : 0
|
|
|
+ avCost += unitCost * Number(item.bigCount || 0)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ return parseFloat(avCost.toFixed(2))
|
|
|
+ },
|
|
|
+ /** 毛利 = 花材合计 - 成本 */
|
|
|
+ financeProfit() {
|
|
|
+ return parseFloat((Number(this.allPrice || 0) - Number(this.financeAvCost)).toFixed(2))
|
|
|
}
|
|
|
},
|
|
|
mounted() {
|
|
|
this.bootstrap()
|
|
|
this.bindHotkeys()
|
|
|
+ this.loadStaffFinance()
|
|
|
},
|
|
|
beforeDestroy() {
|
|
|
document.onkeydown = null
|
|
|
@@ -255,6 +291,28 @@ export default {
|
|
|
successPlay() {
|
|
|
this.$refs.successPlay && this.$refs.successPlay.play()
|
|
|
},
|
|
|
+ /** 拉取员工财务权限(对齐 App staff.finance) */
|
|
|
+ loadStaffFinance() {
|
|
|
+ this.$service.shopAdmin.getStaffInfo().then(res => {
|
|
|
+ const staff = res.staff || (res.data && res.data.staff) || res || {}
|
|
|
+ this.hasFinance = Number(staff.finance) || 0
|
|
|
+ }).catch(() => {
|
|
|
+ // 兜底:merchant/detail 的 staff.finance
|
|
|
+ this.$service.common.shopInfo().then(res => {
|
|
|
+ const staff = res.staff || {}
|
|
|
+ this.hasFinance = Number(staff.finance) || 0
|
|
|
+ }).catch(() => {})
|
|
|
+ })
|
|
|
+ },
|
|
|
+ toggleFinance() {
|
|
|
+ this.showFinance = this.showFinance == 1 ? 0 : 1
|
|
|
+ },
|
|
|
+ /** 单品单位毛利 */
|
|
|
+ unitProfit(item) {
|
|
|
+ const price = Number(item.userPrice) || 0
|
|
|
+ const cost = item.avCost != null ? Number(item.avCost) : 0
|
|
|
+ return parseFloat((price - cost).toFixed(2))
|
|
|
+ },
|
|
|
/** 进页:门店名、快捷客户、分类花材,并聚焦搜索 */
|
|
|
async bootstrap() {
|
|
|
const query = this.$route.query || {}
|
|
|
@@ -531,6 +589,8 @@ export default {
|
|
|
flex-shrink: 0;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
+ /* 客户名 + 搜索 + 按钮整块水平居中 */
|
|
|
+ justify-content: center;
|
|
|
padding: 10px 12px;
|
|
|
background: #fff;
|
|
|
border-bottom: 1px solid #ebeef5;
|
|
|
@@ -549,10 +609,11 @@ export default {
|
|
|
}
|
|
|
|
|
|
.pos-search-wrap {
|
|
|
- flex: 1;
|
|
|
+ /* 相对 520 再短 1/3 */
|
|
|
+ flex: 0 0 347px;
|
|
|
+ width: 347px;
|
|
|
+ max-width: 347px;
|
|
|
min-width: 160px;
|
|
|
- /* 相对原 520 加宽一倍,便于小笔记本连续搜品 */
|
|
|
- max-width: 1040px;
|
|
|
::v-deep .el-input__inner {
|
|
|
height: 40px;
|
|
|
line-height: 40px;
|
|
|
@@ -617,7 +678,7 @@ export default {
|
|
|
gap: 12px;
|
|
|
}
|
|
|
|
|
|
-/* 横向商品卡:左方图 + 右信息区 */
|
|
|
+/* 横向商品卡:整卡可点弹窗,步进器单独 stop */
|
|
|
.pos-goods-card {
|
|
|
position: relative;
|
|
|
display: flex;
|
|
|
@@ -629,6 +690,10 @@ export default {
|
|
|
border-radius: 8px;
|
|
|
box-sizing: border-box;
|
|
|
overflow: hidden;
|
|
|
+ cursor: pointer;
|
|
|
+ &:hover {
|
|
|
+ border-color: #b3d8ff;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.pos-limit-tag {
|
|
|
@@ -766,7 +831,8 @@ export default {
|
|
|
}
|
|
|
|
|
|
.pos-step-num {
|
|
|
- width: 44px;
|
|
|
+ /* 加减中间数量框加宽一倍,便于点选改量 */
|
|
|
+ width: 88px;
|
|
|
height: 36px;
|
|
|
margin: 0 4px;
|
|
|
border: 1px solid #dcdfe6;
|
|
|
@@ -798,7 +864,7 @@ export default {
|
|
|
}
|
|
|
.num--click {
|
|
|
display: inline-block;
|
|
|
- min-width: 36px;
|
|
|
+ min-width: 72px;
|
|
|
height: 28px;
|
|
|
line-height: 26px;
|
|
|
margin: 0 4px;
|
|
|
@@ -848,49 +914,76 @@ export default {
|
|
|
|
|
|
.pos-cart-row {
|
|
|
display: flex;
|
|
|
- align-items: center;
|
|
|
- padding: 8px;
|
|
|
+ align-items: flex-start;
|
|
|
+ padding: 10px 8px;
|
|
|
border-radius: 6px;
|
|
|
cursor: pointer;
|
|
|
+ border-bottom: 1px solid #f0f2f5;
|
|
|
&:hover {
|
|
|
background: #f5f7fa;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.pos-cart-cover {
|
|
|
- width: 48px;
|
|
|
- height: 48px;
|
|
|
+ width: 56px;
|
|
|
+ height: 56px;
|
|
|
border-radius: 4px;
|
|
|
object-fit: cover;
|
|
|
flex-shrink: 0;
|
|
|
background: #f0f2f5;
|
|
|
}
|
|
|
|
|
|
-.pos-cart-info {
|
|
|
+.pos-cart-main {
|
|
|
flex: 1;
|
|
|
min-width: 0;
|
|
|
- margin-left: 8px;
|
|
|
+ margin-left: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.pos-cart-top {
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ justify-content: space-between;
|
|
|
.name {
|
|
|
- font-size: 13px;
|
|
|
- font-weight: 600;
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+ margin-right: 8px;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #303133;
|
|
|
overflow: hidden;
|
|
|
text-overflow: ellipsis;
|
|
|
white-space: nowrap;
|
|
|
}
|
|
|
- .sub {
|
|
|
- margin-top: 4px;
|
|
|
- font-size: 12px;
|
|
|
- color: #909399;
|
|
|
+ .line-price {
|
|
|
+ flex-shrink: 0;
|
|
|
+ color: #303133;
|
|
|
+ font-weight: 700;
|
|
|
+ font-size: 14px;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-.pos-cart-right {
|
|
|
- flex-shrink: 0;
|
|
|
+.pos-cart-mid {
|
|
|
+ margin-top: 6px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ .unit-price {
|
|
|
+ color: #3385ff;
|
|
|
+ font-weight: 700;
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 单品成本/毛利:挂在步进器下方右侧 */
|
|
|
+.pos-cart-finance {
|
|
|
+ margin-top: 6px;
|
|
|
text-align: right;
|
|
|
- .line-price {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #8b7355;
|
|
|
+ line-height: 1.3;
|
|
|
+ &.warn {
|
|
|
color: #f56c6c;
|
|
|
font-weight: 700;
|
|
|
- margin-bottom: 4px;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -901,23 +994,64 @@ export default {
|
|
|
background: #fff;
|
|
|
}
|
|
|
|
|
|
+/* 合计字号相对原先加大后的 24px 再缩小 1/3 → 16px */
|
|
|
.sum-line {
|
|
|
- font-size: 12px;
|
|
|
+ font-size: 16px;
|
|
|
color: #606266;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ line-height: 1.4;
|
|
|
+}
|
|
|
+
|
|
|
+/* 总价与当前在同一行 */
|
|
|
+.footer-main-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: baseline;
|
|
|
+ flex-wrap: wrap;
|
|
|
margin-bottom: 6px;
|
|
|
}
|
|
|
|
|
|
.sum-price {
|
|
|
- font-size: 22px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ /* 相对 44px 缩小 1/3 */
|
|
|
+ font-size: 29px;
|
|
|
font-weight: 700;
|
|
|
color: #f56c6c;
|
|
|
- margin-bottom: 4px;
|
|
|
+ line-height: 1.1;
|
|
|
+ margin-right: 10px;
|
|
|
}
|
|
|
|
|
|
.shop-tip {
|
|
|
- font-size: 12px;
|
|
|
- color: #909399;
|
|
|
- margin-bottom: 10px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ /* 相对 14px 再大 1/3 */
|
|
|
+ font-size: 19px;
|
|
|
+ color: #606266;
|
|
|
+ line-height: 1.2;
|
|
|
+ max-width: 220px;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+
|
|
|
+/* 查看财务单独一行 */
|
|
|
+.footer-finance {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.footer-finance-sum {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #3385ff;
|
|
|
+ font-weight: 700;
|
|
|
+ margin-right: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.cart-finance-link {
|
|
|
+ padding: 0;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #3385ff;
|
|
|
+ font-weight: 700;
|
|
|
+ text-decoration: underline;
|
|
|
}
|
|
|
|
|
|
.submit-btn {
|
|
|
@@ -944,6 +1078,11 @@ export default {
|
|
|
max-width: 140px;
|
|
|
font-size: 14px;
|
|
|
}
|
|
|
+ .pos-search-wrap {
|
|
|
+ flex-basis: 280px;
|
|
|
+ width: 280px;
|
|
|
+ max-width: 280px;
|
|
|
+ }
|
|
|
.pos-goods-cover {
|
|
|
width: 84px;
|
|
|
height: 84px;
|