lilei 1 år sedan
förälder
incheckning
06ff99a801

+ 71 - 0
src/config/router.config.js

@@ -210,6 +210,77 @@ export const asyncRouterMap = [
               }
             ]
           },
+          {
+            path: '/salesManagement/salesQueryNew',
+            redirect: '/salesManagement/salesQueryNew/list',
+            name: 'salesQueryNew',
+            component: BlankLayout,
+            meta: {
+              title: '销售单查询(新版)',
+              icon: 'monitor',
+              permission: 'M_salesQueryList'
+            },
+            hideChildrenInMenu: true,
+            children: [
+              {
+                path: 'list',
+                name: 'salesQueryNewList',
+                component: () => import(/* webpackChunkName: "salesManagement" */ '@/views/salesManagement/salesQueryNew/list.vue'),
+                meta: {
+                  title: '销售单列表(新版)',
+                  icon: 'monitor',
+                  hidden: true,
+                  permission: 'M_salesQueryList'
+                }
+              },
+              {
+                path: 'detail/:sn',
+                name: 'salesNewDetail',
+                component: () => import(/* webpackChunkName: "salesManagement" */ '@/views/salesManagement/salesQueryNew/detail.vue'),
+                meta: {
+                  title: '销售单详情(新版)',
+                  icon: 'monitor',
+                  hidden: true,
+                  replaceTab: true,
+                  permission: 'B_salesDetail'
+                }
+              },
+              {
+                path: 'detail/:sn',
+                name: 'salesNewDetailAudit',
+                component: () => import(/* webpackChunkName: "salesManagement" */ '@/views/salesManagement/salesQueryNew/detail.vue'),
+                meta: {
+                  title: '销售单审核(新版)',
+                  icon: 'monitor',
+                  hidden: true,
+                  replaceTab: true,
+                  permission: 'B_salesAudit'
+                }
+              },
+              {
+                path: 'add/:sn',
+                name: 'salesNewAdd',
+                component: () => import(/* webpackChunkName: "salesManagement" */ '@/views/salesManagement/salesQueryNew/edit.vue'),
+                meta: {
+                  title: '新增销售单(新版)',
+                  icon: 'monitor',
+                  hidden: true,
+                  permission: 'B_salesEdit'
+                }
+              },
+              {
+                path: 'edit/:sn',
+                name: 'salesNewEdit',
+                component: () => import(/* webpackChunkName: "salesManagement" */ '@/views/salesManagement/salesQueryNew/edit.vue'),
+                meta: {
+                  title: '编辑销售单(新版)',
+                  icon: 'monitor',
+                  hidden: true,
+                  permission: 'B_salesEdit'
+                }
+              },
+            ]
+          },
           {
             path: '/salesManagement/salesOrderWarehouse',
             redirect: '/salesManagement/salesOrderWarehouse/list',

+ 221 - 0
src/views/salesManagement/salesQueryNew/chooseCustomModal.vue

@@ -0,0 +1,221 @@
+<template>
+  <a-modal
+    v-model="opened"
+    :title="title"
+    centered
+    :maskClosable="false"
+    :confirmLoading="confirmLoading"
+    :width="800"
+    :footer="null"
+    @cancel="cancel"
+  >
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-form-model
+        id="chooseCustom-form"
+        ref="ruleForm"
+        :model="form"
+        :rules="rules"
+        :label-col="formItemLayout.labelCol"
+        :wrapper-col="formItemLayout.wrapperCol">
+        <a-form-model-item label="客户名称" prop="buyerSn">
+          <dealerSubareaScopeList ref="dealerSubareaScopeList" id="chooseCustom-buyerSn" defValKey="buyerSn" @change="custChange" v-model="form.buyerSn" />
+        </a-form-model-item>
+        <a-form-model-item label="支付方式" prop="settleStyleSn">
+          <v-select
+            code="SETTLE_STYLE"
+            id="chooseCustom-settleStyleSn"
+            v-model="form.settleStyleSn"
+            allowClear
+            placeholder="请选择支付方式"></v-select>
+        </a-form-model-item>
+        <a-form-model-item prop="consigneeTel">
+          <span slot="label">收货地址</span>
+          {{ chooseAddr }}
+          <a-button type="link" :disabled="!form.buyerSn" id="chooseCustom-chooseAddr" @click="handleChoose">{{ addressVal }} >></a-button>
+        </a-form-model-item>
+        <!--  <a-form-model-item label="出库仓库" prop="warehouseSn">
+          <chooseWarehouse ref="warehouse" v-model="form.warehouseSn"></chooseWarehouse>
+        </a-form-model-item> -->
+        <a-form-model-item :wrapper-col="{ span: 12, offset: 6 }" style="text-align: center;">
+          <a-button type="primary" :loading="confirmLoading" @click="handleSubmit" id="chooseCustom-btn-submit">保存</a-button>
+          <a-button @click="cancel" style="margin-left: 15px" id="chooseCustom-btn-back">取消</a-button>
+        </a-form-model-item>
+      </a-form-model>
+    </a-spin>
+    <!-- 选择地址 -->
+    <choose-address-modal :openModal="openAddrModal" :paramsData="form.buyerSn" @ok="handleOk" @verify="verifyFun" @close="openAddrModal=false" />
+  </a-modal>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+import { VSelect } from '@/components'
+import dealerSubareaScopeList from '@/views/common/dealerSubareaScopeList.vue'
+import chooseAddressModal from './receivingAddress/chooseAddressModal.vue'
+import { dealerRecevieAddrQuery } from '@/api/dealerRecevieAddr'
+import chooseWarehouse from '@/views/common/chooseWarehouse'
+import { salesSave } from '@/api/sales'
+export default {
+  name: 'SalesChooseCustomModal',
+  mixins: [commonMixin],
+  components: { VSelect, dealerSubareaScopeList, chooseAddressModal, chooseWarehouse },
+  props: {
+    show: [Boolean]
+  },
+  data () {
+    return {
+      opened: this.show,
+      spinning: false,
+      title: '选择客户',
+      confirmLoading: false,
+      formItemLayout: {
+        labelCol: { span: 4 },
+        wrapperCol: { span: 18 }
+      },
+      form: {
+        buyerSn: undefined, // 客户sn
+        buyerName: '',
+        settleStyleSn: undefined,
+        shippingAddrProvinceSn: '',
+        shippingAddrProvinceName: '', // 省
+        shippingAddrCitySn: '',
+        shippingAddrCityName: '', // 市
+        shippingAddrCountySn: '',
+        shippingAddrCountyName: '', // 区
+        shippingAddr: '', // 详细地址
+        consigneeTel: '', // 联系电话
+        consigneeName: '', // 联系人名称
+        warehouseSn: undefined
+      },
+      rules: {
+        buyerSn: [ { required: true, message: '请选择客户', trigger: ['change', 'blur'] } ],
+        settleStyleSn: [ { required: true, message: '请选择支付方式', trigger: ['change', 'blur'] } ],
+        consigneeTel: [ { required: true, message: '请选择收货地址', trigger: ['change', 'blur'] } ],
+        warehouseSn: [ { required: true, message: '请选择出库仓库', trigger: ['change', 'blur'] } ]
+      },
+      addressVal: '选择地址', //  选择地址/更换地址
+      chooseAddr: '', //  当前已选地址信息
+      openAddrModal: false // 选择地址弹框是否显示
+    }
+  },
+  methods: {
+
+    // 客户 change
+    custChange (val) {
+      if (val && val.key) {
+        this.form.buyerSn = val.key || undefined
+        this.form.buyerName = val.name || ''
+        this.$refs.ruleForm.clearValidate()
+        this.getDefaultAddress()
+        if (val.row) {
+          this.form.warehouseSn = val.row.defaultWarehouseSn
+        }
+      } else {
+        this.form.buyerName = ''
+        this.form.buyerSn = undefined
+        this.form.warehouseSn = undefined
+        this.verifyFun(this.addressId)
+      }
+    },
+    //  选择地址
+    handleChoose () {
+      this.openAddrModal = true
+    },
+    //  保存
+    handleSubmit (e) {
+      e.preventDefault()
+      const _this = this
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          _this.salesSaveFun()
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    },
+    // 新建或编辑销售单
+    salesSaveFun () {
+      const _this = this
+      const form = this.form
+      _this.spinning = true
+      salesSave(form).then(res => {
+        if (res.status == 200) {
+          _this.$message.success(res.message)
+          _this.$emit('ok', res.data)
+          if (_this.form.id) {
+            _this.$emit('updateData')
+          }
+          _this.cancel()
+          _this.spinning = false
+        } else {
+          _this.spinning = false
+        }
+      })
+    },
+    cancel () {
+      this.opened = false
+      this.$emit('cancel')
+      this.$refs.ruleForm.resetFields()
+    },
+    //  地址保存
+    handleOk (data) {
+      this.chooseAddr = (data.consigneeName || '') + '(' + (data.consigneeTel || '-') + ')' + ' ' + (data.address || '')
+      this.addressVal = '更换地址'
+      this.form.shippingAddrProvinceSn = data.provinceSn || ''
+      this.form.shippingAddrProvinceName = data.provinceName || '' // 省
+      this.form.shippingAddrCitySn = data.citySn || ''
+      this.form.shippingAddrCityName = data.cityName || '' // 市
+      this.form.shippingAddrCountySn = data.countySn || ''
+      this.form.shippingAddrCountyName = data.countyName || '' // 区
+      this.form.shippingAddr = data.addr || ''// 详细地址
+      this.form.consigneeTel = data.consigneeTel || '' // 联系电话
+      this.form.consigneeName = data.consigneeName || ''
+      this.addressId = data.id || undefined
+      this.openAddrModal = false
+      // 移除表单项的校验结果
+      this.$refs.ruleForm.clearValidate('consigneeTel')
+    },
+    verifyFun (id) {
+      if (id == this.addressId) {
+        this.chooseAddr = ''
+        this.addressVal = '选择地址'
+        this.form.shippingAddrProvinceSn = ''
+        this.form.shippingAddrProvinceName = ''// 省
+        this.form.shippingAddrCitySn = ''
+        this.form.shippingAddrCityName = '' // 市
+        this.form.shippingAddrCountySn = ''
+        this.form.shippingAddrCountyName = '' // 区
+        this.form.shippingAddr = ''// 详细地址
+        this.form.consigneeTel = '' // 联系电话
+        this.form.consigneeName = ''
+      }
+    },
+    // 获取默认地址
+    getDefaultAddress () {
+      dealerRecevieAddrQuery({ defaultFlag: 1, dealerSn: this.form.buyerSn }).then(res => {
+        if (res.status == 200) {
+          if (res.data.length == 1) {
+            const ret = res.data[0]
+            ret.address = (ret.provinceName ? (ret.provinceName + '-') : '') + (ret.cityName ? (ret.cityName + '-') : '') + (ret.countyName ? (ret.countyName + '-') : '') + ret.addr
+            this.addressId = ret.id || undefined
+            this.handleOk(ret)
+          } else {
+            this.verifyFun(this.addressId)
+          }
+        }
+      })
+    }
+  },
+  watch: {
+    show (newValue, oldValue) {
+      this.opened = newValue
+      if (!newValue) {
+        this.$refs.dealerSubareaScopeList.resetForm()
+        this.$refs.ruleForm.resetFields()
+        this.verifyFun(this.addressId)
+      }
+    }
+  }
+}
+</script>

+ 199 - 0
src/views/salesManagement/salesQueryNew/comps/chooseImportModal.vue

@@ -0,0 +1,199 @@
+<template>
+  <a-modal
+    centered
+    class="chooseImport-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="导入"
+    v-model="isShow"
+    @cancel="isShow=false"
+    :width="900">
+    <div class="chooseImport-con">
+      <!-- 可导入数据 -->
+      <p class="">可导入数据{{ loadData.length }}条</p>
+      <a-table
+        class="sTable"
+        ref="table"
+        size="small"
+        :rowKey="(record) => record.allocateSn"
+        :columns="nowColumns"
+        :dataSource="loadData"
+        :loading="loading"
+        :scroll="{ y: 200 }"
+        :pagination="false"
+        bordered>
+      </a-table>
+      <a-divider />
+      <!-- 不可导入数据 -->
+      <p class="red">不可导入数据{{ unLoadData.length }}条</p>
+      <a-table
+        class="unTable"
+        ref="unTable"
+        size="small"
+        :rowKey="(record) => record.errorDesc"
+        :columns="nowUnColumns"
+        :dataSource="unLoadData"
+        :loading="loading"
+        :scroll="{ y: 200 }"
+        :pagination="false"
+        bordered>
+      </a-table>
+      <!-- 按钮 -->
+      <div class="btn-con">
+        <a-button
+          type="primary"
+          id="chooseImport-submit"
+          size="large"
+          :class="loadData.length==0?'button-grey':'button-primary'"
+          @click="handleSubmit"
+          style="padding: 0 40px;">确认导入</a-button>
+        <a-button
+          id="chooseImport-cancel"
+          size="large"
+          class="button-cancel"
+          @click="isShow=false"
+          style="padding: 0 40px;margin-left: 15px;">取消</a-button>
+        <a-button
+          type="primary"
+          id="chooseImport-error"
+          size="large"
+          class="button-error"
+          @click="handleError"
+          style="padding: 0 40px;margin-left: 15px;">导出错误项</a-button>
+      </div>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+import { hdExportExcel } from '@/libs/exportExcel'
+import { salesParseProducts, salesFailExcel } from '@/api/salesDetail'
+export default {
+  name: 'SalesChooseImportModal',
+  mixins: [commonMixin],
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    paramsData: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      nowColumns: [
+        { title: '序号', dataIndex: 'no', width: '8%', align: 'center' },
+        { title: '产品编码', dataIndex: 'productCode', width: '25%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品名称', dataIndex: 'productEntity.name', width: '25%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '出库仓库', dataIndex: 'warehouseName', width: '20%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '数量', dataIndex: 'qtyText', width: '14%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '库存', dataIndex: 'stockQty', width: '14%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '单位', dataIndex: 'productEntity.unit', width: '14%', align: 'center', customRender: function (text) { return text || '--' } }
+      ],
+      loadData: [],
+      nowUnColumns: [
+        { title: '序号', dataIndex: 'no', width: '9%', align: 'center' },
+        { title: '产品编码', dataIndex: 'productCode', width: '20%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品名称', dataIndex: 'productEntity.name', width: '21%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '出库仓库', dataIndex: 'warehouseName', width: '21%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '数量', dataIndex: 'qtyText', width: '10%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '库存', dataIndex: 'stockQty', width: '10%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '单位', dataIndex: 'productEntity.unit', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '备注', dataIndex: 'errorDesc', width: '20%', align: 'center', customRender: function (text) { return text || '--' } }
+      ],
+      unLoadData: [],
+      loading: false
+    }
+  },
+  methods: {
+    getData () {
+      const _this = this
+      this.loading = true
+      const params = {
+        salesBillSn: this.paramsData.salesBillSn,
+        path: this.paramsData.path
+      }
+      salesParseProducts(params).then(res => {
+        this.loading = false
+        if (res.status == 200) {
+          if (res.data.okList && res.data.okList.length > 0) {
+            res.data.okList.map((item, index) => {
+              item.no = index + 1
+            })
+          }
+          if (res.data.failList && res.data.failList.length > 0) {
+            res.data.failList.map((item, index) => {
+              item.no = index + 1
+            })
+          }
+          _this.loadData = res.data.okList || []
+          _this.unLoadData = res.data.failList || []
+        }
+      })
+    },
+    // 确认导入
+    handleSubmit () {
+      if (this.loadData.length == 0) {
+        this.$message.warning('无可导入产品!')
+      } else {
+        this.$emit('ok', this.loadData)
+        this.isShow = false
+      }
+    },
+    // 导出
+    handleError () {
+      const _this = this
+      if (_this.unLoadData.length < 1) {
+        _this.$message.info('暂无可导出错误项~')
+        return
+      }
+      _this.spinning = true
+      const params = {
+        list: _this.unLoadData
+      }
+      hdExportExcel(salesFailExcel, params, '产品导入错误项', function () {
+        _this.spinning = false
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.loadData = []
+        this.unLoadData = []
+      } else {
+        this.getData()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .chooseImport-modal{
+    .chooseImport-con{
+      .red{
+        color: #f30;
+      }
+      .btn-con{
+        text-align: center;
+        margin: 30px 0 20px;
+        .button-cancel,.button-error{
+          font-size: 12px;
+        }
+      }
+    }
+  }
+</style>

+ 140 - 0
src/views/salesManagement/salesQueryNew/comps/chooseProduct.vue

@@ -0,0 +1,140 @@
+<template>
+  <a-modal
+    centered
+    class="chooseProducts-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="选择产品"
+    v-model="isShow"
+    @cancel="isShow=false"
+    width="70%">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <div class="products-con">
+        <div>
+          <!-- 查询配件列表 -->
+          <queryPart
+            ref="partQuery"
+            :showRemark="true"
+            :showReceiveQty="true"
+            :isShowPrice="isShowPrice"
+            :returnReasonList="returnReasonList"
+            :newLoading="isInster"
+            @add="saveProduct"></queryPart>
+        </div>
+      </div>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+import queryPart from '@/views/salesReturnManagement/salesReturn/queryPart.vue'
+export default {
+  name: 'ChooseProductsModal',
+  components: { queryPart },
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    chooseData: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    buyerSn: {
+      type: String,
+      default: ''
+    },
+    isShowPrice: { //  弹框显示状态
+      type: Boolean,
+      default: true
+    },
+    goodFlag: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      spinning: false,
+      isShow: this.openModal, //  是否打开弹框
+      returnReasonList: [],
+      isInster: false //  表格加载中
+    }
+  },
+  methods: {
+    // 添加或修改产品
+    saveProduct (row) {
+      // 防止多次添加产品
+      if (this.isInster) {
+        return
+      }
+      if (!row.receiveQty) {
+        this.$message.info('请输入仓库实收数量')
+        return
+      }
+      if (!row.returnReasonCode) {
+        this.$message.info('请选择退货原因')
+        return
+      }
+      const rows = this.returnReasonlist.find(item => item.code == row.returnReasonCode)
+      const params = {
+        'price': row.productPrice,
+        'returnReasonCode': row.returnReasonCode,
+        'returnReason': rows ? rows.dispName : '',
+        'returnReasonRemarks': row.returnReasonRemarks,
+        'productSn': row.productSn,
+        'initialQty': row.qty,
+        'receiveQty': row.receiveQty
+      }
+      this.isInster = true
+      this.$emit('addProduct', params)
+    },
+    resetLoading () {
+      this.isInster = false
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+      } else {
+        if (this.goodFlag == 'DEFECTIVE_PRODUCT_RETURN') {
+          this.returnReasonlist = this.$store.state.app.defectiveReturnReason
+        }
+        // 良品
+        if (this.goodFlag == 'GOOD_PRODUCT_RETURN') {
+          this.returnReasonlist = this.$store.state.app.goodReturnReason
+        }
+        // 全部
+        if (!this.goodFlag) {
+          this.returnReasonlist = [...this.$store.state.app.goodReturnReason, ...this.$store.state.app.defectiveReturnReason]
+        }
+        this.$nextTick(() => {
+          this.$refs.partQuery.pageInit(this.buyerSn || '')
+        })
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .chooseProducts-modal{
+    .products-con{
+      .btn-con{
+        text-align: center;
+        margin: 30px 0 20px;
+        .button-cancel{
+          font-size: 12px;
+        }
+      }
+    }
+  }
+</style>

+ 210 - 0
src/views/salesManagement/salesQueryNew/comps/importGuideModal.vue

@@ -0,0 +1,210 @@
+<template>
+  <a-modal
+    centered
+    class="importGuide-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="导入"
+    v-model="isShow"
+    @cancel="isShow=false"
+    :width="750">
+    <div class="importGuide-con">
+      <div class="explain-con">
+        <div class="explain-item">
+          <div class="explain-tit">
+            <span>1</span>准备导入
+          </div>
+          <ul>
+            <li>1) 导入的Excel文件中必须包含名为“产品编码”、“数量”、“出库仓库”的列,且名称必须相同</li>
+            <li>2) 除了“产品编码”、“数量”、“出库仓库”三列,其他列可自定义,不影响数据导入</li>
+            <li>3) 如果导入的产品已经存在,则不会导入该行</li>
+            <li>
+              <a :href="filePath" style="margin: 5px 0 0;display: block;">
+                <a-icon type="download" style="padding-right: 5px;" />下载导入模板
+              </a>
+            </li>
+          </ul>
+          <!-- <a-button type="link" icon="download" style="padding: 0 0 0 23px;" :loading="exportLoading" @click="handleExport">下载导入模板</a-button> -->
+        </div>
+        <div class="explain-item">
+          <div class="explain-tit">
+            <span>2</span>上传数据文件
+          </div>
+          <p>目前支持的文件类型*.xls,*.xlsx.</p>
+          <div style="overflow: hidden;padding-left: 23px;">
+            <Upload
+              id="importGuide-attachList"
+              ref="importUpload"
+              :maxNums="1"
+              fileType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel"
+              uploadType="import"
+              :action="attachAction"
+              :uploadParams="uploadParams"
+              upText="添加文件"
+              @change="changeImport"></Upload>
+          </div>
+        </div>
+      </div>
+      <!-- 按钮 -->
+      <div class="btn-con">
+        <a-button
+          type="primary"
+          id="importGuide-nextStep"
+          size="large"
+          class="button-primary"
+          @click="handlerNextStep"
+          style="padding: 0 60px;">下一步</a-button>
+        <a-button
+          id="importGuide-cancel"
+          size="large"
+          class="button-cancel"
+          @click="isShow=false"
+          style="padding: 0 60px;margin-left: 15px;">取消</a-button>
+      </div>
+    </div>
+    <!-- 导入 -->
+    <chooseImportModal :openModal="openImportModal" :paramsData="paramsData" @close="handleClose" @ok="hanldeOk" />
+  </a-modal>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+import ChooseImportModal from './chooseImportModal.vue'
+import { Upload } from '@/components'
+import { hdExportExcel } from '@/libs/exportExcel'
+import { salesDownload } from '@/api/salesDetail'
+export default {
+  name: 'SalesImportGuideModal',
+  mixins: [commonMixin],
+  components: { ChooseImportModal, Upload },
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    params: {
+      type: Object,
+      default: null
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      openImportModal: false, //  导入
+      attachAction: process.env.VUE_APP_API_BASE_URL + '/upload',
+      paramsData: null,
+      uploadParams: {
+        savePathType: 'local'
+      },
+      exportLoading: false,
+      filePath: location.protocol + '//' + location.host + '/templ/销售导入产品模板.xlsx'
+    }
+  },
+  methods: {
+    // 下一步
+    handlerNextStep () {
+      if (this.paramsData) {
+        this.openImportModal = true
+      } else {
+        this.$message.warning('添加文件后再进行下一步操作!')
+      }
+    },
+    // 上传文件  change
+    changeImport (file) {
+      if (file) {
+        this.paramsData = {
+          salesBillSn: this.params.salesBillSn || '',
+          path: file
+        }
+      }
+    },
+    // 导入
+    hanldeOk (obj) {
+      if (obj && obj.length > 0) {
+        this.$emit('ok', obj)
+        this.isShow = false
+      }
+    },
+    // 关闭
+    handleClose () {
+      this.openImportModal = false
+      this.isShow = false
+    }
+    //  导出
+    // handleExport () {
+    //   const _this = this
+    //   const params = { grabFlag: this.params.grabFlag }
+    //   this.exportLoading = true
+    //   this.spinning = true
+    //   setTimeout(() => {
+    //     _this.exportLoading = false
+    //   }, 1000)
+    //   hdExportExcel(salesDownload, params, '销售导入模板', function () {
+    //     _this.spinning = false
+    //   })
+    // }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.paramsData = null
+        this.$refs.importUpload.setFileList('')
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .importGuide-modal{
+    .importGuide-con{
+      .explain-con{
+        .explain-item{
+          margin-bottom: 10px;
+          .explain-tit{
+            font-weight: bold;
+            span{
+              display: inline-block;
+              width: 18px;
+              height: 18px;
+              line-height: 16px;
+              text-align: center;
+              margin-right: 5px;
+              border-radius: 50%;
+              border: 1px solid rgba(0, 0, 0, 0.3);
+            }
+          }
+          p{
+            margin: 8px 0;
+            padding-left: 23px;
+          }
+          ul{
+            list-style: none;
+            padding: 0;
+            padding-left: 23px;
+            margin: 0;
+            li{
+              line-height: 26px;
+            }
+          }
+        }
+        #importGuide-attachList{
+          width: 100%;
+        }
+      }
+      .btn-con{
+        margin: 10px 0 20px;
+        text-align: center;
+        .button-cancel{
+          font-size: 12px;
+        }
+      }
+    }
+  }
+</style>

+ 532 - 0
src/views/salesManagement/salesQueryNew/comps/productList.vue

@@ -0,0 +1,532 @@
+<template>
+  <div>
+    <!-- 总计 -->
+    <a-alert type="info" style="margin-bottom: 10px;">
+      <div slot="message" class="total-bar">
+        <div>
+          <span v-if="$hasPermissions('B_salesEdit_salesPrice')">总售价:<strong>{{ detailData&&(detailData.totalCommonAmount || detailData.totalCommonAmount==0) ? toThousands(detailData.totalCommonAmount) : '--' }}</strong>;</span>
+          总款数:<strong>{{ detailData&&(detailData.totalCommonCategory || detailData.totalCommonCategory==0) ? detailData.totalCommonCategory : '--' }}</strong>;
+          总数量:<strong>{{ detailData&&(detailData.totalCommonQty || detailData.totalCommonQty==0) ? detailData.totalCommonQty : '--' }}</strong>;
+        </div>
+      </div>
+    </a-alert>
+    <!-- 筛选条件 -->
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline" @keyup.enter.native="$refs.table.refresh(true)">
+        <a-row :gutter="15">
+          <a-col :md="4" :sm="24">
+            <a-form-item label="出库仓库" prop="warehouseSn">
+              <chooseWarehouse ref="warehouse" v-model="queryParam.warehouseSn"></chooseWarehouse>
+            </a-form-item>
+          </a-col>
+          <a-col :md="4" :sm="24">
+            <a-form-item label="产品编码" prop="productCode">
+              <a-input id="salesEdit-productCode" v-model.trim="queryParam.productCode" placeholder="请输入产品编码" allowClear />
+            </a-form-item>
+          </a-col>
+          <a-col :md="4" :sm="24">
+            <a-form-item label="产品名称" prop="productName">
+              <a-input id="salesEdit-productName" v-model.trim="queryParam.productName" placeholder="请输入产品名称" allowClear />
+            </a-form-item>
+          </a-col>
+          <a-col :md="4" :sm="24">
+            <a-form-item label="品牌">
+              <ProductBrand id="salesEdit-productBrandSn" v-model="queryParam.productBrandSn"></ProductBrand>
+            </a-form-item>
+          </a-col>
+          <a-col :md="4" :sm="24">
+            <a-form-item label="产品分类">
+              <productTypeAll placeholder="请选择产品分类" @change="changeProductType" v-model="productType" id="salesEdit-productType"></productTypeAll>
+            </a-form-item>
+          </a-col>
+          <a-col :md="4" :sm="24" style="margin-bottom: 10px;">
+            <a-button type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="salesEdit-refresh">查询</a-button>
+            <a-button style="margin-left: 5px" @click="resetSearchForm" :disabled="disabled" id="salesEdit-reset">重置</a-button>
+          </a-col>
+          <a-col :md="12" :sm="24" style="text-align:left;">
+            <a-dropdown>
+              <a-menu slot="overlay" @click="handleMenuClick">
+                <a-menu-item key="0">
+                  仓库设置
+                </a-menu-item>
+                <a-menu-item key="1">
+                  删除已选项
+                </a-menu-item>
+                <a-menu-item key="2">
+                  全部删除
+                </a-menu-item>
+              </a-menu>
+              <a-button
+                style="margin:0 15px 0 0;"
+                type="info"
+              > 批量操作 <a-icon type="down" /> </a-button>
+            </a-dropdown>
+            <span>已选{{ selectTotal }}项</span>
+          </a-col>
+          <a-col :md="12" :sm="24" style="text-align:right;">
+            <a-space>
+              <a-button
+                type="default"
+                @click="openGuideModal=true">导入产品</a-button>
+              <a-button
+                type="primary"
+                class="button-info"
+                @click="openCpModal=true">添加产品</a-button>
+            </a-space>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+    <!-- 已选配件列表 -->
+    <s-table
+      class="sTable"
+      ref="table"
+      size="small"
+      :rowKey="(record) => record.id"
+      :columns="columns"
+      :data="loadData"
+      :row-selection="{ columnWidth: 40 }"
+      @rowSelection="rowSelectionFun"
+      :defaultLoadData="false"
+      :scroll="{ y: 300 }"
+      bordered>
+      <!-- 产品编码 -->
+      <template slot="productCode" slot-scope="text, record">
+        <a-badge count="缺" v-if="Number(record.stockQty||0) < Number(record.unpushedQty||0)">
+          <div style="padding-right: 15px;">{{ text }}</div>
+        </a-badge>
+        <span v-if="!(Number(record.stockQty||0) < Number(record.unpushedQty||0))">{{ text }}</span>
+      </template>
+      <!-- 产品名称 -->
+      <template slot="productName" slot-scope="text, record">
+        <div class="ellipsisCon">
+          <a-tooltip placement="rightBottom">
+            <template slot="title">
+              <span>{{ text }}</span>
+            </template>
+            <span class="ellipsisText">{{ text }}</span>
+          </a-tooltip>
+          <a-badge :number-style="{ backgroundColor: '#52c41a' }" count="活动" v-if="record.promotableFlag == 1"></a-badge>
+        </div>
+      </template>
+      <!-- 销售数量 -->
+      <template slot="salesNums" slot-scope="text, record">
+        <a-input-number
+          id="salesEdit-qty"
+          size="small"
+          v-model="record.qty"
+          :precision="0"
+          :min="1"
+          :max="999999"
+          placeholder="请输入"
+          @blur="e => onCellBlur(e.target.value, record)"
+          style="width: 100%;" />
+      </template>
+      <!-- 当前库存 -->
+      <template slot="stockQty" slot-scope="text, record">
+        <div v-if="record.stockQty || record.stockQty==0">
+          <p style="margin: 0;" v-if="Number(record.stockQty) < Number(record.unpushedQty)">{{ record.stockQty }}(<span class="redStyle">缺{{ Number(record.unpushedQty||0) - Number(record.stockQty||0) }}</span>)</p>
+          <p style="margin: 0;" v-else>{{ record.stockQty }}</p>
+        </div>
+        <span v-else>--</span>
+      </template>
+      <!-- 出库仓库 -->
+      <template slot="warehouseBox" slot-scope="text, record">
+        <chooseWarehouse style="width:100%;" :allowClear="false" ref="warehouseBox" v-model="record.warehouseSn" @change="handleWarehouseBox(record)"></chooseWarehouse>
+      </template>
+      <!-- 操作 -->
+      <template slot="action" slot-scope="text, record">
+        <a-button
+          size="small"
+          type="link"
+          :loading="delLoading"
+          class="button-error"
+          @click="handleDel(record)"
+        >删除</a-button>
+      </template>
+    </s-table>
+      <!-- 添加产品 -->
+      <chooseProduct
+        ref="chooseProduct"
+        :openModal="openCpModal"
+        :buyerSn="detailData&&detailData.buyerSn||''"
+        @close="openCpModal=false"
+        @addProduct="insterProduct"></chooseProduct>
+      <!-- 导入产品 -->
+      <importGuideModal :openModal="openGuideModal" :params="{salesBillSn: $route.params.sn}" @close="closeGuideModel" @ok="hanldeOk" />
+      <!-- 仓库设置 -->
+      <setWarehouse :show="openWarehouseModal" @ok="chooseWarehouseOk" @cancel="openWarehouseModal=false"></setWarehouse>
+  </div>
+</template>
+
+<script>
+  import { commonMixin } from '@/utils/mixin'
+  import { STable, VSelect } from '@/components'
+  import ImportGuideModal from './importGuideModal.vue'
+  import setWarehouse from './setWarehouse.vue'
+  import chooseProduct from './chooseProduct.vue'
+  import chooseWarehouse from '@/views/common/chooseWarehouse'
+  import ProductBrand from '@/views/common/productBrand.js'
+  import productTypeAll from '@/views/common/productTypeAll.js'
+  import { salesModify, salesDetailBySn, salesWriteSubmit, getPromoacActiveList, deleteAll, submitCheck, updateWarehouse } from '@/api/sales'
+  import { salesDetailStockList, salesDetailInsert, salesDetailUpdateQty, salesDetailDel, salesDetailBatchDel, salesDetailDelAll, addPromoGoods, salesBatchInsert } from '@/api/salesDetail'
+  export default {
+    name: 'ProductList',
+    mixins: [commonMixin],
+    components: { 
+      STable,
+      VSelect,
+      ImportGuideModal,
+      chooseWarehouse,
+      setWarehouse,
+      ProductBrand,
+      productTypeAll,
+      chooseProduct
+    },
+    props: {
+      openModal: { //  弹框显示状态
+        type: Boolean,
+        default: false
+      },
+      newLoading: Boolean,
+      detailData: {
+        type: Object,
+        default: function(){return null}
+      },
+      warehouseSn: {
+        type: String,
+        default: ''
+      },
+      salesBillSn: {
+        type: String,
+        default: ''
+      },
+    },
+    data () {
+      return {
+        spinning: false,
+        // 加载数据方法 必须为 Promise 对象
+        loadData: parameter => {
+          this.disabled = true
+          this.queryParam.salesBillSn = this.salesBillSn || ''
+          return salesDetailStockList(Object.assign(parameter, this.queryParam)).then(res => {
+            let data
+            if (res.status == 200) {
+              data = res.data
+              const no = (data.pageNo - 1) * data.pageSize
+              for (var i = 0; i < data.list.length; i++) {
+                data.list[i].no = no + i + 1
+                data.list[i].qtyBackups = data.list[i].qty
+              }
+              this.disabled = false
+              this.dataSource = data.list
+            }
+            return data
+          })
+        },
+        openCpModal: false,
+        openWarehouseModal: false, // 打开仓库设置
+        openGuideModal: false, //  导入产品引导
+        delLoading: false,
+        chooseDisabled: false,
+        disabled: false, //  查询、重置按钮是否可操作
+        queryParam: {
+          warehouseSn: undefined,
+          productCode: '',
+          productName: '',
+          productBrandSn: undefined,
+          productTypeSn1: '', //  产品一级分类
+          productTypeSn2: '', //  产品二级分类
+          productTypeSn3: '' //  产品三级分类
+        },
+        productType: [],
+        rowSelectionInfo: null,
+      }
+    },
+    computed: {
+      selectTotal () {
+        return this.rowSelectionInfo && this.rowSelectionInfo.selectedRowKeys.length || 0
+      },
+      columns () {
+        const arr = [
+          { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
+          { title: '产品编码', dataIndex: 'productEntity.code', scopedSlots: { customRender: 'productCode' }, width: '13%', align: 'center', sorter: true },
+          { title: '产品名称', dataIndex: 'productEntity.name', scopedSlots: { customRender: 'productName' }, width: '20%', align: 'left' },
+          // { title: '售价', dataIndex: 'price', width: '8%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+          { title: '销售数量', scopedSlots: { customRender: 'salesNums' }, width: '8%', align: 'center' },
+          { title: '库存', dataIndex: 'stockQty', scopedSlots: { customRender: 'stockQty' }, width: '8%', align: 'center' },
+          { title: '出库仓库', scopedSlots: { customRender: 'warehouseBox' }, width: '15%', align: 'center' },
+          { title: '单位', dataIndex: 'productEntity.unit', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
+          // { title: '售价小计', dataIndex: 'totalAmount', width: '8%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+          { title: '操作', scopedSlots: { customRender: 'action' }, width: '10%', align: 'center' }
+        ]
+        if (this.$hasPermissions('B_salesEdit_salesPrice')) { // 售价权限
+          arr.splice(3, 0, { title: '售价', dataIndex: 'price', width: '8%', align: 'right', customRender: text => ((text || text == 0) ? this.toThousands(text) : '--') })
+          arr.splice(7, 0, { title: '售价小计', dataIndex: 'totalAmount', width: '8%', align: 'right', customRender: text => ((text || text == 0) ? this.toThousands(text) : '--') })
+        }
+        return arr
+      }
+    },
+    watch: {
+      salesBillSn(newValue, oldValue) {
+        console.log(newValue)
+        this.resetSearchForm()
+      }
+    },
+    methods: {
+      // 表格选中项
+      rowSelectionFun (obj) {
+        this.rowSelectionInfo = obj || null
+      },
+      handleBatchDelAll () {
+        const _this = this
+        if (_this.dataSource.length == 0) {
+          _this.$message.warning('暂无可删除的已选产品!')
+          return
+        }
+        this.$confirm({
+          title: '提示',
+          content: '确认要删除全部已选产品吗?',
+          centered: true,
+          onOk () {
+            _this.spinning = true
+            deleteAll({ salesBillSn: _this.salesBillSn }).then(res => {
+              if (res.status == 200) {
+                _this.resetSearchForm(true)
+                _this.$refs.promotable.resetCurForm()
+                _this.$message.success(res.message)
+              }
+              _this.spinning = false
+            })
+          }
+        })
+      },
+      // 批量删除已选产品
+      handleBatchDel () {
+        const _this = this
+        if (!_this.rowSelectionInfo || (_this.rowSelectionInfo && _this.rowSelectionInfo.selectedRowKeys.length < 1)) {
+          _this.$message.warning('请先选择要删除的产品后再进行批量操作!')
+          return
+        }
+        const obj = []
+        _this.rowSelectionInfo && _this.rowSelectionInfo.selectedRows.map(item => {
+          obj.push(item.salesBillDetailSn)
+        })
+        this.$confirm({
+          title: '提示',
+          content: '已选产品' + obj.length + '项,确认要批量删除吗?',
+          centered: true,
+          onOk () {
+            _this.spinning = true
+            salesDetailBatchDel({
+              salesBillSn: _this.salesBillSn,
+              salesBillDetailSnList: obj
+            }).then(res => {
+              if (res.status == 200) {
+                _this.resetSearchForm(true)
+                _this.$refs.promotable.resetCurForm()
+                _this.$message.success(res.message)
+              }
+              _this.spinning = false
+            })
+          }
+        })
+      },
+      // 设置单个出库仓库
+      handleWarehouseBox (row) {
+        const snArr = [row.salesBillDetailSn]
+        const ajax_data = {
+          warehouseSn: row.warehouseSn,
+          salesBillDetailSnList: snArr,
+          salesBillSn: this.salesBillSn
+        }
+        this.setWarehouseInfo(ajax_data)
+      },
+      chooseWarehouseOk (sn) {
+        const _this = this
+        const snArr = []
+        _this.rowSelectionInfo.selectedRows.forEach(item => {
+          snArr.push(item.salesBillDetailSn)
+        })
+        const ajax_data = {
+          warehouseSn: sn,
+          salesBillDetailSnList: snArr,
+          salesBillSn: _this.salesBillSn
+        }
+        _this.setWarehouseInfo(ajax_data)
+      },
+      setWarehouseInfo (data) {
+        const _this = this
+        _this.spinning = true
+        updateWarehouse(data).then(res => {
+          if (res.status == 200) {
+            _this.openWarehouseModal = false
+            _this.resetSearchForm(true)
+            _this.$refs.promotable.resetCurForm()
+            _this.$message.success(res.message)
+          }
+          _this.$refs.table.refresh(true)
+          _this.spinning = false
+        })
+      },
+      //  产品分类  change
+      changeProductType (val, opt) {
+        this.queryParam.productTypeSn1 = val[0] ? val[0] : ''
+        this.queryParam.productTypeSn2 = val[1] ? val[1] : ''
+        this.queryParam.productTypeSn3 = val[2] ? val[2] : ''
+      },
+      handleMenuClick (e) {
+        const _this = this
+        if (e.key == 0) { // 仓库设置
+          if (!_this.rowSelectionInfo || (_this.rowSelectionInfo && _this.rowSelectionInfo.selectedRowKeys.length < 1)) {
+            _this.$message.warning('请先选择要设置的产品!')
+          } else {
+            _this.openWarehouseModal = true
+          }
+        } else if (e.key == 1) { // 删除已选项
+          this.handleBatchDel()
+        } else {
+          this.handleBatchDelAll()
+        }
+      },
+      // 已选产品  blur
+      onCellBlur (val, record) {
+        const _this = this
+        //  光标移出,值发生改变再调用编辑接口
+        if (val && val != record.qtyBackups) {
+          _this.spinning = true
+          salesDetailUpdateQty({
+            salesBillDetailSn: record.salesBillDetailSn,
+            qty: record.qty,
+            salesBillSn: _this.salesBillSn
+          }).then(res => {
+            _this.resetSearchForm(true)
+            _this.$refs.promotable.resetCurForm()
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+            }
+            _this.spinning = false
+          })
+        } else {
+          record.qty = record.qtyBackups
+        }
+      },
+      //  重置
+      resetSearchForm (flag) {
+        this.queryParam.productCode = ''
+        this.queryParam.productName = ''
+        this.queryParam.warehouseSn = undefined
+        this.queryParam.productBrandSn = undefined
+        this.queryParam.productTypeSn1 = ''
+        this.queryParam.productTypeSn2 = ''
+        this.queryParam.productTypeSn3 = ''
+        this.productType = []
+        this.$refs.table.refresh(!!flag)
+      },
+      // 整单删除
+      delSalerDetailAll () {
+        const _this = this
+        this.$confirm({
+          title: '提示',
+          content: '确认要整单删除吗?',
+          centered: true,
+          closable: true,
+          onOk () {
+            _this.delLoading = true
+            _this.spinning = true
+            salesDetailDelAll({ salesBillSn: _this.salesBillSn }).then(res => {
+              if (res.status == 200) {
+                _this.resetSearchForm()
+                _this.$refs.promotable.resetCurForm()
+                _this.$message.success(res.message)
+              }
+              _this.delLoading = false
+              _this.spinning = false
+            })
+          }
+        })
+      },
+      // 删除产品
+      handleDel (row) {
+        const _this = this
+        this.$confirm({
+          title: '提示',
+          content: '确认要删除吗?',
+          centered: true,
+          closable: true,
+          onOk () {
+            _this.delLoading = true
+            _this.spinning = true
+            salesDetailDel({ salesBillDetailSn: row.salesBillDetailSn, salesBillSn: _this.salesBillSn }).then(res => {
+              if (res.status == 200) {
+                _this.resetSearchForm(true)
+                _this.$refs.promotable.resetCurForm()
+                _this.$message.success(res.message)
+              }
+              _this.delLoading = false
+              _this.spinning = false
+            })
+          }
+        })
+      },
+      // 添加产品
+      insterProduct (row, promotionFlag) {
+        console.log(row)
+        // 防止多次添加产品
+        if (this.isInster) { return }
+        const _this = this
+        _this.saveNewProduct(row, promotionFlag)
+      },
+      // 保存添加的产品到销售列表
+      saveNewProduct (row, promotionFlag) {
+        this.$message.loading('正在添加产品...', 1)
+        this.isInster = true
+        this.spinning = true
+        salesDetailInsert({
+          packQty: row.productPackQty,
+          productSn: row.productSn,
+          showCost: row.lastStockCost,
+          price: row.productPrice,
+          origPrice: row.productPrice,
+          promotionGiftsAmount: 0,
+          usePromotionGiftsAmount: 0,
+          qty: row.salesNums,
+          salesBillSn: this.detailData.salesBillSn,
+          salesBillNo: this.detailData.salesBillNo,
+          purchaseBillSn: this.detailData.purchaseBillSn,
+          purchaseBillNo: this.detailData.purchaseBillNo,
+          stockSn: row.stockSn,
+          promotableFlag: row.isJoinActivityProduct || 0, // 可促销标记 有活动的传1,没活动的传0
+          promotionFlag: promotionFlag, // 促销标记 正品传0,促销品传1
+          warehouseSn: row.warehouseSn
+        }).then(res => {
+          if (res.status == 200) {
+            this.resetSearchForm()
+            this.$message.success('产品添加成功', 2.5)
+            this.spinning = false
+          } else {
+            this.spinning = false
+          }
+          this.isInster = false
+        }).catch(err => {
+          this.isInster = false
+        })
+      },
+      closeGuideModel () {
+        this.openGuideModal = false
+      },
+      // 导入产品
+      hanldeOk (obj) {
+        salesBatchInsert(obj).then(res => {
+          if (res.status == 200) {
+            this.$refs.table.refresh(true)
+            this.getOrderDetail(false)
+          }
+        })
+      },
+    }
+  }
+</script>
+
+<style>
+</style>

+ 91 - 0
src/views/salesManagement/salesQueryNew/comps/setWarehouse.vue

@@ -0,0 +1,91 @@
+<template>
+  <a-modal
+    v-model="opened"
+    :title="title"
+    centered
+    :maskClosable="false"
+    :confirmLoading="confirmLoading"
+    width="36%"
+    :footer="null"
+    @cancel="cancel"
+  >
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-form-model
+        id="chooseCustom-form"
+        ref="ruleForm"
+        :model="form"
+        :rules="rules"
+        :label-col="formItemLayout.labelCol"
+        :wrapper-col="formItemLayout.wrapperCol">
+        <a-form-model-item label="出库仓库" prop="warehouseSn">
+          <chooseWarehouse ref="warehouse" v-model="form.warehouseSn"></chooseWarehouse>
+        </a-form-model-item>
+        <a-form-model-item :wrapper-col="{ span: 12, offset: 6 }" style="text-align: center;margin-top:60px;">
+          <a-button @click="cancel" style="margin-right: 15px" id="chooseCustom-btn-back">取消</a-button>
+          <a-button type="primary" :loading="confirmLoading" @click="handleSubmit" id="chooseCustom-btn-submit">确定</a-button>
+        </a-form-model-item>
+      </a-form-model>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+import { VSelect } from '@/components'
+import chooseWarehouse from '@/views/common/chooseWarehouse'
+export default {
+  name: 'SetWarehouse',
+  mixins: [commonMixin],
+  components: { VSelect, chooseWarehouse },
+  props: {
+    show: [Boolean]
+  },
+  data () {
+    return {
+      opened: this.show,
+      spinning: false,
+      title: '批量设置出库仓库',
+      confirmLoading: false,
+      formItemLayout: {
+        labelCol: { span: 4 },
+        wrapperCol: { span: 18 }
+      },
+      form: {
+        warehouseSn: undefined
+      },
+      rules: {
+        warehouseSn: [ { required: true, message: '请选择出库仓库', trigger: ['change', 'blur'] } ]
+      }
+    }
+  },
+  methods: {
+    //  保存
+    handleSubmit (e) {
+      e.preventDefault()
+      const _this = this
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          _this.$emit('ok', this.form.warehouseSn)
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    },
+    cancel () {
+      this.opened = false
+      this.$emit('cancel')
+      this.$refs.ruleForm.resetFields()
+    }
+  },
+  watch: {
+    show (newValue, oldValue) {
+      this.opened = newValue
+      if (!newValue) {
+        this.form.warehouseSn = undefined
+        this.$refs.ruleForm.resetFields()
+      }
+    }
+  }
+}
+</script>

+ 540 - 0
src/views/salesManagement/salesQueryNew/detail.vue

@@ -0,0 +1,540 @@
+<template>
+  <div class="salesDetail-wrap">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-page-header :ghost="false" :backIcon="false" class="salesDetail-cont">
+        <template slot="subTitle" v-if="!bizSn">
+          <a href="javascript:;" @click="handleBack"><a-icon type="left"></a-icon> 返回列表</a>
+        </template>
+        <template slot="extra">
+          <a-button
+            key="1"
+            type="primary"
+            class="button-info"
+            id="salesDetail-xs-print-btn"
+            v-if="$hasPermissions('B_salesPrint')"
+            :disabled="localDataSource.length==0"
+            @click="handlePrint('SALES_BILL','B_salesPrint')">销售打印</a-button>
+          <a-button
+            key="2"
+            type="default"
+            class="button-info"
+            id="salesDetail-xsfl-print-btn"
+            v-if="$hasPermissions('B_salesTypePrint')"
+            :disabled="localDataSource.length==0"
+            @click="handlePrint('SALES_BILL_TYPE','B_salesTypePrint')">销售分类打印</a-button>
+          <a-divider type="vertical" />
+          <a-button
+            key="3"
+            type="primary"
+            class="button-info"
+            id="salesDetail-export-btn"
+            v-if="$hasPermissions('B_salesDetailExport')"
+            :disabled="localDataSource.length==0"
+            @click="handlePrint('export','B_salesDetailExport')">导出Excel</a-button>
+          <a-button
+            key="4"
+            type="default"
+            class="button-info"
+            id="salesDetail-export-btn"
+            v-if="$hasPermissions('B_salesTypeExport')"
+            :disabled="localDataSource.length==0"
+            @click="handlePrint('typeExport','B_salesTypeExport')">销售分类导出</a-button>
+        </template>
+      </a-page-header>
+      <!-- 基础信息 -->
+      <a-card size="small" :bordered="false" class="salesDetail-cont">
+        <a-collapse :activeKey="['1']">
+          <a-collapse-panel key="1" header="基础信息">
+            <a-descriptions size="small" :column="3">
+              <a-descriptions-item label="销售单号" :span="2">
+                {{ detailData&&detailData.salesBillNo || '--' }}
+                <span v-if="detailData&&detailData.salesBillNoSource">(原:{{ detailData&&detailData.salesBillNoSource || '--' }})</span>
+              </a-descriptions-item>
+              <a-descriptions-item label="客户名称">{{ detailData&&detailData.buyerName || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="收货地址" :span="2">{{ shippingAddress }}</a-descriptions-item>
+              <a-descriptions-item label="收款方式">{{ detailData&&detailData.settleStyleSnDictValue || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="收货人">{{ detailData&&detailData.salesBillExtEntity&&detailData.salesBillExtEntity.consigneeName || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="收货电话">{{ detailData&&detailData.salesBillExtEntity&&detailData.salesBillExtEntity.consigneeTel || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="审核时间">{{ detailData&&detailData.auditDate || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="业务状态">{{ detailData&&detailData.billStatusDictValue || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="财务状态">{{ detailData&&detailData.financialStatusDictValue || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="备注" :span="3">{{ detailData&&detailData.remarks || '--' }}</a-descriptions-item>
+            </a-descriptions>
+          </a-collapse-panel>
+        </a-collapse>
+      </a-card>
+      <a-card size="small" :bordered="false" class="pages-wrap">
+        <!-- alert -->
+        <a-alert type="info" style="margin-bottom: 10px;">
+          <div slot="message">
+            <div style="display: flex;justify-content: space-between;align-items: center;">
+              <div>
+                总销售数量:<strong>{{ detailData&&(detailData.totalQty || detailData.totalQty==0) ? detailData.totalQty : '--' }}</strong>;
+                已取消数量:<strong>{{ detailData&&(detailData.totalCancelQty || detailData.totalCancelQty==0) ? detailData.totalCancelQty : '--' }}</strong>;
+                已下推数量:<strong>{{ detailData&&(detailData.totalPushedQty || detailData.totalPushedQty==0) ? detailData.totalPushedQty : '--' }}</strong>;
+                待下推数量:<strong>{{ detailData&&(detailData.totalUnpushedQty || detailData.totalUnpushedQty==0) ? detailData.totalUnpushedQty : '--' }}</strong>;
+                已发货数量:<strong>{{ detailData&&(detailData.totalDispatchQty || detailData.totalDispatchQty==0) ? detailData.totalDispatchQty : '--' }}</strong>;
+                待发货数量:<strong>{{ detailData&&(detailData.totalUndispatchQty || detailData.totalUndispatchQty==0) ? detailData.totalUndispatchQty : '--' }}</strong>;<br/>
+                <span v-if="$hasPermissions(authCode + '_salesPrice')">总售价:<strong>{{ detailData&&(detailData.totalAmount || detailData.totalAmount==0) ? toThousands(detailData.totalAmount) : '--' }}</strong>;</span>
+                <span v-if="$hasPermissions(authCode + '_costPrice')">总成本:<strong>{{ detailData&&(detailData.totalCost || detailData.totalCost==0) ? toThousands(detailData.totalCost) : '--' }}</strong>;</span>
+                <span v-if="$hasPermissions(authCode + '_costPrice')">总毛利:<strong>{{ detailData&&(detailData.grossProfit || detailData.grossProfit==0) ? toThousands(detailData.grossProfit) : '--' }}</strong>;</span>
+                <span v-if="$hasPermissions(authCode + '_salesPrice')">已取消金额:<strong>{{ detailData&&(detailData.totalCancelAmount || detailData.totalCancelAmount==0) ? toThousands(detailData.totalCancelAmount) : '--' }}</strong>;</span>
+                <span v-if="$hasPermissions(authCode + '_salesPrice')">已下推金额:<strong>{{ detailData&&(detailData.totalPushedAmount || detailData.totalPushedAmount==0) ? toThousands(detailData.totalPushedAmount) : '--' }}</strong>;</span>
+                <span v-if="$hasPermissions(authCode + '_salesPrice')">待下推金额:<strong>{{ detailData&&(detailData.totalUnpushedAmount || detailData.totalUnpushedAmount==0) ? toThousands(detailData.totalUnpushedAmount) : '--' }}</strong>;</span>
+                <span v-if="$hasPermissions(authCode + '_salesPrice')">已发货金额:<strong>{{ detailData&&(detailData.totalDispatchAmount || detailData.totalDispatchAmount==0) ? toThousands(detailData.totalDispatchAmount) : '--' }}</strong>;</span>
+                <span v-if="$hasPermissions(authCode + '_salesPrice')">待发货金额:<strong>{{ detailData&&(detailData.totalUndispatchAmount || detailData.totalUndispatchAmount==0) ? toThousands(detailData.totalUndispatchAmount) : '--' }}</strong>;</span>
+                <span v-if="isCityPrice">市级总售价:<strong>{{ detailData&&(detailData.totalCityAmount || detailData.totalCityAmount==0) ? toThousands(detailData.totalCityAmount) : '--' }}</strong>;</span>
+              </div>
+              <div>
+                <a-button v-if="detailData && (detailData.billStatus == 'WAIT_AUDIT' || detailData.billStatus == 'HQ_CHANGE')" type="link" @click="openStockOut">缺货明细</a-button>
+                <a-checkbox v-model="isCityPrice" v-if="$hasPermissions(authCode + '_cityPrice')"><span style="display: inline-block;margin-top: 1px;">市级价</span></a-checkbox>
+              </div>
+            </div>
+          </div>
+        </a-alert>
+        <!-- 查询 -->
+        <div class="table-page-search-wrapper">
+          <a-form layout="inline" @keyup.enter.native="$refs.table.refresh(true)">
+            <a-row :gutter="15">
+              <a-col :md="6" :sm="24">
+                <a-form-item label="出库仓库">
+                  <chooseWarehouse ref="warehouse" v-model="queryParam.warehouseSn"></chooseWarehouse>
+                </a-form-item>
+              </a-col>
+              <a-col :md="6" :sm="24" style="margin-bottom: 10px;">
+                <a-button type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="productInfoList-refresh">查询</a-button>
+                <a-button style="margin-left: 5px" @click="resetSearchForm" id="productInfoList-reset">重置</a-button>
+              </a-col>
+            </a-row>
+          </a-form>
+        </div>
+        <!-- 列表 -->
+        <s-table
+          class="sTable"
+          ref="table"
+          size="small"
+          :rowKey="(record) => record.id"
+          :columns="columns"
+          :data="loadData"
+          :defaultLoadData="false"
+          :showPagination="false"
+          bordered>
+          <!-- 产品编码 -->
+          <template slot="productCode" slot-scope="text, record">
+            <div v-if="(record.promotionFlag == 1) || (Number(record.stockQty) < Number(record.unpushedQty)) && (detailData&&(detailData.billStatus == 'WAIT_AUDIT'||detailData.billStatus == 'HQ_CHANGE')&&$hasPermissions('B_salesAudit'))">
+              <span>{{ text }}</span>
+              <a-badge count="促" :number-style="{ backgroundColor: '#f90' }" v-if="record.promotionFlag == 1"></a-badge>
+              <!-- 可审核时才可显示“缺”货产品 -->
+              <a-badge count="缺" v-if="(Number(record.stockQty) < Number(record.unpushedQty)) && (detailData&&(detailData.billStatus == 'WAIT_AUDIT'||detailData.billStatus == 'HQ_CHANGE')&&$hasPermissions('B_salesAudit'))">
+              </a-badge>
+            </div>
+            <span v-if="!(record.promotionFlag == 1 || ((Number(record.stockQty) < Number(record.unpushedQty)) && (detailData&&(detailData.billStatus == 'WAIT_AUDIT'||detailData.billStatus == 'HQ_CHANGE')&&$hasPermissions('B_salesAudit'))))">{{ text }}</span>
+          </template>
+          <!-- 当前库存 -->
+          <template slot="stockQty" slot-scope="text, record">
+            <div v-if="record.stockQty || record.stockQty==0">
+              <p style="margin: 0;" v-if="Number(record.stockQty) < Number(record.unpushedQty)">{{ record.stockQty }}(<span class="redStyle">缺{{ Number(record.unpushedQty) - Number(record.stockQty) }}</span>)</p>
+              <p style="margin: 0;" v-else>{{ record.stockQty }}</p>
+            </div>
+            <span v-else>--</span>
+          </template>
+        </s-table>
+      </a-card>
+    </a-spin>
+    <div class="affix-cont">
+      <a-button
+        size="large"
+        style="width: 100px;"
+        :disabled="spinning"
+        type="primary"
+        class="button-info"
+        id="salesDetail-audit-btn"
+        v-if="detailData&&detailData.billStatus == 'WAIT_AUDIT'&&$hasPermissions('B_salesAudit')"
+        @click="handleAudit()"
+      >
+        审核
+      </a-button>
+      <a-button
+        type="default"
+        :disabled="spinning"
+        class="button-info"
+        size="large"
+        style="width: 100px;margin: 0 20px;"
+        id="salesDetail-edit-btn"
+        v-if="detailData&&detailData.salesBillSource != 'PURCHASE' && (detailData.billStatus == 'WAIT_SUBMIT' || detailData.billStatus == 'WAIT_AUDIT' || detailData.billStatus == 'AUDIT_REJECT')&&$hasPermissions('B_salesEdit')"
+        @click="handleEdit()"
+      >
+        编辑
+      </a-button>
+      <a-button
+        size="large"
+        style="width: 100px;margin: 0 20px;"
+        :disabled="spinning"
+        type="default"
+        class="button-info"
+        id="salesDetail-edit-btn"
+        v-if="detailData&&detailData.salesBillSource == 'PURCHASE' && (detailData.billStatus == 'WAIT_AUDIT'||detailData.billStatus == 'HQ_CHANGE')&&$hasPermissions('B_salesEdit')"
+        @click="handleEdit()"
+      >
+        改单
+      </a-button>
+      <a-button
+        size="large"
+        style="width: 100px;"
+        :disabled="spinning"
+        type="primary"
+        class="button-success"
+        id="salesDetail-batchAudit-btn"
+        v-if="detailData&&detailData.billStatus == 'WAIT_AUDIT'&&$hasPermissions('B_salesAudit')"
+        @click="handleAudit('batch')"
+      >
+        一键审核
+      </a-button>
+    </div>
+    <!-- 打印导出 -->
+    <print-modal :openModal="openModal" :itemData="detailData" :nowType="nowType" @ok="handleOk" @close="closePrint" />
+    <!-- 审核 -->
+    <auditModal
+      :openModal="visibleAudit"
+      :content="auditText"
+      :spinning="spinningAudit"
+      @close="visibleAudit=false"
+      @ok="auditOrder('AUDIT_PASS')"
+      @fail="auditOrder('AUDIT_REJECT')" />
+    <!-- 审核加下推 -->
+    <dsModal ref="dsModal" title="销售单一键审核" :openModal="showDsModal" @close="showDsModal=false" @ok="handleOnceAudit" />
+    <!-- 缺货明细 -->
+    <stockOutDetail :openModal="showStockOut" :detailData="detailData" :salesBillSn="$route.params.sn || bizSn" @close="showStockOut=false"></stockOutDetail>
+  </div>
+</template>
+
+<script>
+import { printFun, exportExcel } from '@/libs/JGPrint.js'
+import { commonMixin } from '@/utils/mixin'
+import moment from 'moment'
+import { STable, VSelect } from '@/components'
+import printModal from './printModal.vue'
+import auditModal from '@/views/common/auditModal.vue'
+import dsModal from '@/views/salesManagement/waitDispatch/dsModal.vue'
+import stockOutDetail from './stockOutDetailModal.vue'
+import chooseWarehouse from '@/views/common/chooseWarehouse'
+import { salesDetailBySn, salesDetailPrint, salesDetailExcel, salesDetailTypeExcel, salesWriteAudit, salesWriteAuditPush } from '@/api/sales'
+import { salesDetailAllList, salesDetailAllStockList } from '@/api/salesDetail'
+export default {
+  name: 'SalesDetail',
+  mixins: [commonMixin],
+  components: { STable, VSelect, printModal, auditModal, dsModal, stockOutDetail, chooseWarehouse },
+  props: {
+    bizSn: { //  有值则为弹框,无值则为页面
+      type: [Number, String],
+      default: ''
+    }
+  },
+  data () {
+    return {
+      spinning: false,
+      disabled: false,
+      showDsModal: false,
+      showStockOut: false,
+      authCode: '',
+      queryParam: {
+        warehouseSn: undefined
+      },
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        const params = Object.assign(parameter, { salesBillSn: this.bizSn || this.$route.params.sn, warehouseSn: this.queryParam.warehouseSn })
+        let url = salesDetailAllList
+        if (this.detailData && (this.detailData.billStatus == 'WAIT_AUDIT' || this.detailData.billStatus == 'HQ_CHANGE') && this.$hasPermissions('B_salesAudit')) { //  审核,需用到库存
+          url = salesDetailAllStockList
+        } else { // 非审核
+          url = salesDetailAllList
+        }
+        return url(params).then(res => {
+          let data
+          if (res.status == 200) {
+            data = res.data
+            const no = 0
+            this.outStockStr = ''
+            let str = ''
+            for (var i = 0; i < data.length; i++) {
+              data[i].no = no + i + 1
+              const productCode = (data[i].productEntity && data[i].productEntity.code) || (data[i].dealerProductEntity && data[i].dealerProductEntity.code)
+              const productName = (data[i].productEntity && data[i].productEntity.name) || (data[i].dealerProductEntity && data[i].dealerProductEntity.name)
+              const productOrigCode = (data[i].productEntity && data[i].productEntity.origCode) || (data[i].dealerProductEntity && data[i].dealerProductEntity.origCode)
+              const productOrigUnit = (data[i].productEntity && data[i].productEntity.unit) || (data[i].dealerProductEntity && data[i].dealerProductEntity.unit)
+              data[i].productCode = productCode || '--'
+              data[i].productName = productName || '--'
+              data[i].productOrigCode = productOrigCode == ' ' ? '--' : productOrigCode
+              data[i].productOrigUnit = productOrigUnit || '--'
+              if (data[i].unpushedQty && (Number(data[i].stockQty) < Number(data[i].unpushedQty))) {
+                str += data[i].productCode + '、'
+              }
+            }
+            if (str.length > 0) {
+              str = str.substr(0, str.length - 1)
+              this.outStockStr = '产品编号为:' + str + '的产品库存不足;'
+            }
+            this.localDataSource = data
+            this.disabled = false
+          }
+          return data
+        })
+      },
+      localDataSource: [],
+      openModal: false,
+      detailData: null, //  详情数据
+      nowType: null,
+      isCityPrice: false, //  是否显示市级价
+      visibleAudit: false,
+      auditInfo: null,
+      spinningAudit: false,
+      outStockStr: '', // 缺货产品信息说明
+      auditText: null,
+      fromRouter: null
+    }
+  },
+  computed: {
+    shippingAddress () {
+      const shippingAddrProvinceName = this.detailData && this.detailData.salesBillExtEntity && this.detailData.salesBillExtEntity.shippingAddrProvinceName ? this.detailData.salesBillExtEntity.shippingAddrProvinceName : ''
+      const shippingAddrCityName = this.detailData && this.detailData.salesBillExtEntity && this.detailData.salesBillExtEntity.shippingAddrCityName ? this.detailData.salesBillExtEntity.shippingAddrCityName : ''
+      const shippingAddrCountyName = this.detailData && this.detailData.salesBillExtEntity && this.detailData.salesBillExtEntity.shippingAddrCountyName ? this.detailData.salesBillExtEntity.shippingAddrCountyName : ''
+      const shippingAddr = this.detailData && this.detailData.salesBillExtEntity && this.detailData.salesBillExtEntity.shippingAddr ? this.detailData.salesBillExtEntity.shippingAddr : ''
+      if (!shippingAddrProvinceName && !shippingAddrCityName && !shippingAddrCountyName && !shippingAddr) {
+        return '--'
+      } else {
+        return shippingAddrProvinceName + shippingAddrCityName + shippingAddrCountyName + shippingAddr
+      }
+    },
+    columns () {
+      const _this = this
+      const arr = [
+        { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
+        { title: '产品编码', dataIndex: 'productCode', width: '13%', scopedSlots: { customRender: 'productCode' }, align: 'center' },
+        { title: '产品名称', dataIndex: 'productName', width: '13%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '原厂编码', dataIndex: 'productOrigCode', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '出库仓库', dataIndex: 'warehouseName', width: '12%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        // { title: '成本价', dataIndex: 'showCost', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        // { title: '省级价', dataIndex: 'provincePrice', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        // { title: '市级价', dataIndex: 'cityPrice', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        // { title: '销售价', dataIndex: 'price', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '单位', dataIndex: 'productOrigUnit', width: '4%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '销售数量', dataIndex: 'qty', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        // { title: '库存', dataIndex: 'stockQty', scopedSlots: { customRender: 'stockQty' }, width: '6%', align: 'center' },
+        { title: '待下推数', dataIndex: 'unpushedQty', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '已下推数', dataIndex: 'pushedQty', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '已取消数', dataIndex: 'cancelQty', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } }
+      ]
+      if (this.$hasPermissions(this.authCode + '_costPrice')) { //  成本价权限
+        arr.splice(5, 0, { title: '成本价', dataIndex: 'showCost', width: '6%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } })
+      }
+
+      const ind = this.$hasPermissions(this.authCode + '_costPrice') ? 6 : 5
+      if (this.$hasPermissions(this.authCode + '_provincePrice')) {
+        arr.splice(ind, 0, { title: '省级价', dataIndex: 'provincePrice', width: '6%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } })
+      }
+      // 是否勾选市级价格
+      if (this.isCityPrice) {
+        arr.splice(ind + 1, 0, { title: '市级价', dataIndex: 'cityPrice', width: '6%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } })
+        if (this.$hasPermissions(this.authCode + '_salesPrice')) { //  售价权限
+          arr.splice(ind + 2, 0, { title: '销售价', dataIndex: 'price', width: '6%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } })
+        }
+      } else {
+        if (this.$hasPermissions(this.authCode + '_salesPrice')) { //  售价权限
+          arr.splice(ind + 1, 0, { title: '销售价', dataIndex: 'price', width: '6%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } })
+        }
+      }
+
+      if (this.detailData && (this.detailData.billStatus == 'WAIT_AUDIT' || this.detailData.billStatus == 'HQ_CHANGE') && this.$hasPermissions('B_salesAudit')) { //  审核,需用到库存
+        arr.splice(arr.length - 3, 0, { title: '库存', dataIndex: 'stockQty', scopedSlots: { customRender: 'stockQty' }, width: '6%', align: 'center' })
+      }
+      return arr
+    }
+  },
+  methods: {
+    //  返回
+    handleBack () {
+      this.$router.push({ name: 'salesQueryList' })
+    },
+    // 编辑
+    handleEdit () {
+      const row = this.detailData
+      this.$router.push({ name: 'salesEdit', params: { sn: row.salesBillSn, wSn: row.warehouseSn } })
+    },
+    //  重置
+    resetSearchForm () {
+      this.queryParam.warehouseSn = undefined
+      this.$refs.table.refresh()
+    },
+    // 打开缺货明细
+    openStockOut () {
+      if (this.outStockStr != '') {
+        this.showStockOut = true
+      } else {
+        this.$info({
+          title: '提示',
+          content: '此销售单暂无缺货产品!',
+          centered: true
+        })
+      }
+    },
+    //  详情
+    getDetail () {
+      salesDetailBySn({ salesBillSn: this.bizSn || this.$route.params.sn }).then(res => {
+        if (res.status == 200) {
+          this.detailData = res.data || null
+          this.$refs.table.refresh(true)
+        } else {
+          this.detailData = null
+        }
+      })
+    },
+    // 打开审核/一键审核弹框
+    handleAudit (isBatch) {
+      if (isBatch) { // 一键审核
+        this.showDsModal = true
+        this.$refs.dsModal.setDetail(this.detailData)
+      } else {
+        this.auditText = null
+        this.visibleAudit = true
+      }
+    },
+    // 一键审核
+    handleOnceAudit (data) {
+      const params = {
+        salesBillSn: this.bizSn || this.$route.params.sn,
+        billStatus: 'AUDIT_PASS',
+        dispatchBill: data
+      }
+      this.spinningAudit = true
+      this.spinning = true
+      salesWriteAuditPush(params).then(res => {
+        if (res.status == 200) {
+          this.$message.success(res.message)
+          //  关闭详情跳列表
+          this.handleBack()
+        }
+        this.spinningAudit = false
+        this.spinning = false
+      })
+    },
+    // 审核
+    auditOrder (billStatus) {
+      this.spinningAudit = true
+      salesWriteAudit({
+        salesBillSn: this.bizSn || this.$route.params.sn,
+        billStatus: billStatus
+      }).then(res => {
+        if (res.status == 200) {
+          this.visibleAudit = false
+          this.$message.success(res.message)
+          this.spinningAudit = false
+          const _this = this
+          this.$nextTick(() => {
+            if (billStatus == 'AUDIT_PASS' && !_this.auditText) {
+              _this.$router.push({ name: 'waitDispatch', params: { salesBillSn: _this.bizSn || _this.$route.params.sn } })
+            } else {
+              //  关闭详情跳列表
+              _this.handleBack()
+            }
+          })
+        } else {
+          this.visibleAudit = false
+          this.spinningAudit = false
+        }
+      })
+    },
+    // 打印导出
+    handlePrint (type, authCode) {
+      const _this = this
+      _this.$store.state.app.curActionPermission = authCode
+      // 销售分类导出
+      if (type == 'typeExport') {
+        const params = {
+          salesBillSn: this.bizSn || this.$route.params.sn
+        }
+        _this.spinning = true
+        exportExcel(salesDetailTypeExcel, params, '销售分类' + moment().format('YYYYMMDDHHmmss'), () => {
+          _this.spinning = false
+          _this.$store.state.app.curActionPermission = ''
+        })
+      } else {
+        this.detailData.authCode = authCode
+        this.nowType = type
+        this.openModal = true
+      }
+    },
+    closePrint () {
+      console.log(9)
+      this.$store.state.app.curActionPermission = ''
+      this.openModal = false
+    },
+    // 确定打印或预览,导出
+    handleOk (objs) {
+      const _this = this
+      const params = JSON.parse(JSON.stringify(objs))
+      _this.$store.state.app.curActionPermission = this.detailData.authCode
+      delete params.type
+      _this.spinning = true
+      if (this.nowType == 'export') { //  导出
+        exportExcel(salesDetailExcel, params, '销售' + moment().format('YYYYMMDDHHmmss'), () => {
+          _this.spinning = false
+          _this.$store.state.app.curActionPermission = ''
+        })
+      } else { //  打印
+        const taskName = this.nowType == 'SALES_BILL' ? '销售单' : '销售分类'
+        printFun(salesDetailPrint, params, objs.type, taskName, () => {
+          _this.spinning = false
+          _this.$store.state.app.curActionPermission = ''
+        })
+      }
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab || this.bizSn) { // 页签刷新时调用
+      this.getDetail()
+    }
+  },
+  activated () {
+    // 如果是新页签打开或者进入新的子页(例:存在列表第2条数据编辑页页签时再打开第4条数据的编辑页),则重置当前页面
+    if (this.$store.state.app.isNewTab || !this.$store.state.app.isNewSubTab) {
+      this.getDetail()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      vm.fromRouter = from
+      vm.authCode = to.meta.permission
+    })
+  }
+}
+</script>
+
+<style lang="less">
+  .salesDetail-wrap{
+    position: relative;
+    height: 100%;
+    padding-bottom: 51px;
+    box-sizing: border-box;
+    >.ant-spin-nested-loading{
+      overflow-y: auto;
+      height: 100%;
+    }
+    .salesDetail-cont{
+      margin-bottom: 10px;
+    }
+    .flexBox{
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+    }
+    .footer-cont{
+      margin-top: 5px;
+      text-align: center;
+    }
+    .redStyle{
+      font-weight: bold;
+      color: red;
+    }
+  }
+</style>

+ 242 - 0
src/views/salesManagement/salesQueryNew/edit.vue

@@ -0,0 +1,242 @@
+<template>
+  <div class="salesEdit-wrap">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-page-header :ghost="false" :backIcon="false" @back="handleBack" >
+        <!-- 自定义的二级文字标题 -->
+        <template slot="subTitle">
+          <a id="salesEdit-back-btn" href="javascript:;" @click="handleBack"><a-icon type="left" /> 返回列表</a>
+          <span style="margin: 0 15px;color: #666;">客户名称:{{ detailData&&detailData.buyerName }}</span>
+        </template>
+      </a-page-header>
+       
+      <a-card size="small" :bordered="false" class="salesEdit-cont">
+        <div slot="title">
+          <a-row :gutter="15" type="flex">
+            <a-col :span="2">
+              <div class="p-title">
+                已选产品
+              </div>
+            </a-col>
+            <a-col :span="16">
+               
+            </a-col>
+          </a-row>
+        </div>
+        
+        <a-collapse v-model="activeKey" accordion>
+          <a-collapse-panel key="1" forceRender>
+            <div slot="header" style="font-size:14px;"><strong>端午节活动</strong>(满5000送500)</div>
+            <productList :detailData="detailData" :warehouseSn="warehouseSn" :salesBillSn="salesBillSn"></productList>
+          </a-collapse-panel>
+          <a-collapse-panel key="2" forceRender>
+            <div slot="header" style="font-size:14px;"><strong>五一超优惠活动</strong>(满5000打9折)</div>
+            <productList :detailData="detailData" :warehouseSn="warehouseSn" :salesBillSn="salesBillSn"></productList>
+          </a-collapse-panel>
+          <a-collapse-panel key="3" forceRender>
+            <div slot="header" style="font-size:14px;"><strong>夏季大促销活动</strong>(满5000打9折)</div>
+            <productList :detailData="detailData" :warehouseSn="warehouseSn" :salesBillSn="salesBillSn"></productList>
+          </a-collapse-panel>
+          <a-collapse-panel key="4" forceRender>
+            <div slot="header" style="font-size:14px;"><strong>国庆10天热门活动</strong>(满5000打9折)</div>
+            <productList :detailData="detailData" :warehouseSn="warehouseSn" :salesBillSn="salesBillSn"></productList>
+          </a-collapse-panel>
+          <a-collapse-panel key="5" forceRender>
+            <div slot="header" style="font-size:14px;"><strong>春节滤清器特价活动</strong>(满5000打9折)</div>
+            <productList :detailData="detailData" :warehouseSn="warehouseSn" :salesBillSn="salesBillSn"></productList>
+          </a-collapse-panel>
+        </a-collapse>
+      </a-card>
+    </a-spin>
+    <div class="affix-cont1">
+      <a-button
+        size="large"
+        style="padding: 0 60px;"
+        :disabled="spinning"
+        type="primary"
+        class="button-primary"
+        @click="handleSubmit()"
+        id="productInfoList-handleSubmit">提交</a-button>
+    </div>
+    <!-- 价格更新弹窗 -->
+    <setPriceModal :show="priceUpdateModal" :totalRealAmount="updataData.totalRealAmount" :totalAmount="updataData.totalAmount" @ok="updatePrice" @cancel="priceUpdateModal=false"></setPriceModal>
+ </div>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+import productList from './comps/productList.vue'
+import setPriceModal from './setPriceModal.vue'
+import { salesDetailBySn, salesWriteSubmit, submitCheck, updateBatch } from '@/api/sales'
+export default {
+  name: 'SalesNewEdit',
+  mixins: [commonMixin],
+  components:{
+    setPriceModal,
+    productList
+  },
+  data () {
+    return {
+      spinning: false,
+      activeKey: 1,
+      salesBillSn: null, // 销售单sn
+      detailData: { discountAmount: 0, id: null, salesBillSn: '' }, // 订单基础数据
+      warehouseSn: undefined,
+      updataData: {
+        totalRealAmount: '',
+        totalAmount: ''
+      },
+      priceUpdateModal: false, // 价格更新弹窗
+    }
+  },
+  methods: {
+    //  返回
+    handleBack () {
+      this.$router.push({ name: 'salesQueryNewList', query: { closeLastOldTab: true } })
+    },
+    //  销售单详情
+    getOrderDetail (flag) {
+      salesDetailBySn({ salesBillSn: this.$route.params.sn }).then(res => {
+        if (res.status == 200) {
+          this.detailData = res.data
+        }
+      })
+    },
+    // 选择价格类型  并更新
+    updatePrice (type) {
+      const _this = this
+      if (type == 0) {
+        const ajax_data = {
+          salesBillSn: _this.salesBillSn,
+          productPriceChangeFlag: type
+        }
+        _this.submitResult(ajax_data)
+      } else {
+        updateBatch(_this.updataData.detailList).then(res => {
+          if (res.status == 200) {
+            const ajax_data = {
+              salesBillSn: _this.salesBillSn,
+              productPriceChangeFlag: type
+            }
+            _this.submitResult(ajax_data)
+          }
+        })
+      }
+    },
+    // 提交销售单
+    handleSubmit () {
+      // 先不提交,先判断是否有价格更新  (下级创建时判断)
+      if (this.detailData && this.detailData.salesBillSource && this.detailData.salesBillSource == 'PURCHASE') {
+        submitCheck({ salesBillSn: this.salesBillSn }).then(res => {
+          if (res.status == 200) {
+            if (res.data.detailList.length > 0) {
+              this.updataData = res.data
+              const _this = this
+              this.$nextTick(() => {
+                _this.priceUpdateModal = true
+              })
+            } else {
+              const ajax_data = { salesBillSn: this.salesBillSn }
+              this.submitResult(ajax_data)
+            }
+          }
+        })
+      } else {
+        const ajax_data = { salesBillSn: this.salesBillSn }
+        this.submitResult(ajax_data)
+      }
+    },
+    // 提交
+    submitResult (data) {
+      this.spinning = true
+      salesWriteSubmit(data).then(res => {
+        if (res.status == 200) {
+          this.handleBack()
+          this.$message.success(res.message)
+          this.spinning = false
+        } else {
+          this.spinning = false
+        }
+      })
+    },
+    pageInit () {
+      this.getOrderDetail(true)
+      this.salesBillSn = this.$route.params.sn
+      this.warehouseSn = this.$route.params.sn ? this.$route.params.wSn : ''
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
+      this.pageInit()
+    }
+  },
+  activated () {
+    // 如果是新页签打开或者进入新的子页(例:存在列表第2条数据编辑页页签时再打开第4条数据的编辑页),则重置当前页面
+    if (this.$store.state.app.isNewTab || !this.$store.state.app.isNewSubTab) {
+      this.pageInit()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {})
+  }
+}
+</script>
+
+<style lang="less">
+  .salesEdit-wrap{
+    position: relative;
+    height: 100%;
+    padding-bottom: 51px;
+    box-sizing: border-box;
+    >.ant-spin-nested-loading{
+      overflow-y: scroll;
+      height: 100%;
+    }
+    .salesEdit-cont{
+      margin-top: 10px;
+    }
+    .p-title{
+      font-weight: bold;
+      font-size: 14px;
+    }
+    .p-notes{
+      font-size: 14px;
+      span{
+        color: #FF9900;
+      }
+    }
+    .redStyle{
+      font-weight: bold;
+      color: red;
+    }
+    .ellipsisCon{
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      .ellipsisText{
+        width: 100%;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        display: box;
+        display: -webkit-box;
+        -webkit-line-clamp: 1;
+        -webkit-box-orient: vertical;
+      }
+    }
+    .total-bar{
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      > div{
+        &:last-child{
+          display: flex;
+          align-items: center;
+          justify-content: space-between;
+          > div{
+            padding: 0 10px;
+          }
+        }
+      }
+    }
+  }
+
+</style>

+ 633 - 0
src/views/salesManagement/salesQueryNew/list.vue

@@ -0,0 +1,633 @@
+<template>
+  <a-card size="small" :bordered="false" class="salesManagementList-wrap">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <!-- 搜索条件 -->
+      <div ref="tableSearch" class="table-page-search-wrapper">
+        <a-form layout="inline">
+          <a-row :gutter="15">
+            <a-col :md="6" :sm="24">
+              <a-form-item label="创建时间">
+                <rangeDate ref="rangeDate" :value="time" @change="dateChange" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="客户名称">
+                <dealerSubareaScopeList ref="dealerSubareaScopeList" id="salesManagementList-buyerName" @change="custChange" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="销售单号">
+                <a-input id="salesManagementList-salesBillNo" v-model.trim="queryParam.salesBillNo" allowClear placeholder="请输入销售单号"/>
+              </a-form-item>
+            </a-col>
+            <template v-if="advanced">
+              <a-col :md="6" :sm="24">
+                <a-form-item label="采购单号">
+                  <a-input id="salesManagementList-purchaseBillNo" v-model.trim="queryParam.purchaseBillNo" allowClear placeholder="请输入采购单号"/>
+                </a-form-item>
+              </a-col>
+              <a-col :md="6" :sm="24">
+                <a-form-item label="备货打印状态">
+                  <v-select
+                    v-model="queryParam.printStatus"
+                    ref="printStatus"
+                    id="salesManagementList-printStatus"
+                    code="PRINT_STATUS"
+                    placeholder="请选择打印状态"
+                    allowClear></v-select>
+                </a-form-item>
+              </a-col>
+              <a-col :md="6" :sm="24">
+                <a-form-item label="业务状态">
+                  <v-select
+                    v-model="queryParam.billStatus"
+                    ref="billStatus"
+                    id="salesManagementList-billStatus"
+                    code="SALES_BILL_STATUS"
+                    placeholder="请选择业务状态"
+                    allowClear></v-select>
+                </a-form-item>
+              </a-col>
+              <a-col :md="6" :sm="24">
+                <a-form-item label="财务状态">
+                  <v-select
+                    v-model="queryParam.financialStatus"
+                    ref="financialStatus"
+                    id="salesManagementList-financialStatus"
+                    code="FINANCIAL_RECEIVE_STATUS"
+                    placeholder="请选择财务状态"
+                    allowClear></v-select>
+                </a-form-item>
+              </a-col>
+              <a-col :md="6" :sm="24">
+                <a-form-item label="单据来源">
+                  <v-select
+                    v-model="queryParam.salesBillSource"
+                    ref="salesBillSource"
+                    id="salesManagementList-salesBillSource"
+                    code="SALES_SOURCE"
+                    placeholder="请选择单据来源"
+                    allowClear></v-select>
+                </a-form-item>
+              </a-col>
+              <a-col :md="6" :sm="24">
+                <a-form-model-item label="所在区域">
+                  <subarea ref="subarea" id="salesManagementList-subarea" @change="subareaChange"></subarea>
+                </a-form-model-item>
+              </a-col>
+              <a-col :md="6" :sm="24">
+                <a-form-model-item label="地区" prop="shippingAddrProvinceSn">
+                  <Area id="salesManagementList-shippingAddrProvinceSn" v-model="queryParam.shippingAddrProvinceSn" placeholder="请选择省"></Area>
+                </a-form-model-item>
+              </a-col>
+              <a-col :md="6" :sm="24">
+                <a-form-model-item label="出库仓库">
+                  <chooseWarehouse ref="warehouse" v-model="queryParam.warehouseSn"></chooseWarehouse>
+                </a-form-model-item>
+              </a-col>
+            </template>
+            <a-col :md="6" :sm="24">
+              <span class="table-page-search-submitButtons">
+                <a-button type="primary" :disabled="disabled" @click="$refs.table.refresh(true)">查询</a-button>
+                <a-button style="margin-left: 8px" :disabled="disabled" @click="resetSearchForm()">重置</a-button>
+                <a-button
+                  style="margin-left: 10px"
+                  type="primary"
+                  class="button-warning"
+                  @click="handleExport"
+                  :disabled="disabled"
+                  :loading="exportLoading"
+                  v-if="$hasPermissions('B_sales_export')"
+                >导出</a-button>
+                <a @click="advanced=!advanced" style="margin-left: 8px">
+                  {{ advanced ? '收起' : '展开' }}
+                  <a-icon :type="advanced ? 'up' : 'down'"/>
+                </a>
+              </span>
+            </a-col>
+          </a-row>
+        </a-form>
+      </div>
+      <!-- 操作按钮 -->
+      <div class="table-operator">
+        <a-button type="primary" class="button-error" v-if="$hasPermissions('B_salesAdd')" @click="handleAdd">新增</a-button>
+      </div>
+      <!-- alert -->
+      <a-alert type="info" style="margin-bottom:10px">
+        <div slot="message">
+          <div style="display: flex;justify-content: space-between;align-items: center;">
+            <div>
+              <div>
+                总单数:<strong>{{ totalData&&(totalData.totalRecord || totalData.totalRecord==0) ? totalData.totalRecord : '--' }}</strong>;
+                总款数:<strong>{{ totalData&&(totalData.totalCategory || totalData.totalCategory==0) ? totalData.totalCategory : '--' }}</strong>;
+                总数量:<strong>{{ totalData&&(totalData.totalQty || totalData.totalQty==0) ? totalData.totalQty : '--' }}</strong>;
+                已下推数量:<strong>{{ totalData&&(totalData.totalPushedQty || totalData.totalPushedQty==0) ? totalData.totalPushedQty : '--' }}</strong>;
+                已发货数量:<strong>{{ totalData&&(totalData.totalDispatchQty || totalData.totalDispatchQty==0) ? totalData.totalDispatchQty : '--' }}</strong>;
+                已取消数量:<strong>{{ totalData&&(totalData.totalCancelQty || totalData.totalCancelQty==0) ? totalData.totalCancelQty : '--' }}</strong>;
+                待下推数量:<strong>{{ totalData&&(totalData.totalUnpushedQty || totalData.totalUnpushedQty==0) ? totalData.totalUnpushedQty : '--' }}</strong>;
+              </div>
+              <div v-if="$hasPermissions('M_salesQueryList_salesPrice')">
+                总售价:<strong>{{ totalData&&(totalData.totalAmount || totalData.totalAmount==0) ? toThousands(totalData.totalAmount) : '--' }}</strong>;
+                已下推金额:<strong>{{ totalData&&(totalData.totalPushedAmount || totalData.totalPushedAmount==0) ? toThousands(totalData.totalPushedAmount) : '--' }}</strong>;
+                已取消金额:<strong>{{ totalData&&(totalData.totalCancelAmount || totalData.totalCancelAmount==0) ? toThousands(totalData.totalCancelAmount) : '--' }}</strong>;
+                待下推金额:<strong>{{ totalData&&(totalData.totalUnpushedAmount || totalData.totalUnpushedAmount==0) ? toThousands(totalData.totalUnpushedAmount) : '--' }}</strong>;
+                已发货金额:<strong>{{ totalData&&(totalData.totalDispatchAmount || totalData.totalDispatchAmount==0) ? toThousands(totalData.totalDispatchAmount) : '--' }}</strong>;
+              </div>
+            </div>
+            <a-checkbox v-model="showCancelNum"><span style="display: inline-block;margin-top: 1px;">显示取消数量</span></a-checkbox>
+          </div>
+        </div>
+      </a-alert>
+      <!-- 列表 -->
+      <s-table
+        class="sTable fixPagination"
+        ref="table"
+        :style="{ height: tableHeight+75+'px' }"
+        size="small"
+        :rowKey="(record) => record.id"
+        :columns="columns"
+        :data="loadData"
+        :scroll="{ y: tableHeight }"
+        :defaultLoadData="false"
+        bordered>
+        <!-- 销售单号 -->
+        <template slot="salesBillNo" slot-scope="text, record">
+          <div v-if="$hasPermissions('B_salesDetail')">
+            <a-badge :count="'改'+record.changeTimes" :offset="[16,-13]" v-if="record.changeTimes>0" class="badge-con-t">
+              <span class="link-bule" @click="handleDetail(record)">{{ record.salesBillNo }}</span>
+            </a-badge>
+            <span v-else class="link-bule" @click="handleDetail(record)">{{ record.salesBillNo }}</span>
+          </div>
+          <div v-else>{{ record.salesBillNo }}</div>
+        </template>
+        <!-- 出库仓库 -->
+        <template slot="warehouseBox" slot-scope="text, record">
+          <a-tooltip placement="right" v-if="record.warehouseNameSet && record.warehouseNameSet.length>0">
+            <template slot="title">
+              <span>{{ record.warehouseNameSet.toString() }}</span>
+            </template>
+            <div class="warehouse_box">
+              <span>{{ record.warehouseNameSet.toString() }}</span>
+            </div>
+          </a-tooltip>
+          <div v-else>--</div>
+        </template>
+        <!-- 总数量 -->
+        <template slot="totalQty" slot-scope="text, record">
+          {{ record.totalQty }}
+        </template>
+        <!-- 操作 -->
+        <template slot="action" slot-scope="text, record">
+          <div>
+            <a-button
+              size="small"
+              type="link"
+              class="button-warning"
+              v-if="record.billStatus == 'WAIT_AUDIT'&&$hasPermissions('B_salesAudit')"
+              @click="handleDetailAudit(record)"
+            >审核</a-button>
+            <a-button
+              size="small"
+              type="link"
+              class="button-warning"
+              v-if="record.billStatus == 'WAIT_PUSH'&&$hasPermissions('B_salesDispatch')"
+              @click="handleDispatch(record)"
+            >下推</a-button>
+            <a-button
+              size="small"
+              type="link"
+              class="button-info"
+              v-if="(record.salesBillSource == 'SALES' && (record.billStatus == 'WAIT_SUBMIT' || record.billStatus == 'WAIT_AUDIT' || record.billStatus == 'AUDIT_REJECT' || record.billStatus == 'HQ_CHANGE'))&&$hasPermissions('B_salesEdit')"
+              @click="handleEdit(record)"
+            >
+              编辑
+            </a-button>
+            <a-button
+              size="small"
+              type="link"
+              class="button-info"
+              v-if="record.salesBillSource == 'PURCHASE' && (record.billStatus == 'WAIT_AUDIT' || record.billStatus == 'HQ_CHANGE') && $hasPermissions('B_salesEdit')"
+              @click="handleEdit(record)"
+            >
+              改单
+            </a-button>
+            <a-button
+              size="small"
+              type="link"
+              class="button-error"
+              v-if="(record.salesBillSource == 'SALES' && (record.billStatus == 'WAIT_SUBMIT' || record.billStatus == 'WAIT_AUDIT' || record.billStatus == 'AUDIT_REJECT' || record.billStatus == 'HQ_CHANGE'))&&$hasPermissions('B_salesDel')"
+              @click="handleDel(record)"
+            >
+              删除
+            </a-button>
+            <a-button
+              size="small"
+              type="link"
+              class="button-error"
+              v-if="record.salesBillSource == 'PURCHASE' && (record.billStatus == 'WAIT_AUDIT' || record.billStatus == 'HQ_CHANGE') && $hasPermissions('B_salesDel')"
+              @click="handleDel(record)"
+            >
+              取消
+            </a-button>
+            <a-button
+              size="small"
+              type="link"
+              class="button-warning"
+              v-if="record.printStatus=='UNABLE_PRINT'&&$hasPermissions('B_Sales_UNABLE_PRINT')"
+              @click="handlePrint(record)"
+            >允许备货打印</a-button>
+          </div>
+        </template>
+      </s-table>
+    </a-spin>
+    <!-- 选择客户弹框 -->
+    <choose-custom-modal :show="openModal" @ok="chooseCustomOk" @cancel="openModal=false"></choose-custom-modal>
+    <!-- 操作提示 -->
+    <commonModal modalTit="操作提示" :width="this.tipData&&this.tipData.length == 1?'500px':'800px'" :openModal="showTipModal" @cancel="canselModal" @ok="updatePrintStatus">
+      <div style="text-align: center;" v-if="this.tipData&&this.tipData.length">
+        <div style="margin-bottom: 15px;font-size: 14px;"><strong>确认允许此单进行备货打印吗?</strong></div>
+        <div style="line-height: 24px;" v-if="this.tipData.length == 1">
+          <div>备货单号:{{ tipData[0]&&tipData[0].dispatchBillNo }}</div>
+          <div>客户名称:{{ tipData[0]&&tipData[0].buyerName }}</div>
+        </div>
+        <div v-else>
+          <a-table
+            :row-selection="{ selectedRowKeys: selectedRowKeys,onChange: onSelectChange, getCheckboxProps: record => ({ props: { disabled: record.printStatus!=='UNABLE_PRINT' }})}"
+            :columns="bhColumns"
+            :data-source="tipData"
+            :pagination="false"
+          />
+        </div>
+      </div>
+    </commonModal>
+    <!-- 导出提示框 -->
+    <reportModal :visible="showExport" @close="showExport=false"></reportModal>
+  </a-card>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+import moment from 'moment'
+import getDate from '@/libs/getDate.js'
+import subarea from '@/views/common/subarea.js'
+import Area from '@/views/common/area.js'
+import rangeDate from '@/views/common/rangeDate.vue'
+import { STable, VSelect } from '@/components'
+import commonModal from '@/views/common/commonModal.vue'
+import chooseCustomModal from './chooseCustomModal.vue'
+import dealerSubareaScopeList from '@/views/common/dealerSubareaScopeList.vue'
+import reportModal from '@/views/common/reportModal.vue'
+import { salesList, salesDel, salesCount } from '@/api/sales'
+import { hdExportExcel } from '@/libs/exportExcel'
+import chooseWarehouse from '@/views/common/chooseWarehouse'
+import { findBySalesBillSn, dispatchBatchPrintStatus, queryBySalesBillSn } from '@/api/dispatch'
+import { salesDetailExport } from '@/api/salesBillReport'
+export default {
+  name: 'SalesQueryList',
+  mixins: [commonMixin],
+  components: { STable, VSelect, chooseCustomModal, dealerSubareaScopeList, Area, rangeDate, subarea, commonModal, reportModal, chooseWarehouse },
+  data () {
+    return {
+      spinning: false,
+      advanced: true, // 高级搜索 展开/关闭
+      disabled: false, //  查询、重置按钮是否可操作
+      openModal: false, // 选择客户弹框是否显示
+      showTipModal: false, // 备货打印弹框
+      showExport: false,
+      exportLoading: false,
+      tableHeight: 0,
+      time: [
+        moment(getDate.getThreeMonthDays().starttime, 'YYYY-MM-DD'),
+        moment(getDate.getCurrMonthDays().endtime, 'YYYY-MM-DD')
+      ],
+      // 查询参数
+      queryParam: {
+        beginDate: getDate.getThreeMonthDays().starttime,
+        endDate: getDate.getCurrMonthDays().endtime,
+        buyerSn: undefined, //  客户名称
+        salesBillNo: '', //  销售单号
+        purchaseBillNo: '',
+        printStatus: undefined,
+        billStatus: undefined, //  业务状态
+        financialStatus: undefined, //  财务状态
+        salesBillSource: undefined,
+        subareaArea: {
+          subareaSn: undefined,
+          subareaAreaSn: undefined
+        },
+        shippingAddrProvinceSn: undefined,
+        warehouseSn: undefined
+      },
+      totalData: {
+        totalAmount: 0,
+        totalCategory: 0,
+        totalQty: 0,
+        totalRecord: 0,
+        totalPushedQty: 0,
+        totalDispatchQty: 0,
+        totalCancelQty: 0,
+        totalUnpushedQty: 0,
+        totalPushedAmount: 0,
+        totalCancelAmount: 0,
+        totalUnpushedAmount: 0,
+        totalDispatchAmount: 0
+      },
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        this.spinning = true
+        delete parameter.tableId
+        delete parameter.index
+        // 查询总计
+        salesCount(Object.assign(parameter, this.queryParam)).then(res => {
+          this.totalData = Object.assign(this.totalData, res.data || {})
+        })
+        return salesList(Object.assign(parameter, this.queryParam)).then(res => {
+          let data
+          if (res.status == 200) {
+            data = res.data
+            const no = (data.pageNo - 1) * data.pageSize
+            for (var i = 0; i < data.list.length; i++) {
+              data.list[i].no = no + i + 1
+            }
+            this.disabled = false
+          }
+          this.spinning = false
+          return data
+        })
+      },
+      showCancelNum: false, //  是否显示取消数量和待下推数量
+      tipData: null, // 备货单信息
+      tempSalesBillSn: null,
+      // 允许备货打印
+      selectedRowKeys: [],
+      bhColumns: [
+        {
+          title: '备货单号',
+          dataIndex: 'dispatchBillNo'
+        },
+        {
+          title: '客户名称',
+          dataIndex: 'buyerName'
+        },
+        {
+          title: '备货打印状态',
+          dataIndex: 'printStatusDictValue'
+        }
+      ]
+    }
+  },
+  computed: {
+    columns () {
+      const _this = this
+      const arr = [
+        { title: '创建时间', dataIndex: 'createDate', width: '6%', align: 'center', customRender: function (text) { return text || '--' }, sorter: true },
+        { title: '销售单号', scopedSlots: { customRender: 'salesBillNo' }, width: '7%', align: 'center' },
+        { title: '提交时间', dataIndex: 'submitDate', width: '6%', align: 'center', customRender: function (text) { return text || '--' }, sorter: true },
+        { title: '客户名称', dataIndex: 'buyerName', width: '8%', align: 'left', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '出库仓库', scopedSlots: { customRender: 'warehouseBox' }, width: '8%', align: 'center', ellipsis: true },
+        { title: '总数量', dataIndex: 'totalQty', scopedSlots: { customRender: 'totalQty' }, width: '4%', align: 'center' },
+        // { title: '总售价', dataIndex: 'totalAmount', width: '4%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '已下推数量', dataIndex: 'totalPushedQty', width: '4%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        // { title: '下推总金额', dataIndex: 'totalPushedAmount', width: '4%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '已发货数量', dataIndex: 'totalDispatchQty', width: '4%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '收款方式', dataIndex: 'settleStyleSnDictValue', width: '5%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '审核时间', dataIndex: 'auditDate', width: '6%', align: 'center', customRender: function (text) { return text || '--' }, sorter: true },
+        { title: '最近备货时间', dataIndex: 'lastStockUpDate', width: '6%', align: 'center', customRender: function (text) { return text || '--' }, sorter: true },
+        { title: '业务状态', dataIndex: 'billStatusDictValue', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '财务状态', dataIndex: 'financialStatusDictValue', width: '5%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '备货打印状态', dataIndex: 'printStatusDictValue', width: '5%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: '7%', align: 'center' }
+      ]
+      if (this.showCancelNum) {
+        const ind = this.$hasPermissions('M_salesQueryList_salesPrice') ? 10 : 8
+        arr.splice(ind, 0, { title: '已取消数量', dataIndex: 'totalCancelQty', width: '4%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } })
+        arr.splice(ind + 1, 0, { title: '待下推数量', dataIndex: 'totalUnpushedQty', width: '4%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } })
+      }
+      if (this.$hasPermissions('M_salesQueryList_salesPrice')) { // 售价权限
+        arr.splice(6, 0, { title: '总售价', dataIndex: 'totalAmount', width: '4%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } })
+        arr.splice(8, 0, { title: '下推总金额', dataIndex: 'totalPushedAmount', width: '4%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } })
+      }
+      return arr
+    }
+  },
+  methods: {
+    //  导出
+    handleExport () {
+      const _this = this
+      _this.$store.state.app.curActionPermission = 'B_sales_export'
+      _this.exportLoading = true
+      _this.spinning = true
+      hdExportExcel(salesDetailExport, _this.queryParam, '销售明细', function () {
+        _this.exportLoading = false
+        _this.spinning = false
+        _this.showExport = true
+        _this.$store.state.app.curActionPermission = ''
+      })
+    },
+    //  时间  change
+    dateChange (date) {
+      this.queryParam.beginDate = date[0]
+      this.queryParam.endDate = date[1]
+    },
+    custChange (val) {
+      this.queryParam.buyerSn = val.key
+    },
+    subareaChange (val) {
+      this.queryParam.subareaArea.subareaSn = val[0] ? val[0] : undefined
+      this.queryParam.subareaArea.subareaAreaSn = val[1] ? val[1] : undefined
+    },
+    // 新增
+    handleAdd () {
+      this.openModal = true
+    },
+    // 选择客户成功
+    chooseCustomOk (data) {
+      this.$router.push({ name: 'salesNewAdd', params: { sn: data.salesBillSn } })
+    },
+    // 下推
+    handleDispatch (row) {
+      this.spinning = true
+      findBySalesBillSn({ salesBillSn: row.salesBillSn }).then(res => {
+        this.spinning = false
+        if (res.status == 200) {
+          this.$router.push({ name: 'waitDispatch', params: { salesBillSn: row.salesBillSn } })
+        }
+      })
+    },
+    // 详情
+    handleDetail (row) {
+      this.$router.push({ name: 'salesNewDetail', params: { sn: row.salesBillSn } })
+    },
+    // 审核
+    handleDetailAudit (row) {
+      this.$router.push({ name: 'salesNewDetailAudit', params: { sn: row.salesBillSn } })
+    },
+    // 编辑
+    handleEdit (row) {
+      this.$router.push({ name: 'salesNewEdit', params: { sn: row.salesBillSn } })
+    },
+    // 删除
+    handleDel (row) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: row.salesBillSource == 'PURCHASE' ? '确认要取消吗?' : '确认要删除吗?',
+        centered: true,
+        closable: true,
+        onOk () {
+          _this.spinning = true
+          salesDel({ salesBillSn: row.salesBillSn }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$refs.table.refresh()
+              _this.spinning = false
+            } else {
+              _this.spinning = false
+            }
+          })
+        }
+      })
+    },
+    // 允许备货打印
+    handlePrint (row) {
+      // 获取关联的下推单
+      this.tempSalesBillSn = row.salesBillSn
+      queryBySalesBillSn({ salesBillSn: row.salesBillSn }).then(res => {
+        this.tipData = res.data || []
+        this.tipData.map(item => {
+          item.key = item.dispatchBillSn
+          if (item.printStatus == 'UNABLE_PRINT') {
+            this.selectedRowKeys.push(item.dispatchBillSn)
+          }
+        })
+        this.showTipModal = true
+      })
+    },
+    canselModal () {
+      this.tipData = null
+      this.showTipModal = false
+      this.tempSalesBillSn = null
+      this.selectedRowKeys = []
+    },
+    onSelectChange (selectedRowKeys) {
+      this.selectedRowKeys = selectedRowKeys
+    },
+    // 允许备货打印状态
+    updatePrintStatus () {
+      const isOne = this.tipData.length
+      if (isOne > 1 && this.selectedRowKeys.length == 0) {
+        this.$message.info('请选择备货单!')
+        return
+      }
+      const dispatchBillSnList = []
+      this.tipData.map(item => {
+        dispatchBillSnList.push(item.dispatchBillSn)
+      })
+
+      const params = {
+        'salesBillSn': this.tempSalesBillSn,
+        'dispatchBillSnList': isOne > 1 ? this.selectedRowKeys : dispatchBillSnList,
+        'printStatus': 'NO_PRINT'
+      }
+      dispatchBatchPrintStatus(params).then(res => {
+        if (res.status == 200) {
+          this.canselModal()
+          this.$message.info(res.message)
+          this.$refs.table.refresh()
+        }
+      })
+    },
+    // 重置
+    resetSearchForm () {
+      this.$refs.rangeDate.resetDate(this.time)
+      this.queryParam.beginDate = getDate.getThreeMonthDays().starttime
+      this.queryParam.endDate = getDate.getCurrMonthDays().endtime
+      this.$refs.dealerSubareaScopeList.resetForm()
+      this.queryParam.buyerSn = undefined
+      this.queryParam.salesBillNo = ''
+      this.queryParam.purchaseBillNo = ''
+      this.queryParam.printStatus = undefined
+      this.queryParam.billStatus = undefined
+      this.queryParam.financialStatus = undefined
+      this.queryParam.salesBillSource = undefined
+      this.queryParam.subareaArea.subareaSn = undefined
+      this.queryParam.subareaArea.subareaAreaSn = undefined
+      this.queryParam.shippingAddrProvinceSn = undefined
+      this.queryParam.warehouseSn = undefined
+      if (this.advanced) {
+        this.$refs.subarea.clearData()
+      }
+      this.$refs.table.refresh(true)
+    },
+    pageInit () {
+      const _this = this
+      this.$nextTick(() => { // 页面渲染完成后的回调
+        _this.setTableH()
+      })
+    },
+    setTableH () {
+      const tableSearchH = this.$refs.tableSearch.offsetHeight
+      this.tableHeight = window.innerHeight - tableSearchH - 290
+    }
+  },
+  watch: {
+    advanced (newValue, oldValue) {
+      const _this = this
+      this.$nextTick(() => { // 页面渲染完成后的回调
+        _this.setTableH()
+      })
+    },
+    '$store.state.app.winHeight' (newValue, oldValue) { //  窗口变更时,需同时更改表格高度
+      console.log(newValue)
+      this.setTableH()
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
+      this.pageInit()
+      this.resetSearchForm()
+    }
+  },
+  activated () {
+    // 如果是新页签打开,则重置当前页面
+    if (this.$store.state.app.isNewTab) {
+      this.pageInit()
+      this.resetSearchForm()
+    }
+    // 仅刷新列表,不重置页面
+    if (this.$store.state.app.updateList) {
+      this.pageInit()
+      this.$refs.table.refresh()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {})
+  }
+}
+</script>
+<style lang="less" scoped>
+  .salesManagementList-wrap{
+    .sTable{
+      margin-top: 10px;
+      .badge-con-t{
+        .ant-badge-count{
+          transform: scale(0.8);
+          font-size: 13px;
+        }
+      }
+      .warehouse_box{
+        width: 100%;
+        overflow: hidden;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+      }
+      // .warehouse_box>span::after{
+      //   content:',';
+      // }
+      // .warehouse_box>span:last-child::after{
+      //   content:'';
+      // }
+    }
+  }
+</style>

+ 241 - 0
src/views/salesManagement/salesQueryNew/printModal.vue

@@ -0,0 +1,241 @@
+<template>
+  <a-modal
+    centered
+    :footer="null"
+    :maskClosable="false"
+    class="sales-print-type-modal"
+    :title="modalTit"
+    v-model="isShow"
+    @cancel="isShow=false"
+    :width="600">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-form-model
+        id="sales-print-form"
+        ref="ruleForm"
+        :model="form"
+        :rules="rules"
+        :label-col="formItemLayout.labelCol"
+        :wrapper-col="formItemLayout.wrapperCol"
+      >
+        <a-form-model-item label="销售单号">{{ itemData&&itemData.salesBillNo || '--' }}</a-form-model-item>
+        <a-form-model-item label="客户名称">{{ itemData&&itemData.buyerName || '--' }}</a-form-model-item>
+        <a-form-model-item label="产品分类" prop="id" v-if="nowType=='SALES_BILL_TYPE'">
+          <a-select id="sales-print-form" v-model="form.id" placeholder="请选择产品分类">
+            <a-select-option v-for="item in typeList" :value="item.id" :key="item.id">
+              <span v-if="item.id != 'all'">{{ item.productBrandName }} - {{ item.productTypeName3 }}</span>
+              <span v-else>全部</span>
+            </a-select-option>
+          </a-select>
+        </a-form-model-item>
+        <a-form-model-item label="是否缺货产品" prop="dataScope" v-if="nowType=='export'">
+          <a-radio-group v-model="form.dataScope">
+            <a-radio value="all">全部</a-radio>
+            <a-radio value="ENOUGH">有库存</a-radio>
+            <a-radio value="LESS">缺货</a-radio>
+          </a-radio-group>
+        </a-form-model-item>
+        <a-form-model-item label="产品售价" prop="priceType"  v-if="nowType=='SALES_BILL_TYPE'&&$hasPermissions('B_salesTypePrint_salesPrice')">
+          <!-- 销售分类打印 -->
+          <a-radio-group v-model="form.priceType">
+            <a-radio value="SALES_BILL_TYPE_COST">打印</a-radio>
+            <a-radio value="SALES_BILL_TYPE">不打印</a-radio>
+          </a-radio-group>
+        </a-form-model-item>
+        <a-form-model-item label="产品售价" prop="priceType" v-if="nowType=='SALES_BILL'&&$hasPermissions('B_salesPrint_salesPrice')">
+          <!-- 销售打印 -->
+          <a-radio-group v-model="form.priceType">
+            <a-radio value="SALES_BILL_COST">打印</a-radio>
+            <a-radio value="SALES_BILL">不打印</a-radio>
+          </a-radio-group>
+        </a-form-model-item>
+        <a-form-model-item label="产品售价" prop="priceType" v-if="nowType=='export'&&$hasPermissions('B_salesDetailExport_salesPrice')">
+          <!-- 销售导出 -->
+          <a-radio-group v-model="form.priceType">
+            <a-radio :value="form.dataScope == 'ENOUGH' ? 'SALES_BILL_COST_NOT_LACK':'SALES_BILL_COST'">导出</a-radio>
+            <a-radio :value="form.dataScope == 'ENOUGH' ? 'SALES_BILL_NOT_LACK':'SALES_BILL'">不导出</a-radio>
+          </a-radio-group>
+        </a-form-model-item>
+        <a-form-model-item label="货位编号" prop="orderBy" v-if="nowType=='SALES_BILL_TYPE'">
+          <a-radio-group v-model="form.orderBy">
+            <a-radio value="sbd.STACK_PLACE_CODE ASC">打印(↑升序)</a-radio>
+            <a-radio value="sbd.STACK_PLACE_CODE DESC">打印(↓降序)</a-radio>
+            <a-radio value="-1">不打印</a-radio>
+          </a-radio-group>
+        </a-form-model-item>
+      </a-form-model>
+      <div class="btn-cont">
+        <a-button :type="nowType=='export'?'primary':''" id="sales-print-save" @click="handleSave()">{{ nowType=='export' ? '导出' : '打印预览' }}</a-button>
+        <a-button :type="nowType=='export'?'':'primary'" id="sales-print-back" @click="handleCancel" style="margin-left: 15px;">{{ nowType=='export' ? '取消' : '快捷打印' }}</a-button>
+      </div>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+import { salesDetailProductType } from '@/api/sales'
+export default {
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    itemData: {
+      type: Object,
+      default: () => {
+        return null
+      }
+    },
+    nowType: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      form: {
+        id: 'all',
+        dataScope: 'all',
+        priceType: undefined,
+        orderBy: undefined
+      },
+      rules: {
+        id: [{ required: true, message: '请选择产品分类', trigger: 'change' }],
+        dataScope: [{ required: true, message: '请选择是否缺货产品', trigger: 'change' }],
+        priceType: [{ required: true, message: '请选择产品售价', trigger: 'change' }],
+        orderBy: [{ required: true, message: '请选择货位编号', trigger: 'change' }]
+      },
+      formItemLayout: {
+        labelCol: { span: 6 },
+        wrapperCol: { span: 15 }
+      },
+      spinning: false,
+      typeList: []
+    }
+  },
+  computed: {
+    modalTit () {
+      let title = ''
+      if (this.nowType == 'SALES_BILL') {
+        title = '销售打印'
+      } else if (this.nowType == 'SALES_BILL_TYPE') {
+        title = '销售分类打印'
+      } else if (this.nowType == 'export') {
+        title = '导出Excel'
+      }
+      return title
+    }
+  },
+  methods: {
+    // 确认
+    handleSave (isPrint) {
+      const _this = this
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          // 分类打印
+          if (_this.nowType == 'SALES_BILL_TYPE') {
+            // 销售分类无权限不打印
+            if(!_this.$hasPermissions('B_salesTypePrint_salesPrice')){
+              _this.form.priceType = 'SALES_BILL_TYPE'
+            }
+            const item = _this.typeList.find(item => item.id == _this.form.id)
+            if (item) {
+              const obj = {
+                salesBillSn: _this.itemData.salesBillSn,
+                productBrandSn: item.productBrandSn,
+                productTypeSn3: item.productTypeSn3,
+                priceType: _this.form.priceType,
+                type: isPrint || 'preview'
+              }
+              // 打印货位编号
+              if (_this.form.orderBy != '-1') {
+                obj.orderBy = _this.form.orderBy
+                obj.priceType = obj.priceType + '_STACK_PLACE'
+              }
+              _this.$emit('ok', obj)
+            }
+          } else if (_this.nowType == 'SALES_BILL') {
+            // 销售打印无权限不打印
+            if(!_this.$hasPermissions('B_salesPrint_salesPrice')){
+              _this.form.priceType = 'SALES_BILL'
+            }
+            const obj = {
+              salesBillSn: _this.itemData.salesBillSn,
+              priceType: _this.form.priceType,
+              type: isPrint || 'preview'
+            }
+            _this.$emit('ok', obj)
+          } else if (_this.nowType == 'export') {
+            // 销售导出无权限不导出
+            if(!_this.$hasPermissions('B_salesDetailExport_salesPrice')){
+              _this.form.priceType = _this.form.dataScope == 'ENOUGH' ? 'SALES_BILL_NOT_LACK':'SALES_BILL'
+            }
+            const obj = {
+              salesBillSn: _this.itemData.salesBillSn,
+              priceType: _this.form.priceType,
+              dataScope: _this.form.dataScope == 'all' ? '' : _this.form.dataScope,
+              type: isPrint || 'preview'
+            }
+            _this.$emit('ok', obj)
+          }
+          _this.isShow = false
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    },
+    // 取消选择分类
+    handleCancel () {
+      if (this.nowType == 'export') {
+        this.isShow = false
+      } else {
+        this.handleSave('print')
+      }
+    },
+    // 获取该销售单产品二级分类
+    getTypeData () {
+      this.typeList = [{ id: 'all' }]
+      salesDetailProductType({ sn: this.itemData.salesBillSn || null }).then(res => {
+        if (res.status == 200) {
+          if (res.data && res.data.length > 0) {
+            this.typeList = [...this.typeList, ...res.data]
+          }
+        }
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.form = {
+          id: 'all',
+          dataScope: 'all',
+          priceType: undefined,
+          orderBy: undefined
+        }
+        this.$refs.ruleForm.resetFields()
+      } else {
+        if (this.nowType == 'SALES_BILL_TYPE') {
+          this.getTypeData()
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .sales-print-type-modal{
+    .btn-cont {
+      text-align: center;
+      margin: 35px 0 10px;
+    }
+  }
+</style>

+ 268 - 0
src/views/salesManagement/salesQueryNew/queryPart.vue

@@ -0,0 +1,268 @@
+<template>
+  <div class="productInfoList-wrap">
+    <!-- 搜索条件 -->
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline" @keyup.enter.native="searchForm">
+        <a-row :gutter="15">
+          <a-col :md="6" :sm="24">
+            <a-form-item label="出库仓库" prop="warehouseSn" required>
+              <chooseWarehouse ref="warehouse" :allowClear="false" v-model="queryParam.warehouseSn" :isDefault="true" @load="loadWarehouse"></chooseWarehouse>
+            </a-form-item>
+          </a-col>
+          <a-col :md="6" :sm="24">
+            <a-form-item label="产品编码">
+              <a-input id="productInfoList-code" v-model.trim="queryParam.productCode" allowClear placeholder="请输入产品编码"/>
+            </a-form-item>
+          </a-col>
+          <a-col :md="6" :sm="24">
+            <a-form-item label="产品名称">
+              <a-input id="productInfoList-name" v-model.trim="queryParam.productName" allowClear placeholder="请输入产品名称"/>
+            </a-form-item>
+          </a-col>
+          <template v-if="advanced">
+            <a-col :md="6" :sm="24">
+              <a-form-item label="原厂编码">
+                <a-input id="productInfoList-origCode" v-model.trim="queryParam.productOrigCode" allowClear placeholder="请输入原厂编码"/>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="产品品牌">
+                <ProductBrand id="productInfoList-productBrandSn" v-model="queryParam.productBrandSn"></ProductBrand>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="产品分类">
+                <ProductType id="productInfoList-productType" v-model="productType" @change="changeProductType"></ProductType>
+              </a-form-item>
+            </a-col>
+          </template>
+          <a-col :md="6" :sm="24" style="margin-bottom: 10px;">
+            <a-button type="primary" @click="searchForm" :disabled="disabled" id="productInfoList-refresh">查询</a-button>
+            <a-button style="margin-left: 5px" @click="resetSearchForm" id="productInfoList-reset">重置</a-button>
+            <a @click="advanced=!advanced" style="margin: 0 5px">
+              {{ advanced ? '收起' : '展开' }}
+              <a-icon :type="advanced ? 'up' : 'down'"/>
+            </a>
+            <a-popover>
+              <template slot="content">双击列表配件可快速选中添加</template>
+              <a-icon type="question-circle" theme="twoTone" />
+            </a-popover>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+    <!-- 列表 -->
+    <s-table
+      class="sTable"
+      ref="table"
+      size="small"
+      :rowKey="(record) => record.id"
+      :columns="columns"
+      :data="loadData"
+      :customRow="handleClickRow"
+      :scroll="{ y: 149 }"
+      :defaultLoadData="false"
+      bordered>
+      <!-- 销售数量 -->
+      <template slot="nums" slot-scope="text, record">
+        <div @dblclick.stop>
+          <a-input-number
+            size="small"
+            v-model="record.salesNums"
+            :precision="0"
+            :min="1"
+            :max="999999"
+            style="width: 100%;"
+            placeholder="请输入" />
+        </div>
+      </template>
+      <!-- 产品名称 -->
+      <template slot="productName" slot-scope="text, record">
+        <div class="ellipsisCon">
+          <a-tooltip placement="rightBottom">
+            <template slot="title">
+              <span>{{ text }}</span>
+            </template>
+            <span class="ellipsisText">{{ text }}</span>
+          </a-tooltip>
+          <a-badge :number-style="{ backgroundColor: '#52c41a' }" count="活动" v-if="record.isJoinActivityProduct == 1"></a-badge>
+        </div>
+      </template>
+      <!-- 操作 -->
+      <template slot="action" slot-scope="text, record">
+        <a-button
+          size="small"
+          type="link"
+          class="button-info"
+          :loading="newLoading"
+          @click="handleAdd(record)"
+          :disabled="!record.productPrice || record.productPrice<=0"
+          id="productInfoList-edit-btn">添加</a-button>
+      </template>
+    </s-table>
+  </div>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+import { queryStockProductPage } from '@/api/stock'
+import ProductType from '@/views/common/productType.js'
+import ProductBrand from '@/views/common/productBrand.js'
+import chooseWarehouse from '@/views/common/chooseWarehouse'
+import { STable, VSelect } from '@/components'
+export default {
+  name: 'QueryPart',
+  mixins: [commonMixin],
+  components: { STable, VSelect, ProductBrand, ProductType, chooseWarehouse },
+  props: {
+    newLoading: Boolean
+  },
+  data () {
+    return {
+      advanced: false, // 高级搜索 展开/关闭
+      showSetting: false, // 设置弹框
+      productType: [],
+      buyerSn: '',
+      queryParam: { //  查询条件
+        productCode: '', //  产品编码
+        productName: '', //  产品名称
+        productOrigCode: '', //  原厂编码
+        productBrandSn: undefined, //  产品品牌
+        productTypeSn1: '', //  产品一级分类
+        productTypeSn2: '', //  产品二级分类
+        productTypeSn3: '', //  产品三级分类
+        warehouseSn: undefined
+      },
+      defaultWarehouseSn: undefined, // 默认仓库sn
+      disabled: false, //  查询、重置按钮是否可操作
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        this.queryParam.dealerSn = this.buyerSn
+        return queryStockProductPage(Object.assign(parameter, this.queryParam, { onlineFalg: '1', pricingState: 'PRICED' })).then(res => {
+          let data
+          if (res.status == 200) {
+            data = res.data
+            data.list = data.list.filter(item => item != null)
+            const no = (data.pageNo - 1) * data.pageSize
+            for (var i = 0; i < data.list.length; i++) {
+              data.list[i].no = no + i + 1
+              data.list[i].salesNums = 1
+              data.list[i].currentStockQty = data.list[i].currentStockQty || 0
+              const productPackQty = (data.list[i].productPackQty || data.list[i].productPackQty == 0) ? data.list[i].productPackQty : '--'
+              const productUnit = data.list[i].productUnit || '--'
+              const productPackQtyUnit = data.list[i].productPackQtyUnit || '--'
+              data.list[i].packQtyV = productPackQty + productUnit + '/' + productPackQtyUnit
+            }
+            this.disabled = false
+          }
+          return data
+        })
+      }
+    }
+  },
+  computed: {
+    columns () {
+      const arr = [
+        { title: '产品编码', dataIndex: 'productCode', width: '14%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品名称', dataIndex: 'productName', scopedSlots: { customRender: 'productName' }, width: '18%', align: 'left' },
+        { title: '原厂编码', dataIndex: 'productOrigCode', width: '11%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '品牌', dataIndex: 'productBrandName', width: '11%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '出库仓库', dataIndex: 'warehouseName', width: '11%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '库存数量', dataIndex: 'currentStockQty', width: '8%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '单位', dataIndex: 'productUnit', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
+        // { title: '售价', dataIndex: 'productPrice', width: '8%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '包装数', dataIndex: 'packQtyV', width: '8%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '销售数量', dataIndex: 'salesNums', scopedSlots: { customRender: 'nums' }, width: '8%', align: 'center' },
+        { title: '操作', dataIndex: 'action', scopedSlots: { customRender: 'action' }, width: '8%', align: 'center' }
+      ]
+      if (this.$hasPermissions('B_salesEdit_salesPrice')) { // 售价权限
+        arr.splice(6, 0, { title: '售价', dataIndex: 'productPrice', width: '8%', align: 'right', customRender: text => ((text || text == 0) ? this.toThousands(text) : '--') })
+      }
+      return arr
+    }
+  },
+  methods: {
+    loadWarehouse (sn) {
+      this.defaultWarehouseSn = sn
+      this.queryParam.warehouseSn = sn
+    },
+    // 双击列表
+    handleClickRow (record) {
+      const _this = this
+      return {
+        on: {
+          dblclick: (event) => {
+            if (!record.productPrice || record.productPrice <= 0) {
+              _this.$message.info('该产品暂时不能添加')
+            } else {
+              event.stopPropagation()
+              _this.$emit('add', record, 0)
+            }
+          }
+        }
+      }
+    },
+    // 查询
+    searchForm () {
+      if (this.queryParam.warehouseSn) {
+        this.$refs.table.refresh(true)
+      } else {
+        this.$message.info('请选择仓库')
+      }
+    },
+    //  重置
+    resetSearchForm () {
+      this.queryParam.productCode = ''
+      this.queryParam.productName = ''
+      this.queryParam.productOrigCode = ''
+      this.queryParam.productBrandSn = undefined
+      this.queryParam.productTypeSn1 = ''
+      this.queryParam.productTypeSn2 = ''
+      this.queryParam.productTypeSn3 = ''
+      this.productType = []
+      this.queryParam.warehouseSn = this.defaultWarehouseSn
+      this.$refs.table.refresh(true)
+    },
+    pageInit (buyerSn, warehouseSn) {
+      this.buyerSn = buyerSn
+      this.resetSearchForm()
+    },
+    // 刷新当前页面
+    resetCurForm () {
+      const _this = this
+      _this.$nextTick(() => {
+        _this.$refs.table.refresh()
+      })
+    },
+    // 选择配件
+    handleAdd (row) {
+      this.$emit('add', row, 0)
+    },
+    //  产品分类  change
+    changeProductType (val, opt) {
+      this.queryParam.productTypeSn1 = val[0] ? val[0] : ''
+      this.queryParam.productTypeSn2 = val[1] ? val[1] : ''
+      this.queryParam.productTypeSn3 = val[2] ? val[2] : ''
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+  .productInfoList-wrap{
+    .ellipsisCon{
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      .ellipsisText{
+        width: 100%;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        display: box;
+        display: -webkit-box;
+        -webkit-line-clamp: 1;
+        -webkit-box-orient: vertical;
+      }
+    }
+  }
+</style>

+ 249 - 0
src/views/salesManagement/salesQueryNew/receivingAddress/chooseAddressModal.vue

@@ -0,0 +1,249 @@
+<template>
+  <a-modal
+    centered
+    class="chooseAddressList-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="收货地址"
+    v-model="isShow"
+    @cancel="isShow=false"
+    :width="960">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <!-- 操作按钮 -->
+      <div class="table-operator">
+        <a-button id="chooseAddressList-add" type="primary" class="button-error" @click="handleEdit()">新增</a-button>
+      </div>
+      <!-- 列表 -->
+      <s-table
+        class="sTable"
+        ref="table"
+        size="small"
+        :rowKey="(record) => record.id"
+        :columns="columns"
+        :data="loadData"
+        :scroll="{ y: 500 }"
+        :showPagination="false"
+        :defaultLoadData="false"
+        bordered>
+        <!-- 收货人 -->
+        <template slot="consignee" slot-scope="text, record">
+          <div class="item-box">
+            <a-tooltip placement="top">
+              <template slot="title">
+                <span>{{ record.consigneeName }}</span>
+              </template>
+              <p class="ellipsis-txt">{{ record.consigneeName }}</p>
+            </a-tooltip>
+            <span v-if="record.defaultFlag==1" class="badge-txt">默认</span>
+          </div>
+        </template>
+        <!-- 操作 -->
+        <template slot="action" slot-scope="text, record">
+          <a-button
+            size="small"
+            type="primary"
+            class="button-success"
+            v-if="record.defaultFlag!=1"
+            @click="handleDefault(record)"
+            id="chooseAddressList-default-btn">设为默认</a-button>
+          <a-button
+            size="small"
+            type="primary"
+            class="button-info"
+            @click="handleEdit(record)"
+            id="chooseAddressList-edit-btn"
+          >编辑</a-button>
+          <a-button
+            size="small"
+            type="primary"
+            class="button-error"
+            @click="handleDel(record)"
+            id="chooseAddressList-del-btn"
+          >删除</a-button>
+        </template>
+        <!-- 选择 -->
+        <template slot="choose" slot-scope="text, record">
+          <a-button
+            size="small"
+            type="primary"
+            class="button-primary"
+            @click="handleChoose(record)"
+            id="chooseAddressList-choose-btn">选择</a-button>
+        </template>
+      </s-table>
+    </a-spin>
+    <!-- 新增/编辑地址 -->
+    <edit-address-modal ref="addrModal" :openModal="openAddrModal" :paramsData="paramsData" @ok="handleOk" @close="openAddrModal=false" />
+  </a-modal>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+import { STable, VSelect } from '@/components'
+import editAddressModal from './editAddressModal'
+import { dealerRecevieAddrQuery, dealerRecevieAddrSet, dealerRecevieAddrDel } from '@/api/dealerRecevieAddr'
+export default {
+  name: 'ChooseAddressModal',
+  mixins: [commonMixin],
+  components: { STable, VSelect, editAddressModal },
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    paramsData: {
+      type: String || Number,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      spinning: false,
+      isShow: this.openModal, //  是否打开弹框
+      // 表头
+      columns: [
+        { title: '序号', dataIndex: 'no', width: 50, align: 'center' },
+        { title: '收货人', scopedSlots: { customRender: 'consignee' }, align: 'center', ellipsis: true },
+        { title: '手机号码', dataIndex: 'consigneeTel', width: 230, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '收货地址', dataIndex: 'address', width: 400, align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        // { title: '操作', scopedSlots: { customRender: 'action' }, width: 200, align: 'center', fixed: 'right' },
+        { title: '选择', scopedSlots: { customRender: 'choose' }, width: 80, align: 'center', fixed: 'right' }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        return dealerRecevieAddrQuery({ dealerSn: this.paramsData }).then(res => {
+          let data
+          if (res.status == 200) {
+            data = res.data
+            const no = 0
+            for (var i = 0; i < data.length; i++) {
+              data[i].no = no + i + 1
+              const provinceName = data[i].provinceName ? (data[i].provinceName + '-') : ''
+              const cityName = data[i].cityName ? (data[i].cityName + '-') : ''
+              const countyName = data[i].countyName ? (data[i].countyName + '-') : ''
+              const addr = data[i].addr || ''
+              data[i].address = provinceName + cityName + countyName + addr
+            }
+            this.disabled = false
+          }
+          return data
+        })
+      },
+      openAddrModal: false // 选择地址弹框是否显示
+    }
+  },
+  methods: {
+    //  设为默认
+    handleDefault (row) {
+      this.spinning = true
+      dealerRecevieAddrSet({ id: row.id }).then(res => {
+        if (res.status == 200) {
+          this.$message.success(res.message)
+          this.$refs.table.refresh(true)
+          this.spinning = false
+        } else {
+          this.spinning = false
+        }
+      })
+    },
+    //  新增/编辑收货地址
+    handleEdit (row) {
+      if (row) {
+        this.$refs.addrModal.setData({
+          id: row.id,
+          consigneeName: row.consigneeName,
+          consigneeTel: row.consigneeTel,
+          provinceSn: row.provinceSn,
+          provinceName: row.provinceName,
+          citySn: row.citySn,
+          cityName: row.cityName,
+          countySn: row.countySn,
+          countyName: row.countyName,
+          addr: row.addr
+        })
+      }
+      this.openAddrModal = true
+    },
+    //  选择
+    handleChoose (row) {
+      this.$emit('ok', row)
+    },
+    //  删除
+    handleDel (row) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '删除后不可恢复,确定要进行删除吗?',
+        centered: true,
+        onOk () {
+          _this.spinning = true
+          dealerRecevieAddrDel({
+            id: row.id
+          }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$emit('verify', row.id)
+              _this.$refs.table.refresh(true)
+              _this.spinning = false
+            } else {
+              _this.spinning = false
+            }
+          })
+        }
+      })
+    },
+    //  地址保存成功
+    handleOk (data) {
+      this.$refs.table.refresh(true)
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+      } else {
+        const _this = this
+        setTimeout(() => {
+          _this.$refs.table.refresh(true)
+        }, 300)
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .chooseAddressList-modal{
+    .table-operator{
+      margin-bottom: 10px;
+    }
+    .item-box{
+      position: relative;
+      display: flex;
+      align-items: center;
+      .ellipsis-txt{
+        margin: 0;
+        width: 100%;
+        overflow: hidden;
+        text-overflow:ellipsis;
+        whitewhite-space: nowrap;
+      }
+      .badge-txt{
+        line-height: 20px;
+        padding: 0 7px;
+        font-size: 12px;
+        background-color: #fff;
+        color: #ed1c24;
+        border-color: #ed1c24;
+        border-radius: 20px;
+        box-shadow: 0 0 0 1px #d9d9d9 inset;
+      }
+    }
+  }
+</style>

+ 269 - 0
src/views/salesManagement/salesQueryNew/receivingAddress/editAddressModal.vue

@@ -0,0 +1,269 @@
+<template>
+  <a-modal
+    centered
+    class="editAddress-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="收货地址"
+    v-model="isShow"
+    @cancel="isShow=false"
+    :width="800">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-form-model
+        id="editAddress-form"
+        ref="ruleForm"
+        :model="form"
+        :rules="rules"
+        :label-col="formItemLayout.labelCol"
+        :wrapper-col="formItemLayout.wrapperCol"
+      >
+        <a-form-model-item label="收货人" prop="consigneeName">
+          <a-input
+            id="editAddress-name"
+            :maxLength="30"
+            v-model.trim="form.consigneeName"
+            placeholder="请输入收货人(最多30个字符)"
+            allowClear />
+        </a-form-model-item>
+        <a-form-model-item label="收货人电话" prop="consigneeTel">
+          <a-input
+            id="editAddress-phone"
+            :maxLength="30"
+            v-model.trim="form.consigneeTel"
+            placeholder="请输入收货人电话(最多30个字符)"
+            allowClear />
+        </a-form-model-item>
+        <a-form-model-item label="所在地区" required style="margin: 0;">
+          <a-row :gutter="20">
+            <!-- 所在地区 -->
+            <a-col span="8">
+              <a-form-model-item prop="provinceSn">
+                <a-select id="editAddress-provinceSn" allowClear @change="getCityList" v-model="form.provinceSn" placeholder="请选择省">
+                  <a-select-option v-for="item in addrProvinceList" :value="item.areaSn" :key="item.areaSn + 'a'">{{ item.name }}</a-select-option>
+                </a-select>
+              </a-form-model-item>
+            </a-col>
+            <a-col span="8">
+              <a-form-model-item prop="citySn">
+                <a-select id="editAddress-citySn" allowClear @change="getAreaList" v-model="form.citySn" placeholder="请选择市">
+                  <a-select-option v-for="item in addrCityList" :value="item.areaSn" :key="item.areaSn + 'b'">{{ item.name }}</a-select-option>
+                </a-select>
+              </a-form-model-item>
+            </a-col>
+            <a-col span="8">
+              <a-form-model-item prop="countySn">
+                <a-select id="editAddress-countySn" allowClear @change="areaCharged" v-model="form.countySn" placeholder="请选择区/县">
+                  <a-select-option v-for="item in addrDistrictList" :value="item.areaSn" :key="item.areaSn + 'c'">{{ item.name }}</a-select-option>
+                </a-select>
+              </a-form-model-item>
+            </a-col>
+          </a-row>
+        </a-form-model-item>
+        <a-form-model-item label="详细地址" prop="addr">
+          <a-input
+            id="editAddress-address"
+            :maxLength="60"
+            v-model.trim="form.addr"
+            placeholder="请输入详细地址(最多60个字符)"
+            allowClear />
+        </a-form-model-item>
+        <a-form-model-item :wrapper-col="{ span: 12, offset: 6 }" style="text-align: center;">
+          <a-button type="primary" @click="handleSubmit" id="editAddress-btn-submit">保存</a-button>
+          <a-button @click="isShow=false" style="margin-left: 15px" id="editAddress-btn-back">返回</a-button>
+        </a-form-model-item>
+      </a-form-model>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+import { getArea } from '@/api/data'
+import { dealerRecevieAddrSave } from '@/api/dealerRecevieAddr'
+export default {
+  name: 'EditAddressModal',
+  mixins: [commonMixin],
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    paramsData: {
+      type: String || Number,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      spinning: false,
+      isShow: this.openModal, //  是否打开弹框
+      isEdit: false,
+      formItemLayout: {
+        labelCol: { span: 4 },
+        wrapperCol: { span: 18 }
+      },
+      form: {
+        consigneeName: '',
+        consigneeTel: '',
+        provinceSn: undefined,
+        provinceName: '',
+        citySn: undefined,
+        cityName: '',
+        countySn: undefined,
+        countyName: '',
+        addr: ''
+      },
+      rules: {
+        consigneeName: [
+          { required: true, message: '请输入收货人', trigger: 'change' }
+        ],
+        consigneeTel: [
+          { required: true, message: '请输入收货人电话', trigger: 'change' }
+        ],
+        provinceSn: [
+          { required: true, message: '请选择省', trigger: 'change' }
+        ],
+        citySn: [
+          { required: true, message: '请选择市', trigger: 'change' }
+        ],
+        countySn: [
+          { required: true, message: '请选择区', trigger: 'change' }
+        ],
+        addr: [
+          { required: true, message: '请输入详细地址', trigger: 'change' }
+        ]
+      },
+      addrProvinceList: [], //  省下拉
+      addrCityList: [], //  市下拉
+      addrDistrictList: [] //  区下拉
+    }
+  },
+  methods: {
+    //  保存
+    handleSubmit () {
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          this.spinning = true
+          dealerRecevieAddrSave(Object.assign(this.form, { dealerSn: this.paramsData })).then(res => {
+            if (res.status == 200) {
+              this.isShow = false
+              this.$emit('ok')
+              this.$message.success(res.message)
+              this.spinning = false
+            } else {
+              this.spinning = false
+            }
+          })
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    },
+    // 获取城市列表
+    getCityList (val) {
+      this.addrCityList = []
+      this.addrDistrictList = []
+      this.form.citySn = undefined
+      this.form.countySn = undefined
+      if (val) {
+        this.getArea('city', val)
+        this.form.provinceName = this.addrProvinceList.find(item => item.areaSn == val).name
+      } else {
+        this.form.provinceName = ''
+      }
+    },
+    // 获取区县列表
+    getAreaList (val) {
+      this.addrDistrictList = []
+      this.form.countySn = undefined
+      if (val) {
+        this.getArea('district', val)
+        this.form.cityName = this.addrCityList.find(item => item.areaSn == val).name
+      } else {
+        this.form.cityName = ''
+      }
+    },
+    // 区县变更
+    areaCharged (val) {
+      if (val) {
+        this.form.countyName = this.addrDistrictList.find(item => item.areaSn == val).name
+      } else {
+        this.form.countyName = ''
+      }
+    },
+    //  省/市/区
+    getArea (leve, sn) {
+      let params
+      if (leve == 'province') {
+        params = { type: '2' }
+      } else {
+        params = { parentId: sn, type: leve == 'city' ? '3' : '4' }
+      }
+      getArea(params).then(res => {
+        if (res.status == 200) {
+          if (leve == 'province') {
+            this.addrProvinceList = res.data || []
+          } else if (leve == 'city') {
+            this.addrCityList = res.data || []
+          } else if (leve == 'district') {
+            this.addrDistrictList = res.data || []
+          }
+        } else {
+          if (leve == 'province') {
+            this.addrProvinceList = []
+          } else if (leve == 'city') {
+            this.addrCityList = []
+          } else if (leve == 'district') {
+            this.addrDistrictList = []
+          }
+        }
+      })
+    },
+    // 编辑数据
+    setData (data) {
+      this.isEdit = true
+      Promise.all([getArea({ type: '2' }), getArea({ parentId: data.provinceSn, type: '3' }), getArea({ parentId: data.citySn, type: '4' })]).then(res => {
+        console.log(res)
+        this.addrProvinceList = res[0].data
+        const provinceName = this.addrProvinceList.find(item => item.id == data.provinceSn)
+        if (provinceName && provinceName.name) {
+          this.form.provinceName = provinceName.name
+        }
+        this.addrCityList = res[1].data
+        const cityName = this.addrCityList.find(item => item.id == data.citySn)
+        if (cityName && cityName.name) {
+          this.form.cityName = cityName.name
+        }
+        this.addrDistrictList = res[2].data
+        const countyName = this.addrDistrictList.find(item => item.id == data.countySn)
+        if (countyName && countyName.name) {
+          this.form.countyName = countyName.name
+        }
+        this.form = Object.assign({}, this.form, data)
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.$refs.ruleForm.resetFields()
+        this.addrCityList = []
+        this.addrDistrictList = []
+        this.isEdit = false
+        delete this.form.id
+      } else {
+        if (!this.isEdit) {
+          this.getArea('province')
+        }
+      }
+    }
+  }
+}
+</script>

+ 87 - 0
src/views/salesManagement/salesQueryNew/setPriceModal.vue

@@ -0,0 +1,87 @@
+<template>
+  <a-modal
+    v-model="opened"
+    title="提交"
+    centered
+    :maskClosable="false"
+    :confirmLoading="confirmLoading"
+    width="30%"
+    :footer="null"
+    @cancel="cancel"
+  >
+    <a-spin :spinning="spinning" tip="Loading...">
+      <div style="display:flex;align-items:center;justify-content:center;">
+        <a-icon type="warning" theme="twoTone" two-tone-color="#D9001b" style="font-size:60px;margin-right:30px;"/>
+        <div>
+          <div style="margin-bottom:10px;font-weight:bold;">销售单部分产品价格发生变更,请确认</div>
+          <a-radio-group v-model="priceVal">
+            <a-radio value="0" :style="radioStyle">
+              以【当前】价格为准,总金额:{{ totalRealAmount }}元
+            </a-radio>
+            <a-radio value="1" :style="radioStyle">
+              以【最新】价格为准,总金额:{{ totalAmount }}元
+            </a-radio>
+          </a-radio-group>
+        </div>
+      </div>
+      <div style="margin-top:36px;text-align:center;">
+        <a-button @click="cancel" style="margin-right: 15px" id="chooseCustom-btn-back">取消</a-button>
+        <a-button type="primary" :loading="confirmLoading" @click="handleSubmit" id="chooseCustom-btn-submit">确定</a-button>
+      </div>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+export default {
+  name: 'SetPriceModal',
+  mixins: [commonMixin],
+  props: {
+    show: [Boolean],
+    totalRealAmount: {
+      type: String,
+      default: ''
+    },
+    totalAmount: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      opened: this.show,
+      spinning: false,
+      priceVal: undefined,
+      confirmLoading: false,
+      radioStyle: {
+        display: 'block',
+        height: '30px',
+        lineHeight: '30px'
+      }
+    }
+  },
+  methods: {
+    //  保存
+    handleSubmit () {
+      if (!this.priceVal) {
+        this.$message.warning('请选择价格变更类型!')
+        return
+      }
+      this.$emit('ok', this.priceVal)
+    },
+    cancel () {
+      this.opened = false
+      this.$emit('cancel')
+    }
+  },
+  watch: {
+    show (newValue, oldValue) {
+      this.opened = newValue
+      if (!newValue) {
+        this.priceVal = undefined
+      }
+    }
+  }
+}
+</script>

+ 171 - 0
src/views/salesManagement/salesQueryNew/stockOutDetailModal.vue

@@ -0,0 +1,171 @@
+<template>
+  <a-modal
+    centered
+    :footer="null"
+    :maskClosable="false"
+    title="销售单缺货明细"
+    v-model="isShow"
+    @cancel="isShow=false"
+    width="50%">
+    <a-descriptions size="small" :column="2">
+      <a-descriptions-item label="销售单号">
+        {{ detailData&&detailData.salesBillNo || '--' }}
+        <span v-if="detailData&&detailData.salesBillNoSource">(原:{{ detailData&&detailData.salesBillNoSource || '--' }})</span>
+      </a-descriptions-item>
+      <a-descriptions-item label="客户名称">{{ detailData&&detailData.buyerName || '--' }}</a-descriptions-item>
+    </a-descriptions>
+    <a-spin :spinning="spinning" tip="Loading...">
+      <s-table
+        class="sTable fixPagination"
+        ref="table"
+        size="small"
+        :rowKey="(record) => record.id"
+        :columns="columns"
+        :data="loadData"
+        :scroll="{ y: 500 }"
+        :showPagination="false"
+        :defaultLoadData="false"
+        bordered>
+      </s-table>
+      <div class="btn-cont" style="padding:20px 20px 0;text-align: center;">
+        <!-- <a-button @click="isShow=false">关闭</a-button> -->
+        <a-button
+          class="button-warning"
+          type="primary"
+          @click="handleExport"
+          :disabled="disabled"
+          :loading="exportLoading"
+          id="allocateBillList-export">导出Excel</a-button>
+        <a-button
+          style="margin-left: 5px"
+          @click="handleClassifyExport"
+          :disabled="disabled"
+          :loading="exportClassifyLoading"
+          id="allocateBillList-export">分类导出Excel</a-button>
+       </div>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+import { STable } from '@/components'
+import { commonMixin } from '@/utils/mixin'
+import { salesStockoutDetail, exportStockout, exportGroupStockout } from '@/api/salesDetail'
+import { hdExportExcel } from '@/libs/exportExcel'
+export default {
+  name: 'StockOutDetail',
+  mixins: [commonMixin],
+  components: { STable },
+  props: {
+    openModal: {
+      type: Boolean,
+      default: false
+    },
+    salesBillSn: {
+      type: [Number, String],
+      default: ''
+    },
+    detailData: {
+      type: Object,
+      default: function () {
+        return null
+      }
+    }
+  },
+  data () {
+    const _this = this
+    return {
+      spinning: false,
+      isShow: this.openModal,
+      disabled: false,
+      exportLoading: false,
+      exportClassifyLoading: false,
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.spinning = true
+        this.disabled = true
+        delete parameter.tableId
+        delete parameter.index
+        return salesStockoutDetail({ isOos: 1, salesBillSn: this.salesBillSn }).then(res => {
+          let data
+          if (res.status == 200) {
+            data = res.data
+            const no = 0
+            for (var i = 0; i < data.length; i++) {
+              data[i].no = no + i + 1
+            }
+            this.disabled = false
+          }
+          this.spinning = false
+          return data
+        })
+      }
+    }
+  },
+  computed:{
+    columns () {
+      const _this = this
+      const arr = [
+        { title: '序号', dataIndex: 'no', width: '5%', align: 'center' },
+        { title: '产品编码', dataIndex: 'productEntity.code', width: '15%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品名称', dataIndex: 'productEntity.name', width: '25%', align: 'left', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '原厂编码', dataIndex: 'productEntity.origCode', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '单位', dataIndex: 'productEntity.unit', width: '5%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '销售数量', dataIndex: 'qty', width: '8%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        // { title: '销售价', dataIndex: 'price', width: '8%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        // { title: '销售金额', dataIndex: 'totalAmount', width: '8%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        { title: '缺货数量', dataIndex: 'lackQty', width: '8%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } }
+      ]
+      
+      if (this.$hasPermissions('B_salesDetail_salesPrice')) { // 售价权限
+        arr.splice(6, 0, { title: '销售价', dataIndex: 'price', width: '8%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } })
+        arr.splice(7, 0, { title: '销售金额', dataIndex: 'totalAmount', width: '8%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } })
+        arr.splice(8, 0, { title: '缺货金额', dataIndex: 'lackAmount', width: '8%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } })
+      }
+      return arr
+    }
+  },
+  methods: {
+    handleExport () {
+      const _this = this
+      _this.exportLoading = true
+      _this.disabled = true
+      _this.spinning = true
+      hdExportExcel(exportStockout, { isOos: 1, salesBillSn: _this.salesBillSn }, '销售单缺货产品导出', function () {
+        _this.exportLoading = false
+        _this.spinning = false
+        _this.disabled = false
+      })
+    },
+    handleClassifyExport () {
+      const _this = this
+      _this.exportClassifyLoading = true
+      _this.disabled = true
+      _this.spinning = true
+      hdExportExcel(exportGroupStockout, { isOos: 1, salesBillSn: _this.salesBillSn }, '销售单缺货产品分类导出', function () {
+        _this.exportClassifyLoading = false
+        _this.spinning = false
+        _this.disabled = false
+      })
+    }
+  },
+  watch: {
+    openModal (nVal, oVal) {
+      this.isShow = nVal
+    },
+    isShow (nVal, oVal) {
+      if (!nVal) {
+        this.$emit('close')
+        this.$refs.table.clearTable()
+      } else {
+        this.$nextTick(() => {
+          this.$refs.table.refresh()
+        })
+      }
+    }
+  }
+}
+</script>
+
+<style>
+</style>