ProductAttrDetail.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  1. <template>
  2. <div style="margin-top: 50px">
  3. <el-form :model="value" ref="productAttrForm" label-width="120px" style="width: 720px" size="small">
  4. <!-- <el-form-item label="属性类型:">
  5. <el-select v-model="value.productAttributeCategoryId"
  6. placeholder="请选择属性类型"
  7. @change="handleProductAttrChange">
  8. <el-option
  9. v-for="item in productAttributeCategoryOptions"
  10. :key="item.value"
  11. :label="item.label"
  12. :value="item.value">
  13. </el-option>
  14. </el-select>
  15. </el-form-item>
  16. <el-form-item label="商品规格:">
  17. <el-card shadow="never" class="cardBg">
  18. <div v-for="(productAttr,idx) in selectProductAttr" :key="idx">
  19. {{productAttr.name}}:
  20. <el-checkbox-group v-if="productAttr.handAddStatus===0" v-model="selectProductAttr[idx].values">
  21. <el-checkbox v-for="item in getInputListArr(productAttr.inputList)" :label="item" :key="item"
  22. class="littleMarginLeft"></el-checkbox>
  23. </el-checkbox-group>
  24. <div v-else>
  25. <el-checkbox-group v-model="selectProductAttr[idx].values">
  26. <div v-for="(item,index) in selectProductAttr[idx].options" :key="index" style="display: inline-block"
  27. class="littleMarginLeft">
  28. <el-checkbox :label="item" :key="item"></el-checkbox>
  29. <el-button type="text" class="littleMarginLeft" @click="handleRemoveProductAttrValue(idx,index)">删除
  30. </el-button>
  31. </div>
  32. </el-checkbox-group>
  33. <el-input v-model="addProductAttrValue" style="width: 160px;margin-left: 10px" clearable></el-input>
  34. <el-button class="littleMarginLeft" @click="handleAddProductAttrValue(idx)">增加</el-button>
  35. </div>
  36. </div>
  37. </el-card>
  38. <el-table style="width: 100%;margin-top: 20px"
  39. :data="value.skuStockList"
  40. border>
  41. <el-table-column
  42. v-for="(item,index) in selectProductAttr"
  43. :label="item.name"
  44. :key="item.id"
  45. align="center">
  46. <template slot-scope="scope">
  47. {{getProductSkuSp(scope.row,index)}}
  48. </template>
  49. </el-table-column>
  50. <el-table-column
  51. label="销售价格"
  52. width="80"
  53. align="center">
  54. <template slot-scope="scope">
  55. <el-input v-model="scope.row.price"></el-input>
  56. </template>
  57. </el-table-column>
  58. <el-table-column
  59. label="商品库存"
  60. width="80"
  61. align="center">
  62. <template slot-scope="scope">
  63. <el-input v-model="scope.row.stock"></el-input>
  64. </template>
  65. </el-table-column>
  66. <el-table-column
  67. label="库存预警值"
  68. width="80"
  69. align="center">
  70. <template slot-scope="scope">
  71. <el-input v-model="scope.row.lowStock"></el-input>
  72. </template>
  73. </el-table-column>
  74. <el-table-column
  75. label="SKU编号"
  76. align="center">
  77. <template slot-scope="scope">
  78. <el-input v-model="scope.row.skuCode"></el-input>
  79. </template>
  80. </el-table-column>
  81. <el-table-column
  82. label="操作"
  83. width="80"
  84. align="center">
  85. <template slot-scope="scope">
  86. <el-button
  87. type="text"
  88. @click="handleRemoveProductSku(scope.$index, scope.row)">删除
  89. </el-button>
  90. </template>
  91. </el-table-column>
  92. </el-table>
  93. <el-button
  94. type="primary"
  95. style="margin-top: 20px"
  96. @click="handleRefreshProductSkuList">刷新列表
  97. </el-button>
  98. <el-button
  99. type="primary"
  100. style="margin-top: 20px"
  101. @click="handleSyncProductSkuPrice">同步价格
  102. </el-button>
  103. <el-button
  104. type="primary"
  105. style="margin-top: 20px"
  106. @click="handleSyncProductSkuStock">同步库存
  107. </el-button>
  108. </el-form-item>
  109. <el-form-item label="属性图片:" v-if="hasAttrPic">
  110. <el-card shadow="never" class="cardBg">
  111. <div v-for="(item,index) in selectProductAttrPics" :key="index">
  112. <span>{{item.name}}:</span>
  113. <single-upload v-model="item.pic"
  114. style="width: 300px;display: inline-block;margin-left: 10px"></single-upload>
  115. </div>
  116. </el-card>
  117. </el-form-item>
  118. <el-form-item label="商品参数:">
  119. <el-card shadow="never" class="cardBg">
  120. <div v-for="(item,index) in selectProductParam" :key="index" :class="{littleMarginTop:index!==0}">
  121. <div class="paramInputLabel">{{item.name}}:</div>
  122. <el-select v-if="item.inputType===1" class="paramInput" v-model="selectProductParam[index].value">
  123. <el-option
  124. v-for="item in getParamInputList(item.inputList)"
  125. :key="item"
  126. :label="item"
  127. :value="item">
  128. </el-option>
  129. </el-select>
  130. <el-input v-else class="paramInput" v-model="selectProductParam[index].value"></el-input>
  131. </div>
  132. </el-card>
  133. </el-form-item> -->
  134. <el-form-item label="商品相册:">
  135. <multi-upload v-model="selectProductPics"></multi-upload>
  136. </el-form-item>
  137. <el-form-item label="规格参数:">
  138. <el-tabs v-model="activeHtmlName" type="card">
  139. <el-tab-pane label="电脑端详情" name="pc">
  140. <tinymce :width="595" :height="300" v-model="value.detailHtml"></tinymce>
  141. </el-tab-pane>
  142. <el-tab-pane label="移动端详情" name="mobile">
  143. <tinymce :width="595" :height="300" v-model="value.detailMobileHtml"></tinymce>
  144. </el-tab-pane>
  145. </el-tabs>
  146. </el-form-item>
  147. <el-form-item style="text-align: center">
  148. <el-button size="medium" @click="handlePrev">上一步,填写商品促销</el-button>
  149. <!-- <el-button type="primary" size="medium" @click="handleNext">下一步,选择商品关联</el-button> -->
  150. <el-button type="primary" size="medium" @click="handleFinishCommit">完成,提交商品</el-button>
  151. </el-form-item>
  152. </el-form>
  153. </div>
  154. </template>
  155. <script>
  156. import {fetchList as fetchProductAttrCateList} from '@/api/productAttrCate'
  157. import {fetchList as fetchProductAttrList} from '@/api/productAttr'
  158. import SingleUpload from '@/components/Upload/singleUpload'
  159. import MultiUpload from '@/components/Upload/multiUpload'
  160. import Tinymce from '@/components/Tinymce'
  161. export default {
  162. name: "ProductAttrDetail",
  163. components: {SingleUpload, MultiUpload, Tinymce},
  164. props: {
  165. value: Object,
  166. isEdit: {
  167. type: Boolean,
  168. default: false
  169. }
  170. },
  171. data() {
  172. return {
  173. //编辑模式时是否初始化成功
  174. hasEditCreated:false,
  175. //商品属性分类下拉选项
  176. productAttributeCategoryOptions: [],
  177. //选中的商品属性
  178. selectProductAttr: [],
  179. //选中的商品参数
  180. selectProductParam: [],
  181. //选中的商品属性图片
  182. selectProductAttrPics: [],
  183. //可手动添加的商品属性
  184. addProductAttrValue: '',
  185. //商品富文本详情激活类型
  186. activeHtmlName: 'pc'
  187. }
  188. },
  189. computed: {
  190. //是否有商品属性图片
  191. hasAttrPic() {
  192. if (this.selectProductAttrPics.length < 1) {
  193. return false;
  194. }
  195. return true;
  196. },
  197. //商品的编号
  198. productId(){
  199. return this.value.id;
  200. },
  201. //商品的主图和画册图片
  202. selectProductPics:{
  203. get:function () {
  204. let pics=[];
  205. if(this.value.pic===undefined||this.value.pic==null||this.value.pic===''){
  206. return pics;
  207. }
  208. pics.push(this.value.pic);
  209. if(this.value.albumPics===undefined||this.value.albumPics==null||this.value.albumPics===''){
  210. return pics;
  211. }
  212. let albumPics = this.value.albumPics.split(',');
  213. for(let i=0;i<albumPics.length;i++){
  214. pics.push(albumPics[i]);
  215. }
  216. return pics;
  217. },
  218. set:function (newValue) {
  219. if (newValue == null || newValue.length === 0) {
  220. this.value.pic = null;
  221. this.value.albumPics = null;
  222. } else {
  223. this.value.pic = newValue[0];
  224. this.value.albumPics = '';
  225. if (newValue.length > 1) {
  226. for (let i = 1; i < newValue.length; i++) {
  227. this.value.albumPics += newValue[i];
  228. if (i !== newValue.length - 1) {
  229. this.value.albumPics += ',';
  230. }
  231. }
  232. }
  233. }
  234. }
  235. }
  236. },
  237. created() {
  238. this.getProductAttrCateList();
  239. },
  240. watch: {
  241. productId:function (newValue) {
  242. if(!this.isEdit)return;
  243. if(this.hasEditCreated)return;
  244. if(newValue===undefined||newValue==null||newValue===0)return;
  245. this.handleEditCreated();
  246. }
  247. },
  248. methods: {
  249. handleEditCreated() {
  250. //根据商品属性分类id获取属性和参数
  251. if(this.value.productAttributeCategoryId!=null){
  252. this.handleProductAttrChange(this.value.productAttributeCategoryId);
  253. }
  254. this.hasEditCreated=true;
  255. },
  256. getProductAttrCateList() {
  257. let param = {pageNum: 1, pageSize: 100};
  258. fetchProductAttrCateList(param).then(response => {
  259. this.productAttributeCategoryOptions = [];
  260. let list = response.data.list;
  261. for (let i = 0; i < list.length; i++) {
  262. this.productAttributeCategoryOptions.push({label: list[i].name, value: list[i].id});
  263. }
  264. });
  265. },
  266. getProductAttrList(type, cid) {
  267. let param = {pageNum: 1, pageSize: 100, type: type};
  268. fetchProductAttrList(cid, param).then(response => {
  269. let list = response.data.list;
  270. if (type === 0) {
  271. this.selectProductAttr = [];
  272. for (let i = 0; i < list.length; i++) {
  273. let options = [];
  274. let values = [];
  275. if (this.isEdit) {
  276. if (list[i].handAddStatus === 1) {
  277. //编辑状态下获取手动添加编辑属性
  278. options = this.getEditAttrOptions(list[i].id);
  279. }
  280. //编辑状态下获取选中属性
  281. values = this.getEditAttrValues(i);
  282. }
  283. this.selectProductAttr.push({
  284. id: list[i].id,
  285. name: list[i].name,
  286. handAddStatus: list[i].handAddStatus,
  287. inputList: list[i].inputList,
  288. values: values,
  289. options: options
  290. });
  291. }
  292. if(this.isEdit){
  293. //编辑模式下刷新商品属性图片
  294. this.refreshProductAttrPics();
  295. }
  296. } else {
  297. this.selectProductParam = [];
  298. for (let i = 0; i < list.length; i++) {
  299. let value=null;
  300. if(this.isEdit){
  301. //编辑模式下获取参数属性
  302. value= this.getEditParamValue(list[i].id);
  303. }
  304. this.selectProductParam.push({
  305. id: list[i].id,
  306. name: list[i].name,
  307. value: value,
  308. inputType: list[i].inputType,
  309. inputList: list[i].inputList
  310. });
  311. }
  312. }
  313. });
  314. },
  315. //获取设置的可手动添加属性值
  316. getEditAttrOptions(id) {
  317. let options = [];
  318. for (let i = 0; i < this.value.productAttributeValueList.length; i++) {
  319. let attrValue = this.value.productAttributeValueList[i];
  320. if (attrValue.productAttributeId === id) {
  321. let strArr = attrValue.value.split(',');
  322. for (let j = 0; j < strArr.length; j++) {
  323. options.push(strArr[j]);
  324. }
  325. break;
  326. }
  327. }
  328. return options;
  329. },
  330. //获取选中的属性值
  331. getEditAttrValues(index) {
  332. let values = new Set();
  333. if (index === 0) {
  334. for (let i = 0; i < this.value.skuStockList.length; i++) {
  335. let sku = this.value.skuStockList[i];
  336. let spData = JSON.parse(sku.spData);
  337. if (spData!= null && spData.length>=1) {
  338. values.add(spData[0].value);
  339. }
  340. }
  341. } else if (index === 1) {
  342. for (let i = 0; i < this.value.skuStockList.length; i++) {
  343. let sku = this.value.skuStockList[i];
  344. let spData = JSON.parse(sku.spData);
  345. if (spData!= null && spData.length>=2) {
  346. values.add(spData[1].value);
  347. }
  348. }
  349. } else {
  350. for (let i = 0; i < this.value.skuStockList.length; i++) {
  351. let sku = this.value.skuStockList[i];
  352. let spData = JSON.parse(sku.spData);
  353. if (spData!= null && spData.length>=3) {
  354. values.add(spData[2].value);
  355. }
  356. }
  357. }
  358. return Array.from(values);
  359. },
  360. //获取属性的值
  361. getEditParamValue(id){
  362. for(let i=0;i<this.value.productAttributeValueList.length;i++){
  363. if(id===this.value.productAttributeValueList[i].productAttributeId){
  364. return this.value.productAttributeValueList[i].value;
  365. }
  366. }
  367. },
  368. handleProductAttrChange(value) {
  369. this.getProductAttrList(0, value);
  370. this.getProductAttrList(1, value);
  371. },
  372. getInputListArr(inputList) {
  373. return inputList.split(',');
  374. },
  375. handleAddProductAttrValue(idx) {
  376. let options = this.selectProductAttr[idx].options;
  377. if (this.addProductAttrValue == null || this.addProductAttrValue == '') {
  378. this.$message({
  379. message: '属性值不能为空',
  380. type: 'warning',
  381. duration: 1000
  382. });
  383. return
  384. }
  385. if (options.indexOf(this.addProductAttrValue) !== -1) {
  386. this.$message({
  387. message: '属性值不能重复',
  388. type: 'warning',
  389. duration: 1000
  390. });
  391. return;
  392. }
  393. this.selectProductAttr[idx].options.push(this.addProductAttrValue);
  394. this.addProductAttrValue = null;
  395. },
  396. handleRemoveProductAttrValue(idx, index) {
  397. this.selectProductAttr[idx].options.splice(index, 1);
  398. },
  399. getProductSkuSp(row, index) {
  400. let spData = JSON.parse(row.spData);
  401. if(spData!=null&&index<spData.length){
  402. return spData[index].value;
  403. }else{
  404. return null;
  405. }
  406. },
  407. handleRefreshProductSkuList() {
  408. this.$confirm('刷新列表将导致sku信息重新生成,是否要刷新', '提示', {
  409. confirmButtonText: '确定',
  410. cancelButtonText: '取消',
  411. type: 'warning'
  412. }).then(() => {
  413. this.refreshProductAttrPics();
  414. this.refreshProductSkuList();
  415. });
  416. },
  417. handleSyncProductSkuPrice(){
  418. this.$confirm('将同步第一个sku的价格到所有sku,是否继续', '提示', {
  419. confirmButtonText: '确定',
  420. cancelButtonText: '取消',
  421. type: 'warning'
  422. }).then(() => {
  423. if(this.value.skuStockList!==null&&this.value.skuStockList.length>0){
  424. let tempSkuList = [];
  425. tempSkuList = tempSkuList.concat(tempSkuList,this.value.skuStockList);
  426. let price=this.value.skuStockList[0].price;
  427. for(let i=0;i<tempSkuList.length;i++){
  428. tempSkuList[i].price=price;
  429. }
  430. this.value.skuStockList=[];
  431. this.value.skuStockList=this.value.skuStockList.concat(this.value.skuStockList,tempSkuList);
  432. }
  433. });
  434. },
  435. handleSyncProductSkuStock(){
  436. this.$confirm('将同步第一个sku的库存到所有sku,是否继续', '提示', {
  437. confirmButtonText: '确定',
  438. cancelButtonText: '取消',
  439. type: 'warning'
  440. }).then(() => {
  441. if(this.value.skuStockList!==null&&this.value.skuStockList.length>0){
  442. let tempSkuList = [];
  443. tempSkuList = tempSkuList.concat(tempSkuList,this.value.skuStockList);
  444. let stock=this.value.skuStockList[0].stock;
  445. let lowStock=this.value.skuStockList[0].lowStock;
  446. for(let i=0;i<tempSkuList.length;i++){
  447. tempSkuList[i].stock=stock;
  448. tempSkuList[i].lowStock=lowStock;
  449. }
  450. this.value.skuStockList=[];
  451. this.value.skuStockList=this.value.skuStockList.concat(this.value.skuStockList,tempSkuList);
  452. }
  453. });
  454. },
  455. refreshProductSkuList() {
  456. this.value.skuStockList = [];
  457. let skuList = this.value.skuStockList;
  458. //只有一个属性时
  459. if (this.selectProductAttr.length === 1) {
  460. let attr = this.selectProductAttr[0];
  461. for (let i = 0; i < attr.values.length; i++) {
  462. skuList.push({
  463. spData: JSON.stringify([{key:attr.name,value:attr.values[i]}])
  464. });
  465. }
  466. } else if (this.selectProductAttr.length === 2) {
  467. let attr0 = this.selectProductAttr[0];
  468. let attr1 = this.selectProductAttr[1];
  469. for (let i = 0; i < attr0.values.length; i++) {
  470. if (attr1.values.length === 0) {
  471. skuList.push({
  472. spData: JSON.stringify([{key:attr0.name,value:attr0.values[i]}])
  473. });
  474. continue;
  475. }
  476. for (let j = 0; j < attr1.values.length; j++) {
  477. let spData = [];
  478. spData.push({key:attr0.name,value:attr0.values[i]});
  479. spData.push({key:attr1.name,value:attr1.values[j]});
  480. skuList.push({
  481. spData: JSON.stringify(spData)
  482. });
  483. }
  484. }
  485. } else {
  486. let attr0 = this.selectProductAttr[0];
  487. let attr1 = this.selectProductAttr[1];
  488. let attr2 = this.selectProductAttr[2];
  489. for (let i = 0; i < attr0.values.length; i++) {
  490. if (attr1.values.length === 0) {
  491. skuList.push({
  492. spData: JSON.stringify([{key:attr0.name,value:attr0.values[i]}])
  493. });
  494. continue;
  495. }
  496. for (let j = 0; j < attr1.values.length; j++) {
  497. if (attr2.values.length === 0) {
  498. let spData = [];
  499. spData.push({key:attr0.name,value:attr0.values[i]});
  500. spData.push({key:attr1.name,value:attr1.values[j]});
  501. skuList.push({
  502. spData: JSON.stringify(spData)
  503. });
  504. continue;
  505. }
  506. for (let k = 0; k < attr2.values.length; k++) {
  507. let spData = [];
  508. spData.push({key:attr0.name,value:attr0.values[i]});
  509. spData.push({key:attr1.name,value:attr1.values[j]});
  510. spData.push({key:attr2.name,value:attr2.values[k]});
  511. skuList.push({
  512. spData: JSON.stringify(spData)
  513. });
  514. }
  515. }
  516. }
  517. }
  518. },
  519. refreshProductAttrPics() {
  520. this.selectProductAttrPics = [];
  521. if (this.selectProductAttr.length >= 1) {
  522. let values = this.selectProductAttr[0].values;
  523. for (let i = 0; i < values.length; i++) {
  524. let pic=null;
  525. if(this.isEdit){
  526. //编辑状态下获取图片
  527. pic=this.getProductSkuPic(values[i]);
  528. }
  529. this.selectProductAttrPics.push({name: values[i], pic: pic})
  530. }
  531. }
  532. },
  533. //获取商品相关属性的图片
  534. getProductSkuPic(name){
  535. for(let i=0;i<this.value.skuStockList.length;i++){
  536. let spData = JSON.parse(this.value.skuStockList[i].spData);
  537. if(name===spData[0].value){
  538. return this.value.skuStockList[i].pic;
  539. }
  540. }
  541. return null;
  542. },
  543. //合并商品属性
  544. mergeProductAttrValue() {
  545. this.value.productAttributeValueList = [];
  546. for (let i = 0; i < this.selectProductAttr.length; i++) {
  547. let attr = this.selectProductAttr[i];
  548. if (attr.handAddStatus === 1 && attr.options != null && attr.options.length > 0) {
  549. this.value.productAttributeValueList.push({
  550. productAttributeId: attr.id,
  551. value: this.getOptionStr(attr.options)
  552. });
  553. }
  554. }
  555. for (let i = 0; i < this.selectProductParam.length; i++) {
  556. let param = this.selectProductParam[i];
  557. this.value.productAttributeValueList.push({
  558. productAttributeId: param.id,
  559. value: param.value
  560. });
  561. }
  562. },
  563. //合并商品属性图片
  564. mergeProductAttrPics() {
  565. for (let i = 0; i < this.selectProductAttrPics.length; i++) {
  566. for (let j = 0; j < this.value.skuStockList.length; j++) {
  567. let spData = JSON.parse(this.value.skuStockList[j].spData);
  568. if (spData[0].value === this.selectProductAttrPics[i].name) {
  569. this.value.skuStockList[j].pic = this.selectProductAttrPics[i].pic;
  570. }
  571. }
  572. }
  573. },
  574. getOptionStr(arr) {
  575. let str = '';
  576. for (let i = 0; i < arr.length; i++) {
  577. str += arr[i];
  578. if (i != arr.length - 1) {
  579. str += ',';
  580. }
  581. }
  582. return str;
  583. },
  584. handleRemoveProductSku(index, row) {
  585. let list = this.value.skuStockList;
  586. if (list.length === 1) {
  587. list.pop();
  588. } else {
  589. list.splice(index, 1);
  590. }
  591. },
  592. getParamInputList(inputList) {
  593. return inputList.split(',');
  594. },
  595. handlePrev() {
  596. this.$emit('prevStep')
  597. },
  598. handleNext() {
  599. this.mergeProductAttrValue();
  600. this.mergeProductAttrPics();
  601. this.$emit('nextStep')
  602. },
  603. handleFinishCommit(){
  604. this.$emit('finishCommit',this.isEdit);
  605. }
  606. }
  607. }
  608. </script>
  609. <style scoped>
  610. .littleMarginLeft {
  611. margin-left: 10px;
  612. }
  613. .littleMarginTop {
  614. margin-top: 10px;
  615. }
  616. .paramInput {
  617. width: 250px;
  618. }
  619. .paramInputLabel {
  620. display: inline-block;
  621. width: 100px;
  622. text-align: right;
  623. padding-right: 10px
  624. }
  625. .cardBg {
  626. background: #F8F9FC;
  627. }
  628. </style>