Browse Source

调拨退货页面

lilei 3 năm trước cách đây
mục cha
commit
be687b9255

+ 17 - 0
src/components/Select/index.js

@@ -83,6 +83,23 @@ export default {
         this.$emit('change', obj, _.find(this.dataList, ['code', obj]))
       }
     }
+    const radioOn = {
+      change: obj => {
+        this.$emit('input', obj.target.value)
+        this.$emit('change', obj.target.value, _.find(this.dataList, ['code', obj.target.value]))
+      }
+    }
+    if(this.showType === 'radio'){
+      return (
+        <a-radio-group vModel={props.value} {...{ props, on: radioOn }} >,
+          {
+            this.dataList.map(item => {
+              return (<a-radio value={item.code} key={item.code}>{item['dispName']}</a-radio>)
+            })
+          }
+        </a-radio-group>
+      )
+    }
     if (this.showType === 'tabs') {
       return (
         <a-tabs vModel={props.value} {...{ props, on: on }}>

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

@@ -1008,6 +1008,61 @@ export const asyncRouterMap = [
                 }
               }
             ]
+          },
+          {
+            path: '/allocationManagement/transferReturn',
+            redirect: '/allocationManagement/transferReturn/list',
+            name: 'transferReturn',
+            component: BlankLayout,
+            meta: {
+              title: '调拨退货列表',
+              icon: 'pull-request',
+              // permission: 'M_transferReturnList'
+            },
+            hideChildrenInMenu: true,
+            children: [
+              {
+                path: 'list',
+                name: 'transferReturnList',
+                component: () => import(/* webpackChunkName: "allocationManagement" */ '@/views/allocationManagement/transferReturn/list.vue'),
+                meta: {
+                  title: '调拨退货列表',
+                  icon: 'pull-request',
+                  hidden: true,
+                  permission: 'M_transferReturnList'
+                }
+              },
+              {
+                path: 'add/:sn/:dealerLevel',
+                name: 'transferReturnGrpEdit',
+                component: () => import(/* webpackChunkName: "allocationManagement" */ '@/views/allocationManagement/transferReturn/editGrp.vue'),
+                meta: {
+                  title: '编辑调拨退货单(抓单)',
+                  icon: 'pull-request',
+                  hidden: true
+                }
+              },
+              {
+                path: 'edit/:sn/:dealerLevel',
+                name: 'transferReturnEdit',
+                component: () => import(/* webpackChunkName: "allocationManagement" */ '@/views/allocationManagement/transferReturn/edit.vue'),
+                meta: {
+                  title: '编辑调拨退货单(不抓单)',
+                  icon: 'pull-request',
+                  hidden: true
+                }
+              },
+              {
+                path: 'detail/:sn',
+                name: 'transferReturnDetail',
+                component: () => import(/* webpackChunkName: "allocationManagement" */ '@/views/allocationManagement/transferReturn/detail.vue'),
+                meta: {
+                  title: '调拨退货单详情',
+                  icon: 'pull-request',
+                  hidden: true
+                }
+              }
+            ]
           }
         ]
       },

+ 220 - 0
src/views/allocationManagement/transferReturn/basicInfoModal.vue

