app-attr.vue 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195
  1. <template>
  2. <view class="app-attr">
  3. <view @click="alert">
  4. <slot name="button"></slot>
  5. </view>
  6. <view class="modal" v-if="display === 'block'" @click="close" >
  7. <view class="safe-area-inset-bottom u-attr-fixed" >
  8. <view class="content" @tap.native.stop="preventD">
  9. <image src="/static/image/icon/close.png" class="close" @click="close"></image>
  10. <view class="first dir-left-nowrap" :class="sign =='wholesale' ? 'no-border' : ''">
  11. <view class="box-grow-0 img" @click.stop="clickImg(attrPic)">
  12. <app-image :img-src="attrPic" width="100%" height="100%"></app-image>
  13. </view>
  14. <view class="info">
  15. <view class="dir-left-nowrap cross-center" :class="priceColor">
  16. <view class="dir-left-nowrap cross-center">
  17. <view class="dir-left-nowrap cross-center" :style="{'color':getTheme.color}" v-if="(selectAttr && selectAttr.extra) || goods.extra">
  18. <view>{{selectAttr.extra ? selectAttr.extra.value + selectAttr.extra.name :
  19. goods.extra.value + goods.extra.name}}
  20. </view>
  21. <view v-if="!(goods.sign === 'integral_mall' && attrPrice == 0)">+</view>
  22. </view>
  23. <app-price :theme="theme" v-if="!(goods.sign === 'integral_mall' && attrPrice == 0) && sign !== 'wholesale'" type="text-price-all" :price="attrPrice"
  24. :default-price="goods.price"></app-price>
  25. <app-price :theme="theme" v-if="sign === 'wholesale'" type="text-price-all" :price="attrPrice" :max="goods.level_show == 1 ? goods.price_member_max : goods.price_max" :min="goods.level_show == 1 ? goods.price_member_min : goods.price_min"></app-price>
  26. </view>
  27. <view v-if="goods.level_show === 1 && (selectAttr || sign == 'wholesale')">
  28. <app-member-mark :theme="theme"></app-member-mark>
  29. </view>
  30. </view>
  31. <view class="stock">库存:{{attrNum}}</view>
  32. </view>
  33. </view>
  34. <view class="second" :class="sign ==='wholesale' ? 'no-padding' : ''">
  35. <slot name="extra"></slot>
  36. <view class="wholesale" v-if="sign ==='wholesale'">
  37. <view class="wholesale-attr-list dir-left-nowrap cross-center" v-if="index != goods.attr_groups.length -1" v-for="(item, index) in goods.attr_groups" :key="index">
  38. <view class="position cross-center">
  39. <view class="wholesale-attr-group t-omit-two">{{item.attr_group_name}}</view>
  40. </view>
  41. <scroll-view @scroll="scrollGet($event,index)" :scroll-left="item.scrollLeft" class="wholesale-attr-item" scroll-x="true">
  42. <view class="scroll-attr-group cross-center">
  43. <view class="wholesale-attr-group t-omit">{{item.attr_group_name.length > 10 ? item.less_attr_group_name : item.attr_group_name}}</view>
  44. </view>
  45. <view class="attr-name attr-background" v-for="(attr, key) in item.attr_list" :key="key" :style="{'background-color': attr.active ? theme.background : '#f2f2f2'}" @click.stop="chooseAttr(index,attr)">{{attr.attr_name}}
  46. <view class="attr-number" :style="{'right':`${attr.length + 'rpx'}`,'background-color': `${theme.background}`}" v-if="index == 0 && attr.number > 0">{{attr.number}}</view>
  47. </view>
  48. <view class="attr-name attr-background" style="visibility: hidden">
  49. </view>
  50. </scroll-view>
  51. <view @click.stop="toBottom(index)" class="right-icon">
  52. <view></view>
  53. <image src="/static/image/icon/right.png"></image>
  54. </view>
  55. </view>
  56. <view class="wholesale-attr-group-list">
  57. <view class="wholesale-attr-group" v-for="(item, index) in goodsAttr" :key="index">
  58. <view class="dir-left-nowrap">
  59. <view class="wholesale-attr-item main-between">
  60. <view class="dir-top-nowrap main-center attr-name t-omit">
  61. <view class="t-omit">{{item.attr_list[item.attr_list.length - 1].attr_name}}</view>
  62. <view class="attr-price">¥{{goods.level_show === 1 ? item.price_member : item.price}}</view>
  63. </view>
  64. <view class="dir-left-nowrap wholesale-number-box cross-center">
  65. <image :src="item.number <= 0 ? '/static/image/plugins/un-low.png' : '/static/image/plugins/low.png'" class="block box-grow-0 cross-center main-center" @click.stop="wholesaleNumberSub(index)">
  66. </image>
  67. <view class="wholesale-number-input box-grow-0 cross-center main-center">
  68. <app-input height="60" type="number" v-model="item.number" paddingLeft="0" :center="true" placeholder=" " @blur="wholesaleNumberBlur(index)" :focus="false" width="88"></app-input>
  69. </view>
  70. <image :src="item.number >= item.stock? '/static/image/plugins/un-add.png' : '/static/image/plugins/add.png'" class="block box-grow-0 cross-center main-center" @click.stop="wholesaleNumberAdd(index)"></image>
  71. </view>
  72. </view>
  73. </view>
  74. </view>
  75. </view>
  76. </view>
  77. <view class="attr-group" v-if="goods.type === 'goods' && sign !='wholesale'" v-for="(item, index) in newAttrGroupList" :key="index">
  78. <view class="attr-group-name">{{item.attr_group_name}}</view>
  79. <view class="dir-left-wrap">
  80. <view v-for="(attr, key) in item.attr_list" :key="key" class="attr-item"
  81. :style="{'background-color':attr.checked && sign !== 'gift' ? theme.background : ''}"
  82. :class="attr.checked && sign !== 'gift' ? 'active' : attr.checked && sign === 'gift' ? theme + '-background active' : 'attr-item-default' + (attr.attr_num_0 ? ' attr_num_0' : '')"
  83. @click.stop="storeAttrClick(attr.attr_id, item.attr_group_id)">{{attr.attr_name}}
  84. </view>
  85. </view>
  86. </view>
  87. <view v-if="chooseNumber" class="dir-left-nowrap number-box cross-center">
  88. <view class="box-grow-1">数量</view>
  89. <image :src="number <= 1 ? '/static/image/icon/can-be-reduced.png' : '/static/image/cart/can-be-reduced.png'" class="block box-grow-0 cross-center main-center" @click.stop="numberSub">
  90. </image>
  91. <view class="number-input box-grow-0 cross-center main-center">
  92. <app-input type="number" v-model="number" paddingLeft="0" :center="true" placeholder=" " @blur="numberBlur"
  93. :focus="false" width="88"></app-input>
  94. </view>
  95. <image src="/static/image/cart/can-be-added.png" class="block box-grow-0 cross-center main-center" @click.stop="numberAdd"></image>
  96. </view>
  97. </view>
  98. <view v-if="sign ==='wholesale'" class="total">已选<text>{{totalNumber}}</text>件 总计<text>¥{{totalPrice > 0? totalPrice : '0.00'}}</text></view>
  99. <view v-if="sell_time > 0">
  100. <app-sell-tip :time="sell_time" @changeTime="changeTime"></app-sell-tip>
  101. </view>
  102. <app-jump-button form>
  103. <view class="three dir-left-nowrap">
  104. <view class="bd-btn box-grow-1" v-if="cartShow"
  105. :style="{'background-color': theme.background_s,'color': theme.secondary_text}" @click="cart">{{addText}}
  106. </view>
  107. <view v-if="showRight" class="bd-btn box-grow-1 buy" :style="{'background-color': theme.background,'color': theme.main_text}" @click="buy">
  108. {{rightRemindText}}
  109. </view>
  110. </view>
  111. </app-jump-button>
  112. </view>
  113. </view>
  114. </view>
  115. </view>
  116. </template>
  117. <script>
  118. import { mapState, mapGetters } from "vuex";
  119. import appPrice from "../../page-component/goods/app-price.vue";
  120. import appMemberMark from '../../page-component/app-member-mark/app-member-mark.vue';
  121. import appSellTip from '@/components/page-component/goods/app-sell-tip.vue';
  122. import goodsMixin from '@/core/goods-mixin.js';
  123. export default {
  124. name: "app-attr",
  125. mixins: [goodsMixin],
  126. components: {
  127. appPrice,
  128. appMemberMark,
  129. appSellTip
  130. },
  131. props: {
  132. goods: Object,
  133. attrGroupList: Array,
  134. attrCart: {
  135. type: Array,
  136. default() {
  137. return [];
  138. }
  139. },
  140. cartShow: {
  141. type: [Boolean, Number],
  142. default() {
  143. return true
  144. }
  145. },
  146. previewUrl: String,
  147. submitUrl: String,
  148. goodsId: {
  149. type:Number,
  150. default() {
  151. return 0
  152. }
  153. },
  154. show: Number,
  155. buyText: {
  156. type: String,
  157. default() {
  158. return '立即购买';
  159. }
  160. },
  161. plugin: {
  162. default: '',
  163. },
  164. theme: {
  165. type: Object,
  166. },
  167. chooseNumber: {
  168. type: Boolean,
  169. default: true,
  170. },
  171. noPay: {
  172. type: Boolean,
  173. default: false,
  174. },
  175. buyClick: {
  176. type: Boolean,
  177. default: false,
  178. },
  179. addText: {
  180. type: String,
  181. default: '加入购物车',
  182. },
  183. is_show_buy: {
  184. type: Boolean,
  185. default: true,
  186. },
  187. sign: {
  188. type: String
  189. },
  190. totalPrice: {
  191. type: String,
  192. default: '0.00',
  193. },
  194. totalNumber: {
  195. type: Number,
  196. default: 0,
  197. },
  198. discount: {
  199. type: Number,
  200. default: 0,
  201. },
  202. wholesaleType: {
  203. type: Number,
  204. default: 0,
  205. },
  206. attentionSign: {
  207. type: String
  208. }
  209. },
  210. data() {
  211. return {
  212. display: 'none',
  213. number: 1,
  214. selectAttr: null,
  215. newAttrGroupList: null,
  216. pic_url: null,
  217. // 商品批发
  218. activeAttr: [],
  219. goodsAttr: [],
  220. sell_time: 0,
  221. };
  222. },
  223. watch: {
  224. show() {
  225. if (this.display === 'block') {
  226. this.selectAttr = null;
  227. this.close();
  228. } else if (this.display === 'none') {
  229. this.alert();
  230. }
  231. },
  232. newData: {
  233. handler() {
  234. this.$emit('attr', this.newData)
  235. },
  236. immediate: true,
  237. },
  238. attrGroupList: {
  239. handler() {
  240. this.newAttrGroupList = this.attrGroupList;
  241. if (this.display == 'block') {
  242. this.alert();
  243. }
  244. },
  245. immediate: true
  246. },
  247. goods: {
  248. handler() {
  249. if (this.display == 'block') {
  250. this.alert();
  251. }
  252. if (this.goods) {
  253. this.sell_time = this.goods.sell_time;
  254. }
  255. },
  256. immediate: true
  257. }
  258. },
  259. mounted() {
  260. if(this.sign == 'wholesale') {
  261. this.pic_url = this.goods.attr_groups[0].attr_list[0].pic_url
  262. if(this.goods.attr_groups.length == 1) {
  263. this.goodsAttr = this.goods.attr;
  264. }else {
  265. for(let item of this.goods.attr_groups) {
  266. let para = {
  267. attr_group_name: '',
  268. attr_group_id: '',
  269. attr_id: '',
  270. attr_name: ''
  271. };
  272. para.attr_group_name = item.attr_group_name
  273. para.attr_group_id = item.attr_group_id
  274. para.attr_id = item.attr_list[0].attr_id
  275. para.attr_name = item.attr_list[0].attr_name
  276. this.activeAttr.push(para)
  277. }
  278. for(let item of this.goods.attr) {
  279. let same = true;
  280. for(let i = 0;i < item.attr_list.length -1;i++) {
  281. let first = {
  282. attr_group_name: item.attr_list[i].attr_group_name,
  283. attr_group_id: item.attr_list[i].attr_group_id,
  284. attr_id: item.attr_list[i].attr_id,
  285. attr_name: item.attr_list[i].attr_name
  286. }
  287. if(JSON.stringify(first) != JSON.stringify(this.activeAttr[i])) {
  288. same = false;
  289. }
  290. }
  291. if(same) {
  292. this.goodsAttr.push(item)
  293. }
  294. }
  295. }
  296. }
  297. },
  298. methods: {
  299. alert() {
  300. if (this.attrGroupList && this.attrGroupList.length === 0) {
  301. return;
  302. }
  303. if(this.sign !== 'wholesale') {
  304. let attr_group_list = this.attrGroupList;
  305. let attrs = this.goods.attr;
  306. let select_attr = null;
  307. this.number = 1;
  308. if (attr_group_list.length === 1) {
  309. for (let i in attrs) {
  310. for (let j in attr_group_list[0].attr_list) {
  311. if (attr_group_list[0].attr_list[j].attr_id == attrs[i].attr_list[0].attr_id) {
  312. if (attrs[i].stock > 0) {
  313. if (attrs.length === 1) {
  314. attr_group_list[0].attr_list[j].checked = true;
  315. }
  316. attr_group_list[0].attr_list[j].attr_num_0 = false;
  317. this.pic_url = attr_group_list[0].attr_list[j].pic_url;
  318. } else {
  319. this.number = 0;
  320. attr_group_list[0].attr_list[j].checked = false;
  321. attr_group_list[0].attr_list[j].attr_num_0 = true;
  322. }
  323. }
  324. }
  325. }
  326. if (attrs.length === 1) {
  327. select_attr = attrs[0];
  328. this.$emit('attrtap', select_attr);
  329. }
  330. }
  331. this.newAttrGroupList = attr_group_list;
  332. if(this.goods.selectAttr) {
  333. this.selectAttr = this.goods.selectAttr
  334. }else {
  335. this.selectAttr = select_attr;
  336. }
  337. }
  338. this.display = 'block';
  339. },
  340. scrollGet(e,index) {
  341. this.goods.attr_groups[index].scrollLeft = e.detail.scrollLeft;
  342. this.$forceUpdate();
  343. },
  344. toBottom(index) {
  345. this.$nextTick().then(() => {
  346. this.goods.attr_groups[index].scrollLeft = 99999;
  347. this.$forceUpdate();
  348. })
  349. },
  350. chooseAttr(index,attrItem) {
  351. let that = this;
  352. for(let attr of that.goods.attr_groups[index].attr_list) {
  353. attr.active = false;
  354. if(attr.attr_id == attrItem.attr_id && attr.attr_name == attrItem.attr_name) {
  355. attr.active = true;
  356. }
  357. }
  358. if(index == 0) {
  359. that.pic_url = attrItem.pic_url;
  360. }
  361. that.activeAttr[index].attr_id = attrItem.attr_id
  362. that.activeAttr[index].attr_name = attrItem.attr_name
  363. that.goodsAttr = [];
  364. for(let item of that.goods.attr) {
  365. let same = true;
  366. for(let i = 0;i < item.attr_list.length -1;i++) {
  367. let first = {
  368. attr_group_name: item.attr_list[i].attr_group_name,
  369. attr_group_id: item.attr_list[i].attr_group_id,
  370. attr_id: item.attr_list[i].attr_id,
  371. attr_name: item.attr_list[i].attr_name
  372. }
  373. if(JSON.stringify(first) != JSON.stringify(this.activeAttr[i])) {
  374. same = false;
  375. }
  376. }
  377. if(same) {
  378. that.goodsAttr.push(item)
  379. }
  380. }
  381. that.$forceUpdate();
  382. that.count();
  383. },
  384. wholesaleNumberSub(index) {
  385. if(this.goodsAttr[index].number == 0) {
  386. return false;
  387. }
  388. this.goodsAttr[index].number--;
  389. if(this.goods.attr_groups.length == 1) {
  390. this.pic_url = this.goodsAttr[index].pic_url;
  391. }
  392. this.count(index);
  393. },
  394. wholesaleNumberAdd(index) {
  395. if(this.goodsAttr[index].number > this.goodsAttr[index].stock || this.goodsAttr[index].number == this.goodsAttr[index].stock) {
  396. return false
  397. }
  398. this.goodsAttr[index].number++;
  399. if(this.goods.attr_groups.length == 1) {
  400. this.pic_url = this.goodsAttr[index].pic_url;
  401. }
  402. this.count(index);
  403. },
  404. wholesaleNumberBlur(index) {
  405. if(+this.goodsAttr[index].number > +this.goodsAttr[index].stock) {
  406. this.goodsAttr[index].number = this.goodsAttr[index].stock
  407. }
  408. if(this.goods.attr_groups.length == 1) {
  409. this.pic_url = this.goodsAttr[index].pic_url;
  410. }
  411. this.count(index);
  412. },
  413. count(index) {
  414. let that =this;
  415. this.$emit('attrtap', {goods: that.goods, goodsAttr:that.goodsAttr});
  416. setTimeout(()=>{
  417. that.selectAttr = that.goodsAttr[index];
  418. })
  419. },
  420. close() {
  421. this.display = 'none';
  422. this.$emit('close', false)
  423. },
  424. preventD() {
  425. },
  426. storeAttrClick(attr_id, attr_group_id) {
  427. let attr_group_list = JSON.parse(JSON.stringify(this.newAttrGroupList));
  428. let attrs = this.goods.attr;
  429. let checkedAttr = [];
  430. let attr_cart = this.attrCart;
  431. for (let i in attr_group_list) {
  432. for (let j in attr_group_list[i].attr_list) {
  433. let temp = attr_group_list[i].attr_list[j];
  434. if (parseInt(attr_group_list[i].attr_group_id) == parseInt(attr_group_id)) {
  435. if (parseInt(temp.attr_id) === parseInt(attr_id)) {
  436. if (temp.checked) {
  437. temp.checked = false;
  438. } else {
  439. temp.checked = true;
  440. }
  441. if (temp.attr_num_0) {
  442. return;
  443. }
  444. } else {
  445. temp.checked = false;
  446. }
  447. }
  448. if (temp.checked) {
  449. if (i == 0) {
  450. this.pic_url = attr_group_list[0].attr_list[j].pic_url;
  451. }
  452. checkedAttr.push(attr_group_list[i].attr_group_id + '-' + temp.attr_id);
  453. }
  454. }
  455. }
  456. function inArray(val, arr) {
  457. return arr.some(function (v) {
  458. return val == v;
  459. })
  460. }
  461. let attrNum_0 = [];
  462. let select_attr = null;
  463. let number = 1;
  464. for (let i in attrs) {
  465. let arr = [];
  466. let sign = 0;
  467. for (let j in attrs[i].attr_list) {
  468. let param = attrs[i].attr_list[j].attr_group_id + '-' + attrs[i].attr_list[j].attr_id;
  469. if (!inArray(param, checkedAttr)) {
  470. sign += 1;
  471. arr.push(param);
  472. }
  473. }
  474. if (attrs[i].stock == 0 && sign <= 1) {
  475. attrNum_0 = attrNum_0.concat(arr);
  476. }
  477. if (sign == 0) {
  478. if (!select_attr) {
  479. select_attr = {};
  480. }
  481. select_attr = attrs[i];
  482. attr_cart.forEach(item => {
  483. if (item.attr_id == select_attr.id) {
  484. number = item.num;
  485. }
  486. });
  487. if (select_attr.stock <= 0) {
  488. uni.showToast({
  489. title: '库存不足',
  490. icon: 'none'
  491. });
  492. return;
  493. }
  494. if (select_attr.stock <= number) {
  495. number = select_attr.stock;
  496. }
  497. }
  498. }
  499. if (checkedAttr.length == 0) {
  500. select_attr = null;
  501. }
  502. //库存为0的规格添加标识
  503. for (let i in attr_group_list) {
  504. for (let j in attr_group_list[i].attr_list) {
  505. let cAttr = attr_group_list[i].attr_list[j];
  506. let cParam = attr_group_list[i].attr_group_id + '-' + cAttr.attr_id;
  507. if (inArray(cParam, attrNum_0) && !inArray(cParam, checkedAttr)) {
  508. cAttr.attr_num_0 = true;
  509. } else {
  510. cAttr.attr_num_0 = false;
  511. }
  512. }
  513. }
  514. this.newAttrGroupList = attr_group_list;
  515. this.selectAttr = select_attr;
  516. this.number = number;
  517. this.$emit('attrtap', this.selectAttr);
  518. },
  519. numberBlur(number) {
  520. number = parseInt(number.value);
  521. if (number > this.attrNum) {
  522. uni.showToast({
  523. title: '库存不足',
  524. icon: 'none'
  525. });
  526. number = this.attrNum;
  527. }
  528. this.$emit('attrtap', this.selectAttr);
  529. return this.number = number;
  530. },
  531. numberSub() {
  532. let number = this.number;
  533. if (number <= 1) {
  534. return true;
  535. }
  536. number--;
  537. this.number = number;
  538. this.$emit('attrtap', this.selectAttr);
  539. },
  540. numberAdd() {
  541. let number = this.number;
  542. number++;
  543. if (number > this.attrNum) {
  544. uni.showToast({
  545. title: '库存不足',
  546. icon: 'none'
  547. });
  548. this.number = this.attrNum;
  549. return;
  550. }
  551. this.number = number;
  552. this.$emit('attrtap', this.selectAttr);
  553. },
  554. cart() {
  555. if (!this.submit()) {
  556. return false;
  557. }
  558. let select_attr = this.selectAttr;
  559. if (this.goods.sign === 'pick' || this.goods.sign === 'community') {
  560. this.$emit('add', select_attr, this.number);
  561. return;
  562. }
  563. // 普通商品
  564. if (this.goods.type === 'goods') {
  565. if (this.goods.sign === 'miaosha') {
  566. this.$request({
  567. url: this.$api.miaosha.add_cart,
  568. data: {
  569. miaosha_goods_id: select_attr.goods_id,
  570. attr_id: select_attr.id,
  571. num: this.number
  572. },
  573. method: 'post'
  574. }).then(e => {
  575. uni.showToast({
  576. title: e.msg,
  577. type: 'success'
  578. });
  579. this.display = 'none';
  580. this.selectAttr.number = this.number;
  581. this.$emit('selectNumber', this.selectAttr);
  582. }).catch(() => {
  583. this.display = 'none';
  584. });
  585. } else if (this.goods.sign === 'flash_sale') {
  586. this.$request({
  587. url: this.$api.flash_sale.add_cart,
  588. data: {
  589. flash_goods_id: select_attr.goods_id,
  590. attr_id: select_attr.id,
  591. num: this.number
  592. },
  593. method: 'post'
  594. }).then(e => {
  595. uni.showToast({
  596. title: e.msg,
  597. type: 'success'
  598. });
  599. this.display = 'none';
  600. this.selectAttr.number = this.number;
  601. this.$emit('selectNumber', this.selectAttr);
  602. }).catch(() => {
  603. this.display = 'none';
  604. });
  605. }else if(this.goods.sign == 'wholesale') {
  606. if(this.totalNumber < this.goods.wholesaleGoods.rise_num) {
  607. uni.showToast({
  608. title: '至少采购' + this.goods.wholesaleGoods.rise_num + this.goods.unit,
  609. image: '/static/image/plugins/tip.png',
  610. duration: 1000
  611. });
  612. return false
  613. }
  614. let para = [];
  615. for(let item of this.goods.attr) {
  616. if(item.number > 0) {
  617. para.push(item)
  618. }
  619. }
  620. this.$request({
  621. url: this.$api.wholesale.cart,
  622. data: {
  623. attr: JSON.stringify(para)
  624. },
  625. method:'post'
  626. }).then(response => {
  627. this.display = 'none';
  628. if (response.code === 0) {
  629. for(let item of this.goods.attr) {
  630. item.number = '0'
  631. }
  632. for(let item of this.goodsAttr) {
  633. item.number = '0'
  634. }
  635. this.count();
  636. uni.hideLoading();
  637. uni.showToast({
  638. title: '添加成功',
  639. duration: 1000
  640. });
  641. }
  642. }).catch(response => {
  643. this.display = 'none';
  644. })
  645. } else {
  646. this.$request({
  647. url: this.$api.cart.add,
  648. data: {
  649. goods_id: select_attr.goods_id,
  650. attr: select_attr.id,
  651. num: this.number
  652. },
  653. method: 'post'
  654. }).then(e => {
  655. if (e.code === 0) {
  656. uni.showToast({
  657. title: e.msg,
  658. type: 'success'
  659. });
  660. this.display = 'none';
  661. this.selectAttr.number = this.number;
  662. this.$emit('selectNumber', this.selectAttr);
  663. } else {
  664. uni.showToast({
  665. title: e.msg,
  666. icon: "none",
  667. duration: 2500
  668. });
  669. this.display = 'none';
  670. }
  671. }).catch(() => {
  672. this.display = 'none';
  673. });
  674. }
  675. // 虚拟商品
  676. } else if (this.goods.type === 'ecard') {
  677. uni.showToast({
  678. title: '虚拟商品不允许加入购物车',
  679. icon: 'none'
  680. });
  681. }
  682. },
  683. buy() {
  684. // 判断登入
  685. if (!this.$user.isLogin()) {
  686. this.$user.getInfo();
  687. return;
  688. }
  689. if (this.goods.sell_time > 0) {
  690. this.rightTip();
  691. return ;
  692. }
  693. if (!this.submit()) return false;
  694. if (this.noPay) {
  695. this.$emit('pay', this.number);
  696. return;
  697. }
  698. if (this.buyClick) {
  699. this.display = 'none';
  700. this.selectAttr.number = this.number;
  701. this.$emit('buyClick', this.selectAttr);
  702. return false;
  703. }
  704. if(this.goods.sign == 'wholesale') {
  705. if(this.totalNumber < this.goods.wholesaleGoods.rise_num) {
  706. uni.showToast({
  707. title: '至少采购' + this.goods.wholesaleGoods.rise_num + this.goods.unit,
  708. image: '/static/image/plugins/tip.png',
  709. duration: 1000
  710. });
  711. return false
  712. }
  713. let para = {};
  714. let mch_list = [{
  715. mch_id: 0,
  716. goods_list: []
  717. }];
  718. for(let item of this.goods.attr) {
  719. if(item.number > 0) {
  720. para = {
  721. id: item.goods_id,
  722. attr: [],
  723. num: item.number,
  724. cat_id: 0,
  725. goods_attr_id: item.id
  726. }
  727. for(let attr of item.attr_list) {
  728. let attrList = {
  729. attr_id: attr.attr_id,
  730. attr_group_id: attr.attr_group_id
  731. }
  732. para.attr.push(attrList)
  733. }
  734. mch_list[0].goods_list.push(para)
  735. }
  736. }
  737. let url = `/pages/order-submit/order-submit?mch_list=${JSON.stringify(mch_list)}`;
  738. if (this.submitUrl && this.previewUrl) {
  739. url += `&preview_url=${encodeURIComponent(this.previewUrl)}&submit_url=${encodeURIComponent(this.submitUrl)}&plugin=${this.plugin}`;
  740. }
  741. uni.navigateTo({
  742. url: url
  743. })
  744. }else {
  745. let goods = this.goods;
  746. let number = this.number;
  747. let select_attr = this.selectAttr;
  748. let goods_attr_id = select_attr.id;
  749. let attr = [];
  750. for (let i in select_attr.attr_list) {
  751. attr.push({
  752. attr_id: select_attr.attr_list[i].attr_id,
  753. attr_group_id: select_attr.attr_list[i].attr_group_id
  754. });
  755. }
  756. let mch_list = [{
  757. mch_id: goods.mch_id ? goods.mch_id : 0,
  758. goods_list: [{
  759. id: this.goodsId ? this.goodsId: goods.id,
  760. attr: attr,
  761. num: number,
  762. cat_id: 0,
  763. goods_attr_id: goods_attr_id
  764. }]
  765. }];
  766. let url = `/pages/order-submit/order-submit?mch_list=${JSON.stringify(mch_list)}`;
  767. if (this.submitUrl && this.previewUrl) {
  768. url += `&preview_url=${encodeURIComponent(this.previewUrl)}&submit_url=${encodeURIComponent(this.submitUrl)}&plugin=${this.plugin}`;
  769. }
  770. uni.navigateTo({
  771. url: url
  772. })
  773. }
  774. },
  775. submit() {
  776. let select_attr = this.selectAttr;
  777. if(this.goods.sign === 'wholesale') {
  778. return true;
  779. }
  780. if (!select_attr) {
  781. uni.showToast({
  782. title: '请先选规格',
  783. icon: 'none'
  784. });
  785. return false;
  786. }
  787. if (select_attr.stock <= 0) {
  788. uni.showToast({
  789. title: '库存不足',
  790. icon: 'none'
  791. });
  792. return false;
  793. }
  794. if (this.number <= 0) {
  795. uni.showToast({
  796. title: '数量不能为0',
  797. icon: 'none'
  798. });
  799. return false;
  800. }
  801. if (!this.goods) {
  802. return false;
  803. }
  804. return true;
  805. },
  806. clickImg(src) {
  807. uni.previewImage({
  808. current: 0,
  809. urls: [src]
  810. });
  811. },
  812. changeTime(time) {
  813. this.sell_time = time;
  814. }
  815. },
  816. computed: {
  817. ...mapState({
  818. gConfig: state => state.gConfig,
  819. isTip: state => state.mallConfig.mall.setting.is_remind_sell_time
  820. }),
  821. attrPic() {
  822. if (this.pic_url) {
  823. return this.pic_url;
  824. } else if (this.goods) {
  825. return this.goods.cover_pic;
  826. } else {
  827. return ``;
  828. }
  829. },
  830. priceColor() {
  831. if (this.goods && this.goods.level_show === 1) {
  832. return `member`;
  833. } else {
  834. return this.theme + '-color';
  835. }
  836. },
  837. attrNum() {
  838. if (this.selectAttr) {
  839. return this.selectAttr.stock;
  840. } else if (this.goods) {
  841. return this.goods.goods_num;
  842. } else {
  843. return 0;
  844. }
  845. },
  846. attrPrice() {
  847. if (this.selectAttr) {
  848. let price;
  849. if (this.goods.level_show === 1) {
  850. price = this.selectAttr.price_member
  851. } else {
  852. price = this.selectAttr.price;
  853. }
  854. if(this.sign == 'wholesale') {
  855. if(this.selectAttr.number == 0) {
  856. return 'undefined'
  857. }
  858. if(this.wholesaleType == 0) {
  859. price = (price*(this.discount/10)).toFixed(2);
  860. return price
  861. }else {
  862. price = (price - this.discount).toFixed(2);
  863. return price
  864. }
  865. }else {
  866. return price
  867. }
  868. } else if(this.sign == 'wholesale') {
  869. return 'undefined';
  870. } else if (this.goods) {
  871. if (this.goods.hasOwnProperty('price_min')) {
  872. return this.goods.price_min;
  873. } else {
  874. return this.goods.price;
  875. }
  876. } else {
  877. return 0;
  878. }
  879. },
  880. newData() {
  881. const { number, display, selectAttr } = this;
  882. return {
  883. number,
  884. display,
  885. selectAttr
  886. }
  887. },
  888. ...mapGetters('iPhoneX', {
  889. boolEmpty: 'getBoolEmpty'
  890. }),
  891. ...mapGetters({
  892. userInfo: 'user/info',
  893. }),
  894. showRight() {
  895. return !(this.isTip == 0 && this.goods.sell_time > 0) && this.is_show_buy
  896. },
  897. remindParams() {
  898. return {
  899. sell_time: this.sell_time,
  900. goods_id: this.goods.id,
  901. template_message_list: this.goods.template_message_list,
  902. buy_text: this.buyText
  903. };
  904. },
  905. }
  906. }
  907. </script>
  908. <style scoped lang="scss">
  909. .app-attr {
  910. background-color: #ffffff;
  911. .modal {
  912. background-color: rgba(0, 0, 0, 0.5);
  913. position: fixed;
  914. top: 0;
  915. left: 0;
  916. width: 100%;
  917. height: 100%;
  918. z-index: 1603;
  919. }
  920. .content {
  921. width: 100%;
  922. background-color: #ffffff;
  923. border-radius: #{16rpx} #{16rpx} 0 0;
  924. .close {
  925. width: #{30rpx};
  926. height: #{30rpx};
  927. position: absolute;
  928. right: #{24rpx};
  929. top: #{24rpx};
  930. background-color: #ffffff;
  931. }
  932. .first {
  933. margin: 0 #{24rpx};
  934. border-bottom: #{1rpx} solid #e2e2e2;
  935. &.no-border {
  936. border-bottom: 0;
  937. }
  938. .img {
  939. width: #{200rpx};
  940. height: #{200rpx};
  941. border: #{4rpx} solid #ffffff;
  942. border-radius: #{8rpx};
  943. margin-top: #{-64rpx};
  944. display: block;
  945. }
  946. .info {
  947. margin: #{36rpx} 0 #{26rpx} #{24rpx};
  948. font-size: $uni-font-size-import-two;
  949. line-height: 1;
  950. .stock {
  951. font-size: $uni-font-size-weak-one;
  952. color: $uni-general-color-two;
  953. margin-top: #{18rpx};
  954. }
  955. view {
  956. &:first-child {
  957. margin-right: #{12rpx};
  958. }
  959. }
  960. >.member {
  961. color: #f39800;
  962. }
  963. }
  964. }
  965. .second {
  966. max-height: #{650rpx};
  967. overflow-y: auto;
  968. overflow-x: hidden;
  969. padding: #{4rpx} #{24rpx};
  970. font-size: $uni-font-size-general-two;
  971. &.no-padding {
  972. padding: 0;
  973. }
  974. .attr-group {
  975. padding: #{32rpx} 0;
  976. border-bottom: #{1rpx} solid #e2e2e2;
  977. .attr-group-name {
  978. color: $uni-general-color-one;
  979. margin-bottom: #{20rpx};
  980. }
  981. .attr-item {
  982. margin-right: #{20rpx};
  983. padding: #{15rpx 24rpx};
  984. border-radius: #{8rpx};
  985. margin-bottom: #{20rpx};
  986. &.attr-item-default {
  987. background-color: #f2f2f2;
  988. color: $uni-important-color-black;
  989. }
  990. &.active {
  991. color: #ffffff;
  992. }
  993. &.attr_num_0 {
  994. color: #cdcdcd;
  995. background-color: #f7f7f7;
  996. }
  997. }
  998. }
  999. .number-box {
  1000. color: $uni-general-color-one;
  1001. height: #{124rpx};
  1002. .block {
  1003. width: #{60rpx};
  1004. height: #{60rpx};
  1005. margin: 0 #{4rpx};
  1006. &.disabled {
  1007. background-color: #fbfbfb;
  1008. color: $uni-general-color-two;
  1009. }
  1010. }
  1011. .number-input {
  1012. width: #{88rpx};
  1013. height: #{60rpx};
  1014. color: $uni-important-color-black;
  1015. font-size: $uni-font-size-general-one;
  1016. background-color: $uni-weak-color-two;
  1017. }
  1018. }
  1019. }
  1020. .three {
  1021. height: #{110rpx};
  1022. width: 100%;
  1023. padding: 20upx 24upx;
  1024. font-size: $uni-font-size-general-one;
  1025. }
  1026. }
  1027. }
  1028. .buy {
  1029. color: #ffffff;
  1030. margin-left: 20upx;
  1031. }
  1032. .wholesale {
  1033. .wholesale-attr-list {
  1034. height: #{88rpx};
  1035. margin: 0 #{24rpx};
  1036. border-bottom: #{1rpx} solid #e2e2e2;
  1037. position: relative;
  1038. &:first-of-type {
  1039. border-top: #{1rpx} solid #e2e2e2;
  1040. }
  1041. .position {
  1042. position: absolute;
  1043. left: 0;
  1044. top: #{2rpx};
  1045. z-index: 10000;
  1046. background-color: #fff;
  1047. height: #{83rpx};
  1048. }
  1049. .wholesale-attr-group {
  1050. max-width: #{200rpx};
  1051. flex-shrink: 0;
  1052. margin-right: #{4rpx};
  1053. font-size: #{20rpx};
  1054. color: #666666;
  1055. background-color: #fff;
  1056. }
  1057. .right-icon {
  1058. position: absolute;
  1059. right: #{-24rpx};
  1060. top: 0;
  1061. height: #{84rpx};
  1062. padding-left: #{10rpx};
  1063. width: #{50rpx};
  1064. z-index: 10000;
  1065. background-color: #fff;
  1066. view {
  1067. height: #{40rpx};
  1068. width: #{3rpx};
  1069. background-color: #e2e2e2;
  1070. position: absolute;
  1071. left: 0;
  1072. top: #{24rpx};
  1073. }
  1074. image {
  1075. margin-top: #{33rpx};
  1076. height: #{22rpx};
  1077. width: #{16rpx};
  1078. }
  1079. }
  1080. .wholesale-attr-item {
  1081. height: 100%;
  1082. width: 100%;
  1083. white-space : nowrap;
  1084. .scroll-attr-group {
  1085. display: inline-block;
  1086. visibility: hidden;
  1087. .wholesale-attr-group {
  1088. height: #{44rpx};
  1089. }
  1090. }
  1091. .attr-name {
  1092. color: #fff;
  1093. padding: 0 #{22rpx};
  1094. height: #{56rpx};
  1095. line-height: #{56rpx};
  1096. border-radius: #{8rpx};
  1097. font-size: #{26rpx};
  1098. margin-left: #{20rpx};
  1099. display: inline-block;
  1100. position: relative;
  1101. min-width: #{10rpx};
  1102. .attr-number {
  1103. color: #fff;
  1104. position: absolute;
  1105. top: #{-15rpx};
  1106. height: #{30rpx};
  1107. line-height: #{26rpx};
  1108. border: #{2rpx} solid #fff;
  1109. padding: 0 #{10rpx};
  1110. border-radius: #{15rpx};
  1111. font-size: #{20rpx};
  1112. z-index: 100;
  1113. }
  1114. &.attr-background {
  1115. background-color: #f2f2f2;
  1116. color: #353535;
  1117. }
  1118. }
  1119. }
  1120. }
  1121. .wholesale-attr-group-list {
  1122. margin-top: #{20rpx};
  1123. .wholesale-attr-group {
  1124. margin-bottom: #{20rpx};
  1125. .wholesale-attr-item {
  1126. padding: #{20rpx};
  1127. background-color: #f7f7f7;
  1128. width: 100%;
  1129. .attr-name {
  1130. width: 60%;
  1131. .attr-price {
  1132. color: #999999;
  1133. font-size: #{24rpx};
  1134. }
  1135. }
  1136. .wholesale-number-box {
  1137. color: $uni-general-color-one;
  1138. .block {
  1139. width: #{60rpx};
  1140. height: #{60rpx};
  1141. margin: 0 #{4rpx};
  1142. &.disabled {
  1143. background-color: #fbfbfb;
  1144. color: $uni-general-color-two;
  1145. }
  1146. }
  1147. .wholesale-number-input {
  1148. width: #{88rpx};
  1149. height: #{60rpx};
  1150. color: $uni-important-color-black;
  1151. font-size: $uni-font-size-general-one;
  1152. background-color: #fff;
  1153. }
  1154. }
  1155. }
  1156. }
  1157. }
  1158. }
  1159. .total {
  1160. width: 100%;
  1161. height: #{80rpx};
  1162. line-height: #{80rpx};
  1163. text-align: right;
  1164. padding: 0 24rpx;
  1165. color: #353535;
  1166. font-size: #{28rpx};
  1167. border-top: #{1rpx} solid #e2e2e2;
  1168. text {
  1169. color: #ff4544;
  1170. }
  1171. }
  1172. .u-attr-fixed {
  1173. position: fixed;
  1174. bottom: 0;
  1175. left: 0;
  1176. width: 100%;
  1177. background-color: #ffffff;
  1178. }
  1179. .bd-btn {
  1180. line-height: 70upx;
  1181. text-align: center;
  1182. font-size: 26upx;
  1183. border-radius: 35upx;
  1184. }
  1185. </style>