goodsAttr2.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. <template>
  2. <el-form size="mini" label-width="100px" :rules="attrRules">
  3. <!-- <el-form-item label="商品规格" prop="attr">
  4. <div class="attr-container">
  5. <el-form
  6. class="attr-wrap"
  7. v-for="(item, index) in Attr"
  8. ref="attr"
  9. :key="index"
  10. :model="item"
  11. size="mini"
  12. label-width="100px"
  13. >
  14. <el-form-item label="规格名:" class="attr-name">
  15. <el-input
  16. v-model="item.name"
  17. maxlength="8"
  18. placeholder="请输入"
  19. :disabled="locking"
  20. />
  21. <i class="el-icon-circle-close" @click="deleteAttr(index)"></i>
  22. </el-form-item>
  23. <el-form-item label="规格值:" class="attr-detail">
  24. <div
  25. v-for="(item1, index1) in item.value"
  26. :key="index1"
  27. class="detail-wrap"
  28. >
  29. <el-input
  30. v-model="item.value[index1]"
  31. maxlength="16"
  32. placeholder="请输入"
  33. :disabled="locking"
  34. />
  35. <i
  36. class="el-icon-circle-close"
  37. @click="deleteAttrValue(index, index1)"
  38. ></i>
  39. </div>
  40. <el-button
  41. type="text"
  42. :size="inputSize"
  43. @click.native="addAttrValue(index)"
  44. class="text-btn"
  45. >添加规格值</el-button
  46. >
  47. </el-form-item>
  48. </el-form>
  49. <div class="addAttr">
  50. <el-button
  51. :size="inputSize"
  52. @click.native="addAttr"
  53. :class="{ gray: Attr.length >= 3, 'cancel-btn': true }"
  54. >添加规格</el-button
  55. >
  56. <el-button
  57. v-if="!locking"
  58. :size="inputSize"
  59. type="primary"
  60. @click.native="buildDetail"
  61. class="confirm-btn"
  62. >生成明细</el-button
  63. >
  64. <el-button
  65. v-else-if="locking"
  66. :size="inputSize"
  67. type="primary"
  68. @click.native="resolveAttr"
  69. class="confirm-btn"
  70. >解锁规格</el-button
  71. >
  72. <p class="tips" v-if="Attr.length > 0">
  73. 提示:编辑完成后,请点击“生成规格明细”填写相关明细,修改规格将会清空明细
  74. </p>
  75. </div>
  76. </div>
  77. </el-form-item> -->
  78. <el-form-item label="规格明细" v-if="tableData.length > 0">
  79. <table>
  80. <tr>
  81. <th v-for="(item, index) in Attr" :key="index">{{ item.name }}</th>
  82. <!-- <th>
  83. <span>*</span> 成本价/元
  84. </th> -->
  85. <th><span></span> 规格主图</th>
  86. <th><span></span> 价格/元</th>
  87. <th><span></span> 库存</th>
  88. <th><span></span> 打赏金额</th>
  89. <th><span></span> 绿通支付金额</th>
  90. <!-- <th><span></span> 编码</th>
  91. <th><span></span> 供应链skuID</th>
  92. <th><span></span> 进价</th> -->
  93. </tr>
  94. <tr v-for="(item, index) in tableData" :key="index">
  95. <td v-for="(item1, index1) in item.attribute" :key="index1">
  96. {{ item1 }}
  97. </td>
  98. <!-- <td>
  99. <el-input v-model="item.cost" type="number" />
  100. </td> -->
  101. <td class="upImg">
  102. <img v-if="item.pic" :src="item.pic || ''" class="mainImg" />
  103. <!-- <div class="add-img" v-else>+</div> -->
  104. <!-- <input type="file" class="file" :name="index" @change="changeImg" /> -->
  105. </td>
  106. <td>
  107. <!-- <el-input v-model="item.price" type="number" @blur="priceFmt" /> -->
  108. {{ item.price }}
  109. </td>
  110. <td>
  111. <!-- <el-input v-model="item.stock" type="number" /> -->
  112. {{ item.stock }}
  113. </td>
  114. <td>
  115. {{ item.rewardAmount }}
  116. </td>
  117. <td>
  118. {{ item.goldAmount }}
  119. </td>
  120. <!-- <td>
  121. <el-input v-model="item.code" type="number" />
  122. </td>
  123. <td>
  124. <el-input v-model="item.chainId" type="text" />
  125. </td>
  126. <td>
  127. <el-input v-model="item.cost" type="number" />
  128. </td> -->
  129. </tr>
  130. <!-- <tr>
  131. <td :colspan="col">
  132. <div class="batch">
  133. <p>批量设置</p>
  134. <div v-if="batchEdit.type">
  135. <el-input
  136. v-model="batchEdit.value"
  137. type="number"
  138. oninput="value=value.length>9?value.slice(0,9):value"
  139. />
  140. <button class="text-btn" @click="saveBatch">保存</button>
  141. <button class="text-btn" @click="cancelBatch">取消</button>
  142. </div>
  143. <div class="batchBtn" v-else>
  144. <button
  145. v-for="(item, i) in batchList"
  146. :key="i"
  147. class="text-btn"
  148. @click="editBatch(i, item.value)"
  149. >
  150. {{ item.name }}
  151. </button>
  152. <div class="batchImg">
  153. <input type="file" class="file" @change="batchImg" />
  154. <button>规格主图</button>
  155. </div>
  156. </div>
  157. </div>
  158. </td>
  159. </tr> -->
  160. </table>
  161. </el-form-item>
  162. <el-form-item label="规格明细" v-else>
  163. <p style="line-height: 2">无</p>
  164. </el-form-item>
  165. <!-- <el-form-item label="划线价">
  166. <el-input v-model="oldPrice" type="number" />
  167. </el-form-item> -->
  168. <!-- <el-form-item label="商品原价">
  169. <el-input v-model="hypocrisy" type="number" />
  170. </el-form-item> -->
  171. </el-form>
  172. </template>
  173. <script type="text/ecmascript-6">
  174. export default {
  175. name: 'goodsAttr',
  176. props: {
  177. attrSku: {
  178. type: Array
  179. },
  180. skuTable: {
  181. type: Array
  182. },
  183. OldPrice: {
  184. type: Number
  185. },
  186. sales: {
  187. type: Number
  188. }
  189. },
  190. data() {
  191. return {
  192. locking: false, // 锁定规
  193. inputSize: 'mini',
  194. oldPrice: this.OldPrice, // 划线价
  195. hypocrisy: this.sales, // 划线价
  196. defaultImg: this.$Public.defaultImg, // 默认规格图
  197. ruleForm: {
  198. name: ''
  199. },
  200. attrRules: {
  201. attr: [
  202. {
  203. required: true,
  204. message: '请输入商品规格值'
  205. }
  206. ]
  207. }, // 基础校验
  208. batchList: [
  209. // {
  210. // name: '成本价',
  211. // value: 'cost'
  212. // },
  213. {
  214. name: '价格',
  215. value: 'price'
  216. },
  217. {
  218. name: '库存',
  219. value: 'stock'
  220. }
  221. ], // 批量设置列表,静态数据
  222. batchEdit: {
  223. name: '', // 批量编辑字段
  224. type: false,
  225. value: '' // 批量编辑数值
  226. },
  227. col: 0, // 表格列数,批量排版
  228. Attr: [
  229. {
  230. name: '',
  231. value: ['']
  232. }
  233. ], // 规格列表
  234. tableData: [], // 规格明细表格
  235. attribute: {}, // tableData单list的attribute信息
  236. info: {
  237. stock: '',
  238. code: '',
  239. pic: '',
  240. price: '',
  241. // cost: '',
  242. attribute: {}
  243. } // tableData单list信息
  244. };
  245. },
  246. created() {},
  247. computed: {},
  248. methods: {
  249. changeImg(e) {
  250. // 上传规格图片
  251. let index = e.target.name;
  252. let file = e.target.files[0];
  253. this.request.upPic({ prefix: 'other', file: file }).then(
  254. (res) => {
  255. this.tableData[index].pic = res;
  256. this.tableData = [...this.tableData];
  257. },
  258. (res) => {}
  259. );
  260. },
  261. batchImg(e) {
  262. // 批量上传图片
  263. let file = e.target.files[0];
  264. this.request.upPic({ type: 3, file: file }).then(
  265. (res) => {
  266. this.tableData.forEach((item) => {
  267. item.pic = res;
  268. });
  269. },
  270. (res) => {}
  271. );
  272. },
  273. editBatch(i, name) {
  274. // 批量设置
  275. this.batchEdit.name = name;
  276. this.batchEdit.type = true;
  277. },
  278. saveBatch() {
  279. this.batchEdit.type = false;
  280. // 遍历tableData,批量改数据
  281. this.tableData.forEach((item, index) => {
  282. // 价格和分润结构不同
  283. let name = this.batchEdit.name;
  284. // 分公司和能量站最多4.2折,价格不能小于0.03
  285. // if (name === 'price') {
  286. // if (this.batchEdit.value && +this.batchEdit.value < 0.03) {
  287. // this.$message({
  288. // message: '商品价格请勿小于0.03',
  289. // type: 'warning'
  290. // });
  291. // this.batchEdit.value = '';
  292. // }
  293. // }
  294. item[name] = this.batchEdit.value;
  295. });
  296. // 清空input
  297. this.batchEdit.value = '';
  298. },
  299. cancelBatch() {
  300. this.batchEdit.type = false;
  301. },
  302. addAttr() {
  303. // 添加规格
  304. if (this.locking) {
  305. return;
  306. }
  307. if (this.Attr.length >= 3) {
  308. this.$message({
  309. message: '至多添加三个规格',
  310. type: 'warning'
  311. });
  312. return false;
  313. }
  314. let obj = {
  315. name: '',
  316. value: ['']
  317. };
  318. this.Attr.push(obj);
  319. },
  320. deleteAttr(index) {
  321. // 删除规格
  322. if (this.locking) {
  323. return;
  324. }
  325. this.Attr.splice(index, 1);
  326. },
  327. addAttrValue(index) {
  328. // 添加规格值
  329. if (this.locking) {
  330. return;
  331. }
  332. let val = '';
  333. this.Attr[index].value.push(val);
  334. },
  335. deleteAttrValue(i, j) {
  336. if (this.locking) {
  337. return;
  338. }
  339. // 删除规格值
  340. this.Attr[i].value.splice(j, 1);
  341. },
  342. resolveAttr() {
  343. // 解锁规格
  344. this.$confirm('此操作将清空规格明细, 是否继续?', '提示', {
  345. confirmButtonText: '确定',
  346. cancelButtonText: '取消',
  347. type: 'warning'
  348. })
  349. .then(() => {
  350. // 清空tableData/info/attribute
  351. this.tableData = [];
  352. this.attribute = {};
  353. this.info = {
  354. stock: '',
  355. code: '',
  356. pic: '',
  357. price: '',
  358. // cost: '',
  359. attribute: {}
  360. };
  361. this.locking = false;
  362. })
  363. .catch(() => {
  364. return false;
  365. });
  366. },
  367. getTable(i, len) {
  368. // 根据选择的attr生成规格明细列表
  369. this.Attr[i].value.forEach((item) => {
  370. this.$set(this.attribute, this.Attr[i].name, item);
  371. if (i === len - 1) {
  372. this.$set(this.info, 'attribute', { ...this.attribute });
  373. this.tableData.push({ ...this.info });
  374. return false;
  375. }
  376. this.getTable(i + 1, len);
  377. });
  378. },
  379. buildDetail() {
  380. let isPass = true;
  381. if (this.Attr.length <= 0) {
  382. this.$message({
  383. message: '请添加规格',
  384. type: 'warning'
  385. });
  386. return false;
  387. }
  388. this.Attr.forEach((item, i) => {
  389. if (item.name === '') {
  390. this.$message({
  391. message: '请填写规格名',
  392. type: 'warning'
  393. });
  394. isPass = false;
  395. }
  396. let value = item.value[0];
  397. if (value === '' || typeof value === 'undefined') {
  398. this.$message({
  399. message: '请填写规格值',
  400. type: 'warning'
  401. });
  402. isPass = false;
  403. }
  404. });
  405. if (!isPass) {
  406. return false;
  407. }
  408. // 锁定规格
  409. this.locking = true;
  410. this.col = this.Attr.length + 7;
  411. // 生成规格明细
  412. let len = this.Attr.length;
  413. this.getTable(0, len);
  414. },
  415. priceFmt() {
  416. // 分公司和能量站最多4.2折,价格不能小于0.03
  417. // this.tableData.map((it, index) => {
  418. // if (it.price && +it.price < 0.03) {
  419. // this.$message({
  420. // message: '商品价格请勿小于0.03',
  421. // type: 'warning'
  422. // });
  423. // this.tableData[index].price = '';
  424. // }
  425. // });
  426. }
  427. },
  428. watch: {
  429. tableData: {
  430. handler(val) {
  431. console.log(val, 'aaaaaaaaaaaaaa');
  432. // val.map((it, index) => {
  433. // if (it.price && +it.price < 0.03) {
  434. // this.$message({
  435. // message: '商品价格请勿小于0.03',
  436. // type: 'warning'
  437. // });
  438. // this.tableData[index].price = '';
  439. // }
  440. // });
  441. // 编辑规格明细时,向父组件传规格明细,库存
  442. this.$emit('editAttr', val);
  443. },
  444. deep: true
  445. },
  446. OldPrice(val) {
  447. this.oldPrice = val;
  448. },
  449. oldPrice(val) {
  450. // 编辑划线价
  451. this.$emit('getOldPrice', val);
  452. },
  453. sales(val) {
  454. this.hypocrisy = val;
  455. },
  456. hypocrisy(val) {
  457. // 编辑划线价
  458. this.$emit('getSales', val);
  459. },
  460. skuTable(val) {
  461. this.tableData = val;
  462. },
  463. attrSku: function (val) {
  464. this.Attr = [];
  465. // 根据根据tableData是否为空判断是上传还是编辑
  466. if (this.tableData.length <= 0) {
  467. // 新品页面时,根据传递的attrSku,计算Attr的规格名
  468. val.forEach((item) => {
  469. let list = {
  470. name: item,
  471. value: ['']
  472. };
  473. this.Attr.push(list);
  474. });
  475. } else {
  476. // 编辑页面时,计算Attr的规格名,根据tableData,推算Attr的规格值,并锁住
  477. val.forEach((item) => {
  478. let list = {
  479. name: item,
  480. value: []
  481. };
  482. this.Attr.push(list);
  483. });
  484. this.tableData.forEach((item) => {
  485. let attribute = item.attribute;
  486. for (let i in attribute) {
  487. this.Attr.forEach((item) => {
  488. if (item.name === i) {
  489. item.value.push(attribute[i]);
  490. }
  491. });
  492. }
  493. });
  494. this.Attr.forEach((item) => {
  495. item.value = [...new Set(item.value)];
  496. }); // value去重
  497. this.locking = true;
  498. this.col = this.Attr.length + 7;
  499. }
  500. }
  501. }
  502. };
  503. </script>
  504. <style lang="stylus" rel="stylesheet/stylus" scoped>
  505. @import '~assets/main.styl';
  506. .el-input {
  507. width: 100px;
  508. }
  509. .batch {
  510. flex-x(flex-satrt);
  511. padding: 0 16px;
  512. word(14px, #333);
  513. button {
  514. color: blue;
  515. margin-left: 10px;
  516. }
  517. p {
  518. word(14px, #333);
  519. margin-right: 15px;
  520. }
  521. .batchBtn {
  522. flex-x(flex-satrt);
  523. .batchImg {
  524. position: relative;
  525. input {
  526. opacity: 0;
  527. position: absolute;
  528. left: 0;
  529. top: 0;
  530. width: 60px;
  531. height: 40px;
  532. line-height: 40px;
  533. margin-left: 10px;
  534. }
  535. }
  536. }
  537. }
  538. .upImg {
  539. position: relative;
  540. vertical-align: middle;
  541. height: 100%;
  542. .add-img{
  543. width: 40px;
  544. height: 40px;
  545. border: 1px solid #e8e8e8;
  546. background: #F6F6F6;
  547. box-sizing: border-box;
  548. position: absolute;
  549. left: 0;
  550. top: 0;
  551. right: 0;
  552. bottom: 0;
  553. margin: auto;
  554. font-size: 24px;
  555. color: #999;
  556. }
  557. .mainImg {
  558. width: 40px;
  559. height: 40px;
  560. position: absolute;
  561. left: 0;
  562. top: 0;
  563. right: 0;
  564. bottom: 0;
  565. margin: auto;
  566. }
  567. input {
  568. width: 40px;
  569. height: 40px;
  570. opacity: 0;
  571. position: absolute;
  572. left: 0;
  573. top: 0;
  574. right: 0;
  575. bottom: 0;
  576. margin: auto;
  577. }
  578. }
  579. .attr-container {
  580. padding: 10px;
  581. box-sizing: border-box;
  582. border();
  583. .addAttr {
  584. flex-x(flex-start);
  585. width: 98%;
  586. height: 40px;
  587. line-height: 40px;
  588. background: bk;
  589. padding-left: 20px;
  590. .tips {
  591. margin-left: 20px;
  592. }
  593. .gray {
  594. color: gray9;
  595. background: grayE;
  596. border();
  597. }
  598. }
  599. .attr-wrap {
  600. .el-input {
  601. width: 160px;
  602. margin-bottom: 5px;
  603. }
  604. .attr-name {
  605. position: relative;
  606. width: 100%;
  607. height: 40px;
  608. padding-top: 5px;
  609. box-sizing: border-box;
  610. background: bk;
  611. i {
  612. position: absolute;
  613. right: 20px;
  614. line-height: 30px;
  615. color: gray9;
  616. }
  617. .el-button--mini {
  618. margin-left: 10px;
  619. }
  620. }
  621. .attr-detail {
  622. .detail-wrap {
  623. position: relative;
  624. width: 160px;
  625. display: inline-block;
  626. margin-right: 10px;
  627. i {
  628. position: absolute;
  629. right: 10px;
  630. line-height: 30px;
  631. color: #999;
  632. top: 0;
  633. }
  634. }
  635. }
  636. .el-autocomplete {
  637. width: 200px;
  638. }
  639. }
  640. }
  641. table {
  642. border: 1px solid border-color;
  643. width: 100%;
  644. tr {
  645. height: 40px;
  646. line-height: 40px;
  647. text-align: left;
  648. }
  649. th {
  650. height: 54px;
  651. background: #F6F6F6;
  652. span {
  653. color: red;
  654. }
  655. text-align: center;
  656. font-weight: normal;
  657. color: gray3;
  658. // padding-left: 20px;
  659. }
  660. td {
  661. // padding-left: 20px;
  662. height: 54px;
  663. text-align: center;
  664. bor-top();
  665. bor-bottom();
  666. color: gray9;
  667. width: 80px;
  668. }
  669. }
  670. .confirm-btn {
  671. confirm-btn();
  672. }
  673. .cancel-btn {
  674. cancel-btn();
  675. }
  676. .text-btn {
  677. color: btn-color !important;
  678. }
  679. </style>