@@ -0,0 +1,220 @@
+<template>
+  <a-modal
+    centered
+    class="allocateBill-basicInfo-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="新增"
+    v-model="isShow"
+    @cancle="isShow = false"
+    :width="800">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-form-model
+        id="allocateBill-basicInfo-form"
+        ref="ruleForm"
+        :model="form"
+        :rules="rules"
+        :label-col="formItemLayout.labelCol"
+        :wrapper-col="formItemLayout.wrapperCol"
+      >
+        <a-form-model-item label="调拨退货对象" prop="targetType">
+          <v-select
+            code="TARGET_TYPE"
+            showType="radio"
+            id="allocateBill-basicInfo-targetType"
+            v-model="form.targetType"
+            @change="targetTypeChange"
+            allowClear
+            placeholder="请选择调拨退货对象"></v-select>
+        </a-form-model-item>
+        <a-form-model-item label="调拨退货对象名称" :prop="isDealer ? 'targetSn' : 'targetName'">
+          <a-select
+            v-if="isDealer"
+            show-search
+            id="allocateBill-basicInfo-dealerName"
+            v-model="form.targetSn"
+            placeholder="请选择经销商"
+            :filter-option="false"
+            :not-found-content="fetching ? undefined : null"
+            @search="fetchUser"
+            @change="handleChange"
+          >
+            <a-spin v-if="fetching" slot="notFoundContent" size="small" />
+            <a-select-option v-for="item in dealerData" :key="item.dealerSn" :value="item.dealerSn">{{ item.dealerName }}</a-select-option>
+          </a-select>
+          <a-input v-if="!isDealer" v-model.trim="form.targetName" placeholder="请输入调拨退货对象名称(最多30个字符)" allowClear :maxLength="30" />
+        </a-form-model-item>
+        <a-form-model-item label="调拨退货类型" prop="allocateTypeSn">
+          <a-select id="allocateBill-basicInfo-allocateTypeSn" v-model="form.allocateTypeSn" placeholder="请选择调拨退货类型" allowClear >
+            <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="grabFlag">
+          <v-select
+            code="FLAG"
+            showType="radio"
+            :disabled="form.targetType !== 'DEALER'"
+            id="allocateBill-basicInfo-grabFlag"
+            v-model="form.grabFlag"
+            allowClear
+            placeholder="请选择"></v-select>
+        </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>
+      </a-form-model>
+      <div class="btn-cont">
+        <a-button type="primary" id="allocateBill-basicInfo-modal-save" @click="handleSave">保存</a-button>
+        <a-button id="allocateBill-basicInfo-modal-back" @click="isShow = false" style="margin-left: 15px;">取消</a-button>
+      </div>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+import debounce from 'lodash/debounce'
+import { VSelect } from '@/components'
+import { allocateBillSave } from '@/api/allocateBill'
+import { dealerSubareaScopeList } from '@/api/dealer'
+import { allocateTypeAllList } from '@/api/allocateType'
+export default {
+  name: 'StoreTransferOutBasicInfoModal',
+  components: { VSelect },
+  props: {
+    openModal: {
+      //  弹框显示状态
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    this.fetchUser = debounce(this.fetchUser, 800)
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      spinning: false,
+      formItemLayout: {
+        labelCol: { span: 4 },
+        wrapperCol: { span: 20 }
+      },
+      form: {
+        targetType: 'DEALER',
+        targetSn: undefined,
+        targetName: '',
+        allocateTypeSn: undefined,
+        grabFlag: '1',
+        remark: ''
+      },
+      rules: {
+        targetType: [{ required: true, message: '请选择调往对象', trigger: 'change' }],
+        targetSn: [{ required: true, message: '请选择调往对象名称', trigger: 'change' }],
+        targetName: [{ required: true, message: '请输入调往对象名称', trigger: 'blur' }],
+        allocateTypeSn: [{ required: true, message: '请选择调拨类型', trigger: 'change' }],
+        grabFlag: [{ required: true, message: '请选择是否抓单', trigger: 'change' }]
+      },
+      fetching: false,
+      dealerData: [], //  经销商  下拉数据
+      allocateTypeList: [] //  调拨类型
+    }
+  },
+  computed: {
+    // 当前所选调往对象是否为经销商
+    isDealer () {
+      return this.form.targetType == 'DEALER'
+    }
+  },
+  methods: {
+    // 搜索经销商
+    fetchUser (value) {
+      console.log('fetching user', value)
+      this.fetching = true
+      dealerSubareaScopeList({ nameLike: value, pageNo: 1, pageSize: 20 }).then(res => {
+        if (res.status == 200) {
+          this.dealerData = res.data && res.data.list ? res.data.list : []
+          this.fetching = false
+        } else {
+          this.dealerData = []
+          this.fetching = false
+        }
+      })
+    },
+    // 调往对象名称  change
+    handleChange (value) {
+      const ind = this.dealerData.findIndex(item => item.dealerSn == value)
+      this.form.targetName = this.dealerData[ind].dealerName
+    },
+    //  保存
+    handleSave () {
+      const _this = this
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          const form = JSON.parse(JSON.stringify(_this.form))
+          _this.spinning = true
+          allocateBillSave(form).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              setTimeout(() => {
+                _this.isShow = false
+                _this.$emit('ok', res.data)
+                _this.spinning = false
+              }, 1000)
+            } else {
+              _this.spinning = false
+            }
+          })
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    },
+    // 调往对象  change
+    targetTypeChange (val) {
+      console.log(val)
+      this.$refs.ruleForm.resetFields()
+      this.form.targetSn = undefined
+      this.form.targetName = ''
+      this.form.targetType = val
+      if (val !== 'DEALER') {
+        this.form.grabFlag = '0'
+      }
+    },
+    //  调拨类型
+    getAllocateTypeAllList () {
+      allocateTypeAllList().then(res => {
+        if (res.status == 200) {
+          this.allocateTypeList = res.data
+        } else {
+          this.allocateTypeList = []
+        }
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.$refs.ruleForm.resetFields()
+      } else {
+        this.getAllocateTypeAllList()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+.allocateBill-basicInfo-modal {
+	.ant-modal-body {
+		padding: 40px 40px 24px;
+	}
+	.btn-cont {
+		text-align: center;
+		margin: 35px 0 10px;
+	}
+}
+</style>

+ 188 - 0
src/views/allocationManagement/transferReturn/chooseImportModal.vue

@@ -0,0 +1,188 @@
+<template>
+  <a-modal
+    centered
+    class="chooseImport-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="导入"
+    v-model="isShow"
+    @cancle="isShow=false"
+    :width="900">
+    <div class="chooseImport-con">
+      <!-- 可导入数据 -->
+      <p class="">可导入数据{{ loadData.length }}条</p>
+      <a-table
+        class="sTable"
+        ref="table"
+        size="small"
+        :rowKey="(record) => record.allocateSn"
+        :columns="nowColumns"
+        :dataSource="loadData"
+        :loading="loading"
+        :scroll="{ y: 200 }"
+        :pagination="false"
+        bordered>
+      </a-table>
+      <a-divider />
+      <!-- 不可导入数据 -->
+      <p class="red">不可导入数据{{ unLoadData.length }}条</p>
+      <a-table
+        class="unTable"
+        ref="unTable"
+        size="small"
+        :rowKey="(record) => record.errorDesc"
+        :columns="nowUnColumns"
+        :dataSource="unLoadData"
+        :loading="loading"
+        :scroll="{ y: 200 }"
+        :pagination="false"
+        bordered>
+      </a-table>
+      <!-- 按钮 -->
+      <div class="btn-con">
+        <a-button
+          type="primary"
+          id="chooseImport-submit"
+          size="large"
+          :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 { allocateBillParseProducts, allocateBillFailExcel } from '@/api/allocateBill'
+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: 70, align: 'center' },
+        { title: '产品编码', dataIndex: 'productCode', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品名称', dataIndex: 'productName', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '数量', dataIndex: 'qtyText', width: 80, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '库存', dataIndex: 'currentStockQty', width: 80, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '单位', dataIndex: 'productUnit', width: 60, align: 'center', customRender: function (text) { return text || '--' } }
+      ],
+      nowUnColumns: [ //  促销品
+        { title: '序号', dataIndex: 'no', width: 70, align: 'center' },
+        { title: '产品编码', dataIndex: 'productCode', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品名称', dataIndex: 'productName', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '数量', dataIndex: 'qtyText', width: 80, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '库存', dataIndex: 'currentStockQty', width: 80, align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '单位', dataIndex: 'productUnit', width: 60, align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '备注', dataIndex: 'errorDesc', width: 180, align: 'center', customRender: function (text) { return text || '--' } }
+      ],
+      loadData: [],
+      unLoadData: [],
+      loading: false
+    }
+  },
+  methods: {
+    getData () {
+      const _this = this
+      this.loading = true
+      allocateBillParseProducts(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(allocateBillFailExcel, _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>

+ 259 - 0
src/views/allocationManagement/transferReturn/detail.vue

@@ -0,0 +1,259 @@
+<template>
+  <div class="allocateBillDetail-wrap">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-page-header :ghost="false" :backIcon="false" class="allocateBillDetail-back" :style="{ padding: !outBizSn ? '16px 24px' : '0px 24px' }" >
+        <!-- 自定义的二级文字标题 -->
+        <template slot="subTitle" v-if="!outBizSn">
+          <a id="allocateBillDetail-back-btn" href="javascript:;" @click="handleBack"><a-icon type="left" /> 返回列表</a>
+          <a-button
+            v-if="isEdit"
+            type="primary"
+            size="small"
+            style="background-color: #1890ff;margin-left: 20px;border: #1890ff;"
+            id="allocateBillDetail-edit-btn"
+            @click.stop="handleEdit">编辑</a-button>
+        </template>
+        <!-- 操作区,位于 title 行的行尾 -->
+        <template slot="extra">
+          <a-button
+            key="3"
+            type="primary"
+            class="button-warning"
+            v-if="$hasPermissions('B_transferOut_detail_export')"
+            id="allocateBillDetail-export-btn"
+            :disabled="localDataSource.length==0"
+            @click="handleExcel">导出Excel</a-button>
+          <a-button
+            key="2"
+            type="primary"
+            class="button-error"
+            v-if="$hasPermissions('B_transferOut_print')"
+            id="allocateBillDetail-db-print-btn"
+            :disabled="localDataSource.length==0"
+            @click="handlePrint('dbPrint')">调拨打印</a-button>
+          <a-button
+            key="1"
+            type="primary"
+            class="button-info"
+            v-if="$hasPermissions('B_transferOut_print')"
+            id="allocateBillDetail-dbfl-print-btn"
+            :disabled="localDataSource.length==0"
+            @click="handlePrint('dbflPrint')">调拨分类打印</a-button>
+        </template>
+      </a-page-header>
+      <a-card size="small" :bordered="false" class="allocateBillDetail-cont">
+        <a-collapse :activeKey="['1']">
+          <a-collapse-panel key="1" header="基础信息">
+            <a-descriptions :column="3">
+              <a-descriptions-item label="调拨退货对象">{{ (basicInfoData&&basicInfoData.targetName) || '--' }}</a-descriptions-item>
+              <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.grabFlag ? '是' : '否' }}</a-descriptions-item>
+              <a-descriptions-item label="备注">{{ (basicInfoData&&basicInfoData.remark) || '--' }}</a-descriptions-item>
+            </a-descriptions>
+          </a-collapse-panel>
+        </a-collapse>
+      </a-card>
+      <a-card size="small" :bordered="false" class="allocateBillDetail-cont">
+        <!-- 总计 -->
+        <a-alert type="info" style="margin-bottom:10px">
+          <div slot="message">
+            退货总数量:<strong>{{ (productTotal&&(productTotal.totalQty || productTotal.totalQty==0)) ? productTotal.totalQty : '--' }}</strong> ,
+            坏件总数量:<strong>{{ (productTotal&&(productTotal.totalQty || productTotal.totalQty==0)) ? productTotal.totalQty : '--' }}</strong> ,
+            返库总数量:<strong>{{ (productTotal&&(productTotal.totalQty || productTotal.totalQty==0)) ? productTotal.totalQty : '--' }}</strong> ,
+            <span >退货总金额(¥):<strong>{{ (productTotal&&(productTotal.totalPrice || productTotal.totalPrice==0)) ? productTotal.totalPrice : '--' }}</strong></span>;
+          </div>
+        </a-alert>
+        <!-- 列表 -->
+        <s-table
+          class="sTable"
+          ref="table"
+          size="small"
+          :rowKey="(record) => record.id"
+          :columns="columns"
+          :data="loadData"
+          :defaultLoadData="false"
+          bordered>
+        </s-table>
+      </a-card>
+    </a-spin>
+    <!-- 打印导出 -->
+    <print-modal :openModal="openModal" :itemData="basicInfoData" :nowType="nowType" @ok="handleOk" @close="openModal=false" />
+    <!-- 打印 -->
+    <div id="print"></div>
+  </div>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import printModal from './printModal.vue'
+import { hdExportExcel } from '@/libs/exportExcel'
+import { allocateBillDetailList, allocateBillDetail, allocateBillDetailCount, allocateBillDetailPrint, allocateBillDetailExcel } from '@/api/allocateBill'
+export default {
+  components: { STable, VSelect, printModal },
+  props: {
+    outBizSn: { //  有值则为弹框,无值则为页面
+      type: [Number, String],
+      default: ''
+    }
+  },
+  data () {
+    return {
+      spinning: false,
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.spinning = true
+        return allocateBillDetailList(Object.assign(parameter, { allocateSn: this.outBizSn || this.$route.params.sn })).then(res => {
+          let data
+          if (res.status == 200) {
+            data = res.data
+            const no = (data.pageNo - 1) * data.pageSize
+            for (var i = 0; i < data.list.length; i++) {
+              data.list[i].no = no + i + 1
+            }
+            this.localDataSource = data.list
+          }
+          this.spinning = false
+          return data
+        })
+      },
+      basicInfoData: null, //  基本信息
+      productTotal: null, //  合计
+      localDataSource: [],
+      openModal: false,
+      nowType: null
+    }
+  },
+  computed: {
+    isEdit () {
+      return this.basicInfoData && ((this.basicInfoData.state == 'WAIT_SUBMIT') || (this.basicInfoData.state == 'WAIT_AUDIT') || (this.basicInfoData.state == 'AUDIT_REJECT')) && this.$hasPermissions('M_transferOut_edit')
+    },
+    columns () {
+      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: '27%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '单位', dataIndex: 'productEntity.unit', width: '5%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '退货单价(¥)', dataIndex: 'cost', width: '9%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '退货数量', dataIndex: 'qty', width: '9%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '坏件数量', dataIndex: 'qty', width: '9%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '返库数量', dataIndex: 'qty', width: '9%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '退货金额(¥)', dataIndex: 'totalPrice', width: '9%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } }
+      ]
+
+      if (this.basicInfoData.grapFlag == '1') {
+        arr.splice(1, 0, { title: '调拨单号', dataIndex: 'productEntity.code', width: '10%', align: 'center', customRender: function (text) { return text || '--' } })
+      }
+      return arr
+    }
+  },
+  methods: {
+    //  返回列表
+    handleBack () {
+      this.$router.push({ name: 'transferReturnList', query: { closeLastOldTab: true } })
+    },
+    // 基本信息
+    getDetail () {
+      allocateBillDetail({ sn: this.outBizSn || this.$route.params.sn }).then(res => {
+        if (res.status == 200) {
+          this.basicInfoData = res.data
+        } else {
+          this.basicInfoData = null
+        }
+      })
+    },
+    // 合计
+    getDetailCount () {
+      allocateBillDetailCount({ allocateSn: this.outBizSn || this.$route.params.sn }).then(res => {
+        if (res.status == 200) {
+          this.productTotal = res.data
+        } else {
+          this.productTotal = null
+        }
+      })
+    },
+    //  编辑
+    handleEdit () {
+      this.$router.push({ path: `/allocationManagement/transferOut/edit/${this.basicInfoData.allocateSn}/${this.basicInfoData.dealerLevel}` })
+    },
+    // 导出
+    handleExcel () {
+      const _this = this
+      this.spinning = true
+      hdExportExcel(allocateBillDetailExcel, { allocateSn: this.outBizSn || this.$route.params.sn }, '调拨明细', function () {
+        _this.spinning = false
+      })
+    },
+    // 打印预览/快捷打印
+    handlePrint (type) {
+      this.nowType = type
+      this.openModal = true
+    },
+    handleOk (objs) {
+      const _this = this
+      const params = JSON.parse(JSON.stringify(objs))
+      delete params.type
+      _this.spinning = true
+      allocateBillDetailPrint(params).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.print(res, objs.isPreview)
+        }
+      })
+    },
+    print (data, type) {
+      if (!data) {
+        return
+      }
+      const url = window.URL.createObjectURL(new Blob([data], { type: 'application/pdf' }))
+      document.getElementById('print').innerHTML = '<iframe id="printftod" name="printftod" src="' + url + '" hidden></iframe>'
+      if (type == '1') { //  预览
+        window.open(url)
+      } else if (type == '0') { //  打印
+        window.frames['printftod'].focus()
+        window.frames['printftod'].print()
+      }
+    },
+    pageInit () {
+      this.$refs.table.refresh(true)
+      this.getDetail()
+      this.getDetailCount()
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab || this.outBizSn) { // 页签刷新 或 为弹框时调用
+      this.pageInit()
+    }
+  },
+  activated () {
+    // 如果是新页签打开或者进入新的子页(例:存在列表第2条数据编辑页页签时再打开第4条数据的编辑页),则重置当前页面
+    if (this.$store.state.app.isNewTab || !this.$store.state.app.isNewSubTab) {
+      this.pageInit()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {})
+  }
+}
+</script>
+
+<style lang="less">
+  .allocateBillDetail-wrap{
+    .allocateBillDetail-back{
+      margin-bottom: 10px;
+    }
+    .allocateBillDetail-cont{
+      margin-bottom: 10px;
+    }
+  }
+</style>

