浏览代码

采购退货不同步

lilei 3 年之前
父节点
当前提交
fbd4d8846f

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

@@ -84,6 +84,17 @@ export default {
         this.$emit('change', obj, _.find(this.dataList, ['code', obj]))
       }
     }
+    if(this.showType === 'radio'){
+      return (
+        <a-radio-group vModel={props.value} {...{ props, on: on }} >,
+          {
+            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 }}>

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

@@ -774,6 +774,65 @@ export const asyncRouterMap = [
                 }
               }
             ]
+          },
+          // 采购退货-不同步
+          {
+            path: '/purchasingManagement/purchaseReturnOutSync',
+            redirect: '/purchasingManagement/purchaseReturnOutSync/list',
+            name: 'purchaseReturnOutSync',
+            component: BlankLayout,
+            meta: {
+              title: '采购退货',
+              icon: 'money-collect',
+              permission: 'M_purchaseReturn_outSnycList'
+            },
+            hideChildrenInMenu: true,
+            children: [
+              {
+                path: 'list',
+                name: 'purchaseReturnOutSyncList',
+                component: () => import(/* webpackChunkName: "purchasingManagement" */ '@/views/purchasingManagement/purchaseReturnOutSync/list.vue'),
+                meta: {
+                  title: '采购退货列表',
+                  icon: 'money-collect',
+                  hidden: true,
+                  permission: 'M_purchaseReturn_outSnycList'
+                }
+              },
+              {
+                path: 'edit/:id/:sn/:name',
+                name: 'purchaseReturnOutSyncEdit',
+                component: () => import(/* webpackChunkName: "purchasingManagement" */ '@/views/purchasingManagement/purchaseReturnOutSync/edit.vue'),
+                meta: {
+                  title: '采购退货单(不抓单)',
+                  icon: 'money-collect',
+                  hidden: true,
+                  permission: 'B_purchaseReturn_outSnycAdd'
+                }
+              },
+              {
+                path: 'edit/:id/:sn/:name',
+                name: 'purchaseReturnOutSyncGrapEdit',
+                component: () => import(/* webpackChunkName: "purchasingManagement" */ '@/views/purchasingManagement/purchaseReturnOutSync/grapEdit.vue'),
+                meta: {
+                  title: '采购退货单(抓单)',
+                  icon: 'money-collect',
+                  hidden: true,
+                  permission: 'B_purchaseReturn_outSnycEdit'
+                }
+              },
+              {
+                path: 'detail/:sn',
+                name: 'purchaseReturnOutSyncDetail',
+                component: () => import(/* webpackChunkName: "purchasingManagement" */ '@/views/purchasingManagement/purchaseReturnOutSync/detail.vue'),
+                meta: {
+                  title: '采购退货详情',
+                  icon: 'money-collect',
+                  hidden: true,
+                  permission: 'B_purchaseReturn_outSnycDetail'
+                }
+              }
+            ]
           }
         ]
       },

+ 7 - 2
src/views/purchasingManagement/purchaseReturn/list.vue

@@ -78,6 +78,10 @@
           <stateIcon :title="record.stateDictValue" v-if="record.state!='AUDIT_REJECT'" :state="record.state == 'WAIT_BACK'||record.state=='CHECKED'||record.state == 'FINISH'?'1':'2'"></stateIcon>
           <stateIcon :title="record.stateDictValue" v-else :state="0"></stateIcon>
         </template>
+        <!-- 出库 -->
+        <template slot="waitOut" slot-scope="text, record">
+          <stateIcon :state="record.hasStockBill == '1'?'1':'2'"></stateIcon>
+        </template>
         <!-- 收款 -->
         <template slot="financial" slot-scope="text, record">
           <stateIcon :title="record.settleStateDictValue" :state="record.settleState == 'FINISH'?'1':'2'"></stateIcon>
@@ -94,7 +98,7 @@
           <a-button
             size="small"
             type="link"
-            v-if="record.state == 'CHECKED' && $hasPermissions('B_purchaseReturnOutStock')"
+            v-if="record.hasStockBill == '1' && $hasPermissions('B_purchaseReturnOutStock')"
             @click="handleWarehouse(record)"
             class="button-primary"
             id="bulkReturnGoodsList-warehouse-btn">生成出库单</a-button>
@@ -112,7 +116,7 @@
             v-if="(record.state == 'WAIT_SUBMIT' || record.state == 'AUDIT_REJECT') && $hasPermissions('B_purchaseReturnDel')"
             @click="handleDel(record)"
             id="purchaseReturnList-del-btn">删除</a-button>
-          <span v-if="!((record.state == 'WAIT_SUBMIT' || record.state == 'AUDIT_REJECT') && ($hasPermissions('B_purchaseReturnEdit') || $hasPermissions('B_purchaseReturnDel'))) && !(record.state == 'CHECKED' && ($hasPermissions('B_purchaseReturnOutStock') || $hasPermissions('B_purchaseReturnFinishBill')))">--</span>
+          <span v-if="!((record.state == 'WAIT_SUBMIT' || record.state == 'AUDIT_REJECT') && ($hasPermissions('B_purchaseReturnEdit') || $hasPermissions('B_purchaseReturnDel'))) && !(record.hasStockBill == '1' && ($hasPermissions('B_purchaseReturnOutStock') || $hasPermissions('B_purchaseReturnFinishBill')))">--</span>
         </template>
       </s-table>
     </a-spin>
