Kaynağa Gözat

销售管理

chenrui 4 yıl önce
ebeveyn
işleme
bca26356f9

+ 48 - 0
src/api/custType.js

@@ -0,0 +1,48 @@
+import { axios } from '@/utils/request'
+
+//  客户类型列表  分页
+export const custTypeList = (params) => {
+  const url = `/custType/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+
+//  客户类型列表  不分页
+export const custTypeAllList = (params) => {
+  return axios({
+    url: `/custType/queryList`,
+    data: {},
+    method: 'post'
+  })
+}
+//  客户类型列表  下拉
+export const custTypeFindAllList = (params) => {
+  return axios({
+    url: `/custType/findAll`,
+    data: {},
+    method: 'post'
+  })
+}
+
+// 新增/编辑客户类型
+export const custTypeSave = params => {
+  return axios({
+    url: '/custType/save',
+    data: params,
+    method: 'post'
+  })
+}
+
+// 删除客户类型
+export const custTypeDel = params => {
+  return axios({
+    url: `/custType/delete/${params.id}`,
+    data: {},
+    method: 'get'
+  })
+}

+ 21 - 4
src/api/sales.js

@@ -19,6 +19,14 @@ export const salesDetail = (params) => {
     method: 'get'
   })
 }
+//  销售 详情bysn
+export const salesDetailBySn = (params) => {
+  return axios({
+    url: `/sales/findBySn`,
+    data: params,
+    method: 'post'
+  })
+}
 //  销售 打印
 export const salesPrint = (params) => {
   return axios({
@@ -78,9 +86,8 @@ export const salesWriteReceipt = (params) => {
 //  销售 出库
 export const salesWriteStockOut = (params) => {
   return axios({
-    url: '/sales/stockOut',
-    data: params,
-    method: 'post'
+    url: `/sales/stockOut/${params.salesBillSn}`,
+    method: 'get'
   })
 }
 //  销售 提交
@@ -91,7 +98,7 @@ export const salesWriteSubmit = (params) => {
     method: 'post'
   })
 }
-//  销售 保存
+//  销售 新增或编辑
 export const salesSave = (params) => {
   return axios({
     url: '/sales/save',
@@ -99,6 +106,7 @@ export const salesSave = (params) => {
     method: 'post'
   })
 }
+
 //  销售 删除
 export const salesDel = (params) => {
   return axios({
@@ -107,3 +115,12 @@ export const salesDel = (params) => {
     method: 'post'
   })
 }
+
+// 销售 统计
+export const salesCount = (params) => {
+  return axios({
+    url: `/sales/queryCount`,
+    data: params,
+    method: 'post'
+  })
+}

+ 160 - 0
src/api/salesReturn.js

@@ -0,0 +1,160 @@
+import { axios } from '@/utils/request'
+
+//  销售退货 审核
+export const salesReturnAudit = (params) => {
+  return axios({
+    url: `/salesReturn/audit/${params.sn}`,
+    method: 'get'
+  })
+}
+//  销售退货 删除
+export const salesReturnDel = (params) => {
+  return axios({
+    url: `/salesReturn/delete/${params.sn}`,
+    method: 'get'
+  })
+}
+
+//  销售退货明细 删除
+export const salesReturnDetailDel = (params) => {
+  return axios({
+    url: `/salesReturn/detail/delete/${params.id}`,
+    method: 'get'
+  })
+}
+
+//  销售退货明细 整单删除
+export const salesReturnDelAll = (params) => {
+  return axios({
+    url: `/salesReturn/detail/deleteAll/${params.sn}`,
+    method: 'get'
+  })
+}
+
+// 明细列表统计,不传sn 是所有统计
+export const salesReturnQueryCount = (params) => {
+  const url = `/salesReturn/detail/queryCount`
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+
+//  销售退货 分页查询销售退货明细
+export const salesReturnDetailList = (params) => {
+  const url = `/salesReturn/detail/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  销售退货 分页查询产品
+export const salesReturnProductList = (params) => {
+  const url = `/salesReturn/detail/querySalesBillDetailPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  产品添加和修改
+export const salesReturnSaveProduct = (params) => {
+  return axios({
+    url: '/salesReturn/detail/save',
+    data: params,
+    method: 'post'
+  })
+}
+
+// 退货打折
+export const salesReturnDiscount = (params) => {
+  return axios({
+    url: '/salesReturn/discount',
+    data: params,
+    method: 'post'
+  })
+}
+
+//  销售退货 导出
+export const salesReturnExport = (params) => {
+  return axios({
+    url: '/salesReturn/export',
+    data: params,
+    method: 'post'
+  })
+}
+
+// 根据SN查询销售退货单
+export const salesReturnDetail = (params) => {
+  return axios({
+    url: `/salesReturn/findBySn/${params.sn}`,
+    method: 'get'
+  })
+}
+
+//  销售退货 付款
+export const salesReturnPay = (params) => {
+  return axios({
+    url: '/salesReturn/pay',
+    data: params,
+    method: 'post'
+  })
+}
+
+//  销售退货 打印
+export const salesReturnPrint = (params) => {
+  return axios({
+    url: '/salesReturn/print',
+    data: params,
+    method: 'post'
+  })
+}
+
+//  销售退货 打印预览
+export const salesReturnprintPreview = (params) => {
+  return axios({
+    url: '/salesReturn/printPreview',
+    data: params,
+    method: 'post'
+  })
+}
+
+//  销售退货 列表分页
+export const salesReturnList = (params) => {
+  const url = `/salesReturn/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+
+//  销售退货单保存
+export const salesReturnSave = (params) => {
+  return axios({
+    url: '/salesReturn/save',
+    data: params,
+    method: 'post'
+  })
+}
+
+//  销售退货 提交
+export const salesReturnSubmit = (params) => {
+  return axios({
+    url: `/salesReturn/submit/${params.sn}`,
+    method: 'get'
+  })
+}
+
+
+
+
+

+ 29 - 0
src/api/salesReturnDetail.js

@@ -0,0 +1,29 @@
+import { axios } from '@/utils/request'
+
+//  销售退货详情 列表  分页
+export const salesReturnDetailList = (params) => {
+  const url = `/salesReturnDetail/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  销售退货详情 保存
+export const salesReturnDetailSave = (params) => {
+  return axios({
+    url: '/salesReturnDetail/save',
+    data: params,
+    method: 'post'
+  })
+}
+//  销售退货详情 删除
+export const salesReturnDetailDel = (params) => {
+  return axios({
+    url: `/salesReturnDetail/delete/${params.id}`,
+    data: params,
+    method: 'post'
+  })
+}

+ 10 - 0
src/api/settleStyle.js

@@ -0,0 +1,10 @@
+import { axios } from '@/utils/request'
+
+//  结算方式列表
+export const settleStyleQueryAll = (params) => {
+  return axios({
+    url: '/settleStyle/findAll',
+    data: params,
+    method: 'post'
+  })
+}

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

@@ -719,6 +719,64 @@ export const asyncRouterMap = [
               }
             ]
           },
+          {
+            path: '/salesManagement/salesReturn',
+            redirect: '/salesManagement/salesReturn/list',
+            name: 'salesReturn',
+            component: RouteView,
+            meta: {
+              title: '销售退货列表',
+              icon: 'fund'
+              // permission: 'M_salesReturn_list'
+            },
+            hideChildrenInMenu: true,
+            children: [
+              {
+                path: 'list',
+                name: 'salesReturnList',
+                component: () => import(/* webpackChunkName: "salesManagement" */ '@/views/salesManagement/salesReturn/list.vue'),
+                meta: {
+                  title: '退货单列表',
+                  icon: 'fund',
+                  hidden: true
+                  // permission: 'M_salesReturn_list'
+                }
+              },
+              {
+                path: 'detail/:id/:sn',
+                name: 'salesReturnDetail',
+                component: () => import(/* webpackChunkName: "salesManagement" */ '@/views/salesManagement/salesReturn/detail.vue'),
+                meta: {
+                  title: '退货单详情',
+                  icon: 'fund',
+                  hidden: true
+                  // permission: 'M_salesReturn'
+                }
+              },
+              {
+                path: 'salesReturnGrabEdit/:id/:sn/:buyerSn',
+                name: 'salesReturnGrabEdit',
+                component: () => import(/* webpackChunkName: "salesManagement" */ '@/views/salesManagement/salesReturn/salesReturnGrabEdit.vue'),
+                meta: {
+                  title: '编辑退货单(抓单)',
+                  icon: 'fund',
+                  hidden: true
+                  // permission: 'M_salesReturnGrabEdit'
+                }
+              },
+              {
+                path: 'salesReturnEdit/:id/:sn/:buyerSn',
+                name: 'salesReturnEdit',
+                component: () => import(/* webpackChunkName: "salesManagement" */ '@/views/salesManagement/salesReturn/salesReturnEdit.vue'),
+                meta: {
+                  title: '编辑退货单(不抓单)',
+                  icon: 'fund',
+                  hidden: true
+                  // permission: 'M_salesReturnEdit'
+                }
+              }
+            ]
+          },
           {
             path: '/salesManagement/backorder',
             redirect: '/salesManagement/backorder/list',
@@ -754,6 +812,56 @@ export const asyncRouterMap = [
                 }
               }
             ]
+          },
+          {
+            path: '/salesManagement/shortageStatisticsC',
+            redirect: '/salesManagement/shortageStatisticsC/list',
+            name: 'shortageStatisticsC',
+            component: RouteView,
+            meta: {
+              title: '缺货统计(按客户)',
+              icon: 'sketch'
+              // permission: 'M_goodsManage_list'
+            },
+            hideChildrenInMenu: true,
+            children: [
+              {
+                path: 'list',
+                name: 'shortageStatisticsCList',
+                component: () => import(/* webpackChunkName: "shop" */ '@/views/salesManagement/shortageStatisticsC/list.vue'),
+                meta: {
+                  title: '缺货统计列表',
+                  icon: 'sketch',
+                  hidden: true
+                  // permission: 'M_goodsManage_list'
+                }
+              }
+            ]
+          },
+          {
+            path: '/salesManagement/shortageStatisticsP',
+            redirect: '/salesManagement/shortageStatisticsP/list',
+            name: 'shortageStatisticsP',
+            component: RouteView,
+            meta: {
+              title: '缺货统计(按产品)',
+              icon: 'sketch'
+              // permission: 'M_goodsManage_list'
+            },
+            hideChildrenInMenu: true,
+            children: [
+              {
+                path: 'list',
+                name: 'shortageStatisticsPList',
+                component: () => import(/* webpackChunkName: "shop" */ '@/views/salesManagement/shortageStatisticsP/list.vue'),
+                meta: {
+                  title: '缺货统计列表',
+                  icon: 'sketch',
+                  hidden: true
+                  // permission: 'M_goodsManage_list'
+                }
+              }
+            ]
           }
         ]
       },

+ 340 - 0
src/views/customerManagement/customerInfo/edit.vue

@@ -0,0 +1,340 @@
+<template>
+  <div class="customerManagementEdit-wrap">
+    <a-page-header :ghost="false" :backIcon="false" v-if="model=='page'" class="customerManagementEdit-back">
+      <!-- 自定义的二级文字标题 -->
+      <template slot="subTitle">
+        <a id="customerManagementEdit-back-btn" href="javascript:;" @click="handleBack"><a-icon type="left" /> 返回列表</a>
+      </template>
+    </a-page-header>
+    <a-card size="small" :bordered="false" class="customerManagementEdit-table-page-wrapper">
+      <a-form-model
+        id="customerManagementEdit-form"
+        ref="ruleForm"
+        :model="form"
+        :rules="rules"
+        :label-col="formItemLayout.labelCol"
+        :wrapper-col="formItemLayout.wrapperCol"
+      >
+        <a-row :gutter="15">
+          <a-col :span="8">
+            <a-form-model-item label="客户名称" prop="customerName">
+              <a-input
+                id="customerManagementEdit-customerName"
+                :maxLength="30"
+                v-model.trim="form.customerName"
+                @change="filterEmpty"
+                placeholder="请输入客户名称(最多30个字符)"
+                allowClear />
+            </a-form-model-item>
+          </a-col>
+          <a-col :span="8">
+            <a-form-model-item label="联系电话" prop="contactTel">
+              <a-input id="customerManagementEdit-contactTel" :maxLength="11" v-model.trim="form.contactTel" placeholder="请输入联系电话(最多11个字符)" allowClear />
+            </a-form-model-item>
+          </a-col>
+          <a-col :span="8">
+            <a-form-model-item label="联系人" prop="contactName">
+              <a-input id="customerManagementEdit-contactName" :maxLength="30" v-model.trim="form.contactName" placeholder="请输入联系人(最多30个字符)" allowClear />
+            </a-form-model-item>
+          </a-col>
+        </a-row>
+        <a-row :gutter="15">
+          <a-col :span="16">
+            <a-form-model-item label="客户地址" required style="margin: 0;" :labelCol="{ span: 4 }" :wrapperCol="{ span: 20 }">
+              <a-row :gutter="15">
+                <!-- 客户地址 -->
+                <a-col span="8">
+                  <a-form-model-item prop="provinceSn">
+                    <a-select id="customerManagementEdit-provinceSn" @change="getCityList" v-model="form.provinceSn" placeholder="请选择省">
+                      <a-select-option v-for="item in addrProvinceList" :value="item.sn" :key="item.sn + '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="customerManagementEdit-citySn" @change="getAreaList" v-model="form.citySn" placeholder="请选择市">
+                      <a-select-option v-for="item in addrCityList" :value="item.sn" :key="item.sn + '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="customerManagementEdit-countySn" @change="areaCharged" v-model="form.countySn" placeholder="请选择区/县">
+                      <a-select-option v-for="item in addrDistrictList" :value="item.sn" :key="item.sn + 'c'">{{ item.name }}</a-select-option>
+                    </a-select>
+                  </a-form-model-item>
+                </a-col>
+              </a-row>
+            </a-form-model-item>
+          </a-col>
+          <a-col :span="8">
+            <a-form-model-item label="" prop="customerAddr">
+              <a-input id="customerManagementEdit-customerAddr" :maxLength="60" v-model.trim="form.customerAddr" placeholder="请输入详细地址(最多60个字符)" allowClear />
+            </a-form-model-item>
+          </a-col>
+        </a-row>
+        <a-row :gutter="15">
+          <a-col :span="8">
+            <a-form-model-item label="客户传真" prop="fax">
+              <a-input id="customerManagementEdit-fax" :maxLength="30" v-model.trim="form.fax" placeholder="请输入客户传真(最多30个字符)" allowClear />
+            </a-form-model-item>
+          </a-col>
+          <a-col :span="8">
+            <a-form-model-item label="配送方式" prop="dispatchType">
+              <v-select
+                code="DISPATCH_TYPE"
+                id="customerManagementEdit-dispatchType"
+                v-model="form.dispatchType"
+                allowClear
+                placeholder="请选择配送方式"
+              ></v-select>
+            </a-form-model-item>
+          </a-col>
+          <a-col :span="8">
+            <a-form-model-item label="是否卫星仓客户" prop="satelliteFlag">
+              <span style="padding-left: 11px;">{{ form.satelliteFlag == 1 ? '是' : '否' }}</span>
+            </a-form-model-item>
+          </a-col>
+        </a-row>
+        <a-row :gutter="15">
+          <a-col :span="8">
+            <a-form-model-item label="价格类型" ref="priceType" prop="priceType">
+              <v-select code="PRICE_TYPE" id="customerManagementEdit-priceType" v-model="form.priceType" allowClear placeholder="请选择价格类型" ></v-select>
+            </a-form-model-item>
+          </a-col>
+          <a-col :span="8">
+            <a-form-model-item label="收款方式" prop="settleStyleSn">
+              <a-select id="customerManagementEdit-settleStyleSn" v-model="form.settleStyleSn" allowClear placeholder="请选择收款方式">
+                <a-select-option v-for="item in settleStyleList" :value="item.settleStyleSn" :key="item.settleStyleSn">{{ item.name }}</a-select-option>
+              </a-select>
+            </a-form-model-item>
+          </a-col>
+          <a-col :span="8">
+            <a-form-model-item label="客户类型" prop="customerTypeSn">
+              <a-select id="customerManagementEdit-customerTypeSn" v-model="form.customerTypeSn" allowClear placeholder="请选择客户类型">
+                <a-select-option v-for="item in custTypeList" :value="item.customerTypeSn" :key="item.customerTypeSn">{{ item.name }}</a-select-option>
+              </a-select>
+            </a-form-model-item>
+          </a-col>
+        </a-row>
+        <a-form-model-item :wrapper-col="{ span: 12, offset: 6 }" style="text-align: center;">
+          <a-button type="primary" @click="handleSubmit" size="large" id="customerManagementEdit-btn-submit" style="padding: 0 60px;">保存</a-button>
+        </a-form-model-item>
+      </a-form-model>
+    </a-card>
+  </div>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import { getArea } from '@/api/data'
+import { custSave, custFindById, settleStyleFindAllList } from '@/api/customer'
+import { custTypeFindAllList } from '@/api/custType'
+export default {
+  name: 'CustomerManagementEdit',
+  components: { STable, VSelect },
+  props: {
+    model: {
+      type: String,
+      default: 'page'
+    }
+  },
+  data () {
+    return {
+      formItemLayout: {
+        labelCol: { span: 8 },
+        wrapperCol: { span: 16 }
+      },
+      form: {
+        id: null,
+        customerName: '', // 客户名称
+        contactTel: '', //  联系电话
+        contactName: '', //  联系人
+        provinceSn: undefined, //  省
+        provinceName: '',
+        citySn: undefined, // 市
+        cityName: '',
+        countySn: undefined, // 区
+        countyName: '',
+        customerAddr: '', //  详细地址
+        fax: '', //  客户传真
+        dispatchType: '', //  配送方式
+        satelliteFlag: 0, //  是否卫星仓客户
+        customerTypeSn: undefined, //  客户类型
+        priceType: '', //  价格类型
+        settleStyleSn: undefined //  收款方式
+      },
+      rules: {
+        customerName: [{ required: true, message: '请输入客户名称', trigger: 'blur' }],
+        contactTel: [{ required: true, message: '请输入联系电话', trigger: 'blur' }, { pattern: /^\d{11}$/, message: '请输入正确的手机号' }],
+        provinceSn: [{ required: true, message: '请选择省', trigger: 'change' }],
+        citySn: [{ required: true, message: '请选择市', trigger: 'change' }],
+        countySn: [{ required: true, message: '请选择区/县', trigger: 'change' }],
+        customerAddr: [{ required: true, message: '请输入详细地址', trigger: 'blur' }],
+        priceType: [{ required: true, message: '请选择价格类型', trigger: 'change' }],
+        settleStyleSn: [{ required: true, message: '请选择收款方式', trigger: 'change' }]
+      },
+      addrProvinceList: [], //  省下拉
+      addrCityList: [], //  市下拉
+      addrDistrictList: [], //  区下拉
+      custTypeList: [], //  客户类型  下拉数据
+      settleStyleList: [] //  收款方式  下拉数据
+    }
+  },
+  methods: {
+    filterEmpty () {
+      let str = this.form.customerName
+      str = str.replace(/\ +/g, '')
+      str = str.replace(/[ ]/g, '')
+      str = str.replace(/[\r\n]/g, '')
+      this.form.customerName = str
+    },
+    //  获取客户信息
+    getDetail () {
+      custFindById({ id: this.$route.params.id }).then(res => {
+        if (res.status == 200) {
+          if (res.data.provinceSn) { this.getArea('city', res.data.provinceSn) }
+          if (res.data.citySn) { this.getArea('district', res.data.citySn) }
+          this.form = Object.assign(this.form, res.data)
+        } else {
+          this.$refs.ruleForm.resetFields()
+        }
+      })
+    },
+    //  客户类型
+    getCustTypeList () {
+      custTypeFindAllList().then(res => {
+        if (res.status == 200) {
+          this.custTypeList = res.data
+        } else {
+          this.custTypeList = []
+        }
+      })
+    },
+    // 收款方式
+    getSettleStyleList () {
+      settleStyleFindAllList().then(res => {
+        if (res.status == 200) {
+          this.settleStyleList = res.data
+        } else {
+          this.settleStyleList = []
+        }
+      })
+    },
+    //  保存
+    handleSubmit (e) {
+      e.preventDefault()
+      const _this = this
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          const form = _this.form
+          form.id = this.$route.params.id && this.model == 'page' ? this.$route.params.id : null
+          custSave(form).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              if (_this.model == 'page') {
+                setTimeout(() => {
+                  _this.$router.push({ path: '/customerManagement/customerInfo/list' })
+                }, 600)
+              } else {
+                _this.$emit('ok', res.data)
+              }
+            }
+          })
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    },
+    //  返回列表
+    handleBack () {
+      this.$router.push({ path: '/customerManagement/customerInfo/list' })
+    },
+    // 获取城市列表
+    getCityList (val) {
+      const index = this.addrProvinceList.findIndex(item => item.sn == val)
+      if (index >= 0) {
+        this.form.provinceName = this.addrProvinceList[index].name
+      }
+      this.addrCityList = []
+      this.addrDistrictList = []
+      this.form.citySn = undefined
+      this.form.countySn = undefined
+      this.form.customerAddr = ''
+      this.getArea('city', val)
+    },
+    // 获取区县列表
+    getAreaList (val) {
+      const index = this.addrCityList.findIndex(item => item.sn == val)
+      if (index >= 0) {
+        this.form.cityName = this.addrCityList[index].name
+      }
+      this.addrDistrictList = []
+      this.form.countySn = undefined
+      this.form.customerAddr = ''
+      this.getArea('district', val)
+    },
+    // 区县变更
+    areaCharged (val) {
+      const index = this.addrDistrictList.findIndex(item => item.sn == val)
+      if (index >= 0) {
+        this.form.countyName = this.addrDistrictList[index].name
+      }
+      this.form.customerAddr = ''
+    },
+    //  省/市/区
+    getArea (type, sn) {
+      let params
+      if (type == 'province') {
+        params = { level: '1' }
+      } else {
+        params = { psn: sn }
+      }
+      getArea(params).then(res => {
+        if (res.status == 200) {
+          if (type == 'province') {
+            this.addrProvinceList = res.data || []
+          } else if (type == 'city') {
+            this.addrCityList = res.data || []
+          } else if (type == 'district') {
+            this.addrDistrictList = res.data || []
+          }
+        } else {
+          if (type == 'province') {
+            this.addrProvinceList = []
+          } else if (type == 'city') {
+            this.addrCityList = []
+          } else if (type == 'district') {
+            this.addrDistrictList = []
+          }
+        }
+      })
+    },
+    // 获取基础数据
+    getBaseData () {
+      this.getArea('province') //  省市区
+      this.getCustTypeList() //  客户类型
+      this.getSettleStyleList() // 收款方式
+      this.$refs.ruleForm.resetFields()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      vm.getBaseData()
+      if (vm.$route.params.id) {
+        //  编辑页
+        vm.getDetail()
+      }
+    })
+  }
+}
+</script>
+
+<style lang="less">
+.customerManagementEdit-wrap {
+	.customerManagementEdit-back {
+		margin-bottom: 15px;
+	}
+}
+</style>

+ 344 - 114
src/views/salesManagement/salesQuery/chooseCustomModal.vue

@@ -1,7 +1,7 @@
 <template>
   <a-modal
     v-model="opened"
-    title="选择客户"
+    :title="title"
     centered
     :maskClosable="false"
     :confirmLoading="confirmLoading"
@@ -19,18 +19,22 @@
     >
       <a-row :gutter="15">
         <a-col :span="8">
-          <a-form-model-item label="客户名称" prop="name">
-            <a-input
-              id="chooseCustom-name"
-              :maxLength="30"
-              v-model="form.name"
-              placeholder="请输入客户名称(最多30个字符)"
-              allowClear />
+          <a-form-model-item label="客户名称" prop="buyerSn">
+            <a-select
+              id="chooseCustom-buyerSn"
+              show-search
+              placeholder="请选择客户"
+              v-model="form.buyerSn"
+              :filter-option="filterOption"
+              @change="custChange">
+              <a-select-option v-for="item in custAllList" :key="item.id" :value="item.customerSn">{{ item.customerName }}</a-select-option>
+            </a-select>
           </a-form-model-item>
         </a-col>
-        <a-col :span="8">
+        <a-col :span="16">
           <a-form-model-item>
-            (未搜索到客户时为新增客户)
+            <a-button type="primary" class="button-primary" @click="openNewCust" icon="plus">新增</a-button>
+            (点击新增按钮新增客户)
           </a-form-model-item>
         </a-col>
       </a-row>
@@ -40,22 +44,22 @@
             <a-row :gutter="15">
               <!-- 客户地址 -->
               <a-col span="8">
-                <a-form-model-item prop="provinceCode">
-                  <a-select id="chooseCustom-provinceCode" @change="getCityList" v-model="form.provinceCode" placeholder="请选择省">
+                <a-form-model-item prop="shippingAddressProvinceSn">
+                  <a-select id="chooseCustom-provinceSn" @change="getCityList" v-model="form.shippingAddressProvinceSn" placeholder="请选择省">
                     <a-select-option v-for="item in addrProvinceList" :value="item.id" :key="item.id + 'a'">{{ item.name }}</a-select-option>
                   </a-select>
                 </a-form-model-item>
               </a-col>
               <a-col span="8">
-                <a-form-model-item prop="cityCode">
-                  <a-select id="chooseCustom-cityCode" @change="getAreaList" v-model="form.cityCode" placeholder="请选择市">
+                <a-form-model-item prop="shippingAddressCitySn">
+                  <a-select id="chooseCustom-citySn" @change="getAreaList" v-model="form.shippingAddressCitySn" placeholder="请选择市">
                     <a-select-option v-for="item in addrCityList" :value="item.id" :key="item.id + 'b'">{{ item.name }}</a-select-option>
                   </a-select>
                 </a-form-model-item>
               </a-col>
               <a-col span="8">
-                <a-form-model-item prop="districtCode">
-                  <a-select id="chooseCustom-districtCode" @change="areaCharged" v-model="form.districtCode" placeholder="请选择区/县">
+                <a-form-model-item prop="shippingAddressCountySn">
+                  <a-select id="chooseCustom-countySn" @change="areaCharged" v-model="form.shippingAddressCountySn" placeholder="请选择区/县">
                     <a-select-option v-for="item in addrDistrictList" :value="item.id" :key="item.id + 'c'">{{ item.name }}</a-select-option>
                   </a-select>
                 </a-form-model-item>
@@ -64,11 +68,11 @@
           </a-form-model-item>
         </a-col>
         <a-col :span="8">
-          <a-form-model-item prop="address">
+          <a-form-model-item label="" prop="shippingAddress">
             <a-input
-              id="chooseCustom-address"
+              id="chooseCustom-shippingAddress"
               :maxLength="60"
-              v-model="form.address"
+              v-model="form.shippingAddress"
               placeholder="请输入详细地址(最多60个字符)"
               allowClear />
           </a-form-model-item>
@@ -76,22 +80,22 @@
       </a-row>
       <a-row :gutter="15">
         <a-col :span="8">
-          <a-form-model-item label="联系人" prop="contacts">
+          <a-form-model-item label="联系人" prop="consigneeName">
             <a-input
-              id="chooseCustom-contacts"
+              id="chooseCustom-consigneeName"
               :maxLength="30"
-              v-model="form.contacts"
+              v-model="form.consigneeName"
               placeholder="请输入联系人(最多30个字符)"
               allowClear />
           </a-form-model-item>
         </a-col>
         <a-col :span="8">
-          <a-form-model-item label="客户电话" prop="customerPhone">
+          <a-form-model-item label="联系电话" prop="consigneeTel">
             <a-input
-              id="chooseCustom-customerPhone"
+              id="chooseCustom-consigneeTel"
               :maxLength="11"
-              v-model="form.customerPhone"
-              placeholder="请输入客户电话(最多11个字符)"
+              v-model="form.consigneeTel"
+              placeholder="请输入联系电话(最多11个字符)"
               allowClear />
           </a-form-model-item>
         </a-col>
@@ -101,64 +105,62 @@
           <a-form-model-item label="价格类型" prop="priceType">
             <a-row :gutter="15">
               <a-col :span="20">
-                <a-select id="chooseCustom-priceType" v-model="form.priceType" placeholder="请选择价格类型">
-                  <a-select-option v-for="item in addrDistrictList" :value="item.id" :key="item.id + 'c'">{{ item.name }}</a-select-option>
-                </a-select>
+                <v-select
+                  code="PRICE_TYPE"
+                  :disabled="priceTypeDisabled"
+                  id="chooseCustom-priceType"
+                  v-model="form.priceType"
+                  allowClear
+                  placeholder="请选择价格类型" ></v-select>
               </a-col>
               <a-col :span="4">
                 <a-popover>
-                  <template slot="content">
-                    (选择后在当前工单不可修改)
-                  </template>
+                  <template slot="content">(选择后在当前工单不可修改)</template>
                   <a-icon type="question-circle" />
                 </a-popover>
               </a-col>
             </a-row>
           </a-form-model-item>
         </a-col>
-        <a-col :span="8">
+        <!-- <a-col :span="8">
           <a-form-model-item label="支付方式" prop="payType">
-            <a-select id="chooseCustom-payType" v-model="form.payType" placeholder="请选择支付方式">
-              <a-select-option v-for="item in addrDistrictList" :value="item.id" :key="item.id + 'c'">{{ item.name }}</a-select-option>
-            </a-select>
+            <v-select code="PAY_TYPE" id="chooseCustom-payType" v-model="form.payType" allowClear placeholder="请选择支付方式" />
           </a-form-model-item>
-        </a-col>
+        </a-col> -->
         <a-col :span="8">
-          <a-form-model-item label="收款方式" prop="payment">
-            <a-select id="chooseCustom-payment" v-model="form.payment" placeholder="请选择收款方式">
-              <a-select-option v-for="item in addrDistrictList" :value="item.id" :key="item.id + 'c'">{{ item.name }}</a-select-option>
+          <a-form-model-item label="收款方式" prop="settleStyleSn">
+            <a-select placeholder="请选择收款方式" v-model="form.settleStyleSn">
+              <a-select-option v-for="item in settleStyleList" :key="item.settleStyleSn" :value="item.settleStyleSn">
+                {{ item.name }}
+              </a-select-option>
             </a-select>
           </a-form-model-item>
         </a-col>
-      </a-row>
-      <a-row :gutter="15">
         <a-col :span="8">
-          <a-form-model-item label="配送方式" prop="shipping">
-            <a-select id="chooseCustom-shipping" v-model="form.shippingCode" placeholder="请选择配送方式">
-              <a-select-option v-for="item in addrDistrictList" :value="item.id" :key="item.id + 'c'">{{ item.name }}</a-select-option>
-            </a-select>
+          <a-form-model-item label="配送方式" prop="dispatchType">
+            <v-select code="DISPATCH_TYPE" id="chooseCustom-dispatchType" v-model="form.dispatchType" allowClear placeholder="请选择配送方式"></v-select>
           </a-form-model-item>
         </a-col>
+      </a-row>
+      <a-row :gutter="15">
         <a-col :span="8">
-          <a-form-model-item label="业务员" prop="salesman">
-            <a-select id="chooseCustom-salesman" v-model="form.salesman" placeholder="请选择业务员">
-              <a-select-option v-for="item in addrDistrictList" :value="item.id" :key="item.id + 'c'">{{ item.name }}</a-select-option>
+          <a-form-model-item label="业务员" prop="salesManSn">
+            <a-select id="chooseCustom-salesManSn" @change="salesManChange" v-model="form.salesManSn" placeholder="请选择业务员">
+              <a-select-option v-for="item in userList" :value="item.id" :key="item.id + 'c'">{{ item.name }}</a-select-option>
             </a-select>
           </a-form-model-item>
         </a-col>
         <a-col :span="8">
-          <a-form-model-item label="铺货出库" prop="salesman">
-            <a-select id="chooseCustom-salesman" v-model="form.salesman" placeholder="请选择是否铺货出库">
-              <a-select-option v-for="item in addrDistrictList" :value="item.id" :key="item.id + 'c'">{{ item.name }}</a-select-option>
-            </a-select>
+          <a-form-model-item label="铺货出库" prop="distributionFlag">
+            <v-select code="FLAG" id="chooseCustom-distributionFlag" v-model="form.distributionFlag" allowClear placeholder="请选择"></v-select>
           </a-form-model-item>
         </a-col>
       </a-row>
       <a-row :gutter="15">
         <a-col :span="8">
-          <a-form-model-item label="备注" prop="remark">
+          <a-form-model-item label="备注" prop="remarks">
             <a-input
-              id="chooseCustom-remark"
+              id="chooseCustom-remarks"
               type="textarea"
               :maxLength="100"
               v-model="form.remarks"
@@ -167,9 +169,7 @@
           </a-form-model-item>
         </a-col>
         <a-col :span="8">
-          <a-form-model-item label="开单人">
-            王明
-          </a-form-model-item>
+          <a-form-model-item label="开单人">{{ $store.state.user.info.userNameCN }}</a-form-model-item>
         </a-col>
       </a-row>
       <a-form-model-item :wrapper-col="{ span: 12, offset: 6 }" style="text-align: center;">
@@ -177,125 +177,339 @@
         <a-button @click="cancel" style="margin-left: 15px" id="chooseCustom-btn-back">取消</a-button>
       </a-form-model-item>
     </a-form-model>
+    <!-- 新增客户 -->
+    <a-modal
+      v-model="isNewCust"
+      title="新增客户"
+      centered
+      width="60%"
+      :maskClosable="false"
+      @cancel="cancelNewCust"
+      :footer="null"
+    >
+      <CustomerManagementEdit ref="newCust" model="modal" @ok="newCustFun"></CustomerManagementEdit>
+    </a-modal>
   </a-modal>
 </template>
 
 <script>
 import { getArea } from '@/api/data'
+import { custAllList, custFindById, custSave, updateByCustomerSn } from '@/api/customer'
+import { salesSave } from '@/api/sales'
+import { getUserAllList } from '@/api/power-user'
+import { settleStyleQueryAll } from '@/api/settleStyle'
+import { VSelect } from '@/components'
+import CustomerManagementEdit from '@/views/customerManagement/customerInfo/edit.vue'
 export default {
   name: 'ChooseCustomModal',
+  components: { VSelect, CustomerManagementEdit },
   props: {
     show: [Boolean]
   },
   data () {
     return {
       opened: this.show,
+      title: '选择客户',
       confirmLoading: false,
       formItemLayout: {
         labelCol: { span: 8 },
         wrapperCol: { span: 16 }
       },
+      buyerSnBak: '', // 更改前客户sn备份
+      priceTypeBak: '', // 更改前客户价格类型备份
       form: {
-        name: '', // 客户名称
-        provinceCode: undefined, //  省
-        provinceName: '',
-        cityCode: undefined, // 市
-        cityName: '',
-        districtCode: undefined, // 区
-        districtName: '',
-        address: '', //  详细地址
-        contactName: '', //  联系人
-        contactPhone: '', //  联系电话
-        remarks: '', //  备注
+        buyerName: '', // 客户名称
+        buyerSn: undefined, // 客户sn
+        consigneeTel: '', //  联系电话
+        consigneeName: '', //  联系人
+        shippingAddressProvinceSn: undefined, //  省
+        shippingAddressProvinceName: '',
+        shippingAddressCitySn: undefined, // 市
+        shippingAddressCityName: '',
+        shippingAddressCountySn: undefined, // 区
+        shippingAddressCountyName: '',
+        shippingAddress: '', //  详细地址
+        fax: '', //  客户传真
+        dispatchType: undefined, //  配送方式
+        satelliteFlag: 0, //  是否卫星仓客户
         priceType: undefined, //  价格类型
-        payType: undefined, // 支付方式
-        payment: undefined // 收款方式
+        settleStyleSn: '', //  收款方式
+        salesManSn: undefined, //  业务员
+        salesManName: '',
+        distributionFlag: '0', // 铺货出库
+        salesTragetType: 'C',
+        remarks: '' //  备注
       },
       rules: {
-        name: [
-          { required: true, message: '请输入客户名称', trigger: 'blur' }
+        buyerSn: [
+          { required: true, message: '请选择客户', trigger: ['change', 'blur'] }
         ],
-        provinceCode: [
+        consigneeTel: [{ required: true, message: '请输入联系电话', trigger: 'blur' }, { pattern: /^\d{11}$/, message: '请输入正确的手机号' }],
+        shippingAddressProvinceSn: [
           { required: true, message: '请选择省', trigger: 'change' }
         ],
-        cityCode: [
+        shippingAddressCitySn: [
           { required: true, message: '请选择市', trigger: 'change' }
         ],
-        districtCode: [
+        shippingAddressCountySn: [
           { required: true, message: '请选择区/县', trigger: 'change' }
         ],
-        address: [
+        shippingAddress: [
           { required: true, message: '请输入详细地址', trigger: 'blur' }
         ],
-        contactName: [
-          { required: true, message: '请输入联系人', trigger: 'blur' }
-        ],
-        contactPhone: [
-          { required: true, message: '请输入联系人电话', trigger: 'blur' }
-        ],
         priceType: [
-          { required: true, message: '请选择价格类型', trigger: 'change' }
+          { required: true, message: '请选择价格类型', trigger: ['change', 'blur'] }
         ],
-        payType: [
-          { required: true, message: '请选择支付方式', trigger: 'change' }
+        settleStyleSn: [
+          { required: true, message: '请选择收款方式', trigger: ['change', 'blur'] }
         ],
-        payment: [
-          { required: true, message: '请选择收款方式', trigger: 'change' }
+        distributionFlag: [
+          { required: true, message: '请选择是否铺货出库', trigger: 'change' }
         ]
+        // salesManSn: [
+        //   { required: true, message: '请选择业务员', trigger: 'change' }
+        // ]
       },
+      custAllList: [], //  客户 下拉数据
       addrProvinceList: [], //  省下拉
       addrCityList: [], //  市下拉
-      addrDistrictList: [] //  区下拉
+      addrDistrictList: [], //  区下拉
+      userList: [], // 业务员 下拉
+      settleStyleList: [], // 收款方式
+      custId: undefined, // 客户id
+      isEdit: false, //  是否编辑状态
+      priceTypeDisabled: false, // 价格类型可编辑
+      isChangeCust: false, // 是否更换客户
+      interId: null,
+      isNewCust: false // 是否新增客户
     }
   },
   methods: {
+    openNewCust () {
+      this.isNewCust = true
+      setTimeout(() => {
+        this.$refs.newCust.getBaseData()
+      }, 500)
+    },
+    // 新建客户
+    newCustFun (data) {
+      console.log(data, this.isEdit)
+      this.isNewCust = false
+      // 更新客户信息
+      this.custAllList.unshift(data)
+      setTimeout(() => {
+        this.custChange(data.customerSn)
+      }, 300)
+    },
+    // 业务员
+    salesManChange (id) {
+      this.form.salesManName = this.userList.find(item => item.id == id).name
+    },
+    // 客户 change
+    custChange (val) {
+      console.log(val, 'custChange')
+      const _this = this
+      const cust = this.custAllList.find(item => item.customerSn == val)
+      // 编辑
+      if (this.isEdit) {
+        this.$confirm({
+          title: '提示',
+          content: '更换客户后信息需要重新完善,确认要更换吗?',
+          centered: true,
+          onOk () {
+            _this.custId = cust.id
+            _this.form.buyerName = cust.customerName
+            _this.priceTypeDisabled = false
+            _this.getDetail()
+          },
+          onCancel () {
+            _this.form.buyerSn = _this.buyerSnBak
+          }
+        })
+      } else {
+        _this.custId = cust.id
+        _this.form.buyerName = cust.customerName
+        _this.getDetail()
+      }
+    },
+    // 编辑客户信息
+    editCust (data) {
+      console.log(data)
+      this.title = '编辑客户信息'
+      this.isEdit = true
+      this.priceTypeDisabled = true
+      if (data.shippingAddressProvinceSn) { this.getArea('city', data.shippingAddressProvinceSn) }
+      if (data.shippingAddressCitySn) { this.getArea('district', data.shippingAddressCitySn) }
+      this.form = Object.assign(this.form, data)
+      this.buyerSnBak = this.form.buyerSn
+      this.priceTypeBak = this.form.priceType
+    },
+    //  获取详情
+    getDetail () {
+      custFindById({ id: this.custId }).then(res => {
+        const data = res.data
+        if (res.status == 200 && data) {
+          if (data.provinceSn) { this.getArea('city', data.provinceSn) }
+          if (data.citySn) { this.getArea('district', data.citySn) }
+          this.form = Object.assign(this.form, {
+            buyerName: data.customerName, // 客户名称
+            buyerSn: data.customerSn, // 客户sn
+            consigneeTel: data.contactTel, //  联系电话
+            consigneeName: data.contactName, //  联系人
+            shippingAddressProvinceSn: data.provinceSn, //  省
+            shippingAddressProvinceName: data.provinceName,
+            shippingAddressCitySn: data.citySn, // 市
+            shippingAddressCityName: data.cityName,
+            shippingAddressCountySn: data.countySn, // 区
+            shippingAddressCountyName: data.countyName,
+            shippingAddress: data.customerAddr, //  详细地址
+            fax: data.fax, //  客户传真
+            dispatchType: data.dispatchType, //  配送方式
+            satelliteFlag: data.satelliteFlag, //  是否卫星仓客户
+            priceType: data.priceType, //  价格类型
+            settleStyleSn: data.settleStyleSn //  收款方式
+          })
+          // this.buyerSnBak = this.form.buyerSn
+          // this.priceTypeBak = this.form.priceType
+        } else {
+          this.$message.error('获取客户信息失败')
+          this.$refs.ruleForm.resetFields()
+        }
+        this.$refs.ruleForm.clearValidate()
+      })
+    },
+    // 保存客户信息
+    handleSaveCust () {
+      const params = {
+        customerName: this.form.buyerName,
+        customerSn: this.form.buyerSn,
+        contactTel: this.form.consigneeTel, //  联系电话
+        contactName: this.form.consigneeName, //  联系人
+        provinceSn: this.form.shippingAddressProvinceSn, //  省
+        provinceName: this.form.shippingAddressProvinceName,
+        citySn: this.form.shippingAddressCitySn, // 市
+        cityName: this.form.shippingAddressCityName,
+        countySn: this.form.shippingAddressCountySn, // 区
+        countyName: this.form.shippingAddressCountyName,
+        customerAddr: this.form.shippingAddress, //  详细地址
+        dispatchType: this.form.dispatchType, //  配送方式
+        priceType: this.form.priceType, //  价格类型
+        settleStyleSn: this.form.settleStyleSn //  收款方式
+      }
+      updateByCustomerSn(params).then(res => {
+        if (res.status != 200) {
+          this.$message.error(res.message)
+        }
+      })
+    },
     //  保存
     handleSubmit (e) {
       e.preventDefault()
       const _this = this
-      this.$emit('ok', { id: 1000, customName: '车领主常青二路店' })
-      this.cancel()
-      // this.$refs.ruleForm.validate(valid => {
-      //   if (valid) {
-      //     const form = values.form
-      //     form.desc = _this.form.desc
-      //     form.id = this.isEdit ? this.$route.params.id : null
-      //     console.log(form,'-----提交信息')
-      //     // goodsSave(form).then(res => {
-      //     //   if (res.status == 200) {
-      //     //     _this.$message.success(res.message)
-      //     //   }
-      //     // })
-      //   } else {
-      //     console.log('error submit!!')
-      //     return false
-      //   }
-      // })
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          console.log(_this.priceTypeBak, _this.form.priceType)
+          // 如果价格类型改变,提示
+          if (_this.priceTypeBak != _this.form.priceType && this.isEdit) {
+            this.$confirm({
+              title: '提示',
+              content: '价格类型变更,确认提交吗?',
+              centered: true,
+              onOk () {
+                // 保存客户信息
+                _this.handleSaveCust()
+                // 保存销售单
+                if (_this.form.buyerSn) {
+                  _this.salesSaveFun()
+                }
+              }
+            })
+          } else {
+            // 保存客户信息
+            _this.handleSaveCust()
+            // 保存销售单
+            if (_this.form.buyerSn) {
+              _this.salesSaveFun()
+            }
+          }
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    },
+    // 新建或编辑销售单
+    salesSaveFun () {
+      const _this = this
+      const form = this.form
+      console.log(form, 'save data')
+      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', form.priceType)
+          }
+          _this.cancel()
+        }
+      })
     },
     cancel () {
       this.opened = false
-      this.$refs.ruleForm.resetFields()
       this.$emit('cancel')
+      this.$refs.ruleForm.resetFields()
+    },
+    cancelNewCust () {
+      this.isNewCust = false
+      this.$refs.newCust.getBaseData()
+    },
+    // 客户无分页列表数据
+    getCustAllList () {
+      const _this = this
+      custAllList().then(res => {
+        if (res.status == 200) {
+          _this.custAllList = res.data || []
+        } else {
+          _this.custAllList = []
+        }
+      })
+    },
+    // 获取业务员列表数据
+    getUserAllList () {
+      getUserAllList({ loginFlag: 1 }).then(res => {
+        if (res.status == 200) {
+          this.userList = res.data || []
+        } else {
+          this.userList = []
+        }
+      })
     },
     // 获取城市列表
     getCityList (val) {
+      console.log(val, '-------------')
       this.addrCityList = []
       this.addrDistrictList = []
-      this.form.cityCode = undefined
-      this.form.districtCode = undefined
-      this.form.address = ''
+      this.form.shippingAddressCitySn = undefined
+      this.form.shippingAddressCityName = ''
+      this.form.shippingAddressCountySn = undefined
+      this.form.shippingAddressCountyName = ''
+      this.form.shippingAddress = ''
+      this.form.shippingAddressCountyName = this.addrProvinceList.find(item => item.id == val).name
       this.getArea('city', val)
     },
     // 获取区县列表
     getAreaList (val) {
       this.addrDistrictList = []
-      this.form.districtCode = undefined
-      this.form.address = ''
+      this.form.shippingAddressCountySn = undefined
+      this.form.shippingAddressCountyName = ''
+      this.form.shippingAddress = ''
+      this.form.shippingAddressCityName = this.addrCityList.find(item => item.id == val).name
       this.getArea('district', val)
     },
     // 区县变更
     areaCharged (val) {
-      this.form.address = ''
+      this.form.shippingAddress = ''
+      this.form.shippingAddressCountyName = this.addrDistrictList.find(item => item.id == val).name
     },
     //  省/市/区
     getArea (type, sn) {
@@ -324,6 +538,19 @@ export default {
           }
         }
       })
+    },
+    filterOption (input, option) {
+      return (
+        option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
+      )
+    },
+    // 获取收款方式
+    getSettleStyle () {
+      settleStyleQueryAll().then(res => {
+        if (res.status == 200) {
+          this.settleStyleList = res.data
+        }
+      })
     }
   },
   watch: {
@@ -331,6 +558,9 @@ export default {
       this.opened = newValue
       if (newValue) {
         this.getArea('province')
+        this.getCustAllList()
+        this.getUserAllList()
+        this.getSettleStyle()
       }
     }
   }

+ 37 - 18
src/views/salesManagement/salesQuery/detail.vue

@@ -1,8 +1,8 @@
 <template>
   <div class="salesDetail-wrap">
-    <a-page-header :ghost="false" @back="handleBack" class="salesDetail-cont">
+    <a-page-header :ghost="false" :backIcon="false" class="salesDetail-cont">
       <template slot="subTitle">
-        <a href="javascript:;" @click="handleBack">返回列表</a>
+        <a href="javascript:;" @click="handleBack"><a-icon type="left"></a-icon> 返回列表</a>
       </template>
       <template slot="extra">
         <span>打印字段:</span>
@@ -25,15 +25,14 @@
           <a-descriptions size="small" :column="3" v-if="detailData">
             <a-descriptions-item label="客户名称">{{ detailData.buyerName || '--' }}</a-descriptions-item>
             <a-descriptions-item label="客户地址">{{ detailData.shippingAddressProvinceName || '--' }}{{ detailData.shippingAddressCityName || '--' }}{{ detailData.shippingAddressCountyName || '--' }}{{ detailData.shippingAddress || '--' }}</a-descriptions-item>
-            <a-descriptions-item label="支付方式">{{ detailData.payType || '--' }}</a-descriptions-item>
-            <a-descriptions-item label="收款方式">{{ detailData.settleStyleSn || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="收款方式">{{ detailData.settleStyleEntity.name || '--' }}</a-descriptions-item>
             <a-descriptions-item label="联系电话">{{ detailData.consigneeTel || '--' }}</a-descriptions-item>
-            <a-descriptions-item label="备注">{{ detailData.buyerName || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="备注">{{ detailData.remarks || '--' }}</a-descriptions-item>
             <a-descriptions-item label="销售单号">{{ detailData.salesBillNo || '--' }}</a-descriptions-item>
             <a-descriptions-item label="制单人">{{ detailData.operatorName || '--' }}</a-descriptions-item>
             <a-descriptions-item label="业务员">{{ detailData.salesManName || '--' }}</a-descriptions-item>
-            <a-descriptions-item label="业务状态">{{ detailData.auditStatus || '--' }}</a-descriptions-item>
-            <a-descriptions-item label="财务状态">{{ detailData.financialStatus || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="业务状态">{{ detailData.billStatusDictValue || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="财务状态">{{ detailData.financialStatusDictValue || '--' }}</a-descriptions-item>
           </a-descriptions>
         </a-collapse-panel>
       </a-collapse>
@@ -42,7 +41,7 @@
       <!-- alert -->
       <a-alert type="info" style="margin-bottom: 15px;" v-if="detailData">
         <div slot="message">
-          总款数:<strong>{{ detailData.totalCategory || 0 }}</strong>;总数量:<strong>{{ detailData.totalQty || 0 }}</strong>;总赠品数量:<strong>{{ detailData.totalGiftNum || 0 }}</strong>;急件总款数:<strong>{{ detailData.urgentTotalCategory || 0 }}</strong>;急件总数量:<strong>{{ detailData.urgentTotalQty || 0 }}</strong>;<br/>
+          总款数:<strong>{{ detailData.totalCategory || 0 }}</strong>;总数量:<strong>{{ detailData.totalQty || 0 }}</strong>;总赠品数量:<strong>{{ detailData.giftQty || 0 }}</strong>;急件总款数:<strong>{{ detailData.oosCategory || 0 }}</strong>;急件总数量:<strong>{{ detailData.oosQty || 0 }}</strong>;<br/>
           总售价:<strong>{{ detailData.totalAmount || 0 }}</strong>;总成本:<strong>{{ detailData.totalCost || 0 }}</strong>;总毛利:<strong>{{ detailData.grossProfit || 0 }}</strong>;折后总售价:<strong>{{ detailData.discountedAmount || 0 }}</strong>;折扣:<strong>{{ detailData.discountRate || 0 }}%</strong>;折扣金额:<strong>{{ detailData.discountAmount || 0 }}</strong>;
         </div>
       </a-alert>
@@ -58,13 +57,23 @@
         bordered>
       </s-table>
     </a-card>
+    <a-card size="small" :bordered="false" class="footer-cont">
+      <a-button
+        type="primary"
+        class="button-info"
+        size="large"
+        style="width: 150px;"
+        v-if="detailData&&detailData.billStatus !== 'CANCEL' && detailData.billStatus !== 'FINISH' && detailData.billStatus != 'WAIT_OUT_WAREHOUSE'"
+        @click="handleEdit()"
+        id="salesDetail-edit-btn">编辑</a-button>
+    </a-card>
   </div>
 </template>
 
 <script>
 import { getOperationalPrecision } from '@/libs/tools.js'
 import { STable, VSelect } from '@/components'
-import { salesDetail } from '@/api/sales'
+import { salesDetailBySn } from '@/api/sales'
 import { salesDetailList } from '@/api/salesDetail'
 export default {
   name: 'SalesDetail',
@@ -88,17 +97,17 @@ export default {
         { title: '产品编码', dataIndex: 'productCode', width: 140, align: 'center' },
         { title: '产品名称', dataIndex: 'productName', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
         { title: '原厂编码', dataIndex: 'productOrigCode', width: 140, align: 'center', customRender: function (text) { return text || '--' } },
-        { title: '成本价', dataIndex: 'costPrice', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
-        { title: '售价', dataIndex: 'price', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
-        { title: '折后售价', dataIndex: 'discountedPrice', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '成本价', dataIndex: 'cost', width: 100, align: 'center', customRender: function (text) { return '¥' + (text || 0) } },
+        { title: '售价', dataIndex: 'price', width: 100, align: 'center', customRender: function (text) { return '¥' + (text || 0) } },
+        { title: '折后售价', dataIndex: 'discountedPrice', width: 100, align: 'center', customRender: function (text) { return '¥' + (text || 0) } },
         { title: '销售数量', dataIndex: 'qty', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
         { title: '单位', dataIndex: 'productOrigUnit', width: 100, align: 'center', customRender: function (text) { return text || '--' } },
-        { title: '售价小计', dataIndex: 'salePriceSubtotal', width: 100, align: 'center' },
-        { title: '折后小计', dataIndex: 'discountedAmount', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
-        { title: '折扣金额', dataIndex: 'discountAmount', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '售价小计', dataIndex: 'totalAmount', width: 100, align: 'center', customRender: function (text) { return '¥' + (text || 0) } },
+        { title: '折后小计', dataIndex: 'discountedAmount', width: 100, align: 'center', customRender: function (text) { return '¥' + (text || 0) } },
+        { title: '折扣金额', dataIndex: 'discountAmount', width: 100, align: 'center', customRender: function (text) { return '¥' + (text || 0) } },
         { title: '仓库', dataIndex: 'warehouseName', width: 100, align: 'center' },
         { title: '仓位', dataIndex: 'warehouseLocationName', width: 100, align: 'center' },
-        { title: '销售类型', dataIndex: 'salesBillType', width: 100, align: 'center', customRender: function (text) { return text || '--' } }
+        { title: '是否急件', dataIndex: 'oosFlagDictValue', width: 100, align: 'center', customRender: function (text) { return text || '--' } }
       ],
       // 加载数据方法 必须为 Promise 对象
       loadData: parameter => {
@@ -131,11 +140,17 @@ export default {
   methods: {
     //  返回
     handleBack () {
-      this.$router.push({ path: '/salesManagement/salesQuery/list' })
+      // this.$router.push({ name: 'salesQueryList' })
+      this.$router.back()
+    },
+    // 编辑
+    handleEdit () {
+      const row = this.detailData
+      this.$router.push({ name: 'salesEdit', params: { id: row.id, sn: row.salesBillSn, priceType: row.priceType } })
     },
     //  详情
     getDetail () {
-      salesDetail({ id: this.$route.params.id }).then(res => {
+      salesDetailBySn({ salesBillSn: this.$route.params.sn }).then(res => {
         if (res.status == 200) {
           this.detailData = res.data
         } else {
@@ -155,5 +170,9 @@ export default {
     .salesDetail-cont{
       margin-bottom: 15px;
     }
+    .footer-cont{
+      margin-top: 5px;
+      text-align: center;
+    }
   }
 </style>

+ 333 - 85
src/views/salesManagement/salesQuery/edit.vue

@@ -1,10 +1,11 @@
 <template>
   <div class="salesEdit-wrap">
-    <a-page-header :ghost="false" @back="handleBack" >
+    <a-page-header :ghost="false" :backIcon="false" @back="handleBack" >
       <!-- 自定义的二级文字标题 -->
       <template slot="subTitle">
-        <a id="salesEdit-back-btn" href="javascript:;" @click="handleBack">客户名称:车领主常青二路店</a>
-        <a-button id="salesEdit-edit-btn" size="small" @click="handleEdit" style="margin-left:50px" key="0">编辑</a-button>
+        <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>
+        <!-- <a-button id="salesEdit-edit-btn" size="small" @click="handleEdit" style="margin-left:10px" key="0">编辑</a-button> -->
       </template>
       <!-- 操作区,位于 title 行的行尾 -->
       <template slot="extra">
@@ -14,33 +15,57 @@
     </a-page-header>
     <a-card size="small" :bordered="false" class="salesEdit-cont">
       <!-- 查询配件列表 -->
-      <queryPart></queryPart>
+      <queryPart ref="partQuery" :buyerSn="detailData&&detailData.buyerSn" :priceType="$route.params.priceType" :newLoading="isInster" @add="insterProduct"></queryPart>
     </a-card>
     <a-card size="small" :bordered="false" class="salesEdit-cont">
       <!-- 总计 -->
       <a-alert style="margin-bottom: 15px;" type="info">
-        <div slot="message">总售价:<strong>6</strong>;总款数:<strong>6</strong>;总数量:<strong>6</strong>;赠品总数量:<strong>6</strong>;</div>
+        <div slot="message" class="total-bar">
+          <div>
+            总售价:<strong>¥{{ detailData&&detailData.totalAmount || 0 }}</strong>;
+            总款数:<strong>{{ detailData&&detailData.totalCategory || 0 }}</strong>;
+            总数量:<strong>{{ detailData&&detailData.totalQty || 0 }}</strong>;
+            赠品总数量:<strong>{{ detailData&&detailData.giftQty || 0 }}</strong>;
+          </div>
+          <div>
+            <div>
+              折扣金额:
+              <a-input-number id="discount" v-model="detailData.discountAmount" :min="0" :precision="2" :max="999999"/>
+              <a-button type="primary" @click="salesDiscount" class="button-info">打折</a-button>
+            </div>
+            <div>
+              折扣:<strong>{{ detailData&&detailData.discountRate || 0 }}%</strong>;
+              折后总售价:<strong>¥{{ detailData&&detailData.discountedAmount || 0 }}</strong>;
+            </div>
+          </div>
+        </div>
       </a-alert>
       <!-- 查询条件 -->
       <a-row :gutter="15">
         <a-col :span="18">
-          <a-form-model layout="inline" :model="productForm" @submit="handleSearch">
+          <a-form-model layout="inline" :model="productForm">
             <a-form-model-item label="产品编码">
-              <a-input v-model="productForm.productNo" placeholder="输入产品编码" />
+              <a-input v-model="productForm.productCode" allowClear placeholder="输入产品编码" />
             </a-form-model-item>
             <a-form-model-item label="产品名称">
-              <a-input v-model="productForm.productName" placeholder="输入产品名称" />
+              <a-input v-model="productForm.productName" allowClear placeholder="输入产品名称" />
             </a-form-model-item>
             <a-form-model-item>
               <a-button style="margin-bottom: 18px;" type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="salesEdit-refresh">查询</a-button>
-              <a-button style="margin: 0 0 18px 8px" @click="resetSearchForm" :disabled="disabled" id="salesEdit-reset">重置</a-button>
+              <a-button style="margin: 0 0 18px 8px" @click="resetForm" id="salesEdit-reset">重置</a-button>
             </a-form-model-item>
           </a-form-model>
         </a-col>
         <a-col :span="6">
           <div style="float:right;overflow: hidden;">
             <a-button size="small" id="salesEdit-dru">导入明细</a-button>
-            <a-button size="small" type="primary" style="margin-left: 10px" id="salesEdit-del-all">整单删除</a-button>
+            <a-button
+              size="small"
+              type="primary"
+              @click="delSalerDetailAll"
+              :loading="delLoading"
+              style="margin-left: 10px"
+              id="salesEdit-del-all">整单删除</a-button>
           </div>
         </a-col>
       </a-row>
@@ -48,36 +73,69 @@
       <s-table
         class="sTable"
         ref="table"
-        size="default"
+        size="small"
         :rowKey="(record) => record.id"
         :columns="columns"
         :data="loadData"
-        :scroll="{ x: 1560 }"
+        :scroll="{ x: 1560, y: 300 }"
+        :rowClassName="(record, index) => record.cost > record.price ? 'redBg-row':''"
         bordered>
+        <!-- 产品编码 -->
+        <template slot="productCode" slot-scope="text, record">
+          <a-badge count="急" v-if="record.oosFlag == 1">
+            <div style="padding-right: 15px;">{{ text }}</div>
+          </a-badge>
+          <span v-else>{{ text }}</span>
+        </template>
         <!-- 售价 -->
         <template slot="price" slot-scope="text, record">
-          <a-input-number
+          <editable-cell
+            size="small"
+            :text="text"
             id="salesEdit-price"
-            :value="record.price"
-            :precision="0"
-            :min="0"
             :max="999999"
-            placeholder="请输入" />
+            :min="0"
+            :precision="2"
+            punit="¥"
+            @change="onCellChange(record.id, 'price', $event)" />
         </template>
         <!-- 销售数量 -->
         <template slot="salesNums" slot-scope="text, record">
-          <a-input-number
+          <editable-cell
+            size="small"
+            :text="record.qty"
             id="salesEdit-salesNums"
-            :value="record.salesNums"
-            :precision="0"
-            :min="0"
             :max="999999"
-            placeholder="请输入" />
+            :min="1"
+            :precision="0"
+            @change="onCellChange(record.id, 'qty', $event)" />
+        </template>
+        <!-- 操作 -->
+        <template slot="action" slot-scope="text, record">
+          <a-button
+            size="small"
+            type="primary"
+            :loading="delLoading"
+            class="button-error"
+            @click="handleDel(record)"
+            id="productInfoList-Del">删除</a-button>
         </template>
       </s-table>
     </a-card>
+    <a-affix :offset-bottom="0">
+      <div
+        style="text-align: center;width: 100%;background-color: #fff;padding: 12px 0;box-shadow: 0 0 20px #dcdee2;">
+        <a-button
+          size="large"
+          style="width: 150px;"
+          type="primary"
+          class="button-primary"
+          @click="handleSubmit()"
+          id="productInfoList-handleSubmit">提交</a-button>
+      </div>
+    </a-affix>
     <!-- 选择客户弹框 -->
-    <choose-custom-modal :show="openModal" @ok="chooseCustomOk" @cancel="openModal=false" />
+    <choose-custom-modal ref="custModal" :show="openModal" @updateData="updateData" @cancel="openModal=false" />
   </div>
 </template>
 
@@ -85,103 +143,275 @@
 import { STable, VSelect } from '@/components'
 import queryPart from './queryPart.vue'
 import chooseCustomModal from './chooseCustomModal.vue'
+import { salesDetail, salesWriteSubmit, salesWriteDiscount } from '@/api/sales'
+import EditableCell from '@/views/common/editInput.js'
+import { salesDetailList, salesDetailInsert, salesDetailUpdatePrice, salesDetailUpdateQty, salesDetailDel, salesDetailDelAll } from '@/api/salesDetail'
 export default {
   name: 'SalesDetail',
-  components: { STable, VSelect, queryPart, chooseCustomModal },
+  components: { STable, VSelect, queryPart, chooseCustomModal, EditableCell },
   data () {
     return {
+      orderId: null, // 销售单id
+      salesBillSn: null, // 销售单sn
       disabled: false, //  查询、重置按钮是否可操作
-      openModal: false,
+      isInster: false, // 是否正在添加产品
+      openModal: false, // 客户弹框
+      delLoading: false,
+      detailData: { discountAmount: 0, id: null, salesBillSn: '' }, // 订单基础数据
       dataSource: [],
       productForm: {
-        productNo: '',
-        productName: ''
+        productName: '',
+        productCode: ''
       },
       // 表头
       columns: [
-        { title: '序号', dataIndex: 'no', width: 80, align: 'center', fixed: 'left' },
-        { title: '产品编码', dataIndex: 'productNo', width: 140, align: 'center', sorter: true },
-        { title: '产品名称', dataIndex: 'productName', align: 'center' },
-        { title: '原厂编码', dataIndex: 'ycNo', width: 140, align: 'center' },
-        { title: '品牌', dataIndex: 'productBrand', width: 100, align: 'center', sorter: true },
-        { title: '仓库', dataIndex: 'cangku', width: 100, align: 'center', sorter: true },
-        { title: '仓位', dataIndex: 'cangwei', width: 100, align: 'center' },
-        { title: '辅助单位', dataIndex: 'pzdw', width: 100, align: 'center' },
-        { title: '售价', scopedSlots: { customRender: 'price' }, width: 150, align: 'center' },
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '产品编码', dataIndex: 'dealerProductEntity.code', scopedSlots: { customRender: 'productCode' }, width: 140, align: 'center', sorter: true },
+        { title: '产品名称', dataIndex: 'dealerProductEntity.name', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '原厂编码', dataIndex: 'dealerProductEntity.origCode', width: 140, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '品牌', dataIndex: 'dealerProductEntity.productBrandName', width: 100, align: 'center', sorter: true, customRender: function (text) { return text || '--' } },
+        { title: '仓库', dataIndex: 'warehouseEntity.name', width: 100, align: 'center', sorter: true, customRender: function (text) { return text || '--' } },
+        { title: '仓位', dataIndex: 'warehouseLocationEntity.name', width: 100, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '售价', dataIndex: 'price', scopedSlots: { customRender: 'price' }, width: 150, align: 'center' },
         { title: '销售数量', scopedSlots: { customRender: 'salesNums' }, width: 150, align: 'center' },
-        { title: '单位', dataIndex: 'dw', width: 100, align: 'center' },
-        { title: '售价小计', dataIndex: 'xj', width: 100, align: 'center' },
-        { title: '折后小计', dataIndex: 'zhxj', width: 100, align: 'center' }
+        { title: '单位', dataIndex: 'dealerProductEntity.unit', width: 100, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '售价小计', dataIndex: 'totalAmount', width: 100, align: 'center', customRender: function (text) { return '¥' + (text || 0) } },
+        { title: '折后小计', dataIndex: 'discountedAmount', width: 100, align: 'center', customRender: function (text) { return '¥' + (text || 0) } },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: 170, align: 'center', fixed: 'right' }
       ],
       // 加载数据方法 必须为 Promise 对象
       loadData: parameter => {
         this.disabled = true
-        // return customerBundleDelayList( Object.assign(parameter, this.queryParam) ).then(res => {
-        //   const 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
-        //   return data
-        // })
-        const _this = this
-        return new Promise(function (resolve, reject) {
-          const data = {
-            pageNo: 1,
-            pageSize: 10,
-            list: [
-              {
-                id: '1',
-                productNo: 'jgqp11111111111',
-                productName: '产品1',
-                ycNo: 'jgqp111123545',
-                productBrand: '箭冠品牌',
-                productType: '产品分类1',
-                price: 5.6,
-                salesNums: 12
-              }
-            ],
-            count: 10
-          }
+        this.productForm.salesBillSn = this.$route.params.sn
+        return salesDetailList(Object.assign(parameter, this.productForm)).then(res => {
+          const 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.dataSource = data.list
-          resolve(data)
+          this.disabled = false
+          this.dataSource = data.list
+          return data
         })
       }
     }
   },
   methods: {
-    onCellChange (key, dataIndex, value) {
-      console.log(key, dataIndex, value)
-      console.log(this.dataSource)
+    onCellChange (id, key, value) {
+      console.log(id, key, value)
       const dataSource = [...this.dataSource]
-      const target = dataSource.find(item => item.id === key)
-      if (target) {
-        target[dataIndex] = Number(value)
+      const row = dataSource.find(item => item.id === id)
+      if (row) {
+        row[key] = Number(value)
         this.dataSource = dataSource
       }
+      // 修改价格
+      if (key == 'price') {
+        salesDetailUpdatePrice({
+          salesBillSn: row.salesBillSn,
+          productSn: row.productSn,
+          price: row.price
+        }).then(res => {
+          this.resetSearchForm(true)
+          this.$message.info(res.message)
+        })
+      }
+      if (key == 'qty') {
+        salesDetailUpdateQty({
+          id: row.id,
+          qty: row.qty
+        }).then(res => {
+          this.resetSearchForm(true)
+          if (res.status == 200) {
+            this.$refs.partQuery.resetCurForm()
+          }
+          this.$message.info(res.message)
+        })
+      }
     },
-    handleSearch () {
-
-    },
-    // 选择客户成功
-    chooseCustomOk (data) {
-
-    },
+    // 编辑客户信息
     handleEdit () {
       this.openModal = true
+      setTimeout(() => {
+        this.$refs.custModal.editCust(this.detailData)
+      }, 500)
+    },
+    // 更新产品列表
+    updateData (priceType) {
+      // 价格类型变更
+      if (priceType != this.$route.params.priceType) {
+        this.$router.push({ name: 'salesEdit', params: { id: this.orderId, sn: this.salesBillSn, priceType: priceType } })
+      } else {
+        this.getOrderDetail()
+      }
     },
     //  重置
-    resetSearchForm () {},
+    resetSearchForm (flag) {
+      this.$refs.table.refresh(!!flag)
+      this.getOrderDetail()
+    },
+    // 重置列表
+    resetForm () {
+      this.productForm = {
+        productName: '',
+        productCode: ''
+      }
+      this.$refs.table.refresh()
+    },
     //  返回
     handleBack () {
-      this.$router.push({ path: '/salesManagement/salesQuery/list' })
+      this.$router.push({ name: 'salesQueryList' })
+    },
+    // 打折
+    salesDiscount () {
+      if (this.detailData.discountAmount < 0) {
+        return
+      }
+      console.log(this.detailData)
+      salesWriteDiscount({
+        discountAmount: this.detailData.discountAmount,
+        salesBillSn: this.detailData.salesBillSn,
+        id: this.detailData.id
+      }).then(res => {
+        if (res.status == 200) {
+          this.resetSearchForm()
+        }
+      })
+    },
+    // 整单删除
+    delSalerDetailAll () {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确认要整单删除吗?',
+        centered: true,
+        closable: true,
+        onOk () {
+          _this.delLoading = true
+          salesDetailDelAll({ salesBillSn: _this.detailData.salesBillSn }).then(res => {
+            if (res.status == 200) {
+              _this.resetSearchForm()
+            }
+            _this.$message.info(res.message)
+            _this.delLoading = false
+          })
+        }
+      })
+    },
+    // 删除产品
+    handleDel (row) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确认要删除吗?',
+        centered: true,
+        closable: true,
+        onOk () {
+          _this.delLoading = true
+          salesDetailDel({ id: row.id }).then(res => {
+            if (res.status == 200) {
+              _this.resetSearchForm(true)
+            }
+            _this.$message.info(res.message)
+            _this.delLoading = false
+          })
+        }
+      })
+    },
+    // 添加产品
+    insterProduct (row) {
+      console.log(row)
+      // 防止多次添加产品
+      if (this.isInster) { return }
+      const _this = this
+      // 判断是否已添加此产品
+      const hasRow = this.dataSource.find(item => item.productSn == row.productSn && item.warehouseSn == row.warehouseSn && item.warehouseLocationSn == row.warehouseLocationSn)
+      if (hasRow) {
+        this.$message.info('该产品已在当前销售单中存在!')
+        return
+      }
+
+      // 库存不足时
+      if (row.currentQty < row.salesNums) {
+        this.$confirm({
+          title: '提示',
+          content: '库存不足,确认添加为急件吗?',
+          centered: true,
+          closable: true,
+          onOk () {
+            _this.saveNewProduct(row)
+          }
+        })
+      } else if (row.putCost > row.salePrice) {
+        // 销售价低于成本价
+        this.$confirm({
+          title: '提示',
+          content: '售价低于成本价,确认要添加吗?',
+          centered: true,
+          closable: true,
+          onOk () {
+            _this.saveNewProduct(row)
+          }
+        })
+      } else {
+        this.saveNewProduct(row)
+      }
+    },
+    // 保存添加的产品到销售列表
+    saveNewProduct (row) {
+      this.$message.loading('正在添加产品...', 1)
+      this.isInster = true
+      salesDetailInsert({
+        buyerSn: this.detailData.buyerSn,
+        productSn: row.productSn,
+        cost: row.putCost,
+        // productCode: row.productCode,
+        // productOrigCode: row.productOrigCode,
+        price: row.salePrice,
+        qty: row.salesNums,
+        salesBillSn: this.detailData.salesBillSn,
+        salesBillNo: this.detailData.salesBillNo,
+        warehouseSn: row.warehouseSn,
+        warehouseLocationSn: row.warehouseLocationSn,
+        stockSn: row.stockSn
+      }).then(res => {
+        if (res.status == 200) {
+          this.resetSearchForm()
+          this.$refs.partQuery.resetCurForm()
+          this.$message.success('产品添加成功', 2.5)
+        }
+        this.isInster = false
+      })
+    },
+    //  销售单详情
+    getOrderDetail () {
+      salesDetail({ id: this.$route.params.id }).then(res => {
+        console.log('getOrderDetail')
+        if (res.status == 200) {
+          this.detailData = res.data
+          console.log(this.detailData)
+        }
+      })
+    },
+    // 提交销售单
+    handleSubmit () {
+      salesWriteSubmit({ id: this.orderId }).then(res => {
+        if (res.status == 200) {
+          this.handleBack()
+          this.$message.success(res.message)
+        }
+      })
     }
+  },
+  mounted () {
+    this.getOrderDetail()
+    this.orderId = this.$route.params.id
+    this.salesBillSn = this.$route.params.sn
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      console.log('beforeRouteEnter')
+    })
   }
 }
 </script>
@@ -191,6 +421,24 @@ export default {
     .salesEdit-cont{
       margin-top: 15px;
     }
+    .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;
+          }
+        }
+      }
+    }
+    .redBg-row{
+      background-color: #f5cdc8;
+    }
   }
 
 </style>

+ 180 - 78
src/views/salesManagement/salesQuery/list.vue

@@ -25,7 +25,7 @@
                 :showSearch="true"
                 option-filter-prop="children"
                 :filter-option="filterOption">
-                <a-select-option v-for="item in customeList" :key="item.salesChannelNo" :value="item.salesChannelNo">{{ item.salesChannelName }}</a-select-option>
+                <a-select-option v-for="item in custAllList" :key="item.customerSn" :value="item.customerName">{{ item.customerName }}</a-select-option>
               </a-select>
             </a-form-item>
           </a-col>
@@ -40,35 +40,22 @@
                 <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.payType"
-                  ref="payType"
-                  id="salesManagementList-payType"
-                  code="PAYMENT_TYPE"
-                  placeholder="请选择支付方式"
-                  allowClear></v-select>
-              </a-form-item>
-            </a-col>
             <a-col :md="6" :sm="24">
               <a-form-item label="收款方式">
-                <v-select
-                  v-model="queryParam.settleStyle"
-                  ref="settleStyle"
-                  id="salesManagementList-settleStyle"
-                  code="PAYMENT_TYPE"
-                  placeholder="请选择收款方式"
-                  allowClear></v-select>
+                <a-select placeholder="请选择收款方式" v-model="queryParam.settleStyleSn">
+                  <a-select-option v-for="item in settleStyleList" :key="item.settleStyleSn" :value="item.settleStyleSn">
+                    {{ item.name }}
+                  </a-select-option>
+                </a-select>
               </a-form-item>
             </a-col>
             <a-col :md="6" :sm="24">
               <a-form-item label="业务状态">
                 <v-select
-                  v-model="queryParam.auditStatus"
-                  ref="auditStatus"
-                  id="salesManagementList-auditStatus"
-                  code="PAYMENT_TYPE"
+                  v-model="queryParam.billStatus"
+                  ref="billStatus"
+                  id="salesManagementList-billStatus"
+                  code="SALES_BILL_STATUS"
                   placeholder="请选择业务状态"
                   allowClear></v-select>
               </a-form-item>
@@ -79,7 +66,7 @@
                   v-model="queryParam.financialStatus"
                   ref="financialStatus"
                   id="salesManagementList-financialStatus"
-                  code="PAYMENT_TYPE"
+                  code="FINANCIAL_RECEIVE_STATUS"
                   placeholder="请选择财务状态"
                   allowClear></v-select>
               </a-form-item>
@@ -100,11 +87,16 @@
     </div>
     <!-- 操作按钮 -->
     <div class="table-operator">
-      <a-button type="primary" @click="handleAdd">新增销售单</a-button>
+      <a-button type="primary" class="button-error" @click="handleAdd">新增(零售)</a-button>
     </div>
     <!-- alert -->
     <a-alert type="info" showIcon style="margin-bottom:15px">
-      <div slot="message">总售价:<strong>13.00</strong>元;总单数:<strong>13.00</strong>;总款数:<strong>13.00</strong>;总数量:<strong>13.00</strong>;</div>
+      <div slot="message">
+        总售价:<strong>{{ totalData.totalAmount }}</strong>元;
+        总单数:<strong>{{ totalData.totalRecord }}</strong>;
+        总款数:<strong>{{ totalData.totalCategory }}</strong>;
+        总数量:<strong>{{ totalData.totalQty }}</strong>;
+      </div>
     </a-alert>
     <!-- 列表 -->
     <s-table
@@ -114,27 +106,73 @@
       :rowKey="(record) => record.id"
       :columns="columns"
       :data="loadData"
-      :scroll="{ x: 1960 }"
+      :scroll="{ x: 2050, y:tableHeight }"
       bordered>
-      <!-- 业务/审核状态 -->
-      <template slot="auditStatus" slot-scope="text, record">
-        <a-tag :color="record.state=='FINISH'?'green':'red'" >{{ record.state=='FINISH'? '待备货审核': '待单据审核' }}</a-tag>
+      <!-- 销售单号 -->
+      <template slot="salesBillNo" slot-scope="text, record">
+        <span style="color: #ed1c24;cursor: pointer;" @click="handleDetail(record)">{{ record.salesBillNo }}</span>
+      </template>
+      <!-- 急件 -->
+      <template slot="oosFlag" slot-scope="text, record">
+        <a-tag :color="record.oosFlag==1?'red':'#ccc'" >{{ record.oosFlagDictValue }}</a-tag>
       </template>
       <!-- 财务状态 -->
       <template slot="financialStatus" slot-scope="text, record">
-        <a-tag :color="record.state==1?'green':'red'" >{{ record.state==1? '待提交': '待单据审核' }}</a-tag>
+        <a-badge :color="text=='FINISH'?'#87d068':'gold'" :text="record.financialStatusDictValue" />
       </template>
       <!-- 操作 -->
       <template slot="action" slot-scope="text, record">
-        <a-button size="small" type="link" @click="handleEexamine(record)" id="salesManagementList-eexamine-btn">审核</a-button>
-        <a-divider type="vertical" style="margin: 0;" />
-        <a-button size="small" type="link" @click="handleSend(record)" id="salesManagementList-send-btn">出库</a-button>
-        <a-divider type="vertical" style="margin: 0;" />
-        <a-button size="small" type="link" @click="handleDetail(record)" id="salesManagementList-detail-btn">详情</a-button>
-        <a-divider type="vertical" style="margin: 0;" />
-        <a-button size="small" type="link" @click="handleEdit(record)" id="salesManagementList-edit-btn">编辑</a-button>
-        <a-divider type="vertical" style="margin: 0;" />
-        <a-button size="small" type="link" @click="handleDel(record)" id="salesManagementList-del-btn">删除</a-button>
+        <a-button
+          size="small"
+          type="link"
+          class="button-warning"
+          v-if="record.billStatus == 'WAIT_AUDIT'"
+          @click="handleEexamine(record)"
+        >审核</a-button>
+        <a-button
+          size="small"
+          type="link"
+          v-if="record.billStatus == 'WAIT_OUT_WAREHOUSE'"
+          class="button-primary"
+          @click="handleSend(record)"
+        >出库</a-button>
+        <a-button
+          size="small"
+          type="link"
+          class="button-info"
+          v-if="record.salesBillSource == 'SALES' && record.billStatus !== 'CANCEL' && record.billStatus !== 'FINISH' && record.billStatus != 'WAIT_OUT_WAREHOUSE'"
+          @click="handleEdit(record)"
+        >
+          编辑
+        </a-button>
+        <a-button
+          size="small"
+          type="link"
+          class="button-error"
+          v-if="record.salesBillSource == 'SALES' && record.billStatus !== 'FINISH' && record.financialStatus !== 'FINISH'"
+          @click="handleDel(record)"
+        >
+          删除
+        </a-button>
+        <a-button
+          size="small"
+          type="link"
+          class="button-info"
+          v-if="record.salesBillSource == 'PURCHASE' && record.billStatus !== 'CANCEL' && record.billStatus !== 'FINISH' && record.billStatus != 'WAIT_OUT_WAREHOUSE'&& record.billStatus != 'AUDIT_REJECT'"
+          @click="handleEdit(record)"
+        >
+          改单
+        </a-button>
+        <a-button
+          size="small"
+          type="link"
+          class="button-error"
+          v-if="record.salesBillSource == 'PURCHASE' && record.billStatus !== 'FINISH' && record.financialStatus !== 'FINISH'&& record.billStatus != 'AUDIT_REJECT'&& record.billStatus != 'WAIT_OUT_WAREHOUSE'"
+          @click="handleDel(record)"
+        >
+          取消
+        </a-button>
+        <span v-if="record.billStatus == 'FINISH'||(record.salesBillSource == 'PURCHASE'&&record.billStatus == 'AUDIT_REJECT')">--</span>
       </template>
     </s-table>
     <!-- 选择客户弹框 -->
@@ -143,51 +181,78 @@
 </template>
 
 <script>
+import moment from 'moment'
 import { STable, VSelect } from '@/components'
 import chooseCustomModal from './chooseCustomModal.vue'
-import { salesList, salesDel } from '@/api/sales'
+import { custAllList } from '@/api/customer'
+import { salesList, salesDel, salesWriteAudit, salesWriteStockOut, salesCount } from '@/api/sales'
+import { settleStyleQueryAll } from '@/api/settleStyle'
 export default {
   name: 'TableList',
   components: { STable, VSelect, chooseCustomModal },
   data () {
     return {
+      tableHeight: 0,
       advanced: false, // 高级搜索 展开/关闭
       disabled: false, //  查询、重置按钮是否可操作
       dateFormat: 'YYYY-MM-DD',
       time: [], //  创建时间
       openModal: false, // 选择客户弹框是否显示
-      customeList: [],
+      custAllList: [], //  客户 下拉数据
+      settleStyleList: [], // 收款方式
       // 查询参数
       queryParam: {
         buyerName: undefined, //  客户名称
         salesBillNo: '', //  销售单号
         purchaseBillNo: '', //  采购单号
         payType: undefined, //  支付方式
-        settleStyle: undefined, //  收款方式
-        auditStatus: undefined, //  业务状态
+        settleStyleSn: undefined, //  收款方式
+        billStatus: undefined, //  业务状态
         financialStatus: undefined //  财务状态
       },
+      totalData: {
+        totalAmount: 0,
+        totalCategory: 0,
+        totalQty: 0,
+        totalRecord: 0
+      },
       // 表头
       columns: [
         { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
         { title: '创建时间', dataIndex: 'createDate', width: 160, align: 'center' },
-        { title: '销售单号', dataIndex: 'salesBillNo', width: 140, align: 'center' },
-        { title: '采购单号', dataIndex: 'purchaseBillNo', width: 140, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '来源', dataIndex: 'salesBillSourceDictValue', width: 120, align: 'center' },
+        { title: '销售单号', scopedSlots: { customRender: 'salesBillNo' }, width: 210, align: 'center' },
+        { title: '采购单号', dataIndex: 'purchaseBillNo', width: 210, align: 'center', customRender: function (text) { return text || '--' } },
         { title: '客户名称', dataIndex: 'buyerName', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
         { title: '总款数', dataIndex: 'totalCategory', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
         { title: '总数量', dataIndex: 'totalQty', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
-        { title: '总售价', dataIndex: 'totalAmount', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
-        { title: '支付方式', dataIndex: 'payType', width: 100, align: 'center', customRender: function (text) { return text || '--' } },
-        { title: '收款方式', dataIndex: 'settleStyle', width: 100, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '总售价', dataIndex: 'totalAmount', width: 100, align: 'center', customRender: function (text) { return '¥' + (text || 0) } },
+        { title: '收款方式', dataIndex: 'settleStyleEntity.name', width: 100, align: 'center', customRender: function (text) { return text || '--' } },
         { title: '审核时间', dataIndex: 'auditTime', width: 160, align: 'center', customRender: function (text) { return text || '--' } },
-        { title: '急件', dataIndex: 'urgentFlag', width: 100, align: 'center', customRender: function (text) { return text || '--' } },
-        { title: '业务状态', scopedSlots: { customRender: 'auditStatus' }, width: 110, align: 'center' },
-        { title: '财务状态', scopedSlots: { customRender: 'financialStatus' }, width: 110, align: 'center' },
-        { title: '操作', scopedSlots: { customRender: 'action' }, width: 260, align: 'center', fixed: 'right' }
+        { title: '急件', dataIndex: 'oosFlag', scopedSlots: { customRender: 'oosFlag' }, width: 100, align: 'center' },
+        { title: '业务状态', dataIndex: 'billStatusDictValue', width: 110, align: 'center' },
+        { title: '财务状态', dataIndex: 'financialStatus', scopedSlots: { customRender: 'financialStatus' }, width: 110, align: 'center' },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: 220, align: 'center', fixed: 'right' }
       ],
       // 加载数据方法 必须为 Promise 对象
       loadData: parameter => {
         this.disabled = true
+        if (this.tableHeight == 0) {
+          this.tableHeight = window.innerHeight - 440
+        }
+        // 创建时间
+        if (this.time && this.time.length > 0) {
+          this.queryParam.beginDate = moment(this.time[0]).format(this.dateFormat)
+          this.queryParam.endDate = moment(this.time[1]).format(this.dateFormat)
+        } else {
+          this.queryParam.beginDate = undefined
+          this.queryParam.endDate = undefined
+        }
+        // 查询总计
+        salesCount(Object.assign(parameter, this.queryParam)).then(res => {
+          console.log(res)
+          this.totalData = Object.assign(this.totalData, res.data || {})
+        })
         return salesList(Object.assign(parameter, this.queryParam)).then(res => {
           const data = res.data
           const no = (data.pageNo - 1) * data.pageSize
@@ -211,27 +276,37 @@ export default {
     },
     // 选择客户成功
     chooseCustomOk (data) {
-      this.$router.push({ path: '/salesManagement/salesQuery/add' })
+      this.$router.push({ name: 'salesAdd', params: { id: data.id, sn: data.salesBillSn, priceType: data.priceType } })
     },
     //  审核
     handleEexamine (row) {
       const _this = this
       this.$confirm({
         title: '提示',
-        content: '确认要审核吗?',
+        content: '请点击下方按钮确认操作?',
+        centered: true,
+        closable: true,
         okText: '审核通过',
         cancelText: '审核不通过',
-        centered: true,
         onOk () {
-          // delectRolePower({
-          //   id: row.id
-          // }).then(res => {
-          //   console.log(res, 'res1111')
-          //   if (res.status == 200) {
-          //     _this.$message.success(res.message)
-          //     _this.$refs.table.refresh()
-          //   }
-          // })
+          _this.auditOrder(row.id, 'WAIT_OUT_WAREHOUSE')
+        },
+        onCancel (e) {
+          if (!e.triggerCancel) {
+            _this.auditOrder(row.id, 'AUDIT_REJECT')
+          }
+          _this.$destroyAll()
+        }
+      })
+    },
+    auditOrder (id, billStatus) {
+      salesWriteAudit({
+        id,
+        billStatus
+      }).then(res => {
+        if (res.status == 200) {
+          this.$message.success(res.message)
+          this.$refs.table.refresh()
         }
       })
     },
@@ -242,26 +317,26 @@ export default {
         title: '提示',
         content: '确认要出库吗?',
         centered: true,
+        closable: true,
         onOk () {
-          // delectRolePower({
-          //   id: row.id
-          // }).then(res => {
-          //   console.log(res, 'res1111')
-          //   if (res.status == 200) {
-          //     _this.$message.success(res.message)
-          //     _this.$refs.table.refresh()
-          //   }
-          // })
+          salesWriteStockOut({
+            salesBillSn: row.salesBillSn
+          }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$refs.table.refresh()
+            }
+          })
         }
       })
     },
     // 详情
     handleDetail (row) {
-      this.$router.push({ path: `/salesManagement/salesQuery/detail/${row.id}/${row.salesBillSn}` })
+      this.$router.push({ name: 'salesDetail', params: { sn: row.salesBillSn } })
     },
     // 编辑
     handleEdit (row) {
-      this.$router.push({ path: `/salesManagement/salesQuery/edit/${row.id}` })
+      this.$router.push({ name: 'salesEdit', params: { id: row.id, sn: row.salesBillSn, priceType: row.priceType } })
     },
     // 删除
     handleDel (row) {
@@ -270,6 +345,7 @@ export default {
         title: '提示',
         content: '确认要删除吗?',
         centered: true,
+        closable: true,
         onOk () {
           salesDel({ id: row.id }).then(res => {
             if (res.status == 200) {
@@ -280,13 +356,25 @@ export default {
         }
       })
     },
+    // 客户无分页列表数据
+    getCustAllList () {
+      const _this = this
+      custAllList().then(res => {
+        if (res.status == 200) {
+          _this.custAllList = res.data || []
+        } else {
+          _this.custAllList = []
+        }
+      })
+    },
+    // 重置
     resetSearchForm () {
       this.queryParam.buyerName = undefined
       this.queryParam.salesBillNo = ''
       this.queryParam.purchaseBillNo = ''
       this.queryParam.payType = undefined
-      this.queryParam.settleStyle = undefined
-      this.queryParam.auditStatus = undefined
+      this.queryParam.settleStyleSn = undefined
+      this.queryParam.billStatus = undefined
       this.queryParam.financialStatus = undefined
       this.time = []
       this.$refs.table.refresh(true)
@@ -295,7 +383,21 @@ export default {
       return (
         option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
       )
+    },
+    // 获取收款方式
+    getSettleStyle () {
+      settleStyleQueryAll().then(res => {
+        if (res.status == 200) {
+          this.settleStyleList = res.data
+        }
+      })
     }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      vm.getCustAllList()
+      vm.getSettleStyle()
+    })
   }
 }
 </script>

+ 65 - 60
src/views/salesManagement/salesQuery/productSalesRecordModal.vue

@@ -9,30 +9,34 @@
     @cancle="isShow=false"
     width="80%">
     <div>
-      <a-tabs type="card" default-active-key="1" @change="callback">
+      <a-tabs size="small" type="card" v-model="curTab" @change="callback">
         <a-tab-pane key="1" tab="当前客户">
         </a-tab-pane>
         <a-tab-pane key="2" tab="全部客户">
         </a-tab-pane>
       </a-tabs>
       <!-- 表格 -->
-      <s-table
+      <a-table
         class="sTable"
         ref="table"
-        size="default"
-        :rowKey="(record) => record.id"
+        size="small"
+        :data-source="list"
+        :pagination="pagination"
+        :loading="loading"
+        :row-key="(record) => record.id"
         :columns="columns"
-        :data="loadData"
+        @change="handleTableChange"
         bordered>
-      </s-table>
+      </a-table>
     </div>
   </a-modal>
 </template>
 
 <script>
+import { salesRecordlList } from '@/api/salesDetail.js'
 import { STable } from '@/components'
 export default {
-  name: 'salesRecordModal',
+  name: 'SalesRecordModal',
   components: { STable },
   props: {
     openModal: { //  弹框显示状态
@@ -52,11 +56,17 @@ export default {
   data () {
     return {
       isShow: this.openModal, //  是否打开弹框
+      buyerSn: null,
+      queryParam: {
+        productSn: null,
+        pageNo: 1,
+        pageSize: 10
+      },
       // 表头
       columns: [
         {
           title: '销售时间',
-          dataIndex: 'salesTime',
+          dataIndex: 'salesBillEntity.createDate',
           align: 'center',
           width: 250
         },
@@ -68,65 +78,63 @@ export default {
         },
         {
           title: '销售数量',
-          dataIndex: 'salesNums',
+          dataIndex: 'qty',
           align: 'center',
           width: 150
         },
         {
           title: '客户名称',
-          dataIndex: 'productBrand',
+          dataIndex: 'salesBillEntity.buyerName',
           align: 'center'
-        },
+        }
       ],
-      // 加载数据方法 必须为 Promise 对象
-      loadData: parameter => {
-        this.disabled = true
-        // return customerBundleDelayList( Object.assign(parameter, this.queryParam) ).then(res => {
-        //   const data = res.data
-        //   return data
-        // })
-        const _this = this
-        return new Promise(function(resolve, reject){
-          const data = {
-            pageNo: 1,
-            pageSize: 10,
-            list: [
-              { 
-                id: '1', 
-                salesTime: '2020-12-23 15:23:15', 
-                price: 56, 
-                salesNums: 12, 
-                productBrand: '箭冠品牌', 
-              },
-              {
-                id: '23', 
-                salesTime: '2020-12-23 15:23:15', 
-                price: 56, 
-                salesNums: 12, 
-                productBrand: '箭冠品牌', 
-              },
-              {
-                id: '44', 
-                salesTime: '2020-12-23 15:23:15', 
-                price: 56, 
-                salesNums: 12, 
-                productBrand: '箭冠品牌', 
-              }
-            ],
-            count: 100
-          }
-          resolve(data)
-        })
-      },
+      list: [],
+      pagination: {},
+      loading: false,
+      curTab: '1'
     }
   },
   methods: {
+    handleTableChange (pagination, filters, sorter) {
+      console.log(pagination)
+      const pager = { ...this.pagination }
+      pager.current = pagination.current
+      this.pagination = pager
+      this.loading = true
+      this.queryParam = Object.assign(this.queryParam, {
+        results: pagination.pageSize,
+        page: pagination.current,
+        sortField: sorter.field,
+        sortOrder: sorter.order,
+        ...filters
+      })
+
+      salesRecordlList(this.queryParam).then(res => {
+        this.list = res.data.list || []
+        this.loading = false
+      })
+    },
     //  获取详情
-    getDetail(){
-      
+    getDetail (buyerSn, productSn) {
+      this.buyerSn = buyerSn
+      if (this.curTab == 1) {
+        this.queryParam.buyerSn = buyerSn
+      } else {
+        delete this.queryParam.buyerSn
+      }
+      this.queryParam.productSn = productSn
+      this.queryParam.pageNo = 1
+      this.queryParam.pageSize = 10
+      this.loading = true
+      salesRecordlList(this.queryParam).then(res => {
+        this.list = res.data.list || []
+        this.loading = false
+      })
     },
-    callback(key){
-      console.log(key);
+    callback (key) {
+      console.log(key)
+      this.curTab = key
+      this.getDetail(this.buyerSn, this.queryParam.productSn)
     }
   },
   watch: {
@@ -138,11 +146,8 @@ export default {
     isShow (newValue, oldValue) {
       if (!newValue) {
         this.$emit('close')
-      }
-    },
-    itemId (newValue, oldValue) {
-      if (this.isShow && newValue) {
-        this.getDetail()
+        this.curTab = '1'
+        this.list = []
       }
     }
   }

+ 270 - 94
src/views/salesManagement/salesQuery/queryPart.vue

@@ -6,42 +6,51 @@
         <a-row :gutter="15">
           <a-col :md="6" :sm="24">
             <a-form-item label="产品编码">
-              <a-input id="productInfoList-bundleName" v-model.trim="queryParam.bundleName" allowClear placeholder="请输入产品编码"/>
+              <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-bundleName" v-model.trim="queryParam.bundleName" allowClear placeholder="请输入产品名称"/>
+              <a-input id="productInfoList-name" v-model.trim="queryParam.productName" allowClear placeholder="请输入产品名称"/>
             </a-form-item>
           </a-col>
           <a-col :md="6" :sm="24">
             <a-form-item label="原厂编码">
-              <a-input id="productInfoList-bundleName" v-model.trim="queryParam.bundleName" allowClear placeholder="请输入原厂编码"/>
+              <a-input id="productInfoList-origCode" v-model.trim="queryParam.productOrigCode" allowClear placeholder="请输入原厂编码"/>
             </a-form-item>
           </a-col>
           <template v-if="advanced">
             <a-col :md="6" :sm="24">
               <a-form-item label="车架号(VIN)">
-                <a-input id="productInfoList-bundleName" v-model.trim="queryParam.bundleName" allowClear placeholder="请输入车架号(VIN)"/>
+                <a-input id="productInfoList-vinNo" v-model.trim="queryParam.vinNo" allowClear placeholder="请输入车架号(VIN)"/>
               </a-form-item>
             </a-col>
             <a-col :md="6" :sm="24">
               <a-form-item label="产品品牌">
                 <a-select
                   placeholder="请选择产品品牌"
-                  id="productInfoList-state"
+                  id="productInfoList-productBrandSn"
                   allowClear
-                  v-model="queryParam.dataSourceNo"
+                  v-model="queryParam.brandSn"
                   :showSearch="true"
                   option-filter-prop="children"
                   :filter-option="filterOption">
-                  <a-select-option v-for="item in brandData" :key="item.salesChannelNo" :value="item.salesChannelNo">{{ item.salesChannelName }}</a-select-option>
+                  <a-select-option v-for="item in productBrandList" :key="item.brandSn" :value="item.brandSn">{{ item.brandName }}</a-select-option>
                 </a-select>
               </a-form-item>
             </a-col>
             <a-col :md="6" :sm="24">
               <a-form-item label="产品类别">
-                <a-cascader :options="typeData" id="productInfoList-state" placeholder="请选择产品类别" allowClear v-model="queryParam.brand" />
+                <a-cascader
+                  @change="changeProductType"
+                  change-on-select
+                  v-model="productType"
+                  expand-trigger="hover"
+                  :options="productTypeList"
+                  :fieldNames="{ label: 'productTypeName', value: 'productTypeSn', children: 'children' }"
+                  id="productInfoList-productType"
+                  placeholder="请选择产品分类"
+                  allowClear />
               </a-form-item>
             </a-col>
             <a-col :md="6" :sm="24">
@@ -51,13 +60,22 @@
             </a-col>
             <a-col :md="6" :sm="24">
               <a-form-item label="仓库">
-                <v-select code="CHECK_ENABLE_STATE" id="productInfoList-state" v-model="queryParam.state" allowClear placeholder="请选择仓库"></v-select>
+                <a-select
+                  placeholder="请选择仓库"
+                  id="productInfoList-warehouseSn"
+                  allowClear
+                  v-model="queryParam.warehouseSn"
+                  :showSearch="true"
+                  option-filter-prop="children"
+                  :filter-option="filterOption">
+                  <a-select-option v-for="item in warehouseList" :key="item.warehouseSn" :value="item.warehouseSn">{{ item.name }}</a-select-option>
+                </a-select>
               </a-form-item>
             </a-col>
           </template>
           <a-col :md="6" :sm="24">
             <a-button style="margin-bottom: 18px;" type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="productInfoList-refresh">查询</a-button>
-            <a-button style="margin: 0 0 18px 8px" @click="resetSearchForm" :disabled="disabled" id="productInfoList-reset">重置</a-button>
+            <a-button style="margin: 0 0 18px 8px" @click="resetSearchForm" id="productInfoList-reset">重置</a-button>
             <a @click="advanced=!advanced" style="margin:0 15px 0 8px">
               {{ advanced ? '收起' : '展开' }}
               <a-icon :type="advanced ? 'up' : 'down'"/>
@@ -66,7 +84,10 @@
               <template slot="content">双击列表配件可快速选中添加</template>
               <a-icon type="question-circle" theme="twoTone" />
             </a-popover>
-            <a-icon style="margin:0 15px" type="setting" theme="twoTone" />
+            <a-popover>
+              <template slot="content">点击设置列的显示</template>
+              <a-icon style="margin:0 15px;cursor: pointer;" @click="showSetting = true" type="setting" theme="twoTone" />
+            </a-popover>
           </a-col>
         </a-row>
       </a-form>
@@ -75,135 +96,255 @@
     <s-table
       class="sTable"
       ref="table"
-      size="default"
+      size="small"
       :rowKey="(record) => record.id"
       :columns="columns"
       :data="loadData"
-      :scroll="{ x: 1530 }"
+      :customRow="handleClickRow"
+      :scroll="{ x: tableWidth, y: 300 }"
+      :defaultLoadData="false"
       bordered>
       <!-- 售价 -->
-      <template slot="price" slot-scope="text, record">
-        <a-input-number
-          id="productInfoList-price"
-          :value="record.price"
-          :precision="0"
-          :min="0"
-          :max="999999"
-          placeholder="请输入" />
+      <template slot="salePrice" slot-scope="text, record">
+        <div @dblclick.stop>
+          ¥
+          <a-input-number
+            size="small"
+            v-model="record.salePrice"
+            :precision="2"
+            :min="0"
+            :max="999999"
+            placeholder="请输入" />
+        </div>
       </template>
       <!-- 销售数量 -->
-      <template slot="salesNums" slot-scope="text, record">
-        <a-input-number
-          id="productInfoList-salesNums"
-          :value="record.salesNums"
-          :precision="0"
-          :min="0"
-          :max="999999"
-          placeholder="请输入" />
+      <template slot="nums" slot-scope="text, record">
+        <div @dblclick.stop>
+          <a-input-number
+            size="small"
+            v-model="record.salesNums"
+            :precision="0"
+            :min="0"
+            :max="999999"
+            placeholder="请输入" />
+        </div>
       </template>
       <!-- 操作 -->
       <template slot="action" slot-scope="text, record">
-        <a-button size="small" type="link" @click="handleAdd(record)" id="productInfoList-edit-btn">添加</a-button>
-        <a-divider type="vertical" style="margin: 0;" />
-        <a-button size="small" type="link" @click="handleDetail(record)" id="productInfoList-detail-btn" style="margin-left: 15px;">销售记录</a-button>
+        <a-button
+          size="small"
+          type="primary"
+          class="button-info"
+          :loading="newLoading"
+          @click="handleAdd(record)"
+          id="productInfoList-edit-btn">添加</a-button>
+        <a-button
+          size="small"
+          type="primary"
+          class="button-success"
+          @click="handleDetail(record)"
+          id="productInfoList-detail-btn"
+          style="margin-left: 15px;">销售记录</a-button>
       </template>
     </s-table>
     <!-- 销售记录 -->
-    <product-salesRecord-modal :openModal="openModal" :itemId="itemId" @close="closeModal" />
+    <product-salesRecord-modal ref="salseRecord" :openModal="openModal" @close="closeModal" />
+    <!-- 设置列 -->
+    <a-modal
+      v-model="showSetting"
+      title="设置要显示的列"
+      centered
+      :footer="null"
+      @ok="() => (showSetting = false)"
+    >
+      <a-checkbox-group v-model="settingColVal" @change="onSettingChange">
+        <a-row>
+          <a-col :span="8" v-for="item in settingColList" :key="item.value">
+            <a-checkbox :value="item.value">
+              {{ item.label }}
+            </a-checkbox>
+          </a-col>
+        </a-row>
+      </a-checkbox-group>
+    </a-modal>
   </div>
 </template>
 
 <script>
-// import { customerBundleDelayList, customerBundleExportDelay } from '@/api/FinancialManagement'
+import { dealerProductBrandQuery } from '@/api/dealerProductBrand'
+import { dealerProductTypeList } from '@/api/dealerProductType'
+import { querySumByProductLocation } from '@/api/stock'
+import { warehouseAllList } from '@/api/warehouse'
 import productSalesRecordModal from './productSalesRecordModal.vue'
 import { STable, VSelect } from '@/components'
 export default {
   name: 'QueryPart',
   components: { STable, VSelect, productSalesRecordModal },
+  props: {
+    buyerSn: {
+      type: [Number, String],
+      default: ''
+    },
+    priceType: {
+      type: [Number, String],
+      default: ''
+    },
+    newLoading: Boolean
+  },
   data () {
     return {
       advanced: false, // 高级搜索 展开/关闭
+      showSetting: false, // 设置弹框
+      tableWidth: 0,
+      settingColVal: ['productOrigCode', 'brandName', 'warehouseName', 'warehouseLocationName', 'currentQty', 'unit'],
+      settingColList: [
+        { label: '原厂编码', value: 'productOrigCode' },
+        { label: '品牌', value: 'brandName' },
+        { label: '仓库', value: 'warehouseName' },
+        { label: '仓位', value: 'warehouseLocationName' },
+        { label: '库存数量', value: 'currentQty' },
+        { label: '单位', value: 'unit' },
+        { label: '成本价', value: 'putCost' },
+        { label: '市级价', value: 'dealerProduct.cityPrice' }
+      ],
+      productType: [],
       queryParam: { //  查询条件
-        bundleName: '', //  供应商名称
-        state: undefined //  状态
+        salePriceType: '',
+        productCode: '', //  产品编码
+        productName: '', //  产品名称
+        productOrigCode: '', //  原厂编码
+        brandSn: undefined, //  产品品牌
+        productTypeSn1: '', //  产品一级分类
+        productTypeSn2: '', //  产品二级分类
+        productTypeSn3: '', //  产品三级分类
+        warehouseSn: undefined //  仓库
       },
       disabled: false, //  查询、重置按钮是否可操作
       exportLoading: false, // 导出loading
-      brandData: [], //  下拉数据
-      typeData: [], //  产品类别  下拉数据
-      columns: [
+      productBrandList: [], //  下拉数据
+      productTypeList: [], //  产品类别  下拉数据
+      warehouseList: [], // 仓库列表
+      columnsBak: [
         { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
-        { title: '产品编码', dataIndex: 'productNo', width: 140, align: 'center', sorter: true },
-        { title: '产品名称', dataIndex: 'productName', align: 'center' },
-        { title: '原厂编码', dataIndex: 'ycNo', width: 140, align: 'center' },
-        { title: '品牌', dataIndex: 'productBrand', width: 100, align: 'center', sorter: true },
-        { title: '仓库', dataIndex: 'cangku', width: 100, align: 'center', sorter: true },
-        { title: '仓位', dataIndex: 'cangwei', width: 100, align: 'center' },
-        { title: '辅助单位', dataIndex: 'pzdw', width: 100, align: 'center' },
-        { title: '售价', scopedSlots: { customRender: 'price' }, width: 150, align: 'center' },
-        { title: '销售数量', scopedSlots: { customRender: 'salesNums' }, width: 150, align: 'center' },
-        { title: '单位', dataIndex: 'dw', width: 100, align: 'center' },
-        { title: '操作', scopedSlots: { customRender: 'action' }, width: 170, align: 'center', fixed: 'right' }
+        { title: '产品编码', dataIndex: 'productCode', width: 140, align: 'center', sorter: true, customRender: function (text) { return text || '--' } },
+        { title: '产品名称', dataIndex: 'productName', width: 200, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '原厂编码', dataIndex: 'productOrigCode', width: 140, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '品牌', dataIndex: 'brandName', width: 100, align: 'center', sorter: true, customRender: function (text) { return text || '--' } },
+        { title: '仓库', dataIndex: 'warehouseName', width: 100, align: 'center', sorter: true, customRender: function (text) { return text || '--' } },
+        { title: '仓位', dataIndex: 'warehouseLocationName', width: 100, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '库存数量', dataIndex: 'currentQty', width: 100, align: 'center', customRender: function (text) { return text || 0 } },
+        { title: '单位', dataIndex: 'unit', width: 100, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '成本价', dataIndex: 'putCost', width: 100, align: 'center', customRender: function (text) { return '¥' + (text || 0) } },
+        { title: '市级价', dataIndex: 'dealerProduct.cityPrice', width: 100, align: 'center', customRender: function (text) { return '¥' + (text || 0) } },
+        { title: '售价', dataIndex: 'salePrice', scopedSlots: { customRender: 'salePrice' }, width: 150, align: 'center' },
+        { title: '销售数量', dataIndex: 'salesNums', scopedSlots: { customRender: 'nums' }, width: 150, align: 'center' },
+        { title: '操作', dataIndex: 'action', scopedSlots: { customRender: 'action' }, width: 200, align: 'center', fixed: 'right' }
       ],
+      columns: [],
       // 加载数据方法 必须为 Promise 对象
       loadData: parameter => {
         this.disabled = true
-        // return customerBundleDelayList( Object.assign(parameter, this.queryParam) ).then(res => {
-        //   const 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
-        //   return data
-        // })
-        const _this = this
-        return new Promise(function (resolve, reject) {
-          const data = {
-            pageNo: 1,
-            pageSize: 10,
-            list: [
-              {
-                id: '1',
-                productNo: 'jgqp1111111111',
-                productName: '产品1',
-                ycNo: 'jgqp111123545',
-                productBrand: '箭冠品牌',
-                productType: '产品分类1',
-                price: 5.6,
-                salesNums: 12,
-                dw: '个'
-              }
-            ],
-            count: 10
-          }
+        this.queryParam.salePriceType = this.priceType
+        // 排序
+        if (parameter.sortField == 'productCode') {
+          parameter.sortField = 'code'
+          parameter.sortAlias = 'product '
+        }
+        if (parameter.sortField == 'brandName') {
+          parameter.sortField = 'firstChar'
+          parameter.sortAlias = 'brand'
+        }
+        if (parameter.sortField == 'warehouseName') {
+          parameter.sortField = 'warehouseSn'
+          parameter.sortAlias = 'sd'
+        }
+        return querySumByProductLocation(Object.assign(parameter, this.queryParam)).then(res => {
+          const 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].currentQty = data.list[i].currentQty || 0
           }
-          _this.disabled = false
-          resolve(data)
+          this.disabled = false
+          return data
         })
       },
-      openModal: false, //  查看客户详情  弹框
-      itemId: '' //  当前产品id
+      openModal: false //  查看客户详情  弹框
+    }
+  },
+  created () {
+    this.columns = this.columnsBak
+    this.onSettingChange()
+    // 产品品牌
+    if (this.productBrandList.length == 0) {
+      this.getProductBrand()
+    }
+    // 产品分类
+    if (this.productTypeList.length == 0) {
+      this.getProductType()
+    }
+    // 仓库
+    if (this.warehouseList.length == 0) {
+      this.getWarehouse()
     }
   },
   methods: {
+    // 设置列
+    onSettingChange (v) {
+      const k = ['productOrigCode', 'brandName', 'warehouseName', 'warehouseLocationName', 'currentQty', 'unit', 'putCost', 'dealerProduct.cityPrice']
+      const a = ['no', 'productCode', 'productName']
+      const b = ['salePrice', 'salesNums', 'action']
+      const c = this.settingColVal
+      const q = k.filter(item => c.indexOf(item) >= 0)
+      const r = a.concat(q).concat(b)
+      const d = []
+      let w = 0
+      for (let i = 0; i < r.length; i++) {
+        const row = this.columnsBak.find(item => item.dataIndex == r[i])
+        if (row) {
+          w = w + row.width
+          d.push(row)
+        }
+      }
+      console.log(w)
+      this.tableWidth = w
+      this.columns = d
+    },
+    // 双击列表
+    handleClickRow (record) {
+      const _this = this
+      return {
+        on: {
+          dblclick: (event) => {
+            event.stopPropagation()
+            _this.$emit('add', record)
+          }
+        }
+      }
+    },
     //  重置
     resetSearchForm () {
-      this.queryParam.orderBundleNo = ''
-      this.queryParam.orderBundle.custMobile = ''
-      this.queryParam.bundleName = ''
-      this.queryParam.itemName = ''
-      this.oldTime = undefined
-      this.newTime = undefined
+      this.queryParam.productCode = ''
+      this.queryParam.productName = ''
+      this.queryParam.productOrigCode = ''
+      this.queryParam.brandSn = undefined
+      this.queryParam.productTypeSn1 = ''
+      this.queryParam.productTypeSn2 = ''
+      this.queryParam.productTypeSn3 = ''
+      this.queryParam.warehouseSn = undefined
+      this.productType = []
       this.$refs.table.refresh(true)
     },
+    // 刷新当前页面
+    resetCurForm () {
+      this.$refs.table.refresh()
+    },
     filterOption (input, option) {
-    	return (
-    		option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
-    	)
+      return (
+        option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
+      )
     },
     // 选择配件
     handleAdd (row) {
@@ -211,13 +352,48 @@ export default {
     },
     // 销售记录
     handleDetail (row) {
-      this.itemId = row.id
       this.openModal = true
+      this.$refs.salseRecord.getDetail(this.buyerSn, row.productSn)
     },
     //  关闭弹框
     closeModal () {
-      this.itemId = ''
       this.openModal = false
+    },
+    // 仓库
+    getWarehouse () {
+      warehouseAllList({}).then(res => {
+        if (res.status == 200) {
+          this.warehouseList = res.data
+        } else {
+          this.warehouseList = []
+        }
+      })
+    },
+    //  产品品牌  列表
+    getProductBrand () {
+      dealerProductBrandQuery({ sysFlag: 0 }).then(res => {
+        if (res.status == 200) {
+          this.productBrandList = res.data
+        } else {
+          this.productBrandList = []
+        }
+      })
+    },
+    //  产品分类  列表
+    getProductType () {
+      dealerProductTypeList({}).then(res => {
+        if (res.status == 200) {
+          this.productTypeList = res.data
+        } else {
+          this.productTypeList = []
+        }
+      })
+    },
+    //  产品分类  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] : ''
     }
   }
 }

+ 433 - 0
src/views/salesManagement/salesReturn/chooseCustomModal.vue

@@ -0,0 +1,433 @@
+<template>
+  <a-modal
+    v-model="opened"
+    :title="title"
+    centered
+    :maskClosable="false"
+    :confirmLoading="confirmLoading"
+    width="80%"
+    :footer="null"
+    @cancel="cancel"
+  >
+    <a-form-model
+      id="chooseCustom-form"
+      ref="ruleForm"
+      :model="form"
+      :rules="rules"
+      :label-col="formItemLayout.labelCol"
+      :wrapper-col="formItemLayout.wrapperCol"
+    >
+      <a-row :gutter="15">
+        <a-col :span="8">
+          <a-form-model-item label="客户名称" prop="buyerSn">
+            <a-select
+              id="chooseCustom-buyerSn"
+              show-search
+              placeholder="请选择客户"
+              v-model="form.buyerSn"
+              :filter-option="filterOption"
+              @change="custChange">
+              <a-select-option v-for="item in custAllList" :key="item.id" :value="item.customerSn">{{ item.customerName }}</a-select-option>
+            </a-select>
+          </a-form-model-item>
+        </a-col>
+        <!-- <a-col :span="16">
+          <a-form-model-item>
+            <a-button type="primary" class="button-primary" @click="openNewCust" icon="plus">新增</a-button>
+            (点击新增按钮新增客户)
+          </a-form-model-item>
+        </a-col> -->
+      </a-row>
+      <a-row :gutter="15">
+        <a-col :span="16">
+          <a-form-model-item label="客户地址" required style="margin: 0;" :labelCol="{ span: 4 }" :wrapperCol="{ span: 20 }">
+            <a-row :gutter="15">
+              <!-- 客户地址 -->
+              <a-col span="8">
+                <a-form-model-item prop="provinceSn">
+                  <a-select id="chooseCustom-provinceSn" @change="getCityList" v-model="form.provinceSn" placeholder="请选择省">
+                    <a-select-option v-for="item in addrProvinceList" :value="item.id" :key="item.id + '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="chooseCustom-citySn" @change="getAreaList" v-model="form.citySn" placeholder="请选择市">
+                    <a-select-option v-for="item in addrCityList" :value="item.id" :key="item.id + '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="chooseCustom-countySn" @change="areaCharged" v-model="form.countySn" placeholder="请选择区/县">
+                    <a-select-option v-for="item in addrDistrictList" :value="item.id" :key="item.id + 'c'">{{ item.name }}</a-select-option>
+                  </a-select>
+                </a-form-model-item>
+              </a-col>
+            </a-row>
+          </a-form-model-item>
+        </a-col>
+        <a-col :span="8">
+          <a-form-model-item label="" prop="customerAddr">
+            <a-input
+              id="chooseCustom-customerAddr"
+              :maxLength="60"
+              v-model="form.customerAddr"
+              placeholder="请输入详细地址(最多60个字符)"
+              allowClear />
+          </a-form-model-item>
+        </a-col>
+      </a-row>
+      <a-row :gutter="15">
+        <a-col :span="8">
+          <a-form-model-item label="联系人" prop="consigneeName">
+            <a-input
+              id="chooseCustom-consigneeName"
+              :maxLength="30"
+              v-model="form.consigneeName"
+              placeholder="请输入联系人(最多30个字符)"
+              allowClear />
+          </a-form-model-item>
+        </a-col>
+        <a-col :span="8">
+          <a-form-model-item label="联系电话" prop="consigneeTel">
+            <a-input
+              id="chooseCustom-consigneeTel"
+              :maxLength="30"
+              v-model="form.consigneeTel"
+              placeholder="请输入联系电话(最多30个字符)"
+              allowClear />
+          </a-form-model-item>
+        </a-col>
+      </a-row>
+      <a-row :gutter="15">
+        <a-col :span="8">
+          <a-form-model-item label="是否抓单" prop="grabFlag">
+            <v-select code="FLAG" id="chooseCustom-grabFlag" v-model="form.grabFlag" allowClear placeholder="请选择"></v-select>
+          </a-form-model-item>
+        </a-col>
+        <a-col :span="8">
+          <a-form-model-item label="开单人">{{ $store.state.user.info.userNameCN }}</a-form-model-item>
+        </a-col>
+      </a-row>
+      <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-modal
+      v-model="isNewCust"
+      title="新增客户"
+      centered
+      width="60%"
+      :maskClosable="false"
+      @cancel="cancelNewCust"
+      :footer="null"
+    >
+      <CustomerManagementEdit ref="newCust" model="modal" @ok="newCustFun"></CustomerManagementEdit>
+    </a-modal>
+  </a-modal>
+</template>
+
+<script>
+import { getArea } from '@/api/data'
+import { custAllList, custFindById, updateByCustomerSn } from '@/api/customer'
+import { salesReturnSave } from '@/api/salesReturn'
+import { VSelect } from '@/components'
+import CustomerManagementEdit from '@/views/customerManagement/customerInfo/edit.vue'
+export default {
+  name: 'ChooseCustomModal',
+  components: { VSelect, CustomerManagementEdit },
+  props: {
+    show: [Boolean]
+  },
+  data () {
+    return {
+      opened: this.show,
+      title: '选择客户',
+      confirmLoading: false,
+      formItemLayout: {
+        labelCol: { span: 8 },
+        wrapperCol: { span: 16 }
+      },
+      buyerSnBak: '', // 更改前客户sn备份
+      form: {
+        buyerName: '', // 客户名称
+        buyerSn: undefined, // 客户sn
+        consigneeTel: '', //  联系电话
+        consigneeName: '', //  联系人
+        priceType: '', // 价格类型
+        provinceSn: undefined, //  省
+        provinceName: '',
+        citySn: undefined, // 市
+        cityName: '',
+        countySn: undefined, // 区
+        countyName: '',
+        customerAddr: '', //  详细地址
+        grabFlag: '1' // 是否抓单
+      },
+      rules: {
+        buyerSn: [
+          { required: true, message: '请选择客户', trigger: ['change', 'blur'] }
+        ],
+        consigneeTel: [
+          { required: true, message: '请输入联系电话', trigger: 'blur' }
+        ],
+        provinceSn: [
+          { required: true, message: '请选择省', trigger: 'change' }
+        ],
+        citySn: [
+          { required: true, message: '请选择市', trigger: 'change' }
+        ],
+        countySn: [
+          { required: true, message: '请选择区/县', trigger: 'change' }
+        ],
+        customerAddr: [
+          { required: true, message: '请输入详细地址', trigger: 'blur' }
+        ],
+        grabFlag: [
+          { required: true, message: '请选择是否铺货出库', trigger: 'change' }
+        ]
+      },
+      custAllList: [], //  客户 下拉数据
+      addrProvinceList: [], //  省下拉
+      addrCityList: [], //  市下拉
+      addrDistrictList: [], //  区下拉
+      custId: undefined, // 客户id
+      isEdit: false, //  是否编辑状态
+      isChangeCust: false, // 是否更换客户
+      interId: null,
+      isNewCust: false // 是否新增客户
+    }
+  },
+  methods: {
+    openNewCust () {
+      this.isNewCust = true
+      setTimeout(() => {
+        this.$refs.newCust.getBaseData()
+      }, 500)
+    },
+    // 新建客户
+    newCustFun (data) {
+      console.log(data, this.isEdit)
+      this.isNewCust = false
+      // 更新客户信息
+      this.custAllList.unshift(data)
+      setTimeout(() => {
+        this.custChange(data.customerSn)
+      }, 300)
+    },
+    cancelNewCust () {
+      this.isNewCust = false
+      this.$refs.newCust.getBaseData()
+    },
+    // 客户 change
+    custChange (val) {
+      console.log(val, 'custChange')
+      const _this = this
+      const cust = this.custAllList.find(item => item.customerSn == val)
+      // 编辑
+      if (this.isEdit) {
+        this.$confirm({
+          title: '提示',
+          content: '更换客户后信息需要重新完善,确认要更换吗?',
+          centered: true,
+          onOk () {
+            _this.custId = cust.id
+            _this.form.buyerName = cust.customerName
+            _this.getDetail()
+          },
+          onCancel () {
+            _this.form.buyerSn = _this.buyerSnBak
+          }
+        })
+      } else {
+        _this.custId = cust.id
+        _this.form.buyerName = cust.customerName
+        _this.getDetail()
+      }
+    },
+    // 编辑客户信息
+    editCust (data) {
+      console.log(data)
+      this.title = '编辑客户信息'
+      this.isEdit = true
+      if (data.provinceSn) { this.getArea('city', data.provinceSn) }
+      if (data.citySn) { this.getArea('district', data.citySn) }
+      this.form = Object.assign(this.form, data)
+      this.buyerSnBak = this.form.buyerSn
+    },
+    //  获取详情
+    getDetail () {
+      custFindById({ id: this.custId }).then(res => {
+        const data = res.data
+        if (res.status == 200 && data) {
+          if (data.provinceSn) { this.getArea('city', data.provinceSn) }
+          if (data.citySn) { this.getArea('district', data.citySn) }
+          this.form = Object.assign(this.form, {
+            buyerName: data.customerName, // 客户名称
+            buyerSn: data.customerSn, // 客户sn
+            consigneeTel: data.contactTel, //  联系电话
+            consigneeName: data.contactName, //  联系人
+            provinceSn: data.provinceSn, //  省
+            provinceName: data.provinceName,
+            priceType: data.priceType,
+            citySn: data.citySn, // 市
+            cityName: data.cityName,
+            countySn: data.countySn, // 区
+            countyName: data.countyName,
+            customerAddr: data.customerAddr, //  详细地址
+            fax: data.fax //  客户传真
+          })
+        } else {
+          this.$message.error('获取客户信息失败')
+          this.$refs.ruleForm.resetFields()
+        }
+        this.$refs.ruleForm.clearValidate()
+      })
+    },
+    // 保存客户信息
+    handleSaveCust () {
+      const params = {
+        customerName: this.form.buyerName,
+        customerSn: this.form.buyerSn,
+        contactTel: this.form.consigneeTel, //  联系电话
+        contactName: this.form.consigneeName, //  联系人
+        provinceSn: this.form.provinceSn, //  省
+        provinceName: this.form.provinceName,
+        priceType: this.form.priceType,
+        citySn: this.form.citySn, // 市
+        cityName: this.form.cityName,
+        countySn: this.form.countySn, // 区
+        countyName: this.form.countyName,
+        customerAddr: this.form.customerAddr //  详细地址
+      }
+      updateByCustomerSn(params).then(res => {
+        if (res.status != 200) {
+          this.$message.error(res.message)
+        }
+      })
+    },
+    //  保存
+    handleSubmit (e) {
+      e.preventDefault()
+      const _this = this
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          // 保存客户信息
+          _this.handleSaveCust()
+          // 保存销售单
+          if (_this.form.buyerSn) {
+            _this.salesSaveFun()
+          }
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    },
+    // 新建或编辑销售单
+    salesSaveFun () {
+      const _this = this
+      const form = this.form
+      console.log(form, 'save data')
+      salesReturnSave(form).then(res => {
+        if (res.status == 200) {
+          _this.$message.success(res.message)
+          _this.$emit('ok', res.data)
+          _this.cancel()
+        }
+      })
+    },
+    cancel () {
+      this.opened = false
+      this.$refs.ruleForm.resetFields()
+      this.$emit('cancel')
+    },
+    // 客户无分页列表数据
+    getCustAllList () {
+      const _this = this
+      custAllList().then(res => {
+        if (res.status == 200) {
+          _this.custAllList = res.data || []
+        } else {
+          _this.custAllList = []
+        }
+      })
+    },
+    // 获取城市列表
+    getCityList (val) {
+      console.log(val, '-------------')
+      this.addrCityList = []
+      this.addrDistrictList = []
+      this.form.citySn = undefined
+      this.form.cityName = ''
+      this.form.countySn = undefined
+      this.form.countyName = ''
+      this.form.customerAddr = ''
+      this.form.countyName = this.addrProvinceList.find(item => item.id == val).name
+      this.getArea('city', val)
+    },
+    // 获取区县列表
+    getAreaList (val) {
+      this.addrDistrictList = []
+      this.form.countySn = undefined
+      this.form.countyName = ''
+      this.form.customerAddr = ''
+      this.form.cityName = this.addrCityList.find(item => item.id == val).name
+      this.getArea('district', val)
+    },
+    // 区县变更
+    areaCharged (val) {
+      this.form.customerAddr = ''
+      this.form.countyName = this.addrDistrictList.find(item => item.id == val).name
+    },
+    //  省/市/区
+    getArea (type, sn) {
+      let params
+      if (type == 'province') {
+        params = { level: '1' }
+      } else {
+        params = { psn: sn }
+      }
+      getArea(params).then(res => {
+        if (res.status == 200) {
+          if (type == 'province') {
+            this.addrProvinceList = res.data || []
+          } else if (type == 'city') {
+            this.addrCityList = res.data || []
+          } else if (type == 'district') {
+            this.addrDistrictList = res.data || []
+          }
+        } else {
+          if (type == 'province') {
+            this.addrProvinceList = []
+          } else if (type == 'city') {
+            this.addrCityList = []
+          } else if (type == 'district') {
+            this.addrDistrictList = []
+          }
+        }
+      })
+    },
+    filterOption (input, option) {
+      return (
+        option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
+      )
+    }
+  },
+  watch: {
+    show (newValue, oldValue) {
+      this.opened = newValue
+      if (newValue) {
+        this.getArea('province')
+        this.getCustAllList()
+      }
+    }
+  }
+}
+</script>
+
+<style>
+</style>

+ 139 - 0
src/views/salesManagement/salesReturn/detail.vue

@@ -0,0 +1,139 @@
+<template>
+  <div class="salesReturnDetail-wrap">
+    <a-page-header :ghost="false" :backIcon="false" class="salesReturnDetail-cont">
+      <template slot="subTitle">
+        <a href="javascript:;" @click="handleBack"><a-icon type="left"></a-icon> 返回列表</a>
+      </template>
+      <template slot="extra">
+        <a-button key="3" id="salesReturnDetail-preview-btn">打印预览</a-button>
+        <a-button key="4" type="primary" id="salesReturnDetail-print-btn">快速打印</a-button>
+        <a-button key="5" id="salesReturnDetail-export-btn">导出</a-button>
+      </template>
+    </a-page-header>
+    <!-- 基础信息 -->
+    <a-card size="small" :bordered="false" class="salesReturnDetail-cont">
+      <a-collapse :activeKey="['1']">
+        <a-collapse-panel key="1" header="基础信息">
+          <a-descriptions size="small" :column="3" v-if="detailData">
+            <a-descriptions-item label="客户名称">{{ detailData.buyerName || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="客户地址">{{ detailData.provinceName || '--' }}{{ detailData.cityName || '--' }}{{ detailData.countyName || '--' }}{{ detailData.customerAddr || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="联系电话">{{ detailData.contactTel || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="备注">{{ detailData.remarks || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="退货单号">{{ detailData.salesReturnNo || '--' }}</a-descriptions-item>
+            <a-descriptions-item label="业务状态">{{ detailData.stateDictValue || '--' }}</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: 15px;" v-if="detailData">
+        <div slot="message">
+          总款数:<strong>{{ countData.totalCategory || 0 }}</strong>;总数量:<strong>{{ countData.totalQty || 0 }}</strong>;废品数量:<strong>{{ countData.totalCelQty || 0 }}</strong>;<br/>
+          退货总金额:<strong>{{ countData.totalAmount || 0 }}</strong>;折扣金额:<strong>{{ countData.discountAmount || 0 }}</strong>;折扣:<strong>{{ countData.discountRate || 0 }}%</strong>;折后金额:<strong>{{ countData.discountedAmount || 0 }}</strong>;
+        </div>
+      </a-alert>
+      <!-- 列表 -->
+      <s-table
+        class="sTable"
+        ref="table"
+        size="default"
+        :rowKey="(record) => record.id"
+        :columns="columns"
+        :data="loadData"
+        :scroll="{ x: 1430 }"
+        bordered>
+      </s-table>
+    </a-card>
+  </div>
+</template>
+
+<script>
+import { getOperationalPrecision } from '@/libs/tools.js'
+import { STable, VSelect } from '@/components'
+import { salesReturnDetail, salesReturnQueryCount, salesReturnDetailList } from '@/api/salesReturn'
+export default {
+  name: 'SalesReturnDetail',
+  components: { STable, VSelect },
+  data () {
+    return {
+      disabled: false,
+      countData: null,
+      // 表头
+      columns: [
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center', fixed: 'left' },
+        { title: '产品编码', dataIndex: 'productCode', width: 140, align: 'center' },
+        { title: '产品名称', dataIndex: 'productName', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '原厂编码', dataIndex: 'productOrigCode', width: 140, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '售价', dataIndex: 'price', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '折后售价', dataIndex: 'discountedPrice', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '退货数量', dataIndex: 'qty', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '废品数量', dataIndex: 'celQty', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '入库数量', dataIndex: 'rkqty', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '退货金额小计', dataIndex: 'saleReturnSubtotal', width: 120, align: 'center' },
+        { title: '折扣金额', dataIndex: 'discountAmount', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '折后退货金额小计', dataIndex: 'discountedAmount', width: 150, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        const params = Object.assign(parameter, { salesReturnBillSn: this.$route.params.sn })
+        this.getQueryCount(params)
+        return salesReturnDetailList(params).then(res => {
+          const 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
+            const productCode = (data.list[i].productEntity && data.list[i].productEntity.code) || (data.list[i].dealerProductEntity && data.list[i].dealerProductEntity.code)
+            const productName = (data.list[i].productEntity && data.list[i].productEntity.name) || (data.list[i].dealerProductEntity && data.list[i].dealerProductEntity.name)
+            const productOrigCode = (data.list[i].productEntity && data.list[i].productEntity.origCode) || (data.list[i].dealerProductEntity && data.list[i].dealerProductEntity.origCode)
+            data.list[i].productCode = productCode || '--'
+            data.list[i].productName = productName || '--'
+            data.list[i].productOrigCode = productOrigCode || '--'
+            // 退货数量和入库数量取值同一个字段,因表格使用统一字段会报错,因此重新定义
+            data.list[i].rkqty = data.list[i].qty || 0
+            // 折后退货金额小计  由于数据库内小数位数为4位,页面则需显示2位。因此会做小数运算精度处理
+            data.list[i].saleReturnSubtotal = getOperationalPrecision(data.list[i].price, data.list[i].qty)
+          }
+          this.disabled = false
+          return data
+        })
+      },
+      detailData: null //  详情数据
+    }
+  },
+  methods: {
+    //  返回
+    handleBack () {
+      this.$router.push({ name: 'salesReturnList' })
+    },
+    // 明细统计
+    getQueryCount (params) {
+      salesReturnQueryCount(params).then(res => {
+        this.countData = res.data || null
+      })
+    },
+    //  详情
+    getDetail () {
+      salesReturnDetail({ sn: this.$route.params.sn }).then(res => {
+        if (res.status == 200) {
+          this.detailData = res.data
+        } else {
+          this.detailData = null
+        }
+      })
+    }
+  },
+  mounted () {
+    this.getDetail()
+  }
+}
+</script>
+
+<style lang="less">
+  .salesReturnDetail-wrap{
+    .salesReturnDetail-cont{
+      margin-bottom: 15px;
+    }
+  }
+</style>

+ 313 - 0
src/views/salesManagement/salesReturn/list.vue

@@ -0,0 +1,313 @@
+<template>
+  <a-card size="small" :bordered="false" class="salesReturn-wrap">
+    <!-- 搜索条件 -->
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline">
+        <a-row :gutter="15">
+          <a-col :md="6" :sm="24">
+            <a-form-item label="创建时间">
+              <a-range-picker
+                style="width:100%"
+                id="salesReturn-creatDate"
+                :disabledDate="disabledDate"
+                v-model="createDate"
+                :format="dateFormat"
+                :placeholder="['开始时间', '结束时间']" />
+            </a-form-item>
+          </a-col>
+          <a-col :md="6" :sm="24">
+            <a-form-item label="审核时间">
+              <a-range-picker
+                style="width:100%"
+                id="salesReturn-examineTime"
+                :disabledDate="disabledDate"
+                v-model="examineTime"
+                :format="dateFormat"
+                :placeholder="['开始时间', '结束时间']" />
+            </a-form-item>
+          </a-col>
+          <a-col :md="6" :sm="24">
+            <a-form-item label="客户名称" :label-col="{ span:7 }" :wrapper-col="{ span:17}">
+              <a-select
+                id="salesReturn-buyerSn"
+                placeholder="请选择客户"
+                allowClear
+                v-model="queryParam.buyerSn"
+                :showSearch="true"
+                option-filter-prop="children"
+                :filter-option="filterOption">
+                <a-select-option v-for="item in custAllList" :key="item.customerSn" :value="item.customerSn">{{ item.customerName }}</a-select-option>
+              </a-select>
+            </a-form-item>
+          </a-col>
+          <template v-if="advanced">
+            <a-col :md="6" :sm="24">
+              <a-form-item label="退货单号">
+                <a-input id="salesReturn-salesReturnNo" v-model.trim="queryParam.salesReturnNo" allowClear placeholder="请输入退货单号"/>
+              </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_RETURN_BILL_STATUS"
+                  placeholder="请选择业务状态"
+                  allowClear></v-select>
+              </a-form-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 @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" @click="openModal = true">新增</a-button>
+    </div>
+    <!-- alert -->
+    <a-alert type="info" style="margin-bottom: 15px;">
+      <div slot="message">
+        退货总金额:<strong>{{ countData&&countData.totalAmount }}</strong>元;
+        总单数:<strong>{{ countData&&countData.totalBillNumber }}</strong>;
+        总款数:<strong>{{ countData&&countData.totalCategory }}</strong>;
+        总数量:<strong>{{ countData&&countData.totalQty }}</strong>;
+      </div>
+    </a-alert>
+    <!-- 列表 -->
+    <s-table
+      class="sTable"
+      ref="table"
+      size="default"
+      :rowKey="(record) => record.id"
+      :columns="columns"
+      :data="loadData"
+      :scroll="{ x: 1810, y: tableHeight }"
+      bordered>
+      <!-- 单号 -->
+      <template slot="salesReturnNo" slot-scope="text, record">
+        <span style="color: #ed1c24;cursor: pointer;" @click="handleDetail(record)">{{ record.salesReturnNo }}</span>
+      </template>
+      <!-- 财务状态 -->
+      <template slot="financialStatus" slot-scope="text, record">
+        <a-badge :color="text=='FINISH'?'#87d068':'gold'" :text="record.settleStateDictValue" />
+      </template>
+      <!-- 操作 -->
+      <template slot="action" slot-scope="text, record">
+        <a-button
+          size="small"
+          type="link"
+          class="button-warning"
+          v-if="record.state == 'WAIT_AUDIT'"
+          @click="handleEexamine(record)"
+          id="salesReturn-eexamine-btn">审核</a-button>
+        <a-button
+          size="small"
+          v-if="record.state == 'WAIT_AUDIT'||record.state == 'WAIT_SUBMIT'"
+          type="link"
+          class="button-info"
+          @click="handleEdit(record)"
+          id="salesReturn-edit-btn">编辑</a-button>
+        <a-button
+          size="small"
+          v-if="record.state == 'WAIT_AUDIT'||record.state == 'WAIT_SUBMIT'"
+          type="link"
+          class="button-error"
+          @click="handleDel(record)"
+          id="salesReturn-del-btn">删除</a-button>
+        <span v-if="record.state == 'FINISH'">--</span>
+      </template>
+    </s-table>
+    <!-- 选择客户弹框 -->
+    <choose-custom-modal :show="openModal" @ok="handleEdit" @cancel="openModal=false"></choose-custom-modal>
+  </a-card>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import chooseCustomModal from './chooseCustomModal.vue'
+import { custAllList } from '@/api/customer'
+import { salesReturnList, salesReturnQueryCount, salesReturnAudit, salesReturnDel } from '@/api/salesReturn'
+import moment from 'moment'
+export default {
+  name: 'TableList',
+  components: {
+    STable,
+    VSelect,
+    chooseCustomModal
+  },
+  data () {
+    return {
+      tableHeight: 0,
+      // 高级搜索 展开/关闭
+      advanced: false,
+      disabled: false, //  查询、重置按钮是否可操作
+      dateFormat: 'YYYY-MM-DD',
+      createDate: [], //  创建时间
+      examineTime: [], //  审核时间
+      openModal: false, // 选择客户弹框是否显示
+      custAllList: [], //  客户下拉数据
+      // 查询参数
+      queryParam: {
+        buyerSn: undefined, //  客户名称
+        salesReturnNo: undefined, //  销售退货单号
+        billStatus: undefined, // 业务状态
+        beginDate: undefined,
+        endDate: undefined,
+        auditBeginDate: undefined,
+        auditEndDate: undefined
+      },
+      countData: null, // 统计数据
+      // 表头
+      columns: [
+        { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
+        { title: '创建时间', dataIndex: 'createDate', width: 160, align: 'center' },
+        { title: '销售退货单号', scopedSlots: { customRender: 'salesReturnNo' }, width: 260, align: 'center' },
+        { title: '客户名称', dataIndex: 'buyerName', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '退款总金额', dataIndex: 'totalAmount', width: 110, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '总款数', dataIndex: 'totalCategory', width: 110, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '总数量', dataIndex: 'totalQty', width: 110, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '是否抓单', dataIndex: 'grabFlag', width: 100, align: 'center', customRender: function (text) { return ['否', '是'][text] } },
+        { title: '审核时间', dataIndex: 'auditTime', width: 160, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '业务状态', dataIndex: 'stateDictValue', width: 110, align: 'center' },
+        { title: '财务状态', dataIndex: 'settleStateDictValue', scopedSlots: { customRender: 'financialStatus' }, width: 110, align: 'center' },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: 220, align: 'center', fixed: 'right' }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        if (this.tableHeight == 0) {
+          this.tableHeight = window.innerHeight - 440
+        }
+        // 创建时间
+        if (this.createDate && this.createDate.length > 0) {
+          this.queryParam.beginDate = moment(this.createDate[0]).format(this.dateFormat)
+          this.queryParam.endDate = moment(this.createDate[1]).format(this.dateFormat)
+        } else {
+          this.queryParam.beginDate = undefined
+          this.queryParam.endDate = undefined
+        }
+        // 审核时间
+        if (this.examineTime && this.examineTime.length > 0) {
+          this.queryParam.auditBeginDate = moment(this.examineTime[0]).format(this.dateFormat)
+          this.queryParam.auditEndDate = moment(this.examineTime[1]).format(this.dateFormat)
+        } else {
+          this.queryParam.auditBeginDate = undefined
+          this.queryParam.auditEndDate = undefined
+        }
+        // 查询总计
+        this.getQueryCount(Object.assign(parameter, this.queryParam))
+        return salesReturnList(Object.assign(parameter, this.queryParam)).then(res => {
+          const 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
+          return data
+        })
+      }
+    }
+  },
+  methods: {
+    // 不可选日期
+    disabledDate (date, dateStrings) {
+      return date && date.valueOf() > Date.now()
+    },
+    // 列表统计
+    getQueryCount (params) {
+      salesReturnQueryCount(params).then(res => {
+        this.countData = res.data || null
+      })
+    },
+    // 编辑
+    handleEdit (row) {
+      console.log(row)
+      this.$router.push({ name: row.grabFlag == 1 ? 'salesReturnGrabEdit' : 'salesReturnEdit', params: { id: row.id, sn: row.salesReturnSn, buyerSn: row.buyerSn } })
+    },
+    // 详情
+    handleDetail (row) {
+      this.$router.push({ name: 'salesReturnDetail', params: { id: row.id, sn: row.salesReturnSn } })
+    },
+    // 删除
+    handleDel (row) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确认要删除吗?',
+        centered: true,
+        onOk () {
+          salesReturnDel({ sn: row.salesReturnSn }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$refs.table.refresh()
+            }
+          })
+        }
+      })
+    },
+    //  审核
+    handleEexamine (row) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确认要审核吗?',
+        centered: true,
+        onOk () {
+          salesReturnAudit({
+            sn: row.salesReturnSn
+          }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$refs.table.refresh()
+            }
+          })
+        }
+      })
+    },
+    resetSearchForm () {
+      this.queryParam.buyerSn = undefined
+      this.queryParam.salesReturnNo = ''
+      this.queryParam.billStatus = ''
+      this.queryParam.beginDate = undefined
+      this.endDate = undefined
+      this.auditBeginDate = undefined
+      this.auditEndDate = undefined
+      this.createDate = []
+      this.examineTime = []
+      this.$refs.table.refresh(true)
+    },
+    // 客户无分页列表数据
+    getCustAllList () {
+      const _this = this
+      custAllList().then(res => {
+        if (res.status == 200) {
+          _this.custAllList = res.data || []
+        } else {
+          _this.custAllList = []
+        }
+      })
+    },
+    filterOption (input, option) {
+      return (
+        option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
+      )
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      vm.getCustAllList()
+    })
+  }
+}
+</script>

+ 278 - 0
src/views/salesManagement/salesReturn/queryPart.vue

@@ -0,0 +1,278 @@
+<template>
+  <div class="productInfoList-wrap">
+    <!-- 搜索条件 -->
+    <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="审核时间">
+              <a-range-picker v-model="shDate" id="salesReturn-shDate"/>
+            </a-form-item>
+          </a-col>
+          <a-col :md="6" :sm="24">
+            <a-form-item label="产品编码">
+              <a-input id="productInfoList-productCode" 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-productName" 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-salesBillNo" v-model.trim="queryParam.salesBillNo" allowClear placeholder="请输入销售单号"/>
+              </a-form-item>
+            </a-col>
+          </template>
+          <a-col :md="6" :sm="24">
+            <a-button style="margin-bottom: 18px;" type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="productInfoList-refresh">查询</a-button>
+            <a-button style="margin: 0 0 18px 8px" @click="resetSearchForm" :disabled="disabled" id="productInfoList-reset">重置</a-button>
+            <a @click="advanced=!advanced" style="margin:0 15px 0 8px">
+              {{ advanced ? '收起' : '展开' }}
+              <a-icon :type="advanced ? 'up' : 'down'"/>
+            </a>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+    <!-- 列表 -->
+    <s-table
+      class="sTable"
+      ref="table"
+      size="default"
+      :rowKey="(record) => record.id"
+      :columns="columns"
+      :data="loadData"
+      :customRow="handleClickRow"
+      :defaultLoadData="false"
+      :scroll="{ x: grabFlag == '1' ? 1700 : 860, y: 300 }"
+      bordered>
+      <!-- 价格 -->
+      <template slot="price" slot-scope="text, record">
+        ¥ {{ text }}
+      </template>
+      <span slot="customTitle">
+        操作
+        <a-popover>
+          <template slot="content">
+            双击列表配件可快速选中添加
+          </template>
+          <a-icon type="question-circle" theme="twoTone" />
+        </a-popover>
+      </span>
+      <!-- 操作 -->
+      <template slot="action" slot-scope="text, record">
+        <a-button
+          size="small"
+          type="primary"
+          class="button-info"
+          :loading="newLoading"
+          @click="handleAdd(record)"
+        >添加</a-button>
+      </template>
+    </s-table>
+  </div>
+</template>
+
+<script>
+import { salesReturnProductList } from '@/api/salesReturn'
+import { querySumByProductLocation } from '@/api/stock'
+import { STable, VSelect } from '@/components'
+import moment from 'moment'
+export default {
+  name: 'QueryPart',
+  components: { STable, VSelect },
+  props: {
+    buyerSn: {
+      type: [Number, String],
+      default: ''
+    },
+    newLoading: Boolean,
+    grabFlag: [Number, String],
+    priceType: [Number, String]
+  },
+  data () {
+    return {
+      advanced: false, // 高级搜索 展开/关闭
+      shDate: [],
+      dateFormat: 'YYYY-MM-DD',
+      queryParam: { //  查询条件
+        salesBillNo: '', //  销售单号
+        productName: '', // 产品名称
+        productCode: '' //  产品编码
+      },
+      disabled: false, //  查询、重置按钮是否可操作
+      exportLoading: false, // 导出loading
+      brandData: [], //  下拉数据
+      typeData: [], //  产品类别  下拉数据
+      columns: [],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        // 抓单时
+        if (this.grabFlag == 1) {
+          this.queryParam.buyerSn = this.buyerSn
+        }
+        // 创建时间
+        if (this.shDate && this.shDate.length > 0) {
+          this.queryParam.beginDate = moment(this.shDate[0]).format(this.dateFormat)
+          this.queryParam.endDate = moment(this.shDate[1]).format(this.dateFormat)
+        } else {
+          this.queryParam.beginDate = undefined
+          this.queryParam.endDate = undefined
+        }
+        const fun = [querySumByProductLocation, salesReturnProductList]
+        if (this.grabFlag == 0) {
+          this.queryParam.salePriceType = this.priceType
+        }
+        return fun[this.grabFlag](Object.assign(parameter, this.queryParam)).then(res => {
+          const 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
+          return data
+        })
+      }
+    }
+  },
+  mounted () {
+    // 抓单
+    if (this.grabFlag == 1) {
+      this.columns = [{
+        title: '序号',
+        dataIndex: 'no',
+        align: 'center',
+        width: 100
+      },
+      {
+        title: '产品编码',
+        dataIndex: 'dealerProductEntity.code',
+        align: 'center',
+        sorter: true,
+        width: 160
+      },
+      {
+        title: '产品名称',
+        dataIndex: 'dealerProductEntity.name',
+        align: 'center'
+      },
+      {
+        title: '原厂编码',
+        dataIndex: 'dealerProductEntity.origCode',
+        align: 'center',
+        customRender: function (text) { return text || '--' },
+        width: 120
+      },
+      {
+        title: '销售单号',
+        dataIndex: 'salesBillNo',
+        align: 'center',
+        width: 160
+      },
+      {
+        title: '销售审核时间',
+        dataIndex: 'auditTime',
+        align: 'center',
+        customRender: function (text) { return text || '--' },
+        width: 120
+      },
+      {
+        title: '售价',
+        dataIndex: 'price',
+        align: 'center',
+        width: 120,
+        scopedSlots: { customRender: 'price' }
+      },
+      {
+        title: '单位',
+        dataIndex: 'dealerProductEntity.unit',
+        align: 'center',
+        width: 100
+      },
+      {
+        title: '销售数量',
+        dataIndex: 'qty',
+        align: 'center',
+        width: 100
+      },
+      {
+        title: '已退数量',
+        dataIndex: 'hasReturnQty',
+        align: 'center',
+        width: 120
+      },
+      { slots: { title: 'customTitle' }, scopedSlots: { customRender: 'action' }, width: 100, align: 'center', fixed: 'right' }]
+    } else {
+      this.columns = [{
+        title: '序号',
+        dataIndex: 'no',
+        align: 'center',
+        width: 100
+      },
+      {
+        title: '产品编码',
+        dataIndex: 'productCode',
+        align: 'center',
+        sorter: true,
+        width: 160
+      },
+      {
+        title: '产品名称',
+        dataIndex: 'productName',
+        align: 'center'
+      },
+      {
+        title: '原厂编码',
+        dataIndex: 'productOrigCode',
+        align: 'center',
+        customRender: function (text) { return text || '--' },
+        width: 160
+      },
+      {
+        title: '售价',
+        dataIndex: 'salePrice',
+        align: 'center',
+        width: 120,
+        scopedSlots: { customRender: 'price' }
+      },
+      {
+        title: '单位',
+        dataIndex: 'unit',
+        align: 'center',
+        customRender: function (text) { return text || '--' },
+        width: 120
+      },
+      { slots: { title: 'customTitle' }, scopedSlots: { customRender: 'action' }, width: 100, align: 'center' }]
+    }
+  },
+  methods: {
+    // 双击列表选择配件
+    handleClickRow (record) {
+      const _this = this
+      return {
+        on: {
+          dblclick: (event) => {
+            event.stopPropagation()
+            _this.$emit('add', record)
+          }
+        }
+      }
+    },
+    //  重置
+    resetSearchForm () {
+      this.queryParam.salesBillNo = ''
+      this.queryParam.productName = ''
+      this.queryParam.productCode = ''
+      this.$refs.table.refresh(true)
+    },
+    // 选择配件
+    handleAdd (row) {
+      this.$emit('add', row, 'new')
+    }
+  }
+}
+</script>

+ 529 - 0
src/views/salesManagement/salesReturn/salesReturnEdit.vue

@@ -0,0 +1,529 @@
+<template>
+  <div>
+    <a-affix :target="() => this.$refs.container">
+      <a-page-header
+        :ghost="false"
+        @back="handleBack"
+        :backIcon="false"
+      >
+        <template slot="subTitle">
+          <a id="back-btn" href="javascript:;" @click="handleBack"><a-icon type="left" /> 返回列表</a>
+          <span style="margin: 0 15px;color: #666;">客户名称:{{ ordeDetail&&ordeDetail.buyerName }}</span>
+          <!-- <a-button size="small" @click="handleEditCustom" style="margin-left:50px" key="0">
+            编辑
+          </a-button> -->
+        </template>
+        <template slot="extra">
+          <a-button key="2">
+            打印预览
+          </a-button>
+          <a-button key="1" type="primary">
+            快速打印
+          </a-button>
+        </template>
+      </a-page-header>
+    </a-affix>
+
+    <a-card size="small" :bordered="false" class="pages-wrap">
+      <!-- 查询配件列表 -->
+      <queryPart :buyerSn="$route.params.buyerSn" :priceType="ordeDetail.priceType" grabFlag="0" :newLoading="isInster" @add="saveProduct"></queryPart>
+    </a-card>
+    <a-card size="small" :bordered="false" class="pages-wrap">
+      <!-- alert -->
+      <a-alert style="margin-bottom: 15px;" type="info">
+        <div slot="message" class="total-bar">
+          <div>
+            <span>退货总金额:{{ countData&&countData.totalAmount }}元;</span>
+            <span>总款数:{{ countData&&countData.totalCategory }};</span>
+            <span>总数量:{{ countData&&countData.totalQty }};</span>
+            <span>废品总数量:{{ countData&&countData.totalCelQty }};</span>
+          </div>
+          <div>
+            <div>
+              折扣金额:
+              <a-input-number id="discount" v-model="ordeDetail.discountAmount" :min="0" :precision="2" :max="999999"/>
+              <a-button type="primary" @click="salesReturnDiscount" class="button-info">打折</a-button>
+            </div>
+            <div>
+              折扣:<strong>{{ ordeDetail&&ordeDetail.discountRate || 0 }}%</strong>;
+              折后总售价:<strong>¥{{ ordeDetail&&ordeDetail.discountedAmount || 0 }}</strong>;
+            </div>
+          </div>
+        </div>
+      </a-alert>
+      <!-- 查询条件 -->
+      <a-row :gutter="15">
+        <a-col :span="18">
+          <a-form-model layout="inline" :model="productForm">
+            <a-form-model-item label="产品编码">
+              <a-input v-model="productForm.productCode" placeholder="输入产品编码" />
+            </a-form-model-item>
+            <a-form-model-item label="产品名称">
+              <a-input v-model="productForm.productName" placeholder="输入产品名称" />
+            </a-form-model-item>
+            <a-form-model-item>
+              <a-button style="margin-bottom: 18px;" type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="salesReturn-refresh">查询</a-button>
+              <a-button style="margin: 0 0 18px 8px" @click="resetForm" id="salesReturn-reset">重置</a-button>
+            </a-form-model-item>
+          </a-form-model>
+        </a-col>
+        <a-col :span="6">
+          <div style="float:right;overflow: hidden;">
+            <a-button id="salesReturn-dru">导入明细</a-button>
+            <a-button
+              size="small"
+              type="primary"
+              @click="salesReturnDelAll"
+              :loading="delLoading"
+              style="margin-left: 10px"
+              id="salesReturn-del-all">整单删除</a-button>
+          </div>
+        </a-col>
+      </a-row>
+      <!-- 已选配件列表 -->
+      <s-table
+        class="sTable"
+        ref="table"
+        size="default"
+        :rowKey="(record) => record.id"
+        :columns="columns"
+        :data="loadData"
+        :scroll="{ x: 1500, y: 300 }"
+        bordered>
+        <!-- 本次退货数量 -->
+        <template slot="qty" slot-scope="text, record">
+          <editable-cell
+            size="small"
+            :text="record.qty"
+            :max="999999"
+            :min="0"
+            :precision="0"
+            @change="onCellChange(record.id, 'qty', $event)" />
+        </template>
+        <!-- 废品数量 -->
+        <template slot="celQty" slot-scope="text, record">
+          <editable-cell
+            size="small"
+            :text="record.celQty"
+            :max="999999"
+            :min="0"
+            :precision="0"
+            @change="onCellChange(record.id, 'celQty', $event)" />
+        </template>
+        <!-- 价格 -->
+        <template slot="price" slot-scope="text, record">
+          <editable-cell
+            size="small"
+            :text="text"
+            :max="999999"
+            :min="0"
+            :precision="2"
+            punit="¥"
+            @change="onCellChange(record.id, 'price', $event)" />
+        </template>
+        <!-- 退货金额小计 -->
+        <template slot="returnAmount" slot-scope="text, record">
+          ¥{{ (record.price * record.qty).toFixed(2) }}
+        </template>
+        <!-- 仓库仓位 -->
+        <template slot="warehouse" slot-scope="text, record, index">
+          <a-cascader
+            @change="e => changeWarehouseCascade(e, record, index)"
+            v-model="record.warehouseCascade"
+            expand-trigger="hover"
+            :options="warehouseCascadeData"
+            :fieldNames="{ label: 'name', value: 'sn', children: 'warehouseLocationList' }"
+            id="bulkWarehousingOrderEdit-warehouseCascade"
+            placeholder="请选择仓库仓位"
+            style="width: 100%;" />
+        </template>
+        <!-- 操作 -->
+        <template slot="action" slot-scope="text, record">
+          <a-button
+            size="small"
+            type="primary"
+            :loading="delLoading"
+            class="button-error"
+            @click="handleDel(record)"
+            id="salesReturn-Del">删除</a-button>
+        </template>
+      </s-table>
+    </a-card>
+    <a-affix :offset-bottom="0">
+      <div
+        style="text-align: center;width: 100%;background-color: #fff;padding: 12px 0;box-shadow: 0 0 20px #dcdee2;">
+        <a-button
+          size="large"
+          style="width: 150px;"
+          type="primary"
+          class="button-primary"
+          @click="handleSubmit()"
+          id="salesReturn-handleSubmit">提交</a-button>
+      </div>
+    </a-affix>
+    <!-- 选择客户弹框 -->
+    <choose-custom-modal :show="openModal" @ok="chooseCustomOk" @cancel="openModal=false"></choose-custom-modal>
+  </div>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import queryPart from './queryPart.vue'
+import EditableCell from '@/views/common/editInput.js'
+import chooseCustomModal from './chooseCustomModal.vue'
+import { warehouseCascadeList } from '@/api/warehouse'
+import { salesReturnDetail, salesReturnQueryCount, salesReturnDetailList, salesReturnDiscount, salesReturnDelAll, salesReturnDetailDel, salesReturnSaveProduct, salesReturnSubmit } from '@/api/salesReturn'
+export default {
+  name: 'SalesDetail',
+  components: {
+    STable,
+    VSelect,
+    queryPart,
+    EditableCell,
+    chooseCustomModal
+  },
+  data () {
+    return {
+      orderId: null,
+      orderSn: null,
+      buyerSn: null,
+      disabled: false,
+      openModal: false,
+      isInster: false, // 是否正在添加产品
+      ordeDetail: { discountAmount: 0 },
+      delLoading: false,
+      warehouseCascadeData: [], //  仓库仓位
+      // 已选产品
+      dataSource: [],
+      productForm: {
+        productCode: '',
+        productName: ''
+      },
+      countData: null,
+      // 表头
+      columns: [
+        {
+          title: '序号',
+          dataIndex: 'no',
+          align: 'center',
+          width: 100
+        },
+        {
+          title: '产品编码',
+          dataIndex: 'dealerProductEntity.code',
+          align: 'center',
+          width: 160
+        },
+        {
+          title: '产品名称',
+          dataIndex: 'dealerProductEntity.name',
+          align: 'center',
+          width: 200
+        },
+        {
+          title: '原厂编码',
+          dataIndex: 'dealerProductEntity.origCode',
+          align: 'center',
+          width: 160,
+          customRender: function (text) { return text || '--' }
+        },
+        {
+          title: '售价',
+          dataIndex: 'price',
+          align: 'center',
+          width: 150,
+          scopedSlots: { customRender: 'price' }
+        },
+        {
+          title: '单位',
+          dataIndex: 'dealerProductEntity.unit',
+          align: 'center',
+          width: 100
+        },
+        { title: '仓库仓位', scopedSlots: { customRender: 'warehouse' }, width: 200, align: 'center' },
+        {
+          title: '退货数量',
+          dataIndex: 'qty',
+          align: 'center',
+          width: 150,
+          scopedSlots: { customRender: 'qty' }
+        },
+        {
+          title: '废品数量',
+          dataIndex: 'celQty',
+          align: 'center',
+          width: 150,
+          scopedSlots: { customRender: 'celQty' }
+        },
+        {
+          title: '退货金额小计',
+          align: 'center',
+          scopedSlots: { customRender: 'returnAmount' },
+          width: 100
+        },
+        {
+          title: '折后金额小计',
+          dataIndex: 'discountedAmount',
+          align: 'center',
+          width: 100
+        },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: 100, align: 'center', fixed: 'right' }
+      ],
+      chooseLoadData: [],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        // 查询总计
+        this.productForm.salesReturnBillSn = this.$route.params.sn
+        this.getQueryCount(Object.assign(parameter, this.productForm))
+        return salesReturnDetailList(Object.assign(parameter, this.productForm)).then(res => {
+          const 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
+            const warehouseSn = data.list[i].warehouseSn || undefined
+            const warehouseLocationSn = data.list[i].warehouseLocationSn || undefined
+            if (warehouseSn || warehouseLocationSn) {
+              data.list[i].warehouseSnBackups = warehouseSn
+              data.list[i].warehouseLocationSnBackups = warehouseLocationSn
+              data.list[i].warehouseCascade = [warehouseSn, warehouseLocationSn]
+            } else {
+              data.list[i].warehouseCascade = undefined
+            }
+          }
+          this.disabled = false
+          this.chooseLoadData = data.list
+          return data
+        })
+      }
+    }
+  },
+  methods: {
+    //  返回
+    handleBack () {
+      this.$router.push({ name: 'salesReturnList' })
+    },
+    // 选择客户成功
+    chooseCustomOk (data) {
+
+    },
+    handleEditCustom () {
+      this.openModal = true
+    },
+    onCellChange (id, key, value) {
+      const chooseLoadData = [...this.chooseLoadData]
+      const row = chooseLoadData.find(item => item.id === id)
+      if (row) {
+        row[key] = Number(value)
+        if (row.celQty > row.qty) {
+          this.$message.info('废品数量不可大于本次退货数量')
+        } else {
+          this.saveProduct(row, 'edit')
+        }
+      }
+    },
+    //  仓库仓位  级联  列表
+    getWarehouseCascade () {
+      warehouseCascadeList({}).then(res => {
+        if (res.status == 200) {
+		  res.data.map(item => {
+		    item.sn = item.warehouseSn
+		    if (item.warehouseLocationList) {
+		  	item.warehouseLocationList.map(subItem => {
+		  	  subItem.sn = subItem.warehouseLocationSn
+		  	})
+		    }
+		  })
+          this.warehouseCascadeData = res.data
+        } else {
+          this.warehouseCascadeData = []
+        }
+      })
+    },
+    // 修改仓库仓位
+    changeWarehouseCascade (val, opt, ind) {
+      console.log(val, opt, ind)
+      let loadData = this.chooseLoadData[ind]
+      if (val.length < 2) {
+        this.$message.warning('当前仓库无仓位,请选择其他仓库')
+        const warehouseSnBackups = loadData.warehouseSnBackups || undefined
+        const warehouseLocationSnBackups = loadData.warehouseLocationSnBackups || undefined
+        loadData.warehouseSn = warehouseSnBackups
+        loadData.warehouseLocationSn = warehouseLocationSnBackups
+        if (warehouseSnBackups || warehouseLocationSnBackups) {
+          loadData.warehouseCascade = [warehouseSnBackups, warehouseLocationSnBackups]
+        } else {
+          loadData.warehouseCascade = undefined
+        }
+      } else {
+        loadData.warehouseSn = val[0] ? val[0] : ''
+        loadData.warehouseLocationSn = val[1] ? val[1] : ''
+        loadData.warehouseSnBackups = val[0] ? val[0] : ''
+        loadData.warehouseLocationSnBackups = val[1] ? val[1] : ''
+        loadData = this.chooseLoadData[ind]
+        console.log(loadData)
+        this.saveProduct(loadData, 'edit')
+      }
+    },
+    // 重置列表
+    resetForm () {
+      this.productForm = {
+        productName: '',
+        productCode: ''
+      }
+      this.$refs.table.refresh(true)
+    },
+    // 明细统计
+    getQueryCount (params) {
+      salesReturnQueryCount(params).then(res => {
+        this.countData = res.data || null
+      })
+    },
+    // 获取单据详细
+    getOrderDetail () {
+      salesReturnDetail({ sn: this.orderSn }).then(res => {
+        this.ordeDetail = res.data || null
+      })
+    },
+    // 打折
+    salesReturnDiscount () {
+      if (this.ordeDetail.discountAmount < 0) {
+        return
+      }
+      salesReturnDiscount({
+        discountAmount: this.ordeDetail.discountAmount,
+        salesReturnSn: this.ordeDetail.salesReturnSn,
+        id: this.ordeDetail.id
+      }).then(res => {
+        if (res.status == 200) {
+          this.resetSearchForm()
+        }
+      })
+    },
+    // 整单删除
+    salesReturnDelAll () {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确认要整单删除吗?',
+        centered: true,
+        closable: true,
+        onOk () {
+          _this.delLoading = true
+          salesReturnDelAll({ sn: _this.ordeDetail.salesReturnSn }).then(res => {
+            if (res.status == 200) {
+              _this.resetSearchForm()
+            }
+            _this.$message.info(res.message)
+            _this.delLoading = false
+          })
+        }
+      })
+    },
+    // 删除产品
+    handleDel (row) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确认要删除吗?',
+        centered: true,
+        closable: true,
+        onOk () {
+          _this.delLoading = true
+          salesReturnDetailDel({ id: row.id }).then(res => {
+            if (res.status == 200) {
+              _this.resetSearchForm(true)
+            }
+            _this.$message.info(res.message)
+            _this.delLoading = false
+          })
+        }
+      })
+    },
+    //  重置
+    resetSearchForm (flag) {
+      this.$refs.table.refresh(!!flag)
+      this.getOrderDetail()
+    },
+    // 添加或修改产品
+    saveProduct (row, type) {
+      console.log(row)
+      // 防止多次添加产品
+      if (this.isInster) {
+        return
+      }
+      this.isInster = true
+      const params = {
+        'salesReturnBillSn': this.orderSn,
+        'salesReturnBillNo': this.ordeDetail.salesReturnBillNo,
+        'salesBillSn': row.salesBillSn,
+        'salesBillNo': row.salesBillNo,
+        'salesBillDetailSn': row.salesBillDetailSn,
+        'price': row.price,
+        'cost': row.cost,
+        'productSn': row.productSn,
+        'celQty': row.celQty,
+        'hasReturnQty': row.hasReturnQty,
+        'warehouseLocationSn': row.warehouseLocationSn,
+        'warehouseSn': row.warehouseSn
+      }
+      // 编辑
+      if (type == 'edit') {
+        params.id = row.id
+        params.qty = row.qty
+      } else {
+        params.salesQty = row.qty
+      }
+      salesReturnSaveProduct(params).then(res => {
+        this.resetSearchForm(true)
+        this.isInster = false
+      })
+    },
+    // 提交销售单
+    handleSubmit () {
+      salesReturnSubmit({ sn: this.orderSn }).then(res => {
+        if (res.status == 200) {
+          this.handleBack()
+          this.$message.success(res.message)
+        }
+      })
+    }
+  },
+  mounted () {
+    this.orderId = this.$route.params.id
+    this.orderSn = this.$route.params.sn
+    this.buyerSn = this.$route.params.buyerSn
+    this.getOrderDetail()
+    this.getWarehouseCascade()
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      console.log('beforeRouteEnter')
+    })
+  }
+}
+</script>
+
+<style lang="less">
+  .pages-wrap{
+    margin-top: 15px;
+    .sTable{
+      margin-top: 15px;
+    }
+    .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>

+ 533 - 0
src/views/salesManagement/salesReturn/salesReturnGrabEdit.vue

@@ -0,0 +1,533 @@
+<template>
+  <div>
+    <a-affix :target="() => this.$refs.container">
+      <a-page-header
+        :ghost="false"
+        @back="handleBack"
+        :backIcon="false"
+      >
+        <template slot="subTitle">
+          <a id="back-btn" href="javascript:;" @click="handleBack"><a-icon type="left" /> 返回列表</a>
+          <span style="margin: 0 15px;color: #666;">客户名称:{{ ordeDetail&&ordeDetail.buyerName }}</span>
+          <!-- <a-button size="small" @click="handleEditCustom" style="margin-left:50px" key="0">
+            编辑
+          </a-button> -->
+        </template>
+        <template slot="extra">
+          <a-button key="2">
+            打印预览
+          </a-button>
+          <a-button key="1" type="primary">
+            快速打印
+          </a-button>
+        </template>
+      </a-page-header>
+    </a-affix>
+
+    <a-card size="small" :bordered="false" class="pages-wrap">
+      <!-- 查询配件列表 -->
+      <queryPart :buyerSn="$route.params.buyerSn" grabFlag="1" :newLoading="isInster" @add="saveProduct"></queryPart>
+    </a-card>
+    <a-card size="small" :bordered="false" class="pages-wrap">
+      <!-- alert -->
+      <a-alert style="margin-bottom: 15px;" type="info">
+        <div slot="message" class="total-bar">
+          <div>
+            <span>退货总金额:{{ countData&&countData.totalAmount }}元;</span>
+            <span>总款数:{{ countData&&countData.totalCategory }};</span>
+            <span>总数量:{{ countData&&countData.totalQty }};</span>
+            <span>废品总数量:{{ countData&&countData.totalCelQty }};</span>
+          </div>
+          <div>
+            <div>
+              折扣金额:
+              <a-input-number id="discount" v-model="ordeDetail.discountAmount" :min="0" :precision="2" :max="999999"/>
+              <a-button type="primary" @click="salesReturnDiscount" class="button-info">打折</a-button>
+            </div>
+            <div>
+              折扣:<strong>{{ ordeDetail&&ordeDetail.discountRate || 0 }}%</strong>;
+              折后总售价:<strong>¥{{ ordeDetail&&ordeDetail.discountedAmount || 0 }}</strong>;
+            </div>
+          </div>
+        </div>
+      </a-alert>
+      <!-- 查询条件 -->
+      <a-row :gutter="15">
+        <a-col :span="18">
+          <a-form-model layout="inline" :model="productForm">
+            <a-form-model-item label="产品编码">
+              <a-input v-model="productForm.productCode" placeholder="输入产品编码" />
+            </a-form-model-item>
+            <a-form-model-item label="产品名称">
+              <a-input v-model="productForm.productName" placeholder="输入产品名称" />
+            </a-form-model-item>
+            <a-form-model-item>
+              <a-button style="margin-bottom: 18px;" type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="salesReturn-refresh">查询</a-button>
+              <a-button style="margin: 0 0 18px 8px" @click="resetForm" id="salesReturn-reset">重置</a-button>
+            </a-form-model-item>
+          </a-form-model>
+        </a-col>
+        <a-col :span="6">
+          <div style="float:right;overflow: hidden;">
+            <a-button id="salesReturn-dru">导入明细</a-button>
+            <a-button
+              size="small"
+              type="primary"
+              @click="salesReturnDelAll"
+              :loading="delLoading"
+              style="margin-left: 10px"
+              id="salesReturn-del-all">整单删除</a-button>
+          </div>
+        </a-col>
+      </a-row>
+      <!-- 已选配件列表 -->
+      <s-table
+        class="sTable"
+        ref="table"
+        size="default"
+        :rowKey="(record) => record.id"
+        :columns="columns"
+        :data="loadData"
+        :scroll="{ x: 1500, y: 300 }"
+        bordered>
+        <!-- 本次退货数量 -->
+        <template slot="qty" slot-scope="text, record">
+          <editable-cell
+            size="small"
+            :text="record.qty"
+            :max="999999"
+            :min="0"
+            :precision="0"
+            @change="onCellChange(record.id, 'qty', $event)" />
+        </template>
+        <!-- 废品数量 -->
+        <template slot="celQty" slot-scope="text, record">
+          <editable-cell
+            size="small"
+            :text="record.celQty"
+            :max="999999"
+            :min="0"
+            :precision="0"
+            @change="onCellChange(record.id, 'celQty', $event)" />
+        </template>
+        <!-- 退货金额小计 -->
+        <template slot="returnAmount" slot-scope="text, record">
+          ¥{{ (record.price * record.qty).toFixed(2) }}
+        </template>
+        <!-- 仓库仓位 -->
+        <template slot="warehouse" slot-scope="text, record, index">
+          <a-cascader
+            @change="e => changeWarehouseCascade(e, record, index)"
+            v-model="record.warehouseCascade"
+            expand-trigger="hover"
+            :options="warehouseCascadeData"
+            :allowClear="false"
+            :fieldNames="{ label: 'name', value: 'sn', children: 'warehouseLocationList' }"
+            id="bulkWarehousingOrderEdit-warehouseCascade"
+            placeholder="请选择仓库仓位"
+            style="width: 100%;" />
+        </template>
+        <!-- 操作 -->
+        <template slot="action" slot-scope="text, record">
+          <a-button
+            size="small"
+            type="primary"
+            :loading="delLoading"
+            class="button-error"
+            @click="handleDel(record)"
+            id="salesReturn-Del">删除</a-button>
+        </template>
+      </s-table>
+    </a-card>
+    <a-affix :offset-bottom="0">
+      <div
+        style="text-align: center;width: 100%;background-color: #fff;padding: 12px 0;box-shadow: 0 0 20px #dcdee2;">
+        <a-button
+          size="large"
+          style="width: 150px;"
+          type="primary"
+          class="button-primary"
+          @click="handleSubmit()"
+          id="salesReturn-handleSubmit">提交</a-button>
+      </div>
+    </a-affix>
+    <!-- 选择客户弹框 -->
+    <choose-custom-modal :show="openModal" @ok="chooseCustomOk" @cancel="openModal=false"></choose-custom-modal>
+  </div>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import queryPart from './queryPart.vue'
+import EditableCell from '@/views/common/editInput.js'
+import chooseCustomModal from './chooseCustomModal.vue'
+import { warehouseCascadeList } from '@/api/warehouse'
+import { salesReturnDetail, salesReturnQueryCount, salesReturnDetailList, salesReturnDiscount, salesReturnDelAll, salesReturnDetailDel, salesReturnSaveProduct, salesReturnSubmit } from '@/api/salesReturn'
+export default {
+  name: 'SalesDetail',
+  components: {
+    STable,
+    VSelect,
+    queryPart,
+    EditableCell,
+    chooseCustomModal
+  },
+  data () {
+    return {
+      orderId: null,
+      orderSn: null,
+      buyerSn: null,
+      disabled: false,
+      openModal: false,
+      isInster: false, // 是否正在添加产品
+      ordeDetail: { discountAmount: 0 },
+      delLoading: false,
+      warehouseCascadeData: [], //  仓库仓位
+      // 已选产品
+      dataSource: [],
+      productForm: {
+        productCode: '',
+        productName: ''
+      },
+      countData: null,
+      // 表头
+      columns: [
+        {
+          title: '序号',
+          dataIndex: 'no',
+          align: 'center',
+          width: 100
+        },
+        {
+          title: '产品编码',
+          dataIndex: 'dealerProductEntity.code',
+          align: 'center',
+          width: 160
+        },
+        {
+          title: '产品名称',
+          dataIndex: 'dealerProductEntity.name',
+          align: 'center',
+          width: 200
+        },
+        {
+          title: '原厂编码',
+          dataIndex: 'dealerProductEntity.origCode',
+          align: 'center',
+          width: 160,
+          customRender: function (text) { return text || '--' }
+        },
+        {
+          title: '销售单号',
+          dataIndex: 'salesBillNo',
+          align: 'center',
+          width: 200
+        },
+        {
+          title: '售价',
+          dataIndex: 'price',
+          align: 'center',
+          width: 150,
+          scopedSlots: { customRender: 'price' }
+        },
+        {
+          title: '单位',
+          dataIndex: 'dealerProductEntity.unit',
+          align: 'center',
+          width: 100
+        },
+        {
+          title: '销售数量',
+          dataIndex: 'salesQty',
+          align: 'center',
+          width: 100
+        },
+        {
+          title: '本次退货数量',
+          dataIndex: 'qty',
+          align: 'center',
+          width: 150,
+          scopedSlots: { customRender: 'qty' }
+        },
+        {
+          title: '废品数量',
+          dataIndex: 'celQty',
+          align: 'center',
+          width: 150,
+          scopedSlots: { customRender: 'celQty' }
+        },
+        { title: '仓库仓位', scopedSlots: { customRender: 'warehouse' }, width: 200, align: 'center' },
+        {
+          title: '退货金额小计',
+          align: 'center',
+          scopedSlots: { customRender: 'returnAmount' },
+          width: 100
+        },
+        {
+          title: '折后金额小计',
+          dataIndex: 'discountedAmount',
+          align: 'center',
+          width: 100
+        },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: 100, align: 'center', fixed: 'right' }
+      ],
+      chooseLoadData: [],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        // 查询总计
+        this.productForm.salesReturnBillSn = this.$route.params.sn
+        this.getQueryCount(Object.assign(parameter, this.productForm))
+        return salesReturnDetailList(Object.assign(parameter, this.productForm)).then(res => {
+          const 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
+            const warehouseSn = data.list[i].warehouseSn || undefined
+            const warehouseLocationSn = data.list[i].warehouseLocationSn || undefined
+            if (warehouseSn || warehouseLocationSn) {
+              data.list[i].warehouseSnBackups = warehouseSn
+              data.list[i].warehouseLocationSnBackups = warehouseLocationSn
+              data.list[i].warehouseCascade = [warehouseSn, warehouseLocationSn]
+            } else {
+              data.list[i].warehouseCascade = undefined
+            }
+          }
+          this.disabled = false
+          this.chooseLoadData = data.list
+          return data
+        })
+      }
+    }
+  },
+  methods: {
+    //  返回
+    handleBack () {
+      this.$router.push({ name: 'salesReturnList' })
+    },
+    // 选择客户成功
+    chooseCustomOk (data) {
+
+    },
+    handleEditCustom () {
+      this.openModal = true
+    },
+    onCellChange (id, key, value) {
+      const chooseLoadData = [...this.chooseLoadData]
+      const row = chooseLoadData.find(item => item.id === id)
+      if (row) {
+        row[key] = Number(value)
+        console.log(row.celQty, row.qty)
+        if (row.celQty > row.qty) {
+          this.$message.info('废品数量不可大于本次退货数量')
+          this.$refs.table.refresh(true)
+        } else {
+          this.saveProduct(row, 'edit')
+        }
+      }
+    },
+    //  仓库仓位  级联  列表
+    getWarehouseCascade () {
+      warehouseCascadeList({}).then(res => {
+        if (res.status == 200) {
+		  res.data.map(item => {
+		    item.sn = item.warehouseSn
+		    if (item.warehouseLocationList) {
+		  	item.warehouseLocationList.map(subItem => {
+		  	  subItem.sn = subItem.warehouseLocationSn
+		  	})
+		    }
+		  })
+          this.warehouseCascadeData = res.data
+        } else {
+          this.warehouseCascadeData = []
+        }
+      })
+    },
+    // 修改仓库仓位
+    changeWarehouseCascade (val, opt, ind) {
+      console.log(val, opt, ind)
+      let loadData = this.chooseLoadData[ind]
+      if (val.length < 2) {
+        this.$message.warning('当前仓库无仓位,请选择其他仓库')
+        const warehouseSnBackups = loadData.warehouseSnBackups || undefined
+        const warehouseLocationSnBackups = loadData.warehouseLocationSnBackups || undefined
+        loadData.warehouseSn = warehouseSnBackups
+        loadData.warehouseLocationSn = warehouseLocationSnBackups
+        if (warehouseSnBackups || warehouseLocationSnBackups) {
+          loadData.warehouseCascade = [warehouseSnBackups, warehouseLocationSnBackups]
+        } else {
+          loadData.warehouseCascade = undefined
+        }
+      } else {
+        loadData.warehouseSn = val[0] ? val[0] : ''
+        loadData.warehouseLocationSn = val[1] ? val[1] : ''
+        loadData.warehouseSnBackups = val[0] ? val[0] : ''
+        loadData.warehouseLocationSnBackups = val[1] ? val[1] : ''
+        loadData = this.chooseLoadData[ind]
+        console.log(loadData)
+        this.saveProduct(loadData, 'edit')
+      }
+    },
+    // 重置列表
+    resetForm () {
+      this.productForm = {
+        productName: '',
+        productCode: ''
+      }
+      this.$refs.table.refresh(true)
+    },
+    // 明细统计
+    getQueryCount (params) {
+      salesReturnQueryCount(params).then(res => {
+        this.countData = res.data || null
+      })
+    },
+    // 获取单据详细
+    getOrderDetail () {
+      salesReturnDetail({ sn: this.orderSn }).then(res => {
+        this.ordeDetail = res.data || null
+      })
+    },
+    // 打折
+    salesReturnDiscount () {
+      if (this.ordeDetail.discountAmount < 0) {
+        return
+      }
+      salesReturnDiscount({
+        discountAmount: this.ordeDetail.discountAmount,
+        salesReturnSn: this.ordeDetail.salesReturnSn,
+        id: this.ordeDetail.id
+      }).then(res => {
+        if (res.status == 200) {
+          this.resetSearchForm()
+        }
+      })
+    },
+    // 整单删除
+    salesReturnDelAll () {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确认要整单删除吗?',
+        centered: true,
+        closable: true,
+        onOk () {
+          _this.delLoading = true
+          salesReturnDelAll({ sn: _this.ordeDetail.salesReturnSn }).then(res => {
+            if (res.status == 200) {
+              _this.resetSearchForm()
+            }
+            _this.$message.info(res.message)
+            _this.delLoading = false
+          })
+        }
+      })
+    },
+    // 删除产品
+    handleDel (row) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确认要删除吗?',
+        centered: true,
+        closable: true,
+        onOk () {
+          _this.delLoading = true
+          salesReturnDetailDel({ id: row.id }).then(res => {
+            if (res.status == 200) {
+              _this.resetSearchForm(true)
+            }
+            _this.$message.info(res.message)
+            _this.delLoading = false
+          })
+        }
+      })
+    },
+    //  重置
+    resetSearchForm (flag) {
+      this.$refs.table.refresh(!!flag)
+      this.getOrderDetail()
+    },
+    // 添加或修改产品
+    saveProduct (row, type) {
+      console.log(row)
+      // 防止多次添加产品
+      if (this.isInster) {
+        return
+      }
+      this.isInster = true
+      const params = {
+        'salesReturnBillSn': this.orderSn,
+        'salesReturnBillNo': this.ordeDetail.salesReturnBillNo,
+        'salesBillSn': row.salesBillSn,
+        'salesBillNo': row.salesBillNo,
+        'salesBillDetailSn': row.salesBillDetailSn,
+        'price': row.price,
+        'cost': row.cost,
+        'productSn': row.productSn,
+        'celQty': row.celQty,
+        'hasReturnQty': row.hasReturnQty,
+        'warehouseLocationSn': row.warehouseLocationSn,
+        'warehouseSn': row.warehouseSn
+      }
+      // 编辑
+      if (type == 'edit') {
+        params.id = row.id
+        params.qty = row.qty
+      } else {
+        params.salesQty = row.qty
+      }
+      salesReturnSaveProduct(params).then(res => {
+        this.resetSearchForm(true)
+        this.isInster = false
+      })
+    },
+    // 提交销售单
+    handleSubmit () {
+      salesReturnSubmit({ sn: this.orderSn }).then(res => {
+        if (res.status == 200) {
+          this.handleBack()
+          this.$message.success(res.message)
+        }
+      })
+    }
+  },
+  mounted () {
+    this.orderId = this.$route.params.id
+    this.orderSn = this.$route.params.sn
+    this.buyerSn = this.$route.params.buyerSn
+    this.getOrderDetail()
+    this.getWarehouseCascade()
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      console.log('beforeRouteEnter')
+    })
+  }
+}
+</script>
+
+<style lang="less">
+  .pages-wrap{
+    margin-top: 15px;
+    .sTable{
+      margin-top: 15px;
+    }
+    .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>

+ 8 - 0
src/views/salesManagement/shortageStatisticsC/list.vue

@@ -0,0 +1,8 @@
+<template>
+</template>
+
+<script>
+</script>
+
+<style>
+</style>

+ 8 - 0
src/views/salesManagement/shortageStatisticsP/list.vue

@@ -0,0 +1,8 @@
+<template>
+</template>
+
+<script>
+</script>
+
+<style>
+</style>