+ 645 - 0
src/views/allocationManagement/transferReturn/edit.vue

@@ -0,0 +1,645 @@
+<template>
+  <div class="allocateBillEdit-wrap">
+    <!-- <a-spin :spinning="spinning" tip="Loading..."> -->
+    <div class="ant-spin-nested-loading">
+      <a-page-header :ghost="false" :backIcon="false" class="allocateBillEdit-back" >
+        <!-- 自定义的二级文字标题 -->
+        <template slot="subTitle">
+          <a id="allocateBillEdit-back-btn" href="javascript:;" @click="handleBack"><a-icon type="left" /> 返回列表</a>
+        </template>
+        <!-- 操作区,位于 title 行的行尾 -->
+        <template slot="extra">
+          <a-button
+            key="3"
+            type="primary"
+            class="button-warning"
+            v-if="$hasPermissions('B_transferOut_detail_export')"
+            id="allocateBillEdit-export-btn"
+            :disabled="localDataSource.length==0"
+            @click="handleExcel">导出Excel</a-button>
+          <a-button
+            key="2"
+            type="primary"
+            class="button-error"
+            v-if="$hasPermissions('B_transferOut_print')"
+            id="allocateBillEdit-db-print-btn"
+            :disabled="localDataSource.length==0"
+            @click="handlePrint('dbPrint')">调拨打印</a-button>
+          <a-button
+            key="1"
+            type="primary"
+            class="button-info"
+            v-if="$hasPermissions('B_transferOut_print')"
+            id="allocateBillEdit-dbfl-print-btn"
+            :disabled="localDataSource.length==0"
+            @click="handlePrint('dbflPrint')">调拨分类打印</a-button>
+        </template>
+      </a-page-header>
+      <a-card size="small" :bordered="false" v-if="basicInfoData" class="allocateBillEdit-cont">
+        <a-collapse :activeKey="['0']">
+          <a-collapse-panel key="0" header="基础信息">
+            <a-descriptions :column="3">
+              <a-descriptions-item label="调往对象">{{ (basicInfoData&&basicInfoData.targetName) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="调拨单号">{{ (basicInfoData&&basicInfoData.allocateNo) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="调拨类型">
+                <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>
+        </a-collapse>
+      </a-card>
+      <!-- 选择产品 -->
+      <a-card size="small" :bordered="false" class="allocateBillEdit-cont">
+        <a-collapse :activeKey="['1']">
+          <a-collapse-panel key="1" :forceRender="true" header="选择产品">
+            <!-- 筛选条件 -->
+            <div class="table-page-search-wrapper">
+              <a-form layout="inline" @keyup.enter.native="$refs.table.refresh(true)">
+                <a-row :gutter="15">
+                  <a-col :md="6" :sm="24">
+                    <a-form-item label="产品编码" prop="productCode">
+                      <a-input id="allocateBillEdit-productCode" v-model.trim="queryParam.productCode" placeholder="请输入产品编码" allowClear />
+                    </a-form-item>
+                  </a-col>
+                  <a-col :md="6" :sm="24">
+                    <a-form-item label="产品名称" prop="productName">
+                      <a-input id="allocateBillEdit-productName" v-model.trim="queryParam.productName" placeholder="请输入产品名称" allowClear />
+                    </a-form-item>
+                  </a-col>
+                  <a-col :md="6" :sm="24">
+                    <a-form-item label="原厂编码" prop="productOrigCode">
+                      <a-input id="allocateBillEdit-productOrigCode" v-model.trim="queryParam.productOrigCode" placeholder="请输入原厂编码" allowClear />
+                    </a-form-item>
+                  </a-col>
+                  <a-col :md="6" :sm="24" style="margin-bottom: 10px;">
+                    <a-button type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="storeTransferOutList-refresh">查询</a-button>
+                    <a-button style="margin-left: 8px" @click="resetSearchForm" :disabled="disabled" id="storeTransferOutList-reset">重置</a-button>
+                  </a-col>
+                </a-row>
+              </a-form>
+            </div>
+            <!-- 列表 -->
+            <s-table
+              class="sTable"
+              ref="table"
+              size="small"
+              index="0"
+              tableId="table1"
+              :rowKey="(record) => record.stockSn"
+              :columns="columns"
+              :customRow="handleClickRow"
+              :data="loadData"
+              :scroll="{ y: 300 }"
+              :defaultLoadData="false"
+              bordered>
+              <!-- 操作 -->
+              <template slot="action1" slot-scope="text, record">
+                <a-button size="small" type="primary" class="button-primary" @click="handleAdd(record)" id="allocateBillEdit-add-btn">添加</a-button>
+              </template>
+            </s-table>
+          </a-collapse-panel>
+        </a-collapse>
+      </a-card>
+      <!-- 已选产品 -->
+      <a-card size="small" :bordered="false" class="allocateBillEdit-cont">
+        <a-collapse :activeKey="['2']">
+          <a-collapse-panel key="2" :forceRender="true" header="已选产品">
+            <!-- 总计 -->
+            <a-alert type="info" style="margin-bottom:10px">
+              <div slot="message">
+                总数量:<strong>{{ (productTotal&&(productTotal.totalQty || productTotal.totalQty==0)) ? productTotal.totalQty : '--' }}</strong> ,
+                <span v-if="$hasPermissions('B_isShowCost')">总成本(¥):<strong>{{ (productTotal&&(productTotal.totalCost || productTotal.totalCost==0)) ? productTotal.totalCost : '--' }}</strong> ,</span>
+                <span v-if="$hasPermissions('B_isShowPrice')">总售价(¥):<strong>{{ (productTotal&&(productTotal.totalPrice || productTotal.totalPrice==0)) ? productTotal.totalPrice : '--' }}</strong></span>
+              </div>
+            </a-alert>
+            <!-- 筛选条件 -->
+            <a-row :gutter="15">
+              <a-col :span="17">
+                <div class="table-page-search-wrapper">
+                  <a-form layout="inline" @keyup.enter.native="$refs.chooseTable.refresh(true)">
+                    <a-row :gutter="15">
+                      <a-col :md="9" :sm="24">
+                        <a-form-item label="产品编码" prop="productCode">
+                          <a-input id="allocateBillEdit-productCode" v-model.trim="chooseQueryParam.productCode" placeholder="请输入产品编码" allowClear />
+                        </a-form-item>
+                      </a-col>
+                      <a-col :md="9" :sm="24">
+                        <a-form-item label="产品名称" prop="productName">
+                          <a-input id="allocateBillEdit-productName" v-model.trim="chooseQueryParam.productName" placeholder="请输入产品名称" allowClear />
+                        </a-form-item>
+                      </a-col>
+                      <a-col :md="6" :sm="24" style="margin-bottom: 10px;">
+                        <a-button type="primary" @click="$refs.chooseTable.refresh(true)" :disabled="chooseDisabled" id="storeTransferOutList-refresh">查询</a-button>
+                        <a-button style="margin-left: 8px" @click="chooseResetSearchForm" :disabled="chooseDisabled" id="storeTransferOutList-reset">重置</a-button>
+                      </a-col>
+                    </a-row>
+                  </a-form>
+                </div>
+              </a-col>
+              <a-col :span="7" style="text-align: right;">
+                <a-button size="small" id="allocateBillEdit-import-btn" @click="openGuideModal=true">导入产品</a-button>
+                <a-button size="small" type="danger" style="margin-left: 5px" @click.stop="handleDel('', 'all')" id="chainTransferOutEdit-del-all-btn">整单删除</a-button>
+              </a-col>
+            </a-row>
+            <!-- 列表 -->
+            <s-table
+              class="sTable"
+              ref="chooseTable"
+              size="small"
+              index="1"
+              tableId="table2"
+              :rowKey="(record) => record.id"
+              :columns="chooseColumns"
+              :data="chooseLoadData"
+              :scroll="{ y: 300 }"
+              :defaultLoadData="false"
+              bordered>
+              <!-- 售价 -->
+              <template slot="price" slot-scope="text, record, index">
+                <!-- 调往对象为经销商时不可编辑售价,为员工或其他时可编辑售价 -->
+                <div v-if="$route.params.dealerLevel == 'OTHER'">
+                  <a-select
+                    size="small"
+                    id="allocateBillEdit-price"
+                    option-label-prop="label"
+                    v-model="record.price"
+                    placeholder="请选择"
+                    @change="e => priceChange(e, record)"
+                    @focus="e => priceFocus(record, index)"
+                    style="width: 100%;">
+                    <a-select-option v-if="record.cost" :value="record.cost" :key="'cb-'+record.cost" :label="record.cost">成本 {{ record.cost }}</a-select-option>
+                    <a-select-option v-if="loadDataSource&&loadDataSource[index]&&loadDataSource[index].provincePrice" :value="loadDataSource[index].provincePrice" :key="'A-'+loadDataSource[index].productSn" :label="loadDataSource[index].provincePrice">A价 {{ loadDataSource[index].provincePrice }}</a-select-option>
+                    <a-select-option v-if="loadDataSource&&loadDataSource[index]&&loadDataSource[index].cityPrice" :value="loadDataSource[index].cityPrice" :key="'B-'+loadDataSource[index].productSn" :label="loadDataSource[index].cityPrice">B价 {{ loadDataSource[index].cityPrice }}</a-select-option>
+                    <a-select-option v-if="loadDataSource&&loadDataSource[index]&&loadDataSource[index].specialPrice" :value="loadDataSource[index].specialPrice" :key="'C-'+loadDataSource[index].productSn" :label="loadDataSource[index].specialPrice">C价 {{ loadDataSource[index].specialPrice }}</a-select-option>
+                  </a-select>
+                </div>
+                <span v-else>{{ record.price }}</span>
+              </template>
+              <!-- 调出数量 -->
+              <template slot="qty" slot-scope="text, record">
+                <a-input-number
+                  size="small"
+                  id="allocateBillEdit-qty"
+                  v-model="record.qty"
+                  :precision="0"
+                  :min="1"
+                  :max="999999"
+                  placeholder="请输入"
+                  @blur="e => qtyBlur(e.target.value, record)"
+                  style="width: 100%;" />
+              </template>
+              <!-- 操作 -->
+              <template slot="action" slot-scope="text, record">
+                <a-button size="small" type="primary" class="button-error" @click="handleDel(record)" id="allocateBillEdit-del-btn">删除</a-button>
+              </template>
+            </s-table>
+          </a-collapse-panel>
+        </a-collapse>
+      </a-card>
+    <!-- </a-spin> -->
+    </div>
+    <div class="affix-cont">
+      <a-button
+        type="primary"
+        id="allocateBillEdit-submit"
+        size="large"
+        :disabled="spinning"
+        class="button-primary"
+        @click="handleSubmit"
+        style="padding: 0 60px;">提交</a-button>
+    </div>
+    <!-- 导入产品 -->
+    <importGuideModal :openModal="openGuideModal" :params="{allocateSn: $route.params.sn}" @close="openGuideModal=false" @ok="handleGuideOk" />
+    <!-- 打印导出 -->
+    <print-modal :openModal="openModal" :itemData="basicInfoData" :nowType="nowType" @ok="handleOk" @close="openModal=false" />
+    <!-- 打印 -->
+    <div id="print"></div>
+  </div>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import ImportGuideModal from './importGuideModal.vue'
+import printModal from './printModal.vue'
+import { hdExportExcel } from '@/libs/exportExcel'
+import { queryStockProductPage } from '@/api/stock'
+import { productPriceInfo } from '@/api/product'
+import AllocateType from '@/views/common/allocateType.js'
+import { allocateBillSave, allocateBillDetailList, allocateBillDetailCount, allocateBillDetail, allocateBillDetailSave, allocateBillSubmit, allocateBillDetailDel, allocateBillDetailDelAll, allocateBillDetailPrint, allocateBillBatchInsert, allocateBillDetailExcel } from '@/api/allocateBill'
+
+export default {
+  components: { STable, VSelect, ImportGuideModal, AllocateType, printModal },
+  data () {
+    return {
+      spinning: false,
+      queryParam: {
+        productCode: '',
+        productName: '',
+        productOrigCode: ''
+      },
+      chooseQueryParam: {
+        productCode: '',
+        productName: ''
+      },
+      disabled: false, //  查询、重置按钮是否可操作
+      loading: false,
+      chooseDisabled: false, //  查询、重置按钮是否可操作
+      advanced: false, // 高级搜索 展开/关闭
+      productBrandList: [], //  产品品牌  下拉数据
+      productTypeList: [], //  产品分类  下拉数据
+      productType: [],
+      warehouseList: [], //  仓库  下拉数据
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        const dealerLevel = this.$route.params.dealerLevel == 'OTHER' ? undefined : this.$route.params.dealerLevel
+        return queryStockProductPage(Object.assign(parameter, this.queryParam, { zeroQtyFlag: '0', dealerLevel: dealerLevel })).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.loadDataSource = data.list || []
+          this.disabled = false
+          return data
+        })
+      },
+      loadDataSource: [],
+      localDataSource: [],
+      // 加载数据方法 必须为 Promise 对象
+      chooseLoadData: parameter => {
+        this.chooseDisabled = true
+        const params = Object.assign(parameter, this.chooseQueryParam, { allocateSn: this.$route.params.sn })
+        return allocateBillDetailList(params).then(res => {
+          this.getDetailCount()
+          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
+            data.list[i].qtyBackups = data.list[i].qty
+            data.list[i].priceBackups = data.list[i].price
+          }
+          this.localDataSource = data.list || []
+          this.chooseDisabled = false
+          return data
+        })
+      },
+      productTotal: null, //  合计
+      basicInfoData: null, // 基本信息
+      openGuideModal: false, //  导入产品引导
+      openModal: false,
+      nowType: null
+    }
+  },
+  computed: {
+    columns () {
+      const arr = [
+        { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
+        { 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: 'lastStockCost', width: '10%', align: 'center', customRender: function (text) { return ((text || text == 0) ? 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' }
+      ]
+      if (this.$hasPermissions('B_isShowCost')) { //  成本价权限
+        arr.splice(4, 0, { title: '成本价', dataIndex: 'lastStockCost', width: '10%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } })
+      }
+      if (this.$hasPermissions('B_isShowPrice')) { //  售价权限
+        const ind = this.$hasPermissions('B_isShowCost') ? 5 : 4
+        arr.splice(ind, 0, { title: '售价', dataIndex: 'productPrice', width: '10%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } })
+      }
+      return arr
+    },
+    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: '成本价', dataIndex: 'cost', width: '10%', align: 'center', customRender: function (text) { return ((text || text == 0) ? 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 : '--') } })
+      }
+      if (this.$hasPermissions('B_isShowPrice')) { //  售价权限
+        const ind = this.$hasPermissions('B_isShowCost') ? 5 : 4
+        arr.splice(ind, 0, { title: '售价', scopedSlots: { customRender: 'price' }, width: '10%', align: 'center' })
+      }
+      return arr
+    }
+  },
+  methods: {
+    // 修改调拨类型
+    changeAllocateType (val) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确定要更改调拨类型吗?',
+        centered: true,
+        onOk () {
+          const params = _this.basicInfoData
+          allocateBillSave({
+            allocateSn: params.allocateSn,
+            targetType: params.targetType,
+            targetSn: params.targetSn,
+            targetName: params.targetName,
+            allocateTypeSn: params.allocateTypeSn,
+            remark: params.remark
+          }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.getDetail()
+            } else {
+              _this.spinning = false
+            }
+          })
+        }
+      })
+    },
+    //  重置
+    resetSearchForm () {
+      this.queryParam.productCode = ''
+      this.queryParam.productName = ''
+      this.queryParam.productOrigCode = ''
+      this.$refs.table.refresh(true)
+    },
+    // 双击快速添加
+    handleClickRow (record) {
+      return {
+        on: {
+          dblclick: (event) => {
+            this.handleAdd(record)
+          }
+        }
+      }
+    },
+    // 导入产品
+    handleGuideOk (obj) {
+      allocateBillBatchInsert(obj).then(res => {
+        if (res.status == 200) {
+          this.$refs.chooseTable.refresh(true)
+        }
+      })
+    },
+    // 已选产品  重置
+    chooseResetSearchForm () {
+      this.chooseQueryParam.productCode = ''
+      this.chooseQueryParam.productName = ''
+      this.$refs.chooseTable.refresh(true)
+    },
+    //  添加/编辑
+    handleAdd (row, isEdit, isRefresh) {
+      const params = {
+        id: isEdit ? row.id : undefined,
+        allocateSn: this.$route.params.sn,
+        cost: isEdit ? row.cost : row.lastStockCost,
+        price: isEdit ? row.price : row.productPrice,
+        qty: isEdit ? row.qty : 1, //  添加时调出数量默认为1
+        productSn: row.productSn
+      }
+      if (isEdit) { // 编辑
+        // 清空数量时,值应保持未清空前的值,因数量不可为空
+        if (!row.qty) {
+          row.qty = row.qtyBackups
+          return
+        }
+        if (!row.price) {
+          row.price = row.priceBackups
+          return
+        }
+      }
+      this.spinning = true
+      allocateBillDetailSave(params).then(res => {
+        if (res.status == 200) {
+          this.$message.success(res.message)
+          if (isRefresh != 'noRefresh') {
+            this.$refs.table.refresh()
+          }
+          this.$refs.chooseTable.refresh()
+          this.spinning = false
+        } else {
+          this.spinning = false
+        }
+      })
+    },
+    //  删除
+    handleDel (row, isAll) {
+      const _this = this
+      const content = isAll ? '删除后不可恢复,确定要进行整单删除吗?' : '删除后不可恢复,确定要进行删除吗?'
+      this.$confirm({
+        title: '提示',
+        content: content,
+        centered: true,
+        onOk () {
+          if (isAll) { //  整单删除
+            allocateBillDetailDelAll({ sn: _this.$route.params.sn }).then(res => {
+              if (res.status == 200) {
+                _this.$message.success(res.message)
+                _this.refashPage()
+              }
+            })
+          } else { //  单个删除
+            allocateBillDetailDel({ id: row.id }).then(res => {
+              if (res.status == 200) {
+                _this.$message.success(res.message)
+                _this.refashPage()
+              }
+            })
+          }
+        }
+      })
+    },
+    //  提交
+    handleSubmit () {
+      const _this = this
+      _this.spinning = true
+      allocateBillSubmit({ sn: this.$route.params.sn }).then(res => {
+        if (res.status == 200) {
+          this.$message.success(res.message)
+          setTimeout(() => {
+            _this.handleBack()
+            _this.spinning = false
+          }, 1000)
+        } else {
+          _this.spinning = false
+        }
+      })
+    },
+    // 基本信息
+    getDetail () {
+      this.spinning = true
+      allocateBillDetail({ sn: this.$route.params.sn }).then(res => {
+        if (res.status == 200) {
+          this.basicInfoData = res.data
+        } else {
+          this.basicInfoData = null
+        }
+        this.spinning = false
+      })
+    },
+    // 合计
+    getDetailCount () {
+      allocateBillDetailCount({ allocateSn: this.$route.params.sn }).then(res => {
+        if (res.status == 200) {
+          this.productTotal = res.data
+        } else {
+          this.productTotal = null
+        }
+      })
+    },
+    //  返回列表
+    handleBack () {
+      this.$router.push({ path: '/allocationManagement/transferOut/list', query: { closeLastOldTab: true } })
+    },
+    // 已选产品 调出数量  blur
+    qtyBlur (val, record) {
+      //  光标移出,值发生改变再调用编辑接口
+      if (val != record.qtyBackups) {
+        this.handleAdd(record, 'edit')
+      }
+    },
+    // 已选产品 售价  change
+    priceChange (val, record) {
+      //  光标移出,值发生改变再调用编辑接口
+      if (val != record.priceBackups) {
+        this.handleAdd(record, 'edit', 'noRefresh')
+      }
+    },
+    // 获取价格
+    priceFocus (row, index) {
+      if (row.productSn) {
+        productPriceInfo({ sn: row.productSn }).then(res => {
+          if (res.status == 200 && res.data) {
+            this.loadDataSource[index].provincePrice = res.data.provincePrice || undefined
+            this.loadDataSource[index].cityPrice = res.data.cityPrice || undefined
+            this.loadDataSource[index].specialPrice = res.data.specialPrice || undefined
+          }
+        })
+      }
+    },
+    // 导出
+    handleExcel () {
+      const _this = this
+      this.spinning = true
+      hdExportExcel(allocateBillDetailExcel, { allocateSn: this.$route.params.sn }, '调拨明细', function () {
+        _this.spinning = false
+      })
+    },
+    // 打印预览/快捷打印
+    handlePrint (type) {
+      this.nowType = type
+      this.openModal = true
+    },
+    handleOk (objs) {
+      const _this = this
+      const params = JSON.parse(JSON.stringify(objs))
+      delete params.type
+      _this.spinning = true
+      allocateBillDetailPrint(params).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.print(res, objs.isPreview)
+        }
+      })
+    },
+    print (data, type) {
+      if (!data) {
+        return
+      }
+      const url = window.URL.createObjectURL(new Blob([data], { type: 'application/pdf' }))
+      document.getElementById('print').innerHTML = '<iframe id="printftoe" name="printftoe" src="' + url + '" hidden></iframe>'
+      if (type == '1') { //  预览
+        window.open(url)
+      } else if (type == '0') { //  打印
+        window.frames['printftoe'].focus()
+        window.frames['printftoe'].print()
+      }
+    },
+    // 刷新当前页面
+    refashPage () {
+      this.$refs.table.refresh()
+      this.$refs.chooseTable.refresh()
+    },
+    pageInit () {
+      this.getDetail()
+      this.resetSearchForm()
+      this.chooseResetSearchForm()
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
+      this.pageInit()
+    }
+  },
+  activated () {
+    // 如果是新页签打开或者进入新的子页(例:存在列表第2条数据编辑页页签时再打开第4条数据的编辑页),则重置当前页面
+    if (this.$store.state.app.isNewTab || !this.$store.state.app.isNewSubTab) {
+      this.pageInit()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {})
+  }
+}
+</script>
+
+<style lang="less">
+  .allocateBillEdit-wrap{
+    position: relative;
+    height: 100%;
+    box-sizing: border-box;
+    >.ant-spin-nested-loading{
+      overflow-y: scroll;
+      height: 100%;
+      padding-bottom: 51px;
+    }
+    .allocateBillEdit-back{
+      margin-bottom: 10px;
+    }
+    .allocateBillEdit-cont{
+      margin-bottom: 10px;
+      .sub-title{
+        font-size: 12px;
+        color: #808695;
+        margin-left: 10px;
+      }
+      .tag-txt{
+        font-size: 12px;
+        color: #ed1c24;
+      }
+      .edit-circle-btn{
+        margin-left: 15px;
+        i{
+          vertical-align: text-bottom;
+        }
+      }
+      .import-btn{
+        margin-left: 15px;
+      }
+    }
+  }
+</style>

