postProduct.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. <template>
  2. <!-- 发布商品页面 -->
  3. <div class="post-product-page">
  4. <div class="prod-main-containers">
  5. <!-- 步骤 -->
  6. <div class="post-step">
  7. <div class="step-item" :class="{'active': postingSteps === 1 || postingSteps === 2 || postingSteps === 3}">
  8. <!-- 01、选择商品类目 -->
  9. <div class="step-txt">01、{{ $t("product.selectProductCategory") }}</div>
  10. </div>
  11. <div class="step-item" :class="{'active': postingSteps === 2 || postingSteps === 3}">
  12. <!-- 02、编辑商品信息 -->
  13. <div class="step-txt">02、{{ $t("product.editProductInfo") }}</div>
  14. </div>
  15. <div class="step-item" :class="{'active': postingSteps === 3}">
  16. <!-- 03、编辑商品详情 -->
  17. <div class="step-txt">03、{{ $t("product.editProductDetails") }}</div>
  18. </div>
  19. </div>
  20. <!-- 内容 -->
  21. <div class="prod-content">
  22. <!-- 01、选择商品类目 -->
  23. <div v-if="postingSteps === 1" class="prod-content-item">
  24. <selectCategory
  25. v-model="dataForm"
  26. @selectedCategoryName="selectedCategoryName"
  27. @refreshDataForm="getDataList"
  28. />
  29. </div>
  30. <!-- 02、编辑商品信息 -->
  31. <div v-if="postingSteps === 2" class="prod-content-item">
  32. <editProduct
  33. ref="editProduct"
  34. v-model="dataForm"
  35. :isCompose="isCompose"
  36. :platCategoryName="platCategoryName"
  37. :storeCategoryName="storeCategoryName"
  38. @changeCategory="changeCategory"
  39. @updataProdDataForm="updataProdDataForm"
  40. @changeWriteOffTime="changeWriteOffTime"
  41. @updateSkuTags="updateSkuTags"
  42. />
  43. </div>
  44. <!-- 03、编辑商品详情 -->
  45. <div v-if="postingSteps === 3" class="prod-content-item">
  46. <productDetails
  47. v-model="dataForm"
  48. @updateContent="updateContent"
  49. />
  50. </div>
  51. </div>
  52. </div>
  53. <!-- 底部固定操作栏 -->
  54. <div class="prod-footer">
  55. <div class="foot">
  56. <div class="inner">
  57. <div v-if="postingSteps === 1" class="default-btn primary-btn" @click="nextStep">{{ $t("product.nextStep1") }}</div>
  58. <div v-if="postingSteps === 2">
  59. <div class="default-btn" @click="prevStep">{{ $t("product.prevStep") }}</div>
  60. <div class="default-btn save-btn" @click="saveStep">{{ $t("product.saveBtn1") }}</div>
  61. <div class="default-btn primary-btn" @click="nextStep">{{ $t("product.nextStep2") }}</div>
  62. </div>
  63. <div v-if="postingSteps === 3">
  64. <div class="default-btn" @click="prevStep">{{ $t("product.prevStep") }}</div>
  65. <div class="default-btn primary-btn" @click="saveStep">{{ $t("product.saveBtn1") }}</div>
  66. </div>
  67. </div>
  68. </div>
  69. </div>
  70. </div>
  71. </template>
  72. <script>
  73. // import { idList } from '@/utils'
  74. import selectCategory from './posting-select-category'
  75. import editProduct from './posting-edit-product'
  76. import productDetails from './posting-product-details'
  77. export default {
  78. components: {
  79. selectCategory,
  80. editProduct,
  81. productDetails
  82. },
  83. data () {
  84. return {
  85. // 发布步骤:1选择商品类目 2编辑商品信息 3编辑商品详情
  86. postingSteps: null,
  87. // 商品详情信息
  88. dataForm: {
  89. // 商品类型(0普通商品 1拼团 2秒杀 3积分 5活动商品)
  90. prodType: 0,
  91. mold: 0,
  92. prodNameEn: '',
  93. prodNameCn: '',
  94. contentEn: '',
  95. contentCn: '',
  96. briefEn: '',
  97. briefCn: '',
  98. video: '',
  99. pic: '',
  100. imgs: '',
  101. isCompose: 0,
  102. preSellStatus: 0,
  103. preSellTime: null,
  104. categoryId: this.$route.query.categoryId ? parseInt(this.$route.query.categoryId) : null,
  105. shopCategoryId: null, // 店铺分类id
  106. prodId: 0,
  107. brandId: 0,
  108. skuList: [],
  109. prodLangList: [],
  110. brandName: '',
  111. deliveryMode: {
  112. hasShopDelivery: true,
  113. hasUserPickUp: false,
  114. hasCityDelivery: false
  115. },
  116. // 运费模板id
  117. deliveryTemplateId: null,
  118. // 库存总和
  119. totalStocks: 0,
  120. useLang: 0 // 0中文 1中英文
  121. },
  122. skuTags:[],
  123. // 平台选定分类名称
  124. platCategoryName: '',
  125. // 店铺选定分类名称
  126. storeCategoryName: '',
  127. isCompose: 0,
  128. page: {
  129. total: 0, // 总页数
  130. currentPage: 1, // 当前页数
  131. pageSize: 10 // 每页显示多少条
  132. },
  133. // 自定义核销有效天数
  134. validDays: 0,
  135. // 根据商品id返回来的商品类型
  136. originalProdType: null
  137. }
  138. },
  139. provide() {
  140. return {
  141. noshopCategoryId: this.noshopCategoryId
  142. }
  143. },
  144. watch: {
  145. isCompose (val) {
  146. }
  147. },
  148. mounted () {
  149. this.dataForm.prodId = this.$route.query.prodId
  150. this.page = this.$route.query.page ? JSON.parse(this.$route.query.page) : this.page
  151. if (!this.dataForm.prodId) {
  152. this.postingSteps = 1
  153. }
  154. // 获取产品详情数据
  155. this.getDataList()
  156. },
  157. methods: {
  158. updateSkuTags(skuTags){
  159. this.skuTags = skuTags;
  160. },
  161. /**
  162. * 获取产品详情数据
  163. */
  164. getDataList () {
  165. if (this.dataForm.prodId) {
  166. this.$http({
  167. url: this.$http.adornUrl(`/prod/prod/info/${this.dataForm.prodId}`),
  168. method: 'get',
  169. params: this.$http.adornParams()
  170. }).then(({ data }) => {
  171. this.dataForm = data
  172. this.dataForm.prodLangList.forEach(prodLang => {
  173. if (prodLang.lang === 0) {
  174. this.dataForm.prodNameCn = prodLang.prodName
  175. this.dataForm.briefCn = prodLang.brief
  176. this.dataForm.contentCn = prodLang.content
  177. }
  178. if (prodLang.lang === 1) {
  179. this.dataForm.prodNameEn = prodLang.prodName
  180. this.dataForm.briefEn = prodLang.brief
  181. this.dataForm.contentEn = prodLang.content
  182. }
  183. })
  184. this.dataForm.deliveryMode = JSON.parse(data.deliveryMode)
  185. this.dataForm.deliveryMode.hasShopDelivery = true
  186. // this.category.selected = idList(this.category.list, this.dataForm.categoryId, 'categoryId', 'children').reverse()
  187. // this.$refs.skuTag.init(data.skuList)
  188. if (data.brand) {
  189. this.dataForm.brandId = data.brand.brandId
  190. this.dataForm.brandName = data.brand.name
  191. }
  192. this.dataForm.skuList.forEach(sku => {
  193. sku.changeStock = parseInt(sku.stocks)
  194. sku.oriStock = parseInt(sku.stocks)
  195. sku.skuLangList.forEach(skulang => {
  196. if (skulang.lang === 0) {
  197. sku.prodNameCn = skulang.prodName
  198. } else {
  199. sku.prodNameEn = skulang.prodName
  200. }
  201. })
  202. })
  203. if (data.mold === 1 && data.writeOffTime !== -1 && data.writeOffTime !== 0 && data.writeOffTime !== 1) {
  204. this.changeWriteOffTime(data.writeOffTime)
  205. }
  206. // this.$refs.skuTable.init()
  207. this.postingSteps = 1
  208. this.$forceUpdate()
  209. }).catch(({ e }) => {
  210. this.postingSteps = 1
  211. // 出错,返回列表
  212. setTimeout(() => {
  213. this.$router.push('/prod-prodList')
  214. }, 1000)
  215. })
  216. } else {
  217. this.$nextTick(() => {
  218. this.postingSteps = 1
  219. // this.$refs['dataForm'].resetFields()
  220. // this.$refs.skuTag.init()
  221. this.dataForm.pic = ''
  222. this.dataForm.imgs = ''
  223. this.dataForm.video = ''
  224. this.brandName = ''
  225. })
  226. }
  227. },
  228. /**
  229. * 子组件更新数据
  230. */
  231. updataProdDataForm (value) {
  232. const dataForm = Object.assign(this.dataForm, value)
  233. this.dataForm = dataForm
  234. },
  235. /**
  236. * 获取选定的分类名称
  237. */
  238. selectedCategoryName (categoryName, categoryType) {
  239. if (categoryType === 'platform') {
  240. this.platCategoryName = categoryName
  241. }
  242. if (categoryType === 'store') {
  243. this.storeCategoryName = categoryName
  244. }
  245. },
  246. /**
  247. * 修改分类
  248. */
  249. changeCategory (type) {
  250. if (type === 1) {
  251. const platProdCategory = this.$store.state.prod.platProdCategory
  252. this.platCategoryName = platProdCategory.firstCat.categoryName +
  253. ' > ' +
  254. platProdCategory.secondCat.categoryName +
  255. ' > ' +
  256. platProdCategory.threeCat.categoryName
  257. this.dataForm.categoryId = platProdCategory.threeCat.id
  258. } else if (type === 2) {
  259. const storeProdCategory = this.$store.state.prod.storeProdCategory
  260. this.storeCategoryName = storeProdCategory.firstCat.categoryName
  261. this.dataForm.shopCategoryId = storeProdCategory.firstCat.id
  262. }
  263. },
  264. noshopCategoryId() {
  265. this.dataForm.shopCategoryId = ''
  266. },
  267. /**
  268. * 虚拟商品-获取自定义核销有效天数
  269. */
  270. changeWriteOffTime (validDays) {
  271. this.validDays = validDays
  272. },
  273. /**
  274. * 获取详情
  275. */
  276. updateContent (value, type) {
  277. if (type === 'cn') {
  278. this.$set(this.dataForm, 'content', value)
  279. this.$set(this.dataForm, 'contentCn', value)
  280. }
  281. if (type === 'en') {
  282. this.$set(this.dataForm, 'contentEn', value)
  283. }
  284. },
  285. /**
  286. * 下一步
  287. */
  288. nextStep () {
  289. if (this.postingSteps === 1) {
  290. if (!this.dataForm.categoryId) {
  291. // 请选择平台分类
  292. this.$message({
  293. message: this.$i18n.t('product.selectPlatformCategoryTips'),
  294. type: 'error',
  295. duration: 1000
  296. })
  297. return
  298. }
  299. if (!this.dataForm.shopCategoryId) {
  300. // 请选择店铺分类
  301. this.$message({
  302. message: this.$i18n.t('product.selectShopCategoryTips'),
  303. type: 'error',
  304. duration: 1000
  305. })
  306. return
  307. }
  308. }
  309. if (this.postingSteps === 2) {
  310. if (!this.$refs.editProduct.dataFormValidation()) {
  311. return
  312. }
  313. if (!this.dataForm.skuList.find(el => el.status)) {
  314. // 至少要启用一种商品规格
  315. this.$message({
  316. message: this.$i18n.t('product.enableSpec'),
  317. type: 'error',
  318. duration: 1500
  319. })
  320. return
  321. }
  322. }
  323. this.postingSteps += 1
  324. },
  325. /**
  326. * 上一步
  327. */
  328. prevStep () {
  329. if (this.postingSteps === 2) {
  330. // 返回第一步之前先更新已填写的商品信息
  331. this.$refs.editProduct.upadteProdInfo()
  332. }
  333. this.postingSteps -= 1
  334. },
  335. /**
  336. * 保存
  337. */
  338. saveStep () {
  339. if (this.postingSteps === 2 && !this.$refs.editProduct.dataFormValidation()) {
  340. return
  341. }
  342. this.dataFormSubmit()
  343. },
  344. paramSetPriceAndStocks (param) {
  345. // 获取规格属性信息
  346. // param.skuList = this.$refs.prodSpec.getTableSpecData()
  347. // 商品库存
  348. param.totalStocks = 0
  349. // 商品价格
  350. param.price = 0
  351. // 商品原价
  352. param.oriPrice = 0
  353. // 商品实际库存
  354. for (let i = 0; i < param.skuList.length; i++) {
  355. const element = param.skuList[i]
  356. if (element.status !== 1) {
  357. continue
  358. }
  359. if (param.price === 0) {
  360. param.price = element.price ? Number.parseFloat(element.price) : 0
  361. }
  362. // 商品价格为最低价的那件商品的价格
  363. param.price = Math.min(param.price, element.price)
  364. if ((param.price === element.price) || (Number.parseFloat(param.price) === Number.parseFloat(element.price))) {
  365. param.oriPrice = element.oriPrice ? Number.parseFloat(element.oriPrice) : 0
  366. }
  367. param.totalStocks += element.stocks ? Number.parseInt(element.stocks) : 0
  368. }
  369. // 如果sku没有商品名称,则使用商品的商品名称
  370. if (param.skuList.length === 1 && !param.skuList[0].skuName) {
  371. param.skuList[0].prodName = this.dataForm.prodName
  372. param.skuList[0].prodNameCn = this.dataForm.prodNameCn
  373. param.skuList[0].prodNameEn = this.dataForm.prodNameEn
  374. }
  375. },
  376. // 表单提交
  377. dataFormSubmit () {
  378. console.log(this.skuTags);
  379. if (!this.dataForm.categoryId || !this.dataForm.shopCategoryId) {
  380. // 请选择商品分类
  381. this.errorMsg(this.$i18n.t('product.thisProduCategroy'))
  382. return
  383. }
  384. if (!this.dataForm.skuList.find(el => el.status)) {
  385. // 至少要启用一种商品规格
  386. this.$message({
  387. message: this.$i18n.t('product.enableSpec'),
  388. type: 'error',
  389. duration: 1000
  390. })
  391. return
  392. }
  393. //skuMap拼接
  394. let skuPicMapArr = this.cartesianProduct(this.skuTags);
  395. if(skuPicMapArr.length > 0){
  396. for(let i = 0; i < this.dataForm.skuList.length; i++){
  397. if(skuPicMapArr[i]){
  398. this.dataForm.skuList[i].skuPicMap = skuPicMapArr[i]
  399. this.dataForm.skuList[i].pic = skuPicMapArr[i].split(",")[0]
  400. }
  401. }
  402. }
  403. this.dataForm.prodName = this.dataForm.prodNameCn
  404. this.dataForm.brief = this.dataForm.briefCn
  405. let param = Object.assign({}, this.dataForm)
  406. // 设置价格和库存
  407. this.paramSetPriceAndStocks(param)
  408. if (!param.prodId && param.totalStocks === 0) {
  409. this.$confirm(this.$i18n.t('product.saveTip'), this.$i18n.t('resource.tips'), {
  410. confirmButtonText: this.$i18n.t('resource.confirm'),
  411. cancelButtonText: this.$i18n.t('resource.cancel'),
  412. type: 'warning'
  413. }).then(() => {
  414. this.confirmMethod(param)
  415. })
  416. } else {
  417. this.confirmMethod(param)
  418. }
  419. },
  420. confirmMethod (param) {
  421. param.content = null
  422. if (this.dataForm.prodLangList.length) {
  423. this.dataForm.prodLangList.forEach(el => {
  424. if (el.lang === 0) {
  425. el.content = param.contentCn
  426. el.prodName = param.prodNameCn
  427. el.brief = param.briefCn
  428. }
  429. if (el.lang === 1) {
  430. el.content = param.contentEn
  431. el.prodName = param.prodNameEn
  432. el.brief = param.briefEn
  433. }
  434. })
  435. }
  436. this.dataForm.skuList.forEach(el => {
  437. el.changeStock = parseInt(el.stocks) - parseInt(el.oriStock)
  438. })
  439. param.deliveryMode = undefined
  440. param.deliveryModeVo = this.dataForm.deliveryMode
  441. // 商品主图
  442. let newImgs = this.dataForm.imgs.split(',')
  443. for(let idx in newImgs){
  444. newImgs[idx] = newImgs[idx].split('?')[0]
  445. }
  446. this.dataForm.imgs = newImgs.join(',')
  447. param.pic = this.dataForm.imgs.split(',')[1]
  448. param.imgs = this.dataForm.imgs
  449. // 虚拟商品
  450. if (this.dataForm.mold === 1) {
  451. // 选择"无需核销",没有核销有效期
  452. if (this.dataForm.writeOffNum === 0) { param.writeOffTime = null }
  453. // 自定义核销有效天数
  454. if (this.dataForm.writeOffNum !== 0 && this.dataForm.writeOffTime === 2) {
  455. param.writeOffTime = parseInt(this.validDays)
  456. }
  457. param.virtualRemark = JSON.stringify(this.dataForm.virtualRemark)
  458. }
  459. if (this.dataForm.mold !== 1) {
  460. // 普通商品,清空虚拟商品信息
  461. param = {
  462. ...param,
  463. virtualRemark: null,
  464. writeOffNum: null,
  465. writeOffTime: null,
  466. writeOffStart: null,
  467. writeOffEnd: null,
  468. isRefund: null
  469. }
  470. }
  471. if (this.isSubmit) {
  472. return
  473. }
  474. this.isSubmit = true
  475. this.$http({
  476. url: this.$http.adornUrl(`/prod/prod`),
  477. method: param.prodId ? 'put' : 'post',
  478. data: this.$http.adornData(param)
  479. }).then(({ data }) => {
  480. this.$message({
  481. message: this.$i18n.t('publics.operation'),
  482. type: 'success',
  483. duration: 1500,
  484. onClose: () => {
  485. this.visible = false
  486. this.isSubmit = false
  487. this.$store.commit('common/removeMainActiveTab')
  488. this.$router.push({
  489. path: '/prod-prodList',
  490. query: { page: JSON.stringify(this.page) }
  491. })
  492. this.$emit('refreshDataList')
  493. }
  494. })
  495. }).catch((e) => {
  496. this.isSubmit = false
  497. })
  498. },
  499. //求skutag笛卡尔值组成sku图片映射
  500. cartesianProduct(skuTags) {
  501. let result = [];
  502. if (skuTags.length === 0) {
  503. return result;
  504. } else {
  505. let tempResult = skuTags[0].tagItems.map(item => item.pic);
  506. if(tempResult.length > 0){
  507. for (let i = 1; i < skuTags.length; i++) {
  508. let newResult = [];
  509. tempResult.forEach(arr =>{
  510. skuTags[i].tagItems.forEach(item =>{
  511. if(!item.pic){
  512. item.pic = ''
  513. }
  514. if(arr){
  515. let newArr = arr.concat(',').concat(item.pic);
  516. newResult.push(newArr);
  517. }
  518. })
  519. })
  520. tempResult = newResult;
  521. }
  522. }
  523. return tempResult;
  524. }
  525. }
  526. }
  527. }
  528. </script>
  529. <style lang="scss" scoped>
  530. .post-product-page {
  531. color: #333;
  532. .prod-main-containers {
  533. display: block;
  534. width: 100%;
  535. padding: 15px;
  536. box-sizing: border-box;
  537. background: #fff;
  538. margin-bottom: 50px;
  539. // 步骤
  540. .post-step {
  541. display: flex;
  542. align-content: center;
  543. justify-content: space-between;
  544. .step-item {
  545. position: relative;
  546. flex: 1;
  547. .step-txt {
  548. display: block;
  549. font-size: 14px;
  550. text-align: center;
  551. box-sizing: border-box;
  552. background: #f9f9f9;
  553. padding: 12px 0;
  554. }
  555. }
  556. .step-item.active {
  557. .step-txt {
  558. color: #fff;
  559. background: #155bd4;
  560. }
  561. }
  562. // 右箭头
  563. .step-item:not(:last-child) {
  564. .step-txt {
  565. margin-right: 10px;
  566. }
  567. &::after {
  568. position: absolute;
  569. top: 0;
  570. right: 0;
  571. content: '';
  572. width: 0;
  573. height: 0;
  574. border-top: 20px solid transparent;
  575. border-left: 10px solid #f9f9f9;
  576. border-bottom: 20px solid transparent;
  577. }
  578. }
  579. .step-item.active:not(:last-child) {
  580. &::after {
  581. border-left: 10px solid #155bd4;
  582. }
  583. }
  584. // 左箭头
  585. .step-item:not(:first-child) {
  586. &::before {
  587. position: absolute;
  588. top: 0;
  589. left: 0;
  590. content: '';
  591. width: 0;
  592. height: 0;
  593. border-top: 20px solid transparent;
  594. border-left: 10px solid #fff;
  595. border-bottom: 20px solid transparent;
  596. }
  597. }
  598. }
  599. // 内容
  600. .prod-content {
  601. display: block;
  602. width: 100%;
  603. margin-top: 20px;
  604. // 公共
  605. & ::v-deep .prod-title-row {
  606. display: block;
  607. width: 100%;
  608. background: #f9f9f9;
  609. font-size: 14px;
  610. color: #333;
  611. font-weight: bold;
  612. padding: 10px;
  613. margin-bottom: 20px;
  614. }
  615. }
  616. }
  617. // 底部固定操作栏
  618. .prod-footer {
  619. position: fixed;
  620. bottom: 0;
  621. width: 93%;
  622. box-shadow: 0 -3px 5px #eee;
  623. z-index: 3;
  624. margin-top: 20px;
  625. margin-right: 20px;
  626. .foot {
  627. display: flex;
  628. align-items: center;
  629. justify-content: center;
  630. padding: 10px 0;
  631. background: #fff;
  632. box-sizing: border-box;
  633. .inner {
  634. .default-btn.save-btn {
  635. border-color: #155bd4;
  636. color: #155bd4;
  637. }
  638. }
  639. }
  640. }
  641. }
  642. </style>