edit.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. <template>
  2. <div class="salesNewEdit-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;font-weight: bold;">单号:{{ detailData&&detailData.salesBillNo }}</span>
  9. <span v-if="detailData&&detailData.salesBillNoSource">(原:{{ detailData&&detailData.salesBillNoSource || '--' }})</span>
  10. <a-button type="link" class="button-default" @click="showDetail=!showDetail">
  11. <a-icon :type="showDetail ? 'eye-invisible' : 'eye'"/> {{ showDetail?'隐藏':'查看' }}信息
  12. </a-button>
  13. </template>
  14. </a-page-header>
  15. <!-- 单据详情 -->
  16. <a-card size="small" :bordered="false" class="salesEdit-cont" v-show="showDetail">
  17. <div style="padding: 10px;">
  18. <a-descriptions size="small" :column="3">
  19. <a-descriptions-item label="客户名称">{{ detailData&&detailData.buyerName || '--' }}</a-descriptions-item>
  20. <a-descriptions-item label="收货地址" :span="2">{{ shippingAddress||'--' }}</a-descriptions-item>
  21. <a-descriptions-item label="收货人">{{ detailData&&detailData.salesBillExtEntity&&detailData.salesBillExtEntity.consigneeName || '--' }}</a-descriptions-item>
  22. <a-descriptions-item label="收货电话">{{ detailData&&detailData.salesBillExtEntity&&detailData.salesBillExtEntity.consigneeTel || '--' }}</a-descriptions-item>
  23. <a-descriptions-item label="收款方式">{{ detailData&&detailData.settleStyleSnDictValue || '--' }}</a-descriptions-item>
  24. <a-descriptions-item label="审核时间">{{ detailData&&detailData.auditDate || '--' }}</a-descriptions-item>
  25. <a-descriptions-item label="业务状态">{{ detailData&&detailData.billStatusDictValue || '--' }}</a-descriptions-item>
  26. <a-descriptions-item label="财务状态">{{ detailData&&detailData.financialStatusDictValue || '--' }}</a-descriptions-item>
  27. <a-descriptions-item label="备注" :span="3">{{ detailData&&detailData.remarks || '--' }}</a-descriptions-item>
  28. </a-descriptions>
  29. </div>
  30. </a-card>
  31. <!-- 正常产品 -->
  32. <a-card size="small" :bordered="false" class="salesEdit-cont" v-if="salesBillSn">
  33. <div style="padding: 10px;">
  34. <productNormalList
  35. ref="productNormalList"
  36. @insterOk="insterActiveOk"
  37. @openCpModal="openProductModal"
  38. :showTotal="activeList.length>0"
  39. :detailData="detailData"
  40. :warehouseSn="warehouseSn"
  41. :salesBillSn="salesBillSn"></productNormalList>
  42. </div>
  43. </a-card>
  44. <!-- 活动产品 -->
  45. <a-card
  46. size="small"
  47. :bordered="false"
  48. class="salesEdit-cont"
  49. v-for="item in activeList"
  50. :key="item.promoRuleSn"
  51. v-if="activeList.length"
  52. >
  53. <div slot="title" style="display: inline-block;width:100%;">
  54. <strong style="margin-right:10px;font-size:14px;">{{item.promotion.title}}</strong> ({{item.promotionRule.description}})
  55. <span style="margin-left:20px;color:#00aaff;cursor: pointer;" @click="(event) => {showDesc(event, item)}">
  56. <a-icon title="查看活动详情" type="eye"/> 活动详情
  57. </span>
  58. <span style="margin:0 20px;color:#ff0800;cursor: pointer;" @click="(event) => {disabledActive(event, item)}">
  59. <a-icon title="禁用规则" type="disconnect"/> 禁用规则
  60. </span>
  61. </div>
  62. <div slot="extra" @click="tooglePanel(item)" style="cursor: pointer;">{{ item.isActive ? '收起' : '展开' }} <a-icon type="caret-right" :rotate="item.isActive ? 90 : 0"/> </div>
  63. <div v-show="item.isActive" style="padding: 10px;">
  64. <productList
  65. :ref="'productList-'+item.promoRuleSn"
  66. :id="item.promoRuleSn"
  67. @openCpModal="openProductModal"
  68. @insterOk="insterActiveOk"
  69. @upActive="upActive"
  70. :promo="item"
  71. :detailData="detailData"
  72. :warehouseSn="warehouseSn"
  73. :salesBillSn="salesBillSn"></productList>
  74. </div>
  75. </a-card>
  76. </a-spin>
  77. <div class="affix-cont">
  78. <div class="footer-price">
  79. <div></div>
  80. <div v-if="detailData">
  81. <div class="totalPrice">总售价:¥<span>{{ toThousands(detailData.totalAmount) }}</span></div>
  82. <div>
  83. 产品总款数:<strong style="margin-right: 10px;"> {{ detailData.totalCategory }} </strong>
  84. 总数量:<strong> {{ detailData.totalQty }} </strong>
  85. <span style="margin:0 0 0 10px;" v-if="detailData.totalLossAmount">优惠金额:¥<strong>{{ toThousands(detailData.totalLossAmount) }}</strong></span>
  86. <a-popover title="优惠明细" @visibleChange="(visible)=>{visible&&getPromYhDetail()}">
  87. <a-button shape="round" size="small" v-if="detailData.totalLossAmount">优惠明细</a-button>
  88. <div slot="content">
  89. <div v-if="yhDetail">
  90. <div
  91. class="yhdetail"
  92. style="min-width:300px;margin-bottom: 5px;"
  93. v-for="(item,index) in yhDetail.promoMapList"
  94. :key="index">
  95. <div class="yhdetail-h" style="font-weight: bold;font-size:14px;">{{ item.title }}</div>
  96. <div style="padding-left:10px;"
  97. v-for="(sitem,sindex) in item.promoRuleMapList"
  98. :key="sindex"
  99. v-if="sitem.lossAmount"
  100. >
  101. <div style="display: flex;justify-content: space-between;">
  102. <span>{{sitem.promotionRuleTypeDictValue}}:</span>
  103. <strong>¥{{ toThousands(sitem.lossAmount) }}</strong>
  104. </div>
  105. <div class="yhdetail-d" style="color:#999;">{{ sitem.description }}</div>
  106. </div>
  107. </div>
  108. <div class="yhdetail" style="display: flex;justify-content: space-between;">
  109. <span style="font-weight: bold;font-size:14px;">优惠金额:</span>
  110. <span style="font-weight: bold;font-size:18px;">¥{{ toThousands(yhDetail.totalLossAmount) }}</span>
  111. </div>
  112. </div>
  113. <div style="text-align: center;padding: 20px;" v-else>
  114. 正在加载...
  115. </div>
  116. </div>
  117. </a-popover>
  118. </div>
  119. </div>
  120. </div>
  121. <div>
  122. <a-button
  123. size="large"
  124. style="padding: 0 60px;"
  125. :disabled="spinning"
  126. type="primary"
  127. class="button-primary"
  128. @click="handleSubmit()"
  129. id="productInfoList-handleSubmit">提交</a-button>
  130. </div>
  131. </div>
  132. <!-- 添加产品 -->
  133. <chooseProduct
  134. ref="chooseProduct"
  135. :openModal="showCpModal"
  136. @close="closeProductModal"
  137. @addProduct="insterProduct"></chooseProduct>
  138. <!-- 价格更新弹窗 -->
  139. <setPriceModal
  140. :show="priceUpdateModal"
  141. :totalRealAmount="updataData.totalRealAmount"
  142. :totalAmount="updataData.totalAmount"
  143. @ok="updatePrice"
  144. @cancel="priceUpdateModal=false"></setPriceModal>
  145. <!-- 新活动窗口 -->
  146. <newPromoModal
  147. :show="showNewActiveModal"
  148. :salesBillSn="salesBillSn"
  149. :newActiveList="newActiveList"
  150. ></newPromoModal>
  151. </div>
  152. </template>
  153. <script>
  154. import { commonMixin } from '@/utils/mixin'
  155. import productList from './comps/productList.vue'
  156. import productNormalList from './comps/productNormalList.vue'
  157. import chooseProduct from './comps/chooseProduct.vue'
  158. import setPriceModal from './setPriceModal.vue'
  159. import newPromoModal from './newPromoModal.vue'
  160. import { salesDisablePromo, salesChangePromo } from '@/api/salesDetailNew'
  161. import { salesDetailBySn,salesPromoQueryCount, salesWriteSubmit, submitCheck, updateBatch, salesPromoQueryList, salesQueryUnPartPromo,salesPromoValidaSubmit } from '@/api/salesNew'
  162. export default {
  163. name: 'SalesNewEdit',
  164. mixins: [commonMixin],
  165. components:{
  166. setPriceModal,
  167. productList,
  168. chooseProduct,
  169. productNormalList,
  170. newPromoModal
  171. },
  172. data () {
  173. return {
  174. spinning: false,
  175. activeList:[], // 活动列表
  176. newActiveList: [], // 新活动列表
  177. activeDesKey: {},
  178. salesBillSn: null, // 销售单sn
  179. detailData: { discountAmount: 0, id: null, salesBillSn: '' }, // 订单基础数据
  180. warehouseSn: undefined,
  181. updataData: {
  182. totalRealAmount: '',
  183. totalAmount: ''
  184. },
  185. priceUpdateModal: false, // 价格更新弹窗
  186. showDetail: false,
  187. showCpModal: false,
  188. cpCurRefId: '',
  189. disabledActiveOption: null,
  190. yhDetail: null,
  191. showNewActiveModal: false
  192. }
  193. },
  194. computed: {
  195. shippingAddress () {
  196. const shippingAddrProvinceName = this.detailData && this.detailData.salesBillExtEntity && this.detailData.salesBillExtEntity.shippingAddrProvinceName ? this.detailData.salesBillExtEntity.shippingAddrProvinceName : ''
  197. const shippingAddrCityName = this.detailData && this.detailData.salesBillExtEntity && this.detailData.salesBillExtEntity.shippingAddrCityName ? this.detailData.salesBillExtEntity.shippingAddrCityName : ''
  198. const shippingAddrCountyName = this.detailData && this.detailData.salesBillExtEntity && this.detailData.salesBillExtEntity.shippingAddrCountyName ? this.detailData.salesBillExtEntity.shippingAddrCountyName : ''
  199. const shippingAddr = this.detailData && this.detailData.salesBillExtEntity && this.detailData.salesBillExtEntity.shippingAddr ? this.detailData.salesBillExtEntity.shippingAddr : ''
  200. if (!shippingAddrProvinceName && !shippingAddrCityName && !shippingAddrCountyName && !shippingAddr) {
  201. return '--'
  202. } else {
  203. return shippingAddrProvinceName + shippingAddrCityName + shippingAddrCountyName + shippingAddr
  204. }
  205. }
  206. },
  207. methods: {
  208. // 返回
  209. handleBack () {
  210. this.$router.push({ name: 'salesQueryNewList', query: { closeLastOldTab: true } })
  211. },
  212. tooglePanel(item){
  213. item.isActive=!item.isActive
  214. this.activeList.splice()
  215. },
  216. // 销售单详情
  217. getOrderDetail (flag) {
  218. salesDetailBySn({ salesBillSn: this.$route.params.sn }).then(res => {
  219. if (res.status == 200) {
  220. this.detailData = res.data
  221. }
  222. if(flag){
  223. this.getActiveList()
  224. }
  225. })
  226. },
  227. // 优惠明细查看
  228. getPromYhDetail(){
  229. salesPromoQueryCount({salesBillSn: this.$route.params.sn }).then(res => {
  230. if (res.status == 200) {
  231. this.yhDetail = res.data
  232. }
  233. })
  234. },
  235. // 获取销售单参与的活动列表
  236. async getActiveList(){
  237. const hasNewActive = await salesQueryUnPartPromo({ salesBillSn: this.$route.params.sn }).then(res => res.data)
  238. // 有新活动
  239. if(hasNewActive.length){
  240. this.newActiveList = hasNewActive
  241. this.showNewActiveModal=true
  242. }
  243. this.activeList = await salesPromoQueryList({ salesBillSn: this.$route.params.sn }).then(res => res.data || [])
  244. this.activeList.map(item => {
  245. item.isActive = true
  246. this.activeDesKey['search-'+item.promoRuleSn] = false
  247. })
  248. },
  249. showNewActiveOk(){
  250. this.pageInit()
  251. },
  252. // 添加产品,包括正常和活动的产品
  253. closeProductModal(){
  254. this.cpCurRefId = ''
  255. this.showCpModal = false
  256. },
  257. // 打开选择产品弹框
  258. openProductModal(type, refId){
  259. console.log(type, refId)
  260. const promo = this.activeList.find(item => item.promoRuleSn == refId)
  261. this.$refs.chooseProduct.pageInit(this.detailData, promo, type)
  262. this.cpCurRefId = 'productList-' + refId
  263. this.showCpModal = true
  264. },
  265. // 添加活动产品成功的回调
  266. insterActiveOk(type){
  267. if(type == 'promo'){
  268. // 刷新正常产品列表
  269. this.$refs.productNormalList.resetSearchForm()
  270. }
  271. if(type == 'normal'){
  272. // 刷新活动产品列表
  273. this.activeList.map(item => {
  274. this.$refs['productList-' + item.promoRuleSn][0].resetSearchForm()
  275. })
  276. }
  277. this.getOrderDetail()
  278. },
  279. // 新增产品
  280. insterProduct(row, promotionFlag, type){
  281. // 正常产品
  282. if(type == 0){
  283. this.$refs.productNormalList.insterProduct(row, promotionFlag)
  284. }else{
  285. // 活动产品
  286. this.$refs[this.cpCurRefId][0].insterProduct(row, promotionFlag, type)
  287. }
  288. },
  289. // 更换活动
  290. upActive(oldPromo,data,params){
  291. const promo = data.split('-')
  292. const newSn = this.activeList.find(item => item.promoRuleSn == promo[1])
  293. const newSalesPromoSn = newSn && newSn.salesPromoSn || ''
  294. salesChangePromo({
  295. salesPromoSn: data != 0 ? newSalesPromoSn : '',
  296. promoRuleSn: promo[1],
  297. promotionFlag: promo[2]||'',
  298. ...params
  299. }).then(res => {
  300. if(res.status == 200){
  301. // 刷新新参与活动
  302. if(data != 0){
  303. this.$refs['productList-'+promo[1]][0].resetSearchForm()
  304. }
  305. // 刷新正常活动
  306. this.$refs.productNormalList.resetSearchForm()
  307. // 刷新当前活动
  308. this.$refs['productList-'+oldPromo.promoRuleSn][0].upAcitveSuccess()
  309. }
  310. })
  311. },
  312. // 选择价格类型 并更新
  313. updatePrice (type) {
  314. const _this = this
  315. if (type == 0) {
  316. const ajax_data = {
  317. salesBillSn: _this.salesBillSn,
  318. productPriceChangeFlag: type
  319. }
  320. _this.submitResult(ajax_data)
  321. } else {
  322. updateBatch(_this.updataData.detailList).then(res => {
  323. if (res.status == 200) {
  324. const ajax_data = {
  325. salesBillSn: _this.salesBillSn,
  326. productPriceChangeFlag: type
  327. }
  328. _this.submitResult(ajax_data)
  329. }
  330. })
  331. }
  332. },
  333. // 提交销售单
  334. handleSubmit () {
  335. // 先不提交,先判断是否有价格更新 (下级创建时判断)
  336. if (this.detailData && this.detailData.salesBillSource && this.detailData.salesBillSource == 'PURCHASE') {
  337. submitCheck({ salesBillSn: this.salesBillSn }).then(res => {
  338. if (res.status == 200) {
  339. if (res.data.detailList.length > 0) {
  340. this.updataData = res.data
  341. const _this = this
  342. this.$nextTick(() => {
  343. _this.priceUpdateModal = true
  344. })
  345. } else {
  346. this.submitResult({ salesBillSn: this.salesBillSn })
  347. }
  348. }
  349. })
  350. } else {
  351. this.submitResult({ salesBillSn: this.salesBillSn })
  352. }
  353. },
  354. // 提交销售单
  355. async submitResult (data) {
  356. const _this = this
  357. // 校验活动规则
  358. const vaildActive = await salesPromoValidaSubmit({salesBillSn: this.salesBillSn}).then(res => res.data)
  359. // console.log(vaildActive)
  360. const a = vaildActive.filter(item => item.type == 1) // 不可提交
  361. const b = vaildActive.filter(item => item.type == 0) // 可跳过继续提交
  362. // 弹出不符合规则弹框,不可提交
  363. if(a.length){
  364. this.$info({
  365. title: '提示',
  366. centered: true,
  367. class:'confirm-center',
  368. okText:'关闭',
  369. width: 600,
  370. content: <div style="padding-top:15px;">
  371. <ol>
  372. {a.map(item => (
  373. <li style="padding:3px 0;">{item.message}</li>
  374. ))}
  375. </ol>
  376. <div style="padding:10px 0;text-align:center"><strong>请按照以上提示修改后再提交</strong></div>
  377. </div>
  378. });
  379. }else{
  380. // 弹出确认提示信息,可跳过继续提交
  381. if(b.length){
  382. this.$confirm({
  383. title: '提示',
  384. centered: true,
  385. class:'confirm-center',
  386. okText:'提交',
  387. width: 600,
  388. content: <div style="padding-top:15px;">
  389. <ol>
  390. {b.map(item => (
  391. <li style="padding:3px 0;">{item.message}</li>
  392. ))}
  393. </ol>
  394. <div style="padding:10px 0;text-align:center"><strong>继续提交将无法享受优惠</strong></div>
  395. </div>,
  396. onOk() {
  397. _this.submitOrder(data)
  398. }
  399. });
  400. }else{
  401. _this.submitOrder(data)
  402. }
  403. }
  404. },
  405. async submitOrder(data){
  406. this.spinning = true
  407. const res = await salesWriteSubmit(data)
  408. if (res.status == 200) {
  409. this.handleBack()
  410. this.$message.success(res.message)
  411. }
  412. this.spinning = false
  413. },
  414. // 展开收缩活动详情
  415. showDesc(e,item){
  416. e.stopPropagation()
  417. const row = this.$refs['productList-'+item.promoRuleSn][0]
  418. row&&row.showDesc(item.promotionRule)
  419. },
  420. // 禁用活动
  421. disabledActive(e,item){
  422. const _this = this
  423. if(item.disabled){
  424. this.$message.info("规则已经禁用!")
  425. return
  426. }
  427. this.$confirm({
  428. title: '确定禁用规则?',
  429. centered: true,
  430. class:'confirm-center',
  431. content: <div>
  432. <div style="padding:10px 0;text-align:center;">禁用规则后,将无法享受该活动规则优惠</div>
  433. <div style="padding:0 0 10px 0;text-align:center;">
  434. <aRadioGroup onChange={_this.changeDaOpt}>
  435. <aRadio style="display:block;height: '30px';lineHeight: '30px';padding:5px 0;" value="DELETE">
  436. 删除规则中相关产品
  437. </aRadio>
  438. <aRadio style="display:block;height: '30px';lineHeight: '30px';padding:5px 0;" value="REMOVE">
  439. 移出规则中相关产品
  440. </aRadio>
  441. </aRadioGroup>
  442. </div>
  443. </div>,
  444. onOk() {
  445. if(_this.disabledActiveOption){
  446. salesDisablePromo({
  447. salesBillSn: _this.salesBillSn,
  448. salesPromoSn: item.salesPromoSn,
  449. promoRuleSn: item.promoRuleSn,
  450. salesDisableType: _this.disabledActiveOption
  451. }).then(res => {
  452. if(res.status == 200){
  453. _this.$refs['productList-'+item.promoRuleSn][0].disableActive()
  454. _this.disabledActiveOption = null
  455. item.disabled = true
  456. }
  457. })
  458. }else{
  459. _this.$message.info("请选择如何禁用规则!")
  460. return true
  461. }
  462. },
  463. onCancel() {
  464. _this.disabledActiveOption = null
  465. },
  466. });
  467. },
  468. changeDaOpt(e){
  469. console.log(e)
  470. this.disabledActiveOption = e.target.value
  471. },
  472. pageInit () {
  473. this.salesBillSn = this.$route.params.sn
  474. this.warehouseSn = this.$route.params.sn ? this.$route.params.wSn : ''
  475. this.getOrderDetail(true)
  476. }
  477. },
  478. mounted () {
  479. if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
  480. this.pageInit()
  481. }
  482. },
  483. activated () {
  484. // 如果是新页签打开或者进入新的子页(例:存在列表第2条数据编辑页页签时再打开第4条数据的编辑页),则重置当前页面
  485. if (this.$store.state.app.isNewTab || !this.$store.state.app.isNewSubTab) {
  486. this.pageInit()
  487. }
  488. },
  489. beforeRouteEnter (to, from, next) {
  490. next(vm => {})
  491. }
  492. }
  493. </script>
  494. <style lang="less">
  495. .salesNewEdit-wrap{
  496. position: relative;
  497. height: 100%;
  498. padding-bottom: 75px;
  499. box-sizing: border-box;
  500. >.ant-spin-nested-loading{
  501. overflow-y: auto;
  502. height: 100%;
  503. }
  504. .salesEdit-cont{
  505. margin: 10px 0;
  506. }
  507. .redStyle{
  508. font-weight: bold;
  509. color: red;
  510. }
  511. .ellipsisCon{
  512. display: flex;
  513. justify-content: space-between;
  514. align-items: center;
  515. .ellipsisText{
  516. width: 100%;
  517. overflow: hidden;
  518. text-overflow: ellipsis;
  519. display: box;
  520. display: -webkit-box;
  521. -webkit-line-clamp: 1;
  522. -webkit-box-orient: vertical;
  523. }
  524. }
  525. .ant-card-small > .ant-card-body {
  526. padding: 0!important;
  527. }
  528. .affix-cont{
  529. padding: 10px 15px;
  530. text-align: right;
  531. display: flex;
  532. justify-content: space-between;
  533. align-items: center;
  534. .footer-price{
  535. flex-grow:1;
  536. display: flex;
  537. justify-content: flex-end;
  538. align-items: center;
  539. > div{
  540. padding: 0 15px;
  541. }
  542. .totalPrice{
  543. span{
  544. font-weight: bold;
  545. color: red;
  546. font-size: 20px;
  547. }
  548. }
  549. }
  550. }
  551. }
  552. </style>