+ 645 - 0
src/views/allocationManagement/transferReturn/editGrp.vue

@@ -0,0 +1,645 @@
+<template>
+  <div class="allocateBillEdit-wrap">
+    <!-- <a-spin :spinning="spinning" tip="Loading..."> -->
+    <div class="ant-spin-nested-loading">
+      <a-page-header :ghost="false" :backIcon="false" class="allocateBillEdit-back" >
+        <!-- 自定义的二级文字标题 -->
+        <template slot="subTitle">
+          <a id="allocateBillEdit-back-btn" href="javascript:;" @click="handleBack"><a-icon type="left" /> 返回列表</a>
+        </template>
+        <!-- 操作区,位于 title 行的行尾 -->
+        <template slot="extra">
+          <a-button
+            key="3"
+            type="primary"
+            class="button-warning"
+            v-if="$hasPermissions('B_transferOut_detail_export')"
+            id="allocateBillEdit-export-btn"
+            :disabled="localDataSource.length==0"
+            @click="handleExcel">导出Excel</a-button>
+          <a-button
+            key="2"
+            type="primary"
+            class="button-error"
+            v-if="$hasPermissions('B_transferOut_print')"
+            id="allocateBillEdit-db-print-btn"
+            :disabled="localDataSource.length==0"
+            @click="handlePrint('dbPrint')">调拨打印</a-button>
+          <a-button
+            key="1"
+            type="primary"
+            class="button-info"
+            v-if="$hasPermissions('B_transferOut_print')"
+            id="allocateBillEdit-dbfl-print-btn"
+            :disabled="localDataSource.length==0"
+            @click="handlePrint('dbflPrint')">调拨分类打印</a-button>
+        </template>
+      </a-page-header>
+      <a-card size="small" :bordered="false" v-if="basicInfoData" class="allocateBillEdit-cont">
+        <a-collapse :activeKey="['0']">
+          <a-collapse-panel key="0" header="基础信息">
+            <a-descriptions :column="3">
+              <a-descriptions-item label="调往对象">{{ (basicInfoData&&basicInfoData.targetName) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="调拨单号">{{ (basicInfoData&&basicInfoData.allocateNo) || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="调拨类型">
+                <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>
+        </a-collapse>
+      </a-card>
+      <!-- 选择产品 -->
+      <a-card size="small" :bordered="false" class="allocateBillEdit-cont">
+        <a-collapse :activeKey="['1']">
+          <a-collapse-panel key="1" :forceRender="true" header="选择产品">
+            <!-- 筛选条件 -->
+            <div class="table-page-search-wrapper">
+              <a-form layout="inline" @keyup.enter.native="$refs.table.refresh(true)">
+                <a-row :gutter="15">
+                  <a-col :md="6" :sm="24">
+                    <a-form-item label="产品编码" prop="productCode">
+                      <a-input id="allocateBillEdit-productCode" v-model.trim="queryParam.productCode" placeholder="请输入产品编码" allowClear />
+                    </a-form-item>
+                  </a-col>
+                  <a-col :md="6" :sm="24">
+                    <a-form-item label="产品名称" prop="productName">
+                      <a-input id="allocateBillEdit-productName" v-model.trim="queryParam.productName" placeholder="请输入产品名称" allowClear />
+                    </a-form-item>
+                  </a-col>
+                  <a-col :md="6" :sm="24">
+                    <a-form-item label="原厂编码" prop="productOrigCode">
+                      <a-input id="allocateBillEdit-productOrigCode" v-model.trim="queryParam.productOrigCode" placeholder="请输入原厂编码" allowClear />
+                    </a-form-item>
+                  </a-col>
+                  <a-col :md="6" :sm="24" style="margin-bottom: 10px;">
+                    <a-button type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="storeTransferOutList-refresh">查询</a-button>
+                    <a-button style="margin-left: 8px" @click="resetSearchForm" :disabled="disabled" id="storeTransferOutList-reset">重置</a-button>
+                  </a-col>
+                </a-row>
+              </a-form>
+            </div>
+            <!-- 列表 -->
+            <s-table
+              class="sTable"
+              ref="table"
+              size="small"
+              index="0"
+              tableId="table1"
+              :rowKey="(record) => record.stockSn"
+              :columns="columns"
+              :customRow="handleClickRow"
+              :data="loadData"
+              :scroll="{ y: 300 }"
+              :defaultLoadData="false"
+              bordered>
+              <!-- 操作 -->
+              <template slot="action1" slot-scope="text, record">
+                <a-button size="small" type="primary" class="button-primary" @click="handleAdd(record)" id="allocateBillEdit-add-btn">添加</a-button>
+              </template>
+            </s-table>
+          </a-collapse-panel>
+        </a-collapse>
+      </a-card>
+      <!-- 已选产品 -->
+      <a-card size="small" :bordered="false" class="allocateBillEdit-cont">
+        <a-collapse :activeKey="['2']">
+          <a-collapse-panel key="2" :forceRender="true" header="已选产品">
+            <!-- 总计 -->
+            <a-alert type="info" style="margin-bottom:10px">
+              <div slot="message">
+                总数量:<strong>{{ (productTotal&&(productTotal.totalQty || productTotal.totalQty==0)) ? productTotal.totalQty : '--' }}</strong> ,
+                <span v-if="$hasPermissions('B_isShowCost')">总成本(¥):<strong>{{ (productTotal&&(productTotal.totalCost || productTotal.totalCost==0)) ? productTotal.totalCost : '--' }}</strong> ,</span>
+                <span v-if="$hasPermissions('B_isShowPrice')">总售价(¥):<strong>{{ (productTotal&&(productTotal.totalPrice || productTotal.totalPrice==0)) ? productTotal.totalPrice : '--' }}</strong></span>
+              </div>
+            </a-alert>
+            <!-- 筛选条件 -->
+            <a-row :gutter="15">
+              <a-col :span="17">
+                <div class="table-page-search-wrapper">
+                  <a-form layout="inline" @keyup.enter.native="$refs.chooseTable.refresh(true)">
+                    <a-row :gutter="15">
+                      <a-col :md="9" :sm="24">
+                        <a-form-item label="产品编码" prop="productCode">
+                          <a-input id="allocateBillEdit-productCode" v-model.trim="chooseQueryParam.productCode" placeholder="请输入产品编码" allowClear />
+                        </a-form-item>
+                      </a-col>
+                      <a-col :md="9" :sm="24">
+                        <a-form-item label="产品名称" prop="productName">
+                          <a-input id="allocateBillEdit-productName" v-model.trim="chooseQueryParam.productName" placeholder="请输入产品名称" allowClear />
+                        </a-form-item>
+                      </a-col>
+                      <a-col :md="6" :sm="24" style="margin-bottom: 10px;">
+                        <a-button type="primary" @click="$refs.chooseTable.refresh(true)" :disabled="chooseDisabled" id="storeTransferOutList-refresh">查询</a-button>
+                        <a-button style="margin-left: 8px" @click="chooseResetSearchForm" :disabled="chooseDisabled" id="storeTransferOutList-reset">重置</a-button>
+                      </a-col>
+                    </a-row>
+                  </a-form>
+                </div>
+              </a-col>
+              <a-col :span="7" style="text-align: right;">
+                <a-button size="small" id="allocateBillEdit-import-btn" @click="openGuideModal=true">导入产品</a-button>
+                <a-button size="small" type="danger" style="margin-left: 5px" @click.stop="handleDel('', 'all')" id="chainTransferOutEdit-del-all-btn">整单删除</a-button>
+              </a-col>
+            </a-row>
+            <!-- 列表 -->
+            <s-table
+              class="sTable"
+              ref="chooseTable"
+              size="small"
+              index="1"
+              tableId="table2"
+              :rowKey="(record) => record.id"
+              :columns="chooseColumns"
+              :data="chooseLoadData"
+              :scroll="{ y: 300 }"
+              :defaultLoadData="false"
+              bordered>
+              <!-- 售价 -->
+              <template slot="price" slot-scope="text, record, index">
+                <!-- 调往对象为经销商时不可编辑售价,为员工或其他时可编辑售价 -->
+                <div v-if="$route.params.dealerLevel == 'OTHER'">
+                  <a-select
+                    size="small"
+                    id="allocateBillEdit-price"
+                    option-label-prop="label"
+                    v-model="record.price"
+                    placeholder="请选择"
+                    @change="e => priceChange(e, record)"
+                    @focus="e => priceFocus(record, index)"
+                    style="width: 100%;">
+                    <a-select-option v-if="record.cost" :value="record.cost" :key="'cb-'+record.cost" :label="record.cost">成本 {{ record.cost }}</a-select-option>
+                    <a-select-option v-if="loadDataSource&&loadDataSource[index]&&loadDataSource[index].provincePrice" :value="loadDataSource[index].provincePrice" :key="'A-'+loadDataSource[index].productSn" :label="loadDataSource[index].provincePrice">A价 {{ loadDataSource[index].provincePrice }}</a-select-option>
+                    <a-select-option v-if="loadDataSource&&loadDataSource[index]&&loadDataSource[index].cityPrice" :value="loadDataSource[index].cityPrice" :key="'B-'+loadDataSource[index].productSn" :label="loadDataSource[index].cityPrice">B价 {{ loadDataSource[index].cityPrice }}</a-select-option>
+                    <a-select-option v-if="loadDataSource&&loadDataSource[index]&&loadDataSource[index].specialPrice" :value="loadDataSource[index].specialPrice" :key="'C-'+loadDataSource[index].productSn" :label="loadDataSource[index].specialPrice">C价 {{ loadDataSource[index].specialPrice }}</a-select-option>
+                  </a-select>
+                </div>
+                <span v-else>{{ record.price }}</span>
+              </template>
+              <!-- 调出数量 -->
+              <template slot="qty" slot-scope="text, record">
+                <a-input-number
+                  size="small"
+                  id="allocateBillEdit-qty"
+                  v-model="record.qty"
+                  :precision="0"
+                  :min="1"
+                  :max="999999"
+                  placeholder="请输入"
+                  @blur="e => qtyBlur(e.target.value, record)"
+                  style="width: 100%;" />
+              </template>
+              <!-- 操作 -->
+              <template slot="action" slot-scope="text, record">
+                <a-button size="small" type="primary" class="button-error" @click="handleDel(record)" id="allocateBillEdit-del-btn">删除</a-button>
+              </template>
+            </s-table>
+          </a-collapse-panel>
+        </a-collapse>
+      </a-card>
+    <!-- </a-spin> -->
+    </div>
+    <div class="affix-cont">
+      <a-button
+        type="primary"
+        id="allocateBillEdit-submit"
+        size="large"
+        :disabled="spinning"
+        class="button-primary"
+        @click="handleSubmit"
+        style="padding: 0 60px;">提交</a-button>
+    </div>
+    <!-- 导入产品 -->
+    <importGuideModal :openModal="openGuideModal" :params="{allocateSn: $route.params.sn}" @close="openGuideModal=false" @ok="handleGuideOk" />
+    <!-- 打印导出 -->
+    <print-modal :openModal="openModal" :itemData="basicInfoData" :nowType="nowType" @ok="handleOk" @close="openModal=false" />
+    <!-- 打印 -->
+    <div id="print"></div>
+  </div>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import ImportGuideModal from './importGuideModal.vue'
+import printModal from './printModal.vue'
+import { hdExportExcel } from '@/libs/exportExcel'
+import { queryStockProductPage } from '@/api/stock'
+import { productPriceInfo } from '@/api/product'
+import AllocateType from '@/views/common/allocateType.js'
+import { allocateBillSave, allocateBillDetailList, allocateBillDetailCount, allocateBillDetail, allocateBillDetailSave, allocateBillSubmit, allocateBillDetailDel, allocateBillDetailDelAll, allocateBillDetailPrint, allocateBillBatchInsert, allocateBillDetailExcel } from '@/api/allocateBill'
+
+export default {
+  components: { STable, VSelect, ImportGuideModal, AllocateType, printModal },
+  data () {
+    return {
+      spinning: false,
+      queryParam: {
+        productCode: '',
+        productName: '',
+        productOrigCode: ''
+      },
+      chooseQueryParam: {
+        productCode: '',
+        productName: ''
+      },
+      disabled: false, //  查询、重置按钮是否可操作
+      loading: false,
+      chooseDisabled: false, //  查询、重置按钮是否可操作
+      advanced: false, // 高级搜索 展开/关闭
+      productBrandList: [], //  产品品牌  下拉数据
+      productTypeList: [], //  产品分类  下拉数据
+      productType: [],
+      warehouseList: [], //  仓库  下拉数据
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        const dealerLevel = this.$route.params.dealerLevel == 'OTHER' ? undefined : this.$route.params.dealerLevel
+        return queryStockProductPage(Object.assign(parameter, this.queryParam, { zeroQtyFlag: '0', dealerLevel: dealerLevel })).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.loadDataSource = data.list || []
+          this.disabled = false
+          return data
+        })
+      },
+      loadDataSource: [],
+      localDataSource: [],
+      // 加载数据方法 必须为 Promise 对象
+      chooseLoadData: parameter => {
+        this.chooseDisabled = true
+        const params = Object.assign(parameter, this.chooseQueryParam, { allocateSn: this.$route.params.sn })
+        return allocateBillDetailList(params).then(res => {
+          this.getDetailCount()
+          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
+            data.list[i].qtyBackups = data.list[i].qty
+            data.list[i].priceBackups = data.list[i].price
+          }
+          this.localDataSource = data.list || []
+          this.chooseDisabled = false
+          return data
+        })
+      },
+      productTotal: null, //  合计
+      basicInfoData: null, // 基本信息
+      openGuideModal: false, //  导入产品引导
+      openModal: false,
+      nowType: null
+    }
+  },
+  computed: {
+    columns () {
+      const arr = [
+        { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
+        { 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: 'lastStockCost', width: '10%', align: 'center', customRender: function (text) { return ((text || text == 0) ? 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' }
+      ]
+      if (this.$hasPermissions('B_isShowCost')) { //  成本价权限
+        arr.splice(4, 0, { title: '成本价', dataIndex: 'lastStockCost', width: '10%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } })
+      }
+      if (this.$hasPermissions('B_isShowPrice')) { //  售价权限
+        const ind = this.$hasPermissions('B_isShowCost') ? 5 : 4
+        arr.splice(ind, 0, { title: '售价', dataIndex: 'productPrice', width: '10%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } })
+      }
+      return arr
+    },
+    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: '成本价', dataIndex: 'cost', width: '10%', align: 'center', customRender: function (text) { return ((text || text == 0) ? 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 : '--') } })
+      }
+      if (this.$hasPermissions('B_isShowPrice')) { //  售价权限
+        const ind = this.$hasPermissions('B_isShowCost') ? 5 : 4
+        arr.splice(ind, 0, { title: '售价', scopedSlots: { customRender: 'price' }, width: '10%', align: 'center' })
+      }
+      return arr
+    }
+  },
+  methods: {
+    // 修改调拨类型
+    changeAllocateType (val) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确定要更改调拨类型吗?',
+        centered: true,
+        onOk () {
+          const params = _this.basicInfoData
+          allocateBillSave({
+            allocateSn: params.allocateSn,
+            targetType: params.targetType,
+            targetSn: params.targetSn,
+            targetName: params.targetName,
+            allocateTypeSn: params.allocateTypeSn,
+            remark: params.remark
+          }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.getDetail()
+            } else {
+              _this.spinning = false
+            }
+          })
+        }
+      })
+    },
+    //  重置
+    resetSearchForm () {
+      this.queryParam.productCode = ''
+      this.queryParam.productName = ''
+      this.queryParam.productOrigCode = ''
+      this.$refs.table.refresh(true)
+    },
+    // 双击快速添加
+    handleClickRow (record) {
+      return {
+        on: {
+          dblclick: (event) => {
+            this.handleAdd(record)
+          }
+        }
+      }
+    },
+    // 导入产品
+    handleGuideOk (obj) {
+      allocateBillBatchInsert(obj).then(res => {
+        if (res.status == 200) {
+          this.$refs.chooseTable.refresh(true)
+        }
+      })
+    },
+    // 已选产品  重置
+    chooseResetSearchForm () {
+      this.chooseQueryParam.productCode = ''
+      this.chooseQueryParam.productName = ''
+      this.$refs.chooseTable.refresh(true)
+    },
+    //  添加/编辑
+    handleAdd (row, isEdit, isRefresh) {
+      const params = {
+        id: isEdit ? row.id : undefined,
+        allocateSn: this.$route.params.sn,
+        cost: isEdit ? row.cost : row.lastStockCost,
+        price: isEdit ? row.price : row.productPrice,
+        qty: isEdit ? row.qty : 1, //  添加时调出数量默认为1
+        productSn: row.productSn
+      }
+      if (isEdit) { // 编辑
+        // 清空数量时,值应保持未清空前的值,因数量不可为空
+        if (!row.qty) {
+          row.qty = row.qtyBackups
+          return
+        }
+        if (!row.price) {
+          row.price = row.priceBackups
+          return
+        }
+      }
+      this.spinning = true
+      allocateBillDetailSave(params).then(res => {
+        if (res.status == 200) {
+          this.$message.success(res.message)
+          if (isRefresh != 'noRefresh') {
+            this.$refs.table.refresh()
+          }
+          this.$refs.chooseTable.refresh()
+          this.spinning = false
+        } else {
+          this.spinning = false
+        }
+      })
+    },
+    //  删除
+    handleDel (row, isAll) {
+      const _this = this
+      const content = isAll ? '删除后不可恢复,确定要进行整单删除吗?' : '删除后不可恢复,确定要进行删除吗?'
+      this.$confirm({
+        title: '提示',
+        content: content,
+        centered: true,
+        onOk () {
+          if (isAll) { //  整单删除
+            allocateBillDetailDelAll({ sn: _this.$route.params.sn }).then(res => {
+              if (res.status == 200) {
+                _this.$message.success(res.message)
+                _this.refashPage()
+              }
+            })
+          } else { //  单个删除
+            allocateBillDetailDel({ id: row.id }).then(res => {
+              if (res.status == 200) {
+                _this.$message.success(res.message)
+                _this.refashPage()
+              }
+            })
+          }
+        }
+      })
+    },
+    //  提交
+    handleSubmit () {
+      const _this = this
+      _this.spinning = true
+      allocateBillSubmit({ sn: this.$route.params.sn }).then(res => {
+        if (res.status == 200) {
+          this.$message.success(res.message)
+          setTimeout(() => {
+            _this.handleBack()
+            _this.spinning = false
+          }, 1000)
+        } else {
+          _this.spinning = false
+        }
+      })
+    },
+    // 基本信息
+    getDetail () {
+      this.spinning = true
+      allocateBillDetail({ sn: this.$route.params.sn }).then(res => {
+        if (res.status == 200) {
+          this.basicInfoData = res.data
+        } else {
+          this.basicInfoData = null
+        }
+        this.spinning = false
+      })
+    },
+    // 合计
+    getDetailCount () {
+      allocateBillDetailCount({ allocateSn: this.$route.params.sn }).then(res => {
+        if (res.status == 200) {
+          this.productTotal = res.data
+        } else {
+          this.productTotal = null
+        }
+      })
+    },
+    //  返回列表
+    handleBack () {
+      this.$router.push({ path: '/allocationManagement/transferOut/list', query: { closeLastOldTab: true } })
+    },
+    // 已选产品 调出数量  blur
+    qtyBlur (val, record) {
+      //  光标移出,值发生改变再调用编辑接口
+      if (val != record.qtyBackups) {
+        this.handleAdd(record, 'edit')
+      }
+    },
+    // 已选产品 售价  change
+    priceChange (val, record) {
+      //  光标移出,值发生改变再调用编辑接口
+      if (val != record.priceBackups) {
+        this.handleAdd(record, 'edit', 'noRefresh')
+      }
+    },
+    // 获取价格
+    priceFocus (row, index) {
+      if (row.productSn) {
+        productPriceInfo({ sn: row.productSn }).then(res => {
+          if (res.status == 200 && res.data) {
+            this.loadDataSource[index].provincePrice = res.data.provincePrice || undefined
+            this.loadDataSource[index].cityPrice = res.data.cityPrice || undefined
+            this.loadDataSource[index].specialPrice = res.data.specialPrice || undefined
+          }
+        })
+      }
+    },
+    // 导出
+    handleExcel () {
+      const _this = this
+      this.spinning = true
+      hdExportExcel(allocateBillDetailExcel, { allocateSn: this.$route.params.sn }, '调拨明细', function () {
+        _this.spinning = false
+      })
+    },
+    // 打印预览/快捷打印
+    handlePrint (type) {
+      this.nowType = type
+      this.openModal = true
+    },
+    handleOk (objs) {
+      const _this = this
+      const params = JSON.parse(JSON.stringify(objs))
+      delete params.type
+      _this.spinning = true
+      allocateBillDetailPrint(params).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.print(res, objs.isPreview)
+        }
+      })
+    },
+    print (data, type) {
+      if (!data) {
+        return
+      }
+      const url = window.URL.createObjectURL(new Blob([data], { type: 'application/pdf' }))
+      document.getElementById('print').innerHTML = '<iframe id="printftoe" name="printftoe" src="' + url + '" hidden></iframe>'
+      if (type == '1') { //  预览
+        window.open(url)
+      } else if (type == '0') { //  打印
+        window.frames['printftoe'].focus()
+        window.frames['printftoe'].print()
+      }
+    },
+    // 刷新当前页面
+    refashPage () {
+      this.$refs.table.refresh()
+      this.$refs.chooseTable.refresh()
+    },
+    pageInit () {
+      this.getDetail()
+      this.resetSearchForm()
+      this.chooseResetSearchForm()
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
+      this.pageInit()
+    }
+  },
+  activated () {
+    // 如果是新页签打开或者进入新的子页(例:存在列表第2条数据编辑页页签时再打开第4条数据的编辑页),则重置当前页面
+    if (this.$store.state.app.isNewTab || !this.$store.state.app.isNewSubTab) {
+      this.pageInit()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {})
+  }
+}
+</script>
+
+<style lang="less">
+  .allocateBillEdit-wrap{
+    position: relative;
+    height: 100%;
+    box-sizing: border-box;
+    >.ant-spin-nested-loading{
+      overflow-y: scroll;
+      height: 100%;
+      padding-bottom: 51px;
+    }
+    .allocateBillEdit-back{
+      margin-bottom: 10px;
+    }
+    .allocateBillEdit-cont{
+      margin-bottom: 10px;
+      .sub-title{
+        font-size: 12px;
+        color: #808695;
+        margin-left: 10px;
+      }
+      .tag-txt{
+        font-size: 12px;
+        color: #ed1c24;
+      }
+      .edit-circle-btn{
+        margin-left: 15px;
+        i{
+          vertical-align: text-bottom;
+        }
+      }
+      .import-btn{
+        margin-left: 15px;
+      }
+    }
+  }
+</style>

