Browse Source

Merge branch 'deploy_0804' of jianguan-web/jg-ocs-html into master

陈瑞 3 years ago
parent
commit
c867f33735

+ 136 - 0
src/api/checkWarehouse.js

@@ -0,0 +1,136 @@
+import { axios } from '@/utils/request'
+
+//  库存盘点  列表  分页
+export const checkWarehouseList = (params) => {
+  const url = `/checkWarehouse/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  库存盘点  保存
+export const checkWarehouseSave = (params) => {
+  return axios({
+    url: '/checkWarehouse/save',
+    data: params,
+    method: 'post'
+  })
+}
+//  库存盘点  详情
+export const checkWarehouseDetail = (params) => {
+  return axios({
+    url: `/checkWarehouse/queryBySn/${params.sn}`,
+    method: 'get'
+  })
+}
+//  库存盘点  详情  分页
+export const checkWarehouseDetailList = (params) => {
+  const url = `/checkWarehouse/detail/queryPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  库存盘点  详情  合计
+export const checkWarehouseDetailCount = (params) => {
+  return axios({
+    url: '/checkWarehouse/detail/queryCount',
+    data: params,
+    method: 'post'
+  })
+}
+// 盘点人盘点/监盘人监盘 盘点  打印
+export const checkWarehouseDetailPrint = params => {
+  const url = `/checkWarehouse/detail/print/${params.checkWarehouseSn}/${params.type}`
+  delete params.checkWarehouseSn
+  delete params.type
+  return axios.request({
+    url: url,
+    data: params,
+    method: 'post',
+    responseType: 'blob'
+  })
+}
+//  库存盘点  新增盘点  检查是否有未完结
+export const checkWarehouseStartCheck = (params) => {
+  return axios({
+    url: '/checkWarehouse/startCheck',
+    method: 'get'
+  })
+}
+//  盘点人盘点/监盘人监盘  盘点  打印检查产品
+export const checkWarehousePrintCheck = (params) => {
+  const url = `/checkWarehouse/detail/printCheck/${params.checkWarehouseSn}/${params.type}`
+  delete params.checkWarehouseSn
+  delete params.type
+  return axios({
+    url: url,
+    data: {},
+    method: 'get'
+  })
+}
+//  盘点人盘点/监盘人监盘  详情  保存
+export const checkWarehouseDetailSave = (params) => {
+  return axios({
+    url: '/checkWarehouse/detail/save',
+    data: params,
+    method: 'post'
+  })
+}
+//  盘点人盘点  盘点
+export const checkWarehouseCheck = (params) => {
+  return axios({
+    url: '/checkWarehouse/checkWarehouse',
+    data: params,
+    method: 'post'
+  })
+}
+//  库存盘点  作废
+export const checkWarehouseDelete = (params) => {
+  return axios({
+    url: '/checkWarehouse/delete',
+    data: params,
+    method: 'post'
+  })
+}
+//  盘点人盘点  监盘
+export const checkWarehouseSupervise = (params) => {
+  return axios({
+    url: '/checkWarehouse/checkSupervise',
+    data: params,
+    method: 'post'
+  })
+}
+//  盘点人盘点  重盘
+export const checkWarehouseReCheck = (params) => {
+  return axios({
+    url: '/checkWarehouse/reCheckWarehouse',
+    data: params,
+    method: 'post'
+  })
+}
+//  盘点人盘点  财务确认
+export const checkWarehouseFinanceAudit = (params) => {
+  return axios({
+    url: '/checkWarehouse/financeAudit',
+    data: params,
+    method: 'post'
+  })
+}
+//  财务盘点确认  详情  列表  分页
+export const checkWarehouseDetailFinanceList = (params) => {
+  const url = `/checkWarehouse/detail/queryFinanceAuditPage/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}

+ 33 - 0
src/api/supplier.js

@@ -87,3 +87,36 @@ export const supplierProductSnList = (params) => {
     method: 'get'
   })
 }
+// 供应商关联产品 下载模板
+export const supplierProductDownload = params => {
+  return axios.request({
+    url: `/supplierProduct/downloadExcel`,
+    method: 'post',
+    responseType: 'blob'
+  })
+}
+// 供应商关联产品  解析导入的文件
+export const supplierProductParseProducts = params => {
+  return axios({
+    url: '/supplierProduct/parseProducts',
+    data: params,
+    method: 'post'
+  })
+}
+// 供应商关联产品  批量插入
+export const supplierProductBatchInsert = params => {
+  return axios({
+    url: '/supplierProduct/batchInsert',
+    data: params,
+    method: 'post'
+  })
+}
+//  供应商关联产品 导入产品  导出错误项
+export const supplierProductailExcel = (params) => {
+  return axios({
+    url: '/supplierProduct/downloadFailExcel',
+    data: params,
+    method: 'post',
+    responseType: 'blob'
+  })
+}

+ 4 - 4
src/components/MultiTab/MultiTab.vue

@@ -178,18 +178,18 @@ export default {
         const na = newVal.meta.title.indexOf('详情') >= 0
         const nb = newVal.meta.title.indexOf('新增') >= 0
         const nc = newVal.meta.title.indexOf('编辑') >= 0
-        const nxt = newVal.meta.title.indexOf('下推销售单') >= 0
+        const nxt = newVal.meta.replaceTab
         const oa = oldMenu.meta.title.indexOf('详情') >= 0
         const ob = oldMenu.meta.title.indexOf('新增') >= 0
         const oc = oldMenu.meta.title.indexOf('编辑') >= 0
-        const oxt = oldMenu.meta.title.indexOf('下推销售单') >= 0
+        const oxt = oldMenu.meta.replaceTab
         if ((na || nb || nc || nxt || oa || ob || oc || oxt) && hasChildren) {
           // 替换当前页签
           this.replaceTab(newVal, oldMenu)
           // 从列表打开新增,编辑
-          this.$store.state.app.isNewTab = na || nb || nc
+          this.$store.state.app.isNewTab = na || nb || nc || nxt
           // 从编辑,新增返回列表,刷新列表
-          this.$store.state.app.updateList = ob || oc
+          this.$store.state.app.updateList = ob || oc || oxt
           this.activeKey = newVal.name
         } else {
           // 新打开的页签

+ 125 - 8
src/config/router.config.js

@@ -144,6 +144,7 @@ export const asyncRouterMap = [
                 meta: {
                   title: '下推销售单',
                   icon: 'monitor',
+                  replaceTab: true,
                   hidden: true
                   // permission: 'M_salesNew'
                 }
@@ -299,6 +300,7 @@ export const asyncRouterMap = [
                 meta: {
                   title: '销售退货品检',
                   icon: 'fund',
+                  replaceTab: true,
                   hidden: true
                   // permission: 'M_salesReturnCheck'
                 }
@@ -526,6 +528,42 @@ export const asyncRouterMap = [
               }
             ]
           },
+          // {
+          //   path: '/financialManagement/inventoryConfirmation',
+          //   redirect: '/financialManagement/inventoryConfirmation/list',
+          //   name: 'inventoryConfirmation',
+          //   component: BlankLayout,
+          //   meta: {
+          //     title: '盘点确认',
+          //     icon: 'monitor',
+          //     permission: 'M_inventoryConfirmationList'
+          //   },
+          //   hideChildrenInMenu: true,
+          //   children: [
+          //     {
+          //       path: 'list',
+          //       name: 'inventoryConfirmationList',
+          //       component: () => import(/* webpackChunkName: "financialManagement" */ '@/views/financialManagement/inventoryConfirmation/list.vue'),
+          //       meta: {
+          //         title: '盘点确认列表',
+          //         icon: 'monitor',
+          //         hidden: true,
+          //         permission: 'M_inventoryConfirmationList'
+          //       }
+          //     },
+          //     {
+          //       path: 'detail/:sn',
+          //       name: 'inventoryConfirmationDetail',
+          //       component: () => import(/* webpackChunkName: "financialManagement" */ '@/views/financialManagement/inventoryConfirmation/detail.vue'),
+          //       meta: {
+          //         title: '盘点确认详情',
+          //         icon: 'monitor',
+          //         hidden: true,
+          //         permission: 'B_inventoryConfirmationDetail'
+          //       }
+          //     }
+          //   ]
+          // },
           {
             path: '/financialManagement/financialCollection',
             redirect: '/financialManagement/financialCollection/list',
@@ -594,6 +632,7 @@ export const asyncRouterMap = [
                 meta: {
                   title: '出入库明细',
                   icon: 'monitor',
+                  replaceTab: true,
                   hidden: true
                   // permission: 'B_goodsManage_edit'
                 }
@@ -602,25 +641,25 @@ export const asyncRouterMap = [
           },
           // {
           //   path: '/inventoryManagement/inventoryCheck',
-          //   redirect: '/inventoryManagement/inventoryCheck/list',
+          //   redirect: '/inventoryManagement/inventoryCheck/list/0',
           //   name: 'inventoryCheck',
           //   component: BlankLayout,
           //   meta: {
           //     title: '库存盘点',
-          //     icon: 'monitor'
-          //     // permission: 'M_inventoryCheckList'
+          //     icon: 'monitor',
+          //     permission: 'M_inventoryCheckList'
           //   },
           //   hideChildrenInMenu: true,
           //   children: [
           //     {
-          //       path: 'list',
+          //       path: 'list/:type',
           //       name: 'inventoryCheckList',
           //       component: () => import(/* webpackChunkName: "inventoryManagement" */ '@/views/inventoryManagement/inventoryCheck/list.vue'),
           //       meta: {
           //         title: '库存盘点列表',
           //         icon: 'monitor',
-          //         hidden: true
-          //         // permission: 'M_inventoryCheckList'
+          //         hidden: true,
+          //         permission: 'M_inventoryCheckList'
           //       }
           //     },
           //     {
@@ -630,8 +669,82 @@ export const asyncRouterMap = [
           //       meta: {
           //         title: '库存盘点详情',
           //         icon: 'monitor',
-          //         hidden: true
-          //         // permission: 'B_goodsManage_edit'
+          //         hidden: true,
+          //         permission: 'B_inventoryCheckDetail'
+          //       }
+          //     }
+          //   ]
+          // },
+          // {
+          //   path: '/inventoryManagement/makeInventory',
+          //   redirect: '/inventoryManagement/makeInventory/list',
+          //   name: 'makeInventory',
+          //   component: BlankLayout,
+          //   meta: {
+          //     title: '盘点人盘点',
+          //     icon: 'monitor',
+          //     permission: 'M_inventoryMakeInventoryList'
+          //   },
+          //   hideChildrenInMenu: true,
+          //   children: [
+          //     {
+          //       path: 'list',
+          //       name: 'makeInventoryList',
+          //       component: () => import(/* webpackChunkName: "inventoryManagement" */ '@/views/inventoryManagement/makeInventory/list.vue'),
+          //       meta: {
+          //         title: '盘点人盘点列表',
+          //         icon: 'monitor',
+          //         hidden: true,
+          //         permission: 'M_inventoryMakeInventoryList'
+          //       }
+          //     },
+          //     {
+          //       path: 'check/:sn',
+          //       name: 'makeInventoryCheck',
+          //       component: () => import(/* webpackChunkName: "inventoryManagement" */ '@/views/inventoryManagement/makeInventory/check.vue'),
+          //       meta: {
+          //         title: '盘点人盘点',
+          //         icon: 'monitor',
+          //         hidden: true,
+          //         replaceTab: true,
+          //         permission: 'B_inventoryMakeInventoryCheck'
+          //       }
+          //     }
+          //   ]
+          // },
+          // {
+          //   path: '/inventoryManagement/supervisionDisk',
+          //   redirect: '/inventoryManagement/supervisionDisk/list',
+          //   name: 'supervisionDisk',
+          //   component: BlankLayout,
+          //   meta: {
+          //     title: '监盘人盘点',
+          //     icon: 'monitor',
+          //     permission: 'M_supervisionDiskList'
+          //   },
+          //   hideChildrenInMenu: true,
+          //   children: [
+          //     {
+          //       path: 'list',
+          //       name: 'supervisionDiskList',
+          //       component: () => import(/* webpackChunkName: "inventoryManagement" */ '@/views/inventoryManagement/supervisionDisk/list.vue'),
+          //       meta: {
+          //         title: '监盘人盘点列表',
+          //         icon: 'monitor',
+          //         hidden: true,
+          //         permission: 'M_supervisionDiskList'
+          //       }
+          //     },
+          //     {
+          //       path: 'check/:sn',
+          //       name: 'supervisionDiskCheck',
+          //       component: () => import(/* webpackChunkName: "inventoryManagement" */ '@/views/inventoryManagement/supervisionDisk/check.vue'),
+          //       meta: {
+          //         title: '监盘人监盘',
+          //         icon: 'monitor',
+          //         replaceTab: true,
+          //         hidden: true,
+          //         permission: 'B_supervisionDiskCheck'
           //       }
           //     }
           //   ]
@@ -1661,6 +1774,7 @@ export const asyncRouterMap = [
                 meta: {
                   title: '经销权设置',
                   icon: 'file-text',
+                  replaceTab: true,
                   hidden: true
                   // permission: 'B_goodsManage_edit'
                 }
@@ -1832,6 +1946,7 @@ export const asyncRouterMap = [
                 meta: {
                   title: '关联产品',
                   icon: 'team',
+                  replaceTab: true,
                   hidden: true
                   // permission: 'B_goodsManage_edit'
                 }
@@ -1917,6 +2032,7 @@ export const asyncRouterMap = [
                 meta: {
                   title: '促销规则设置',
                   icon: 'thunderbolt',
+                  replaceTab: true,
                   hidden: true
                   // permission: 'B_goodsManage_edit'
                 }
@@ -2016,6 +2132,7 @@ export const asyncRouterMap = [
                 meta: {
                   title: '仓位列表',
                   icon: 'deployment-unit',
+                  replaceTab: true,
                   hidden: true
                   // permission: 'B_goodsManage_edit'
                 }

+ 40 - 1
src/views/allocationManagement/transferOut/basicInfoModal.vue

@@ -44,6 +44,17 @@
             <a-select-option v-for="item in allocateTypeList" :key="item.allocateTypeSn" :value="item.allocateTypeSn">{{ item.name }}</a-select-option>
           </a-select>
         </a-form-model-item>
+        <a-form-model-item label="起止时间" prop="time">
+          <a-range-picker
+            style="width:100%"
+            v-model="form.time"
+            show-time
+            :disabledDate="disabledDate"
+            :format="dateFormat"
+            @change="dateChange"
+            @calendarChange="dateCalendarChange"
+            :placeholder="['开始时间', '结束时间']" />
+        </a-form-model-item>
         <a-form-model-item label="备注" prop="remark">
           <a-textarea id="allocateBill-basicInfo-remark" :maxLength="120" v-model="form.remark" placeholder="请输入备注(最多120个字符)" allowClear />
         </a-form-model-item>
@@ -57,6 +68,7 @@
 </template>
 
 <script>
+import moment from 'moment'
 import debounce from 'lodash/debounce'
 import { VSelect } from '@/components'
 import { allocateBillSave } from '@/api/allocateBill'
@@ -87,6 +99,9 @@ export default {
         targetSn: undefined,
         targetName: '',
         allocateTypeSn: undefined,
+        time: [],
+        promoStartDate: '',
+        promoEndDate: '',
         remark: ''
       },
       rules: {
@@ -98,7 +113,9 @@ export default {
       fetching: false,
       dealerData: [], //  经销商  下拉数据
       targetTypeList: [], //  调往对象类型
-      allocateTypeList: [] //  调拨类型
+      allocateTypeList: [], //  调拨类型
+      dateFormat: 'YYYY-MM-DD HH:mm:ss',
+      selectPriceDate: ''
     }
   },
   computed: {
@@ -108,6 +125,28 @@ export default {
     }
   },
   methods: {
+	  // 不可选日期
+	  disabledDate (current) {
+      // 可选今天以后的时间(包含今天),所选时间跨度最多可为一年
+      const minYearVs = moment().subtract(1, 'day') // 今天以后,包含今天
+	    // //  限制最多只能查一年区间的数据
+	    if (this.selectPriceDate) {
+        const maxYearVs = moment(this.selectPriceDate, 'YYYY-MM-DD HH:mm:ss').add(1, 'years') //  当前选中开始日期后推一年
+        return current && current < minYearVs || current && current > maxYearVs
+      } else {
+        return current && current < minYearVs
+	    }
+	  },
+    // 日期  change
+    dateChange (date, dateStrings) {
+      this.selectPriceDate = ''
+      this.form.time = dateStrings
+      this.form.promoStartDate = dateStrings[0] || ''
+      this.form.promoEndDate = dateStrings[1] || ''
+    },
+    dateCalendarChange (date, dateStrings) {
+      this.selectPriceDate = date[0]
+    },
     // 搜索经销商
     fetchUser (value) {
       console.log('fetching user', value)

+ 6 - 2
src/views/allocationManagement/transferOut/detail.vue

@@ -39,6 +39,10 @@
               <a-descriptions-item label="调拨单号">{{ (basicInfoData&&basicInfoData.allocateNo) || '--' }}</a-descriptions-item>
               <a-descriptions-item label="调拨类型">{{ (basicInfoData&&basicInfoData.allocateTypeName) || '--' }}</a-descriptions-item>
               <a-descriptions-item label="业务状态">{{ (basicInfoData&&basicInfoData.stateDictValue) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="起止时间">
+                <span v-if="basicInfoData&&(basicInfoData.promoStartDate || basicInfoData.promoEndDate)">{{ (basicInfoData&&basicInfoData.promoStartDate) || '--' }} ~ {{ (basicInfoData&&basicInfoData.promoEndDate) || '--' }}</span>
+                <span v-else>--</span>
+              </a-descriptions-item>
               <a-descriptions-item label="备注">{{ (basicInfoData&&basicInfoData.remark) || '--' }}</a-descriptions-item>
             </a-descriptions>
           </a-collapse-panel>
@@ -115,9 +119,9 @@ export default {
     },
     columns () {
       const arr = [
-        { title: '序号', dataIndex: 'no', width: '4%', align: 'center', },
+        { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
         { title: '产品编码', dataIndex: 'productEntity.code', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
-        { title: '产品名称', dataIndex: 'productEntity.name',width: '27%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '产品名称', dataIndex: 'productEntity.name', width: '27%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
         { title: '原厂编码', dataIndex: 'productEntity.origCode', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
         { title: '单位', dataIndex: 'productEntity.unit', width: '5%', align: 'center', customRender: function (text) { return text || '--' } },
         { title: '售价', dataIndex: 'price', width: '8%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },

+ 18 - 14
src/views/allocationManagement/transferOut/edit.vue

@@ -35,6 +35,10 @@
                 <AllocateType id="allocateEdit-allocateTypeSn" style="width: 200px;" @change="changeAllocateType" v-model="basicInfoData.allocateTypeSn"></AllocateType>
               </a-descriptions-item>
               <a-descriptions-item label="业务状态">{{ (basicInfoData&&basicInfoData.stateDictValue) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="起止时间">
+                <span v-if="basicInfoData&&(basicInfoData.promoStartDate || basicInfoData.promoEndDate)">{{ (basicInfoData&&basicInfoData.promoStartDate) || '--' }} ~ {{ (basicInfoData&&basicInfoData.promoEndDate) || '--' }}</span>
+                <span v-else>--</span>
+              </a-descriptions-item>
               <a-descriptions-item label="备注">{{ (basicInfoData&&basicInfoData.remark) || '--' }}</a-descriptions-item>
             </a-descriptions>
           </a-collapse-panel>
@@ -286,13 +290,13 @@ export default {
     columns () {
       const arr = [
         { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
-        { title: '产品编码', dataIndex: 'productCode',  width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品编码', dataIndex: 'productCode', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
         { title: '产品名称', dataIndex: 'productName', align: 'center', width: '29%', customRender: function (text) { return text || '--' }, ellipsis: true },
-        { title: '原厂编码', dataIndex: 'productOrigCode',  width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
-        { title: '售价', dataIndex: 'productPrice',  width: '10%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
-        { title: '库存数量', dataIndex: 'currentStockQty',  width: '10%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '原厂编码', dataIndex: 'productOrigCode', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '售价', dataIndex: 'productPrice', width: '10%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '库存数量', dataIndex: 'currentStockQty', width: '10%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
         { title: '单位', dataIndex: 'productUnit', width: '7%', align: 'center', customRender: function (text) { return text || '--' } },
-        { title: '操作', scopedSlots: { customRender: 'action1' }, width: '10%',align: 'center' }
+        { title: '操作', scopedSlots: { customRender: 'action1' }, width: '10%', align: 'center' }
       ]
       if (this.$hasPermissions('B_isShowCost')) {
         arr.splice(4, 0, { title: '成本价', dataIndex: 'lastStockCost', width: '10%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } })
@@ -301,15 +305,15 @@ export default {
     },
     chooseColumns () {
       const arr = [
-        { title: '序号', dataIndex: 'no',  width: '4%', align: 'center' },
-        { title: '产品编码', dataIndex: 'productEntity.code',  width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
-        { title: '产品名称', dataIndex: 'productEntity.name',  width: '20%',align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
-        { title: '原厂编码', dataIndex: 'productEntity.origCode',  width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
-        { title: '售价', scopedSlots: { customRender: 'price' },  width: '10%', align: 'center' },
-        { title: '库存数量', dataIndex: 'currentStockQty',  width: '10%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
-        { title: '调出数量', scopedSlots: { customRender: 'qty' },  width: '10%',align: 'center' },
-        { title: '单位', dataIndex: 'productEntity.unit',  width: '6%',align: 'center', customRender: function (text) { return text || '--' } },
-        { title: '操作', scopedSlots: { customRender: 'action' },  width: '6%', align: 'center' }
+        { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
+        { title: '产品编码', dataIndex: 'productEntity.code', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品名称', dataIndex: 'productEntity.name', width: '20%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '原厂编码', dataIndex: 'productEntity.origCode', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '售价', scopedSlots: { customRender: 'price' }, width: '10%', align: 'center' },
+        { title: '库存数量', dataIndex: 'currentStockQty', width: '10%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '调出数量', scopedSlots: { customRender: 'qty' }, width: '10%', align: 'center' },
+        { title: '单位', dataIndex: 'productEntity.unit', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: '6%', align: 'center' }
       ]
       if (this.$hasPermissions('B_isShowCost')) {
         arr.splice(4, 0, { title: '成本价', dataIndex: 'cost', width: '10%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } })

+ 12 - 6
src/views/allocationManagement/transferOut/list.vue

@@ -79,6 +79,11 @@
         <template slot="allocateNo" slot-scope="text, record">
           <span :class="$hasPermissions('M_transferOut_detail')?'active':'common'" @click="handleDetail(record)">{{ record.allocateNo }}</span>
         </template>
+        <!-- 起止时间 -->
+        <template slot="promoDate" slot-scope="text, record">
+          <span v-if="record.promoStartDate || record.promoEndDate">{{ record.promoStartDate }} ~ {{ record.promoEndDate }}</span>
+          <span v-else>--</span>
+        </template>
         <!-- 操作 -->
         <template slot="action" slot-scope="text, record">
           <a-button
@@ -168,19 +173,20 @@ export default {
   computed: {
     columns () {
       const arr = [
-        { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
-        { title: '创建时间', dataIndex: 'createDate', width: '8.5%', align: 'center', customRender: function (text) { return text || '--' } },
-        { title: '调拨单号', scopedSlots: { customRender: 'allocateNo' }, align: 'center', width: '15%' },
-        { title: '调往对象', dataIndex: 'targetName', width: '10%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '序号', dataIndex: 'no', width: '3.5%', align: 'center' },
+        { title: '创建时间', dataIndex: 'createDate', width: '7%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '调拨单号', scopedSlots: { customRender: 'allocateNo' }, align: 'center', width: '13.5%' },
+        { title: '起止时间', scopedSlots: { customRender: 'promoDate' }, align: 'center', width: '8%' },
+        { title: '调往对象', dataIndex: 'targetName', width: '8%', align: 'left', customRender: function (text) { return text || '--' }, ellipsis: true },
         { title: '客户类型', dataIndex: 'dealerLevelDictValue', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
         { title: '总数量', dataIndex: 'totalQty', width: '5%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
         { title: '总售价', dataIndex: 'totalPrice', width: '5%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
-        { title: '审核时间', dataIndex: 'auditTime', width: '8.5%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '审核时间', dataIndex: 'auditTime', width: '7%', align: 'center', customRender: function (text) { return text || '--' } },
         { title: '调拨类型', dataIndex: 'allocateTypeName', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
         { title: '业务状态', dataIndex: 'stateDictValue', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
         { title: '打印状态', dataIndex: 'printStateDictValue', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
         { title: '打印次数', dataIndex: 'printCount', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
-        { title: '操作', scopedSlots: { customRender: 'action' }, width: '9%', align: 'center' }
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: '8%', align: 'center' }
       ]
       if (this.$hasPermissions('B_isShowCost')) {
         arr.splice(6, 0, { title: '总成本', dataIndex: 'totalCost', width: '5%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } })

+ 14 - 2
src/views/common/auditModal.vue

@@ -16,8 +16,8 @@
         </div>
       </div>
       <div class="btn-box">
-        <a-button type="primary" class="button-error" @click="handleAuditFail">审核不通过</a-button>
-        <a-button type="primary" class="button-info" @click="handleAuditOk">审核通过</a-button>
+        <a-button type="primary" class="button-warning" @click="handleAuditFail" v-if="isCancel">{{ cancelText || '审核不通过' }}</a-button>
+        <a-button type="primary" class="button-info" @click="handleAuditOk">{{ okText || '审核通过' }}</a-button>
       </div>
     </a-spin>
   </a-modal>
@@ -35,6 +35,18 @@ export default {
       type: String,
       default: '请点击下方按钮确认操作?'
     },
+    okText: {
+      type: String,
+      default: '审核通过'
+    },
+    cancelText: {
+      type: String,
+      default: '审核不通过'
+    },
+    isCancel: {
+      type: Boolean,
+      default: true
+    },
     spinning: {
       type: Boolean,
       default: false

+ 112 - 0
src/views/common/commonModal.vue

@@ -0,0 +1,112 @@
+<template>
+  <a-modal
+    centered
+    class="common-modal"
+    :footer="null"
+    :maskClosable="false"
+    v-model="isShow"
+    :title="modalTit"
+    @cancle="isShow=false"
+    :width="416">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <div class="common-main" v-html="modalHtml"></div>
+      <div class="btn-box">
+        <a-button type="primary" class="button-warning" @click="handleCommonCancel" v-if="isCancel">{{ cancelText }}</a-button>
+        <a-button type="primary" class="button-info" @click="handleCommonOk">{{ okText }}</a-button>
+      </div>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+export default {
+  name: 'CommonModal',
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    modalTit: { // 弹框标题
+      type: String,
+      default: null
+    },
+    modalHtml: {
+      type: String,
+      default: ''
+    },
+    okText: { // 确定 按钮文字
+      type: String,
+      default: '确定'
+    },
+    cancelText: { // 取消 按钮文字
+      type: String,
+      default: '取消'
+    },
+    isCancel: { // 是否显示  取消 按钮
+      type: Boolean,
+      default: true
+    },
+    spinning: { // 加载中
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal //  是否打开弹框
+    }
+  },
+  methods: {
+    // 确定
+    handleCommonOk () {
+      this.$emit('ok')
+    },
+    // 取消
+    handleCommonCancel () {
+      this.$emit('cancel')
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .common-modal{
+    .ant-modal-body{
+      padding: 32px 32px 24px;
+    }
+    .common-main{
+      display: flex;
+      .common-cont{
+        .common-tit{
+          color: rgba(0, 0, 0, 0.85);
+          font-weight: 500;
+          font-size: 16px;
+          line-height: 1.4;
+          margin: 0;
+        }
+        .common-txt{
+          margin: 8px 0 0;
+          color: rgba(0, 0, 0, 0.65);
+          font-size: 14px;
+          line-height: 1.5;
+        }
+      }
+    }
+    .btn-box{
+      text-align: right;
+      margin-top: 24px;
+    }
+  }
+</style>

+ 225 - 0
src/views/financialManagement/inventoryConfirmation/detail.vue

@@ -0,0 +1,225 @@
+<template>
+  <div class="inventoryConfirmationDetail-wrap">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-page-header :ghost="false" :backIcon="false" @back="handleBack" class="inventoryConfirmationDetail-cont" >
+        <!-- 自定义的二级文字标题 -->
+        <template slot="subTitle">
+          <a id="inventoryConfirmationDetail-back-btn" href="javascript:;" @click="handleBack"><a-icon type="left" /> 返回列表</a>
+          <span class="billno">单号:{{ detail&&detail.checkWarehouseNo }}</span>
+        </template>
+      </a-page-header>
+      <!-- 基础信息 -->
+      <a-card size="small" :bordered="false" class="inventoryConfirmationDetail-cont">
+        <a-collapse>
+          <a-collapse-panel key="1" header="基础信息">
+            <a-descriptions :column="3">
+              <a-descriptions-item label="创建人">{{ (detail&&detail.creatorName) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="创建时间">{{ (detail&&detail.createDate) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="盘点类型">{{ (detail&&detail.checkTypeDictValue) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="盘点状态">{{ (detail&&detail.checkStateDictValue) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="盘点人">{{ (detail&&detail.checkPersonName) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="盘点时间">{{ (detail&&detail.checkTime) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="监盘状态">{{ (detail&&detail.checkSuperviseStateDictValue) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="监盘人">{{ (detail&&detail.checkSupervisePersonName) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="监盘时间">{{ (detail&&detail.checkSuperviseTime) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="财务确认时间">{{ (detail&&detail.financeAuditTime) || '--' }}</a-descriptions-item>
+            </a-descriptions>
+          </a-collapse-panel>
+        </a-collapse>
+      </a-card>
+      <!-- 产品详情 -->
+      <a-card size="small" :bordered="false" class="inventoryConfirmationDetail-cont">
+        <!-- 总计 -->
+        <a-alert type="info" style="margin-bottom:10px">
+          <div slot="message">
+            盘盈数量:<strong :style="{ color: productTotal && productTotal.profitQty>0?'red':productTotal && productTotal.profitQty<0?'green':'' }">{{ productTotal && (productTotal.profitQty || productTotal.profitQty==0) ? productTotal.profitQty : '--' }}</strong>,
+            盘盈金额:<strong :style="{ color: productTotal && productTotal.profitCost>0?'red':productTotal && productTotal.profitCost<0?'green':'' }">{{ productTotal && (productTotal.profitCost || productTotal.profitCost==0) ? productTotal.profitCost : '--' }}</strong>,
+            盘亏数量:<strong :style="{ color: productTotal && productTotal.lossQty>0?'red':productTotal && productTotal.lossQty<0?'green':'' }">{{ productTotal && (productTotal.lossQty || productTotal.lossQty==0) ? productTotal.lossQty : '--' }}</strong>,
+            盘亏金额:<strong :style="{ color: productTotal && productTotal.lossCost>0?'red':productTotal && productTotal.lossCost<0?'green':'' }">{{ productTotal && (productTotal.lossCost || productTotal.lossCost==0) ? productTotal.lossCost : '--' }}</strong>,
+            盈亏总数量:<strong :style="{ color: productTotal && productTotal.profitLossQty>0?'red':productTotal && productTotal.profitLossQty<0?'green':'' }">{{ productTotal && (productTotal.profitLossQty	|| productTotal.profitLossQty ==0) ? productTotal.profitLossQty : '--' }}</strong>,
+            盈亏总金额:<strong :style="{ color: productTotal && productTotal.profitLossCost>0?'red':productTotal && productTotal.profitLossCost<0?'green':'' }">{{ productTotal && (productTotal.profitLossCost || productTotal.profitLossCost==0) ? productTotal.profitLossCost : '--' }}</strong>
+          </div>
+        </a-alert>
+        <!-- 搜索条件 -->
+        <div class="table-page-search-wrapper">
+          <a-row :gutter="15">
+            <a-col :span="18">
+              <a-form-model :model="queryParam" layout="inline" @keyup.enter.native="$refs.table.refresh(true)" >
+                <a-row :gutter="15">
+                  <a-col :md="8" :sm="24">
+                    <a-form-model-item label="产品编码">
+                      <a-input v-model="queryParam.productCode" allowClear placeholder="输入产品编码" />
+                    </a-form-model-item>
+                  </a-col>
+                  <a-col :md="8" :sm="24">
+                    <a-form-model-item style="margin-bottom: 10px;">
+                      <a-button type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="inventoryConfirmationDetail-refresh">查询</a-button>
+                      <a-button style="margin-left: 5px" @click="resetSearchForm" id="inventoryConfirmationDetail-reset">重置</a-button>
+                    </a-form-model-item>
+                  </a-col>
+                </a-row>
+              </a-form-model>
+            </a-col>
+            <a-col :span="6">
+              <div style="float:right;overflow: hidden;">
+                <a-checkbox v-model="foldState" @change="foldStateChange"><span style="display: inline-block;margin-top: 1px;">仅显示盈亏</span></a-checkbox>
+              </div>
+            </a-col>
+          </a-row>
+        </div>
+        <!-- 列表 -->
+        <s-table
+          class="sTable"
+          ref="table"
+          size="small"
+          :rowKey="(record) => record.id"
+          :columns="columns"
+          :data="loadData"
+          :defaultLoadData="false"
+          bordered>
+          <!-- 盈亏数量 -->
+          <template slot="profitLossQty" slot-scope="text, record">
+            <span :style="{ color: record.profitLossQty>0?'red':record.profitLossQty<0?'green':'', fontWeight: record.profitLossQty!=0?'bold':'' }">
+              {{ (record.profitLossQty || record.profitLossQty==0) ? record.profitLossQty : '--' }}
+            </span>
+          </template>
+          <!-- 盈亏金额 -->
+          <template slot="profitLossCost" slot-scope="text, record">
+            <span :style="{ color: record.profitLossCost>0?'red':record.profitLossCost<0?'green':'', fontWeight: record.profitLossCost!=0?'bold':'' }">
+              {{ (record.profitLossCost || record.profitLossCost==0) ? record.profitLossCost : '--' }}
+            </span>
+          </template>
+        </s-table>
+      </a-card>
+    </a-spin>
+  </div>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import { checkWarehouseDetail, checkWarehouseDetailFinanceList, checkWarehouseDetailCount } from '@/api/checkWarehouse'
+export default {
+  components: { STable, VSelect },
+  data () {
+    return {
+      spinning: false,
+      disabled: false,
+      queryParam: {
+        profitLossFlag: undefined,
+        productCode: ''
+      },
+      // 表头
+      columns: [
+        { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
+        { title: '产品名称', dataIndex: 'productName', width: '11%', align: 'left', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '单位', dataIndex: 'productUnit', width: '4%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '仓库', dataIndex: 'warehouseName', width: '10%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '仓位', dataIndex: 'warehouseLocationName', width: '10%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '入库时间', dataIndex: 'lastStockTime', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '批次', dataIndex: 'stockBatchNo', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品编码', dataIndex: 'productCode', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '库存数量', dataIndex: 'stockQty', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '盘点数量', dataIndex: 'checkQty', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '监盘数量', dataIndex: 'checkSuperviseQty', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '单价', dataIndex: 'checkCost', width: '5%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '盈亏数量', dataIndex: 'profitLossQty', scopedSlots: { customRender: 'profitLossQty' }, width: '6%', align: 'center' },
+        { title: '盈亏金额', dataIndex: 'profitLossCost', scopedSlots: { customRender: 'profitLossCost' }, width: '6%', align: 'center' }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        this.spinning = true
+        const params = Object.assign(parameter, this.queryParam, { checkWarehouseSn: this.$route.params.sn })
+        return checkWarehouseDetailFinanceList(params).then(res => {
+          this.getCount(params)
+          const data = res.data
+          const no = (data.pageNo - 1) * data.pageSize
+          for (var i = 0; i < data.list.length; i++) {
+            data.list[i].no = no + i + 1
+          }
+          this.disabled = false
+          this.spinning = false
+          return data
+        })
+      },
+      detail: null, //  详情数据
+      foldState: false, //  是否仅显示盈亏
+      productTotal: null //  合计
+    }
+  },
+  methods: {
+    //  返回列表
+    handleBack () {
+      this.$router.push({ path: '/financialManagement/inventoryConfirmation/list', query: { closeLastOldTab: true } })
+    },
+    // 重置
+    resetSearchForm () {
+      this.queryParam.productCode = ''
+      this.$refs.table.refresh(true)
+    },
+    getCount (params) {
+      checkWarehouseDetailCount(params).then(res => {
+        if (res.status == 200) {
+          this.productTotal = res.data
+        } else {
+          this.productTotal = null
+        }
+      })
+    },
+    //  详情
+    getDetail () {
+      checkWarehouseDetail({ sn: this.$route.params.sn }).then(res => {
+        if (res.status == 200) {
+          this.detail = res.data
+        } else {
+          this.detail = null
+        }
+      })
+    },
+    // 折叠列表
+    foldStateChange (e) {
+      if (e.target.checked) {
+        this.queryParam.profitLossFlag = 1
+        this.$refs.table.refresh(true)
+      } else {
+        this.queryParam.profitLossFlag = undefined
+        this.$refs.table.refresh(true)
+      }
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
+      this.$refs.table.refresh(true)
+      this.getDetail()
+    }
+  },
+  activated () {
+    // 如果是新页签打开或者进入新的子页(例:存在列表第2条数据编辑页页签时再打开第4条数据的编辑页),则重置当前页面
+    if (this.$store.state.app.isNewTab || !this.$store.state.app.isNewSubTab) {
+      this.$refs.table.refresh(true)
+      this.getDetail()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {})
+  }
+}
+</script>
+
+<style lang="less">
+  .inventoryConfirmationDetail-wrap{
+    .inventoryConfirmationDetail-cont{
+      margin-bottom: 10px;
+      .billno{
+        font-size: 16px;
+        font-weight: bold;
+        margin: 0 15px;
+      }
+      .state-c{
+        color: #ed1c24;
+        font-size: 13px;
+        font-weight: bold;
+      }
+    }
+  }
+</style>

+ 236 - 0
src/views/financialManagement/inventoryConfirmation/list.vue

@@ -0,0 +1,236 @@
+<template>
+  <a-card size="small" :bordered="false" class="inventoryConfirmationList-wrap">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <!-- 标签页 -->
+      <a-tabs type="card" :default-active-key="queryParam.state" @change="handleTabChange" class="inventoryConfirmationList-tabs ">
+        <a-tab-pane v-for="item in tabPaneData" :key="item.type">
+          <span slot="tab">{{ item.name }}</span>
+        </a-tab-pane>
+      </a-tabs>
+      <!-- 搜索条件 -->
+      <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="inventoryConfirmationList-checkWarehouseNo" v-model.trim="queryParam.checkWarehouseNo" allowClear placeholder="请输入盘点单号"/>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-button type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="inventoryConfirmationList-refresh">查询</a-button>
+              <a-button style="margin-left: 5px" @click="resetSearchForm" :disabled="disabled" id="inventoryConfirmationList-reset">重置</a-button>
+            </a-col>
+          </a-row>
+        </a-form>
+      </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="checkWarehouseNo" slot-scope="text, record">
+          <span :class="$hasPermissions('B_inventoryConfirmationDetail')?'active':'common'" @click="handleDetail(record)">{{ record.checkWarehouseNo }}</span>
+        </template>
+        <!-- 操作 -->
+        <template slot="action" slot-scope="text, record">
+          <a-button
+            size="small"
+            type="link"
+            class="button-info"
+            v-if="$hasPermissions('B_inventoryConfirmationConfirm')"
+            @click="handleConfirm(record)"
+            id="inventoryConfirmationList-audit-btn">盘点确认</a-button>
+          <a-button
+            size="small"
+            type="link"
+            class="button-success"
+            v-if="$hasPermissions('B_inventoryConfirmationCheck')"
+            @click="handleCheck(record)"
+            id="inventoryConfirmationList-audit-btn">重新盘点</a-button>
+          <span v-if="!($hasPermissions('B_inventoryConfirmationConfirm') && $hasPermissions('B_inventoryConfirmationCheck'))">--</span>
+        </template>
+      </s-table>
+    </a-spin>
+  </a-card>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import { checkWarehouseList, checkWarehouseReCheck, checkWarehouseFinanceAudit } from '@/api/checkWarehouse'
+export default {
+  components: { STable, VSelect },
+  data () {
+    return {
+      spinning: false,
+      tableHeight: 0,
+      queryParam: { //  查询条件
+        state: 'WAIT_FINANCE_AUDIT',
+        checkWarehouseNo: ''
+      },
+      disabled: false, //  查询、重置按钮是否可操作
+      tabPaneData: [
+        { name: '未完结', type: 'WAIT_FINANCE_AUDIT' },
+        { name: '已完结', type: 'FINISH' }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        this.spinning = true
+        return checkWarehouseList(Object.assign(parameter, this.queryParam)).then(res => {
+          const data = res.data
+          const no = (data.pageNo - 1) * data.pageSize
+          for (var i = 0; i < data.list.length; i++) {
+            data.list[i].no = no + i + 1
+          }
+          this.disabled = false
+          this.spinning = false
+          return data
+        })
+      }
+    }
+  },
+  computed: {
+    columns () {
+      let arr = []
+      if (this.queryParam.state == 'WAIT_FINANCE_AUDIT') { // 未完结
+        arr = [
+          { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
+          { title: '盘点单号', dataIndex: 'checkWarehouseNo', scopedSlots: { customRender: 'checkWarehouseNo' }, width: '15%', align: 'center' },
+          { title: '盘点状态', dataIndex: 'checkStateDictValue', width: '9%', align: 'center', customRender: function (text) { return text || '--' } },
+          { title: '监盘状态', dataIndex: 'checkSuperviseStateDictValue', width: '9%', align: 'center', customRender: function (text) { return text || '--' } },
+          { title: '盘点人', dataIndex: 'checkPersonName', align: 'center', width: '14%', customRender: function (text) { return text || '--' }, ellipsis: true },
+          { title: '盘点时间', dataIndex: 'checkTime', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+          { title: '监盘人', dataIndex: 'checkSupervisePersonName', align: 'center', width: '14%', customRender: function (text) { return text || '--' }, ellipsis: true },
+          { title: '监盘时间', dataIndex: 'checkSuperviseTime', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+          { title: '操作', scopedSlots: { customRender: 'action' }, width: '15%', align: 'center' }
+        ]
+      } else if (this.queryParam.state == 'FINISH') { // 已完结
+        arr = [
+          { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
+          { title: '盘点单号', dataIndex: 'checkWarehouseNo', scopedSlots: { customRender: 'checkWarehouseNo' }, width: '14%', align: 'center' },
+          { title: '盘点状态', dataIndex: 'checkStateDictValue', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+          { title: '监盘状态', dataIndex: 'checkSuperviseStateDictValue', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+          { title: '盘点人', dataIndex: 'checkPersonName', align: 'center', width: '16%', customRender: function (text) { return text || '--' }, ellipsis: true },
+          { title: '盘点时间', dataIndex: 'checkTime', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+          { title: '监盘人', dataIndex: 'checkSupervisePersonName', align: 'center', width: '16%', customRender: function (text) { return text || '--' }, ellipsis: true },
+          { title: '监盘时间', dataIndex: 'checkSuperviseTime', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+          { title: '财务确认时间', dataIndex: 'financeAuditTime', width: '10%', align: 'center', customRender: function (text) { return text || '--' } }
+        ]
+      }
+      return arr
+    }
+  },
+  methods: {
+    // 选择类型
+    handleTabChange (key) {
+      this.queryParam.state = key
+      this.$refs.table.refresh(true)
+    },
+    // 详情
+    handleDetail (row) {
+      if (this.$hasPermissions('B_inventoryConfirmationDetail')) {
+        this.$router.push({ path: `/financialManagement/inventoryConfirmation/detail/${row.checkWarehouseSn}` })
+      }
+    },
+    // 盘点确认
+    handleConfirm (row) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确认盘点结果正确无误吗?',
+        centered: true,
+        closable: true,
+        onOk () {
+          _this.spinning = true
+          checkWarehouseFinanceAudit({ checkWarehouseSn: row.checkWarehouseSn }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$refs.table.refresh(true)
+              _this.spinning = false
+            } else {
+              _this.spinning = false
+            }
+          })
+        }
+      })
+    },
+    // 重新盘点
+    handleCheck (row) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确认要重新盘点吗?',
+        centered: true,
+        closable: true,
+        onOk () {
+          _this.spinning = true
+          checkWarehouseReCheck({ checkWarehouseSn: row.checkWarehouseSn }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$refs.table.refresh(true)
+              _this.spinning = false
+            } else {
+              _this.spinning = false
+            }
+          })
+        }
+      })
+    },
+    resetSearchForm () {
+      this.queryParam.state = 'WAIT_FINANCE_AUDIT'
+      this.queryParam.checkWarehouseNo = ''
+      this.$refs.table.refresh(true)
+    },
+    pageInit () {
+      const _this = this
+      this.$nextTick(() => { // 页面渲染完成后的回调
+        _this.setTableH()
+      })
+    },
+    setTableH () {
+      this.tableHeight = window.innerHeight - 295
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
+      this.pageInit()
+      this.$refs.table.refresh(true)
+    }
+  },
+  activated () {
+    // 如果是新页签打开,则重置当前页面
+    if (this.$store.state.app.isNewTab) {
+      this.pageInit()
+      this.$refs.table.refresh(true)
+    }
+    // 仅刷新列表,不重置页面
+    if (this.$store.state.app.updateList) {
+      this.pageInit()
+      this.$refs.table.refresh()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {})
+  }
+}
+</script>
+
+<style lang="less">
+  .inventoryConfirmationList-wrap{
+    .active{
+      color: #ed1c24;
+      cursor: pointer;
+    }
+    .common{
+      color: rgba(0, 0, 0, 0.65);
+    }
+  }
+</style>

+ 91 - 0
src/views/inventoryManagement/inventoryCheck/addModal.vue

@@ -0,0 +1,91 @@
+<template>
+  <a-modal
+    centered
+    class="inventoryCheckAddModal-modal"
+    :footer="null"
+    :maskClosable="false"
+    :closable="false"
+    title="新增盘点单"
+    v-model="isShow"
+    @cancle="isShow=false"
+    :width="600">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <div>
+        <div class="inventoryCheckAddModal-con">
+          <h3>全盘盘点</h3>
+          <p>全盘是指所有有过入库记录的产品都参与盘点</p>
+          <p>确定创建新的盘点单吗?</p>
+        </div>
+        <div class="btn-cont">
+          <a-button type="primary" id="inventoryCheckAddModal-save" @click="handleSave">确定</a-button>
+          <a-button id="inventoryCheckAddModal-back" @click="isShow = false" style="margin-left: 15px;">取消</a-button>
+        </div>
+      </div>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+import { checkWarehouseSave } from '@/api/checkWarehouse'
+export default {
+  name: 'ProductInfoDetailModal',
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      spinning: false,
+      isShow: this.openModal //  是否打开弹框
+    }
+  },
+  methods: {
+    // 确定
+    handleSave () {
+      this.spinning = true
+      checkWarehouseSave({}).then(res => {
+        this.spinning = false
+        if (res.status == 200) {
+          this.$message.success('盘点单新增成功')
+          this.$emit('ok', res.data)
+          this.isShow = false
+        }
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .inventoryCheckAddModal-modal{
+    .ant-modal-body {
+      padding: 30px 40px 24px;
+    }
+    .inventoryCheckAddModal-con{
+      text-align: center;
+      h3{
+        font-size: 16px;
+        font-weight: bold;
+        margin-bottom: 25px;
+      }
+    }
+    .btn-cont {
+      text-align: center;
+      margin: 35px 0 10px;
+    }
+  }
+</style>

+ 313 - 0
src/views/inventoryManagement/inventoryCheck/detail.vue

@@ -0,0 +1,313 @@
+<template>
+  <div class="inventoryCheckDetail-wrap">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-page-header :ghost="false" :backIcon="false" @back="handleBack" class="inventoryCheckDetail-cont" >
+        <!-- 自定义的二级文字标题 -->
+        <template slot="subTitle">
+          <a id="inventoryCheckDetail-back-btn" href="javascript:;" @click="handleBack"><a-icon type="left" /> 返回列表</a>
+          <span class="billno">单号:{{ detail&&detail.checkWarehouseNo }}</span>
+          <span class="state-c" v-if="detail&&detail.state=='DELETE'">已作废</span>
+        </template>
+      </a-page-header>
+      <!-- 基础信息 -->
+      <a-card size="small" :bordered="false" class="inventoryCheckDetail-cont">
+        <a-collapse>
+          <a-collapse-panel key="1" header="基础信息">
+            <a-descriptions :column="3">
+              <a-descriptions-item label="创建人">{{ (detail&&detail.creatorName) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="创建时间">{{ (detail&&detail.createDate) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="盘点类型">{{ (detail&&detail.checkTypeDictValue) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="盘点状态">{{ (detail&&detail.checkStateDictValue) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="盘点人">{{ (detail&&detail.checkPersonName) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="盘点时间">{{ (detail&&detail.checkTime) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="监盘状态">{{ (detail&&detail.checkSuperviseStateDictValue) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="监盘人">{{ (detail&&detail.checkSupervisePersonName) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="监盘时间">{{ (detail&&detail.checkSuperviseTime) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="财务确认时间">{{ (detail&&detail.financeAuditTime) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="作废时间" v-if="detail&&detail.state=='DELETE'">{{ (detail&&detail.deleteTime) || '--' }}</a-descriptions-item>
+            </a-descriptions>
+          </a-collapse-panel>
+        </a-collapse>
+      </a-card>
+      <!-- 产品详情 -->
+      <a-card size="small" :bordered="false" class="inventoryCheckDetail-cont">
+        <!-- 总计 -->
+        <a-alert type="info" style="margin-bottom:10px">
+          <div slot="message">
+            库存数量:<strong>{{ productTotal && (productTotal.stockQty || productTotal.stockQty==0) ? productTotal.stockQty : '--' }}</strong>,
+            盘点数量:<strong>{{ productTotal && (productTotal.checkQty || productTotal.checkQty==0) ? productTotal.checkQty : '--' }}</strong>,
+            监盘数量:<strong>{{ productTotal && (productTotal.checkSuperviseQty || productTotal.checkSuperviseQty==0) ? productTotal.checkSuperviseQty : '--' }}</strong>
+          </div>
+        </a-alert>
+        <!-- 搜索条件 -->
+        <div class="table-page-search-wrapper">
+          <a-row :gutter="15">
+            <a-col :span="18">
+              <a-form-model :model="queryParam" layout="inline" @keyup.enter.native="getList(1)" >
+                <a-row :gutter="15">
+                  <a-col :md="8" :sm="24">
+                    <a-form-model-item label="产品编码">
+                      <a-input v-model="queryParam.productCode" allowClear placeholder="输入产品编码" />
+                    </a-form-model-item>
+                  </a-col>
+                  <a-col :md="8" :sm="24">
+                    <a-form-model-item style="margin-bottom: 10px;">
+                      <a-button type="primary" @click="getList(1)" :disabled="disabled" id="inventoryCheckDetail-refresh">查询</a-button>
+                      <a-button style="margin-left: 5px" @click="resetSearchForm" id="inventoryCheckDetail-reset">重置</a-button>
+                    </a-form-model-item>
+                  </a-col>
+                </a-row>
+              </a-form-model>
+            </a-col>
+            <a-col :span="6">
+              <div style="float:right;overflow: hidden;">
+                <a-checkbox v-model="foldState" @change="foldStateChange"><span style="display: inline-block;margin-top: 1px;">折叠列表</span></a-checkbox>
+              </div>
+            </a-col>
+          </a-row>
+        </div>
+        <!-- 列表 -->
+        <a-table
+          class="sTable"
+          ref="table"
+          size="small"
+          :rowKey="(record) => record.id + record.type"
+          :columns="columns"
+          :pagination="false"
+          :data-source="list"
+          :loading="loading"
+          @expand="handleExpand"
+          :expandedRowKeys="expandedRowKeys"
+          :expandRowByClick="true"
+          bordered>
+        </a-table>
+        <!-- 分页 -->
+        <tablePagination
+          ref="tablePagination"
+          :total="paginationProps.total"
+          :current="paginationProps.current"
+          :pageSize="paginationProps.pageSize"
+          @changePageSize="changePageSize"
+          @changePage="changePage" />
+      </a-card>
+    </a-spin>
+    <div class="affix-cont">
+      <a-button
+        type="primary"
+        id="inventoryCheckDetail-submit-btn"
+        v-if="detail&&(detail.state!='FINSH' && detail.state!='DELETE') && $hasPermissions('B_inventoryCheckVoid')"
+        size="large"
+        class="button-primary"
+        :disabled="spinning"
+        @click="handleSubmit"
+        style="padding: 0 60px;">作废盘点单</a-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import tablePagination from '@/views/common/tablePagination.vue'
+import { checkWarehouseDetail, checkWarehouseDetailList, checkWarehouseDetailCount, checkWarehouseDelete } from '@/api/checkWarehouse'
+export default {
+  components: { STable, VSelect, tablePagination },
+  data () {
+    return {
+      spinning: false,
+      disabled: false,
+      loading: false,
+      queryParam: {
+        productCode: ''
+      },
+      // 表头
+      columns: [
+        { title: '序号', dataIndex: 'no', width: '6%', align: 'center' },
+        { title: '产品名称', dataIndex: 'productName', width: '16%', align: 'left', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '单位', dataIndex: 'productUnit', width: '5%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '仓库', dataIndex: 'warehouseName', width: '12%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '仓位', dataIndex: 'warehouseLocationName', width: '11%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '入库时间', dataIndex: 'lastStockTime', width: '12%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '批次', dataIndex: 'stockBatchNo', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品编码', dataIndex: 'productCode', width: '14%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '库存数量', dataIndex: 'stockQty', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '盘点数量', dataIndex: 'checkQty', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '监盘数量', dataIndex: 'checkSuperviseQty', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } }
+      ],
+      list: [],
+      paginationProps: {
+        total: 0, //  分页总条数
+        current: 1,
+        pageSize: 20
+      },
+      expandedRowKeys: [],
+      detail: null, //  详情数据
+      foldState: false, //  是否折叠列表
+      productTotal: null //  合计
+    }
+  },
+  methods: {
+    //  返回列表
+    handleBack () {
+      this.$router.push({ path: '/inventoryManagement/inventoryCheck/list/0', query: { closeLastOldTab: true } })
+    },
+    // 重置
+    resetSearchForm () {
+      this.queryParam.productCode = ''
+      this.getList()
+    },
+    // 作废盘点单
+    handleSubmit () {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '作废后数据无法恢复,确认作废吗?',
+        centered: true,
+        closable: true,
+        onOk () {
+          _this.spinning = true
+          checkWarehouseDelete({ checkWarehouseSn: _this.$route.params.sn }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.spinning = false
+              _this.$router.push({ path: '/inventoryManagement/inventoryCheck/list/1', query: { closeLastOldTab: true } })
+            } else {
+              _this.spinning = false
+            }
+          })
+        }
+      })
+    },
+    // 获取列表数据
+    getList (pageNo) {
+      this.disabled = true
+      this.paginationProps.current = pageNo || this.paginationProps.current
+      const params = {
+        pageNo: this.paginationProps.current,
+        pageSize: this.paginationProps.pageSize,
+        checkWarehouseSn: this.$route.params.sn,
+        productCode: this.queryParam.productCode
+      }
+      this.loading = true
+      checkWarehouseDetailList(params).then(res => {
+        this.loading = false
+        if (res.status == 200) {
+          this.getCount(params)
+          const data = res.data
+          this.paginationProps.total = Number(res.data.count) || 0
+          this.paginationProps.current = data.pageNo
+          const no = (data.pageNo - 1) * data.pageSize
+          for (var i = 0; i < data.list.length; i++) {
+            data.list[i].no = no + i + 1
+            if (!this.foldState) {
+              this.expandedRowKeys.push(data.list[i].id + data.list[i].type)
+            }
+          }
+          this.list = data.list
+          this.disabled = false
+        } else {
+          this.paginationProps.total = 0
+          this.paginationProps.current = 1
+          this.paginationProps.pageSize = 20
+          this.list = []
+        }
+      })
+    },
+    getCount (params) {
+      checkWarehouseDetailCount(params).then(res => {
+        if (res.status == 200) {
+          this.productTotal = res.data
+        } else {
+          this.productTotal = null
+        }
+      })
+    },
+    //  分页  一页多少条change
+    changePageSize (current, pageSize) {
+      this.paginationProps.current = current
+      this.paginationProps.pageSize = pageSize
+      this.getList()
+    },
+    //  分页 页码change
+    changePage (current) {
+      this.paginationProps.current = current
+      this.getList()
+    },
+    //  详情
+    getDetail () {
+      checkWarehouseDetail({ sn: this.$route.params.sn }).then(res => {
+        if (res.status == 200) {
+          this.detail = res.data
+        } else {
+          this.detail = null
+        }
+      })
+    },
+    // 展开收起
+    handleExpand (expanded, record) {
+      if (record.type == 'superior') { // 只处理父级
+        if (expanded) {
+          this.expandedRowKeys.push(record.id + record.type)
+        } else {
+          if (this.expandedRowKeys.length > 0) {
+            const expandedRowKeys = this.expandedRowKeys.filter(RowKey => RowKey !== (record.id + record.type))
+            this.expandedRowKeys = expandedRowKeys
+          }
+        }
+      }
+    },
+    // 折叠列表
+    foldStateChange (e) {
+      if (e.target.checked) {
+        this.expandedRowKeys = []
+      } else {
+        this.expandedRowKeys = []
+        this.list.map(item => {
+          this.expandedRowKeys.push(item.id + item.type)
+        })
+      }
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
+      this.getList(1)
+      this.getDetail()
+    }
+  },
+  activated () {
+    // 如果是新页签打开或者进入新的子页(例:存在列表第2条数据编辑页页签时再打开第4条数据的编辑页),则重置当前页面
+    if (this.$store.state.app.isNewTab || !this.$store.state.app.isNewSubTab) {
+      this.getList(1)
+      this.getDetail()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {})
+  }
+}
+</script>
+
+<style lang="less">
+  .inventoryCheckDetail-wrap{
+    position: relative;
+    height: 100%;
+    padding-bottom: 51px;
+    box-sizing: border-box;
+    >.ant-spin-nested-loading{
+      overflow-y: scroll;
+      height: 100%;
+    }
+    .inventoryCheckDetail-cont{
+      margin-bottom: 10px;
+      .billno{
+        font-size: 16px;
+        font-weight: bold;
+        margin: 0 15px;
+      }
+      .state-c{
+        color: #ed1c24;
+        font-size: 13px;
+        font-weight: bold;
+      }
+    }
+  }
+</style>

+ 271 - 0
src/views/inventoryManagement/inventoryCheck/list.vue

@@ -0,0 +1,271 @@
+<template>
+  <a-card size="small" :bordered="false" class="inventoryCheckList-wrap">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <!-- 标签页 -->
+      <a-tabs type="card" :default-active-key="queryParam.deleteFlag" @change="handleTabChange" class="inventoryCheckList-tabs ">
+        <a-tab-pane v-for="item in tabPaneData" :key="item.type">
+          <span slot="tab">{{ item.name }}</span>
+        </a-tab-pane>
+      </a-tabs>
+      <!-- 搜索条件 -->
+      <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="inventoryCheckList-checkWarehouseNo" v-model.trim="queryParam.checkWarehouseNo" allowClear placeholder="请输入盘点单号"/>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="盘点状态">
+                <v-select
+                  v-model="queryParam.checkState"
+                  ref="checkState"
+                  id="inventoryCheckList-checkState"
+                  code="CHECK_WAREHOUSE_STATE"
+                  placeholder="请选择盘点状态"
+                  allowClear
+                ></v-select>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="监盘状态">
+                <v-select
+                  v-model="queryParam.checkSuperviseState"
+                  ref="checkSuperviseState"
+                  id="inventoryCheckList-checkSuperviseState"
+                  code="CHECK_WAREHOUSE_SUPERVISE_STATE"
+                  placeholder="请选择监盘状态"
+                  allowClear
+                ></v-select>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-button type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="inventoryCheckList-refresh">查询</a-button>
+              <a-button style="margin-left: 5px" @click="resetSearchForm" :disabled="disabled" id="inventoryCheckList-reset">重置</a-button>
+            </a-col>
+          </a-row>
+        </a-form>
+      </div>
+      <!-- 操作按钮 -->
+      <div class="table-operator">
+        <a-button v-if="$hasPermissions('B_inventoryCheckAdd')" id="inventoryCheckList-add" type="primary" class="button-error" @click="handleAdd">新增</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="action" slot-scope="text, record">
+          <a-button
+            size="small"
+            type="link"
+            v-if="$hasPermissions('B_inventoryCheckDetail')"
+            class="button-info"
+            @click="handleDetail(record)"
+            id="inventoryCheckList-audit-btn">详情</a-button>
+          <span v-else>--</span>
+        </template>
+      </s-table>
+    </a-spin>
+    <!-- 新增盘点单 -->
+    <inventory-check-add-modal :openModal="openAddModal" @ok="handleAddOk" @close="openAddModal=false" />
+    <!-- 盘点校验 -->
+    <common-modal
+      :openModal="openCommonModal"
+      :modalHtml="modalHtml"
+      okText="好的"
+      :isCancel="false"
+      @ok="openCommonModal=false"
+      @close="openCommonModal=false" />
+  </a-card>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import inventoryCheckAddModal from './addModal.vue'
+import commonModal from '@/views/common/commonModal.vue'
+import { checkWarehouseList, checkWarehouseStartCheck } from '@/api/checkWarehouse'
+export default {
+  components: { STable, VSelect, inventoryCheckAddModal, commonModal },
+  data () {
+    return {
+      spinning: false,
+      tableHeight: 0,
+      queryParam: { //  查询条件
+        deleteFlag: this.$route.params.type == '0' ? '' : '1',
+        checkWarehouseNo: '',
+        checkState: undefined,
+        checkSuperviseState: undefined
+      },
+      disabled: false, //  查询、重置按钮是否可操作
+      tabPaneData: [
+        { name: '正常', type: '' },
+        { name: '已作废', type: '1' }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        this.spinning = true
+        return checkWarehouseList(Object.assign(parameter, this.queryParam)).then(res => {
+          const data = res.data
+          const no = (data.pageNo - 1) * data.pageSize
+          for (var i = 0; i < data.list.length; i++) {
+            data.list[i].no = no + i + 1
+          }
+          this.disabled = false
+          this.spinning = false
+          return data
+        })
+      },
+      openModal: false,
+      itemSn: '',
+      openAddModal: false,
+      openCommonModal: false,
+      modalHtml: ''
+    }
+  },
+  computed: {
+    columns () {
+      let arr = []
+      if (this.queryParam.deleteFlag == '') { // 正常
+        arr = [
+          { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
+          { title: '盘点单号', dataIndex: 'checkWarehouseNo', width: '14%', align: 'center' },
+          { title: '盘点状态', dataIndex: 'checkStateDictValue', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
+          { title: '监盘状态', dataIndex: 'checkSuperviseStateDictValue', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
+          { title: '盘点人', dataIndex: 'checkPersonName', align: 'center', width: '12%', customRender: function (text) { return text || '--' }, ellipsis: true },
+          { title: '盘点提交时间', dataIndex: 'checkTime', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+          { title: '监盘人', dataIndex: 'checkSupervisePersonName', align: 'center', width: '12%', customRender: function (text) { return text || '--' }, ellipsis: true },
+          { title: '监盘提交时间', dataIndex: 'checkSuperviseTime', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+          { title: '财务确认时间', dataIndex: 'financeAuditTime', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+          { title: '盘点单创建时间', dataIndex: 'createDate', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+          { title: '操作', scopedSlots: { customRender: 'action' }, width: '6%', align: 'center' }
+        ]
+      } else if (this.queryParam.deleteFlag == '1') { // 已作废
+        arr = [
+          { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
+          { title: '盘点单号', dataIndex: 'checkWarehouseNo', width: '14%', align: 'center' },
+          { title: '盘点状态', dataIndex: 'checkStateDictValue', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
+          { title: '监盘状态', dataIndex: 'checkSuperviseStateDictValue', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
+          { title: '盘点人', dataIndex: 'checkPersonName', align: 'center', width: '12%', customRender: function (text) { return text || '--' }, ellipsis: true },
+          { title: '盘点提交时间', dataIndex: 'checkTime', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+          { title: '监盘人', dataIndex: 'checkSupervisePersonName', align: 'center', width: '12%', customRender: function (text) { return text || '--' }, ellipsis: true },
+          { title: '监盘提交时间', dataIndex: 'checkSuperviseTime', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+          { title: '盘点单创建时间', dataIndex: 'createDate', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+          { title: '盘点单作废时间', dataIndex: 'deleteTime', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+          { title: '操作', scopedSlots: { customRender: 'action' }, width: '6%', align: 'center' }
+        ]
+      }
+      return arr
+    }
+  },
+  methods: {
+    // 新增
+    handleAdd () {
+      this.spinning = true
+      checkWarehouseStartCheck({}).then(res => {
+        this.spinning = false
+        if (res.status == 200) {
+          if (res.data && res.data.length > 0) {
+            this.modalHtml = `<div style="width: 100%">
+              <h3 style="font-size: 15px;font-weight: bold;margin: 20px 0 5px;text-align: center;">存在以下状态的销售单,无法盘点。</h3>
+              <h3 style="font-size: 15px;font-weight: bold;margin-bottom: 25px;text-align: center;">请先检查并处理完以下单据再试。</h3>
+              ${res.data.indexOf('WAIT_AUDIT') != -1 ? '<p>销售单-待审核(总部自建)</p>' : ''}
+              ${res.data.indexOf('AUDIT_REJECT') != -1 ? '<p>销售单-审核不通过(总部自建)</p>' : ''}
+              ${res.data.indexOf('HQ_CHANGE') != -1 ? '<p>销售单-总公司改单</p>' : ''}
+              ${res.data.indexOf('WAIT_PUSH') != -1 ? '<p>销售单-待下推</p>' : ''}
+            </div>`
+            this.openCommonModal = true
+          } else {
+            this.openAddModal = true
+          }
+        }
+      })
+    },
+    // 新增 成功
+    handleAddOk (data) {
+      this.$router.push({ path: `/inventoryManagement/inventoryCheck/detail/${data.checkWarehouseSn}` })
+    },
+    // 选择类型
+    handleTabChange (key) {
+      this.queryParam.deleteFlag = key
+      this.$refs.table.refresh(true)
+    },
+    // 详情
+    handleDetail (row) {
+      if (this.$hasPermissions('B_inventoryCheckDetail')) {
+        this.$router.push({ path: `/inventoryManagement/inventoryCheck/detail/${row.checkWarehouseSn}` })
+      }
+    },
+    resetSearchForm () {
+      this.queryParam.deleteFlag = ''
+      this.queryParam.checkWarehouseNo = ''
+      this.queryParam.checkState = undefined
+      this.queryParam.checkSuperviseState = undefined
+      this.$refs.table.refresh(true)
+    },
+    closeModal () {
+      this.itemSn = ''
+      this.openModal = false
+    },
+    pageInit () {
+      const _this = this
+      this.$nextTick(() => { // 页面渲染完成后的回调
+        _this.setTableH()
+      })
+    },
+    setTableH () {
+      this.tableHeight = window.innerHeight - 338
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
+      this.pageInit()
+      this.$refs.table.refresh(true)
+    }
+  },
+  activated () {
+    // 如果是新页签打开,则重置当前页面
+    if (this.$store.state.app.isNewTab) {
+      this.pageInit()
+      this.$refs.table.refresh(true)
+    }
+    // 仅刷新列表,不重置页面
+    if (this.$store.state.app.updateList) {
+      this.pageInit()
+      this.$refs.table.refresh()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      const _this = vm
+      if (_this.$route.params.type == '1') {
+        setTimeout(() => {
+          _this.$refs.table.refresh(true)
+        }, 300)
+      }
+    })
+  }
+}
+</script>
+
+<style lang="less">
+  .inventoryCheckList-wrap{
+    .active{
+      color: #ed1c24;
+      cursor: pointer;
+    }
+    .common{
+      color: rgba(0, 0, 0, 0.65);
+    }
+  }
+</style>

+ 460 - 0
src/views/inventoryManagement/makeInventory/check.vue

@@ -0,0 +1,460 @@
+<template>
+  <div class="makeInventoryCheck-wrap">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-page-header :ghost="false" :backIcon="false" @back="handleBack" class="makeInventoryCheck-cont" >
+        <!-- 自定义的二级文字标题 -->
+        <template slot="subTitle">
+          <a id="makeInventoryCheck-back-btn" href="javascript:;" @click="handleBack"><a-icon type="left" /> 返回列表</a>
+          <span class="billno">单号:{{ detail&&detail.checkWarehouseNo }}</span>
+        </template>
+        <!-- 操作区,位于 title 行的行尾 -->
+        <template slot="extra">
+          <a-button
+            key="1"
+            type="primary"
+            class="button-info"
+            id="makeInventoryCheck-print-btn"
+            :disabled="list.length==0"
+            v-if="$hasPermissions('B_inventoryMakeInventoryPrint')"
+            @click="handlePdPrint">盘点打印</a-button>
+        </template></a-page-header>
+      <!-- 基础信息 -->
+      <a-card size="small" :bordered="false" class="makeInventoryCheck-cont">
+        <a-collapse>
+          <a-collapse-panel key="1" header="基础信息">
+            <a-descriptions :column="3">
+              <a-descriptions-item label="创建人">{{ (detail&&detail.creatorName) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="创建时间">{{ (detail&&detail.createDate) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="盘点类型">{{ (detail&&detail.checkTypeDictValue) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="盘点状态">{{ (detail&&detail.checkStateDictValue) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="盘点人">{{ (detail&&detail.checkPersonName) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="盘点时间">{{ (detail&&detail.checkTime) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="监盘状态">{{ (detail&&detail.checkSuperviseStateDictValue) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="监盘人">{{ (detail&&detail.checkSupervisePersonName) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="监盘时间">{{ (detail&&detail.checkSuperviseTime) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="财务确认时间">{{ (detail&&detail.financeAuditTime) || '--' }}</a-descriptions-item>
+            </a-descriptions>
+          </a-collapse-panel>
+        </a-collapse>
+      </a-card>
+      <!-- 产品详情 -->
+      <a-card size="small" :bordered="false" class="makeInventoryCheck-cont">
+        <!-- 总计 -->
+        <a-alert type="info" style="margin-bottom:10px">
+          <div slot="message">
+            <div style="display: flex;justify-content: space-between;align-items: center;">
+              <div>
+                库存数量:<strong>{{ productTotal && (productTotal.stockQty || productTotal.stockQty==0) ? productTotal.stockQty : '--' }}</strong>,
+                盘点数量:<strong>{{ productTotal && (productTotal.checkQty || productTotal.checkQty==0) ? productTotal.checkQty : '--' }}</strong>,
+                盘点盈亏数量:<strong>{{ productTotal && (productTotal.profitLossQty || productTotal.profitLossQty==0) ? productTotal.profitLossQty : '--' }}</strong>
+              </div>
+              <div>
+                <span style="color: red;display: inline-block;margin-right: 8px;">红色代表盘盈</span>
+                <span style="color: green;">绿色代表盘亏</span>
+              </div>
+            </div>
+          </div></a-alert>
+        <!-- 搜索条件 -->
+        <div class="table-page-search-wrapper">
+          <a-row :gutter="15">
+            <a-col :span="18">
+              <a-form-model :model="queryParam" layout="inline" @keyup.enter.native="getList(1)" >
+                <a-row :gutter="15">
+                  <a-col :md="8" :sm="24">
+                    <a-form-model-item label="产品编码">
+                      <a-input v-model="queryParam.productCode" allowClear placeholder="输入产品编码" />
+                    </a-form-model-item>
+                  </a-col>
+                  <a-col :md="8" :sm="24">
+                    <a-form-model-item style="margin-bottom: 10px;">
+                      <a-button type="primary" @click="getList(1)" :disabled="disabled" id="makeInventoryCheck-refresh">查询</a-button>
+                      <a-button style="margin-left: 5px" @click="resetSearchForm" id="makeInventoryCheck-reset">重置</a-button>
+                    </a-form-model-item>
+                  </a-col>
+                </a-row>
+              </a-form-model>
+            </a-col>
+            <a-col :span="6">
+              <div style="float:right;overflow: hidden;">
+                <a-checkbox v-model="foldState" @change="foldStateChange"><span style="display: inline-block;margin-top: 1px;">折叠列表</span></a-checkbox>
+              </div>
+            </a-col>
+          </a-row>
+        </div>
+        <!-- 列表 -->
+        <a-table
+          class="sTable"
+          ref="table"
+          size="small"
+          :rowKey="(record) => record.id + record.type"
+          :columns="columns"
+          :pagination="false"
+          :data-source="list"
+          :loading="loading"
+          @expand="handleExpand"
+          :expandedRowKeys="expandedRowKeys"
+          bordered>
+          <!-- 数量 -->
+          <template slot="checkQty" slot-scope="text, record">
+            <a-input-number
+              size="small"
+              id="makeInventoryCheck-checkQty"
+              v-model="record.checkQty"
+              :precision="0"
+              :min="0"
+              :max="999999"
+              placeholder="请输入"
+              v-if="record.type=='superior'"
+              @blur="e => checkQtyBlur(e.target.value, record)"
+              class="input-number"
+              style="width: 100%;text-align: center;" />
+            <span v-else>{{ record.checkQty }}</span>
+          </template>
+          <!-- 盈亏数量 -->
+          <template slot="profitLossQty" slot-scope="text, record">
+            <span v-if="record.type=='superior'" :style="{ color: record.profitLossQty>0?'red':record.profitLossQty<0?'green':'', fontWeight: record.profitLossQty!=0?'bold':'' }">
+              {{ record.profitLossQty>0?'盘盈':record.profitLossQty<0?'盘亏':'' }}
+              {{ (record.profitLossQty || record.profitLossQty==0) ? Math.abs(record.profitLossQty) : '--' }}
+            </span>
+            <span v-else></span>
+          </template>
+        </a-table>
+        <!-- 分页 -->
+        <tablePagination
+          ref="tablePagination"
+          :total="paginationProps.total"
+          :current="paginationProps.current"
+          :pageSize="paginationProps.pageSize"
+          @changePageSize="changePageSize"
+          @changePage="changePage" />
+      </a-card>
+    </a-spin>
+    <div class="affix-cont">
+      <a-button
+        type="primary"
+        id="makeInventoryCheck-submit-btn"
+        size="large"
+        class="button-primary"
+        :disabled="spinning"
+        @click="handleSubmit"
+        style="padding: 0 60px;">提交盘点</a-button>
+    </div>
+    <!-- 盘点打印确认 -->
+    <printModal
+      :openModal="visiblePrint"
+      :content="printContent"
+      :okText="printOkText"
+      cancelText="打印预览"
+      :isCancel="isPrintCancel"
+      :spinning="spinningPrint"
+      @close="visiblePrint=false"
+      @ok="printOkText == '好的' ? visiblePrint=false : handlePrint('print')"
+      @fail="handlePrint('preview')" />
+    <!-- 打印 -->
+    <div id="print"></div>
+  </div>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import tablePagination from '@/views/common/tablePagination.vue'
+import printModal from '@/views/common/auditModal.vue'
+import { checkWarehouseDetail, checkWarehouseDetailList, checkWarehouseDetailCount, checkWarehouseDetailPrint, checkWarehousePrintCheck, checkWarehouseDetailSave, checkWarehouseCheck } from '@/api/checkWarehouse'
+export default {
+  components: { STable, VSelect, tablePagination, printModal },
+  data () {
+    return {
+      spinning: false,
+      disabled: false,
+      loading: false,
+      queryParam: {
+        productCode: ''
+      },
+      // 表头
+      columns: [
+        { title: '序号', dataIndex: 'no', width: '6%', align: 'center' },
+        { title: '产品名称', dataIndex: 'productName', width: '16%', align: 'left', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '单位', dataIndex: 'productUnit', width: '5%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '仓库', dataIndex: 'warehouseName', width: '12%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '仓位', dataIndex: 'warehouseLocationName', width: '11%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '入库时间', dataIndex: 'lastStockTime', width: '12%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '批次', dataIndex: 'stockBatchNo', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品编码', dataIndex: 'productCode', width: '14%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '库存数量', dataIndex: 'stockQty', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '盘点数量', dataIndex: 'checkQty', scopedSlots: { customRender: 'checkQty' }, width: '6%', align: 'center' },
+        { title: '盈亏数量', dataIndex: 'profitLossQty', scopedSlots: { customRender: 'profitLossQty' }, width: '6%', align: 'center' }
+      ],
+      list: [],
+      paginationProps: {
+        total: 0, //  分页总条数
+        current: 1,
+        pageSize: 20
+      },
+      expandedRowKeys: [],
+      detail: null, //  详情数据
+      foldState: false, //  是否折叠列表
+      productTotal: null, //  合计
+      spinningPrint: false,
+      visiblePrint: false,
+      printContent: '',
+      printOkText: '',
+      isPrintCancel: false
+    }
+  },
+  methods: {
+    //  返回列表
+    handleBack () {
+      this.$router.push({ path: '/inventoryManagement/makeInventory/list', query: { closeLastOldTab: true, isRefresh: true } })
+    },
+    // 重置
+    resetSearchForm () {
+      this.queryParam.productCode = ''
+      this.getList()
+    },
+    // 盘点数量  blur
+    checkQtyBlur (val, record) {
+      //  光标移出,值发生改变再调用编辑接口
+      if (val != record.checkQtyBackups) {
+        this.handleEdit(record)
+      }
+    },
+    //  编辑
+    handleEdit (row) {
+      const params = {
+        checkWarehouseSn: this.$route.params.sn,
+        productSn: row.productSn,
+        reCheckQty: row.checkQty,
+        stockQty: row.stockQty
+      }
+      // 清空数量时,值应保持未清空前的值,因数量不可为空
+      if (!(row.checkQty || row.checkQty == 0)) {
+        row.checkQty = row.checkQtyBackups
+        return
+      }
+      this.spinning = true
+      checkWarehouseDetailSave(params).then(res => {
+        if (res.status == 200) {
+          this.$message.success(res.message)
+          this.getList()
+          this.spinning = false
+        } else {
+          this.spinning = false
+        }
+      })
+    },
+    // 提交盘点
+    handleSubmit () {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确认提交盘点吗?',
+        centered: true,
+        closable: true,
+        onOk () {
+          _this.spinning = true
+          checkWarehouseCheck({ checkWarehouseSn: _this.$route.params.sn }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.handleBack()
+              _this.spinning = false
+            } else {
+              _this.spinning = false
+            }
+          })
+        }
+      })
+    },
+    // 获取列表数据
+    getList (pageNo) {
+      this.disabled = true
+      this.paginationProps.current = pageNo || this.paginationProps.current
+      const params = {
+        pageNo: this.paginationProps.current,
+        pageSize: this.paginationProps.pageSize,
+        checkWarehouseSn: this.$route.params.sn,
+        productCode: this.queryParam.productCode
+      }
+      this.loading = true
+      checkWarehouseDetailList(params).then(res => {
+        this.loading = false
+        if (res.status == 200) {
+          this.getCount(params)
+          const data = res.data
+          this.paginationProps.total = Number(res.data.count) || 0
+          this.paginationProps.current = data.pageNo
+          const no = (data.pageNo - 1) * data.pageSize
+          for (var i = 0; i < data.list.length; i++) {
+            data.list[i].no = no + i + 1
+            data.list[i].checkQtyBackups = data.list[i].checkQty
+            if (!this.foldState) {
+              this.expandedRowKeys.push(data.list[i].id + data.list[i].type)
+            }
+          }
+          this.list = data.list
+          this.disabled = false
+        } else {
+          this.paginationProps.total = 0
+          this.paginationProps.current = 1
+          this.paginationProps.pageSize = 20
+          this.list = []
+        }
+      })
+    },
+    getCount (params) {
+      checkWarehouseDetailCount(params).then(res => {
+        if (res.status == 200) {
+          this.productTotal = res.data
+        } else {
+          this.productTotal = null
+        }
+      })
+    },
+    //  分页  一页多少条change
+    changePageSize (current, pageSize) {
+      this.paginationProps.current = current
+      this.paginationProps.pageSize = pageSize
+      this.getList()
+    },
+    //  分页 页码change
+    changePage (current) {
+      this.paginationProps.current = current
+      this.getList()
+    },
+    //  详情
+    getDetail () {
+      checkWarehouseDetail({ sn: this.$route.params.sn }).then(res => {
+        if (res.status == 200) {
+          this.detail = res.data
+        } else {
+          this.detail = null
+        }
+      })
+    },
+    // 展开收起
+    handleExpand (expanded, record) {
+      if (record.type == 'superior') { // 只处理父级
+        if (expanded) {
+          this.expandedRowKeys.push(record.id + record.type)
+        } else {
+          if (this.expandedRowKeys.length > 0) {
+            const expandedRowKeys = this.expandedRowKeys.filter(RowKey => RowKey !== (record.id + record.type))
+            this.expandedRowKeys = expandedRowKeys
+          }
+        }
+      }
+    },
+    // 折叠列表
+    foldStateChange (e) {
+      if (e.target.checked) {
+        this.expandedRowKeys = []
+      } else {
+        this.expandedRowKeys = []
+        this.list.map(item => {
+          this.expandedRowKeys.push(item.id + item.type)
+        })
+      }
+    },
+    // 盘点打印
+    handlePdPrint () {
+      this.spinning = true
+      checkWarehousePrintCheck({ checkWarehouseSn: this.$route.params.sn, type: 'CHECK_WAREHOUSE' }).then(res => {
+        this.spinning = false
+        if (res.status == 200) {
+          if (res.data && res.data == 0) { // 无产品
+            this.printContent = '此盘点单没有产品,无法打印'
+            this.printOkText = '好的'
+            this.isPrintCancel = false
+            this.visiblePrint = true
+          } else { // 有产品
+            this.printContent = '打印范围 —— 所有盘点产品(批次合并)'
+            this.printOkText = '立即打印'
+            this.isPrintCancel = true
+            this.visiblePrint = true
+          }
+        }
+      })
+    },
+    // 打印预览/快捷打印
+    handlePrint (type) {
+      const _this = this
+      _this.spinningPrint = true
+      checkWarehouseDetailPrint({ checkWarehouseSn: this.$route.params.sn, type: 'CHECK_WAREHOUSE' }).then(res => {
+        _this.spinningPrint = false
+        if (res.type == 'application/json') {
+          var reader = new FileReader()
+          reader.addEventListener('loadend', function () {
+            const obj = JSON.parse(reader.result)
+            _this.$notification.error({
+              message: '提示',
+              description: obj.message
+            })
+          })
+          reader.readAsText(res)
+        } else {
+          this.print(res, type)
+        }
+      })
+    },
+    print (data, type) {
+      if (!data) {
+        return
+      }
+      const url = window.URL.createObjectURL(new Blob([data], { type: 'application/pdf' }))
+      document.getElementById('print').innerHTML = '<iframe id="printfbod" name="printfbod" src="' + url + '" hidden></iframe>'
+      if (type == 'preview') { //  预览
+        window.open(url)
+      } else if (type == 'print') { //  打印
+        window.frames['printfbod'].focus()
+        window.frames['printfbod'].print()
+      }
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
+      this.getList(1)
+      this.getDetail()
+    }
+  },
+  activated () {
+    // 如果是新页签打开或者进入新的子页(例:存在列表第2条数据编辑页页签时再打开第4条数据的编辑页),则重置当前页面
+    if (this.$store.state.app.isNewTab || !this.$store.state.app.isNewSubTab) {
+      this.getList(1)
+      this.getDetail()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {})
+  }
+}
+</script>
+
+<style lang="less">
+  .makeInventoryCheck-wrap{
+    position: relative;
+    height: 100%;
+    padding-bottom: 51px;
+    box-sizing: border-box;
+    >.ant-spin-nested-loading{
+      overflow-y: scroll;
+      height: 100%;
+    }
+    .makeInventoryCheck-cont{
+      margin-bottom: 10px;
+      .billno{
+        font-size: 16px;
+        font-weight: bold;
+        margin: 0 15px;
+      }
+      .state-c{
+        color: #ed1c24;
+        font-size: 13px;
+        font-weight: bold;
+      }
+    }
+    .input-number{
+      .ant-input-number-input{
+        text-align: center;
+      }
+    }
+  }
+</style>

+ 149 - 0
src/views/inventoryManagement/makeInventory/list.vue

@@ -0,0 +1,149 @@
+<template>
+  <a-card size="small" :bordered="false" class="makeInventoryList-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="makeInventoryList-checkWarehouseNo" v-model.trim="queryParam.checkWarehouseNo" allowClear placeholder="请输入盘点单号"/>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-button type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="makeInventoryList-refresh">查询</a-button>
+              <a-button style="margin-left: 5px" @click="resetSearchForm" :disabled="disabled" id="makeInventoryList-reset">重置</a-button>
+            </a-col>
+          </a-row>
+        </a-form>
+      </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="action" slot-scope="text, record">
+          <a-button
+            size="small"
+            type="link"
+            v-if="$hasPermissions('B_inventoryMakeInventoryCheck')"
+            class="button-info"
+            @click="handleCheck(record)"
+            id="makeInventoryList-audit-btn">盘点</a-button>
+          <span v-else>--</span>
+        </template>
+      </s-table>
+    </a-spin>
+  </a-card>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import { checkWarehouseList } from '@/api/checkWarehouse'
+export default {
+  components: { STable, VSelect },
+  data () {
+    return {
+      spinning: false,
+      tableHeight: 0,
+      disabled: false, //  查询、重置按钮是否可操作
+      queryParam: { //  查询条件
+        checkWarehouseNo: ''
+      },
+      columns: [
+        { title: '序号', dataIndex: 'no', width: '6%', align: 'center' },
+        { title: '盘点单号', dataIndex: 'checkWarehouseNo', width: '18%', align: 'center' },
+        { title: '盘点状态', dataIndex: 'checkStateDictValue', width: '9%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品款数', dataIndex: 'productTotalCategory', width: '11%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '库存数量', dataIndex: 'totalStockQty', width: '11%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '盘点数量', dataIndex: 'checkTotalQty', width: '11%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '盘点盘亏数量', dataIndex: 'totalProfitLossQty', width: '11%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '盘点单创建时间', dataIndex: 'createDate', width: '13%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: '10%', align: 'center' }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        this.spinning = true
+        return checkWarehouseList(Object.assign(parameter, this.queryParam, { state: 'WAIT_CHECK' })).then(res => {
+          const data = res.data
+          const no = (data.pageNo - 1) * data.pageSize
+          for (var i = 0; i < data.list.length; i++) {
+            data.list[i].no = no + i + 1
+          }
+          this.disabled = false
+          this.spinning = false
+          return data
+        })
+      }
+    }
+  },
+  methods: {
+    // 盘点
+    handleCheck (row) {
+      this.$router.push({ path: `/inventoryManagement/makeInventory/check/${row.checkWarehouseSn}` })
+    },
+    resetSearchForm () {
+      this.queryParam.checkWarehouseNo = ''
+      this.$refs.table.refresh(true)
+    },
+    pageInit () {
+      const _this = this
+      this.$nextTick(() => { // 页面渲染完成后的回调
+        _this.setTableH()
+      })
+    },
+    setTableH () {
+      this.tableHeight = window.innerHeight - 240
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
+      this.pageInit()
+      this.$refs.table.refresh(true)
+    }
+  },
+  activated () {
+    // 如果是新页签打开,则重置当前页面
+    if (this.$store.state.app.isNewTab) {
+      this.pageInit()
+      this.$refs.table.refresh(true)
+    }
+    // 仅刷新列表,不重置页面
+    if (this.$store.state.app.updateList) {
+      this.pageInit()
+      this.$refs.table.refresh()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      const _this = vm
+      if (vm.$route.query.isRefresh) {
+        setTimeout(() => {
+          _this.$refs.table.refresh(true)
+        }, 300)
+      }
+    })
+  }
+}
+</script>
+
+<style lang="less">
+  .makeInventoryList-wrap{
+    .active{
+      color: #ed1c24;
+      cursor: pointer;
+    }
+    .common{
+      color: rgba(0, 0, 0, 0.65);
+    }
+  }
+</style>

+ 494 - 0
src/views/inventoryManagement/supervisionDisk/check.vue

@@ -0,0 +1,494 @@
+<template>
+  <div class="supervisionDiskCheck-wrap">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-page-header :ghost="false" :backIcon="false" @back="handleBack" class="supervisionDiskCheck-cont" >
+        <!-- 自定义的二级文字标题 -->
+        <template slot="subTitle">
+          <a id="supervisionDiskCheck-back-btn" href="javascript:;" @click="handleBack"><a-icon type="left" /> 返回列表</a>
+          <span class="billno">单号:{{ detail&&detail.checkWarehouseNo }}</span>
+        </template>
+        <!-- 操作区,位于 title 行的行尾 -->
+        <template slot="extra">
+          <a-button
+            key="1"
+            type="primary"
+            class="button-info"
+            id="supervisionDiskCheck-print-btn"
+            :disabled="list.length==0"
+            v-if="$hasPermissions('B_supervisionDiskPrint')"
+            @click="handlePdPrint">监盘打印</a-button>
+        </template></a-page-header>
+      <!-- 基础信息 -->
+      <a-card size="small" :bordered="false" class="supervisionDiskCheck-cont">
+        <a-collapse>
+          <a-collapse-panel key="1" header="基础信息">
+            <a-descriptions :column="3">
+              <a-descriptions-item label="创建人">{{ (detail&&detail.creatorName) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="创建时间">{{ (detail&&detail.createDate) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="盘点类型">{{ (detail&&detail.checkTypeDictValue) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="盘点状态">{{ (detail&&detail.checkStateDictValue) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="盘点人">{{ (detail&&detail.checkPersonName) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="盘点时间">{{ (detail&&detail.checkTime) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="监盘状态">{{ (detail&&detail.checkSuperviseStateDictValue) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="监盘人">{{ (detail&&detail.checkSupervisePersonName) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="监盘时间">{{ (detail&&detail.checkSuperviseTime) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="财务确认时间">{{ (detail&&detail.financeAuditTime) || '--' }}</a-descriptions-item>
+            </a-descriptions>
+          </a-collapse-panel>
+        </a-collapse>
+      </a-card>
+      <!-- 产品详情 -->
+      <a-card size="small" :bordered="false" class="supervisionDiskCheck-cont">
+        <!-- 总计 -->
+        <a-alert type="info" style="margin-bottom:10px">
+          <div slot="message">
+            <div style="display: flex;justify-content: space-between;align-items: center;">
+              <div>
+                库存数量:<strong>{{ productTotal && (productTotal.stockQty || productTotal.stockQty==0) ? productTotal.stockQty : '--' }}</strong>,
+                盘点数量:<strong>{{ productTotal && (productTotal.checkQty || productTotal.checkQty==0) ? productTotal.checkQty : '--' }}</strong>,
+                监盘数量:<strong>{{ productTotal && (productTotal.checkSuperviseQty || productTotal.checkSuperviseQty==0) ? productTotal.checkSuperviseQty : '--' }}</strong>,
+                监盘盈亏数量:<strong :style="{ color: productTotal && productTotal.profitLossQty>0?'red':productTotal && productTotal.profitLossQty<0?'green':'' }">{{ productTotal && (productTotal.profitLossQty || productTotal.profitLossQty==0) ? productTotal.profitLossQty : '--' }}</strong>
+              </div>
+              <div>
+                <span style="color: red;display: inline-block;margin-right: 8px;">红色代表盘盈</span>
+                <span style="color: green;">绿色代表盘亏</span>
+              </div>
+            </div>
+          </div></a-alert>
+        <!-- 搜索条件 -->
+        <div class="table-page-search-wrapper">
+          <a-row :gutter="15">
+            <a-col :span="18">
+              <a-form-model :model="queryParam" layout="inline" @keyup.enter.native="getList(1)" >
+                <a-row :gutter="15">
+                  <a-col :md="8" :sm="24">
+                    <a-form-model-item label="产品编码">
+                      <a-input v-model="queryParam.productCode" allowClear placeholder="输入产品编码" />
+                    </a-form-model-item>
+                  </a-col>
+                  <a-col :md="8" :sm="24">
+                    <a-form-model-item style="margin-bottom: 10px;">
+                      <a-button type="primary" @click="getList(1)" :disabled="disabled" id="supervisionDiskCheck-refresh">查询</a-button>
+                      <a-button style="margin-left: 5px" @click="resetSearchForm" id="supervisionDiskCheck-reset">重置</a-button>
+                    </a-form-model-item>
+                  </a-col>
+                </a-row>
+              </a-form-model>
+            </a-col>
+            <a-col :span="6">
+              <div style="float:right;overflow: hidden;">
+                <a-checkbox v-model="foldState" @change="foldStateChange"><span style="display: inline-block;margin-top: 1px;">折叠列表</span></a-checkbox>
+              </div>
+            </a-col>
+          </a-row>
+        </div>
+        <!-- 列表 -->
+        <a-table
+          class="sTable"
+          ref="table"
+          size="small"
+          :rowKey="(record) => record.id + record.type"
+          :columns="columns"
+          :pagination="false"
+          :data-source="list"
+          :loading="loading"
+          @expand="handleExpand"
+          :expandedRowKeys="expandedRowKeys"
+          bordered>
+          <!-- 数量 -->
+          <template slot="checkSuperviseQty" slot-scope="text, record">
+            <a-input-number
+              size="small"
+              id="supervisionDiskCheck-checkSuperviseQty"
+              v-model="record.checkSuperviseQty"
+              :precision="0"
+              :min="0"
+              :max="999999"
+              placeholder="请输入"
+              v-if="record.type=='superior'"
+              @blur="e => checkSuperviseQtyBlur(e.target.value, record)"
+              class="input-number"
+              style="width: 100%;text-align: center;" />
+            <span v-else>{{ record.checkSuperviseQty }}</span>
+          </template>
+          <!-- 盈亏数量 -->
+          <template slot="profitLossQty" slot-scope="text, record">
+            <span v-if="record.type=='superior'" :style="{ color: record.profitLossQty>0?'red':record.profitLossQty<0?'green':'', fontWeight: record.profitLossQty!=0?'bold':'' }">
+              {{ record.profitLossQty>0?'盘盈':record.profitLossQty<0?'盘亏':'' }}
+              {{ (record.profitLossQty || record.profitLossQty==0) ? Math.abs(record.profitLossQty) : '--' }}
+            </span>
+            <span v-else></span>
+          </template>
+        </a-table>
+        <!-- 分页 -->
+        <tablePagination
+          ref="tablePagination"
+          :total="paginationProps.total"
+          :current="paginationProps.current"
+          :pageSize="paginationProps.pageSize"
+          @changePageSize="changePageSize"
+          @changePage="changePage" />
+      </a-card>
+    </a-spin>
+    <div class="affix-cont">
+      <a-button
+        type="primary"
+        id="supervisionDiskCheck-check-btn"
+        size="large"
+        class="button-primary"
+        :disabled="spinning"
+        @click="handleCheck"
+        style="padding: 0 50px;">重新盘点</a-button>
+      <a-button
+        type="primary"
+        id="supervisionDiskCheck-submit-btn"
+        size="large"
+        class="button-primary"
+        :disabled="spinning"
+        @click="handleSubmit"
+        style="padding: 0 60px;margin-left: 15px">提交监盘</a-button>
+    </div>
+    <!-- 盘点打印确认 -->
+    <printModal
+      :openModal="visiblePrint"
+      :content="printContent"
+      :okText="printOkText"
+      cancelText="打印预览"
+      :isCancel="isPrintCancel"
+      :spinning="spinningPrint"
+      @close="visiblePrint=false"
+      @ok="printOkText == '好的' ? visiblePrint=false : handlePrint('print')"
+      @fail="handlePrint('preview')" />
+    <!-- 打印 -->
+    <div id="print"></div>
+  </div>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import tablePagination from '@/views/common/tablePagination.vue'
+import printModal from '@/views/common/auditModal.vue'
+import { checkWarehouseDetail, checkWarehouseDetailList, checkWarehouseDetailCount, checkWarehouseDetailPrint, checkWarehousePrintCheck, checkWarehouseDetailSave, checkWarehouseSupervise, checkWarehouseReCheck } from '@/api/checkWarehouse'
+export default {
+  components: { STable, VSelect, tablePagination, printModal },
+  data () {
+    return {
+      spinning: false,
+      disabled: false,
+      loading: false,
+      queryParam: {
+        productCode: ''
+      },
+      // 表头
+      columns: [
+        { title: '序号', dataIndex: 'no', width: '6%', align: 'center' },
+        { title: '产品名称', dataIndex: 'productName', width: '16%', align: 'left', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '单位', dataIndex: 'productUnit', width: '5%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '仓库', dataIndex: 'warehouseName', width: '12%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '仓位', dataIndex: 'warehouseLocationName', width: '11%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '入库时间', dataIndex: 'lastStockTime', width: '12%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '批次', dataIndex: 'stockBatchNo', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品编码', dataIndex: 'productCode', width: '14%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '库存数量', dataIndex: 'stockQty', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '盘点数量', dataIndex: 'checkQty', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '监盘数量', dataIndex: 'checkSuperviseQty', width: '8%', scopedSlots: { customRender: 'checkSuperviseQty' }, align: 'center' },
+        { title: '盈亏数量', dataIndex: 'profitLossQty', scopedSlots: { customRender: 'profitLossQty' }, width: '6%', align: 'center' }
+      ],
+      list: [],
+      paginationProps: {
+        total: 0, //  分页总条数
+        current: 1,
+        pageSize: 20
+      },
+      expandedRowKeys: [],
+      detail: null, //  详情数据
+      foldState: false, //  是否折叠列表
+      productTotal: null, //  合计
+      spinningPrint: false,
+      visiblePrint: false,
+      printContent: '',
+      printOkText: '',
+      isPrintCancel: false
+    }
+  },
+  methods: {
+    //  返回列表
+    handleBack () {
+      this.$router.push({ path: '/inventoryManagement/supervisionDisk/list', query: { closeLastOldTab: true, isRefresh: true } })
+    },
+    // 重置
+    resetSearchForm () {
+      this.queryParam.productCode = ''
+      this.getList()
+    },
+    // 盘点数量  blur
+    checkSuperviseQtyBlur (val, record) {
+      //  光标移出,值发生改变再调用编辑接口
+      if (val != record.checkSuperviseQtyBackups) {
+        this.handleEdit(record)
+      }
+    },
+    //  编辑
+    handleEdit (row) {
+      const params = {
+        checkWarehouseSn: this.$route.params.sn,
+        productSn: row.productSn,
+        reCheckSuperviseQty: row.checkSuperviseQty,
+        stockQty: row.stockQty
+      }
+      // 清空数量时,值应保持未清空前的值,因数量不可为空
+      if (!(row.checkSuperviseQty || row.checkSuperviseQty == 0)) {
+        row.checkSuperviseQty = row.checkSuperviseQtyBackups
+        return
+      }
+      this.spinning = true
+      checkWarehouseDetailSave(params).then(res => {
+        if (res.status == 200) {
+          this.$message.success(res.message)
+          this.getList()
+          this.spinning = false
+        } else {
+          this.spinning = false
+        }
+      })
+    },
+    // 提交监盘
+    handleSubmit () {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确认提交盘点吗?',
+        centered: true,
+        closable: true,
+        onOk () {
+          _this.spinning = true
+          checkWarehouseSupervise({ checkWarehouseSn: _this.$route.params.sn }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.handleBack()
+              _this.spinning = false
+            } else {
+              _this.spinning = false
+            }
+          })
+        }
+      })
+    },
+    // 重新盘点
+    handleCheck () {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确认要重新盘点吗?',
+        centered: true,
+        closable: true,
+        onOk () {
+          _this.spinning = true
+          checkWarehouseReCheck({ checkWarehouseSn: _this.$route.params.sn }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.handleBack()
+              _this.spinning = false
+            } else {
+              _this.spinning = false
+            }
+          })
+        }
+      })
+    },
+    // 获取列表数据
+    getList (pageNo) {
+      this.disabled = true
+      this.paginationProps.current = pageNo || this.paginationProps.current
+      const params = {
+        pageNo: this.paginationProps.current,
+        pageSize: this.paginationProps.pageSize,
+        checkWarehouseSn: this.$route.params.sn,
+        productCode: this.queryParam.productCode
+      }
+      this.loading = true
+      checkWarehouseDetailList(params).then(res => {
+        this.loading = false
+        if (res.status == 200) {
+          this.getCount(params)
+          const data = res.data
+          this.paginationProps.total = Number(res.data.count) || 0
+          this.paginationProps.current = data.pageNo
+          const no = (data.pageNo - 1) * data.pageSize
+          for (var i = 0; i < data.list.length; i++) {
+            data.list[i].no = no + i + 1
+            data.list[i].checkSuperviseQtyBackups = data.list[i].checkSuperviseQty
+            if (!this.foldState) {
+              this.expandedRowKeys.push(data.list[i].id + data.list[i].type)
+            }
+          }
+          this.list = data.list
+          this.disabled = false
+        } else {
+          this.paginationProps.total = 0
+          this.paginationProps.current = 1
+          this.paginationProps.pageSize = 20
+          this.list = []
+        }
+      })
+    },
+    getCount (params) {
+      checkWarehouseDetailCount(params).then(res => {
+        if (res.status == 200) {
+          this.productTotal = res.data
+        } else {
+          this.productTotal = null
+        }
+      })
+    },
+    //  分页  一页多少条change
+    changePageSize (current, pageSize) {
+      this.paginationProps.current = current
+      this.paginationProps.pageSize = pageSize
+      this.getList()
+    },
+    //  分页 页码change
+    changePage (current) {
+      this.paginationProps.current = current
+      this.getList()
+    },
+    //  详情
+    getDetail () {
+      checkWarehouseDetail({ sn: this.$route.params.sn }).then(res => {
+        if (res.status == 200) {
+          this.detail = res.data
+        } else {
+          this.detail = null
+        }
+      })
+    },
+    // 展开收起
+    handleExpand (expanded, record) {
+      if (record.type == 'superior') { // 只处理父级
+        if (expanded) {
+          this.expandedRowKeys.push(record.id + record.type)
+        } else {
+          if (this.expandedRowKeys.length > 0) {
+            const expandedRowKeys = this.expandedRowKeys.filter(RowKey => RowKey !== (record.id + record.type))
+            this.expandedRowKeys = expandedRowKeys
+          }
+        }
+      }
+    },
+    // 折叠列表
+    foldStateChange (e) {
+      if (e.target.checked) {
+        this.expandedRowKeys = []
+      } else {
+        this.expandedRowKeys = []
+        this.list.map(item => {
+          this.expandedRowKeys.push(item.id + item.type)
+        })
+      }
+    },
+    // 盘点打印
+    handlePdPrint () {
+      this.spinning = true
+      checkWarehousePrintCheck({ checkWarehouseSn: this.$route.params.sn, type: 'CHECK_WAREHOUSE_SUPERVISE' }).then(res => {
+        this.spinning = false
+        if (res.status == 200) {
+          if (res.data && res.data == 0) { // 无产品
+            this.printContent = '打印模板内容是所有有盈亏的产品,此单盘点人盘点无盈亏记录,无法打印'
+            this.printOkText = '好的'
+            this.isPrintCancel = false
+            this.visiblePrint = true
+          } else { // 有产品
+            this.printContent = '打印范围 —— 有盈亏(批次合并)'
+            this.printOkText = '立即打印'
+            this.isPrintCancel = true
+            this.visiblePrint = true
+          }
+        }
+      })
+    },
+    // 打印预览/快捷打印
+    handlePrint (type) {
+      const _this = this
+      _this.spinningPrint = true
+      checkWarehouseDetailPrint({ checkWarehouseSn: this.$route.params.sn, type: 'CHECK_WAREHOUSE_SUPERVISE' }).then(res => {
+        _this.spinningPrint = false
+        if (res.type == 'application/json') {
+          var reader = new FileReader()
+          reader.addEventListener('loadend', function () {
+            const obj = JSON.parse(reader.result)
+            _this.$notification.error({
+              message: '提示',
+              description: obj.message
+            })
+          })
+          reader.readAsText(res)
+        } else {
+          this.print(res, type)
+        }
+      })
+    },
+    print (data, type) {
+      if (!data) {
+        return
+      }
+      const url = window.URL.createObjectURL(new Blob([data], { type: 'application/pdf' }))
+      document.getElementById('print').innerHTML = '<iframe id="printfbod" name="printfbod" src="' + url + '" hidden></iframe>'
+      if (type == 'preview') { //  预览
+        window.open(url)
+      } else if (type == 'print') { //  打印
+        window.frames['printfbod'].focus()
+        window.frames['printfbod'].print()
+      }
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
+      console.log(111)
+      this.resetSearchForm()
+      this.getDetail()
+    }
+  },
+  activated () {
+    // 如果是新页签打开或者进入新的子页(例:存在列表第2条数据编辑页页签时再打开第4条数据的编辑页),则重置当前页面
+    if (this.$store.state.app.isNewTab || !this.$store.state.app.isNewSubTab) {
+      console.log(222)
+      this.resetSearchForm()
+      this.getDetail()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {})
+  }
+}
+</script>
+
+<style lang="less">
+  .supervisionDiskCheck-wrap{
+    position: relative;
+    height: 100%;
+    padding-bottom: 51px;
+    box-sizing: border-box;
+    >.ant-spin-nested-loading{
+      overflow-y: scroll;
+      height: 100%;
+    }
+    .supervisionDiskCheck-cont{
+      margin-bottom: 10px;
+      .billno{
+        font-size: 16px;
+        font-weight: bold;
+        margin: 0 15px;
+      }
+      .state-c{
+        color: #ed1c24;
+        font-size: 13px;
+        font-weight: bold;
+      }
+    }
+    .input-number{
+      .ant-input-number-input{
+        text-align: center;
+      }
+    }
+  }
+</style>

+ 152 - 0
src/views/inventoryManagement/supervisionDisk/list.vue

@@ -0,0 +1,152 @@
+<template>
+  <a-card size="small" :bordered="false" class="supervisionDiskList-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="supervisionDiskList-checkWarehouseNo" v-model.trim="queryParam.checkWarehouseNo" allowClear placeholder="请输入盘点单号"/>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-button type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="supervisionDiskList-refresh">查询</a-button>
+              <a-button style="margin-left: 5px" @click="resetSearchForm" :disabled="disabled" id="supervisionDiskList-reset">重置</a-button>
+            </a-col>
+          </a-row>
+        </a-form>
+      </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="action" slot-scope="text, record">
+          <a-button
+            size="small"
+            type="link"
+            v-if="$hasPermissions('B_supervisionDiskCheck')"
+            class="button-info"
+            @click="handleCheck(record)"
+            id="supervisionDiskList-audit-btn">监盘</a-button>
+          <span v-else>--</span>
+        </template>
+      </s-table>
+    </a-spin>
+  </a-card>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import { checkWarehouseList } from '@/api/checkWarehouse'
+export default {
+  components: { STable, VSelect },
+  data () {
+    return {
+      spinning: false,
+      tableHeight: 0,
+      disabled: false, //  查询、重置按钮是否可操作
+      queryParam: { //  查询条件
+        checkWarehouseNo: ''
+      },
+      columns: [
+        { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
+        { title: '盘点单号', dataIndex: 'checkWarehouseNo', width: '15%', align: 'center' },
+        { title: '盘点状态', dataIndex: 'checkStateDictValue', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '盘点人', dataIndex: 'checkPersonName', align: 'center', width: '12%', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '盘点时间', dataIndex: 'checkTime', width: '11%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '监盘状态', dataIndex: 'checkSuperviseStateDictValue', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品款数', dataIndex: 'productTotalCategory', width: '8%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '库存数量', dataIndex: 'totalStockQty', width: '8%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '盘点数量', dataIndex: 'checkTotalQty', width: '8%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '监盘数量', dataIndex: 'checkSuperviseTotalQty', width: '8%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '监盘盈亏数量', dataIndex: 'totalProfitLossQty', width: '8%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: '6%', align: 'center' }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        this.spinning = true
+        return checkWarehouseList(Object.assign(parameter, this.queryParam, { state: 'WAIT_SUPERVISE_CHECK' })).then(res => {
+          const data = res.data
+          const no = (data.pageNo - 1) * data.pageSize
+          for (var i = 0; i < data.list.length; i++) {
+            data.list[i].no = no + i + 1
+          }
+          this.disabled = false
+          this.spinning = false
+          return data
+        })
+      }
+    }
+  },
+  methods: {
+    // 监盘
+    handleCheck (row) {
+      this.$router.push({ path: `/inventoryManagement/supervisionDisk/check/${row.checkWarehouseSn}` })
+    },
+    resetSearchForm () {
+      this.queryParam.checkWarehouseNo = ''
+      this.$refs.table.refresh(true)
+    },
+    pageInit () {
+      const _this = this
+      this.$nextTick(() => { // 页面渲染完成后的回调
+        _this.setTableH()
+      })
+    },
+    setTableH () {
+      this.tableHeight = window.innerHeight - 240
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
+      this.pageInit()
+      this.$refs.table.refresh(true)
+    }
+  },
+  activated () {
+    // 如果是新页签打开,则重置当前页面
+    if (this.$store.state.app.isNewTab) {
+      this.pageInit()
+      this.$refs.table.refresh(true)
+    }
+    // 仅刷新列表,不重置页面
+    if (this.$store.state.app.updateList) {
+      this.pageInit()
+      this.$refs.table.refresh()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      const _this = vm
+      if (vm.$route.query.isRefresh) {
+        setTimeout(() => {
+          _this.$refs.table.refresh(true)
+        }, 300)
+      }
+    })
+  }
+}
+</script>
+
+<style lang="less">
+  .supervisionDiskList-wrap{
+    .active{
+      color: #ed1c24;
+      cursor: pointer;
+    }
+    .common{
+      color: rgba(0, 0, 0, 0.65);
+    }
+  }
+</style>

+ 21 - 3
src/views/supplierManagement/associatedProduct/add.vue

@@ -50,6 +50,12 @@
         <!-- 操作按钮 -->
         <div class="table-operator">
           <a-button id="associatedProduct-addProduct-btn" type="primary" class="button-error" @click="choosePModal">增加产品</a-button>
+          <a-button
+            id="associatedProduct-addProduct-import-btn"
+            type="primary"
+            class="button-info"
+            @click="openGuideModal=
+              true">导入产品</a-button>
         <!-- <a-button id="associatedProduct-import-btn" type="primary" class="button-success">批量导入</a-button> -->
         </div>
         <!-- 列表 -->
@@ -91,18 +97,21 @@
     <SettingCost ref="settingCost" :openModal="openModal" @ok="$refs.table.refresh()" @close="openModal=false"></SettingCost>
     <!-- 选择产品 -->
     <chooseProductsModal type="supplier" :openModal="newProduct" :chooseData="chooseProducts" @close="newProduct=false" @ok="handleProductsOk" />
+    <!-- 导入产品 -->
+    <importGuideModal :openModal="openGuideModal" :params="{supplierSn: $route.params.sn}" @close="openGuideModal=false" @ok="handleGuideOk" />
   </div>
 </template>
 
 <script>
 import { STable, VSelect } from '@/components'
-import { supplierProductList, deleteProduct, addProduct, supplierProductSnList } from '@/api/supplier'
+import { supplierProductList, deleteProduct, addProduct, supplierProductSnList, supplierProductBatchInsert } from '@/api/supplier'
 import ProductType from '@/views/common/productType.js'
 import ProductBrand from '@/views/common/productBrand.js'
 import SettingCost from './settingCost.vue'
+import ImportGuideModal from './importGuideModal.vue'
 import ChooseProductsModal from '@/views/common/chooseProductsModal.vue'
 export default {
-  components: { STable, VSelect, ProductBrand, ProductType, SettingCost, ChooseProductsModal },
+  components: { STable, VSelect, ProductBrand, ProductType, SettingCost, ChooseProductsModal, ImportGuideModal },
   data () {
     return {
       spinning: false,
@@ -148,7 +157,8 @@ export default {
           return data
         })
       },
-      chooseProducts: [] //  所选产品
+      chooseProducts: [], //  所选产品
+      openGuideModal: false //  导入产品引导
     }
   },
   methods: {
@@ -238,6 +248,14 @@ export default {
         }
       })
     },
+    // 导入产品
+    handleGuideOk (obj) {
+      supplierProductBatchInsert(obj).then(res => {
+        if (res.status == 200) {
+          this.$refs.table.refresh(true)
+        }
+      })
+    },
     pageInit () {
       const _this = this
       this.$nextTick(() => { // 页面渲染完成后的回调

+ 186 - 0
src/views/supplierManagement/associatedProduct/chooseImportModal.vue

@@ -0,0 +1,186 @@
+<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.supplierSn"
+        :columns="nowColumns"
+        :dataSource="loadData"
+        :loading="loading"
+        :scroll="{ y: 200 }"
+        :pagination="false"
+        bordered>
+      </a-table>
+      <a-divider />
+      <!-- 不可导入数据 -->
+      <p class="red">不可导入数据{{ unLoadData.length }}条</p>
+      <a-table
+        class="unTable"
+        ref="unTable"
+        size="small"
+        :rowKey="(record) => record.errorDesc"
+        :columns="nowUnColumns"
+        :dataSource="unLoadData"
+        :loading="loading"
+        :scroll="{ y: 200 }"
+        :pagination="false"
+        bordered>
+      </a-table>
+      <!-- 按钮 -->
+      <div class="btn-con">
+        <a-button
+          type="primary"
+          id="chooseImport-submit"
+          size="large"
+          :class="loadData.length==0?'button-grey':'button-primary'"
+          @click="handleSubmit"
+          style="padding: 0 40px;">确认导入</a-button>
+        <a-button
+          id="chooseImport-cancel"
+          size="large"
+          class="button-cancel"
+          @click="isShow=false"
+          style="padding: 0 40px;margin-left: 15px;">取消</a-button>
+        <a-button
+          type="primary"
+          id="chooseImport-error"
+          size="large"
+          class="button-error"
+          @click="handleError"
+          style="padding: 0 40px;margin-left: 15px;">导出错误项</a-button>
+      </div>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { hdExportExcel } from '@/libs/exportExcel'
+import { supplierProductParseProducts, supplierProductailExcel } from '@/api/supplier'
+export default {
+  name: 'ChooseImportModal',
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    paramsData: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      nowColumns: [ //  可导入
+        { title: '序号', dataIndex: 'no', width: '10%', align: 'center' },
+        { title: '产品编码', dataIndex: 'productCode', width: '30%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品名称', dataIndex: 'product.name', width: '30%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '成本', dataIndex: 'costText', width: '20%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '单位', dataIndex: 'product.unit', width: '10%', align: 'center', customRender: function (text) { return text || '--' } }
+      ],
+      nowUnColumns: [ //  不可导入
+        { title: '序号', dataIndex: 'no', width: '10%', align: 'center' },
+        { title: '产品编码', dataIndex: 'productCode', width: '25%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品名称', dataIndex: 'product.name', width: '25%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '成本', dataIndex: 'costText', width: '15%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '单位', dataIndex: 'product.unit', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '备注', dataIndex: 'errorDesc', width: '15%', align: 'center', customRender: function (text) { return text || '--' } }
+      ],
+      loadData: [],
+      unLoadData: [],
+      loading: false
+    }
+  },
+  methods: {
+    getData () {
+      const _this = this
+      this.loading = true
+      supplierProductParseProducts(this.paramsData).then(res => {
+        this.loading = false
+        if (res.status == 200) {
+          if (res.data.okList && res.data.okList.length > 0) {
+            res.data.okList.map((item, index) => {
+              item.no = index + 1
+            })
+          }
+          if (res.data.failList && res.data.failList.length > 0) {
+            res.data.failList.map((item, index) => {
+              item.no = index + 1
+            })
+          }
+          _this.loadData = res.data.okList || []
+          _this.unLoadData = res.data.failList || []
+        }
+      })
+    },
+    // 确认导入
+    handleSubmit () {
+      if (this.loadData.length == 0) {
+        this.$message.warning('无可导入产品!')
+      } else {
+        this.$emit('ok', this.loadData)
+        this.isShow = false
+      }
+    },
+    // 导出
+    handleError () {
+      const _this = this
+      if (_this.unLoadData.length < 1) {
+        _this.$message.info('暂无可导出错误项~')
+        return
+      }
+      _this.spinning = true
+      hdExportExcel(supplierProductailExcel, _this.unLoadData, '关联产品导入错误项', 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>

+ 219 - 0
src/views/supplierManagement/associatedProduct/importGuideModal.vue

@@ -0,0 +1,219 @@
+<template>
+  <a-modal
+    centered
+    class="importGuide-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="导入"
+    v-model="isShow"
+    @cancle="isShow=false"
+    :width="750">
+    <div class="importGuide-con">
+      <div class="explain-con">
+        <div class="explain-item">
+          <div class="explain-tit">
+            <span>1</span>准备导入
+          </div>
+          <ul>
+            <li>1) 导入的Excel文件中必须包含名为“产品编码”、“成本”的列,且名称必须相同</li>
+            <li>2) 除了“产品编码”、“成本”两列,其他列可自定义,不影响数据导入</li>
+            <li>3) 如果导入的产品已经存在,则不会导入该行</li>
+          </ul>
+          <a-button type="link" icon="download" style="padding: 0 0 0 23px;" @click="handleExport">下载导入模板</a-button>
+        </div>
+        <div class="explain-item">
+          <div class="explain-tit">
+            <span>2</span>上传数据文件
+          </div>
+          <p>目前支持的文件类型*.xls,*.xlsx.</p>
+          <div style="overflow: hidden;padding-left: 23px;">
+            <Upload
+              id="importGuide-attachList"
+              ref="importUpload"
+              :maxNums="1"
+              fileType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel"
+              uploadType="import"
+              :action="attachAction"
+              :uploadParams="uploadParams"
+              upText="添加文件"
+              @change="changeImport"></Upload>
+          </div>
+        </div>
+      </div>
+      <!-- 按钮 -->
+      <div class="btn-con">
+        <a-button
+          type="primary"
+          id="importGuide-nextStep"
+          size="large"
+          class="button-primary"
+          @click="handlerNextStep"
+          style="padding: 0 60px;">下一步</a-button>
+        <a-button
+          id="importGuide-cancel"
+          size="large"
+          class="button-cancel"
+          @click="isShow=false"
+          style="padding: 0 60px;margin-left: 15px;">取消</a-button>
+      </div>
+    </div>
+    <!-- 导入 -->
+    <chooseImportModal :openModal="openImportModal" :paramsData="paramsData" @close="handleClose" @ok="hanldeOk" />
+  </a-modal>
+</template>
+
+<script>
+import ChooseImportModal from './chooseImportModal.vue'
+import { Upload } from '@/components'
+import { supplierProductDownload } from '@/api/supplier'
+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 + '/upload',
+      paramsData: null,
+      uploadParams: {
+        savePathType: 'local'
+      }
+    }
+  },
+  methods: {
+    // 下一步
+    handlerNextStep () {
+      if (this.paramsData) {
+        this.openImportModal = true
+      } else {
+        this.$message.warning('添加文件后再进行下一步操作!')
+      }
+    },
+    // 上传文件  change
+    changeImport (file) {
+      if (file) {
+        this.paramsData = {
+          supplierSn: this.params.supplierSn || '',
+          path: file
+        }
+      }
+    },
+    // 导入
+    hanldeOk (obj) {
+      if (obj && obj.length > 0) {
+        this.$emit('ok', obj)
+        this.isShow = false
+      }
+    },
+    // 关闭
+    handleClose () {
+      this.openImportModal = false
+      this.isShow = false
+    },
+    //  导出
+    handleExport () {
+      const _this = this
+      _this.spinning = true
+      supplierProductDownload({}).then(res => {
+        _this.spinning = false
+        if (res.type == 'application/json') {
+          var reader = new FileReader()
+          reader.addEventListener('loadend', function () {
+            const obj = JSON.parse(reader.result)
+            _this.$notification.error({
+              message: '提示',
+              description: obj.message
+            })
+          })
+          reader.readAsText(res)
+        } else {
+          this.download(res)
+        }
+      })
+    },
+    download (data) {
+      if (!data) { return }
+      const url = window.URL.createObjectURL(new Blob([data]))
+      const link = document.createElement('a')
+      link.style.display = 'none'
+      link.href = url
+      const fname = '关联产品导入模板'
+      link.setAttribute('download', fname + '.xlsx')
+      document.body.appendChild(link)
+      link.click()
+    }
+  },
+  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>