salesReturnEdit.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. <template>
  2. <div class="salesReturnEdit-wrap">
  3. <a-spin :spinning="spinning" tip="Loading...">
  4. <a-page-header :ghost="false" :backIcon="false" class="salesReturnEdit-back" >
  5. <!-- 自定义的二级文字标题 -->
  6. <template slot="subTitle">
  7. <a id="salesReturnEdit-back-btn" href="javascript:;" @click="handleBack"><a-icon type="left" /> 返回列表</a>
  8. <span style="margin: 0 15px;color: #666;">客户名称:{{ ordeDetail&&ordeDetail.buyerName || '--' }}</span>
  9. <span style="margin: 0 15px;color: #666;" v-if="ordeDetail">
  10. 退货仓库:<warehouse
  11. style="width:200px;"
  12. :allowClear="false"
  13. disabled
  14. v-model="ordeDetail.warehouseSn"
  15. @change="updateWarehouse"
  16. id="basicInfo-warehouseSn"
  17. placeholder="请选择退货仓库"
  18. />
  19. </span>
  20. </template>
  21. <!-- 操作区,位于 title 行的行尾 -->
  22. <template slot="extra">
  23. <a-button
  24. key="3"
  25. type="default"
  26. class="button-info"
  27. id="salesReturnEdit-preview-btn"
  28. v-if="$hasPermissions('B_salesReturnPrint')"
  29. :disabled="chooseLoadData.length==0"
  30. @click="handlePrint('preview')">打印预览</a-button>
  31. <a-button
  32. key="2"
  33. type="primary"
  34. class="button-info"
  35. id="salesReturnEdit-print-btn"
  36. v-if="$hasPermissions('B_salesReturnPrint')"
  37. :disabled="chooseLoadData.length==0"
  38. @click="handlePrint('print')">快捷打印</a-button>
  39. <a-divider type="vertical" />
  40. <a-button
  41. key="1"
  42. type="primary"
  43. class="button-warning"
  44. id="salesReturnEdit-export-btn"
  45. v-if="$hasPermissions('B_salesReturnExport')"
  46. :disabled="chooseLoadData.length==0"
  47. @click="handlePrint('export')">导出Excel</a-button>
  48. </template>
  49. </a-page-header>
  50. <a-card size="small" :bordered="false" class="salesReturnEdit-cont">
  51. <!-- 查询配件列表 -->
  52. <queryPart ref="partQuery" :newLoading="isInster" @add="saveProduct"></queryPart>
  53. </a-card>
  54. <a-card size="small" :bordered="false" class="salesReturnEdit-cont">
  55. <a-alert style="margin-bottom: 10px;" type="info">
  56. <div slot="message" class="total-bar">
  57. <div>
  58. <span>申请退货数量:{{ ordeDetail&&(ordeDetail.totalInitialQty || ordeDetail.totalInitialQty==0) ? ordeDetail.totalInitialQty : '--' }};</span>
  59. <span v-if="$hasPermissions('B_salesReturnEdit_salesPrice')">参考退货金额:{{ ordeDetail&&(ordeDetail.totalAmount || ordeDetail.totalAmount==0) ? toThousands(ordeDetail.totalAmount) : '--' }};</span>
  60. </div>
  61. </div>
  62. </a-alert>
  63. <div class="table-page-search-wrapper" style="display:flex;align-items: center;justify-content: space-between;">
  64. <div style="flex-grow:1;">
  65. <a-form layout="inline" @keyup.enter.native="$refs.table.refresh(true)">
  66. <a-row :gutter="15">
  67. <a-col :md="6" :sm="24">
  68. <a-form-item label="产品编码">
  69. <a-input v-model.trim="productForm.productCode" allowClear placeholder="请输入产品编码"/>
  70. </a-form-item>
  71. </a-col>
  72. <a-col :md="6" :sm="24">
  73. <a-form-item label="产品名称">
  74. <a-input v-model.trim="productForm.productName" allowClear placeholder="请输入产品名称"/>
  75. </a-form-item>
  76. </a-col>
  77. <a-col :md="6" :sm="24" style="margin-bottom: 10px;">
  78. <a-button type="primary" @click="$refs.table.refresh(true)" :disabled="disabled">查询</a-button>
  79. <a-button style="margin-left: 5px" @click="resetSearchForm(true)" :disabled="disabled">重置</a-button>
  80. </a-col>
  81. </a-row>
  82. </a-form>
  83. </div>
  84. <div>
  85. <span style="margin-right: 10px;" v-if="selNums">已选{{ selNums }}项</span>
  86. <a-button type="default" class="button-info" @click="openPlSetReason">批量设置退货原因</a-button>
  87. <a-button type="primary" class="button-info" id="salesReturnEdit-import-btn" @click="openGuideModal=true">导入产品</a-button>
  88. </div>
  89. </div>
  90. <!-- 已选配件列表 -->
  91. <s-table
  92. class="sTable"
  93. ref="table"
  94. size="small"
  95. :rowKey="(record) => record.id"
  96. :row-selection="{ columnWidth: 40 }"
  97. @rowSelection="rowSelectionFun"
  98. :columns="columns"
  99. :data="loadData"
  100. :defaultLoadData="false"
  101. :scroll="{ y: 300 }"
  102. bordered>
  103. <!-- 本次退货数量 -->
  104. <template slot="qty" slot-scope="text, record">
  105. <a-input-number
  106. id="salesReturn-qty"
  107. size="small"
  108. v-model="record.initialQty"
  109. :precision="0"
  110. :min="0"
  111. :max="999999"
  112. placeholder="请输入"
  113. @blur="e => onCellBlur(e.target.value, record, 'qty')"
  114. style="width: 100%;" />
  115. </template>
  116. <!-- 退货原因 -->
  117. <template slot="returnReason" slot-scope="text, record">
  118. <returnReason v-model="record.returnReason" @blur="updateReason(record)"></returnReason>
  119. </template>
  120. <!-- 操作 -->
  121. <template slot="action" slot-scope="text, record">
  122. <a-button
  123. size="small"
  124. type="link"
  125. :loading="delLoading"
  126. class="button-error"
  127. @click="handleDel(record)"
  128. id="salesReturn-Del">删除</a-button>
  129. </template>
  130. </s-table>
  131. </a-card>
  132. </a-spin>
  133. <div class="affix-cont">
  134. <a-button
  135. size="large"
  136. style="padding: 0 60px;"
  137. :disabled="spinning"
  138. type="primary"
  139. class="button-primary"
  140. @click="beforeSubmit()"
  141. id="salesReturn-handleSubmit">提交</a-button>
  142. </div>
  143. <!-- 选择审核人员 -->
  144. <chooseDepartUserModal ref="chooseDepart" :openModal="openDepartUserModal" @close="openDepartUserModal=false" @submit="handleSubmit"></chooseDepartUserModal>
  145. <!-- 导入产品 -->
  146. <importGuideModal :openModal="openGuideModal" :params="{salesReturnBillSn: $route.params.sn}" @close="closeGuideModel" @ok="hanldeOk" />
  147. <!-- 批量设置退货原因 -->
  148. <commonModal modalTit="批量设置退货原因" :openModal="showPlModal" @cancel="showPlModal=false" @ok="setPlReturnReason">
  149. <div style="text-align: center;">
  150. <div style="margin-bottom: 15px;font-size: 14px;"><strong>请输入退货原因</strong></div>
  151. <div style="line-height: 24px;">
  152. <div><returnReason size="large" v-model="plReturnReason"></returnReason></div>
  153. </div>
  154. </div>
  155. </commonModal>
  156. </div>
  157. </template>
  158. <script>
  159. import { commonMixin } from '@/utils/mixin'
  160. import { STable, VSelect } from '@/components'
  161. import { printFun, exportExcel } from '@/libs/JGPrint.js'
  162. import { removeEmptyStr } from '@/libs/tools'
  163. import ImportGuideModal from './importGuideModal.vue'
  164. import queryPart from './queryPart.vue'
  165. import commonModal from '@/views/common/commonModal.vue'
  166. import EditableCell from '@/views/common/editInput.js'
  167. import chooseDepartUserModal from './chooseDepartUserModal.vue'
  168. import warehouse from '@/views/common/chooseWarehouse.js'
  169. import returnReason from '@/views/common/returnReason'
  170. import {
  171. salesReturnDetail,
  172. salesReturnSubmit,
  173. salesReturnBatchInsert,
  174. salesReturnPrint,
  175. salesReturnExport,
  176. salesReturnModify
  177. } from '@/api/salesReturn'
  178. import {
  179. salesReturnDetailList,
  180. salesReturnDetailDel,
  181. salesReturnDetailInsert,
  182. salesReturnDetailUpdateQty,
  183. salesReturnDetailUpdateReason,
  184. salesReturnDetailSetReason
  185. } from '@/api/salesReturnDetail'
  186. export default {
  187. name: 'SalesReturnEdit',
  188. mixins: [commonMixin],
  189. components: {
  190. STable,
  191. VSelect,
  192. queryPart,
  193. EditableCell,
  194. ImportGuideModal,
  195. chooseDepartUserModal,
  196. returnReason,
  197. commonModal,
  198. warehouse
  199. },
  200. data () {
  201. return {
  202. spinning: false,
  203. orderId: null,
  204. orderSn: null,
  205. buyerSn: null,
  206. disabled: false,
  207. isInster: false, // 是否正在添加产品
  208. openDepartUserModal: false,
  209. ordeDetail: { discountAmount: 0 },
  210. delLoading: false,
  211. // 已选产品
  212. dataSource: [],
  213. productForm: {
  214. salesReturnBillSn: '',
  215. productName: '',
  216. productCode: ''
  217. },
  218. chooseLoadData: [],
  219. // 加载数据方法 必须为 Promise 对象
  220. loadData: parameter => {
  221. this.disabled = true
  222. // 查询总计
  223. this.productForm.salesReturnBillSn = this.$route.params.sn
  224. return salesReturnDetailList(Object.assign(parameter, this.productForm)).then(res => {
  225. let data
  226. if (res.status == 200) {
  227. data = res.data
  228. const no = (data.pageNo - 1) * data.pageSize
  229. for (var i = 0; i < data.list.length; i++) {
  230. data.list[i].no = no + i + 1
  231. data.list[i].qtyBackups = data.list[i].initialQty
  232. data.list[i].returnReasonBackups = data.list[i].returnReason
  233. }
  234. this.disabled = false
  235. this.chooseLoadData = data.list
  236. this.total = res.data.count
  237. }
  238. return data
  239. })
  240. },
  241. openGuideModal: false, // 导入产品引导
  242. total: 0,
  243. rowSelectionInfo: null,
  244. plReturnReason: '',
  245. showPlModal: false
  246. }
  247. },
  248. watch: {
  249. showPlModal (newValue, oldValue) {
  250. if (!newValue) {
  251. this.plReturnReason = ''
  252. }
  253. }
  254. },
  255. computed: {
  256. selNums () {
  257. return this.rowSelectionInfo && this.rowSelectionInfo.selectedRowKeys.length || 0
  258. },
  259. columns () {
  260. const arr = [
  261. { title: '序号', dataIndex: 'no', align: 'center', width: '4%' },
  262. { title: '产品编码', dataIndex: 'productEntity.code', width: '18%', align: 'center', customRender: function (text) { return text || '--' } },
  263. { title: '产品名称', dataIndex: 'productEntity.name', width: '25%', align: 'left', customRender: function (text) { return text || '--' }, ellipsis: true },
  264. { title: '单位', dataIndex: 'productEntity.unit', align: 'center', width: '6%', customRender: function (text) { return text || '--' } },
  265. { title: '申请退货数量', dataIndex: 'initialQty', align: 'center', width: '8%', scopedSlots: { customRender: 'qty' } },
  266. { title: '退货原因', dataIndex: 'returnReason', align: 'center', width: '13%', scopedSlots: { customRender: 'returnReason' } },
  267. { title: '操作', scopedSlots: { customRender: 'action' }, width: '10%', align: 'center' }
  268. ]
  269. if (this.$hasPermissions('B_salesReturnEdit_salesPrice')) { // 售价权限
  270. arr.splice(4, 0, { title: '参考退货单价', dataIndex: 'price', align: 'right', width: '8%', customRender: text => ((text || text == 0) ? this.toThousands(text) : '--') })
  271. arr.splice(7, 0, { title: '参考退货金额', align: 'right', dataIndex: 'totalAmount', width: '8%', customRender: text => ((text || text == 0) ? this.toThousands(text) : '--') })
  272. }
  273. return arr
  274. }
  275. },
  276. methods: {
  277. // 返回
  278. handleBack () {
  279. this.$router.push({ name: 'salesReturnList', query: { closeLastOldTab: true } })
  280. },
  281. // 表格选中项
  282. rowSelectionFun (obj) {
  283. this.rowSelectionInfo = obj || null
  284. },
  285. // 已选产品 blur
  286. onCellBlur (val, record, type) {
  287. const valBackups = record.qtyBackups
  288. // 光标移出,值发生改变再调用编辑接口
  289. if (val && val != valBackups) {
  290. this.spinning = true
  291. salesReturnDetailUpdateQty({
  292. salesReturnDetailSn: record.salesReturnDetailSn,
  293. initialQty: record.initialQty,
  294. price: record.price
  295. }).then(res => {
  296. if (res.status == 200) {
  297. this.resetTable(false)
  298. this.$message.success(res.message)
  299. this.spinning = false
  300. record.qtyBackups = record.initialQty
  301. } else {
  302. this.spinning = false
  303. record.initialQty = valBackups
  304. }
  305. })
  306. } else {
  307. record.initialQty = valBackups
  308. }
  309. },
  310. // 修改仓库
  311. updateWarehouse(warehouseSn){
  312. const _this = this
  313. _this.spinning = true
  314. const params = {id:this.ordeDetail.id,warehouseSn: warehouseSn}
  315. salesReturnModify(params).then(res => {
  316. if (res.status == 200) {
  317. _this.$message.success(res.message)
  318. _this.getOrderDetail()
  319. }
  320. _this.spinning = false
  321. })
  322. },
  323. // 修改退货原因
  324. updateReason (row) {
  325. console.log(row.returnReason)
  326. row.returnReason = removeEmptyStr(row.returnReason)
  327. // 空或没有改变时不保存数据
  328. if (!row.returnReason || row.returnReason == row.returnReasonBackups) {
  329. row.returnReason = row.returnReasonBackups
  330. return
  331. }
  332. this.spinning = true
  333. salesReturnDetailUpdateReason({
  334. salesReturnDetailSn: row.salesReturnDetailSn,
  335. returnReason: row.returnReason
  336. }).then(res => {
  337. if (res.status == 200) {
  338. this.resetTable(false)
  339. this.$message.success(res.message)
  340. } else {
  341. row.returnReason = row.returnReasonBackups
  342. }
  343. this.spinning = false
  344. })
  345. },
  346. // 批量设置退货原因
  347. openPlSetReason () {
  348. if (this.selNums) {
  349. this.showPlModal = true
  350. } else {
  351. this.$message.warning('请先选择产品!')
  352. }
  353. },
  354. setPlReturnReason () {
  355. if (this.plReturnReason == '') {
  356. this.$message.warning('请输入退货原因!')
  357. } else {
  358. this.spinning = true
  359. const snList = []
  360. const arr = this.rowSelectionInfo && this.rowSelectionInfo.selectedRows || []
  361. arr.map(item => {
  362. snList.push(item.salesReturnDetailSn)
  363. })
  364. salesReturnDetailSetReason({
  365. salesReturnBillDetailSnList: snList,
  366. returnReason: this.plReturnReason
  367. }).then(res => {
  368. if (res.status == 200) {
  369. this.showPlModal = false
  370. this.$refs.table.clearSelected()
  371. this.resetTable(false)
  372. }
  373. this.spinning = false
  374. })
  375. }
  376. },
  377. // 获取单据详细
  378. getOrderDetail (flag) {
  379. salesReturnDetail({ sn: this.orderSn }).then(res => {
  380. this.ordeDetail = res.data || null
  381. if(!flag){
  382. this.$refs.partQuery.pageInit(this.buyerSn, this.ordeDetail.warehouseSn)
  383. }
  384. })
  385. },
  386. // 删除产品
  387. handleDel (row) {
  388. const _this = this
  389. this.$confirm({
  390. title: '提示',
  391. content: '确认要删除吗?',
  392. centered: true,
  393. closable: true,
  394. onOk () {
  395. _this.delLoading = true
  396. _this.spinning = true
  397. salesReturnDetailDel({ salesReturnDetailSn: row.salesReturnDetailSn }).then(res => {
  398. if (res.status == 200) {
  399. _this.resetTable(false)
  400. }
  401. _this.$message.info(res.message)
  402. _this.delLoading = false
  403. _this.spinning = false
  404. })
  405. }
  406. })
  407. },
  408. resetTable (flag) {
  409. this.$refs.table.refresh(flag)
  410. this.getOrderDetail(true)
  411. },
  412. // 重置
  413. resetSearchForm (flag) {
  414. this.productForm.productName = ''
  415. this.productForm.productCode = ''
  416. this.$refs.table.refresh(!!flag)
  417. this.getOrderDetail(flag)
  418. },
  419. // 添加或修改产品
  420. saveProduct (row) {
  421. // 防止多次添加产品
  422. if (this.isInster) {
  423. return
  424. }
  425. this.isInster = true
  426. const params = {
  427. 'salesReturnBillSn': this.orderSn,
  428. 'salesReturnBillNo': this.ordeDetail.salesReturnBillNo,
  429. 'price': row.productPrice,
  430. // 'cost': row.lastStockCost,
  431. 'returnReason': row.returnReason,
  432. 'productSn': row.productSn,
  433. 'initialQty': row.qty
  434. }
  435. this.spinning = true
  436. salesReturnDetailInsert(params).then(res => {
  437. if (res.status == 200) {
  438. this.resetSearchForm(true)
  439. this.$message.success(res.message)
  440. }
  441. this.isInster = false
  442. this.spinning = false
  443. })
  444. },
  445. beforeSubmit () {
  446. if (this.total) {
  447. const hasKong = this.chooseLoadData.find(item => !item.returnReason)
  448. if (hasKong) {
  449. this.$message.warning('请输入退货原因!')
  450. } else {
  451. this.openDepartUserModal = true
  452. if (this.ordeDetail.billStatus == 'AUDIT_REJECT') {
  453. this.$refs.chooseDepart.getDetail(this.ordeDetail)
  454. }
  455. }
  456. } else {
  457. this.$message.warning('请添加产品!')
  458. }
  459. },
  460. // 提交销售退货
  461. handleSubmit (data) {
  462. this.spinning = true
  463. salesReturnSubmit({ salesReturnBillSn: this.orderSn, ...data }).then(res => {
  464. if (res.status == 200) {
  465. this.handleBack()
  466. this.$message.success(res.message)
  467. }
  468. this.spinning = false
  469. })
  470. },
  471. closeGuideModel () {
  472. this.openGuideModal = false
  473. },
  474. // 导入产品
  475. hanldeOk (obj) {
  476. salesReturnBatchInsert(obj).then(res => {
  477. if (res.status == 200) {
  478. this.resetTable(true)
  479. }
  480. })
  481. },
  482. // 打印预览/快捷打印
  483. handlePrint (type) {
  484. const _this = this
  485. const a = ['WAIT_CUSTOMER_SERVICE_CONFIRM', 'WAIT_FINANCIAL_AUDIT', 'FINANCIAL_REJECT', 'FINISH'].find(item => item == this.ordeDetail.billStatus)
  486. const status = a ? 'SALES_RETURN_AMOUNT' : 'SALES_RETURN_REASON'
  487. const params = { salesReturnBillSn: this.$route.params.sn, priceType: status }
  488. _this.spinning = true
  489. // 导出
  490. if (type == 'export') {
  491. exportExcel(salesReturnExport, params, '销售退货', function () {
  492. _this.spinning = false
  493. _this.$store.state.app.curActionPermission = ''
  494. })
  495. } else {
  496. // 打印或预览
  497. printFun(salesReturnPrint, params, type, '销售退货', () => {
  498. _this.spinning = false
  499. _this.$store.state.app.curActionPermission = ''
  500. })
  501. }
  502. },
  503. pageInit () {
  504. this.orderSn = this.$route.params.sn
  505. this.buyerSn = this.$route.params.buyerSn
  506. this.resetSearchForm()
  507. }
  508. },
  509. mounted () {
  510. if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
  511. this.pageInit()
  512. }
  513. },
  514. activated () {
  515. // 如果是新页签打开或者进入新的子页(例:存在列表第2条数据编辑页页签时再打开第4条数据的编辑页),则重置当前页面
  516. if (this.$store.state.app.isNewTab || !this.$store.state.app.isNewSubTab) {
  517. this.pageInit()
  518. }
  519. },
  520. beforeRouteEnter (to, from, next) {
  521. next(vm => {})
  522. }
  523. }
  524. </script>
  525. <style lang="less">
  526. .salesReturnEdit-wrap{
  527. position: relative;
  528. height: 100%;
  529. padding-bottom: 51px;
  530. box-sizing: border-box;
  531. >.ant-spin-nested-loading{
  532. overflow-y: scroll;
  533. height: 100%;
  534. }
  535. .salesReturnEdit-cont{
  536. margin-top: 10px;
  537. .total-bar{
  538. display: flex;
  539. align-items: center;
  540. justify-content: space-between;
  541. > div{
  542. &:last-child{
  543. display: flex;
  544. align-items: center;
  545. justify-content: space-between;
  546. > div{
  547. padding: 0 10px;
  548. }
  549. }
  550. }
  551. }
  552. }
  553. }
  554. </style>