+ 219 - 0
src/views/allocationManagement/transferReturn/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 { allocateBillDownload } from '@/api/allocateBill'
+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 = {
+          allocateSn: this.params.allocateSn || '',
+          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
+      allocateBillDownload({}).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>

+ 339 - 0
src/views/allocationManagement/transferReturn/list.vue

@@ -0,0 +1,339 @@
+<template>
+  <a-card size="small" :bordered="false" class="allocateBillList-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="创建时间">
+                <rangeDate ref="rangeDate" :value="time" @change="dateChange" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="调拨退货单号">
+                <a-input id="allocateBillList-allocateNo" v-model.trim="queryParam.allocateNo" allowClear placeholder="请输入调拨退货单号"/>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="调拨退货对象名称">
+                <a-input id="allocateBillList-targetName" v-model.trim="queryParam.targetName" allowClear placeholder="请输入调拨退货对象名称"/>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="调拨退货对象类型">
+                <AllocateType id="allocateBillList-allocateTypeSn" v-model="queryParam.allocateTypeSn"></AllocateType>
+              </a-form-item>
+            </a-col>
+            <template v-if="advanced">
+              <a-col :md="6" :sm="24">
+                <a-form-item label="业务状态">
+                  <v-select
+                    v-model="queryParam.state"
+                    ref="state"
+                    id="allocateBillList-state"
+                    code="ALLOCATE_STATUS"
+                    placeholder="请选择业务状态"
+                    allowClear
+                  ></v-select>
+                </a-form-item>
+              </a-col>
+            </template>
+            <a-col :md="6" :sm="24">
+              <a-button type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="allocateBillList-refresh">查询</a-button>
+              <a-button style="margin-left: 5px" @click="resetSearchForm" :disabled="disabled" id="allocateBillList-reset">重置</a-button>
+              <a-button
+                style="margin-left: 5px"
+                type="primary"
+                class="button-warning"
+                v-if="$hasPermissions('B_transferOut_export')"
+                @click="handleExport"
+                :disabled="disabled"
+                :loading="exportLoading"
+                id="allocateBillList-export">导出</a-button>
+              <a @click="advanced=!advanced" style="margin-left: 5px">
+                {{ advanced ? '收起' : '展开' }}
+                <a-icon :type="advanced ? 'up' : 'down'"/>
+              </a>
+            </a-col>
+          </a-row>
+        </a-form>
+      </div>
+      <!-- 操作按钮 -->
+      <div class="table-operator">
+        <a-button v-if="$hasPermissions('B_transferOut_add')" id="allocateBillList-add" type="primary" class="button-error" @click="openModal=true">新增</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"
+        :defaultLoadData="false"
+        :scroll="{ y: tableHeight }"
+        bordered>
+        <!-- 单号 -->
+        <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
+            size="small"
+            type="link"
+            v-if="record.state == 'WAIT_AUDIT' && $hasPermissions('B_transferOut_audit')"
+            class="button-warning"
+            @click="handleExamine(record)"
+            id="allocateBillList-examine-btn">审核</a-button>
+          <a-button
+            size="small"
+            type="link"
+            v-if="((record.state == 'WAIT_SUBMIT') || (record.state == 'WAIT_AUDIT') || (record.state == 'AUDIT_REJECT')) && $hasPermissions('M_transferOut_edit')"
+            class="button-info"
+            @click="handleEdit(record)"
+            id="allocateBillList-edit-btn">编辑</a-button>
+          <a-button
+            size="small"
+            type="link"
+            v-if="((record.state == 'WAIT_SUBMIT') || (record.state == 'WAIT_AUDIT') || (record.state == 'AUDIT_REJECT')) && $hasPermissions('B_transferOut_del')"
+            class="button-error"
+            @click="handleDel(record)"
+            id="allocateBillList-del-btn">删除</a-button>
+          <span v-if="((record.state != 'WAIT_SUBMIT') && (record.state != 'WAIT_AUDIT') && (record.state != 'AUDIT_REJECT'))||(!$hasPermissions('B_transferOut_audit') && !$hasPermissions('M_transferOut_edit') && !$hasPermissions('B_transferOut_del'))">--</span>
+        </template>
+      </s-table>
+    </a-spin>
+    <!-- 新增 -->
+    <basic-info-modal :openModal="openModal" @ok="handleEdit" @close="openModal=false" />
+    <!-- 审核 -->
+    <auditModal :openModal="visibleAudit" :spinning="spinningAudit" @close="visibleAudit=false" @ok="auditOrder('WAIT_OUT_WAREHOUSE')" @fail="auditOrder('AUDIT_REJECT')" />
+  </a-card>
+</template>
+
+<script>
+import moment from 'moment'
+import getDate from '@/libs/getDate.js'
+import { STable, VSelect } from '@/components'
+import basicInfoModal from './basicInfoModal.vue'
+import rangeDate from '@/views/common/rangeDate.vue'
+import auditModal from '@/views/common/auditModal.vue'
+import { allocateBillList, allocateBillDel, allocateBillAudit, allocateBillExport } from '@/api/allocateBill'
+import AllocateType from '@/views/common/allocateType.js'
+import { hdExportExcel } from '@/libs/exportExcel'
+export default {
+  components: { STable, VSelect, basicInfoModal, rangeDate, auditModal, AllocateType },
+  data () {
+    return {
+      spinning: false,
+      advanced: true, // 高级搜索 展开/关闭
+      tableHeight: 0,
+      time: [
+        moment(getDate.getThreeMonthDays().starttime, 'YYYY-MM-DD'),
+        moment(getDate.getCurrMonthDays().endtime, 'YYYY-MM-DD')
+      ],
+      queryParam: { //  查询条件
+        beginDate: getDate.getThreeMonthDays().starttime,
+        endDate: getDate.getCurrMonthDays().endtime,
+        targetName: '', //  调往对象
+        allocateTypeSn: undefined, //  调拨类型
+        state: undefined, //  业务状态
+        allocateNo: '' //  调拨单号
+      },
+      disabled: false, //  查询、重置按钮是否可操作
+      exportLoading: false,
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        this.spinning = true
+        return allocateBillList(Object.assign(parameter, this.queryParam)).then(res => {
+          let data
+          if (res.status == 200) {
+            data = res.data
+            const no = (data.pageNo - 1) * data.pageSize
+            for (var i = 0; i < data.list.length; i++) {
+              data.list[i].no = no + i + 1
+            }
+            this.disabled = false
+          }
+          this.spinning = false
+          return data
+        })
+      },
+      visibleAudit: false,
+      auditInfo: null,
+      spinningAudit: false,
+      openModal: false //  新增编辑  弹框
+    }
+  },
+  computed: {
+    columns () {
+      const arr = [
+        { 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: 'totalCost', width: '5%', align: 'center', customRender: function (text) { return ((text || text == 0) ? 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: '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: '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 : '--') } })
+      }
+      if (this.$hasPermissions('B_isShowPrice')) { //  售价权限
+        const ind = this.$hasPermissions('B_isShowCost') ? 8 : 7
+        arr.splice(ind, 0, { title: '总售价', dataIndex: 'totalPrice', width: '5%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } })
+      }
+      return arr
+    }
+  },
+  methods: {
+    //  创建时间  change
+    dateChange (date) {
+      this.queryParam.beginDate = date[0]
+      this.queryParam.endDate = date[1]
+    },
+    //  重置
+    resetSearchForm () {
+      this.$refs.rangeDate.resetDate(this.time)
+      this.queryParam.beginDate = getDate.getThreeMonthDays().starttime
+      this.queryParam.endDate = getDate.getCurrMonthDays().endtime
+      this.queryParam.targetName = ''
+      this.queryParam.allocateTypeSn = undefined
+      this.queryParam.state = undefined
+      this.queryParam.allocateNo = ''
+      this.$refs.table.refresh(true)
+    },
+    //  删除
+    handleDel (row) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '删除后不可恢复,确定要进行删除吗?',
+        centered: true,
+        onOk () {
+          _this.spinning = true
+          allocateBillDel({ sn: row.allocateSn }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$refs.table.refresh()
+              _this.spinning = false
+            } else {
+              _this.spinning = false
+            }
+          })
+        }
+      })
+    },
+    //  审核
+    handleExamine (row) {
+      this.auditInfo = row
+      this.visibleAudit = true
+    },
+    // 审核
+    auditOrder (state) {
+      const _this = this
+      _this.spinningAudit = true
+      allocateBillAudit({ sn: this.auditInfo.allocateSn, state: state }).then(res => {
+        if (res.status == 200) {
+          _this.visibleAudit = false
+          _this.$message.success(res.message)
+          _this.$refs.table.refresh()
+          _this.spinningAudit = false
+        } else {
+          _this.visibleAudit = false
+          _this.spinningAudit = false
+        }
+      })
+    },
+    //  详情
+    handleDetail (row) {
+      if (this.$hasPermissions('M_transferOut_detail')) {
+        this.$router.push({ name: 'transferReturnDetail', params: { sn: row.allocateSn } })
+      }
+    },
+    //  编辑
+    handleEdit (row) {
+      this.$router.push({ name: row.grabFlag == 1 ? 'transferReturnGrpEdit' : 'transferReturnEdit', params: { sn: row.allocateSn, dealerLevel: row.dealerLevel } })
+    },
+    //  导出
+    handleExport () {
+      const _this = this
+      const params = this.queryParam
+      this.exportLoading = true
+      this.spinning = true
+      hdExportExcel(allocateBillExport, params, '调拨列表', function () {
+        _this.exportLoading = false
+        _this.spinning = false
+      })
+    },
+    pageInit () {
+      const _this = this
+      this.$nextTick(() => { // 页面渲染完成后的回调
+        _this.setTableH()
+      })
+      this.openModal = false
+    },
+    setTableH () {
+      const tableSearchH = this.$refs.tableSearch.offsetHeight
+      this.tableHeight = window.innerHeight - tableSearchH - 238
+    }
+  },
+  watch: {
+    advanced (newValue, oldValue) {
+      const _this = this
+      this.$nextTick(() => { // 页面渲染完成后的回调
+        _this.setTableH()
+      })
+    },
+    '$store.state.app.winHeight' (newValue, oldValue) { //  窗口变更时,需同时更改表格高度
+      this.setTableH()
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
+      this.pageInit()
+      this.resetSearchForm()
+    }
+  },
+  activated () {
+    // 如果是新页签打开,则重置当前页面
+    if (this.$store.state.app.isNewTab) {
+      this.pageInit()
+      this.resetSearchForm()
+    }
+    // 仅刷新列表,不重置页面
+    if (this.$store.state.app.updateList) {
+      this.pageInit()
+      this.$refs.table.refresh()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {})
+  }
+}
+</script>
+<style lang="less">
+	.active{
+		color: #ed1c24;
+		cursor: pointer;
+	}
+	.common{
+		color: rgba(0, 0, 0);
+	}
+</style>

