edit.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. <template>
  2. <div class="salesEdit-wrap">
  3. <a-spin :spinning="spinning" tip="Loading...">
  4. <a-page-header :ghost="false" :backIcon="false" @back="handleBack" >
  5. <!-- 自定义的二级文字标题 -->
  6. <template slot="subTitle">
  7. <a id="salesEdit-back-btn" href="javascript:;" @click="handleBack"><a-icon type="left" /> 返回列表</a>
  8. <span style="margin: 0 15px;color: #666;">客户名称:{{ detailData&&detailData.buyerName }}</span>
  9. </template>
  10. </a-page-header>
  11. <a-card size="small" :bordered="false" class="salesEdit-cont">
  12. <div slot="title">
  13. <div class="p-title">
  14. 选择产品
  15. </div>
  16. </div>
  17. <!-- 查询配件列表 -->
  18. <queryPart ref="partQuery" :newLoading="isInster" @add="insterProduct"></queryPart>
  19. </a-card>
  20. <a-card size="small" :bordered="false" class="salesEdit-cont">
  21. <div slot="title">
  22. <a-row :gutter="15" type="flex">
  23. <a-col :span="2">
  24. <div class="p-title">
  25. 已选产品
  26. </div>
  27. </a-col>
  28. <a-col :span="16" v-if="activeName">
  29. <div class="p-notes">
  30. <a-icon style="color: #FF9900;" type="bell" /> 已选产品可参加<span>{{ activeName }}</span>的促销活动,促销产品为指定产品
  31. </div>
  32. </a-col>
  33. </a-row>
  34. </div>
  35. <!-- 总计 -->
  36. <a-alert type="info" style="margin-bottom: 10px;">
  37. <div slot="message" class="total-bar">
  38. <div style="position: relative;width: 100%;">
  39. <div>
  40. 总售价:<strong>{{ detailData&&(detailData.totalCommonAmount || detailData.totalCommonAmount==0) ? '¥'+detailData.totalCommonAmount : '--' }}</strong>;
  41. 总款数:<strong>{{ detailData&&(detailData.totalCommonCategory || detailData.totalCommonCategory==0) ? detailData.totalCommonCategory : '--' }}</strong>;
  42. 总数量:<strong>{{ detailData&&(detailData.totalCommonQty || detailData.totalCommonQty==0) ? detailData.totalCommonQty : '--' }}</strong>;
  43. </div>
  44. <div style="position: absolute;right: 0;top: -3px;">
  45. <!-- <a-button size="small" type="primary" class="button-info" id="salesEdit-import-btn" @click="openGuideModal=true">导入产品</a-button> -->
  46. </div>
  47. </div>
  48. </div>
  49. </a-alert>
  50. <!-- 已选配件列表 -->
  51. <s-table
  52. class="sTable"
  53. ref="table"
  54. size="small"
  55. :rowKey="(record) => record.id"
  56. :columns="columns"
  57. :data="loadData"
  58. :defaultLoadData="false"
  59. :scroll="{ y: 300 }"
  60. bordered>
  61. <!-- 产品编码 -->
  62. <template slot="productCode" slot-scope="text, record">
  63. <a-badge count="缺" v-if="Number(record.stockQty) < Number(record.unpushedQty)">
  64. <div style="padding-right: 15px;">{{ text }}</div>
  65. </a-badge>
  66. <span v-if="!(Number(record.stockQty) < Number(record.unpushedQty))">{{ text }}</span>
  67. </template>
  68. <!-- 产品名称 -->
  69. <template slot="productName" slot-scope="text, record">
  70. <div class="ellipsisCon">
  71. <a-tooltip placement="rightBottom">
  72. <template slot="title">
  73. <span>{{ text }}</span>
  74. </template>
  75. <span class="ellipsisText">{{ text }}</span>
  76. </a-tooltip>
  77. <a-badge :number-style="{ backgroundColor: '#52c41a' }" count="活动" v-if="record.promotableFlag == 1"></a-badge>
  78. </div>
  79. </template>
  80. <!-- 销售数量 -->
  81. <template slot="salesNums" slot-scope="text, record">
  82. <a-input-number
  83. id="salesEdit-qty"
  84. size="small"
  85. v-model="record.qty"
  86. :precision="0"
  87. :min="1"
  88. :max="999999"
  89. placeholder="请输入"
  90. @blur="e => onCellBlur(e.target.value, record)"
  91. style="width: 100%;" />
  92. </template>
  93. <!-- 当前库存 -->
  94. <template slot="stockQty" slot-scope="text, record">
  95. <div v-if="record.stockQty || record.stockQty==0">
  96. <p style="margin: 0;" v-if="Number(record.stockQty) < Number(record.unpushedQty)">{{ record.stockQty }}(<span class="redStyle">缺{{ Number(record.unpushedQty) - Number(record.stockQty) }}</span>)</p>
  97. <p style="margin: 0;" v-else>{{ record.stockQty }}</p>
  98. </div>
  99. <span v-else>--</span>
  100. </template>
  101. <!-- 操作 -->
  102. <template slot="action" slot-scope="text, record">
  103. <a-button
  104. size="small"
  105. type="link"
  106. :loading="delLoading"
  107. class="button-error"
  108. @click="handleDel(record)"
  109. >删除</a-button>
  110. <a-button
  111. size="small"
  112. type="link"
  113. :loading="delLoading"
  114. class="button-warning"
  115. @click="handleSelCx(record)"
  116. v-if="record.promotableFlag == 1"
  117. >选择促销品</a-button>
  118. </template>
  119. </s-table>
  120. </a-card>
  121. <a-card size="small" :bordered="false" class="salesEdit-cont">
  122. <div slot="title">
  123. <div class="p-title">
  124. 已选促销品
  125. </div>
  126. </div>
  127. <!-- 总计 -->
  128. <a-alert type="info" style="margin-bottom: 10px;">
  129. <div slot="message" class="total-bar">
  130. <div>
  131. <span v-if="$hasPermissions('B_isShowCost')">总成本:<strong>{{ detailData&&(detailData.totalPromoCost || detailData.totalPromoCost==0) ? '¥'+detailData.totalPromoCost : '--' }}</strong>;</span>
  132. 总款数:<strong>{{ detailData&&(detailData.totalPromoCategory || detailData.totalPromoCategory==0) ? detailData.totalPromoCategory : '--' }}</strong>;
  133. 总数量:<strong>{{ detailData&&(detailData.totalPromoQty || detailData.totalPromoQty==0) ? detailData.totalPromoQty : '--' }}</strong>;
  134. </div>
  135. <div>
  136. </div>
  137. </div>
  138. </a-alert>
  139. <!-- 已选促销品列表 -->
  140. <queryPromotable ref="promotable" :delLoading="delLoading" @onCellBlur="onCellBlur" @del="handleDel"></queryPromotable>
  141. </a-card>
  142. </a-spin>
  143. <div class="affix-cont">
  144. <a-button
  145. size="large"
  146. style="padding: 0 60px;"
  147. :disabled="spinning"
  148. type="primary"
  149. class="button-primary"
  150. @click="handleSubmit()"
  151. id="productInfoList-handleSubmit">提交</a-button>
  152. </div>
  153. <!-- 添加产品 -->
  154. <ChooseActive
  155. ref="activeProduct"
  156. :openModal="newActive"
  157. @ok="addNewActive"
  158. :newLoading="isInster"
  159. @close="closeActive"></ChooseActive>
  160. <!-- 导入产品 -->
  161. <importGuideModal :openModal="openGuideModal" :params="{salesBillSn: $route.params.sn}" @close="closeGuideModel" @ok="hanldeOk" />
  162. </div>
  163. </template>
  164. <script>
  165. import { STable, VSelect } from '@/components'
  166. import queryPart from './queryPart.vue'
  167. import queryPromotable from './queryPromotable.vue'
  168. import ChooseActive from './chooseActive.vue'
  169. import ImportGuideModal from './importGuideModal.vue'
  170. import { salesDetailBySn, salesWriteSubmit, getPromoacActiveList } from '@/api/sales'
  171. import { salesDetailStockList, salesDetailInsert, salesDetailUpdateQty, salesDetailDel, salesDetailDelAll, addPromoGoods, salesBatchInsert } from '@/api/salesDetail'
  172. export default {
  173. name: 'SalesDetail',
  174. components: { STable, VSelect, queryPart, queryPromotable, ChooseActive, ImportGuideModal },
  175. data () {
  176. return {
  177. spinning: false,
  178. salesBillSn: null, // 销售单sn
  179. disabled: false, // 查询、重置按钮是否可操作
  180. isInster: false, // 是否正在添加产品
  181. delLoading: false,
  182. newActive: false, // 选择促销品
  183. detailData: { discountAmount: 0, id: null, salesBillSn: '' }, // 订单基础数据
  184. dataSource: [],
  185. productForm: {
  186. salesBillSn: '',
  187. promotionFlag: 0
  188. },
  189. activeName: '', // 促销活动
  190. nowData: null,
  191. // 表头
  192. columns: [
  193. { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
  194. { title: '产品编码', dataIndex: 'productEntity.code', scopedSlots: { customRender: 'productCode' }, width: '20%', align: 'center', sorter: true },
  195. { title: '产品名称', dataIndex: 'productEntity.name', scopedSlots: { customRender: 'productName' }, width: '25%', align: 'left' },
  196. { title: '售价', dataIndex: 'price', width: '8%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
  197. { title: '销售数量', scopedSlots: { customRender: 'salesNums' }, width: '8%', align: 'center' },
  198. { title: '库存', dataIndex: 'stockQty', scopedSlots: { customRender: 'stockQty' }, width: '8%', align: 'center' },
  199. { title: '单位', dataIndex: 'productEntity.unit', width: '6%', align: 'center', customRender: function (text) { return text || '--' } },
  200. { title: '售价小计', dataIndex: 'totalAmount', width: '8%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
  201. { title: '操作', scopedSlots: { customRender: 'action' }, width: '13%', align: 'center' }
  202. ],
  203. // 加载数据方法 必须为 Promise 对象
  204. loadData: parameter => {
  205. this.disabled = true
  206. this.productForm.salesBillSn = this.$route.params.sn
  207. return salesDetailStockList(Object.assign(parameter, this.productForm)).then(res => {
  208. const data = res.data
  209. const no = (data.pageNo - 1) * data.pageSize
  210. for (var i = 0; i < data.list.length; i++) {
  211. data.list[i].no = no + i + 1
  212. data.list[i].qtyBackups = data.list[i].qty
  213. }
  214. this.disabled = false
  215. this.dataSource = data.list
  216. this.$refs.promotable.getData(this.salesBillSn)
  217. return data
  218. })
  219. },
  220. openGuideModal: false // 导入产品引导
  221. }
  222. },
  223. methods: {
  224. // 已选产品 blur
  225. onCellBlur (val, record) {
  226. const _this = this
  227. // 光标移出,值发生改变再调用编辑接口
  228. if (val && val != record.qtyBackups) {
  229. _this.spinning = true
  230. salesDetailUpdateQty({
  231. salesBillDetailSn: record.salesBillDetailSn,
  232. qty: record.qty,
  233. salesBillSn: _this.salesBillSn
  234. }).then(res => {
  235. _this.resetSearchForm(true)
  236. _this.$refs.promotable.resetCurForm()
  237. if (res.status == 200) {
  238. _this.$message.success(res.message)
  239. }
  240. _this.spinning = false
  241. })
  242. } else {
  243. record.qty = record.qtyBackups
  244. }
  245. },
  246. // 重置
  247. resetSearchForm (flag) {
  248. this.$refs.table.refresh(!!flag)
  249. this.getPromoacActiveList()
  250. this.getOrderDetail(false)
  251. },
  252. // 返回
  253. handleBack () {
  254. this.$router.push({ path: '/salesManagement/salesQuery/list', query: { closeLastOldTab: true } })
  255. },
  256. // 整单删除
  257. delSalerDetailAll () {
  258. const _this = this
  259. this.$confirm({
  260. title: '提示',
  261. content: '确认要整单删除吗?',
  262. centered: true,
  263. closable: true,
  264. onOk () {
  265. _this.delLoading = true
  266. _this.spinning = true
  267. salesDetailDelAll({ salesBillSn: _this.salesBillSn }).then(res => {
  268. if (res.status == 200) {
  269. _this.resetSearchForm()
  270. _this.$refs.promotable.resetCurForm()
  271. _this.$message.success(res.message)
  272. }
  273. _this.delLoading = false
  274. _this.spinning = false
  275. })
  276. }
  277. })
  278. },
  279. // 删除产品
  280. handleDel (row) {
  281. const _this = this
  282. this.$confirm({
  283. title: '提示',
  284. content: '确认要删除吗?',
  285. centered: true,
  286. closable: true,
  287. onOk () {
  288. _this.delLoading = true
  289. _this.spinning = true
  290. salesDetailDel({ salesBillDetailSn: row.salesBillDetailSn, salesBillSn: _this.salesBillSn }).then(res => {
  291. if (res.status == 200) {
  292. _this.resetSearchForm(true)
  293. _this.$refs.promotable.resetCurForm()
  294. _this.$message.success(res.message)
  295. }
  296. _this.delLoading = false
  297. _this.spinning = false
  298. })
  299. }
  300. })
  301. },
  302. // 添加产品
  303. insterProduct (row, promotionFlag) {
  304. console.log(row)
  305. // 防止多次添加产品
  306. if (this.isInster) { return }
  307. const _this = this
  308. _this.saveNewProduct(row, promotionFlag)
  309. },
  310. // 保存添加的产品到销售列表
  311. saveNewProduct (row, promotionFlag) {
  312. this.$message.loading('正在添加产品...', 1)
  313. this.isInster = true
  314. this.spinning = true
  315. salesDetailInsert({
  316. packQty: row.productPackQty,
  317. productSn: row.productSn,
  318. showCost: row.lastStockCost,
  319. price: row.productPrice,
  320. origPrice: row.productPrice,
  321. promotionGiftsAmount: 0,
  322. usePromotionGiftsAmount: 0,
  323. qty: row.salesNums,
  324. salesBillSn: this.detailData.salesBillSn,
  325. salesBillNo: this.detailData.salesBillNo,
  326. purchaseBillSn: this.detailData.purchaseBillSn,
  327. purchaseBillNo: this.detailData.purchaseBillNo,
  328. stockSn: row.stockSn,
  329. promotableFlag: row.isJoinActivityProduct || 0, // 可促销标记 有活动的传1,没活动的传0
  330. promotionFlag: promotionFlag // 促销标记 正品传0,促销品传1
  331. }).then(res => {
  332. if (res.status == 200) {
  333. this.resetSearchForm()
  334. this.$message.success('产品添加成功', 2.5)
  335. this.spinning = false
  336. } else {
  337. this.spinning = false
  338. }
  339. this.isInster = false
  340. })
  341. },
  342. // 销售单详情
  343. getOrderDetail (flag) {
  344. salesDetailBySn({ salesBillSn: this.$route.params.sn }).then(res => {
  345. if (res.status == 200) {
  346. this.detailData = res.data
  347. if (flag) {
  348. this.$refs.partQuery.pageInit(this.detailData && this.detailData.buyerSn || '')
  349. }
  350. }
  351. })
  352. },
  353. // 提交销售单
  354. handleSubmit () {
  355. this.spinning = true
  356. salesWriteSubmit({ salesBillSn: this.salesBillSn }).then(res => {
  357. if (res.status == 200) {
  358. this.handleBack()
  359. this.$message.success(res.message)
  360. this.spinning = false
  361. } else {
  362. this.spinning = false
  363. }
  364. })
  365. },
  366. // 获取促销活动
  367. getPromoacActiveList () {
  368. const _this = this
  369. getPromoacActiveList({ salesBillSn: this.salesBillSn }).then(res => {
  370. if (res.status == 200) {
  371. _this.activeName = ''
  372. res.data.map(item => {
  373. _this.activeName += item.name + '、'
  374. })
  375. _this.activeName = _this.activeName.slice(0, _this.activeName.length - 1)
  376. }
  377. })
  378. },
  379. // 选择促销品
  380. handleSelCx (row) {
  381. // this.nowData = row
  382. this.newActive = true
  383. this.$refs.activeProduct.getData(row, this.detailData && this.detailData.buyerSn || '')
  384. },
  385. // 批量添加促销品
  386. addNewActive (list) {
  387. const temp = []
  388. list.map(item => {
  389. temp.push(Object.assign(item, {
  390. salesBillSn: this.detailData.salesBillSn,
  391. salesBillNo: this.detailData.salesBillNo,
  392. purchaseBillSn: this.detailData.purchaseBillSn,
  393. purchaseBillNo: this.detailData.purchaseBillNo
  394. }))
  395. })
  396. this.isInster == true
  397. this.spinning = true
  398. addPromoGoods(temp).then(res => {
  399. if (res.status == 200) {
  400. this.$refs.promotable.getData(this.salesBillSn)
  401. this.getOrderDetail(false)
  402. this.newActive = false
  403. this.isInster == false
  404. this.spinning = false
  405. } else {
  406. this.spinning = false
  407. }
  408. })
  409. },
  410. closeActive () {
  411. this.nowData = null
  412. this.newActive = false
  413. },
  414. closeGuideModel () {
  415. this.openGuideModal = false
  416. },
  417. // 导入产品
  418. hanldeOk (obj) {
  419. salesBatchInsert(obj).then(res => {
  420. if (res.status == 200) {
  421. this.$refs.table.refresh(true)
  422. this.getOrderDetail(false)
  423. }
  424. })
  425. },
  426. pageInit () {
  427. this.getOrderDetail(true)
  428. this.$refs.table.refresh(true)
  429. this.salesBillSn = this.$route.params.sn
  430. // 获取促销活动
  431. this.getPromoacActiveList()
  432. }
  433. },
  434. mounted () {
  435. if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
  436. this.pageInit()
  437. }
  438. },
  439. activated () {
  440. // 如果是新页签打开或者进入新的子页(例:存在列表第2条数据编辑页页签时再打开第4条数据的编辑页),则重置当前页面
  441. if (this.$store.state.app.isNewTab || !this.$store.state.app.isNewSubTab) {
  442. this.pageInit()
  443. }
  444. },
  445. beforeRouteEnter (to, from, next) {
  446. next(vm => {})
  447. }
  448. }
  449. </script>
  450. <style lang="less">
  451. .salesEdit-wrap{
  452. position: relative;
  453. height: 100%;
  454. padding-bottom: 51px;
  455. box-sizing: border-box;
  456. >.ant-spin-nested-loading{
  457. overflow-y: scroll;
  458. height: 100%;
  459. }
  460. .salesEdit-cont{
  461. margin-top: 10px;
  462. }
  463. .p-title{
  464. font-weight: bold;
  465. font-size: 16px;
  466. }
  467. .p-notes{
  468. font-size: 14px;
  469. span{
  470. color: #FF9900;
  471. }
  472. }
  473. .redStyle{
  474. font-weight: bold;
  475. color: red;
  476. }
  477. .ellipsisCon{
  478. display: flex;
  479. justify-content: space-between;
  480. align-items: center;
  481. .ellipsisText{
  482. width: 100%;
  483. overflow: hidden;
  484. text-overflow: ellipsis;
  485. display: box;
  486. display: -webkit-box;
  487. -webkit-line-clamp: 1;
  488. -webkit-box-orient: vertical;
  489. }
  490. }
  491. .total-bar{
  492. display: flex;
  493. align-items: center;
  494. justify-content: space-between;
  495. > div{
  496. &:last-child{
  497. display: flex;
  498. align-items: center;
  499. justify-content: space-between;
  500. > div{
  501. padding: 0 10px;
  502. }
  503. }
  504. }
  505. }
  506. .redBg-row{
  507. background-color: #f5cdc8;
  508. }
  509. }
  510. </style>