Browse Source

Merge branch 'develop_yh42' of jianguan-web/qpls-md-html into pre-release

李磊 1 year ago
parent
commit
7dabc5c96a
36 changed files with 2345 additions and 243 deletions
  1. 1 1
      public/version.json
  2. 34 0
      src/api/reportData.js
  3. 11 0
      src/api/shelf.js
  4. 130 0
      src/api/shelfTemplate.js
  5. 29 19
      src/components/tools/UserMenu.vue
  6. 60 2
      src/config/router.config.js
  7. 1 0
      src/layouts/BasicLayout.vue
  8. 1 1
      src/libs/JGPrint.js
  9. 1 0
      src/store/getters.js
  10. 10 0
      src/store/modules/app.js
  11. 2 2
      src/views/allocationManagement/storeTransferOut/importGuideModal.vue
  12. 27 10
      src/views/common/productJqList.vue
  13. 67 0
      src/views/common/shelfTemplate.js
  14. 235 0
      src/views/numsGoodsShelves/shelfProductTempl/addHwModal.vue
  15. 133 0
      src/views/numsGoodsShelves/shelfProductTempl/basicInfoModal.vue
  16. 192 0
      src/views/numsGoodsShelves/shelfProductTempl/chooseImportModal.vue
  17. 200 0
      src/views/numsGoodsShelves/shelfProductTempl/importGuideModal.vue
  18. 234 0
      src/views/numsGoodsShelves/shelfProductTempl/list.vue
  19. 260 0
      src/views/numsGoodsShelves/shelfProductTempl/set.vue
  20. 28 27
      src/views/numsGoodsShelves/shelfSet/addHwModal.vue
  21. 14 13
      src/views/numsGoodsShelves/shelfSet/basicInfoModal.vue
  22. 13 12
      src/views/numsGoodsShelves/shelfSet/bindProductModal.vue
  23. 6 3
      src/views/numsGoodsShelves/shelfSet/chooseImportModal.vue
  24. 11 8
      src/views/numsGoodsShelves/shelfSet/chooseShelfImportModal.vue
  25. 4 14
      src/views/numsGoodsShelves/shelfSet/importGuideModal.vue
  26. 6 7
      src/views/numsGoodsShelves/shelfSet/importHuoweiModal.vue
  27. 52 36
      src/views/numsGoodsShelves/shelfSet/list.vue
  28. 120 56
      src/views/numsGoodsShelves/shelfSet/set.vue
  29. 10 3
      src/views/outboundOrderManagement/outboundOrder/list.vue
  30. 5 1
      src/views/productManagement/productInfo/edit.vue
  31. 1 0
      src/views/reportData/customerReport/list.vue
  32. 20 15
      src/views/reportData/salesDetailReport/list.vue
  33. 410 0
      src/views/reportData/salesRankingReport/list.vue
  34. 5 3
      src/views/salesManagement/salesQuery/list.vue
  35. 11 9
      src/views/salesManagement/salesQueryNew/list.vue
  36. 1 1
      vue.config.js

+ 1 - 1
public/version.json

@@ -1,5 +1,5 @@
 {
   "message": "发现有新版本发布,确定更新系统?",
   "vendorJsVersion": "",
-  "version": 1717384672649
+  "version": 1719296425506
 }

+ 34 - 0
src/api/reportData.js

@@ -1168,3 +1168,37 @@ export const salesOosExport = params => {
     }
   })
 }