+ 167 - 0
src/views/allocationManagement/transferReturn/printModal.vue

@@ -0,0 +1,167 @@
+<template>
+  <a-modal
+    centered
+    :footer="null"
+    :maskClosable="false"
+    class="allocateBill-print-type-modal"
+    :title="modalTit"
+    v-model="isShow"
+    @cancle="isShow=false"
+    :width="600">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-form-model
+        id="allocateBill-print-form"
+        ref="ruleForm"
+        :model="form"
+        :rules="rules"
+        :label-col="formItemLayout.labelCol"
+        :wrapper-col="formItemLayout.wrapperCol"
+      >
+        <a-form-model-item label="调拨单号">{{ itemData&&itemData.allocateNo || '--' }}</a-form-model-item>
+        <a-form-model-item label="客户名称">{{ itemData&&itemData.targetName || '--' }}</a-form-model-item>
+        <a-form-model-item label="产品分类" prop="id" v-if="nowType=='dbflPrint'">
+          <a-select id="allocateBill-print-form" v-model="form.id" placeholder="请选择产品分类">
+            <a-select-option v-for="item in typeList" :value="item.id" :key="item.id">
+              <span v-if="item.id != 'all'">{{ item.productBrandName }} - {{ item.productTypeName3 }}</span>
+              <span v-else>全部</span>
+            </a-select-option>
+          </a-select>
+        </a-form-model-item>
+        <a-form-model-item label="产品价格" prop="priceType" v-if="nowType=='dbPrint'">
+          <a-radio-group v-model="form.priceType">
+            <a-radio value="ALLOCATE_BILL_PRICE">销售价</a-radio>
+            <a-radio value="ALLOCATE_BILL_COST">成本价</a-radio>
+            <a-radio value="ALLOCATE_BILL">不打印</a-radio>
+          </a-radio-group>
+        </a-form-model-item>
+      </a-form-model>
+      <div class="btn-cont">
+        <a-button type="primary" id="allocateBill-print-save" @click="handleSave('preview')">打印预览</a-button>
+        <a-button id="allocateBill-print-back" @click="handleSave('print')" style="margin-left: 15px;">快捷打印</a-button>
+      </div>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+import { allocateBillProductTypeList } from '@/api/allocateBill'
+export default {
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    },
+    itemData: {
+      type: Object,
+      default: () => {
+        return null
+      }
+    },
+    nowType: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  是否打开弹框
+      form: {
+        id: 'all',
+        priceType: undefined
+      },
+      rules: {
+        id: [{ required: true, message: '请选择产品分类', trigger: 'change' }],
+        priceType: [{ required: true, message: '请选择产品价格', trigger: 'change' }]
+      },
+      formItemLayout: {
+        labelCol: { span: 6 },
+        wrapperCol: { span: 18 }
+      },
+      spinning: false,
+      typeList: []
+    }
+  },
+  computed: {
+    modalTit () {
+      let title = ''
+      if (this.nowType == 'dbPrint') {
+        title = '调拨打印'
+      } else if (this.nowType == 'dbflPrint') {
+        title = '调拨分类打印'
+      }
+      return title
+    }
+  },
+  methods: {
+    // 确认
+    handleSave (type) {
+      const _this = this
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          if (_this.nowType == 'dbflPrint') {
+            const item = _this.typeList.find(item => item.id == _this.form.id)
+            if (item) {
+              const obj = {
+                allocateSn: _this.itemData.allocateSn,
+                productBrandSn: item.productBrandSn,
+                productTypeSn3: item.productTypeSn3,
+                printType: 'ALLOCATE_BILL_TYPE',
+                isPreview: type == 'preview' ? 1 : 0
+              }
+              _this.$emit('ok', obj)
+            }
+          } else {
+            const obj = {
+              allocateSn: _this.itemData.allocateSn,
+              printType: _this.form.priceType,
+              isPreview: type == 'preview' ? 1 : 0
+            }
+            _this.$emit('ok', obj)
+          }
+          _this.isShow = false
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    },
+    // 获取该销售单产品二级分类
+    getTypeData () {
+      this.typeList = [{ id: 'all' }]
+      allocateBillProductTypeList({ sn: this.itemData.allocateSn || null }).then(res => {
+        if (res.status == 200) {
+          if (res.data && res.data.length > 0) {
+            this.typeList = [...this.typeList, ...res.data]
+          }
+        }
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.$refs.ruleForm.resetFields()
+      } else {
+        if (this.nowType == 'dbflPrint') {
+          this.getTypeData()
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .allocateBill-print-type-modal{
+    .btn-cont {
+      text-align: center;
+      margin: 35px 0 10px;
+    }
+  }
+</style>