@@ -158,6 +162,7 @@ export default {
         { title: '扣减库存', dataIndex: 'hasStockBill', width: '6%', align: 'center', customRender: function (text) { return ['否', '是'][text] } },
         { title: '业务状态', dataIndex: 'stateDictValue', width: '8%', align: 'center', customRender: function (text) { return text || '--' } },
         { title: '审核', scopedSlots: { customRender: 'audit' }, width: '3%', align: 'center' },
+        { title: '出库', scopedSlots: { customRender: 'waitOut' }, width: '3%', align: 'center' },
         { title: '收款', scopedSlots: { customRender: 'financial' }, width: '3%', align: 'center' },
         // { title: '财务状态', dataIndex: 'settleStateDictValue', width: '8%', align: 'center', customRender: function (text) { return text || '--' } },
         { title: '操作', scopedSlots: { customRender: 'action' }, width: '13%', align: 'center' }

+ 188 - 0
src/views/purchasingManagement/purchaseReturnOutSync/basicInfoModal.vue

@@ -0,0 +1,188 @@
+<template>
+  <a-modal
+    centered
+    class="purchaseOrder-basicInfo-modal"
+    :footer="null"
+    :maskClosable="false"
+    title="新增采购单"
+    v-model="isShow"
+    @cancel="isShow=false"
+    :width="800">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-form-model
+        id="purchaseOrder-basicInfo-form"
+        ref="ruleForm"
+        :model="form"
+        :rules="rules"
+        :label-col="formItemLayout.labelCol"
+        :wrapper-col="formItemLayout.wrapperCol" >
+        <a-form-model-item label="供应商" prop="purchaseTargetSn">
+          <a-radio-group
+            name="radioGroup"
+            v-model="form.purchaseTargetSn"
+            @change="tragetTypeChange"
+            v-if="purchaseTragetType.length"
+            id="purchaseOrder-basicInfo-purchaseTargetSn" >
+            <a-radio v-for="item in purchaseTragetType" :key="item.purchaseTargetSn" :value="item.purchaseTargetSn" class="radio-s">{{ item.purchaseTargetName }}</a-radio>
+          </a-radio-group>
+          <span v-else>没有可选择的供应商</span>
+        </a-form-model-item>
+        <a-form-model-item label="是否抓单" prop="grabFlag">
+          <v-select
+            code="FLAG"
+            showType="radio"
+            id="purchaseOrder-grabFlag"
+            v-model="form.grabFlag"
+            allowClear
+            placeholder="请选择"></v-select>
+        </a-form-model-item>
+        <a-form-model-item :wrapper-col="{ span: 12, offset: 6 }" style="text-align: center;">
+          <a-button type="primary" :loading="confirmLoading" @click="handleSubmit" id="chooseCustom-btn-submit">保存</a-button>
+          <a-button @click="isShow=false" style="margin-left: 15px" id="chooseCustom-btn-back">取消</a-button>
+        </a-form-model-item>
+      </a-form-model>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+import { VSelect } from '@/components'
+import { purchaseTargetList } from '@/api/purchase'
+import { purchaseReturnSave } from '@/api/purchaseReturn'
+export default {
+  name: 'BasicInfoModal',
+  components: { VSelect },
+  mixins: [commonMixin],
+  props: {
+    openModal: { //  弹框显示状态
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      spinning: false,
+      confirmLoading: false,
+      isShow: this.openModal, //  是否打开弹框
+      settleStyleList: [], // 支付方式
+      formItemLayout: {
+        labelCol: { span: 4 },
+        wrapperCol: { span: 18 }
+      },
+      form: {
+        purchaseTargetType: '', // 供应商
+        purchaseTargetSn: undefined,
+        purchaseTargetName: '',
+        grabFlag: '1'
+      },
+      rules: {
+        purchaseTargetSn: [
+          { required: true, message: '请选择供应商', trigger: 'change' }
+        ],
+        grabFlag: [
+          { required: true, message: '请选择抓单类型', trigger: 'change' }
+        ]
+      },
+      purchaseTragetType: []
+    }
+  },
+  methods: {
+    resetForm () {
+      this.$refs.ruleForm.resetFields()
+      this.form.purchaseTargetType = ''
+      this.form.purchaseTargetSn = undefined
+      this.form.purchaseTargetName = ''
+    },
+    // 供应商change
+    tragetTypeChange (e) {
+      const val = e.target.value
+      const ind = this.purchaseTragetType.findIndex(item => item.purchaseTargetSn == val)
+      if (ind != -1) {
+        this.form.purchaseTargetType = this.purchaseTragetType[ind].purchaseTargetType
+        this.form.purchaseTargetName = this.purchaseTragetType[ind].purchaseTargetName
+      }
+    },
+    //  保存
+    handleSubmit (e) {
+      e.preventDefault()
+      const _this = this
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          _this.spinning = true
+          purchaseReturnSave(_this.form).then(res => {
+            if (res.status == 200) {
+              _this.isShow = false
+              _this.$emit('ok', res.data)
+              _this.spinning = false
+              _this.$message.info(res.message)
+            } else {
+              _this.spinning = false
+            }
+          })
+        } else {
+          return false
+        }
+      })
+    },
+    // 编辑信息
+    setData (data) {
+      this.form = JSON.parse(JSON.stringify(data))
+    },
+    getParentDealer () {
+      const zb = this.$hasPermissions('B_PR_outSnycZB')
+      const sj = this.$hasPermissions('B_PR_outSnycSJ')
+      let params = {}
+      // 只能向上级退货
+      if (sj) {
+        params.purchaseTargetType = 'DEALER_UP'
+      }
+      // 只能向总部退货
+      if (zb) {
+        params.purchaseTargetType = 'SUPPLIER_SYS'
+      }
+      // 总部和上级都可以
+      if (sj && zb) {
+        params = {}
+      }
+      purchaseTargetList(params).then(res => {
+        if (res.status == 200 && res.data[0]) {
+          this.purchaseTragetType = res.data
+        } else {
+          this.purchaseTragetType = []
+        }
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (newValue, oldValue) {
+      if (!newValue) {
+        this.$emit('close')
+        this.resetForm()
+      } else {
+        this.getParentDealer()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .purchaseOrder-basicInfo-modal{
+    .ant-modal-body {
+      padding: 40px 40px 24px;
+    }
+    .radio-s{
+      margin-bottom: 8px;
+    }
+    .btn-cont {
+      text-align: center;
+      margin: 35px 0 10px;
+    }
+  }
+</style>

+ 184 - 0
src/views/purchasingManagement/purchaseReturnOutSync/detail.vue

@@ -0,0 +1,184 @@
+<template>
+  <div class="purchaseReturnDetail-wrap">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-page-header :ghost="false" :backIcon="false" class="purchaseReturnDetail-cont" :style="{ padding: !outBizSn ? '16px 24px' : '0px 24px' }" >
+        <!-- 自定义的二级文字标题 -->
+        <template slot="subTitle" v-if="!outBizSn">
+          <a id="purchaseReturnDetail-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="purchaseReturnDetail-edit-btn"
+            @click.stop="handleEdit">编辑</a-button>
+        </template>
+        <!-- 操作区,位于 title 行的行尾 -->
+        <template slot="extra" v-if="$hasPermissions('B_purchaseReturnPrint')">
+          <Print :disabled="dataSource.length==0" @handlePrint="handlePrint"></Print>
+        </template>
+      </a-page-header>
+      <!-- 基础信息 -->
+      <a-card size="small" :bordered="false" class="purchaseReturnDetail-cont">
+        <a-collapse :activeKey="['1']">
+          <a-collapse-panel key="1" header="基础信息">
+            <a-descriptions :column="3">
+              <a-descriptions-item label="客户名称">{{ basicInfoData&&basicInfoData.returnTargetName || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="采退单号">{{ basicInfoData&&basicInfoData.purchaseReturnNo || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="创建时间">{{ basicInfoData&&basicInfoData.createDate || '--' }}</a-descriptions-item>
+              <a-descriptions-item label="退货数量">{{ basicInfoData&&(basicInfoData.totalQty || basicInfoData.totalQty==0) ? basicInfoData.totalQty : '--' }}</a-descriptions-item>
+              <a-descriptions-item label="坏件数量">{{ basicInfoData&&(basicInfoData.totalBadQty || basicInfoData.totalBadQty == 0) ? basicInfoData.totalBadQty : '--' }}</a-descriptions-item>
+              <a-descriptions-item label="返库数量">{{ basicInfoData&&(basicInfoData.totalBackStockQty || basicInfoData.totalBackStockQty == 0) ? basicInfoData.totalBackStockQty : '--' }}</a-descriptions-item>
+              <a-descriptions-item label="退货金额">{{ basicInfoData&&(basicInfoData.totalAmount || basicInfoData.totalAmount == 0) ? basicInfoData.totalAmount : '--' }}</a-descriptions-item>
+            </a-descriptions>
+          </a-collapse-panel>
+        </a-collapse>
+      </a-card>
+      <!-- 产品详情 -->
+      <a-card size="small" :bordered="false" class="purchaseReturnDetail-cont">
+        <a-collapse :activeKey="['1']">
+          <a-collapse-panel key="1" header="产品详情">
+            <!-- 列表 -->
+            <s-table
+              class="sTable"
+              ref="table"
+              size="small"
+              :rowKey="(record) => record.id"
+              :columns="columns"
+              :data="loadData"
+              :defaultLoadData="false"
+              bordered>
+            </s-table>
+          </a-collapse-panel>
+        </a-collapse>
+      </a-card>
+    </a-spin>
+  </div>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+import { STable, VSelect } from '@/components'
+import Print from '@/views/common/print.vue'
+import { hdPrint } from '@/libs/JGPrint'
+import { getOperationalPrecision } from '@/libs/tools.js'
+import { purchaseReturnDetailSn, purchaseReturnDetailList, purchaseReturnDetailPrint, purchaseReturnDetailExport } from '@/api/purchaseReturn'
+export default {
+  name: 'PurchaseReturnDetail',
+  components: { STable, VSelect, Print },
+  mixins: [commonMixin],
+  props: {
+    outBizSn: { //  有值则为弹框,无值则为页面
+      type: [Number, String],
+      default: ''
+    }
+  },
+  data () {
+    return {
+      spinning: false,
+      // 表头
+      columns: [
+        { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
+        { title: '采购单号', dataIndex: 'purchaseBillNo', width: '17%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品编码', dataIndex: 'dealerProductEntity.code', width: '14%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品名称', dataIndex: 'dealerProductEntity.name', width: '14%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '售价', dataIndex: 'cost', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '退货数量', dataIndex: 'qty', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '坏件数量', dataIndex: 'badQty', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '返库数量', dataIndex: 'backStockQty', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '单位', dataIndex: 'dealerProductEntity.unit', width: '5%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '退货金额小计', dataIndex: 'purchaseReturnAmount', width: '10%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '退货原因', dataIndex: 'remarks', width: '12%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true }
+      ],
+      dataSource: [],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        return purchaseReturnDetailList(Object.assign(parameter, { purchaseReturnSn: 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
+              // 采购金额  由于数据库内小数位数为4位,页面则需显示2位。因此会做小数运算精度处理
+              data.list[i].purchaseReturnAmount = getOperationalPrecision(data.list[i].cost, data.list[i].qty)
+            }
+            this.disabled = false
+            this.dataSource = data.list
+          }
+          return data
+        })
+      },
+      basicInfoData: null //  基本信息
+    }
+  },
+  computed: {
+    isEdit () {
+      return ((this.basicInfoData && this.basicInfoData.state == 'WAIT_SUBMIT') || (this.basicInfoData && this.basicInfoData.state == 'AUDIT_REJECT')) && this.$hasPermissions('B_purchaseReturnEdit')
+    }
+  },
+  methods: {
+    // 打印预览/快捷打印
+    handlePrint (type, printerType) {
+      const _this = this
+      _this.spinning = true
+      let url = purchaseReturnDetailPrint
+      const params = { sn: this.$route.params.sn || this.outBizSn }
+      if (type == 'export') { //  导出
+        url = purchaseReturnDetailExport
+      }
+      // 打印或导出
+      hdPrint(printerType, type, url, params, '采购退货单', function () {
+        _this.spinning = false
+      })
+    },
+    //  返回列表
+    handleBack () {
+      this.$router.push({ path: '/purchasingManagement/purchaseReturn/list' })
+    },
+    // 基本信息
+    getDetail () {
+      purchaseReturnDetailSn({ sn: this.outBizSn || this.$route.params.sn }).then(res => {
+        if (res.status == 200) {
+          this.basicInfoData = res.data
+        } else {
+          this.basicInfoData = null
+        }
+      })
+    },
+    //  编辑
+    handleEdit () {
+      this.$router.push({ path: `/purchasingManagement/purchaseReturn/edit/${this.basicInfoData.id}/${this.basicInfoData.purchaseReturnSn}/${this.basicInfoData.returnTargetName}` })
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab || this.outBizSn) { // 页签刷新 或 为弹框时调用
+      this.$refs.table.refresh(true)
+      this.getDetail()
+    }
+  },
+  activated () {
+    // 如果是新页签打开或者进入新的子页(例:存在列表第2条数据编辑页页签时再打开第4条数据的编辑页),则重置当前页面
+    if (this.$store.state.app.isNewTab || !this.$store.state.app.isNewSubTab) {
+      this.$refs.table.refresh(true)
+      this.getDetail()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {})
+  }
+}
+</script>
+
+<style lang="less">
+  .purchaseReturnDetail-cont{
+    margin-bottom: 10px;
+    .timeline-box{
+      margin-top: 30px;
+      .auxiliary-txt{
+        color: #808695;
+      }
+    }
+  }
+</style>

+ 432 - 0
src/views/purchasingManagement/purchaseReturnOutSync/edit.vue

@@ -0,0 +1,432 @@
+<template>
+  <div class="purchaseReturnEdit-wrap">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-page-header :ghost="false" :backIcon="false" class="purchaseReturnEdit-back" >
+        <!-- 自定义的二级文字标题 -->
+        <template slot="subTitle">
+          <a id="purchaseReturnEdit-back-btn" href="javascript:;" @click="handleBack"><a-icon type="left" /> 返回列表</a>
+          <span style="margin: 0 15px;color: #666;">供应商名称:{{ $route.params.name || '--' }}</span>
+        </template>
+        <!-- 操作区,位于 title 行的行尾 -->
+        <template slot="extra" v-if="$hasPermissions('B_purchaseReturnPrint')">
+          <Print :disabled="dataSource.length==0" @handlePrint="handlePrint"></Print>
+        </template>
+      </a-page-header>
+      <!-- 选择产品 -->
+      <div class="purchaseReturnEdit-cont">
+        <a-collapse :activeKey="['1']">
+          <a-collapse-panel key="1" 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="purchaseBillNo">
+                      <a-input id="purchaseReturnEdit-purchaseBillNo" v-model.trim="queryParam.purchaseBillNo" placeholder="请输入采购单号" allowClear />
+                    </a-form-item>
+                  </a-col>
+                  <a-col :md="6" :sm="24">
+                    <a-form-item label="产品编码" prop="productCode">
+                      <a-input id="purchaseReturnEdit-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="purchaseReturnEdit-productName" v-model.trim="queryParam.productName" 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="purchaseReturnList-refresh">查询</a-button>
+                    <a-button style="margin-left: 8px" @click="resetSearchForm" :disabled="disabled" id="purchaseReturnList-reset">重置</a-button>
+                  </a-col>
+                </a-row>
+              </a-form>
+            </div>
+            <!-- 列表 -->
+            <s-table
+              class="sTable"
+              ref="table"
+              size="small"
+              :rowKey="(record) => record.id"
+              :columns="columns"
+              :data="loadData"
+              :defaultLoadData="false"
+              :pageSize="10"
+              :scroll="{ y: 149 }"
+              bordered>
+              <!-- 自定义表头 -->
+              <template slot="refundableQtyTitle">
+                <a-tooltip placement="top">
+                  <template slot="title">
+                    <span>同一个采购单,可多次退货,所以可退数量=采购数量-已退货数量</span>
+                  </template>
+                  可退数量<a-icon type="question-circle" :style="{ marginLeft: '3px' }" />
+                </a-tooltip>
+              </template>
+              <!-- 数量 -->
+              <template slot="returnQty" slot-scope="text, record">
+                <a-input-number
+                  size="small"
+                  id="purchaseReturnEdit-returnQty"
+                  v-model="record.returnQty"
+                  :precision="0"
+                  :min="1"
+                  :max="record.refundableQty"
+                  placeholder="请输入"
+                  style="width: 100%;" />
+              </template>
+              <!-- 操作 -->
+              <template slot="action" slot-scope="text, record">
+                <span v-if="record.refundableQty==0">--</span>
+                <a-button
+                  v-else
+                  size="small"
+                  type="link"
+                  class="button-primary"
+                  @click="handleAdd(record)"
+                  id="purchaseReturnEdit-add-btn">添加</a-button>
+              </template>
+            </s-table>
+          </a-collapse-panel>
+        </a-collapse>
+      </div>
+      <!-- 已选产品 -->
+      <a-card size="small" :bordered="false" class="purchaseReturnEdit-cont">
+        <a-collapse :activeKey="['1']">
+          <a-collapse-panel key="1">
+            <template slot="header">
+              已选产品
+              <a-button
+                size="small"
+                type="primary"
+                class="button-error"
+                id="purchaseReturnEdit-delAll-btn"
+                @click.stop="handleDel('', 'all')"
+                style="margin-right: 10px;float: right;">整单删除</a-button>
+            </template>
+            <!-- 列表 -->
+            <s-table
+              class="sTable"
+              ref="chooseTable"
+              size="small"
+              :rowKey="(record) => record.id"
+              :columns="chooseColumns"
+              :data="chooseLoadData"
+              :defaultLoadData="false"
+              :pageSize="10"
+              :scroll="{ y: 149 }"
+              bordered>
+              <!-- 退货数量 -->
+              <template slot="qty" slot-scope="text, record">
+                <a-input-number
+                  size="small"
+                  id="purchaseReturnEdit-qty"
+                  v-model="record.qty"
+                  :precision="0"
+                  :min="1"
+                  placeholder="请输入"
+                  @blur="e => qtyBlur(e.target.value, record)"
+                  style="width: 100%;" />
+              </template>
+              <!-- 退货原因 -->
+              <template slot="remarks" slot-scope="text, record">
+                <a-input
+                  size="small"
+                  id="purchaseReturnEdit-remarks"
+                  v-model.trim="record.remarks"
+                  :maxLength="30"
+                  placeholder="退货原因(最多30个字符)"
+                  @blur="e => remarksBlur(e.target.value, record)"
+                  style="width: 100%;" />
+              </template>
+              <!-- 操作 -->
+              <template slot="action" slot-scope="text, record">
+                <a-button size="small" type="link" class="button-error" @click="handleDel(record)" id="purchaseReturnEdit-del-btn">删除</a-button>
+              </template>
+            </s-table>
+          </a-collapse-panel>
+        </a-collapse>
+      </a-card>
+    </a-spin>
+    <a-card size="small" :bordered="false" class="affix-cont">
+      <a-button
+        type="primary"
+        id="purchaseReturnEdit-submit"
+        size="large"
+        :disabled="spinning"
+        class="button-primary"
+        @click="handleSubmit"
+        style="padding: 0 60px;">提交</a-button>
+    </a-card>
+  </div>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+import { STable, VSelect } from '@/components'
+import Print from '@/views/common/print.vue'
+import { hdPrint } from '@/libs/JGPrint'
+import {
+  purchaseReturnPurchaseBillDetailList,
+  purchaseReturnDetailList,
+  purchaseReturnDetailSave,
+  purchaseReturnDetailDel,
+  purchaseReturnSubmit,
+  purchaseReturnDelAll,
+  purchaseReturnDetailPrint,
+  purchaseReturnDetailExport } from '@/api/purchaseReturn'
+export default {
+  name: 'PurchaseReturnEdit',
+  components: { STable, VSelect, Print },
+  mixins: [commonMixin],
+  data () {
+    return {
+      spinning: false,
+      queryParam: {
+        purchaseBillNo: '',
+        productCode: '',
+        productName: ''
+      },
+      dataSource: [],
+      disabled: false, //  查询、重置按钮是否可操作
+      advanced: false, // 高级搜索 展开/关闭
+      // 表头
+      columns: [
+        { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
+        { title: '采购单号', dataIndex: 'purchaseBillNo', width: '14%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品编码', dataIndex: 'dealerProductEntity.code', width: '13%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品名称', dataIndex: 'dealerProductEntity.name', width: '13%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '采购总数', dataIndex: 'qty', width: '7%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { slots: { title: 'refundableQtyTitle' }, dataIndex: 'refundableQty', width: '9%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '库存数量', dataIndex: 'stock.currentStockQty', width: '7%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '缺货数量', dataIndex: 'cancelQty', width: '7%', align: 'center' },
+        { title: '退货数量', scopedSlots: { customRender: 'returnQty' }, width: '8%', align: 'center' },
+        { title: '采购价', dataIndex: 'price', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '单位', dataIndex: 'dealerProductEntity.unit', width: '5%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: '7%', align: 'center' }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        return purchaseReturnPurchaseBillDetailList(Object.assign(parameter, this.queryParam)).then(res => {
+          const data = res.data
+          const no = (data.pageNo - 1) * data.pageSize
+          for (var i = 0; i < data.list.length; i++) {
+            data.list[i].no = no + i + 1
+          }
+          this.disabled = false
+          return data
+        })
+      },
+      // 表头
+      chooseColumns: [
+        { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
+        { title: '采购单号', dataIndex: 'purchaseBillNo', width: '15%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品编码', dataIndex: 'dealerProductEntity.code', width: '14%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品名称', dataIndex: 'dealerProductEntity.name', width: '15%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '采购总数', dataIndex: 'purchaseBillQty', width: '7%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '退货数量', scopedSlots: { customRender: 'qty' }, width: '10%', align: 'center' },
+        { title: '采购价', dataIndex: 'cost', width: '7%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '单位', dataIndex: 'dealerProductEntity.unit', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '退货原因', scopedSlots: { customRender: 'remarks' }, width: '15%', align: 'center' },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: '8%', align: 'center' }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      chooseLoadData: parameter => {
+        return purchaseReturnDetailList(Object.assign(parameter, { purchaseReturnSn: this.$route.params.sn, orderBy: 'qpls_purchase_return_bill_detail.CREATE_DATE desc' })).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
+            data.list[i].qtyBackups = data.list[i].qty
+            data.list[i].remarksBackups = data.list[i].remarks
+            data.list[i].refundableQty = data.list[i].purchaseBillRefundableQty + data.list[i].qty
+          }
+          this.dataSource = data.list
+          return data
+        })
+      }
+    }
+  },
+  methods: {
+    // 打印预览/快捷打印
+    handlePrint (type, printerType) {
+      const _this = this
+      _this.spinning = true
+      let url = purchaseReturnDetailPrint
+      const params = { sn: this.$route.params.sn }
+      if (type == 'export') { //  导出
+        url = purchaseReturnDetailExport
+      }
+      // 打印或导出
+      hdPrint(printerType, type, url, params, '采购退货单', function () {
+        _this.spinning = false
+      })
+    },
+    //  重置
+    resetSearchForm () {
+      this.queryParam.purchaseBillNo = ''
+      this.queryParam.productCode = ''
+      this.queryParam.productName = ''
+      this.$refs.table.refresh(true)
+    },
+    //  添加/编辑
+    handleAdd (row, isEdit) {
+      // 添加时退货数量字段名为returnQty,编辑时退货数量字段名为qty
+      if (!isEdit && !row.returnQty) {
+        this.$message.warning('请输入退货数量')
+        return
+      }
+      const params = {
+        id: isEdit ? row.id : undefined,
+        purchaseReturnSn: this.$route.params.sn,
+        purchaseBillSn: row.purchaseBillSn,
+        purchaseBillNo: row.purchaseBillNo,
+        purchaseBillDetailSn: row.purchaseBillDetailSn,
+        qty: isEdit ? row.qty : row.returnQty, //  退货数量
+        productSn: row.productSn,
+        cost: row.price,
+        remarks: row.remarks,
+        promotionFlag: row.promotionFlag
+      }
+      if (isEdit) { // 编辑
+        // 清空退货数量时,值应保持未清空前的值,因退货数量都不可为空
+        if (!row.qty) {
+          row.qty = row.qtyBackups
+          return
+        }
+      }
+      this.spinning = true
+      purchaseReturnDetailSave(params).then(res => {
+        if (res.status == 200) {
+          this.$message.success(res.message)
+          // this.$refs.table.refresh()
+          this.$refs.chooseTable.refresh()
+          this.spinning = false
+        } else {
+          this.spinning = false
+        }
+      })
+    },
+    // 双击快速添加
+    handleClickRow (record) {
+      return {
+        on: {
+          dblclick: (event) => {
+            this.handleAdd(record)
+          }
+        }
+      }
+    },
+    // 导入明细
+    handleImport () {},
+    //  删除
+    handleDel (row, isAll) {
+      const _this = this
+      const content = isAll ? '删除后不可恢复,确定要进行整单删除吗?' : '删除后不可恢复,确定要进行删除吗?'
+      this.$confirm({
+        title: '提示',
+        content: content,
+        centered: true,
+        onOk () {
+          if (isAll) { //  整单删除
+            _this.spinning = true
+            purchaseReturnDelAll({ purchaseReturnSn: _this.$route.params.sn }).then(res => {
+              if (res.status == 200) {
+                _this.$message.success(res.message)
+                // _this.$refs.table.refresh()
+                _this.$refs.chooseTable.refresh()
+                _this.spinning = false
+              } else {
+                _this.spinning = false
+              }
+            })
+          } else { //  单个删除
+            _this.spinning = true
+            purchaseReturnDetailDel({ id: row.id }).then(res => {
+              if (res.status == 200) {
+                _this.$message.success(res.message)
+                // _this.$refs.table.refresh()
+                _this.$refs.chooseTable.refresh()
+                _this.spinning = false
+              } else {
+                _this.spinning = false
+              }
+            })
+          }
+        }
+      })
+    },
+    //  提交
+    handleSubmit () {
+      const _this = this
+      _this.spinning = true
+      purchaseReturnSubmit({ id: this.$route.params.id }).then(res => {
+        if (res.status == 200) {
+          this.$message.success(res.message)
+          setTimeout(() => {
+            _this.handleBack()
+            _this.spinning = false
+          }, 1000)
+        } else {
+          _this.spinning = false
+        }
+      })
+    },
+    //  返回列表
+    handleBack () {
+      this.$router.push({ path: '/purchasingManagement/purchaseReturn/list' })
+    },
+    // 已选产品 退货数量  blur
+    qtyBlur (val, record) {
+      //  光标移出,值发生改变再调用编辑接口
+      if (val != record.qtyBackups) {
+        this.handleAdd(record, 'edit')
+      }
+    },
+    // 已选产品 退货原因  blur
+    remarksBlur (val, record) {
+      if (val && (val != record.remarksBackups)) {
+        this.handleAdd(record, 'edit')
+      }
+    },
+    filterOption (input, option) {
+      return (
+        option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
+      )
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
+      this.$refs.chooseTable.refresh(true)
+      this.resetSearchForm()
+    }
+  },
+  activated () {
+    // 如果是新页签打开或者进入新的子页(例:存在列表第2条数据编辑页页签时再打开第4条数据的编辑页),则重置当前页面
+    if (this.$store.state.app.isNewTab || !this.$store.state.app.isNewSubTab) {
+      this.$refs.chooseTable.refresh(true)
+      this.resetSearchForm()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {})
+  }
+}
+</script>
+
+<style lang="less">
+  .purchaseReturnEdit-wrap{
+    position: relative;
+    height: 100%;
+    padding-bottom: 51px;
+    box-sizing: border-box;
+    >.ant-spin-nested-loading{
+      overflow-y: scroll;
+      height: 100%;
+    }
+    .purchaseReturnEdit-back, .purchaseReturnEdit-cont{
+      margin-bottom: 10px;
+    }
+  }
+</style>

+ 432 - 0
src/views/purchasingManagement/purchaseReturnOutSync/grapEdit.vue

@@ -0,0 +1,432 @@
+<template>
+  <div class="purchaseReturnEdit-wrap">
+    <a-spin :spinning="spinning" tip="Loading...">
+      <a-page-header :ghost="false" :backIcon="false" class="purchaseReturnEdit-back" >
+        <!-- 自定义的二级文字标题 -->
+        <template slot="subTitle">
+          <a id="purchaseReturnEdit-back-btn" href="javascript:;" @click="handleBack"><a-icon type="left" /> 返回列表</a>
+          <span style="margin: 0 15px;color: #666;">供应商名称:{{ $route.params.name || '--' }}</span>
+        </template>
+        <!-- 操作区,位于 title 行的行尾 -->
+        <template slot="extra" v-if="$hasPermissions('B_purchaseReturnPrint')">
+          <Print :disabled="dataSource.length==0" @handlePrint="handlePrint"></Print>
+        </template>
+      </a-page-header>
+      <!-- 选择产品 -->
+      <div class="purchaseReturnEdit-cont">
+        <a-collapse :activeKey="['1']">
+          <a-collapse-panel key="1" 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="purchaseBillNo">
+                      <a-input id="purchaseReturnEdit-purchaseBillNo" v-model.trim="queryParam.purchaseBillNo" placeholder="请输入采购单号" allowClear />
+                    </a-form-item>
+                  </a-col>
+                  <a-col :md="6" :sm="24">
+                    <a-form-item label="产品编码" prop="productCode">
+                      <a-input id="purchaseReturnEdit-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="purchaseReturnEdit-productName" v-model.trim="queryParam.productName" 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="purchaseReturnList-refresh">查询</a-button>
+                    <a-button style="margin-left: 8px" @click="resetSearchForm" :disabled="disabled" id="purchaseReturnList-reset">重置</a-button>
+                  </a-col>
+                </a-row>
+              </a-form>
+            </div>
+            <!-- 列表 -->
+            <s-table
+              class="sTable"
+              ref="table"
+              size="small"
+              :rowKey="(record) => record.id"
+              :columns="columns"
+              :data="loadData"
+              :defaultLoadData="false"
+              :pageSize="10"
+              :scroll="{ y: 149 }"
+              bordered>
+              <!-- 自定义表头 -->
+              <template slot="refundableQtyTitle">
+                <a-tooltip placement="top">
+                  <template slot="title">
+                    <span>同一个采购单,可多次退货,所以可退数量=采购数量-已退货数量</span>
+                  </template>
+                  可退数量<a-icon type="question-circle" :style="{ marginLeft: '3px' }" />
+                </a-tooltip>
+              </template>
+              <!-- 数量 -->
+              <template slot="returnQty" slot-scope="text, record">
+                <a-input-number
+                  size="small"
+                  id="purchaseReturnEdit-returnQty"
+                  v-model="record.returnQty"
+                  :precision="0"
+                  :min="1"
+                  :max="record.refundableQty"
+                  placeholder="请输入"
+                  style="width: 100%;" />
+              </template>
+              <!-- 操作 -->
+              <template slot="action" slot-scope="text, record">
+                <span v-if="record.refundableQty==0">--</span>
+                <a-button
+                  v-else
+                  size="small"
+                  type="link"
+                  class="button-primary"
+                  @click="handleAdd(record)"
+                  id="purchaseReturnEdit-add-btn">添加</a-button>
+              </template>
+            </s-table>
+          </a-collapse-panel>
+        </a-collapse>
+      </div>
+      <!-- 已选产品 -->
+      <a-card size="small" :bordered="false" class="purchaseReturnEdit-cont">
+        <a-collapse :activeKey="['1']">
+          <a-collapse-panel key="1">
+            <template slot="header">
+              已选产品
+              <a-button
+                size="small"
+                type="primary"
+                class="button-error"
+                id="purchaseReturnEdit-delAll-btn"
+                @click.stop="handleDel('', 'all')"
+                style="margin-right: 10px;float: right;">整单删除</a-button>
+            </template>
+            <!-- 列表 -->
+            <s-table
+              class="sTable"
+              ref="chooseTable"
+              size="small"
+              :rowKey="(record) => record.id"
+              :columns="chooseColumns"
+              :data="chooseLoadData"
+              :defaultLoadData="false"
+              :pageSize="10"
+              :scroll="{ y: 149 }"
+              bordered>
+              <!-- 退货数量 -->
+              <template slot="qty" slot-scope="text, record">
+                <a-input-number
+                  size="small"
+                  id="purchaseReturnEdit-qty"
+                  v-model="record.qty"
+                  :precision="0"
+                  :min="1"
+                  placeholder="请输入"
+                  @blur="e => qtyBlur(e.target.value, record)"
+                  style="width: 100%;" />
+              </template>
+              <!-- 退货原因 -->
+              <template slot="remarks" slot-scope="text, record">
+                <a-input
+                  size="small"
+                  id="purchaseReturnEdit-remarks"
+                  v-model.trim="record.remarks"
+                  :maxLength="30"
+                  placeholder="退货原因(最多30个字符)"
+                  @blur="e => remarksBlur(e.target.value, record)"
+                  style="width: 100%;" />
+              </template>
+              <!-- 操作 -->
+              <template slot="action" slot-scope="text, record">
+                <a-button size="small" type="link" class="button-error" @click="handleDel(record)" id="purchaseReturnEdit-del-btn">删除</a-button>
+              </template>
+            </s-table>
+          </a-collapse-panel>
+        </a-collapse>
+      </a-card>
+    </a-spin>
+    <a-card size="small" :bordered="false" class="affix-cont">
+      <a-button
+        type="primary"
+        id="purchaseReturnEdit-submit"
+        size="large"
+        :disabled="spinning"
+        class="button-primary"
+        @click="handleSubmit"
+        style="padding: 0 60px;">提交</a-button>
+    </a-card>
+  </div>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+import { STable, VSelect } from '@/components'
+import Print from '@/views/common/print.vue'
+import { hdPrint } from '@/libs/JGPrint'
+import {
+  purchaseReturnPurchaseBillDetailList,
+  purchaseReturnDetailList,
+  purchaseReturnDetailSave,
+  purchaseReturnDetailDel,
+  purchaseReturnSubmit,
+  purchaseReturnDelAll,
+  purchaseReturnDetailPrint,
+  purchaseReturnDetailExport } from '@/api/purchaseReturn'
+export default {
+  name: 'PurchaseReturnEdit',
+  components: { STable, VSelect, Print },
+  mixins: [commonMixin],
+  data () {
+    return {
+      spinning: false,
+      queryParam: {
+        purchaseBillNo: '',
+        productCode: '',
+        productName: ''
+      },
+      dataSource: [],
+      disabled: false, //  查询、重置按钮是否可操作
+      advanced: false, // 高级搜索 展开/关闭
+      // 表头
+      columns: [
+        { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
+        { title: '采购单号', dataIndex: 'purchaseBillNo', width: '14%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品编码', dataIndex: 'dealerProductEntity.code', width: '13%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品名称', dataIndex: 'dealerProductEntity.name', width: '13%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '采购总数', dataIndex: 'qty', width: '7%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { slots: { title: 'refundableQtyTitle' }, dataIndex: 'refundableQty', width: '9%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '库存数量', dataIndex: 'stock.currentStockQty', width: '7%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '缺货数量', dataIndex: 'cancelQty', width: '7%', align: 'center' },
+        { title: '退货数量', scopedSlots: { customRender: 'returnQty' }, width: '8%', align: 'center' },
+        { title: '采购价', dataIndex: 'price', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '单位', dataIndex: 'dealerProductEntity.unit', width: '5%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: '7%', align: 'center' }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        return purchaseReturnPurchaseBillDetailList(Object.assign(parameter, this.queryParam)).then(res => {
+          const data = res.data
+          const no = (data.pageNo - 1) * data.pageSize
+          for (var i = 0; i < data.list.length; i++) {
+            data.list[i].no = no + i + 1
+          }
+          this.disabled = false
+          return data
+        })
+      },
+      // 表头
+      chooseColumns: [
+        { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
+        { title: '采购单号', dataIndex: 'purchaseBillNo', width: '15%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品编码', dataIndex: 'dealerProductEntity.code', width: '14%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '产品名称', dataIndex: 'dealerProductEntity.name', width: '15%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
+        { title: '采购总数', dataIndex: 'purchaseBillQty', width: '7%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '退货数量', scopedSlots: { customRender: 'qty' }, width: '10%', align: 'center' },
+        { title: '采购价', dataIndex: 'cost', width: '7%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '单位', dataIndex: 'dealerProductEntity.unit', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '退货原因', scopedSlots: { customRender: 'remarks' }, width: '15%', align: 'center' },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: '8%', align: 'center' }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      chooseLoadData: parameter => {
+        return purchaseReturnDetailList(Object.assign(parameter, { purchaseReturnSn: this.$route.params.sn, orderBy: 'qpls_purchase_return_bill_detail.CREATE_DATE desc' })).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
+            data.list[i].qtyBackups = data.list[i].qty
+            data.list[i].remarksBackups = data.list[i].remarks
+            data.list[i].refundableQty = data.list[i].purchaseBillRefundableQty + data.list[i].qty
+          }
+          this.dataSource = data.list
+          return data
+        })
+      }
+    }
+  },
+  methods: {
+    // 打印预览/快捷打印
+    handlePrint (type, printerType) {
+      const _this = this
+      _this.spinning = true
+      let url = purchaseReturnDetailPrint
+      const params = { sn: this.$route.params.sn }
+      if (type == 'export') { //  导出
+        url = purchaseReturnDetailExport
+      }
+      // 打印或导出
+      hdPrint(printerType, type, url, params, '采购退货单', function () {
+        _this.spinning = false
+      })
+    },
+    //  重置
+    resetSearchForm () {
+      this.queryParam.purchaseBillNo = ''
+      this.queryParam.productCode = ''
+      this.queryParam.productName = ''
+      this.$refs.table.refresh(true)
+    },
+    //  添加/编辑
+    handleAdd (row, isEdit) {
+      // 添加时退货数量字段名为returnQty,编辑时退货数量字段名为qty
+      if (!isEdit && !row.returnQty) {
+        this.$message.warning('请输入退货数量')
+        return
+      }
+      const params = {
+        id: isEdit ? row.id : undefined,
+        purchaseReturnSn: this.$route.params.sn,
+        purchaseBillSn: row.purchaseBillSn,
+        purchaseBillNo: row.purchaseBillNo,
+        purchaseBillDetailSn: row.purchaseBillDetailSn,
+        qty: isEdit ? row.qty : row.returnQty, //  退货数量
+        productSn: row.productSn,
+        cost: row.price,
+        remarks: row.remarks,
+        promotionFlag: row.promotionFlag
+      }
+      if (isEdit) { // 编辑
+        // 清空退货数量时,值应保持未清空前的值,因退货数量都不可为空
+        if (!row.qty) {
+          row.qty = row.qtyBackups
+          return
+        }
+      }
+      this.spinning = true
+      purchaseReturnDetailSave(params).then(res => {
+        if (res.status == 200) {
+          this.$message.success(res.message)
+          // this.$refs.table.refresh()
+          this.$refs.chooseTable.refresh()
+          this.spinning = false
+        } else {
+          this.spinning = false
+        }
+      })
+    },
+    // 双击快速添加
+    handleClickRow (record) {
+      return {
+        on: {
+          dblclick: (event) => {
+            this.handleAdd(record)
+          }
+        }
+      }
+    },
+    // 导入明细
+    handleImport () {},
+    //  删除
+    handleDel (row, isAll) {
+      const _this = this
+      const content = isAll ? '删除后不可恢复,确定要进行整单删除吗?' : '删除后不可恢复,确定要进行删除吗?'
+      this.$confirm({
+        title: '提示',
+        content: content,
+        centered: true,
+        onOk () {
+          if (isAll) { //  整单删除
+            _this.spinning = true
+            purchaseReturnDelAll({ purchaseReturnSn: _this.$route.params.sn }).then(res => {
+              if (res.status == 200) {
+                _this.$message.success(res.message)
+                // _this.$refs.table.refresh()
+                _this.$refs.chooseTable.refresh()
+                _this.spinning = false
+              } else {
+                _this.spinning = false
+              }
+            })
+          } else { //  单个删除
+            _this.spinning = true
+            purchaseReturnDetailDel({ id: row.id }).then(res => {
+              if (res.status == 200) {
+                _this.$message.success(res.message)
+                // _this.$refs.table.refresh()
+                _this.$refs.chooseTable.refresh()
+                _this.spinning = false
+              } else {
+                _this.spinning = false
+              }
+            })
+          }
+        }
+      })
+    },
+    //  提交
+    handleSubmit () {
+      const _this = this
+      _this.spinning = true
+      purchaseReturnSubmit({ id: this.$route.params.id }).then(res => {
+        if (res.status == 200) {
+          this.$message.success(res.message)
+          setTimeout(() => {
+            _this.handleBack()
+            _this.spinning = false
+          }, 1000)
+        } else {
+          _this.spinning = false
+        }
+      })
+    },
+    //  返回列表
+    handleBack () {
+      this.$router.push({ path: '/purchasingManagement/purchaseReturn/list' })
+    },
+    // 已选产品 退货数量  blur
+    qtyBlur (val, record) {
+      //  光标移出,值发生改变再调用编辑接口
+      if (val != record.qtyBackups) {
+        this.handleAdd(record, 'edit')
+      }
+    },
+    // 已选产品 退货原因  blur
+    remarksBlur (val, record) {
+      if (val && (val != record.remarksBackups)) {
+        this.handleAdd(record, 'edit')
+      }
+    },
+    filterOption (input, option) {
+      return (
+        option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
+      )
+    }
+  },
+  mounted () {
+    if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
+      this.$refs.chooseTable.refresh(true)
+      this.resetSearchForm()
+    }
+  },
+  activated () {
+    // 如果是新页签打开或者进入新的子页(例:存在列表第2条数据编辑页页签时再打开第4条数据的编辑页),则重置当前页面
+    if (this.$store.state.app.isNewTab || !this.$store.state.app.isNewSubTab) {
+      this.$refs.chooseTable.refresh(true)
+      this.resetSearchForm()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {})
+  }
+}
+</script>
+
+<style lang="less">
+  .purchaseReturnEdit-wrap{
+    position: relative;
+    height: 100%;
+    padding-bottom: 51px;
+    box-sizing: border-box;
+    >.ant-spin-nested-loading{
+      overflow-y: scroll;
+      height: 100%;
+    }
+    .purchaseReturnEdit-back, .purchaseReturnEdit-cont{
+      margin-bottom: 10px;
+    }
+  }
+</style>

+ 344 - 0
src/views/purchasingManagement/purchaseReturnOutSync/list.vue

@@ -0,0 +1,344 @@
+<template>
+  <a-card size="small" :bordered="false" class="purchaseReturnList-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="purchaseReturnList-purchaseReturnNo" v-model.trim="queryParam.purchaseReturnNo" allowClear placeholder="请输入退货单号"/>
+              </a-form-item>
+            </a-col>
+            <a-col :md="6" :sm="24">
+              <a-form-item label="业务状态">
+                <v-select
+                  v-model="queryParam.state"
+                  ref="state"
+                  id="purchaseReturnList-state"
+                  code="PURCHASE_RETURN_STATUS"
+                  placeholder="请选择业务状态"
+                  allowClear
+                ></v-select>
+              </a-form-item>
+            </a-col>
+            <template v-if="advanced">
+              <a-col :md="6" :sm="24">
+                <a-form-item label="财务状态">
+                  <v-select
+                    v-model="queryParam.settleState"
+                    ref="settleState"
+                    id="chainTransferOutList-settleState"
+                    code="FINANCIAL_RECEIVE_STATUS"
+                    placeholder="请选择财务状态"
+                    allowClear></v-select>
+                </a-form-item>
+              </a-col>
+            </template>
+            <a-col :md="6" :sm="24" style="margin-bottom: 10px;">
+              <a-button type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="purchaseReturnList-refresh">查询</a-button>
+              <a-button style="margin-left: 8px" @click="resetSearchForm" :disabled="disabled" id="purchaseReturnList-reset">重置</a-button>
+              <a @click="advanced=!advanced" style="margin-left: 8px">
+                {{ advanced ? '收起' : '展开' }}
+                <a-icon :type="advanced ? 'up' : 'down'"/>
+              </a>
+            </a-col>
+          </a-row>
+        </a-form>
+      </div>
+      <!-- 操作按钮 -->
+      <div class="table-operator">
+        <a-button id="B_purchaseReturn-add" type="primary" v-if="$hasPermissions('B_purchaseReturn_outSnycAdd')&&($hasPermissions('B_PR_outSnycSJ')||$hasPermissions('B_PR_outSnycZB'))" 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"
+        :scroll="{ y: tableHeight }"
+        :defaultLoadData="false"
+        bordered>
+        <!-- 采退单号 -->
+        <template slot="purchaseReturnNo" slot-scope="text, record">
+          <span style="color: #ed1c24;cursor: pointer;" v-if="$hasPermissions('B_purchaseReturn_outSnycDetail')" @click="handleDetail(record)">{{ record.purchaseReturnNo }}</span>
+          <span v-else>{{ record.purchaseReturnNo }}</span>
+          <a-badge count="改" :offset="[10,0]" v-if="record.state=='HQ_CHANGE'"></a-badge>
+        </template>
+        <!-- 审核 -->
+        <template slot="audit" slot-scope="text, record">
+          <stateIcon :title="record.stateDictValue" v-if="record.state!='AUDIT_REJECT'" :state="record.state == 'WAIT_BACK'||record.state=='CHECKED'||record.state == 'FINISH'?'1':'2'"></stateIcon>
+          <stateIcon :title="record.stateDictValue" v-else :state="0"></stateIcon>
+        </template>
+        <!-- 出库 -->
+        <template slot="waitOut" slot-scope="text, record">
+          <stateIcon :state="record.hasStockBill == '1'?'1':'2'"></stateIcon>
+        </template>
+        <!-- 收款 -->
+        <template slot="financial" slot-scope="text, record">
+          <stateIcon :title="record.settleStateDictValue" :state="record.settleState == 'FINISH'?'1':'2'"></stateIcon>
+        </template>
+        <!-- 操作 -->
+        <template slot="action" slot-scope="text, record">
+          <a-button
+            size="small"
+            type="link"
+            class="button-primary"
+            v-if="(record.state == 'WAIT_SUBMIT' || record.state == 'AUDIT_REJECT') && $hasPermissions('B_purchaseReturn_outSnycEdit')"
+            @click="handleEdit(record)"
+            id="purchaseReturnList-edit-btn">编辑</a-button>
+          <a-button
+            size="small"
+            type="link"
+            v-if="record.state == 'CHECKED' && $hasPermissions('B_purchaseReturn_outSnycAudit')"
+            @click="handleAudit(record)"
+            class="button-primary"
+            id="bulkReturnGoodsList-audit-btn">审核</a-button>
+          <a-button
+            size="small"
+            type="link"
+            v-if="record.state == 'CHECKED' && $hasPermissions('B_purchaseReturn_outSnycOut')"
+            @click="handleWarehouse(record)"
+            class="button-primary"
+            id="bulkReturnGoodsList-out-btn">出库</a-button>
+          <a-button
+            size="small"
+            type="link"
+            class="button-error"
+            v-if="(record.state == 'WAIT_SUBMIT' || record.state == 'AUDIT_REJECT') && $hasPermissions('B_purchaseReturn_outSnycDel')"
+            @click="handleDel(record)"
+            id="purchaseReturnList-del-btn">删除</a-button>
+          <span v-if="!((record.state == 'WAIT_SUBMIT' || record.state == 'AUDIT_REJECT') && ($hasPermissions('B_purchaseReturn_outSnycEdit') || $hasPermissions('B_purchaseReturn_outSnycDel'))) && !(record.state == 'CHECKED' && ($hasPermissions('B_purchaseReturn_outSnycOut') || $hasPermissions('B_purchaseReturn_outSnycAudit')))">--</span>
+        </template>
+      </s-table>
+    </a-spin>
+    <!-- 选择基本信息弹框 -->
+    <basic-info-modal :openModal="openModal" @ok="handleEdit" @close="openModal=false" />
+  </a-card>
+</template>
+
+<script>
+import { commonMixin } from '@/utils/mixin'
+import { STable, VSelect } from '@/components'
+import rangeDate from '@/views/common/rangeDate.vue'
+import { purchaseTargetList } from '@/api/purchase'
+import basicInfoModal from './basicInfoModal.vue'
+import getDate from '@/libs/getDate.js'
+import stateIcon from '@/views/common/stateIcon'
+import { purchaseReturnList, purchaseReturnDel, purchaseReturnOutStockBill, purchaseReturnFinishBill } from '@/api/purchaseReturn'
+export default {
+  name: 'PurchaseReturnList',
+  components: { STable, VSelect, rangeDate, stateIcon, basicInfoModal },
+  mixins: [commonMixin],
+  data () {
+    return {
+      spinning: false,
+      advanced: true, // 高级搜索 展开/关闭
+      openModal: false, // 基本信息弹框是否显示
+      time: [
+        getDate.getCurrMonthDays().starttime,
+        getDate.getCurrMonthDays().endtime
+      ],
+      queryParam: { //  查询条件
+        beginDate: getDate.getCurrMonthDays().starttime,
+        endDate: getDate.getCurrMonthDays().endtime,
+        purchaseReturnNo: '', //  退货单号
+        state: undefined, //  业务状态
+        settleState: undefined
+      },
+      disabled: false, //  查询、重置按钮是否可操作
+      tableHeight: 0,
+      columns: [
+        { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
+        { title: '创建时间', dataIndex: 'createDate', width: '14%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '采退单号', scopedSlots: { customRender: 'purchaseReturnNo' }, width: '17%', align: 'center' },
+        { title: '退货数量', dataIndex: 'totalQty', width: '8%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '退款金额', dataIndex: 'totalAmount', width: '8%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
+        { title: '客服审核时间', dataIndex: 'auditTime', width: '14%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '扣减库存', dataIndex: 'hasStockBill', width: '6%', align: 'center', customRender: function (text) { return ['否', '是'][text] } },
+        { title: '业务状态', dataIndex: 'stateDictValue', width: '8%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '审核', scopedSlots: { customRender: 'audit' }, width: '3%', align: 'center' },
+        { title: '出库', scopedSlots: { customRender: 'waitOut' }, width: '3%', align: 'center' },
+        { title: '收款', scopedSlots: { customRender: 'financial' }, width: '3%', align: 'center' },
+        // { title: '财务状态', dataIndex: 'settleStateDictValue', width: '8%', align: 'center', customRender: function (text) { return text || '--' } },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: '13%', align: 'center' }
+      ],
+      // 加载数据方法 必须为 Promise 对象
+      loadData: parameter => {
+        this.disabled = true
+        this.spinning = true
+        return purchaseReturnList(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
+        })
+      },
+      purchaseTragetType: []
+    }
+  },
+  methods: {
+    //  时间  change
+    dateChange (date) {
+      this.queryParam.beginDate = date[0]
+      this.queryParam.endDate = date[1]
+    },
+    //  重置
+    resetSearchForm () {
+      this.resetData()
+      this.$refs.table.refresh(true)
+    },
+    // 重置数据
+    resetData () {
+      this.$refs.rangeDate.resetDate(this.time)
+      this.queryParam.beginDate = getDate.getCurrMonthDays().starttime
+      this.queryParam.endDate = getDate.getCurrMonthDays().endtime
+      this.queryParam.purchaseReturnNo = ''
+      this.queryParam.state = undefined
+      this.queryParam.settleState = undefined
+    },
+    //  删除
+    handleDel (row) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '删除后不可恢复,确定要进行删除吗?',
+        centered: true,
+        onOk () {
+          _this.spinning = true
+          purchaseReturnDel({ id: row.id }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$refs.table.refresh()
+              _this.spinning = false
+            } else {
+              _this.spinning = false
+            }
+          })
+        }
+      })
+    },
+    // 编辑
+    handleEdit (row) {
+      this.$router.push({ name: row.grabFlag == 1 ? 'purchaseReturnOutSyncGrapEdit' : 'purchaseReturnOutSyncEdit', params: { id: row.id, sn: row.purchaseReturnSn, name: row.returnTargetName } })
+    },
+    // 详情
+    handleDetail (row) {
+      this.$router.push({ name: 'purchaseReturnOutSyncDetail', params: { sn: row.purchaseReturnSn } })
+    },
+    //  生成出库单
+    handleWarehouse (row) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确定要生成出库单吗?',
+        centered: true,
+        onOk () {
+          _this.spinning = true
+          purchaseReturnOutStockBill({ sn: row.purchaseReturnSn }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$refs.table.refresh()
+              _this.spinning = false
+            } else {
+              _this.spinning = false
+            }
+          })
+        }
+      })
+    },
+    //  审核
+    handleAudit (row) {
+      const _this = this
+      this.$confirm({
+        title: '提示',
+        content: '确定要完结该单据吗?',
+        centered: true,
+        onOk () {
+          _this.spinning = true
+          purchaseReturnFinishBill({ sn: row.purchaseReturnSn }).then(res => {
+            if (res.status == 200) {
+              _this.$message.success(res.message)
+              _this.$refs.table.refresh()
+              _this.spinning = false
+            } else {
+              _this.spinning = false
+            }
+          })
+        }
+      })
+    },
+    getParentDealer () {
+      purchaseTargetList({ purchaseTargetType: 'SUPPLIER_SYS' }).then(res => {
+        if (res.status == 200) {
+          this.purchaseTragetType = res.data
+        } else {
+          this.purchaseTragetType = []
+        }
+      })
+    },
+    pageInit () {
+      const _this = this
+      this.$nextTick(() => { // 页面渲染完成后的回调
+        _this.setTableH()
+      })
+      this.getParentDealer()
+    },
+    setTableH () {
+      const tableSearchH = this.$refs.tableSearch.offsetHeight
+      this.tableHeight = window.innerHeight - tableSearchH - 235
+    }
+  },
+  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.resetData()
+      if (this.$route.query.pageParams) {
+        this.queryParam.state = this.$route.query.pageParams.state
+      }
+      this.pageInit()
+      this.$refs.table.refresh(true)
+    }
+    // 仅刷新列表,不重置页面
+    if (this.$store.state.app.updateList) {
+      this.pageInit()
+      this.$refs.table.refresh()
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {})
+  }
+}
+</script>