+// 销售排行报表-列表
+export const salesBillRankList = (params) => {
+  const url = `/report/reportSalesBillRank/reportPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post',
+    headers: {
+      'module': encodeURIComponent('列表查询')
+    }
+  })
+}
+// 采购明细退货报表-列表合计
+export const salesBillRankCount = (params) => {
+  return axios({
+    url: '/report/reportSalesBillRank/reportCount',
+    data: params,
+    method: 'post'
+  })
+}
+// 销售排行报表-导出
+export const salesBillRankExport = params => {
+  return axios.request({
+    url: `/report/reportSalesBillRank/export`,
+    data: params,
+    method: 'post',
+    responseType: 'blob',
+    headers: {
+      'module': encodeURIComponent('导出')
+    }
+  })
+}

+ 11 - 0
src/api/shelf.js

@@ -92,6 +92,17 @@ export const shelfSave = (params) => {
     }
   })
 }
+// 导入货架模板
+export const importShelfTemplate = params => {
+  return axios({
+    url: '/shelfTemplate/importShelfTemplate',
+    data: params,
+    method: 'post',
+    headers:{
+      'module': encodeURIComponent('导入货架模板')
+    }
+  })
+}
 //  货架  货位产品 列表 不分页
 export const shelfProductList = (params) => {
   return axios({

+ 130 - 0
src/api/shelfTemplate.js

@@ -0,0 +1,130 @@
+import { axios } from '@/utils/request'
+
+// 货架模板 列表  分页
+export const shelfTemplateList = (params) => {
+  const url = `/shelfTemplate/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post',
+    headers:{
+      'module': encodeURIComponent('货架模板列表查询')
+    }
+  })
+}
+//  新建
+export const shelfTemplateSave = (params) => {
+  return axios({
+    url: `/shelfTemplate/save`,
+    data: params,
+    method: 'post',
+    headers:{
+      'module': encodeURIComponent('新建编辑货架模板')
+    }
+  })
+}
+//  复制
+export const shelfTemplateCopy = (params) => {
+  return axios({
+    url: `/shelfTemplate/copy/${params.templateSn}`,
+    data: params,
+    method: 'post',
+    headers:{
+      'module': encodeURIComponent('复制货架模板')
+    }
+  })
+}
+//  删除
+export const shelfTemplateDel = (params) => {
+  return axios({
+    url: `/shelfTemplate/deleteBySn/${params.templateSn}`,
+    data: params,
+    method: 'post',
+    headers:{
+      'module': encodeURIComponent('删除货架模板')
+    }
+  })
+}
+//  详情
+export const shelfTemplateDetail = (params) => {
+  return axios({
+    url: `/shelfTemplate/queryBySn/${params.templateSn}`,
+    data: params,
+    method: 'post',
+    headers:{
+      'module': encodeURIComponent('复制货架模板')
+    }
+  })
+}
+// 货架模板明细 列表  分页
+export const shelfTemplateDetailList = (params) => {
+  const url = `/shelfTemplate/detail/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post',
+    headers:{
+      'module': encodeURIComponent('货架模板明细列表查询')
+    }
+  })
+}
+//  货架模板明细保存
+export const shelfTemplateDetailSave = (params) => {
+  return axios({
+    url: `/shelfTemplate/detail/save`,
+    data: params,
+    method: 'post',
+    headers:{
+      'module': encodeURIComponent('货架模板新增编辑明细')
+    }
+  })
+}
+// 删除货架模板明细
+export const shelfTemplateDetailBySn = (params) => {
+  return axios({
+    url: `/shelfTemplate/detail/deleteBySn/${params.templateDetailSn}`,
+    data: params,
+    method: 'post',
+    headers:{
+      'module': encodeURIComponent('货架模板明细删除')
+    }
+  })
+}
+// 导入货架产品-保存数据
+export const shelfTemplateDetailImportSave = (params) => {
+  return axios({
+    url: `/shelfTemplate/detail/insertImport`,
+    data: params,
+    method: 'post',
+    headers:{
+      'module': encodeURIComponent('货架模板明细导入产品')
+    }
+  })
+}
+// 导入货架产品-导出错误项
+export const shelfTemplateImportDetailError = (params) => {
+  return axios({
+    url: `/shelfTemplate/detail/importDetailError`,
+    data: params,
+    method: 'post',
+    responseType: 'blob',
+    headers:{
+      'module': encodeURIComponent('货架模板导出错误项')
+    }
+  })
+}
+// 导入货架模板-解析模板
+export const shelfTemplateDetailImportParse = (params) => {
+  return axios({
+    url: `/shelfTemplate/detail/importDetail`,
+    data: params,
+    method: 'post',
+    headers:{
+      'module': encodeURIComponent('导入货架模板产品')
+    }
+  })
+}

+ 29 - 19
src/components/tools/UserMenu.vue

@@ -5,16 +5,16 @@
         <img style="width: 18px;height: 18px;vertical-align: middle;margin: 0 5px;" src="../../assets/icon_movie.png"/>
         <span style="vertical-align: middle;color: #666;">帮助</span>
       </p>
-      
+
       <p class="help-cont" @click="showShopCar" v-if="$hasPermissions('M_shoppingCart')">
         <a-popover placement="bottom">
-        <template slot="content">
-          <span>购物车</span>
-        </template>
-        <a-badge :count="cartCount" :overflow-count="999">
-          <a-icon type="shopping-cart" style="font-size:16px;margin: 0 5px;color: #666;"/>
-        </a-badge>
-      </a-popover>
+          <template slot="content">
+            <span>购物车</span>
+          </template>
+          <a-badge :count="cartCount" :overflow-count="999">
+            <a-icon type="shopping-cart" style="font-size:16px;margin: 0 5px;color: #666;"/>
+          </a-badge>
+        </a-popover>
       </p>
       <!-- 通知 -->
       <notice-icon class="action"/>
@@ -22,7 +22,7 @@
       <a-popover title="系统设置">
         <div slot="content" :style="{width: fontSize == 'large' ? '340px' : '300px'}">
           <a-form-model :label-col="{ span: 9 }" :wrapper-col="{ span: 15 }">
-            <a-form-model-item label="主题">
+            <a-form-model-item label="主题" style="margin-bottom:10px;">
               <a-radio-group :value="theme" @change="changeTheme">
                 <a-radio-button value="dark">
                   深色
@@ -32,7 +32,7 @@
                 </a-radio-button>
               </a-radio-group>
             </a-form-model-item>
-            <a-form-model-item label="字体大小">
+            <a-form-model-item label="字体大小" style="margin-bottom:10px;">
               <a-radio-group :value="fontSize" @change="changeFontSize">
                 <a-radio-button value="small">
@@ -45,7 +45,7 @@
                 </a-radio-button>
               </a-radio-group>
             </a-form-model-item>
-            <a-form-model-item label="默认针式打印机">
+            <a-form-model-item label="默认针式打印机" style="margin-bottom:10px;">
               <div style="line-height: normal;padding-top: 10px;">
                 <span style="color: #999;">{{ printName ||'还未设置默认打印机' }}</span>
                 <div style="padding-top: 10px;">
@@ -53,6 +53,9 @@
                 </div>
               </div>
             </a-form-model-item>
+            <!-- <a-form-model-item label="打印纸张节约模式" style="margin-bottom:10px;">
+              <a-switch style="margin-left: 10px;" checked-children="开" un-checked-children="关" v-model="printContentType" @change="changeContentType"/>
+            </a-form-model-item> -->
           </a-form-model>
         </div>
         <span class="skin">
@@ -62,11 +65,11 @@
 
       <p class="help-cont" @click="screen">
         <a-popover placement="bottom">
-        <template slot="content">
-          <span>{{ isFullscreen?'取消全屏':'全屏' }}</span>
-        </template>
-        <a-icon :type="isFullscreen?'fullscreen-exit':'fullscreen'" style="font-size:14px;margin: 0 5px;color: #666;"/>
-      </a-popover>
+          <template slot="content">
+            <span>{{ isFullscreen?'取消全屏':'全屏' }}</span>
+          </template>
+          <a-icon :type="isFullscreen?'fullscreen-exit':'fullscreen'" style="font-size:14px;margin: 0 5px;color: #666;"/>
+        </a-popover>
       </p>
 
       <a-dropdown>
@@ -113,7 +116,7 @@ export default {
     NoticeIcon
   },
   computed: {
-    ...mapGetters(['nickname', 'avatar', 'authOrgs', 'userInfo', 'nowRoute', 'theme', 'fontSize', 'printDefNeedle', 'cartCount']),
+    ...mapGetters(['nickname', 'avatar', 'authOrgs', 'userInfo', 'nowRoute', 'theme', 'fontSize', 'printDefNeedle', 'cartCount', 'printDefPageSize']),
     authOrgsList () { //  过滤掉当前登录账户(不可由自己切换为自己)
       const _this = this
       const arr = []
@@ -137,14 +140,18 @@ export default {
     printName () {
       const defName = this.printDefNeedle
       return defName && defName != 'undefined' ? defName : null
-    },
+    }
   },
   data () {
     return {
       defaultAvatar: defaultAvatar,
-      isFullscreen: false
+      isFullscreen: false,
+      printContentType: false
     }
   },
+  mounted () {
+    this.printContentType = this.printDefPageSize == 3
+  },
   methods: {
     ...mapActions(['Logout', 'SetOrgSn', 'Login']),
     // 打开视频播放弹窗
@@ -222,6 +229,9 @@ export default {
       this.$store.dispatch('TogglePrintSettingType', type)
       // 选择打印机
       this.$store.commit('SET_showSelectPrint', true)
+    },
+    changeContentType (value) {
+      this.$store.dispatch('TogglePrintDefPageSize', value ? 3 : 0)
     }
   }
 }

+ 60 - 2
src/config/router.config.js

@@ -465,6 +465,41 @@ export const asyncRouterMap = [
               }
             ]
           },
+          {
+            path: '/numsGoodsShelves/shelfProductTempl',
+            redirect: '/numsGoodsShelves/shelfProductTempl/list',
+            name: 'shelfProductTempl',
+            component: BlankLayout,
+            meta: {
+              title: '货架产品模板设置',
+              icon: 'monitor',
+              permission: 'M_shelfTeplSet'
+            },
+            hideChildrenInMenu: true,
+            children: [
+              {
+                path: 'list',
+                name: 'shelfProductTemplList',
+                component: () => import(/* webpackChunkName: "numsGoodsShelves" */ '@/views/numsGoodsShelves/shelfProductTempl/list.vue'),
+                meta: {
+                  title: '货架产品模板列表',
+                  icon: 'monitor',
+                  hidden: true
+                }
+              },
+              {
+                path: 'set/:sn',
+                name: 'shelfProductTemplSetting',
+                component: () => import(/* webpackChunkName: "numsGoodsShelves" */ '@/views/numsGoodsShelves/shelfProductTempl/set.vue'),
+                meta: {
+                  title: '货架产品模板设置',
+                  icon: 'monitor',
+                  hidden: true,
+                  replaceTab: true
+                }
+              }
+            ]
+          },
           {
             path: '/numsGoodsShelves/shelfMonitoring',
             redirect: '/numsGoodsShelves/shelfMonitoring/list',
@@ -485,7 +520,6 @@ export const asyncRouterMap = [
                   title: '货架监控列表',
                   icon: 'monitor',
                   hidden: true
-                  // permission: 'M_salesQueryList'
                 }
               },
               {
@@ -497,7 +531,6 @@ export const asyncRouterMap = [
                   icon: 'monitor',
                   hidden: true,
                   replaceTab: true
-                  // permission: 'M_salesQueryList'
                 }
               }
             ]
@@ -2164,6 +2197,31 @@ export const asyncRouterMap = [
               }
             ]
           },
+          {
+            path: '/reportData/salesRankingReport',
+            redirect: '/reportData/salesRankingReport/list',
+            name: 'salesRankingReport',
+            component: BlankLayout,
+            meta: {
+              title: '销售排行报表',
+              icon: 'profile',
+              permission: 'M_salesRankingReport'
+            },
+            hideChildrenInMenu: true,
+            children: [
+              {
+                path: 'list',
+                name: 'salesRankingReportList',
+                component: () => import(/* webpackChunkName: "reportData" */ '@/views/reportData/salesRankingReport/list.vue'),
+                meta: {
+                  title: '销售排行报表列表',
+                  icon: 'profile',
+                  hidden: true,
+                  permission: 'M_salesRankingReportList'
+                }
+              }
+            ]
+          },
           {
             path: '/reportData/customerReport',
             redirect: '/reportData/customerReport/list',

+ 1 - 0
src/layouts/BasicLayout.vue

@@ -289,6 +289,7 @@ export default {
     this.$store.commit('SET_printLoading', false)
     this.$store.commit('SET_printDefNeedle', localStorage.getItem('DEFAULT_PRINT_NEEDLE') || undefined)
     this.$store.commit('SET_printDefInk', localStorage.getItem('DEFAULT_PRINT_INK') || undefined)
+    this.$store.commit('SET_printDefPageSize', localStorage.getItem('DEFAULT_PRINT_PAGESIZE') || undefined)
 
     // 消息通知
     this.getNotes()

+ 1 - 1
src/libs/JGPrint.js

@@ -217,10 +217,10 @@ export const pdfPrint = function (data,index){
        store.commit('SET_printLoading',false)
      }
   };
-  console.log(store.state.app.printDefNeedle)
   // 指定打印机
   LODOP.SET_PRINTER_INDEX(store.state.app.printDefNeedle)
   LODOP.ADD_PRINT_PDF(0, 0, '100%', '100%', data[index])
+  // store.state.app.printDefPageSize
   LODOP.SET_PRINT_PAGESIZE(3, 2090, (index==dlen-1)?50:0, '')
   LODOP.PRINT()
 }

+ 1 - 0
src/store/getters.js

@@ -25,6 +25,7 @@ const getters = {
   closeTabPages: state => state.app.closeTabPages,
   loadingStatus: state => state.app.loadingStatus,
   printDefNeedle: state => state.app.printDefNeedle,
+  printDefPageSize: state => state.app.printDefPageSize,
   printDefInk: state => state.app.printDefInk,
   printUseing: state => state.app.printUseing,
   printSettingType: state => state.app.printSettingType,

+ 10 - 0
src/store/modules/app.js

@@ -48,6 +48,7 @@ const app = {
     printUseing: '0', // 选择打印机的用途 0 设置打印机,1打印时
     printSettingType: '', // 设置打印机类型,0 针式,1 喷墨
     printDefNeedle: undefined,// 默认针式打印机
+    printDefPageSize:'3', // 默认针式打印机纸张自适应高度,3:auto,0:pageEnd
     printDefInk: undefined, // 默认喷墨打印机
     defectiveReturnReason: [], // 不良品申请退货列表
     goodReturnReason: [], // 良品申请退货列表
@@ -148,6 +149,10 @@ const app = {
       state.printDefNeedle = val
       localStorage.setItem('DEFAULT_PRINT_NEEDLE',val)
     },
+    SET_printDefPageSize: (state, val) => {
+      state.printDefPageSize = val
+      localStorage.setItem('DEFAULT_PRINT_PAGESIZE',val)
+    },
     SET_printDefInk: (state, val) => {
       state.printDefInk = val
       localStorage.setItem('DEFAULT_PRINT_INK',val)
@@ -193,6 +198,11 @@ const app = {
     }, str) {
       commit('SET_printDefNeedle', str)
     },
+    TogglePrintDefPageSize({
+      commit
+      },str){
+      commit('SET_printDefPageSize', str)
+    },
     TogglePrintDefInk({
       commit
     }, str) {

+ 2 - 2
src/views/allocationManagement/storeTransferOut/importGuideModal.vue

@@ -92,7 +92,7 @@ export default {
         savePathType: 'local',
         storeCallOutSn: this.params.storeCallOutSn
       },
-      filePath: location.protocol + '//' +location.host + '/templ/店内调出产品导入模板.xls'
+      filePath: location.protocol + '//' + location.host + '/templ/店内调出产品导入模板.xls'
     }
   },
   methods: {
@@ -129,7 +129,7 @@ export default {
     handleClose () {
       this.openImportModal = false
       this.isShow = false
-    },
+    }
   },
   watch: {
     //  父页面传过来的弹框状态

+ 27 - 10
src/views/common/productJqList.vue

@@ -20,6 +20,7 @@
 <script>
 import debounce from 'lodash/debounce'
 import { shelfDealerProductList } from '@/api/shelf'
+import { productList } from '@/api/product'
 export default {
   props: {
     itemSn: {
@@ -28,9 +29,13 @@ export default {
     },
     params: {
       type: Object,
-      default: ()=> {
+      default: () => {
         return null
       }
+    },
+    dataType: {
+      type: String,
+      default: 'shelf'
     }
   },
   data () {
@@ -51,16 +56,27 @@ export default {
       this.data = []
       this.fetching = true
       let params = { code: productCode, pageNo: 1, pageSize: 20 }
-      if(this.params){
-        params = Object.assign(params, this.params)
-      }
-      shelfDealerProductList(params).then(res => {
-        if (fetchId !== this.lastFetchId) {
-          return
+
+      if (this.dataType == 'shelf') {
+        if (this.params) {
+          params = Object.assign(params, this.params)
         }
-        this.data = res.data && res.data.list ? res.data.list : []
-        this.fetching = false
-      })
+        shelfDealerProductList(params).then(res => {
+          if (fetchId !== this.lastFetchId) {
+            return
+          }
+          this.data = res.data && res.data.list ? res.data.list : []
+          this.fetching = false
+        })
+      } else {
+        productList(params).then(res => {
+          if (fetchId !== this.lastFetchId) {
+            return
+          }
+          this.data = res.data && res.data.list ? res.data.list : []
+          this.fetching = false
+        })
+      }
     },
     handleChange (value) {
       if (value && value.key) {
@@ -78,6 +94,7 @@ export default {
       this.productCode = undefined
     },
     setData (value) {
+      console.log(value)
       Object.assign(this, {
         productCode: value,
         data: [],

+ 67 - 0
src/views/common/shelfTemplate.js

@@ -0,0 +1,67 @@
+import { shelfTemplateList } from '@/api/shelfTemplate'
+const custType = {
+  template: `
+      <a-select
+        :placeholder="placeholder"
+        :id="id"
+        allowClear
+        :value="defaultVal"
+        :showSearch="true"
+        @change="handleChange"
+        option-filter-prop="children"
+        :dropdownMatchSelectWidth="false"
+        :filter-option="filterOption">
+        <a-select-option v-for="item in list" :key="item.templateSn" :value="item.templateSn">{{ item.templateName }}</a-select-option>
+      </a-select>
+    `,
+  props: {
+    value: {
+      type: String,
+    },
+    id: {
+      type: String,
+      default: ''
+    },
+    placeholder: {
+      type: String,
+      default: '请选择货架模板'
+    }
+  },
+  data() {
+    return {
+      defaultVal: this.value,
+      list: []
+    };
+  },
+  mounted() {
+    this.getList()
+  },
+  watch: {
+    value(newValue, oldValue) {
+      this.defaultVal = newValue
+    }
+  },
+  methods: {
+    filterOption (input, option) {
+      return (
+        option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
+      )
+    },
+    handleChange(value) {
+      this.defaultVal = value;
+      this.$emit('change', value);
+      this.$emit('input', value);
+    },
+    getList () {
+      shelfTemplateList({pageNo:1,pageSize:100}).then(res => {
+        if (res.status == 200) {
+          this.list = res.data.list
+        } else {
+          this.list = []
+        }
+      })
+    },
+  },
+};
+
+export default custType

+ 235 - 0
src/views/numsGoodsShelves/shelfProductTempl/addHwModal.vue

@@ -0,0 +1,235 @@
+<template>
+  <a-modal
+    centered
+    class="shelfSet-newHw-modal"
+    :footer="null"
+    :maskClosable="false"
+    :title="modalTit"
+    v-model="isShow"
+    @cancel="isShow=false"
+    :width="600">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-form-model
+        id="shelfSet-newHw-form"
+        ref="ruleForm"
+        :model="form"
+        :rules="rules"
+        :label-col="formItemLayout.labelCol"
+        :wrapper-col="formItemLayout.wrapperCol">
+        <a-form-model-item label="货位号" prop="shelfPlaceCode">
+          <a-input id="shelfSet-newHw-shelfPlaceCode" v-model="form.shelfPlaceCode" @input="placeCodeBlur" placeholder="请输入货位号(字母+数字格式)"></a-input>
+        </a-form-model-item>
+        <a-form-model-item label="绑定产品" prop="productSn">
+          <productJqList id="shelfSet-newHw-productJqList" ref="productJqList" dataType="jg" @change="productJqChange"></productJqList>
+        </a-form-model-item>
+        <a-form-model-item label="车主价">
+          <a-input-number
+            id="shelfSet-newHw-price"
+            v-model="form.price"
+            :precision="2"
+            :min="0"
+            :max="999999"
+            placeholder="请输入车主价(最多允许两位小数)"
+            style="width: 80%;display: inline-block;" /> 元
+        </a-form-model-item>
+        <a-form-model-item label="结算价">
+          <a-input-number
+            id="shelfSet-newHw-cost"
+            v-model="form.cost"
+            :precision="2"
+            :min="0"
+            :max="999999"
+            placeholder="请输入结算价(最多允许两位小数)"
+            style="width: 80%;display: inline-block;" /> 元
+        </a-form-model-item>
+        <a-form-model-item label="最大库容" prop="maxQty">
+          <a-input-number
+            id="shelfSet-newHw-maxQty"
+            v-model="form.maxQty"
+            :precision="0"
+            :min="0"
+            :max="999999"
+            placeholder="请输入最大库容(正整数或0)"
+            style="width: 100%;display: inline-block;" />
+        </a-form-model-item>
+      </a-form-model>
+      <div class="btn-cont">
+        <a-button type="primary" id="shelfSet-newHw-modal-save" @click="handleSave">保存</a-button>
+        <a-button id="shelfSet-newHw-modal-back" @click="isShow=false" style="margin-left: 15px;">取消</a-button>
+      </div>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+import { VSelect } from '@/components'
+import productJqList from '@/views/common/productJqList.vue'
+import { shelfTemplateDetailSave } from '@/api/shelfTemplate'
+export default {
+  name: 'AddHwModal',
+  components: { VSelect, productJqList },
+  mixins: [commonMixin],
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    type: { // 编辑or新增
+      type: String,
+      default: ''
+    },
+    nowData: { // 当前操作数据
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      spinning: false,
+      isShow: this.openModal, //  是否打开弹框
+      formItemLayout: {
+        labelCol: { span: 4 },
+        wrapperCol: { span: 18 }
+      },
+      form: {
+        shelfPlaceCode: '', // 货位号
+        productSn: undefined, // 产品sn
+        productCode: undefined, // 产品编码
+        price: '', // 售价(车主价)
+        cost: '', // 成本(结算价)
+        maxQty: '' // 最大库容
+      },
+      // 表单校验规则
+      rules: {
+        shelfPlaceCode: [
+          { required: true, message: '请输入货位号', trigger: 'blur' },
+          {
+          	pattern: /^[a-zA-Z]{1}[0-9]{1,29}$/g,
+          	message: '货位号必需字母+数字,且不能超过30个字符'
+          }
+        ],
+        productSn: [{ required: true, message: '请选择产品', trigger: 'blur' }],
+        maxQty: [{ required: true, message: '请输入最大库容', trigger: 'blur' }]
+      }
+    }
+  },
+  computed: {
+    modalTit () {
+      let title = ''
+      if (this.type == 'edit') {
+        title = '编辑货位'
+      } else if (this.type == 'add') {
+        title = '新增货位'
+      }
+      return title
+    }
+  },
+  methods: {
+    // 选择产品 change
+    productJqChange (obj) {
+      this.form.productSn = obj.key || undefined
+      if (obj && obj.row) {
+        this.form.productCode = obj.row.code || ''
+        this.form.price = obj.row.carOwnersPrice || ''
+        this.form.cost = obj.row.terminalPrice || ''
+      }
+    },
+    // 货位号变更
+    placeCodeBlur (v) {
+      this.$nextTick(() => {
+        this.form.shelfPlaceCode = this.form.shelfPlaceCode.toLocaleUpperCase()
+      })
+    },
+    // 保存
+    handleSave () {
+      const _this = this
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          const params = {}
+          const form = JSON.parse(JSON.stringify(_this.form))
+          params.templateSn = _this.nowData && _this.nowData.templateSn
+          params.shelfPlaceCode = form.shelfPlaceCode.toLocaleUpperCase()
+          if (this.type == 'edit') {
+            params.templateDetailSn = this.nowData.templateDetailSn
+          }
+          // 开始提交数据
+          _this.spinning = true
+          shelfTemplateDetailSave({ ...form, ...params }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.isShow = false
+              _this.$emit('ok', res.data)
+              _this.spinning = false
+            } else {
+              _this.spinning = false
+            }
+          })
+        } else {
+          return false
+        }
+      })
+    },
+    // 编辑赋值
+    setFormData () {
+      const product = this.nowData
+      this.form.shelfPlaceCode = this.nowData.shelfPlaceCode
+      this.form.productSn = product.productSn
+      this.form.productCode = product.productCode
+      this.form.price = product.price
+      this.form.cost = product.cost
+      this.form.maxQty = product.maxQty
+      this.$refs.productJqList.setData({ key: product.productCode })
+    },
+    // 重置表单
+    resetData () {
+      this.form.shelfPlaceCode = ''
+      this.form.productSn = undefined
+      this.form.productCode = undefined
+      this.form.price = ''
+      this.form.cost = ''
+      this.form.maxQty = ''
+      if (this.$refs.productJqList) {
+        this.$refs.productJqList.resetForm()
+      }
+      this.$refs.ruleForm.resetFields(['productSn'])
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.resetData()
+      } else {
+        if (this.type == 'edit') {
+          this.$nextTick(() => {
+            this.setFormData()
+          })
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+.shelfSet-newHw-modal {
+	.ant-modal-body {
+		padding: 40px 40px 24px;
+	}
+  .ant-form-item{
+    margin-bottom: 15px;
+  }
+	.btn-cont {
+		text-align: center;
+		margin: 35px 0 10px;
+	}
+}
+</style>

+ 133 - 0
src/views/numsGoodsShelves/shelfProductTempl/basicInfoModal.vue

@@ -0,0 +1,133 @@
+<template>
+  <a-modal
+    centered
+    class="shelfSet-basicInfo-modal"
+    :footer="null"
+    :maskClosable="false"
+    :title="form.templateSn?'更改名称':'新增模板'"
+    v-model="isShow"
+    @cancel="isShow = false"
+    :width="600">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-form-model
+        ref="ruleForm"
+        :model="form"
+        :rules="rules"
+        :label-col="formItemLayout.labelCol"
+        :wrapper-col="formItemLayout.wrapperCol">
+        <a-form-model-item label="模板名称" prop="templateName">
+          <a-input id="shelfTpl-templateName" v-model="form.templateName" :maxLength="30" placeholder="请输入模板名称(最多30个字符)"></a-input>
+        </a-form-model-item>
+      </a-form-model>
+      <div class="btn-cont">
+        <a-button id="shelfTpl-save" type="primary" @click="handleSave">保存</a-button>
+        <a-button id="shelfTpl-cancel" @click="isShow = false" style="margin-left: 15px;">取消</a-button>
+      </div>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+import { VSelect } from '@/components'
+import { shelfTemplateSave } from '@/api/shelfTemplate'
+export default {
+  name: 'ShelfSetBasicInfoModal',
+  components: { VSelect },
+  mixins: [commonMixin],
+  props: {
+    openModal: {
+      //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    nowData: { // 当前操作数据
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      spinning: false,
+      isShow: this.openModal, //  是否打开弹框
+      formItemLayout: {
+        labelCol: { span: 6 },
+        wrapperCol: { span: 17 }
+      },
+      form: {
+        templateName: '', // 模板名称
+        templateSn: undefined // 模板sn
+      },
+      rules: {
+        templateName: [{ required: true, message: '请输入模板名称', trigger: 'change' }]
+      }
+    }
+  },
+  methods: {
+    //  保存
+    handleSave () {
+      const _this = this
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          const form = JSON.parse(JSON.stringify(_this.form))
+          _this.spinning = true
+          shelfTemplateSave(form).then(res => {
+            if (res.status == 200) {
+              _this.$message.success('保存成功')
+              _this.$emit('ok', res.data)
+              _this.spinning = false
+            } else {
+              _this.spinning = false
+            }
+          })
+        } else {
+          return false
+        }
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.form.templateName = ''
+        this.form.templateSn = undefined
+        this.$refs.ruleForm.resetFields()
+      } else {
+        const _this = this
+        // 如果是编辑
+        if (_this.nowData) {
+          this.$nextTick(() => {
+            _this.form.templateName = _this.nowData.templateName || ''
+            if (_this.nowData.templateSn) {
+              _this.form.templateSn = _this.nowData.templateSn
+            }
+          })
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+.shelfSet-basicInfo-modal {
+	.ant-modal-body {
+		padding: 40px 40px 24px;
+	}
+  .ant-form-item{
+    margin-bottom: 15px;
+  }
+	.btn-cont {
+		text-align: center;
+		margin: 35px 0 10px;
+	}
+}
+</style>

+ 192 - 0
src/views/numsGoodsShelves/shelfProductTempl/chooseImportModal.vue

@@ -0,0 +1,192 @@
+<template>
+  <a-modal
+    centered
+    class="chooseImport-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="确认导入货位"
+    v-model="isShow"
+    @cancle="isShow=false"
+    :width="900">
+    <div class="chooseImport-con">
+      <!-- 可导入数据 -->
+      <p class="">可导入数据{{ loadData.length }}条</p>
+      <a-table
+        class="sTable"
+        ref="table"
+        size="small"
+        :rowKey="(record) => record.allocateSn"
+        :columns="nowColumns"
+        :dataSource="loadData"
+        :loading="loading"
+        :scroll="{ y: 200 }"
+        :pagination="false"
+        bordered>
+      </a-table>
+      <a-divider />
+      <!-- 不可导入数据 -->
+      <p class="red">不可导入数据{{ unLoadData.length }}条</p>
+      <a-table
+        class="unTable"
+        ref="unTable"
+        size="small"
+        :rowKey="(record) => record.errorDesc"
+        :columns="nowUnColumns"
+        :dataSource="unLoadData"
+        :loading="loading"
+        :scroll="{ y: 200 }"
+        :pagination="false"
+        bordered>
+      </a-table>
+      <!-- 按钮 -->
+      <div class="btn-con">
+        <a-button
+          type="primary"
+          id="chooseImport-submit"
+          size="large"
+          :disabled="disabled"
+          :class="loadData.length==0?'button-grey':'button-primary'"
+          @click="handleSubmit"
+          style="padding: 0 40px;">确认导入</a-button>
+        <a-button
+          id="chooseImport-cancel"
+          size="large"
+          :disabled="disabled"
+          class="button-cancel"
+          @click="isShow=false"
+          style="padding: 0 40px;margin-left: 15px;">取消</a-button>
+        <a-button
+          type="primary"
+          id="chooseImport-error"
+          size="large"
+          :disabled="disabled"
+          class="button-error"
+          @click="handleError"
+          style="padding: 0 40px;margin-left: 15px;">导出错误项</a-button>
+      </div>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { hdExportExcel } from '@/libs/exportExcel'
+import { shelfTemplateImportDetailError } from '@/api/shelfTemplate'
+import { toThousands } from '@/libs/tools.js'
+export default {
+  name: 'ChooseImportModal',
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    paramsData: { // 参数
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data () {
+    const _this = this
+    return {
+      toThousands,
+      isShow: this.openModal, //  是否打开弹框
+      nowColumns: [
+        { title: '序号', dataIndex: 'no', width: '8%', align: 'center' },
+        { title: '货位号', dataIndex: 'shelfPlaceCode', width: '8%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品编码', dataIndex: 'productCode', width: '35%', align: 'center', customRender: function (text) { return text || '--' } },
+        // { title: '产品名称', dataIndex: 'productName', width: '45%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '车主价', dataIndex: 'price', width: '8%', align: 'right', customRender: function (text) { return ((text || text == 0) && text.length ? _this.toThousands(text, 2) : '--') } },
+        { title: '结算价', dataIndex: 'cost', width: '8%', align: 'right', customRender: function (text) { return ((text || text == 0) && text.length ? _this.toThousands(text, 2) : '--') } },
+        { title: '最大库容', dataIndex: 'maxQty', width: '8%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } }
+      ],
+      loadData: [], // 正确数据
+      nowUnColumns: [
+        { title: '序号', dataIndex: 'no', width: '8%', align: 'center' },
+        { title: '货位号', dataIndex: 'shelfPlaceCode', width: '8%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品编码', dataIndex: 'productCode', width: '35%', align: 'center', customRender: function (text) { return text || '--' } },
+        // { title: '产品名称', dataIndex: 'productName', width: '30%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '车主价', dataIndex: 'price', width: '8%', align: 'right', customRender: function (text) { return ((text || text == 0) && text.length ? _this.toThousands(text, 2) : '--') } },
+        { title: '结算价', dataIndex: 'cost', width: '8%', align: 'right', customRender: function (text) { return ((text || text == 0) && text.length ? _this.toThousands(text, 2) : '--') } },
+        { title: '最大库容', dataIndex: 'maxQty', width: '8%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '错误原因', dataIndex: 'remark', width: '25%', align: 'center', customRender: function (text) { return text || '--' } }
+      ],
+      unLoadData: [], // 错误数据
+      loading: false,
+      disabled: false
+    }
+  },
+  methods: {
+    // 获取数据
+    getData () {
+      const paramsData = JSON.parse(JSON.stringify(this.paramsData))
+      this.loadData = paramsData.rightList || []
+      this.unLoadData = paramsData.errorList || []
+      this.loadData.map((item, index) => {
+        item.no = index + 1
+        item.templateSn = paramsData.templateSn
+      })
+      this.unLoadData.map((item, index) => {
+        item.no = index + 1
+        item.templateSn = paramsData.templateSn
+      })
+    },
+    // 确认导入
+    handleSubmit () {
+      if (this.paramsData.rightList.length == 0) {
+        this.$message.warning('无可导入的货位!')
+      } else {
+        const data = this.paramsData.rightList
+
+        this.$emit('ok', data)
+        this.isShow = false
+      }
+    },
+    // 导出错误项
+    handleError () {
+      const _this = this
+      if (_this.paramsData.errorList.length < 1) {
+        _this.$message.info('暂无可导出错误项~')
+        return
+      }
+      _this.spinning = true
+      hdExportExcel(shelfTemplateImportDetailError, _this.paramsData.errorList, '货架模板货位错误项', function () {
+        _this.spinning = false
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.loadData = []
+        this.unLoadData = []
+      } else {
+        this.getData()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .chooseImport-modal{
+    .chooseImport-con{
+      .red{
+        color: #f30;
+      }
+      .btn-con{
+        text-align: center;
+        margin: 30px 0 20px;
+        .button-cancel,.button-error{
+          font-size: 12px;
+        }
+      }
+    }
+  }
+</style>

+ 200 - 0
src/views/numsGoodsShelves/shelfProductTempl/importGuideModal.vue

@@ -0,0 +1,200 @@
+<template>
+  <a-modal
+    centered
+    class="importGuide-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="导入绑定产品"
+    v-model="isShow"
+    @cancel="isShow=false"
+    :width="750">
+    <div class="importGuide-con">
+      <div class="explain-con">
+        <div class="explain-item">
+          <div class="explain-tit">
+            <span>1</span>下载导入模板
+          </div>
+          <p>请按照下载的Excel模板填写数据</p>
+          <a :href="filePath" style="padding: 5px 0 0 23px;display: block;">
+            <a-icon type="download" style="padding-right: 5px;" />下载导入模板
+          </a>
+        </div>
+        <div class="explain-item">
+          <div class="explain-tit">
+            <span>2</span>准备导入数据
+          </div>
+          <ul>
+            <li>1) 导入的Excel文件中必须包含名为“货位号”、“产品编码”、“车主价”、“结算价”、“最大库容”的列,且名称必须相同</li>
+            <li>2) 除了“货位号”、“产品编码”、“车主价”、“结算价”、“最大库容”四列,其他列可自定义,不影响数据导入</li>
+          </ul>
+        </div>
+        <div class="explain-item">
+          <div class="explain-tit">
+            <span>3</span>上传数据文件
+          </div>
+          <p>目前支持的文件类型*.xls,*.xlsx.</p>
+          <div style="overflow: hidden;padding-left: 23px;">
+            <Upload
+              id="importGuide-attachList"
+              ref="importUpload"
+              :maxNums="1"
+              fileType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel"
+              uploadType="attach"
+              :action="attachAction"
+              :uploadParams="uploadParams"
+              upText="选择导入文件"
+              @remove="resetSearchForm"
+              @change="changeImport"></Upload>
+          </div>
+        </div>
+      </div>
+      <!-- 按钮 -->
+      <div class="btn-con">
+        <a-button
+          type="primary"
+          id="importGuide-nextStep"
+          size="large"
+          class="button-primary"
+          @click="handlerNextStep"
+          style="padding: 0 60px;">下一步</a-button>
+        <a-button
+          id="importGuide-cancel"
+          size="large"
+          class="button-cancel"
+          @click="isShow=false"
+          style="padding: 0 60px;margin-left: 15px;">取消</a-button>
+      </div>
+    </div>
+    <!-- 导入 -->
+    <chooseImportModal :openModal="openImportModal" :paramsData="paramsData" @close="handleClose" @ok="hanldeOk" />
+  </a-modal>
+</template>
+
+<script>
+import ChooseImportModal from './chooseImportModal.vue'
+import { Upload } from '@/components'
+export default {
+  name: 'ImportGuideModal',
+  components: { ChooseImportModal, Upload },
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    params: { // 参数
+      type: Object,
+      default: null
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      openImportModal: false, //  导入
+      attachAction: process.env.VUE_APP_API_BASE_URL + '/shelfTemplate/detail/importDetail',
+      filePath: location.protocol + '//' + location.host + '/templ/绑定产品导入模板.xlsx',
+      paramsData: null,
+      uploadParams: { // 参数
+        savePathType: 'local',
+        templateSn: this.params.templateSn
+      }
+    }
+  },
+  methods: {
+    // 清空数据
+    resetSearchForm () {
+      this.$refs.importUpload.setFileList() //  清空导入文件
+      this.paramsData = null //  清空上传数据
+    },
+    // 下一步
+    handlerNextStep () {
+      if (this.paramsData) {
+        this.openImportModal = true
+      } else {
+        this.$message.warning('添加文件后再进行下一步操作!')
+      }
+    },
+    // 上传文件  change
+    changeImport (file) {
+      if (file && JSON.parse(file).length > 0) {
+        this.paramsData = Object.assign({}, JSON.parse(file)[0] || null, this.params)
+      } else {
+        this.paramsData = null
+      }
+    },
+    // 导入
+    hanldeOk (obj) {
+      if (obj && obj.length > 0) {
+        this.$emit('ok', obj)
+        this.isShow = false
+      }
+    },
+    // 关闭
+    handleClose () {
+      this.openImportModal = false
+      this.isShow = false
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.paramsData = null
+        this.$refs.importUpload.setFileList('')
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .importGuide-modal{
+    .importGuide-con{
+      .explain-con{
+        .explain-item{
+          margin-bottom: 10px;
+          .explain-tit{
+            font-weight: bold;
+            span{
+              display: inline-block;
+              width: 18px;
+              height: 18px;
+              line-height: 16px;
+              text-align: center;
+              margin-right: 5px;
+              border-radius: 50%;
+              border: 1px solid rgba(0, 0, 0, 0.3);
+            }
+          }
+          p{
+            margin: 8px 0;
+            padding-left: 23px;
+          }
+          ul{
+            list-style: none;
+            padding: 0;
+            padding-left: 23px;
+            margin: 0;
+            li{
+              line-height: 26px;
+            }
+          }
+        }
+        #importGuide-attachList{
+          width: 100%;
+        }
+      }
+      .btn-con{
+        margin: 10px 0 20px;
+        text-align: center;
+        .button-cancel{
+          font-size: 12px;
+        }
+      }
+    }
+  }
+</style>

+ 234 - 0
src/views/numsGoodsShelves/shelfProductTempl/list.vue

@@ -0,0 +1,234 @@
+<template>
+  <a-card size="small" :bordered="false" class="shelfSetList-wrap">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <!-- 搜索条件 -->
+      <div ref="tableSearch" 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-input id="shelfPlList-templateName" v-model.trim="queryParam.templateName" allowClear placeholder="请输入模板名称"/>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="模板类型">
+                <v-select
+                  id="shelfPlList-sysFlag"
+                  v-model="queryParam.sysFlag"
+                  code="SHELF_TEMPLATE_SYS_FLAG"
+                  placeholder="请选择模板类型"
+                  allowClear></v-select>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24" style="margin-bottom: 10px">
+              <a-button type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="shelfPlList-refresh">查询</a-button>
+              <a-button style="margin-left: 5px" @click="resetSearchForm" :disabled="disabled" id="shelfPlList-reset">重置</a-button>
+            </a-col>
+          </a-row>
+        </a-form>
+      </div>
+      <div class="table-operator">
+        <a-button v-if="orgData.length<20" type="primary" class="button-error" @click="addTemp" id="shelfPlList-addTemp">新增</a-button>
+      </div>
+      <!-- 列表 -->
+      <s-table
+        class="sTable fixPagination"
+        ref="table"
+        :style="{ height: tableHeight+84.5+'px' }"
+        size="small"
+        :rowKey="(record) => record.id"
+        :columns="columns"
+        :data="loadData"
+        :scroll="{ y: tableHeight }"
+        :defaultLoadData="false"
+        bordered>
+        <!-- 模板名称 -->
+        <template slot="templateName" slot-scope="text, record">
+          <span class="table-td-link" id="shelfPlList-links" @click="handleDetail(record)">{{ record.templateName }}</span>
+        </template>
+        <!-- 操作 -->
+        <template slot="action" slot-scope="text, record">
+          <div>
+            <a-button
+              id="shelfPlList-edit"
+              size="small"
+              v-if="record.sysFlag==0"
+              type="link"
+              class="button-primary"
+              @click="addTemp(record)">更改名称</a-button>
+            <a-button
+              v-if="orgData.length<20"
+              id="shelfPlList-copy"
+              size="small"
+              type="link"
+              class="button-primary"
+              @click="handleCopy(record)">复制</a-button>
+            <a-button
+              id="shelfPlList-del"
+              size="small"
+              v-if="record.sysFlag==0"
+              type="link"
+              class="button-error"
+              @click="handleCancel(record)">删除</a-button>
+          </div>
+        </template>
+      </s-table>
+    </a-spin>
+    <!-- 基础设置弹框 -->
+    <basic-info-modal :openModal="openModal" :nowData="nowData" @ok="saveOk" @close="openModal=false" />
+  </a-card>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+import { STable, VSelect } from '@/components'
+import basicInfoModal from './basicInfoModal.vue'
+import commonModal from '@/views/common/commonModal.vue'
+import { shelfTemplateList, shelfTemplateCopy, shelfTemplateDel } from '@/api/shelfTemplate'
+export default {
+  name: 'ShelfProductTemplList',
+  components: { STable, VSelect, basicInfoModal, commonModal },
+  mixins: [commonMixin],
+  data () {
+    return {
+      spinning: false,
+      tableHeight: 0,
+      disabled: false, //  查询、重置按钮是否可操作
+      queryParam: {
+        templateName: '', // 模板名称
+        sysFlag: undefined // 模板类型
+      },
+      columns: [
+        { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
+        { title: '模板类型', dataIndex: 'sysFlagDictValue', width: '20%', align: 'center' },
+        { title: '模板名称', scopedSlots: { customRender: 'templateName' }, width: '50%', align: 'left', ellipsis: true },
+        { title: '产品款数', dataIndex: 'productCategory', width: '15%', align: 'center' },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: '11%', align: 'center' }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        this.spinning = true
+        return shelfTemplateList(Object.assign(parameter, this.queryParam)).then(res => {
+          let data
+          if (res.status == 200) {
+            data = res.data
+            const no = (data.pageNo - 1) * data.pageSize
+            for (var i = 0; i < data.list.length; i++) {
+              data.list[i].no = no + i + 1
+            }
+            this.disabled = false
+          }
+          this.spinning = false
+          this.orgData = data.list
+          return data
+        })
+      },
+      orgData: [], // 原始列表数据
+      openModal: false, // 打开新增编辑弹框
+      nowData: null // 当前操作数据
+    }
+  },
+  methods: {
+    // 新增/修改模板
+    addTemp (row) {
+      this.nowData = row || {}
+      this.openModal = true
+    },
+    // 模板详情设置
+    handleDetail (data) {
+      this.$router.push({ name: 'shelfProductTemplSetting', params: { sn: data.templateSn } })
+    },
+    // 复制模板
+    handleCopy (record) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '复制选择的内置模板,将在列表生成一条相同的模板,可进行编辑!是否确认生成?',
+        centered: true,
+        closable: true,
+        onOk () {
+          _this.spinning = true
+          shelfTemplateCopy({
+            templateSn: record.templateSn
+          }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.resetSearchForm()
+            }
+            _this.spinning = false
+          })
+        }
+      })
+    },
+    // 删除模板
+    handleCancel (record) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '删除模板后,模板信息将全部清除,是否确认删除?',
+        centered: true,
+        closable: true,
+        onOk () {
+          _this.spinning = true
+          shelfTemplateDel({
+            templateSn: record.templateSn
+          }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$refs.table.refresh()
+            }
+            _this.spinning = false
+          })
+        }
+      })
+    },
+    // 保存成功
+    saveOk () {
+      this.$refs.table.refresh(true)
+      this.openModal = false
+    },
+    // 重置
+    resetSearchForm () {
+      this.queryParam.templateName = ''
+      this.queryParam.sysFlag = undefined
+      this.$refs.table.refresh(true)
+    },
+    // 表格高度
+    setTableH () {
+      const tableSearchH = this.$refs.tableSearch.offsetHeight
+      this.tableHeight = window.innerHeight - tableSearchH - 235
+    },
+    // 初始化页面
+    pageInit () {
+      const _this = this
+      this.$nextTick(() => { // 页面渲染完成后的回调
+        _this.setTableH()
+      })
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
+      this.pageInit()
+      this.resetSearchForm()
+    }
+  },
+  watch: {
+    '$store.state.app.winHeight' (newValue, oldValue) { //  窗口变更时,需同时更改表格高度
+      this.setTableH()
+    }
+  },
+  activated () {
+    // 如果是新页签打开,则重置当前页面
+    if (this.$store.state.app.isNewTab) {
+      this.pageInit()
+      this.resetSearchForm()
+    }
+    // 仅刷新列表,不重置页面
+    if (this.$store.state.app.updateList) {
+      this.pageInit()
+      this.$refs.table.refresh()
+    }
+  }
+}
+</script>

+ 260 - 0
src/views/numsGoodsShelves/shelfProductTempl/set.vue

@@ -0,0 +1,260 @@
+<template>
+  <div class="shelfSet-wrap">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-page-header :ghost="false" :backIcon="false" @back="handleBack" >
+        <!-- 自定义的二级文字标题 -->
+        <template slot="subTitle">
+          <a href="javascript:;" @click="handleBack"><a-icon type="left" /> 返回列表</a>
+          <span style="margin-left:10px;" v-if="basicInfoData">模板名称:{{ basicInfoData&&basicInfoData.templateName || '--' }}</span>
+        </template>
+      </a-page-header>
+      <!-- 页面内容 -->
+      <a-card size="small" :bordered="false" class="shelfSet-cont">
+        <!-- 搜索条件 -->
+        <div ref="tableSearch" 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-input id="shelfPlSet-shelfPlaceCode" v-model.trim="queryParam.shelfPlaceCode" allowClear placeholder="请输入货位号"/>
+                </a-form-item>
+              </a-col>
+              <a-col :md="6" :sm="24">
+                <a-form-item label="产品编码">
+                  <a-input id="shelfPlSet-productCode" v-model.trim="queryParam.productCode" allowClear placeholder="请输入产品编码"/>
+                </a-form-item>
+              </a-col>
+              <a-col :md="6" :sm="24">
+                <span class="table-page-search-submitButtons">
+                  <a-button type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="shelfPlSet-refresh">查询</a-button>
+                  <a-button style="margin-left: 5px" @click="resetSearchForm()" :disabled="disabled" id="shelfPlSet-reset">重置</a-button>
+                </span>
+              </a-col>
+            </a-row>
+          </a-form>
+        </div>
+        <!-- 操作按钮 -->
+        <div class="table-operator" v-if="basicInfoData&&basicInfoData.sysFlag==0">
+          <a-button id="shelfPlSet-addHW" type="primary" class="button-error" @click="addHW">新增</a-button>
+          <a-button id="shelfPlSet-import" type="primary" class="button-info" @click="openGuideModal=true">导入</a-button>
+        </div>
+        <!-- 列表 -->
+        <s-table
+          class="sTable"
+          ref="table"
+          size="small"
+          :scroll="{ y: tableHeight }"
+          :rowKey="(record) => record.id"
+          :columns="columns"
+          :data="loadData"
+          :defaultLoadData="false"
+          bordered>
+          <span slot="customTitle">
+            结算价
+            <a-popover>
+              <template slot="content">
+                即易码通进货价
+              </template>
+              <a-icon type="question-circle"/>
+            </a-popover>
+          </span>
+          <!-- 操作 -->
+          <template slot="action" slot-scope="text, record">
+            <a-button
+              size="small"
+              type="link"
+              class="button-primary"
+              @click="editHW(record)"
+              id="shelfPlSet-detail-edit"
+            >编辑</a-button>
+            <a-button
+              size="small"
+              type="link"
+              class="button-error"
+              @click="handleDel(record)"
+              id="shelfPlSet-detail-del"
+            >删除</a-button>
+          </template>
+        </s-table>
+      </a-card>
+    </a-spin>
+    <!-- 编辑、新增 -->
+    <addHwModal :openModal="openHwModal" :type="modalType" :nowData="nowData" @ok="$refs.table.refresh()" @close="handleCancel" />
+    <!-- 导入产品 -->
+    <importGuideModal :openModal="openGuideModal" :params="{templateSn: $route.params.sn}" @close="openGuideModal=false" @ok="handleGuideOk" />
+  </div>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+import { STable, VSelect } from '@/components'
+import commonModal from '@/views/common/commonModal.vue'
+import addHwModal from './addHwModal.vue'
+import ImportGuideModal from './importGuideModal.vue'
+import { shelfTemplateDetail, shelfTemplateDetailList, shelfTemplateDetailBySn, shelfTemplateDetailImportSave } from '@/api/shelfTemplate'
+export default {
+  name: 'ShelfMonitoringWarehousing',
+  components: { STable, VSelect, commonModal, addHwModal, ImportGuideModal },
+  mixins: [commonMixin],
+  data () {
+    return {
+      spinning: false,
+      disabled: false, //  查询、重置按钮是否可操作
+      tableHeight: 400, // 表格高度
+      queryParam: {
+        productCode: '', // 产品编码
+        shelfPlaceCode: '' // 货位号
+      },
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        this.spinning = true
+        return shelfTemplateDetailList(Object.assign(parameter, this.queryParam, { templateSn: this.$route.params.sn })).then(res => {
+          let data
+          if (res.status == 200) {
+            data = res.data
+            const no = (data.pageNo - 1) * data.pageSize
+            for (var i = 0; i < data.list.length; i++) {
+              data.list[i].no = no + i + 1
+            }
+          }
+          this.disabled = false
+          this.spinning = false
+          return data
+        })
+      },
+      basicInfoData: null, // 模板详细信息
+      nowData: null, // 当前修改的数据
+      openGuideModal: false, // 导入产品
+      modalType: null, // 新增or编辑
+      openHwModal: false // 打开新增编辑弹框
+    }
+  },
+  computed: {
+    columns () {
+      const _this = this
+      const ret = [
+        { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
+        { title: '货位号', dataIndex: 'shelfPlaceCode', width: '15%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品编码', dataIndex: 'productCode', width: '25%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '车主价', dataIndex: 'price', width: '15%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text, 2) : '--') } },
+        { slots: { title: 'customTitle' }, dataIndex: 'cost', width: '15%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text, 2) : '--') } },
+        { title: '最大库容', dataIndex: 'maxQty', width: '15%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } }
+      ]
+      // 内置模板没有操作这一列
+      if (this.basicInfoData && this.basicInfoData.sysFlag == 0) {
+        ret.push({ title: '操作', scopedSlots: { customRender: 'action' }, width: '15%', align: 'center' })
+      }
+      return ret
+    }
+  },
+  methods: {
+    //  返回列表
+    handleBack () {
+      this.$router.push({ name: 'shelfProductTemplList' })
+    },
+    // 新增货位
+    addHW () {
+      this.handleProduct(null, 'add')
+    },
+    // 编辑货位
+    editHW (row) {
+      this.handleProduct(row, 'edit')
+    },
+    // 绑定产品/修改信息
+    handleProduct (row, type) {
+      if (row) {
+        this.nowData = Object.assign(row, { templateSn: this.basicInfoData && this.basicInfoData.templateSn })
+      } else {
+        this.nowData = this.basicInfoData
+      }
+      this.modalType = type
+      this.openHwModal = true
+    },
+    // 关闭弹框
+    handleCancel () {
+      this.modalType = null
+      this.nowData = null
+      this.openHwModal = false
+      this.openHwModal = false
+    },
+    // 基本信息
+    getDetail () {
+      shelfTemplateDetail({ templateSn: this.$route.params.sn }).then(res => {
+        if (res.status == 200) {
+          this.basicInfoData = res.data
+        } else {
+          this.basicInfoData = null
+        }
+      })
+    },
+    // 删除
+    handleDel (row) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '删除后无法恢复,确认删除?',
+        centered: true,
+        onOk () {
+          _this.spinning = true
+          shelfTemplateDetailBySn({ templateDetailSn: row.templateDetailSn }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$refs.table.refresh()
+            }
+            _this.spinning = false
+          })
+        }
+      })
+    },
+    // 导入成功
+    handleGuideOk (obj) {
+      shelfTemplateDetailImportSave(obj).then(res => {
+        if (res.status == 200) {
+          this.$refs.table.refresh(true)
+        }
+      })
+    },
+    //  重置
+    resetSearchForm () {
+      this.queryParam.productCode = ''
+      this.queryParam.shelfPlaceCode = ''
+      this.$refs.table.refresh(true)
+    },
+    // 计算表格高度
+    setTableH () {
+      const tableSearchH = this.$refs.tableSearch.offsetHeight
+      this.tableHeight = window.innerHeight - tableSearchH - 350
+    },
+    // 初始页面
+    pageInit () {
+      this.setTableH()
+      this.getDetail()
+      this.resetSearchForm()
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
+      this.pageInit()
+    }
+  },
+  activated () {
+    // 如果是新页签打开或者进入新的子页(例:存在列表第2条数据编辑页页签时再打开第4条数据的编辑页),则重置当前页面
+    if (this.$store.state.app.isNewTab || !this.$store.state.app.isNewSubTab) {
+      this.pageInit()
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .shelfSet-wrap{
+    .store-info{
+      margin: 0 15px;
+      color: rgb(102, 102, 102);
+    }
+    .shelfSet-cont{
+      margin-top: 10px;
+    }
+  }
+</style>

+ 28 - 27
src/views/numsGoodsShelves/shelfSet/addHwModal.vue

@@ -18,10 +18,10 @@
         :wrapper-col="formItemLayout.wrapperCol">
         <a-form-model-item label="货架名称">{{ nowData&&nowData.shelfName || '--' }}</a-form-model-item>
         <a-form-model-item label="货位号" prop="shelfPlaceCode">
-          <a-input v-model="form.shelfPlaceCode" @input="placeCodeBlur" placeholder="请输入货位号(字母+数字格式)"></a-input>
+          <a-input id="shelfSet-newHw-shelfPlaceCode" v-model="form.shelfPlaceCode" @input="placeCodeBlur" placeholder="请输入货位号(字母+数字格式)"></a-input>
         </a-form-model-item>
         <a-form-model-item label="绑定产品" v-if="type=='add'">
-          <productJqList ref="productJqList" :params="{customerSn:nowData&&nowData.customerSn}" @change="productJqChange"></productJqList>
+          <productJqList id="shelfSet-newHw-product" ref="productJqList" :params="{customerSn:nowData&&nowData.customerSn}" @change="productJqChange"></productJqList>
         </a-form-model-item>
         <a-form-model-item label="产品名称" v-if="form.productSn">{{ productName || '--' }}</a-form-model-item>
         <a-form-model-item v-if="form.productSn" label="车主价" prop="price">
@@ -68,22 +68,22 @@
 <script>
 import { commonMixin } from '@/utils/mixin'
 import { VSelect } from '@/components'
-import productJqList from '@/views/common/productJqList.vue'
-import { addPlaceAndProduct } from '@/api/shelf'
+import productJqList from '@/views/common/productJqList.vue' // 货架产品列表组件
+import { addPlaceAndProduct } from '@/api/shelf' // 接口
 export default {
   name: 'AddHwModal',
   components: { VSelect, productJqList },
   mixins: [commonMixin],
   props: {
-    openModal: { //  弹框显示状态
+    openModal: { // 弹框显示状态
       type: Boolean,
       default: false
     },
-    type: {
+    type: { // 编辑or新增
       type: String,
       default: ''
     },
-    nowData: {
+    nowData: { // 当前操作数据
       type: Object,
       default: () => {
         return {}
@@ -98,30 +98,30 @@ export default {
         labelCol: { span: 4 },
         wrapperCol: { span: 18 }
       },
+      // 表单数据
       form: {
-        shelfPlaceCode: '',
-        productSn: undefined,
-        productCode: undefined,
-        price: '',
-        cost: '',
-        maxQty: ''
+        shelfPlaceCode: '', // 货位号
+        productSn: undefined, // 产品sn
+        productCode: undefined, // 产品编码
+        price: '', // 车主价
+        cost: '', // 结算价
+        maxQty: '' // 最大库容
       },
+      // 规则校验
       rules: {
         shelfPlaceCode: [
           { required: true, message: '请输入货位号', trigger: 'blur' },
-          {
-          	pattern: /^[a-zA-Z]{1}[0-9]{1,29}$/g,
-          	message: '货位号必需字母+数字,且不能超过30个字符'
-          }
+          { pattern: /^[a-zA-Z]{1}[0-9]{1,29}$/g, message: '货位号必需字母+数字,且不能超过30个字符' }
         ],
         price: [{ required: true, message: '请输入销售价', trigger: 'blur' }],
         cost: [{ required: true, message: '请输入结算价', trigger: 'blur' }],
         maxQty: [{ required: true, message: '请输入最大库容', trigger: 'blur' }]
       },
-      productName: ''
+      productName: '' // 产品名称
     }
   },
   computed: {
+    // 弹框标题
     modalTit () {
       let title = ''
       if (this.type == 'edit') {
@@ -133,7 +133,7 @@ export default {
     }
   },
   methods: {
-    // 产品 change
+    // 选择产品
     productJqChange (obj) {
       this.form.productSn = obj.key || undefined
       this.form.productCode = obj && obj.row && obj.row.code || ''
@@ -144,12 +144,13 @@ export default {
       this.form.oldCost = obj && obj.row && obj.row.cost || ''
       this.form.oldMaxQty = ''
     },
+    // 货位号变更
     placeCodeBlur (v) {
-    	this.$nextTick(() => {
-    		this.form.shelfPlaceCode = this.form.shelfPlaceCode.toLocaleUpperCase()
-    	})
+      this.$nextTick(() => {
+        this.form.shelfPlaceCode = this.form.shelfPlaceCode.toLocaleUpperCase()
+      })
     },
-    //  保存
+    // 保存
     handleSave () {
       const _this = this
       this.$refs.ruleForm.validate(valid => {
@@ -181,16 +182,15 @@ export default {
               _this.$message.success(res.message)
               _this.isShow = false
               _this.$emit('ok', res.data)
-              _this.spinning = false
-            } else {
-              _this.spinning = false
             }
+            _this.spinning = false
           })
         } else {
           return false
         }
       })
     },
+    // 重置表单
     resetData () {
       this.form.productSn = undefined
       this.form.productCode = undefined
@@ -201,6 +201,7 @@ export default {
         this.$refs.productJqList.resetForm()
       }
       this.$refs.ruleForm.resetFields(['productSn'])
+      this.productName = ''
     }
   },
   watch: {
@@ -213,8 +214,8 @@ export default {
       if (!newValue) {
         this.$emit('close')
         this.resetData()
-        this.productName = ''
       } else {
+        // 如果是编辑
         if (this.type == 'edit') {
           this.form.shelfPlaceCode = this.nowData.shelfPlaceCode
         }

+ 14 - 13
src/views/numsGoodsShelves/shelfSet/basicInfoModal.vue

@@ -18,7 +18,7 @@
         :label-col="formItemLayout.labelCol"
         :wrapper-col="formItemLayout.wrapperCol">
         <a-form-model-item label="货架名称" v-if="type==1" prop="shelfName">
-          <a-input v-model="form.shelfName" :maxLength="30" placeholder="请输入货架名称"></a-input>
+          <a-input id="shelfSet-basicInfo-modal-shelfName" v-model="form.shelfName" :maxLength="30" placeholder="请输入货架名称"></a-input>
         </a-form-model-item>
         <a-form-model-item prop="customerSn">
           <template slot="label">
@@ -29,7 +29,7 @@
               关联客户<a-icon type="question-circle" style="color: rgba(0,0,0,.65);font-size: 16px;margin-left: 2px;vertical-align: sub;cursor: pointer;" />
             </a-tooltip>
           </template>
-          <custList ref="custList" :dealerFlag="0" :isEnabled="true" @change="custChange"></custList>
+          <custList id="shelfSet-basicInfo-modal-custList" ref="custList" :dealerFlag="0" :isEnabled="true" @change="custChange"></custList>
         </a-form-model-item>
         <a-form-model-item prop="showPrice">
           <template slot="label">
@@ -40,7 +40,7 @@
               价格权限设置<a-icon type="question-circle" style="color: rgba(0,0,0,.65);font-size: 16px;margin-left: 2px;vertical-align: sub;cursor: pointer;" />
             </a-tooltip>
           </template>
-          <a-checkbox-group v-model="form.showPrice">
+          <a-checkbox-group v-model="form.showPrice" id="shelfSet-basicInfo-showPrice-checkbox">
             <div style="display: flex;padding:10px 0;">
               <div style="width: 80px;font-weight: bold;">货架产品:</div>
               <a-checkbox value="shelf_price_show">
@@ -81,17 +81,17 @@ export default {
   mixins: [commonMixin],
   props: {
     openModal: {
-      //  弹框显示状态
+      // 弹框显示状态
       type: Boolean,
       default: false
     },
-    nowData: {
+    nowData: { // 当前操作数据
       type: Object,
       default: () => {
         return {}
       }
     },
-    type: {
+    type: { // 新增or查看
       type: [String, Number],
       default: '1'
     }
@@ -105,19 +105,19 @@ export default {
         wrapperCol: { span: 17 }
       },
       form: {
-        customerSn: undefined,
-        shelfName: '',
-        showPrice: undefined
+        customerSn: undefined, // 关联客户sn
+        shelfName: '', // 货架名称
+        showPrice: undefined // 价格显示
       },
       rules: {
         shelfName: [{ required: true, message: '请输入货架名称', trigger: 'change' }],
-        customerSn: [{ required: true, message: '请选择关联客户', trigger: 'change' }],
+        customerSn: [{ required: true, message: '请选择关联客户', trigger: 'change' }]
         // showPrice: [{ required: true, message: '请选择价格显示', trigger: 'change' }]
       }
     }
   },
   methods: {
-    // 客户 change
+    // 选择关联客户
     custChange (obj, row) {
       this.form.customerSn = row && row.customerSn || undefined
     },
@@ -129,6 +129,7 @@ export default {
           const form = JSON.parse(JSON.stringify(_this.form))
           form.shelfSn = _this.nowData && _this.nowData.shelfSn
           _this.spinning = true
+          // 保存货架信息
           shelfSave(form).then(res => {
             if (res.status == 200) {
               const paramValue = []
@@ -138,7 +139,7 @@ export default {
                   paramValue: form.showPrice.includes(item.paramCode) ? 1 : 0
                 })
               })
-              // 更新价格显示
+              // 更新价格显示设置
               updateShelfPriceShow({
                 shelfSn: form.shelfSn,
                 paramValue: paramValue
@@ -159,7 +160,6 @@ export default {
             }
           })
         } else {
-          console.log('error submit!!')
           return false
         }
       })
@@ -182,6 +182,7 @@ export default {
           _this.form.shelfName = _this.nowData.shelfName
           _this.form.showPrice = _this.nowData.showPrice.filter(item => item.paramValue == 1).map(item => item.paramCode)
           const custome = _this.nowData.customerEntity
+          // 如果关联了客户
           if (custome) {
             _this.form.customerSn = custome.customerSn || ''
             _this.$refs.custList.fetchUser(custome.customerName || '')

+ 13 - 12
src/views/numsGoodsShelves/shelfSet/bindProductModal.vue

@@ -23,7 +23,7 @@
           <p style="margin: 0;">{{ productInfo&&productInfo.productName || '--' }}</p>
         </a-form-model-item>
         <a-form-model-item :label="type!='bind'?'新绑定产品':'绑定产品'" prop="productSn" v-if="type!='edit'">
-          <productJqList ref="productJqList" :params="{customerSn:nowData&&nowData.customerSn}" @change="productJqChange"></productJqList>
+          <productJqList id="shelfSet-bindProduct-product" ref="productJqList" :params="{customerSn:nowData&&nowData.customerSn}" @change="productJqChange"></productJqList>
           <span v-if="form.productSn">{{ productName || '--' }}</span>
         </a-form-model-item>
         <a-form-model-item label="车主价" prop="price">
@@ -80,11 +80,11 @@ export default {
       type: Boolean,
       default: false
     },
-    type: {
+    type: { // 编辑、新增
       type: String,
       default: ''
     },
-    nowData: {
+    nowData: { // 当前操作数据
       type: Object,
       default: () => {
         return {}
@@ -100,11 +100,11 @@ export default {
         wrapperCol: { span: 18 }
       },
       form: {
-        productSn: undefined,
-        productCode: undefined,
-        price: '',
-        cost: '',
-        maxQty: ''
+        productSn: undefined, // 产品sn
+        productCode: undefined, // 产品编码
+        price: '', // 车主价
+        cost: '', // 结算价
+        maxQty: '' // 最大库容
       },
       rules: {
         productSn: [{ required: true, message: '请选择绑定产品', trigger: 'change' }],
@@ -112,11 +112,12 @@ export default {
         cost: [{ required: true, message: '请输入结算价', trigger: 'change' }],
         maxQty: [{ required: true, message: '请输入最大库容', trigger: 'change' }]
       },
-      productName: '',
-      productInfo: null
+      productName: '', // 产品名称
+      productInfo: null // 产品信息
     }
   },
   computed: {
+    // 弹框标题
     modalTit () {
       let title = ''
       if (this.type == 'edit') {
@@ -130,7 +131,7 @@ export default {
     }
   },
   methods: {
-    // 产品 change
+    // 选择产品
     productJqChange (obj) {
       this.form.productSn = obj.key || undefined
       this.form.productCode = obj && obj.row && obj.row.code || ''
@@ -167,7 +168,6 @@ export default {
             }
           })
         } else {
-          console.log('error submit!!')
           return false
         }
       })
@@ -193,6 +193,7 @@ export default {
         }
       })
     },
+    // 重置表单
     resetData () {
       this.productName = ''
       this.productInfo = null

+ 6 - 3
src/views/numsGoodsShelves/shelfSet/chooseImportModal.vue

@@ -68,7 +68,7 @@ export default {
       type: Boolean,
       default: false
     },
-    paramsData: {
+    paramsData: { // 参数
       type: Object,
       default: () => {
         return {}
@@ -99,23 +99,26 @@ export default {
         { title: '最大库容', dataIndex: 'maxQty', width: '8%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
         { title: '错误原因', dataIndex: 'remarks', width: '17%', align: 'left', customRender: function (text) { return text || '--' }, ellipsis: true }
       ],
-      loadData: [],
-      unLoadData: [],
+      loadData: [], // 正常表格数据
+      unLoadData: [], // 错误表格数据
       loading: false
     }
   },
   methods: {
+    // 获取表格数据
     getData () {
       const _this = this
       this.loading = true
       shelfProductParseProducts(this.paramsData).then(res => {
         this.loading = false
         if (res.status == 200) {
+          // 正确列表
           if (res.data.successList && res.data.successList.length > 0) {
             res.data.successList.map((item, index) => {
               item.no = index + 1
             })
           }
+          // 错误列表
           if (res.data.failList && res.data.failList.length > 0) {
             res.data.failList.map((item, index) => {
               item.no = index + 1

+ 11 - 8
src/views/numsGoodsShelves/shelfSet/chooseShelfImportModal.vue

@@ -79,7 +79,7 @@ export default {
       type: Boolean,
       default: false
     },
-    paramsData: {
+    paramsData: { // 参数
       type: Object,
       default: () => {
         return {}
@@ -96,27 +96,28 @@ export default {
         { title: '货位号', dataIndex: 'shelfPlaceCode', width: '8%', align: 'center', customRender: function (text) { return text || '--' } },
         { title: '产品编码', dataIndex: 'productCode', width: '15%', align: 'center', customRender: function (text) { return text || '--' } },
         { title: '产品名称', dataIndex: 'productName', width: '45%', align: 'center', customRender: function (text) { return text || '--' } },
-        { title: '车主价', dataIndex: 'price', width: '8%', align: 'right', customRender: function (text) { return ((text || text == 0)&&text.length ? _this.toThousands(text, 2) : '--') } },
-        { title: '结算价', dataIndex: 'cost', width: '8%', align: 'right', customRender: function (text) { return ((text || text == 0)&&text.length ? _this.toThousands(text, 2) : '--') } },
+        { title: '车主价', dataIndex: 'price', width: '8%', align: 'right', customRender: function (text) { return ((text || text == 0) && text.length ? _this.toThousands(text, 2) : '--') } },
+        { title: '结算价', dataIndex: 'cost', width: '8%', align: 'right', customRender: function (text) { return ((text || text == 0) && text.length ? _this.toThousands(text, 2) : '--') } },
         { title: '最大库容', dataIndex: 'maxQty', width: '8%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } }
       ],
-      loadData: [],
+      loadData: [], // 正确列表数据
       nowUnColumns: [
         { title: '序号', dataIndex: 'no', width: '8%', align: 'center' },
         { title: '货位号', dataIndex: 'shelfPlaceCode', width: '8%', align: 'center', customRender: function (text) { return text || '--' } },
         { title: '产品编码', dataIndex: 'productCode', width: '15%', align: 'center', customRender: function (text) { return text || '--' } },
         { title: '产品名称', dataIndex: 'productName', width: '30%', align: 'center', customRender: function (text) { return text || '--' } },
-        { title: '车主价', dataIndex: 'price', width: '8%', align: 'right', customRender: function (text) { return ((text || text == 0)&&text.length ? _this.toThousands(text, 2) : '--') } },
-        { title: '结算价', dataIndex: 'cost', width: '8%', align: 'right', customRender: function (text) { return ((text || text == 0)&&text.length ? _this.toThousands(text, 2) : '--') } },
+        { title: '车主价', dataIndex: 'price', width: '8%', align: 'right', customRender: function (text) { return ((text || text == 0) && text.length ? _this.toThousands(text, 2) : '--') } },
+        { title: '结算价', dataIndex: 'cost', width: '8%', align: 'right', customRender: function (text) { return ((text || text == 0) && text.length ? _this.toThousands(text, 2) : '--') } },
         { title: '最大库容', dataIndex: 'maxQty', width: '8%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
         { title: '错误原因', dataIndex: 'remarks', width: '15%', align: 'center', customRender: function (text) { return text || '--' } }
       ],
-      unLoadData: [],
+      unLoadData: [], // 错误列表数据
       loading: false,
       disabled: false
     }
   },
   methods: {
+    // 获取解析后的数据
     getData () {
       const _this = this
       this.loading = true
@@ -129,11 +130,13 @@ export default {
         this.loading = false
         this.disabled = false
         if (res.status == 200) {
+          // 正确列表
           if (res.data.successList && res.data.successList.length > 0) {
             res.data.successList.map((item, index) => {
               item.no = index + 1
             })
           }
+          // 错误列表
           if (res.data.failList && res.data.failList.length > 0) {
             res.data.failList.map((item, index) => {
               item.no = index + 1
@@ -159,7 +162,7 @@ export default {
         })
       }
     },
-    // 导出
+    // 导出错误项
     handleError () {
       const _this = this
       if (_this.unLoadData.length < 1) {

+ 4 - 14
src/views/numsGoodsShelves/shelfSet/importGuideModal.vue

@@ -15,7 +15,7 @@
             <span>1</span>下载导入模板
           </div>
           <p>请按照下载的Excel模板填写数据</p>
-          <a :href="filePath" style="padding: 5px 0 0 23px;display: block;">
+          <a :href="filePath" style="padding: 5px 0 0 23px;display: block;" id="importGuide-downloadTpl">
             <a-icon type="download" style="padding-right: 5px;" />下载导入模板
           </a>
         </div>
@@ -73,7 +73,6 @@
 import { hdPrint } from '@/libs/JGPrint.js'
 import ChooseImportModal from './chooseImportModal.vue'
 import { Upload } from '@/components'
-import { shelfProductDownload } from '@/api/shelf'
 export default {
   name: 'ImportGuideModal',
   components: { ChooseImportModal, Upload },
@@ -82,7 +81,7 @@ export default {
       type: Boolean,
       default: false
     },
-    params: {
+    params: { // 参数
       type: Object,
       default: null
     }
@@ -93,9 +92,9 @@ export default {
       openImportModal: false, //  导入
       attachAction: process.env.VUE_APP_API_BASE_URL + '/upload',
       filePath: location.protocol + '//' + location.host + '/templ/绑定产品导入模板.xlsx',
-      paramsData: null,
+      paramsData: null, // 参数
       uploadParams: {
-        savePathType: 'local'
+        savePathType: 'local' // 保存到本地
       }
     }
   },
@@ -128,15 +127,6 @@ export default {
     handleClose () {
       this.openImportModal = false
       this.isShow = false
-    },
-    //  导出
-    handleExport () {
-      const _this = this
-      _this.spinning = true
-      // 导出
-      hdPrint('', 'export', shelfProductDownload, _this.params, '导入绑定产品模板', function () {
-        _this.spinning = false
-      })
     }
   },
   watch: {

+ 6 - 7
src/views/numsGoodsShelves/shelfSet/importHuoweiModal.vue

@@ -14,7 +14,7 @@
           <div class="explain-tit">
             <span>1</span>下载导入模板
             <p>请按照下载的Excel模板填写数据</p>
-            <a :href="filePath" style="padding: 5px 0 0 23px;display: block;">
+            <a :href="filePath" style="padding: 5px 0 0 23px;display: block;" id="importHuoweiModal-downloadTpl">
               <a-icon type="download" style="padding-right: 5px;" />下载导入模板
             </a>
           </div>
@@ -83,7 +83,7 @@ export default {
       type: Boolean,
       default: false
     },
-    shelfSn: {
+    shelfSn: { // 货架sn
       type: [String, Number],
       default: ''
     }
@@ -92,9 +92,9 @@ export default {
     return {
       isShow: this.openModal, //  是否打开弹框
       openImportModal: false, //  导入
-      filePath: location.protocol + '//' + location.host + '/templ/货位导入模板.xlsx',
-      attachAction: process.env.VUE_APP_API_BASE_URL + '/upload',
-      paramsData: null,
+      filePath: location.protocol + '//' + location.host + '/templ/货位导入模板.xlsx', // 模板地址
+      attachAction: process.env.VUE_APP_API_BASE_URL + '/upload', // 统一上传接口
+      paramsData: null, // 参数
       uploadParams: {
         savePathType: 'local'
       }
@@ -109,14 +109,13 @@ export default {
         this.$message.warning('添加文件后再进行下一步操作!')
       }
     },
-    // 上传文件  change
+    // 上传文件成功
     changeImport (file) {
       if (file) {
         this.paramsData = {
           shelfSn: this.shelfSn || '',
           path: file
         }
-        console.log(this.paramsData, 'this.paramsData')
       }
     },
     // 导入

+ 52 - 36
src/views/numsGoodsShelves/shelfSet/list.vue

@@ -7,12 +7,12 @@
           <a-row :gutter="15">
             <a-col :md="6" :sm="24">
               <a-form-item label="货架名称">
-                <shelfSList v-model="queryParam.shelfSn"></shelfSList>
+                <shelfSList v-model="queryParam.shelfSn" id="shelfSetList-shelfName"></shelfSList>
               </a-form-item>
             </a-col>
             <a-col :md="6" :sm="24">
               <a-form-item label="关联客户">
-                <custList ref="custList" :dealerFlag="0" @change="custChange" :isEnabled="true"></custList>
+                <custList ref="custList" id="shelfSetList-custList" :dealerFlag="0" @change="custChange" :isEnabled="true"></custList>
               </a-form-item>
             </a-col>
             <a-col :md="6" :sm="24">
@@ -51,9 +51,9 @@
         bordered>
         <!-- 货架名称 -->
         <template slot="shelfName" slot-scope="text, record">
-           {{record.shelfName}}
-           <a-badge count="已注销" :number-style="{ zoom:'80%',marginLeft:'5px', color: '#fff',background:'#999' }" v-if="record.state=='WRITE_OFF'"></a-badge>
-           <a-badge count="已暂停" :number-style="{ zoom:'80%',marginLeft:'5px', color: '#fff',background:'#999' }" v-if="record.state=='SUSPEND'"></a-badge>
+          {{ record.shelfName }}
+          <a-badge count="已注销" :number-style="{ zoom:'80%',marginLeft:'5px', color: '#fff',background:'#999' }" v-if="record.state=='WRITE_OFF'"></a-badge>
+          <a-badge count="已暂停" :number-style="{ zoom:'80%',marginLeft:'5px', color: '#fff',background:'#999' }" v-if="record.state=='SUSPEND'"></a-badge>
         </template>
         <!-- 货位数量 -->
         <template slot="shelfPlaceNum" slot-scope="text, record">
@@ -72,6 +72,7 @@
             v-if="record.finishFlag!=undefined"
             @change="changeStatus(record)"
             :checked="record.finishFlag == 1"
+            id="shelfSetList-finishFlag"
           />
           <span v-else :style="{ color: record.finishFlag == 1 ? '#00aa00' : '#999' }">
             {{ record.finishFlag == 1 ? '是' : (record.finishFlag!=undefined?'否':'--') }}
@@ -86,6 +87,7 @@
             v-if="record.state!=undefined"
             @change="enableShelf(record)"
             :checked="record.state == 'ENABLE'"
+            id="shelfSetList-state"
           />
           <span v-else :style="{ color: record.state == 'ENABLE' ? '#00aa00' : '#999' }">
             {{ record.state == 'ENABLE' ? '启用' : (record.state!=undefined&&record.state!='WRITE_OFF'&&record.state!='SUSPEND'?'停用':'--') }}
@@ -94,14 +96,20 @@
         <!-- 操作 -->
         <template slot="action" slot-scope="text, record">
           <div>
-            <a-button size="small" type="link" class="button-primary" @click="handleSet(record)">{{record.state!='WRITE_OFF'&&record.state!='SUSPEND'?'货架设置':'查看'}}</a-button>
-            <a-button size="small" type="link" class="button-primary" v-if="record.state!='WRITE_OFF'&&record.state!='SUSPEND'" @click="handleCancel(record)">注销</a-button>
+            <a-button id="shelfSetList-setView" size="small" type="link" class="button-primary" @click="handleSet(record)">{{ record.state!='WRITE_OFF'&&record.state!='SUSPEND'?'货架设置':'查看' }}</a-button>
+            <a-button
+              id="shelfSetList-cancel"
+              size="small"
+              type="link"
+              class="button-primary"
+              v-if="record.state!='WRITE_OFF'&&record.state!='SUSPEND'"
+              @click="handleCancel(record)">注销</a-button>
           </div>
         </template>
       </s-table>
     </a-spin>
     <!-- 基础设置 -->
-    <basic-info-modal :type="0" :openModal="openModal" :nowData="nowData" @ok="handleOk" @close="openModal=false" />
+    <basic-info-modal :type="0" :openModal="openModal" :nowData="nowData" @ok="handleOkToSet" @close="openModal=false" />
     <a-modal
       centered
       class="common-modal"
@@ -117,8 +125,8 @@
         <div style="font-size:12px;color:#999;margin-top:10px;">如需要迁移该数字货架的数据,可去货架设置中导出货架信息</div>
       </div>
       <div class="btn-box" style="display: flex;align-items: center;justify-content: center;margin-top:25px;">
-        <a-button type="primary" @click="handleCommonOk">确定</a-button>
-        <a-button type="default" class="button-warning" @click="showTip=false">取消</a-button>
+        <a-button id="shelfSetList-handle-ok" type="primary" @click="handleCommonOk">确定</a-button>
+        <a-button id="shelfSetList-handle-cancel" type="default" class="button-warning" @click="showTip=false">取消</a-button>
       </div>
     </a-modal>
   </a-card>
@@ -127,28 +135,29 @@
 <script>
 import { commonMixin } from '@/utils/mixin'
 import { STable, VSelect } from '@/components'
-import custList from '@/views/common/custList.vue'
-import shelfSList from '@/views/common/shelfList'
-import basicInfoModal from './basicInfoModal.vue'
-import commonModal from '@/views/common/commonModal.vue'
-import { shelfList, modifFinishFlag, shelfModifState } from '@/api/shelf'
+import custList from '@/views/common/custList.vue' // 客户列表组件
+import shelfSList from '@/views/common/shelfList' // 货架列表组件
+import basicInfoModal from './basicInfoModal.vue' // 基本信息弹框
+import commonModal from '@/views/common/commonModal.vue' // 公共弹框
+import { shelfList, modifFinishFlag, shelfModifState } from '@/api/shelf' // 接口api
 export default {
   components: { STable, VSelect, custList, shelfSList, basicInfoModal, commonModal },
   mixins: [commonMixin],
   data () {
     return {
-      spinning: false,
-      tableHeight: 0,
+      spinning: false, // loading
+      tableHeight: 0, // 表格高度
       disabled: false, //  查询、重置按钮是否可操作
-      showTip: false,
+      showTip: false, // 注销弹框
       queryParam: {
-        shelfSn: undefined,
-        customerSn: undefined,
-        finishFlag: undefined,
-        customerEntity: {
+        shelfSn: undefined, // 货架sn
+        customerSn: undefined, // 关联客户sn
+        finishFlag: undefined, // 是否完成设置
+        customerEntity: { // 关联客户名称
           customerName: undefined
         }
       },
+      // 列定义
       columns: [
         { title: '序号', dataIndex: 'no', width: '5%', align: 'center' },
         { title: '货架名称', scopedSlots: { customRender: 'shelfName' }, width: '25%', align: 'left', ellipsis: true },
@@ -176,16 +185,18 @@ export default {
           return data
         })
       },
-      openModal: false,
-      nowData: null
+      openModal: false, // 新增编辑弹框
+      nowData: null // 当前操作行数据
     }
   },
   methods: {
     // 设置/修改
     handleSet (row) {
+      // 如果有关联客户跳转到设置页面
       if (row.customerSn) {
-        this.$router.push({ path: `/numsGoodsShelves/shelfSet/set/${row.shelfSn}` })
+        this.handleOkToSet(row)
       } else {
+        // 否则打开编辑弹框
         this.nowData = {
           shelfSn: row.shelfSn,
           shelfName: row.shelfName
@@ -193,10 +204,11 @@ export default {
         this.openModal = true
       }
     },
-    handleOk (data) {
+    // 跳转到货架设置页面
+    handleOkToSet (data) {
       this.$router.push({ path: `/numsGoodsShelves/shelfSet/set/${data.shelfSn}` })
     },
-    // 客户 change
+    // 选择关联客户
     custChange (obj, row) {
       if (row) {
         this.queryParam.customerSn = row && row.customerSn || undefined
@@ -206,7 +218,7 @@ export default {
         this.queryParam.customerSn = undefined
       }
     },
-    // 是否设置完成
+    // 是否设置完成更改
     changeStatus (record) {
       const params = {
         shelfSn: record.shelfSn,
@@ -224,7 +236,7 @@ export default {
       })
     },
     // 启用禁用
-    enableShelf(record){
+    enableShelf (record) {
       const params = {
         shelfSn: record.shelfSn,
         state: record.state == 'ENABLE' ? 'DISABLED' : 'ENABLE'
@@ -232,27 +244,29 @@ export default {
       const _this = this
       _this.$confirm({
         title: '提示',
-        content: <div style="text-align:center;">是否{(record.state == 'ENABLE'?'停用':'启用')+record.shelfName}</div>,
+        content: <div style="text-align:center;">是否{(record.state == 'ENABLE' ? '停用' : '启用') + record.shelfName}</div>,
         centered: true,
         closable: true,
         class: 'confirm-center',
         onOk () {
-           _this.updateState(params)
+          _this.updateState(params)
         }
       })
     },
-    // 注销
-    handleCancel(record){
+    // 打开注销弹框
+    handleCancel (record) {
       this.nowData = {
         shelfSn: record.shelfSn,
         state: 'WRITE_OFF'
       }
       this.showTip = true
     },
-    handleCommonOk(){
+    // 确定注销
+    handleCommonOk () {
       this.updateState(this.nowData)
     },
-    updateState(params){
+    // 更改货架状态
+    updateState (params) {
       this.spinning = true
       shelfModifState(params).then(res => {
         if (res.status == 200) {
@@ -265,7 +279,7 @@ export default {
         this.showTip = false
       })
     },
-    // 重置
+    // 重置列表查询
     resetSearchForm () {
       this.queryParam.shelfSn = undefined
       this.queryParam.customerSn = undefined
@@ -274,10 +288,12 @@ export default {
       this.queryParam.finishFlag = undefined
       this.$refs.table.refresh(true)
     },
+    // 计算表格高度
     setTableH () {
       const tableSearchH = this.$refs.tableSearch.offsetHeight
       this.tableHeight = window.innerHeight - tableSearchH - 235
     },
+    // 初始化页面
     pageInit () {
       const _this = this
       this.$nextTick(() => { // 页面渲染完成后的回调

+ 120 - 56
src/views/numsGoodsShelves/shelfSet/set.vue

@@ -13,20 +13,26 @@
           <a-collapse-panel key="1">
             <template slot="header">
               <span>基础信息</span>
-              <a-button icon="edit" v-if="basicInfoData&&basicInfoData.state!='WRITE_OFF'&&basicInfoData.state!='SUSPEND'" size="small" type="link" style="margin-left: 20px;color: #39f;" @click.stop="openInfoModal = true">编辑</a-button>
+              <a-button
+                icon="edit"
+                v-if="basicInfoData&&basicInfoData.state!='WRITE_OFF'&&basicInfoData.state!='SUSPEND'"
+                size="small"
+                type="link"
+                style="margin-left: 20px;color: #39f;"
+                @click.stop="openInfoModal = true">编辑</a-button>
             </template>
             <a-descriptions :column="2">
               <a-descriptions-item label="货架名称">
-              {{ basicInfoData&&basicInfoData.shelfName || '--' }}
-              <a-badge count="已注销" :number-style="{ zoom:'80%',marginLeft:'5px', color: '#fff',background:'#999' }" v-if="basicInfoData&&basicInfoData.state=='WRITE_OFF'"></a-badge>
-              <a-badge count="已停用" :number-style="{ zoom:'80%',marginLeft:'5px', color: '#fff',background:'#999' }" v-if="basicInfoData&&basicInfoData.state=='DISABLED'"></a-badge>
-              <a-badge count="已暂停" :number-style="{ zoom:'80%',marginLeft:'5px', color: '#fff',background:'#999' }" v-if="basicInfoData&&basicInfoData.state=='SUSPEND'"></a-badge>
+                {{ basicInfoData&&basicInfoData.shelfName || '--' }}
+                <a-badge count="已注销" :number-style="{ zoom:'80%',marginLeft:'5px', color: '#fff',background:'#999' }" v-if="basicInfoData&&basicInfoData.state=='WRITE_OFF'"></a-badge>
+                <a-badge count="已停用" :number-style="{ zoom:'80%',marginLeft:'5px', color: '#fff',background:'#999' }" v-if="basicInfoData&&basicInfoData.state=='DISABLED'"></a-badge>
+                <a-badge count="已暂停" :number-style="{ zoom:'80%',marginLeft:'5px', color: '#fff',background:'#999' }" v-if="basicInfoData&&basicInfoData.state=='SUSPEND'"></a-badge>
               </a-descriptions-item>
               <a-descriptions-item>
                 <template slot="label">
-                    货架产品 
+                  货架产品
                 </template>
-                <span>{{showPriceStr.length ? showPriceStr.join("/") : '--'}}</span>
+                <span>{{ showPriceStr.length ? showPriceStr.join("/") : '--' }}</span>
               </a-descriptions-item>
               <a-descriptions-item>
                 <template slot="label">
@@ -41,9 +47,9 @@
               </a-descriptions-item>
               <a-descriptions-item>
                 <template slot="label">
-                    非货架产品
+                  非货架产品
                 </template>
-                <span>{{showNoShelfPriceStr.length ? showNoShelfPriceStr.join("/") : '--'}}</span>
+                <span>{{ showNoShelfPriceStr.length ? showNoShelfPriceStr.join("/") : '--' }}</span>
               </a-descriptions-item>
             </a-descriptions>
           </a-collapse-panel>
@@ -74,7 +80,7 @@
                     @click="handleExport"
                     :disabled="disabled"
                     :loading="exportLoading"
-                    >导出</a-button>
+                  >导出</a-button>
                 </span>
               </a-col>
             </a-row>
@@ -83,14 +89,21 @@
         <!-- 操作按钮 -->
         <div class="table-operator" v-if="basicInfoData&&basicInfoData.state!='WRITE_OFF'&&basicInfoData.state!='SUSPEND'">
           <a-button id="shelfSet-addHW" type="primary" class="button-error" @click="addHW(1)">新增货位</a-button>
-          <a-button id="shelfSet-impoort" type="primary" class="button-info" @click="addHW(0)">批量导入货位</a-button>
-          <a-button id="shelfSet-import" type="primary" class="button-error" @click="openGuideModal=true">导入绑定产品</a-button>
+          <a-button id="shelfSet-imports" type="primary" class="button-info" @click="addHW(0)">批量导入货位</a-button>
+          <a-button id="shelfSet-importProduct" type="primary" class="button-error" @click="openGuideModal=true">导入绑定产品</a-button>
           <a-tooltip placement="top">
             <template slot="title">
               <span>如果货位还没有绑定产品,可使用此功能通过Excel批量导入</span>
             </template>
             <a-icon type="question-circle" style="color: rgba(0,0,0,.45);font-size: 16px;margin-left: 5px;vertical-align: middle;cursor: pointer;" />
           </a-tooltip>
+          <a-button
+            v-if="showTplBtn"
+            id="shelfSet-import-template"
+            style="margin-left:10px;"
+            type="primary"
+            class="button-primary"
+            @click="showTplModal=true">导入模板</a-button>
         </div>
         <!-- 列表 -->
         <s-table
@@ -116,6 +129,7 @@
           <!-- 操作 -->
           <template slot="action" slot-scope="text, record">
             <a-button
+              id="shelfSet-link"
               size="small"
               type="link"
               :class="record.enableFlag==1?'button-error':'button-primary'"
@@ -123,6 +137,7 @@
               @click="handleEnable(record)"
             >{{ record.enableFlag==1?'禁用':'启用' }}</a-button>
             <a-button
+              id="shelfSet-bindProduct"
               size="small"
               type="link"
               class="button-primary"
@@ -130,6 +145,7 @@
               @click="handleProduct(record, 'bind')"
             >绑定产品</a-button>
             <a-button
+              id="shelfSet-editProduct"
               size="small"
               type="link"
               :class="record.enableFlag==1?'button-primary':''"
@@ -138,6 +154,7 @@
               @click="handleReplace(record)"
             >更换产品</a-button>
             <a-button
+              id="shelfSet-editHw"
               size="small"
               type="link"
               :class="record.enableFlag==1?'button-primary':''"
@@ -145,6 +162,7 @@
               @click="editHW(record)"
             >编辑</a-button>
             <a-button
+              id="shelfSet-del"
               size="small"
               type="link"
               class="button-error"
@@ -171,8 +189,12 @@
       @close="openTipsModal=false" />
     <!-- 导入产品 -->
     <importGuideModal :openModal="openGuideModal" :params="{shelfSn: $route.params.sn}" @close="openGuideModal=false" @ok="handleGuideOk" />
-    <!-- 导入货位模板 -->
+    <!-- 导入货位弹框 -->
     <importHuoweiModal :openModal="openImportModal" @close="openImportModal=false" @ok="$refs.table.refresh(true)" :shelfSn="$route.params.sn"></importHuoweiModal>
+    <!-- 导入货架模板弹框 -->
+    <commonModal modalTit="导入货架模板" :openModal="showTplModal" @close="closeTplModal" @ok="saveTpl">
+      <shelfTemplate v-if="showTplModal" style="width:100%" v-model="tplSn"></shelfTemplate>
+    </commonModal>
   </div>
 </template>
 
@@ -180,29 +202,33 @@
 import { commonMixin } from '@/utils/mixin'
 import { downloadExcel } from '@/libs/JGPrint.js'
 import { STable, VSelect } from '@/components'
-import commonModal from '@/views/common/commonModal.vue'
-import addHwModal from './addHwModal.vue'
-import bindProductModal from './bindProductModal.vue'
-import ImportGuideModal from './importGuideModal.vue'
-import basicInfoModal from './basicInfoModal.vue'
-import importHuoweiModal from './importHuoweiModal.vue'
-import { shelfDetail, shelfProductList, shelfProductBatchInsert, delShelfPlaceSn, shelfProductEnable, getShelfPriceShow, shelfProductExport } from '@/api/shelf'
+import commonModal from '@/views/common/commonModal.vue' // 公共提示弹框
+import addHwModal from './addHwModal.vue' // 新增货位弹框
+import bindProductModal from './bindProductModal.vue' // 绑定产品弹框
+import ImportGuideModal from './importGuideModal.vue' // 导入产品弹框
+import basicInfoModal from './basicInfoModal.vue' // 基本信息弹框
+import importHuoweiModal from './importHuoweiModal.vue' // 导入货位模板
+import shelfTemplate from '@/views/common/shelfTemplate' // 货架模板下拉组件
+import { shelfDetail, shelfProductList, shelfProductBatchInsert, delShelfPlaceSn, shelfProductEnable, getShelfPriceShow, shelfProductExport, importShelfTemplate } from '@/api/shelf'
 export default {
   name: 'ShelfMonitoringWarehousing',
-  components: { STable, VSelect, commonModal, bindProductModal, addHwModal, ImportGuideModal, basicInfoModal, importHuoweiModal },
+  components: { STable, VSelect, commonModal, bindProductModal, addHwModal, ImportGuideModal, basicInfoModal, importHuoweiModal, shelfTemplate },
   mixins: [commonMixin],
   data () {
     return {
-      spinning: false,
+      spinning: false, // 页面loading
       disabled: false, //  查询、重置按钮是否可操作
-      tableHeight: 400,
-      exportLoading: false,
+      tableHeight: 400, // 表格高度
+      exportLoading: false, // 导出loading
+      showTplModal: false, // 是否显示导入模板弹框
+      tplSn: undefined, // 货架模板sn
       queryParam: {
         shelfProductApiEntity: {
-          productCode: '',
-          productName: ''
+          productCode: '', // 产品编码
+          productName: '' // 产品名称
         }
       },
+      orginData: [], // 原始数据
       // 加载数据方法 必须为 Promise 对象
       loadData: parameter => {
         this.disabled = true
@@ -216,26 +242,32 @@ export default {
               data[i].enableFlag = data[i].shelfProductApiEntity && data[i].shelfProductApiEntity.enableFlag
             }
             this.disabled = false
+            this.orginData = data
           }
           this.spinning = false
           return data
         })
       },
-      basicInfoData: null,
-      openTipsModal: false,
-      openModal: false,
-      nowData: null,
-      openGuideModal: false,
-      modalType: null,
-      openInfoModal: false,
-      openHwModal: false,
-      openImportModal: false,
-      showPriceStr: [],
-      showNoShelfPriceStr: []
+      basicInfoData: null, // 基础设置弹框
+      openTipsModal: false, // 更换产品提示弹框
+      openModal: false, // 修改信息/绑定产品/更换产品弹框
+      nowData: null, // 当前操作货位产品数据
+      openGuideModal: false, // 导入产品
+      modalType: null, // 新增或编辑
+      openInfoModal: false, // 基础设置弹框
+      openHwModal: false, // 新增编辑货位弹框
+      openImportModal: false, // 导入货位模板弹框
+      showPriceStr: [], // 货架产品价格权限
+      showNoShelfPriceStr: [] // 非货架产品价格权限
     }
   },
-  computed:{
-    columns(){
+  computed: {
+    // 是否显示模板导入按钮
+    showTplBtn () {
+      return this.orginData.length == 0
+    },
+    // 列定义
+    columns () {
       const _this = this
       const ret = [
         { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
@@ -245,9 +277,10 @@ export default {
         { title: '车主价', dataIndex: 'shelfProductApiEntity.price', width: '9%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text, 2) : '--') } },
         { slots: { title: 'customTitle' }, dataIndex: 'shelfProductApiEntity.cost', width: '9%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text, 2) : '--') } },
         { title: '最大库容', dataIndex: 'shelfProductApiEntity.maxQty', width: '9%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
-        { title: '当前库存', dataIndex: 'shelfProductApiEntity.qty', width: '9%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '当前库存', dataIndex: 'shelfProductApiEntity.qty', width: '9%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } }
       ]
-      if(this.basicInfoData&&this.basicInfoData.state!='WRITE_OFF'&&this.basicInfoData.state!='SUSPEND'){
+      // 注销或停用的货架不能操作
+      if (this.basicInfoData && this.basicInfoData.state != 'WRITE_OFF' && this.basicInfoData.state != 'SUSPEND') {
         ret.push({ title: '操作', scopedSlots: { customRender: 'action' }, width: '15%', align: 'center' })
       }
       return ret
@@ -260,30 +293,52 @@ export default {
       this.showNoShelfPriceStr = []
       getShelfPriceShow({ shelfSn: this.$route.params.sn }).then(res => {
         if (res.status == 200) {
-          const ret = res.data&&res.data
+          const ret = res.data && res.data
           this.basicInfoData.showPrice = ret
           ret.map(item => {
-            if(item.paramCode == 'shelf_price_show'&&item.paramValue == 1){
-              this.showPriceStr.push("车主价")
+            if (item.paramCode == 'shelf_price_show' && item.paramValue == 1) {
+              this.showPriceStr.push('车主价')
             }
-            if(item.paramCode == 'shelf_cost_show'&&item.paramValue == 1){
-              this.showPriceStr.push("结算价")
+            if (item.paramCode == 'shelf_cost_show' && item.paramValue == 1) {
+              this.showPriceStr.push('结算价')
             }
-            if(item.paramCode == 'non_shelf_price_show'&&item.paramValue == 1){
-              this.showNoShelfPriceStr.push("车主价")
+            if (item.paramCode == 'non_shelf_price_show' && item.paramValue == 1) {
+              this.showNoShelfPriceStr.push('车主价')
             }
-            if(item.paramCode == 'non_shelf_cost_show'&&item.paramValue == 1){
-              this.showNoShelfPriceStr.push("结算价")
+            if (item.paramCode == 'non_shelf_cost_show' && item.paramValue == 1) {
+              this.showNoShelfPriceStr.push('结算价')
             }
           })
         }
       })
     },
+    closeTplModal () {
+      this.tplSn = undefined
+      this.showTplModal = false
+    },
+    // 导入模板成功
+    saveTpl () {
+      if (!this.tplSn) {
+        this.$message.success('请选择货架模板')
+        return
+      }
+      if (!this.spinning) {
+        this.spinning = true
+        importShelfTemplate({ shelfSn: this.$route.params.sn, templateSn: this.tplSn }).then(res => {
+          if (res.status == 200) {
+            this.$message.success(res.message)
+            this.showTplModal = false
+            this.resetSearchForm()
+          }
+          this.spinning = false
+        })
+      }
+    },
     // 导出产品
     handleExport () {
       this.exportLoading = true
-      shelfProductExport({shelfSn: this.$route.params.sn}).then(res => {
-        downloadExcel(res, (this.basicInfoData?this.basicInfoData.shelfName:'')+"的产品")
+      shelfProductExport({ shelfSn: this.$route.params.sn }).then(res => {
+        downloadExcel(res, (this.basicInfoData ? this.basicInfoData.shelfName : '') + '的产品')
         this.exportLoading = false
       })
     },
@@ -299,7 +354,7 @@ export default {
         this.openHwModal = true
       }
     },
-    // 禁用启用
+    // 禁用启用弹框提示
     handleEnable (row) {
       const _this = this
       if (row.enableFlag == 1) {
@@ -315,10 +370,15 @@ export default {
         _this.enableFun(row)
       }
     },
+    // 禁用启用货架
     enableFun (row) {
       const _this = this
       _this.spinning = true
-      shelfProductEnable({ shelfSn: this.$route.params.sn, shelfProductSn: row.shelfProductApiEntity.shelfProductSn, enableFlag: row.enableFlag == 1 ? 0 : 1 }).then(res => {
+      shelfProductEnable({
+        shelfSn: this.$route.params.sn,
+        shelfProductSn: row.shelfProductApiEntity.shelfProductSn,
+        enableFlag: row.enableFlag == 1 ? 0 : 1
+      }).then(res => {
         if (res.status == 200) {
           _this.$message.success(res.message)
           _this.$refs.table.refresh()
@@ -343,6 +403,7 @@ export default {
       shelfDetail({ sn: this.$route.params.sn }).then(res => {
         if (res.status == 200) {
           this.basicInfoData = res.data
+          // 获取价格权限
           this.getShelfPriceShow()
         } else {
           this.basicInfoData = null
@@ -386,6 +447,7 @@ export default {
       this.modalType = type
       this.openModal = true
     },
+    // 编辑弹框取消
     handleCancel () {
       this.modalType = null
       this.nowData = null
@@ -400,20 +462,22 @@ export default {
         }
       })
     },
+    // 编辑基本信息成功
     handleInfoOk () {
       this.getDetail()
     },
-    //  重置
+    // 重置
     resetSearchForm () {
       this.queryParam.shelfProductApiEntity.productCode = ''
       this.queryParam.shelfProductApiEntity.productName = ''
       this.$refs.table.refresh(true)
     },
+    // 计算表格高度
     setTableH () {
       const tableSearchH = this.$refs.tableSearch.offsetHeight
       this.tableHeight = window.innerHeight - tableSearchH - 350
     },
-    //  返回列表
+    // 返回列表
     handleBack () {
       this.$router.push({ path: '/numsGoodsShelves/shelfSet/list' })
     }

+ 10 - 3
src/views/outboundOrderManagement/outboundOrder/list.vue

@@ -10,12 +10,17 @@
                 <rangeDate ref="rangeDate" :value="time" @change="dateChange" />
               </a-form-item>
             </a-col>
+            <a-col :xl="6" :lg="6" :md="12" :sm="24">
+              <a-form-item label="关联单号">
+                <a-input v-model.trim="queryParam.outBizNo" placeholder="请输入关联单号" allowClear />
+              </a-form-item>
+            </a-col>
             <a-col :xl="6" :lg="6" :md="12" :sm="24">
               <a-form-item label="客户名称">
-                <a-input id="outboundOrderList-demanderName" v-model.trim="queryParam.demanderNameCurrent" placeholder="请输入客户名称" allowClear />
+                <a-input v-model.trim="queryParam.demanderNameCurrent" placeholder="请输入客户名称" allowClear />
               </a-form-item>
             </a-col>
-            <a-col :xl="4" :lg="6" :md="6" :sm="8">
+            <a-col :xl="6" :lg="6" :md="6" :sm="8">
               <a-form-item label="出库类型">
                 <v-select
                   v-model="queryParam.outBizType"
@@ -27,7 +32,7 @@
                   allowClear></v-select>
               </a-form-item>
             </a-col>
-            <a-col :xl="4" :lg="6" :md="6" :sm="8">
+            <a-col :xl="6" :lg="6" :md="6" :sm="8">
               <a-form-item label="单据状态">
                 <v-select
                   v-model="queryParam.state"
@@ -165,6 +170,7 @@ export default {
       queryParam: { //  查询条件
         beginDate: getDate.getCurrMonthDays().starttime,
         endDate: getDate.getCurrMonthDays().endtime,
+        outBizNo: undefined, //  出库单号
         demanderNameCurrent: undefined, //  单位名称
         outBizType: undefined, //  出库类型
         state: undefined //  状态
@@ -266,6 +272,7 @@ export default {
       this.$refs.rangeDate.resetDate(flag ? '' : this.time)
       this.queryParam.beginDate = flag ? '' : getDate.getCurrMonthDays().starttime
       this.queryParam.endDate = flag ? '' : getDate.getCurrMonthDays().endtime
+      this.queryParam.outBizNo = undefined
       this.queryParam.demanderNameCurrent = undefined
       this.queryParam.outBizType = undefined
       this.queryParam.state = undefined

+ 5 - 1
src/views/productManagement/productInfo/edit.vue

@@ -392,6 +392,10 @@ export default {
           }
           delete form.productType
           _this.spinning = true
+          // 后台不要为null的值
+          form.carOwnersPrice = !form.carOwnersPrice ? '' : form.carOwnersPrice
+          form.specialPrice = !form.specialPrice ? '' : form.specialPrice
+          form.terminalPrice = !form.terminalPrice ? '' : form.terminalPrice
           dealerProductSave(form).then(res => {
             if (res.status == 200) {
               _this.$message.success(res.message)
@@ -500,7 +504,7 @@ export default {
     height: 100%;
     >.ant-spin-nested-loading{
       height: 100%;
-	  overflow-y: auto;
+      overflow-y: auto;
       .ant-spin-container{
         height: 90%;
       }

+ 1 - 0
src/views/reportData/customerReport/list.vue

@@ -91,6 +91,7 @@ import ProductType from '@/views/common/productType.js'
 import { reportBigCustomerList, reportBigCustomerCount } from '@/api/reportData'
 export default {
   mixins: [commonMixin],
+  name: 'CustomerReport',
   components: { STable, VSelect, rangeDate, custType, custList, AreaList, ProductType },
   data () {
     return {

+ 20 - 15
src/views/reportData/salesDetailReport/list.vue

@@ -224,6 +224,9 @@ export default {
             const no = (data.pageNo - 1) * data.pageSize
             for (var i = 0; i < data.list.length; i++) {
               data.list[i].no = no + i + 1
+              if (data.list[i].productEntity) {
+                data.list[i].productTypeName = data.list[i].productEntity.productTypeName1 + '>' + data.list[i].productEntity.productTypeName2 + '>' + data.list[i].productEntity.productTypeName3
+              }
             }
             this.disabled = false
           }
@@ -245,25 +248,27 @@ export default {
     columns () {
       const _this = this
       const arr = [
-        { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
-        { title: '销售单号', dataIndex: 'salesBillNo', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
-        { title: '客户名称', dataIndex: 'salesTargetName', width: '15%', align: 'left', customRender: function (text) { return text || '--' }, ellipsis: true },
-        { title: '收款方式', dataIndex: 'settleStyleSnDictValue', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
-        { title: '产品编码', dataIndex: 'productEntity.code', width: '13%', align: 'center', customRender: function (text) { return text || '--' } },
-        { title: '产品名称', dataIndex: 'productEntity.name', width: '17%', align: 'left', customRender: function (text) { return text || '--' }, ellipsis: true },
-        { title: '原厂编码', dataIndex: 'productEntity.origCode', width: '13%', align: 'center', customRender: function (text) { return text || '--' } },
-        { title: '单位', dataIndex: 'productEntity.unit', width: '4%', align: 'center', customRender: function (text) { return text || '--' } },
-        { title: '数量', dataIndex: 'productQty', width: '5%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '序号', dataIndex: 'no', width: '3%', align: 'center' },
+        { title: '销售单号', dataIndex: 'salesBillNo', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '客户名称', dataIndex: 'salesTargetName', width: '8%', align: 'left', customRender: function (text) { return text || '--' } },
+        { title: '收款方式', dataIndex: 'settleStyleSnDictValue', width: '5%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品编码', dataIndex: 'productEntity.code', width: '5%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '品牌', dataIndex: 'productEntity.productBrandName', width: '5%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '分类', dataIndex: 'productTypeName', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品名称', dataIndex: 'productEntity.name', width: '12%', align: 'left', customRender: function (text) { return text || '--' } },
+        { title: '原厂编码', dataIndex: 'productEntity.origCode', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '单位', dataIndex: 'productEntity.unit', width: '3%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '数量', dataIndex: 'productQty', width: '3%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
         // { title: '成本', dataIndex: 'productCost', width: '5%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
-        { title: '总售价', dataIndex: 'totalAmount', width: '7%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
-        { title: '折扣金额', dataIndex: 'discountAmount', width: '8%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
-        { title: '折后总售价', dataIndex: 'discountedAmount', width: '9%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        { title: '总售价', dataIndex: 'totalAmount', width: '5%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        { title: '折扣金额', dataIndex: 'discountAmount', width: '5%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        { title: '折后总售价', dataIndex: 'discountedAmount', width: '5%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
         // { title: '毛利', dataIndex: 'productProfit', width: '5%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
-        { title: '审核时间', dataIndex: 'salesAuditDate', width: '11%', align: 'center', customRender: function (text) { return text || '--' } }
+        { title: '审核时间', dataIndex: 'salesAuditDate', width: '5%', align: 'center', customRender: function (text) { return text || '--' } }
       ]
       if (this.$hasPermissions('M_ShowAllCost')) {
-        arr.splice(8, 0, { title: '成本', dataIndex: 'totalCost', width: '7%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } })
-        arr.splice(12, 0, { title: '毛利', dataIndex: 'grossProfit', width: '7%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } })
+        arr.splice(10, 0, { title: '成本', dataIndex: 'totalCost', width: '5%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } })
+        arr.splice(14, 0, { title: '毛利', dataIndex: 'grossProfit', width: '5%', align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } })
       }
       return arr
     }

+ 410 - 0
src/views/reportData/salesRankingReport/list.vue

@@ -0,0 +1,410 @@
+<template>
+  <div class="jg-page-wrap customerReportList-wrap">
+    <a-card size="small" :bordered="false" class="table-page-search-wrapper">
+      <div ref="tableSearch">
+        <!-- 搜索条件 -->
+        <a-form-model
+          id="customerReportList-form"
+          ref="ruleForm"
+          class="form-model-con"
+          layout="inline"
+          :model="queryParam"
+          :rules="rules"
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          @keyup.enter.native="handleSearch" >
+          <a-row :gutter="15">
+            <a-col :md="6" :sm="24">
+              <a-form-model-item label="查询时间" prop="time">
+                <rangeDate ref="rangeDate" @change="dateChange" />
+              </a-form-model-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="产品品牌">
+                <ProductBrand id="salesDetailReportList-productBrandSn" placeholder="请选择产品品牌" v-model="queryParam.productBrandSn"></ProductBrand>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-model-item label="产品分类">
+                <ProductType id="chainSalesReportList-productType" placeholder="请选择产品分类" @change="changeProductType" v-model="productType"></ProductType>
+              </a-form-model-item>
+            </a-col>
+            <template v-if="advanced">
+              <a-col :md="6" :sm="24">
+                <a-form-model-item label="产品编码">
+                  <a-input id="salesDetailReportList-code" v-model.trim="queryParam.productCode" allowClear placeholder="请输入产品编码"/>
+                </a-form-model-item>
+              </a-col>
+              <a-col :md="6" :sm="24">
+                <a-form-model-item label="产品名称">
+                  <a-input id="salesDetailReportList-name" v-model.trim="queryParam.productName" allowClear placeholder="请输入产品名称"/>
+                </a-form-model-item>
+              </a-col>
+            </template>
+            <a-col :md="6" :sm="24" style="margin-bottom: 10px;">
+              <a-button type="primary" @click="handleSearch" :disabled="disabled" id="customerReportList-refresh">查询</a-button>
+              <a-button style="margin-left: 5px" @click="resetSearchForm" :disabled="disabled" id="customerReportList-reset">重置</a-button>
+              <a-button
+                type="primary"
+                style="margin-left: 5px"
+                @click="handleExport"
+                :disabled="disabled"
+                :loading="exportLoading"
+                v-if="$hasPermissions('B_salesRankingReportExport')"
+                class="button-warning"
+                id="salesDetailReportList-export-btn">导出</a-button>
+              <a @click="advanced=!advanced" style="margin-left: 8px">
+                {{ advanced ? '收起' : '展开' }}
+                <a-icon :type="advanced ? 'up' : 'down'"/>
+              </a>
+            </a-col>
+          </a-row>
+        </a-form-model>
+      </div>
+    </a-card>
+    <a-card size="small" :bordered="false">
+      <a-spin :spinning="spinning" tip="Loading...">
+        <!-- 合计 -->
+        <div class="table-operator">
+          <div class="alert-message">
+            销售数量:<strong>{{ (totalData && (totalData.salesTotalQty || totalData.salesTotalQty==0)) ? totalData.salesTotalQty : '--' }}</strong>;
+            销售金额:<strong>{{ (totalData && (totalData.salesTotalAmount || totalData.salesTotalAmount==0)) ? toThousands(totalData.salesTotalAmount) : '--' }}</strong>;
+            销售折后金额:<strong>{{ (totalData && (totalData.salesTotalDiscountedAmount || totalData.salesTotalDiscountedAmount==0)) ? toThousands(totalData.salesTotalDiscountedAmount) : '--' }}</strong>;
+            <div style="display: inline-block;" v-show="showCols&&showCols.length>0">
+              销售退货数量:<strong>{{ (totalData && (totalData.salesReturnTotalQty || totalData.salesReturnTotalQty==0)) ? totalData.salesReturnTotalQty : '--' }}</strong>;
+              销售退货金额:<strong>{{ (totalData && (totalData.salesReturnTotalAmount || totalData.salesReturnTotalAmount==0)) ?toThousands(totalData.salesReturnTotalAmount) : '--' }}</strong>;
+              销售退货折后金额:<strong>{{ (totalData && (totalData.salesReturnTotalDiscountedAmount || totalData.salesReturnTotalDiscountedAmount==0)) ? toThousands(totalData.salesReturnTotalDiscountedAmount) : '--' }}</strong>;
+              销售数量合计:<strong>{{ (totalData && (totalData.totalQty || totalData.totalQty==0)) ? totalData.totalQty : '--' }}</strong>;
+              销售金额合计:<strong>{{ (totalData && (totalData.totalAmount || totalData.totalAmount==0)) ? toThousands(totalData.totalAmount) : '--' }}</strong>;
+            </div>
+          </div>
+          <div>
+            <span>显示:</span>
+            <a-tree-select
+              size="small"
+              v-model="showCols"
+              style="min-width: 200px"
+              dropdownMatchSelectWidth
+              :maxTagCount="3"
+              :tree-data="colsArr"
+              tree-checkable
+              @change="handleShowFlag"
+              placeholder="请选择要显示的列(多选)"
+            />
+          </div>
+        </div>
+        <!-- 列表 -->
+        <s-table
+          class="sTable"
+          ref="table"
+          size="small"
+          :rowKey="(record) => record.no"
+          rowKeyName="no"
+          :columns="columns"
+          :data="loadData"
+          :style="{ height: tableHeight+84+'px' }"
+          :scroll="{ x: 1800,y: tableHeight}"
+          :defaultLoadData="false"
+          bordered>
+          <!-- 产品分类 -->
+          <template slot="productType" slot-scope="text, record">
+            <span v-if="record.productTypeName2 || record.productTypeName3">{{ record.productTypeName2 }} {{ record.productTypeName3 ? '>' : '' }} {{ record.productTypeName3 }}</span>
+            <span v-else>--</span>
+          </template>
+          <!-- 销售数量  标题 -->
+          <template slot="salesNumTit">
+            <a-tooltip placement="top">
+              <template slot="title">
+                <span>销售单创建后开始计算销售数量</span>
+              </template>
+              <div>
+                <span style="margin-right:5px;">销售数量</span>
+                <a-icon type="question-circle" />
+              </div>
+            </a-tooltip>
+          </template>
+          <!-- 销售退货数量  标题 -->
+          <template slot="salesReturnNum">
+            <a-tooltip placement="top">
+              <template slot="title">
+                <span>销售退货单完结后开始计算销售数量</span>
+              </template>
+              <div>
+                <span style="margin-right:5px;">销售退货数量</span>
+                <a-icon type="question-circle" />
+              </div>
+            </a-tooltip>
+          </template>
+          <template slot="action" slot-scope="text, record">
+            <a-button
+              v-if="record.sysFlag==1&&$hasPermissions('B_salesRankingAddCar')"
+              size="small"
+              type="link"
+              class="button-primary"
+              @click="addShopCar(record)"
+            >加入购物车</a-button>
+            <span v-else>--</span>
+          </template>
+        </s-table>
+      </a-spin>
+    </a-card>
+  </div>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+import { STable, VSelect } from '@/components'
+import rangeDate from '@/views/common/rangeDate.vue'
+import ProductBrand from '@/views/common/productBrand.js'
+import ProductType from '@/views/common/productType.js'
+import { downloadExcel } from '@/libs/JGPrint.js'
+import { purchaseCartSave } from '@/api/purchaseCart'
+import { salesBillRankList, salesBillRankCount, salesBillRankExport } from '@/api/reportData'
+export default {
+  mixins: [commonMixin],
+  name: 'SalesRankingReport',
+  components: { STable, VSelect, rangeDate, ProductType, ProductBrand },
+  data () {
+    return {
+      spinning: false,
+      labelCol: { span: 8 },
+      wrapperCol: { span: 16 },
+      advanced: true, // 高级搜索 展开/关闭
+      tableHeight: 0,
+      queryParam: { //  查询条件
+        time: [],
+        beginDate: '',
+        endDate: '',
+        productBrandSn: undefined,
+        productTypeSn1: undefined, //  产品一级分类
+        productTypeSn2: undefined, //  产品二级分类
+        productTypeSn3: undefined, //  产品三级分类
+        productCode: undefined,
+        productName: undefined
+      },
+      productType: [], // 产品分类
+      rules: {
+        'time': [{ required: true, message: '请选择添加时间', trigger: 'change' }]
+      },
+      disabled: false, //  查询、重置按钮是否可操作
+      exportLoading: false,
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        const params = Object.assign(parameter, this.queryParam)
+        params.returnFlag = this.showCols.includes('returnFlag') ? 1 : 0
+        delete params.time
+        this.spinning = true
+        if (params.beginDate && params.endDate) {
+          return salesBillRankList(params).then(res => {
+            let data
+            if (res.status == 200) {
+              data = res.data
+              // 总计
+              this.getCount(params)
+              const no = (data.pageNo - 1) * data.pageSize
+              for (var i = 0; i < data.list.length; i++) {
+                data.list[i].no = no + i + 1
+              }
+              this.disabled = false
+            }
+            this.spinning = false
+            return data
+          })
+        } else {
+          const _this = this
+          return new Promise(function (resolve, reject) {
+            const data = {
+              pageNo: 1,
+              pageSize: 10,
+              list: [],
+              count: 0
+            }
+            _this.disabled = false
+            _this.spinning = false
+            _this.$message.info('请选择查询时间')
+            resolve(data)
+          })
+        }
+      },
+      totalData: null, //  合计
+      colsArr: [// 显示列表所需要的列
+        {
+          title: '销售退货(明细)',
+          value: 'returnFlag',
+          key: 'returnFlag',
+          disabled: false
+        }],
+      showCols: []// 选中显示的列
+    }
+  },
+  computed: {
+    columns () {
+      const _this = this
+      const arr = [
+        { title: '序号', dataIndex: 'no', width: 60, align: 'center' },
+        { title: '品牌', dataIndex: 'productBrandName', width: 100, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '分类', scopedSlots: { customRender: 'productType' }, width: 150, align: 'center' },
+        { title: '产品编码', dataIndex: 'productCode', width: 100, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品名称', dataIndex: 'productName', width: 300, align: 'left', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '原厂编码', dataIndex: 'productOrigCode', width: 180, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '单位', dataIndex: 'productUnit', width: 80, align: 'center', customRender: function (text) { return text || '--' } },
+        { slots: { title: 'salesNumTit' }, dataIndex: 'salesTotalQty', width: 100, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '销售金额', dataIndex: 'salesTotalAmount', width: 100, align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        { title: '销售折扣金额', dataIndex: 'salesTotalDiscountAmount', width: 110, align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        { title: '销售折后金额', dataIndex: 'salesTotalDiscountedAmount', width: 110, align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        { title: '当前库存数量', dataIndex: 'stockTotalQty', width: 110, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '当前库存金额', dataIndex: 'stockTotalCost', width: 110, align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: 120, align: 'center', fixed: 'right' }
+      ]
+      if (this.$hasPermissions('M_ShowAllCost')) {
+        arr.splice(11, 0, { title: '销售成本金额', dataIndex: 'salesTotalCost', width: 100, align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } })
+      }
+      if (this.showCols.includes('returnFlag')) {
+        arr.splice(12, 0, { slots: { title: 'salesReturnNum' }, dataIndex: 'salesReturnTotalQty', width: 110, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } })
+        arr.splice(13, 0, { title: '销售退货金额', dataIndex: 'salesReturnTotalAmount', width: 100, align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } })
+        arr.splice(14, 0, { title: '销售退货折扣金额', dataIndex: 'salesReturnTotalDiscountAmount', width: 120, align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } })
+        arr.splice(15, 0, { title: '销售退货折后金额', dataIndex: 'salesReturnTotalDiscountedAmount', width: 120, align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } })
+        if (this.$hasPermissions('M_ShowAllCost')) {
+          arr.splice(16, 0, { title: '销售退货成本金额', dataIndex: 'salesReturnTotalCost', width: 120, align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } })
+        }
+        const pos = this.showCols.includes('returnFlag') ? 17 : 16
+        arr.splice(pos, 0, { title: '销售数量合计', dataIndex: 'totalQty', width: 120, align: 'right', customRender: function (text) { return ((text || text == 0) ? text : '--') } })
+        arr.splice(pos * 1 + 1, 0, { title: '销售金额合计', dataIndex: 'totalAmount', width: 120, align: 'right', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } })
+      }
+      return arr
+    }
+  },
+  methods: {
+    // 统计 合计
+    getCount (params) {
+      salesBillRankCount(params).then(res => {
+        if (res.status == 200) {
+          this.totalData = res.data
+        } else {
+          this.totalData = null
+        }
+      })
+    },
+    //  创建时间  change
+    dateChange (date) {
+      this.queryParam.time = date
+      this.queryParam.beginDate = date[0] || ''
+      this.queryParam.endDate = date[1] || ''
+    },
+    //  查询
+    handleSearch () {
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          this.$refs.table.refresh(true)
+        } else {
+          this.$message.error('查询时间不能为空!')
+          return false
+        }
+      })
+    },
+    //  重置
+    resetSearchForm () {
+      this.$refs.rangeDate.resetDate()
+      this.queryParam.time = []
+      this.queryParam.beginDate = ''
+      this.queryParam.endDate = ''
+      this.queryParam.productBrandSn = undefined
+      this.queryParam.productTypeSn1 = undefined
+      this.queryParam.productTypeSn2 = undefined
+      this.queryParam.productTypeSn3 = undefined
+      this.queryParam.productCode = undefined
+      this.queryParam.productName = undefined
+      this.productType = []
+      this.$refs.ruleForm.resetFields()
+      this.totalData = null
+      this.$refs.table.clearTable()
+    },
+    //  产品分类  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] : ''
+    },
+    handleExport () {
+      const _this = this
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          const params = JSON.parse(JSON.stringify(_this.queryParam))
+          params.returnFlag = _this.showCols.includes('returnFlag') ? 1 : 0
+          params.showCost = this.$hasPermissions('M_ShowAllCost') ? '1' : '0'
+          delete params.time
+          _this.exportLoading = true
+          _this.spinning = true
+          salesBillRankExport(params).then(res => {
+            downloadExcel(res, '销售排行报表')
+            _this.exportLoading = false
+            _this.spinning = false
+          })
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    },
+    // 判断是否显示销售退货(明细)
+    handleShowFlag (e) {
+      this.$refs.table.refresh()
+    },
+    // 加入购物车
+    addShopCar (row) {
+      this.spinning = true
+      purchaseCartSave({
+        productSn: row.productSn,
+        qty: 1,
+        productCode: row.productCode,
+        sysFlag: row.sysFlag
+      }).then(res => {
+        if (res.status == 200) {
+          this.$message.success('添加购物车成功!')
+        }
+        this.spinning = false
+      })
+    },
+    setTableH () {
+      const tableSearchH = this.$refs.tableSearch.offsetHeight
+      this.tableHeight = window.innerHeight - tableSearchH - 255
+    }
+  },
+  watch: {
+    advanced (newValue, oldValue) {
+      const _this = this
+      this.$nextTick(() => { // 页面渲染完成后的回调
+        _this.setTableH()
+      })
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
+      this.resetSearchForm()
+      this.$nextTick(() => { // 页面渲染完成后的回调
+        this.setTableH()
+      })
+    }
+  },
+  activated () {
+    // 如果是新页签打开,则重置当前页面
+    if (this.$store.state.app.isNewTab) {
+      this.resetSearchForm()
+      this.$nextTick(() => { // 页面渲染完成后的回调
+        this.setTableH()
+      })
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {})
+  }
+}
+</script>
+<style lang="less" scoped>
+  .table-operator{
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+  }
+</style>

+ 5 - 3
src/views/salesManagement/salesQuery/list.vue

@@ -135,10 +135,14 @@
       </div>
       <a-alert type="info" style="margin-bottom:10px">
         <div slot="message">
-          总售价:<strong>{{ totalData&&(totalData.totalAmount || totalData.totalAmount==0) ? toThousands(totalData.totalAmount) : '--' }}</strong>元;
           总单数:<strong>{{ totalData&&(totalData.totalRecord || totalData.totalRecord==0) ? totalData.totalRecord : '--' }}</strong>;
           总款数:<strong>{{ totalData&&(totalData.totalCategory || totalData.totalCategory==0) ? totalData.totalCategory : '--' }}</strong>;
           总数量:<strong>{{ totalData&&(totalData.totalQty || totalData.totalQty==0) ? totalData.totalQty : '--' }}</strong>;
+          总售价:<strong>{{ totalData&&(totalData.totalAmount || totalData.totalAmount==0) ? toThousands(totalData.totalAmount) : '--' }}</strong>;
+          <span v-if="showDiscount">
+            折扣金额:<strong>{{ totalData&&(totalData.discountAmount || totalData.discountAmount==0) ? toThousands(totalData.discountAmount) : '--' }}</strong>;
+            折后总售价:<strong>{{ totalData&&(totalData.discountedAmount || totalData.discountedAmount==0) ? toThousands(totalData.discountedAmount) : '--' }}</strong>;
+          </span>
         </div>
       </a-alert>
       <!-- 列表 -->
@@ -258,7 +262,6 @@ export default {
   components: { STable, VSelect, chooseCustomModal, rangeDate, auditModal, custList, stateIcon },
   mixins: [commonMixin],
   data () {
-    const _this = this
     return {
       spinning: false,
       tableHeight: 0,
@@ -319,7 +322,6 @@ export default {
             }
             this.disabled = false
           }
-          console.log(res, 'res')
           this.spinning = false
           return data
         })

+ 11 - 9
src/views/salesManagement/salesQueryNew/list.vue

@@ -121,10 +121,15 @@
         <!-- 操作按钮 -->
         <div class="table-operator" style="display:flex;align-items:center;justify-content: space-between;">
           <div class="alert-message">
-            销售单数合计:<strong>{{ totalData&&(totalData.totalRecord || totalData.totalRecord==0) ? totalData.totalRecord : '--' }}</strong>;
-            销售款数合计:<strong>{{ totalData&&(totalData.totalCategory || totalData.totalCategory==0) ? totalData.totalCategory : '--' }}</strong>;
-            销售数量合计:<strong>{{ totalData&&(totalData.totalQty || totalData.totalQty==0) ? totalData.totalQty : '--' }}</strong>;
-            销售金额合计:<strong>{{ totalData&&(totalData.totalAmount || totalData.totalAmount==0) ? toThousands(totalData.totalAmount) : '--' }}</strong>;
+            合计:
+            总单数:<strong>{{ totalData&&(totalData.totalRecord || totalData.totalRecord==0) ? totalData.totalRecord : '--' }}</strong>;
+            总款数:<strong>{{ totalData&&(totalData.totalCategory || totalData.totalCategory==0) ? totalData.totalCategory : '--' }}</strong>;
+            总数量:<strong>{{ totalData&&(totalData.totalQty || totalData.totalQty==0) ? totalData.totalQty : '--' }}</strong>;
+            总售价:<strong>{{ totalData&&(totalData.totalAmount || totalData.totalAmount==0) ? toThousands(totalData.totalAmount) : '--' }}</strong>;
+            <span v-if="showDiscount">
+              折扣金额:<strong>{{ totalData&&(totalData.discountAmount || totalData.discountAmount==0) ? toThousands(totalData.discountAmount) : '--' }}</strong>;
+              折后总售价:<strong>{{ totalData&&(totalData.discountedAmount || totalData.discountedAmount==0) ? toThousands(totalData.discountedAmount) : '--' }}</strong>;
+            </span>
           </div>
           <div class="action-buttons">
             <a-button type="primary" class="button-error" v-if="$hasPermissions('B_salesNews')" @click="handleAdd(0)"><a-icon type="plus" /> 新增(零售)</a-button>
@@ -258,7 +263,6 @@ export default {
   components: { STable, VSelect, chooseCustomModal, rangeDate, auditModal, custList, stateIcon },
   mixins: [commonMixin],
   data () {
-    const _this = this
     return {
       spinning: false,
       tableHeight: 0,
@@ -319,7 +323,6 @@ export default {
             }
             this.disabled = false
           }
-          console.log(res, 'res')
           this.spinning = false
           return data
         })
@@ -336,8 +339,8 @@ export default {
       const arr = [
         { title: '序号', dataIndex: 'no', align: 'center', width: '4%' },
         { title: '来源', dataIndex: 'sourceTypeDictValue', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
-        { title: '销售单号', scopedSlots: { customRender: 'salesBillNo' }, width: '9%', align: 'center' },
-        { title: '客户名称', dataIndex: 'buyerNameCurrent', align: 'center', width: '15%', customRender: function (text) { return text || '--' } },
+        { title: '销售单号', scopedSlots: { customRender: 'salesBillNo' }, width: this.showDiscount ? '6%' : '9%', align: 'center' },
+        { title: '客户名称', dataIndex: 'buyerNameCurrent', align: 'center', width: this.showDiscount ? '12%' : '15%', customRender: function (text) { return text || '--' } },
         { title: '总款数', dataIndex: 'totalCategory', align: 'center', width: '5%', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
         { title: '总数量', dataIndex: 'totalQty', align: 'center', width: '5%', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
         { title: '总售价', dataIndex: 'totalAmount', align: 'right', width: '5%', customRender: function (text) { return ((text || text == 0) ? _this.toThousands(text) : '--') } },
@@ -599,7 +602,6 @@ export default {
           this.$refs.table.refresh()
         }
       }
-      
     }
   },
   watch: {

+ 1 - 1
vue.config.js

@@ -209,7 +209,7 @@ const vueConfig = {
     // If you want to turn on the proxy, please remove the mockjs /src/main.jsL11
     proxy: {
       '/api': {
-        // target: 'http://192.168.2.113:8550/qpls-md',
+        // target: 'http://192.168.2.124/qpls-md',
         target: 'https://p.iscm.360arrow.com/qpls-md',
         // ws: false,
         ws: true,