Procházet zdrojové kódy

销花宝PC后台 开单界面调整

ouyang před 1 dnem
rodič
revize
ee0028e8b8

+ 124 - 96
ghs/src/components/order/OrderCommitDialog.vue

@@ -1,29 +1,16 @@
 <!--
-  开单确认提交弹窗
-  开单确认提交弹窗
+  开单确认提交面板(常驻在购物车右侧,非弹窗
+  由开单 POS 页四栏布局直接挂载,始终渲染;切换客户时刷新表单。
   UI/业务对齐 ghsApp affirm:配送、打折、付款与备注提交。
-  查看财务在 POS 购物车侧;本弹窗供 add.vue 复用。
 -->
 <template>
-  <el-dialog
-    title="确认提交"
-    :visible.sync="innerVisible"
-    :width="dialogWidth"
-    center
-    append-to-body
-    :close-on-click-modal="false"
-    custom-class="order-commit-dialog"
-    @open="onOpen"
-  >
+  <aside class="order-commit-panel">
+    <!-- 与购物车 .pos-cart-head 同高,保证右栏标题齐平 -->
+    <div class="panel-head">确认提交</div>
+    <!-- 中间可滚动:表单内容多,避免挤掉底部提交按钮 -->
+    <div class="panel-scroll">
     <div class="commit-body">
-      <div class="accounts-list">
-        <span class="accounts-label">当前门店</span>
-        <div class="accounts-center shop-name">{{ displayShopName }}</div>
-      </div>
-      <div class="accounts-list">
-        <span class="accounts-label">客户名称</span>
-        <div class="accounts-center" style="font-weight:bold;color:black;">{{ form.customName }}</div>
-      </div>
+      <!-- 当前门店/客户名称已移至顶栏展示,此处不再重复渲染;form.customName 仍用于提交 -->
 
       <!-- 批发商 pfLevel:同城/德邦等 -->
       <div class="accounts-list" v-if="currentShop.pfLevel && currentShop.pfLevel == 1">
@@ -254,12 +241,6 @@
           <el-input type="textarea" :rows="2" placeholder="请输入内容" v-model="form.remark" />
         </div>
       </div>
-      <div class="accounts-list accounts-list--footer">
-        <el-button @click="innerVisible = false">取消(Esc)</el-button>
-        <el-button type="primary" :loading="submitting" @click="submitOrder(false)">确认(Ctrl+Enter)</el-button>
-      </div>
-      <p class="tip">按 Tab 切到下一个,按空格选中</p>
-
       <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>
@@ -270,8 +251,17 @@
         </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
@@ -286,7 +276,7 @@
       </div>
     </el-dialog>
 
-    <!-- 打折:1–9折 / 不打 / 自定义 -->
+    <!-- 打折:1–9折 / 不打 / 自定义;append-to-body 保证遮罩盖住整页 -->
     <el-dialog title="选择打折" :visible.sync="discountVisible" width="440px" append-to-body>
       <div class="discount-box">
         <el-button
@@ -307,7 +297,7 @@
         <el-button @click="discountVisible = false">取消</el-button>
       </span>
     </el-dialog>
-  </el-dialog>
+  </aside>
 </template>
 
 <script>
@@ -316,7 +306,6 @@ import dayjs from 'dayjs'
 export default {
   name: 'OrderCommitDialog',
   props: {
-    visible: { type: Boolean, default: false },
     customId: { type: [Number, String], default: 0 },
     customName: { type: String, default: '' },
     /** 当前开单门店名,与 POS 页「当前在 xxx」一致 */
@@ -391,21 +380,12 @@ export default {
     }
   },
   computed: {
-    innerVisible: {
-      get() { return this.visible },
-      set(v) { this.$emit('update:visible', v) }
-    },
+    // 面板已隐藏「当前门店」行;仍保留计算,避免与 shopName/currentShop 同步逻辑脱节
     displayShopName() {
       if (this.shopName) return this.shopName
       const shop = this.currentShop || {}
       return shop.shopName || shop.name || '门店'
     },
-    dialogWidth() {
-      if (typeof window !== 'undefined' && window.innerWidth < 720) {
-        return '92%'
-      }
-      return '655px'
-    },
     displayPackCost() {
       return this.currentShop.pfLevel && this.currentShop.pfLevel == 1
     },
@@ -459,10 +439,24 @@ export default {
       } else {
         this.modifyPrice = val
       }
+    },
+    /** 切换客户时重置面板,避免沿用上一客户配送/付款等选项 */
+    customId() {
+      this.resetPanel()
+    },
+    customName(val) {
+      this.form.customName = val || ''
     }
   },
+  mounted() {
+    this.resetPanel()
+  },
   methods: {
-    onOpen() {
+    /**
+     * 重置面板表单与询价状态
+     * 用于:进页、切换客户、提交成功后;侧栏常驻,不再关弹窗
+     */
+    resetPanel() {
       this.diffList = []
       this.discountValue = 0
       this.customDiscount = ''
@@ -487,8 +481,6 @@ export default {
       this.form.callErrand = 0
       this.form.weight = 1
       this.form.deliveryRemark = ''
-      this.discountValue = 0
-      this.customDiscount = ''
       this.pickupTimeValue = dayjs().format('YYYY-MM-DD HH:mm')
       this.$nextTick(() => {
         this.modifyPrice = this.finalPrice
@@ -666,6 +658,8 @@ export default {
     },
     /**
      * 提交订单;forceDealPrice 为差价二次确认
+     * 成功后只重置面板并 emit success,不关侧栏(侧栏始终展示)
+     * 父页可通过 $refs.commitPanel.submitOrder(false) 走快捷键提交
      */
     submitOrder(forceDealPrice) {
       const that = this
@@ -756,7 +750,8 @@ export default {
             return
           }
           that.$notify({ title: '成功', message: '开单成功', type: 'success' })
-          that.innerVisible = false
+          // 成功后重置表单,面板继续常驻;清车等由父页 onOrderSuccess 处理
+          that.resetPanel()
           that.$emit('success', data)
         }).catch(() => {
           that.submitting = false
@@ -768,41 +763,82 @@ export default {
 </script>
 
 <style lang="scss">
-.order-commit-dialog {
-  .el-dialog__body {
-    max-height: calc(100vh - 160px);
-    overflow-y: auto;
-    padding-top: 10px;
-  }
-}
+/* 侧栏内嵌套弹窗无需改 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: 14px;
+    font-size: 13px;
     color: #666;
   }
   .accounts-list--top {
     align-items: flex-start;
   }
-  .accounts-list--footer {
-    justify-content: flex-end;
-    margin-top: 4px;
-  }
   .accounts-label {
     flex-shrink: 0;
-    width: 72px;
+    width: 64px;
     line-height: 32px;
   }
   .accounts-center {
     flex: 1;
     min-width: 0;
-    margin-left: 12px;
+    margin-left: 8px;
     text-align: left;
   }
   .accounts-center--row {
@@ -822,6 +858,27 @@ export default {
     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;
@@ -831,61 +888,34 @@ export default {
     flex-wrap: wrap;
   }
   .quote-item {
-    min-width: 88px;
-    margin: 0 8px 8px 0;
-    padding: 8px 10px;
+    width: calc(50% - 6px);
+    margin: 0 6px 6px 0;
+    padding: 8px;
     border: 1px solid #dcdfe6;
     border-radius: 4px;
-    text-align: center;
     cursor: pointer;
+    box-sizing: border-box;
     &.active {
       border-color: #3385ff;
       background: #ecf5ff;
-      color: #3385ff;
     }
     &.disabled {
-      opacity: 0.45;
-      cursor: not-allowed;
+      opacity: 0.5;
+      pointer-events: none;
     }
     .platform-name {
-      font-size: 13px;
       font-weight: 600;
+      color: #303133;
     }
     .platform-price {
+      color: #3385ff;
       margin-top: 4px;
-      font-size: 14px;
     }
     .platform-type {
-      margin-top: 2px;
       font-size: 12px;
       color: #909399;
     }
   }
-  .discount-tag {
-    margin-left: 8px;
-    color: #3385ff;
-    font-weight: 600;
-  }
-  .tip {
-    text-align: center;
-    color: #999;
-    margin: 8px 0 0;
-  }
-  .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;
-    .g { color: green; font-weight: bold; margin-left: 4px; }
-    .r { color: red; font-weight: bold; margin-left: 4px; }
-  }
 }
 .discount-box {
   .discount-btn {
@@ -895,8 +925,6 @@ export default {
     display: flex;
     align-items: center;
     margin-top: 12px;
-    padding-top: 12px;
-    border-top: 1px solid #ebeef5;
   }
 }
 </style>

+ 84 - 64
ghs/src/views/order/add.vue

@@ -1,7 +1,7 @@
 <!--
   PC 开单 POS 页(原客户列表入口改造)
-  三栏:分类 | 商品卡 | 购物车;进页默认快捷客户;切换客户不清其它购物车
-  点「提交订单」打开 OrderCommitDialog(UI 对齐 confirm,业务对齐 App affirm)
+  四栏:分类 | 商品卡 | 购物车(收窄) | 确认提交面板(常驻右侧,非弹窗)
+  进页默认快捷客户;切换客户不清其它购物车;提交在右侧面板完成
 -->
 <template>
   <div class="pos-page">
@@ -9,24 +9,27 @@
     <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">
-        <el-input
-          ref="goodsSearchRef"
-          v-model="globalPy"
-          clearable
-          size="medium"
-          prefix-icon="el-icon-search"
-          placeholder="搜索商品名称"
-          @input="onSearchInput"
-          @keyup.enter.native="doSearch"
-        />
-      </div>
-      <div class="pos-header-actions">
-        <el-button type="primary" size="medium" icon="el-icon-user" @click="openCustomPicker">选客户</el-button>
-        <el-button type="primary" plain size="medium" icon="el-icon-document" @click="goSkCustom">快捷开单</el-button>
+      <div class="pos-header-inner">
+        <div class="pos-search-wrap">
+          <el-input
+            ref="goodsSearchRef"
+            v-model="globalPy"
+            clearable
+            size="medium"
+            prefix-icon="el-icon-search"
+            placeholder="搜索商品名称"
+            @input="onSearchInput"
+            @keyup.enter.native="doSearch"
+          />
+        </div>
+        <div class="pos-header-actions">
+          <el-button type="primary" size="medium" icon="el-icon-user" @click="openCustomPicker">选客户</el-button>
+          <el-button type="primary" plain size="medium" icon="el-icon-document" @click="goSkCustom">快捷开单</el-button>
+        </div>
+        <!-- 客户名跟在快捷开单右侧(非整栏贴右缘);过长 ellipsis,title 悬停看全称 -->
+        <div class="pos-customer-name" :title="headerCustomerLabel">{{ headerCustomerLabel }}</div>
       </div>
     </div>
 
@@ -97,7 +100,7 @@
         </div>
       </section>
 
-      <!-- 右:购物车 -->
+      <!-- 购物车(收窄,右侧紧挨确认提交面板) -->
       <aside class="pos-cart">
         <div class="pos-cart-head">
           <span>购物车 ({{ allCount.kind || 0 }})</span>
@@ -154,9 +157,21 @@
             </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>
+
+      <!-- 最右:确认提交常驻面板(替代原弹窗) -->
+      <order-commit-dialog
+        ref="commitPanel"
+        :custom-id="currentCustomId"
+        :custom-name="currentCustomName"
+        :shop-name="shopDisplayName"
+        :select-list="selectList"
+        :goods-price="allPrice"
+        :book="formBook"
+        :custom-balance="customBalance"
+        @success="onOrderSuccess"
+      />
     </div>
 
     <!-- 选客户 -->
@@ -196,18 +211,6 @@
       @confirm="onEditConfirm"
       @closed="focusGoodsSearch"
     />
-
-    <order-commit-dialog
-      :visible.sync="commitVisible"
-      :custom-id="currentCustomId"
-      :custom-name="currentCustomName"
-      :shop-name="shopDisplayName"
-      :select-list="selectList"
-      :goods-price="allPrice"
-      :book="formBook"
-      :custom-balance="customBalance"
-      @success="onOrderSuccess"
-    />
   </div>
 </template>
 
@@ -242,7 +245,6 @@ export default {
       editVisible: false,
       editItem: {},
       editMode: 'add',
-      commitVisible: false,
       /** 员工财务权限;购物车内查看成本毛利 */
       hasFinance: 0,
       showFinance: 0
@@ -250,7 +252,7 @@ export default {
   },
   computed: {
     ...mapGetters(['shopInfo']),
-    /** 顶栏搜索左侧:当前开单客户名 */
+    /** 顶栏客户名(跟在快捷开单右侧;过长由 CSS ellipsis 截断) */
     headerCustomerLabel() {
       if (this.currentCustomId && this.currentCustomName) {
         return this.currentCustomName
@@ -543,31 +545,34 @@ export default {
       this.applyCustom(this.skCustomId, this.skCustomName || '快捷开单', true)
       this.focusGoodsSearch()
     },
-    openCommit() {
-      if (!this.ensureCustom()) return
-      if (this.$util.isEmpty(this.selectList)) {
-        this.$message({ message: '请选择花材', type: 'warning' })
-        return
-      }
-      this.commitVisible = true
-    },
+    /** 开单成功:播提示音并清空当前客户购物车 */
     onOrderSuccess() {
       this.successPlay()
       // 仅清空当前客户购物车
       this.removeFromSaveDirect()
       this.focusGoodsSearch()
     },
+    /**
+     * 快捷键:Esc 关改量弹窗;Ctrl+Enter 触发右侧面板提交;Ctrl+Alt+Enter 确认差价
+     */
     bindHotkeys() {
       const that = this
       document.onkeydown = function(e) {
         if (!e) return
         if (e.key == 'Escape') {
-          if (that.commitVisible) that.commitVisible = false
           if (that.editVisible) that.editVisible = false
           that.focusGoodsSearch()
         }
-        if (e.key == 'Enter' && e.ctrlKey && that.commitVisible) {
-          // 交由弹窗内按钮;此处不重复提交
+        // Ctrl+Enter:调用侧栏提交;差价二次确认用 Ctrl+Alt+Enter
+        if (e.key == 'Enter' && e.ctrlKey) {
+          const panel = that.$refs.commitPanel
+          if (!panel || typeof panel.submitOrder !== 'function') return
+          e.preventDefault()
+          if (e.altKey) {
+            panel.submitOrder(true)
+          } else {
+            panel.submitOrder(false)
+          }
         }
       }
     }
@@ -585,21 +590,28 @@ export default {
   box-sizing: border-box;
 }
 
+/* 整块居中,客户名跟在快捷开单右侧,不用 space-between 甩到屏幕右缘 */
 .pos-header {
   flex-shrink: 0;
   display: flex;
   align-items: center;
-  /* 客户名 + 搜索 + 按钮整块水平居中 */
   justify-content: center;
   padding: 10px 12px;
   background: #fff;
   border-bottom: 1px solid #ebeef5;
 }
 
+/* 搜索 / 选客户 / 快捷开单 / 客户名 同一排横向排列,作为整块被外层居中 */
+.pos-header-inner {
+  display: flex;
+  align-items: center;
+  min-width: 0;
+}
+
 .pos-customer-name {
-  flex-shrink: 0;
-  max-width: 200px;
-  margin-right: 12px;
+  flex-shrink: 1;
+  max-width: 220px;
+  margin-left: 12px;
   font-size: 16px;
   font-weight: 700;
   color: #303133;
@@ -883,8 +895,9 @@ export default {
 
 .pos-cart {
   flex-shrink: 0;
-  /* 原 300px 加宽 50% */
-  width: 450px;
+  /* 收窄购物车,腾出右侧确认提交面板空间 */
+  width: 320px;
+  max-width: 320px;
   background: #fff;
   border-left: 1px solid #ebeef5;
   display: flex;
@@ -892,12 +905,18 @@ export default {
   min-height: 0;
 }
 
+/* 与确认提交 .panel-head 统一高度,两侧标题视觉齐平 */
 .pos-cart-head {
   flex-shrink: 0;
+  box-sizing: border-box;
+  height: 48px;
+  min-height: 48px;
   display: flex;
   align-items: center;
   justify-content: space-between;
-  padding: 12px 14px;
+  padding: 0 14px;
+  font-size: 16px;
+  line-height: 22px;
   font-weight: 700;
   border-bottom: 1px solid #ebeef5;
   .clear-btn {
@@ -1026,17 +1045,18 @@ export default {
   font-size: 19px;
   color: #606266;
   line-height: 1.2;
-  max-width: 220px;
+  /* 购物车收窄后限制门店名宽度,避免撑破 */
+  max-width: 160px;
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
 }
 
-/* 查看财务单独一行 */
+/* 查看财务单独一行;提交已挪到右侧面板,不再预留按钮间距 */
 .footer-finance {
   display: flex;
   align-items: center;
-  margin-bottom: 12px;
+  margin-bottom: 0;
 }
 
 .footer-finance-sum {
@@ -1054,12 +1074,6 @@ export default {
   text-decoration: underline;
 }
 
-.submit-btn {
-  width: 100%;
-  height: 44px;
-  font-size: 16px;
-}
-
 .pos-empty {
   padding: 40px 12px;
   text-align: center;
@@ -1071,8 +1085,14 @@ export default {
     width: 140px;
   }
   .pos-cart {
-    /* 原断点 250px 同步加宽 50% */
-    width: 375px;
+    /* 窄屏同步收窄购物车 */
+    width: 300px;
+    max-width: 300px;
+  }
+  /* 窄屏同步略收提交面板,避免商品区过挤 */
+  ::v-deep .order-commit-panel {
+    width: 320px;
+    max-width: 320px;
   }
   .pos-customer-name {
     max-width: 140px;