index.vue 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108
  1. <template>
  2. <view>
  3. <view class='shoppingCart copy-data' v-if="showCartList">
  4. <!-- <view class='labelNav acea-row row-around'>
  5. <view class='item'><text class='iconfont icon-xuanzhong'></text>100%正品保证</view>
  6. <view class='item'><text class='iconfont icon-xuanzhong'></text>所有商品精挑细选</view>
  7. <view class='item'><text class='iconfont icon-xuanzhong'></text>售后无忧</view>
  8. </view>
  9. -->
  10. <view class="borRadius14 cartBox">
  11. <view
  12. v-if="(cartList.valid.length === 0 && cartList.invalid.length === 0) || (cartList.valid.length > 0)"
  13. class='nav acea-row row-between-wrapper'>
  14. <view>购物数量 <text class='num font-color'>{{cartCount}}</text></view>
  15. <view v-if="cartList.valid.length > 0 || cartList.invalid.length > 0"
  16. class='administrate acea-row row-center-wrapper' @click='manage'>{{ footerswitch ? '管理' : '取消'}}
  17. </view>
  18. </view>
  19. <view v-if="cartList.valid.length > 0 || cartList.invalid.length > 0" class="pad30">
  20. <!-- 有效的购物车 -->
  21. <view class='list'>
  22. <checkbox-group @change="checkboxChange">
  23. <block v-for="(item,index) in cartList.valid" :key="index">
  24. <view class='item acea-row row-between-wrapper'>
  25. <!-- #ifndef MP -->
  26. <checkbox :value="item.id.toString()" :checked="item.selected"
  27. :disabled="!item.canChecked && footerswitch" style="margin-right: 10rpx;" />
  28. <!-- #endif -->
  29. <!-- #ifdef MP -->
  30. <checkbox :value="item.id.toString()" :checked="item.selected"
  31. :disabled="!item.canChecked && footerswitch" />
  32. <!-- #endif -->
  33. <navigator :url='"/pages/goods_details/index?id=" + item.spu.id' hover-class='none'
  34. class='picTxt acea-row row-between-wrapper'>
  35. <view class='pictrue'>
  36. <image v-if="item.sku" :src='item.sku.picUrl' />
  37. <image v-else :src='item.spu.picUrl' />
  38. </view>
  39. <view class='text'>
  40. <view class='line1' :class="item.canChecked?'':'reColor'">
  41. {{ item.spu.name }}
  42. </view>
  43. <view class='infor line1' v-if="item.sku">属性:
  44. <text v-for="property in item.sku.properties"
  45. style="padding-left: 2px">{{property.valueName}}</text>
  46. </view>
  47. <view class='money' v-if="item.canChecked">¥{{ fen2yuan(item.sku.price) }}
  48. </view>
  49. <view class="reElection acea-row row-between-wrapper" v-else>
  50. <view class="title">请重新选择商品规格</view>
  51. <view class="reBnt cart-color acea-row row-center-wrapper"
  52. @click.stop="reElection(item)">重选</view>
  53. </view>
  54. </view>
  55. <view class='carnum acea-row row-center-wrapper' v-if="item.canChecked">
  56. <view class="reduce" :class="item.numSub ? 'on' : ''"
  57. @click.stop='subCart(index)'>-</view>
  58. <view class='num'>{{ item.count }}</view>
  59. <view class="plus" :class="item.numAdd ? 'on' : ''"
  60. @click.stop='addCart(index)'>+</view>
  61. </view>
  62. </navigator>
  63. </view>
  64. </block>
  65. </checkbox-group>
  66. </view>
  67. <!-- 无效的购物车 -->
  68. <view v-if="cartList.invalid.length > 0" class='invalidGoods borRadius14' :style="cartList.valid.length === 0 && cartList.invalid.length > 0
  69. ? 'position: relative;z-index: 111;top: -120rpx;'
  70. :'position: static;'">
  71. <view class='goodsNav acea-row row-between-wrapper'>
  72. <view v-if="cartList.invalid.length > 1 || cartList.valid.length > 0" @click='goodsOpen'>
  73. <text class='iconfont' :class='goodsHidden ? "icon-xiangxia":"icon-xiangshang"' /> 失效商品
  74. </view>
  75. <view v-else>失效商品</view>
  76. <view class='del' @click='unsetCart'>
  77. <text class='iconfont icon-shanchu1' />清空
  78. </view>
  79. </view>
  80. <view class='goodsList' :hidden='goodsHidden'>
  81. <block v-for="(item,index) in cartList.invalid" :key='index'>
  82. <view class='item acea-row row-between-wrapper'>
  83. <view class='invalid'>失效</view>
  84. <view class='picTxt acea-row row-between-wrapper'>
  85. <view class='pictrue'>
  86. <image v-if="item.sku" :src='item.sku.picUrl' />
  87. <image v-else :src='item.spu.picUrl' />
  88. </view>
  89. <view class='text acea-row row-column-between'>
  90. <view class='line1 name'>{{ item.spu.name }}</view>
  91. <view class='infor line1' v-if="item.sku.properties">属性:
  92. <text v-for="property in item.sku.properties"
  93. style="padding-left: 2px">{{property.valueName}}</text>
  94. </view>
  95. <view class='acea-row row-between-wrapper'>
  96. <view class='end'>该商品已失效</view>
  97. </view>
  98. </view>
  99. </view>
  100. </view>
  101. </block>
  102. </view>
  103. </view>
  104. </view>
  105. <!-- 热门推荐 -->
  106. <view class='noCart' v-if="cartList.valid.length === 0 && cartList.invalid.length === 0 && canShow">
  107. <view class='pictrue'>
  108. <image src='../../static/images/noCart.png' />
  109. </view>
  110. <recommend :hostProduct='hostProduct'></recommend>
  111. </view>
  112. </view>
  113. </view>
  114. <!-- 管理操作 -->
  115. <view class='footer acea-row row-between-wrapper' @click="aaa">
  116. <view>
  117. <checkbox-group @change="checkboxAllChange">
  118. <checkbox value="all" :checked="!!isAllSelect" />
  119. <text class='checkAll'>全选({{selectValue.length}})</text>
  120. </checkbox-group>
  121. </view>
  122. <view class='money acea-row row-middle' v-if="footerswitch">
  123. <text class='font-color'>¥{{ fen2yuan(selectCountPrice) }}</text>
  124. <form @submit="subOrder" report-submit='true'>
  125. <button class='placeOrder bg-color' formType="submit">立即下单</button>
  126. </form>
  127. </view>
  128. <view class='button acea-row row-middle' v-else>
  129. <form @submit="subCollect" report-submit='true'>
  130. <button class='bnt cart-color' formType="submit">收藏</button>
  131. </form>
  132. <form @submit="subDel" report-submit='true'>
  133. <button class='bnt' formType="submit">删除</button>
  134. </form>
  135. </view>
  136. </view>
  137. <!-- SKU 不可用的商品,重新选择 SKU -->
  138. <productWindow :attr="attr" :isShow='1' :iSplus='1' :iScart='1' @ChangeAttr="ChangeAttr"
  139. @ChangeCartNum="ChangeCartNum" @iptCartNum="iptCartNum" @close="closeAttr" @goCat="reGoCat" />
  140. <!-- <view class="uni-p-b-96" />
  141. <view class="uni-p-b-98" /> -->
  142. </view>
  143. </template>
  144. <script>
  145. let sysHeight = 0
  146. import {
  147. toLogin
  148. } from '@/libs/login.js';
  149. import {
  150. mapGetters
  151. } from "vuex";
  152. import recommend from '@/components/recommend';
  153. import productWindow from '@/components/productWindow';
  154. import * as TradeCartApi from '@/api/trade/cart.js';
  155. import * as ProductSpuApi from '@/api/product/spu.js'
  156. import * as ProductFavoriteApi from '@/api/product/favorite.js';
  157. import * as Util from '@/utils/util.js';
  158. import * as ProductUtil from '@/utils/product.js';
  159. import * as PromotionActivityApi from '@/api/promotion/activity.js';
  160. export default {
  161. components: {
  162. recommend,
  163. productWindow,
  164. },
  165. data() {
  166. return {
  167. sysHeight: sysHeight,
  168. goodsHidden: false,
  169. footerswitch: true,
  170. hostProduct: [],
  171. hotPage: 1,
  172. hotLimit: 10,
  173. hotScroll: false,
  174. // 购物车列表
  175. cartList: { // 购物车列表
  176. valid: [], // 有效
  177. invalid: [] // 无效
  178. },
  179. isAllSelect: false, // 是否全选
  180. selectValue: [], // 选中的数据
  181. selectCountPrice: 0.00, // 选中的金额
  182. cartCount: 0, // 选中的商品数量
  183. canShow: false, // 是否可展示
  184. // 重选
  185. cartId: 0, // 重选的 cart id
  186. product_id: 0, // 重选的 SPU 编号
  187. attr: { // productWindow 组件,使用该属性
  188. cartAttr: false, // 是否打开属性的选择弹出
  189. // ↓↓↓ 属性数组,结构为:id = 属性编号;name = 属性编号的名字;values[].id = 属性值的编号,values[].name = 属性值的名字;index = 选中的属性值的名字
  190. properties: [],
  191. productSelect: {} // 选中的 SKU
  192. },
  193. spu: {}, // 商品 SPU 详情
  194. skuMap: [], // 商品 SKU Map
  195. attrValue: '', // 已选属性名的拼接,例如说 红色,大 这样的格式
  196. showCartList: false, //是否显示购物车list
  197. };
  198. },
  199. computed: mapGetters(['isLogin']),
  200. created() {
  201. console.log('我执行了')
  202. },
  203. created: function(options) {
  204. console.log(222)
  205. if (!this.isLogin) {
  206. toLogin();
  207. }
  208. },
  209. mounted: function() {
  210. console.log(1111)
  211. this.canShow = false
  212. if (this.isLogin === true) {
  213. // 加载热门商品
  214. this.hotPage = 1;
  215. this.hotLimit = 10;
  216. this.hostProduct = [];
  217. this.hotScroll = false;
  218. this.loadend = false;
  219. this.getHostProduct()
  220. // 加载购物车列表
  221. this.footerswitch = true;
  222. this.hotScroll = false;
  223. this.cartList = {
  224. valid: [],
  225. invalid: []
  226. };
  227. this.isAllSelect = false; // 全选
  228. this.selectValue = []; // 选中的数据
  229. this.selectCountPrice = 0.00;
  230. this.cartCount = 0;
  231. this.getCartList();
  232. }
  233. },
  234. methods: {
  235. /**
  236. * 修改购物车
  237. */
  238. reGoCat: function() {
  239. const productSelect = this.skuMap[this.attrValue];
  240. // 如果有属性,没有选择,提示用户选择
  241. if (this.attr.properties.length &&
  242. productSelect === undefined) {
  243. return this.$util.Tips({
  244. title: "产品库存不足,请选择其它"
  245. });
  246. }
  247. TradeCartApi.resetCart({
  248. id: this.cartId,
  249. skuId: this.attr.productSelect.id,
  250. count: this.attr.productSelect.cart_num
  251. }).then(res => {
  252. this.attr.cartAttr = false;
  253. this.$util.Tips({
  254. title: this.$t(`添加购物车成功`)
  255. });
  256. this.cartList.valid = [];
  257. this.getCartList();
  258. }).catch(res => {
  259. return this.$util.Tips({
  260. title: res
  261. });
  262. });
  263. },
  264. aaa() {
  265. console.log('我执行了点击btn')
  266. this.showCartList = true
  267. this.$emit('showMask')
  268. },
  269. /**
  270. * 重选 SKU
  271. */
  272. reElection: function(item) {
  273. this.getGoodsDetails(item)
  274. },
  275. /**
  276. * 获取产品详情
  277. */
  278. getGoodsDetails: function(item) {
  279. uni.showLoading({
  280. title: '加载中',
  281. mask: true
  282. });
  283. this.cartId = item.id;
  284. this.product_id = item.spu.id;
  285. ProductSpuApi.getSpuDetail(item.spu.id).then(res => {
  286. uni.hideLoading();
  287. this.attr.cartAttr = true;
  288. let spu = res.data;
  289. let properties = ProductUtil.convertProductPropertyList(res.data.skus);
  290. let skuMap = ProductUtil.convertProductSkuMap(res.data.skus);
  291. // 设置变量
  292. this.$set(this, 'spu', spu);
  293. this.$set(this.attr, 'properties', properties);
  294. this.$set(this, 'skuMap', skuMap);
  295. this.selectDefaultSku();
  296. }).catch(err => {
  297. uni.hideLoading();
  298. })
  299. },
  300. /**
  301. * 关闭 productWindow 弹窗
  302. */
  303. closeAttr: function() {
  304. this.$set(this.attr, "cartAttr", false);
  305. },
  306. /**
  307. * 属性变动赋值
  308. *
  309. * @param newSkuKey 新的 skuKey
  310. * @param propertyIndex properties 的下标
  311. * @param valueIndex values 的下标
  312. */
  313. ChangeAttr: function(newSkuKey, propertyIndex, valueIndex) {
  314. // SKU
  315. let sku = this.skuMap[newSkuKey];
  316. if (!sku) {
  317. return;
  318. }
  319. this.$set(this.attr.productSelect, "id", sku.id);
  320. this.$set(this.attr.productSelect, "picUrl", sku.picUrl);
  321. this.$set(this.attr.productSelect, "price", sku.price);
  322. this.$set(this.attr.productSelect, "stock", sku.stock);
  323. this.$set(this.attr.productSelect, "cart_num", 1);
  324. // SKU 关联属性
  325. this.$set(this.attr.properties[propertyIndex], 'index',
  326. this.attr.properties[propertyIndex].values[valueIndex].name);
  327. this.$set(this, "attrValue", newSkuKey);
  328. },
  329. /**
  330. * 查找默认选中的 sku,设置到 attr.productSelect 中
  331. *
  332. * 先找有库存的 SKU,否则找第一个 SKU
  333. */
  334. selectDefaultSku: function() {
  335. const properties = this.attr.properties;
  336. // 获得选中的属性值的名字,例如说 "黑色,大",则 skuKey = ["黑色", "大"]
  337. let skuKey = undefined;
  338. for (let key in this.skuMap) {
  339. if (this.skuMap[key].stock > 0) {
  340. skuKey = key.split(",");
  341. break;
  342. }
  343. }
  344. if (!skuKey) { // 如果找不到,则选中第一个
  345. skuKey = Object.keys(this.skuMap)[0].split(",");
  346. }
  347. // 使用 index 属性表示当前选中的,值为属性值的名字
  348. for (let i = 0; i < properties.length; i++) {
  349. this.$set(properties[i], "index", skuKey[i]);
  350. }
  351. let sku = this.skuMap[skuKey.join(",")];
  352. if (!sku) {
  353. return
  354. }
  355. this.$set(this.attr.productSelect, "spuName", this.spu.name);
  356. this.$set(this.attr.productSelect, "id", sku.id);
  357. this.$set(this.attr.productSelect, "picUrl", sku.picUrl);
  358. this.$set(this.attr.productSelect, "price", sku.price);
  359. this.$set(this.attr.productSelect, "stock", sku.stock);
  360. this.$set(this.attr.productSelect, "cart_num", 1);
  361. this.$set(this, "attrValue", skuKey.join(","));
  362. },
  363. /**
  364. * 购物车数量加和数量减
  365. *
  366. * @param changeValue true 增加;false 减少
  367. */
  368. ChangeCartNum: function(changeValue) {
  369. /// 获取当前 sku
  370. let sku = this.attr.productSelect;
  371. if (!sku) {
  372. return;
  373. }
  374. // 设置数量
  375. let stock = sku.stock || 0;
  376. if (changeValue) {
  377. sku.cart_num++;
  378. if (sku.cart_num > stock) {
  379. this.$set(this.attr.productSelect, "cart_num", stock);
  380. }
  381. } else {
  382. sku.cart_num--;
  383. if (sku.cart_num < 1) {
  384. this.$set(this.attr.productSelect, "cart_num", 1);
  385. }
  386. }
  387. },
  388. /**
  389. * 购物车手动填写
  390. */
  391. iptCartNum: function(number) {
  392. this.$set(this.attr.productSelect, 'cart_num', number ? number : 1);
  393. },
  394. /**
  395. * 删除选中的商品
  396. */
  397. subDel: function(event) {
  398. const selectValue = this.selectValue;
  399. if (selectValue.length === 0) {
  400. return this.$util.Tips({
  401. title: '请选择产品'
  402. });
  403. }
  404. TradeCartApi.deleteCart(selectValue).then(res => {
  405. this.getCartList();
  406. });
  407. },
  408. getSelectValueProductId: function() {
  409. const validList = this.cartList.valid;
  410. const selectValue = this.selectValue;
  411. let productId = [];
  412. if (selectValue.length > 0) {
  413. for (let index in validList) {
  414. if (this.inArray(validList[index].id, selectValue)) {
  415. productId.push(validList[index].spu.id);
  416. }
  417. }
  418. }
  419. return productId;
  420. },
  421. /**
  422. * 收藏选中的商品
  423. */
  424. subCollect: function(event) {
  425. const spuIds = this.getSelectValueProductId();
  426. if (spuIds.length === 0) {
  427. return this.$util.Tips({
  428. title: '请选择产品'
  429. });
  430. }
  431. ProductFavoriteApi.createFavoriteList(spuIds).then(res => {
  432. return this.$util.Tips({
  433. title: '收藏成功',
  434. icon: 'success'
  435. });
  436. }).catch(err => {
  437. return that.$util.Tips({
  438. title: err
  439. });
  440. });
  441. },
  442. /**
  443. * 立即下单
  444. */
  445. subOrder: function(event) {
  446. const selectValue = this.selectValue;
  447. if (selectValue.length === 0) {
  448. return this.$util.Tips({
  449. title: '请选择产品'
  450. });
  451. }
  452. uni.navigateTo({
  453. url: '/pages/users/order_confirm/index?cartIds=' + selectValue.join(',')
  454. });
  455. },
  456. /**
  457. * 预下单
  458. */
  459. getPreOrder: function() {
  460. let shoppingCartId = this.selectValue.map(item => {
  461. return {
  462. "shoppingCartId": Number(item)
  463. }
  464. })
  465. this.$Order.getPreOrder("shoppingCart", shoppingCartId);
  466. },
  467. /**
  468. * 全选 / 全不选
  469. */
  470. checkboxAllChange: function(event) {
  471. let value = event.detail.value;
  472. if (value.length > 0) {
  473. this.setAllSelectValue(true)
  474. } else {
  475. this.setAllSelectValue(false)
  476. }
  477. },
  478. /**
  479. * 全选 / 全不选
  480. */
  481. setAllSelectValue: function(selected) {
  482. const valid = this.cartList.valid;
  483. const values = [];
  484. for (const item of valid) {
  485. values.push(item.id.toString());
  486. }
  487. TradeCartApi.updateCartSelected({
  488. ids: values,
  489. selected: selected
  490. }).then(res => {
  491. this.getCartList()
  492. })
  493. },
  494. /**
  495. * 更新是否选中
  496. */
  497. checkboxChange: function(event) {
  498. // 由于 uniapp 不支持直接通过 event 获取到变更的值,所以只能通过比对
  499. const valid = this.cartList.valid;
  500. const oldValues = [];
  501. for (const item of valid) {
  502. if (item.canChecked && item.selected) {
  503. oldValues.push(item.id.toString());
  504. } else if (!this.footerswitch && item.selected) {
  505. oldValues.push(item.id.toString());
  506. }
  507. }
  508. const newValues = event.detail.value;
  509. // 情况一:选中
  510. const selectedItem = newValues.find(item => !oldValues.includes(item));
  511. if (selectedItem) {
  512. TradeCartApi.updateCartSelected({
  513. ids: [selectedItem],
  514. selected: true
  515. }).then(res => {
  516. this.getCartList()
  517. })
  518. return;
  519. }
  520. // 情况二:取消选中
  521. const cancelSelectedItem = oldValues.find(item => !newValues.includes(item));
  522. if (cancelSelectedItem) {
  523. TradeCartApi.updateCartSelected({
  524. ids: [cancelSelectedItem],
  525. selected: false
  526. }).then(res => {
  527. this.getCartList()
  528. })
  529. }
  530. },
  531. /**
  532. * 合计金额、数量
  533. */
  534. switchSelect: function() {
  535. // 是否全选
  536. const validList = this.cartList.valid;
  537. const selectValue = [];
  538. let isAllSelect = true;
  539. if (validList && validList.length > 0) {
  540. for (const item of validList) {
  541. if (item.canChecked) {
  542. if (item.selected) {
  543. selectValue.push(item.id);
  544. } else {
  545. isAllSelect = false;
  546. }
  547. } else {
  548. if (!this.footerswitch && item.selected) {
  549. selectValue.push(item.id);
  550. }
  551. if (!this.footerswitch && !item.selected) {
  552. isAllSelect = false;
  553. }
  554. }
  555. }
  556. }
  557. this.selectValue = selectValue;
  558. this.isAllSelect = isAllSelect;
  559. // 合计金额
  560. let selectCountPrice = 0.00;
  561. let cartCount = 0
  562. for (let index in validList) {
  563. if (this.inArray(validList[index].id, selectValue) &&
  564. validList[index].sku) {
  565. selectCountPrice = this.$util.$h.Add(selectCountPrice, this.$util.$h.Mul(validList[index]
  566. .count, validList[index].sku.price))
  567. cartCount += validList[index].count
  568. }
  569. }
  570. this.selectCountPrice = selectCountPrice;
  571. this.cartCount = cartCount;
  572. },
  573. /**
  574. * 减少购买数量
  575. */
  576. subCart: function(index) {
  577. let item = this.cartList.valid[index];
  578. if (item.count < 1) {
  579. this.$util.Tips({
  580. title: '商品数量不能减少!'
  581. });
  582. return;
  583. }
  584. // 本地先修改状态
  585. item.count = Number(item.count) - 1;
  586. console.log(item.count,8888)
  587. if (item.count <= 1) {
  588. item.count = 1;
  589. item.numSub = true;
  590. } else {
  591. item.numSub = false;
  592. item.numAdd = false;
  593. }
  594. // 提交修改
  595. this.setCartNum(item.id, item.count);
  596. },
  597. /**
  598. * 增加购买数量
  599. */
  600. addCart: function(index) {
  601. // 本地先修改状态
  602. let item = this.cartList.valid[index];
  603. item.count = Number(item.count) + 1
  604. if (item.count >= item.sku.stock) {
  605. item.count = item.sku.stock;
  606. item.numAdd = true;
  607. item.numSub = false;
  608. } else {
  609. item.numAdd = false;
  610. item.numSub = false;
  611. }
  612. // 提交修改
  613. this.setCartNum(item.id, item.count);
  614. },
  615. /**
  616. * 修改购物项为指定数量
  617. */
  618. setCartNum(cartId, cartNum) {
  619. TradeCartApi.updateCartCount({
  620. id: cartId,
  621. count: cartNum
  622. }).then(res => {
  623. // 加载最新状态
  624. this.getCartList()
  625. });
  626. },
  627. getCartData() {
  628. return new Promise((resolve, reject) => {
  629. TradeCartApi.getCartList().then((res) => {
  630. resolve(res.data);
  631. }).catch(function(err) {
  632. this.canShow = true;
  633. this.$util.Tips({
  634. title: err
  635. });
  636. })
  637. });
  638. },
  639. async getCartList() {
  640. console.log('我是组件购物车')
  641. uni.showLoading({
  642. title: '加载中',
  643. mask: true
  644. });
  645. // 加载购物车
  646. const cartList = await this.getCartData();
  647. const validList = cartList.validList;
  648. const invalidList = cartList.invalidList;
  649. // 有效的购物车
  650. if (validList.length > 0) {
  651. for (let index in validList) {
  652. // 设置是否可减少(到底,不可减少)
  653. validList[index].numSub = validList[index].cartNum === 1;
  654. // 设置是否可添加(到顶,不可添加)
  655. const sku = validList[index].sku;
  656. validList[index].numAdd = sku && validList[index].count < sku.stock;
  657. // 设置为选中,并添加到 selectValue 数组中
  658. // why?库存不足时,可以引导选择该 SPU 对应的其它 SKU。而 invalidList 是 SPU 不存在或者库存彻底不足
  659. if (sku && sku.stock > 0) {
  660. validList[index].canChecked = true; // 是否可选中:是
  661. } else {
  662. validList[index].canChecked = false; // 是否可选中:否
  663. }
  664. }
  665. }
  666. this.$Cache
  667. this.$emit('cartList', validList);
  668. this.$set(this.cartList, 'valid', validList);
  669. console.log(this.cartList,888)
  670. this.switchSelect();
  671. // 无效的购物车
  672. this.$set(this.cartList, 'invalid', invalidList);
  673. // 标记加载结束
  674. this.canShow = true;
  675. uni.hideLoading();
  676. },
  677. /**
  678. * 获得“热门推荐”
  679. */
  680. getHostProduct: function() {
  681. ProductSpuApi.getSpuPage({
  682. recommendType: 'hot',
  683. pageNo: this.hotPage,
  684. pageSize: this.hotLimit
  685. }).then(res => {
  686. const good_list = res.data.list;
  687. this.hotPage++
  688. this.hotScroll = good_list.length < this.hotLimit
  689. // 设置营销活动
  690. const spuIds = good_list.map(item => item.id);
  691. if (spuIds.length > 0) {
  692. PromotionActivityApi.getActivityListBySpuIds(spuIds).then(res => {
  693. ProductUtil.setActivityList(good_list, res.data);
  694. this.hostProduct = this.hostProduct.concat(
  695. good_list) // 放在此处,避免 Vue 监控不到数组里的元素变化
  696. });
  697. }
  698. });
  699. },
  700. goodsOpen: function() {
  701. this.goodsHidden = !this.goodsHidden;
  702. },
  703. /**
  704. * 切换到管理
  705. */
  706. manage: function() {
  707. this.footerswitch = !this.footerswitch;
  708. this.switchSelect();
  709. },
  710. /**
  711. * 清空
  712. */
  713. unsetCart: function() {
  714. const ids = [];
  715. for (let i = 0, len = this.cartList.invalid.length; i < len; i++) {
  716. ids.push(this.cartList.invalid[i].id);
  717. }
  718. TradeCartApi.deleteCart(ids).then(res => {
  719. this.$util.Tips({
  720. title: '清除成功'
  721. });
  722. this.getCartList()
  723. }).catch(res => {});
  724. },
  725. fen2yuan(price) {
  726. return Util.fen2yuan(price)
  727. },
  728. inArray: function(search, array) {
  729. for (let i in array) {
  730. if (array[i] === search) {
  731. return true;
  732. }
  733. }
  734. return false;
  735. },
  736. },
  737. onReachBottom() {
  738. if (this.cartList.valid.length === 0 &&
  739. this.cartList.invalid.length === 0 &&
  740. this.hotPage != 1) {
  741. this.getHostProduct();
  742. }
  743. }
  744. }
  745. </script>
  746. <style scoped lang="scss">
  747. .invalidClas {
  748. position: relative;
  749. z-index: 111;
  750. top: -120rpx;
  751. }
  752. .invalidClasNO {
  753. position: static;
  754. margin-top: 15px;
  755. }
  756. .cartBox {
  757. // background-color: #fff;
  758. }
  759. .shoppingCart {
  760. /* #ifdef H5 */
  761. // padding-bottom: 0;
  762. // padding-bottom: constant(safe-area-inset-bottom);
  763. // padding-bottom: env(safe-area-inset-bottom);
  764. /* #endif */
  765. }
  766. .shoppingCart .labelNav {
  767. height: 178rpx;
  768. padding: 30rpx 30rpx 0 30rpx;
  769. font-size: 22rpx;
  770. color: #fff;
  771. position: fixed;
  772. left: 0;
  773. width: 100%;
  774. box-sizing: border-box;
  775. background-color: $theme-color;
  776. z-index: 5;
  777. top: 0;
  778. }
  779. .shoppingCart .labelNav .item .iconfont {
  780. font-size: 25rpx;
  781. margin-right: 10rpx;
  782. }
  783. .shoppingCart .nav {
  784. width: 92%;
  785. height: 90rpx;
  786. background-color: #fff;
  787. padding: 0 24rpx;
  788. -webkit-box-sizing: border-box;
  789. box-sizing: border-box;
  790. font-size: 28rpx;
  791. color: #282828;
  792. // position: fixed;
  793. left: 30rpx;
  794. z-index: 6;
  795. top: 94rpx;
  796. border-top-left-radius: 14rpx;
  797. border-top-right-radius: 14rpx;
  798. }
  799. .shoppingCart .nav .num {
  800. margin-left: 12rpx;
  801. }
  802. .shoppingCart .nav .administrate {
  803. font-size: 28rpx;
  804. color: #333333;
  805. }
  806. .shoppingCart .noCart {
  807. margin-top: 171rpx;
  808. background-color: #fff;
  809. padding-top: 0.1rpx;
  810. }
  811. .shoppingCart .noCart .pictrue {
  812. width: 414rpx;
  813. height: 336rpx;
  814. margin: 78rpx auto 56rpx auto;
  815. }
  816. .shoppingCart .noCart .pictrue image {
  817. width: 100%;
  818. height: 100%;
  819. }
  820. .shoppingCart .list {
  821. width: 100%;
  822. // margin-top: 178rpx;
  823. overflow: hidden;
  824. border-bottom-left-radius: 14rpx;
  825. border-bottom-right-radius: 14rpx;
  826. }
  827. .shoppingCart .list .item {
  828. padding: 24rpx;
  829. background-color: #fff;
  830. }
  831. .shoppingCart .list .item .picTxt {
  832. width: 582rpx;
  833. position: relative;
  834. }
  835. .shoppingCart .list .item .picTxt .pictrue {
  836. width: 160rpx;
  837. height: 160rpx;
  838. }
  839. .shoppingCart .list .item .picTxt .pictrue image {
  840. width: 100%;
  841. height: 100%;
  842. border-radius: 6rpx;
  843. }
  844. .shoppingCart .list .item .picTxt .text {
  845. width: 396rpx;
  846. font-size: 28rpx;
  847. color: #282828;
  848. }
  849. .shoppingCart .list .item .picTxt .text .reColor {
  850. color: #999;
  851. }
  852. .shoppingCart .list .item .picTxt .text .reElection {
  853. margin-top: 20rpx;
  854. }
  855. .shoppingCart .list .item .picTxt .text .reElection .title {
  856. font-size: 24rpx;
  857. }
  858. .shoppingCart .list .item .picTxt .text .reElection .reBnt {
  859. width: 120rpx;
  860. height: 46rpx;
  861. border-radius: 23rpx;
  862. font-size: 26rpx;
  863. }
  864. .shoppingCart .list .item .picTxt .text .infor {
  865. font-size: 24rpx;
  866. color: #999999;
  867. margin-top: 16rpx;
  868. }
  869. .shoppingCart .list .item .picTxt .text .money {
  870. font-size: 32rpx;
  871. color: #E93323;
  872. margin-top: 28rpx;
  873. font-weight: 600;
  874. }
  875. .shoppingCart .list .item .picTxt .carnum {
  876. height: 47rpx;
  877. position: absolute;
  878. bottom: 7rpx;
  879. right: 0;
  880. }
  881. .shoppingCart .list .item .picTxt .carnum view {
  882. border: 1rpx solid #a4a4a4;
  883. width: 66rpx;
  884. text-align: center;
  885. height: 100%;
  886. line-height: 44rpx;
  887. font-size: 28rpx;
  888. color: #a4a4a4;
  889. }
  890. .shoppingCart .list .item .picTxt .carnum .reduce {
  891. border-right: 0;
  892. border-radius: 3rpx 0 0 3rpx;
  893. border-radius: 22rpx 0rpx 0rpx 22rpx;
  894. font-size: 34rpx;
  895. line-height: 40rpx;
  896. }
  897. .shoppingCart .list .item .picTxt .carnum .reduce.on {
  898. border-color: #e3e3e3;
  899. color: #dedede;
  900. }
  901. .shoppingCart .list .item .picTxt .carnum .plus {
  902. border-left: 0;
  903. border-radius: 0 3rpx 3rpx 0;
  904. border-radius: 0rpx 22rpx 22rpx 0rpx;
  905. font-size: 34rpx;
  906. line-height: 40rpx;
  907. }
  908. .shoppingCart .list .item .picTxt .carnum .num {
  909. color: #282828;
  910. }
  911. .shoppingCart .invalidGoods {
  912. background-color: #fff;
  913. margin-top: 30rpx;
  914. /* #ifdef MP */
  915. margin-top: 140rpx;
  916. /* #endif */
  917. }
  918. .shoppingCart .invalidGoods .goodsNav {
  919. width: 100%;
  920. height: 90rpx;
  921. padding: 0 24rpx;
  922. box-sizing: border-box;
  923. font-size: 28rpx;
  924. color: #333333;
  925. }
  926. .shoppingCart .invalidGoods .goodsNav .iconfont {
  927. color: #424242;
  928. font-size: 28rpx;
  929. margin-right: 17rpx;
  930. }
  931. .shoppingCart .invalidGoods .goodsNav .del {
  932. font-size: 26rpx;
  933. color: #333;
  934. }
  935. .shoppingCart .invalidGoods .goodsNav .del .icon-shanchu1 {
  936. color: #333;
  937. font-size: 33rpx;
  938. vertical-align: -2rpx;
  939. margin-right: 8rpx;
  940. }
  941. .shoppingCart .invalidGoods .goodsList .item {
  942. padding: 24rpx;
  943. }
  944. .shoppingCart .invalidGoods .goodsList .picTxt {
  945. width: 576rpx;
  946. }
  947. .shoppingCart .invalidGoods .goodsList .item .invalid {
  948. font-size: 22rpx;
  949. color: #CCCCCC;
  950. height: 36rpx;
  951. border-radius: 3rpx;
  952. text-align: center;
  953. line-height: 36rpx;
  954. }
  955. .shoppingCart .invalidGoods .goodsList .item .pictrue {
  956. width: 160rpx;
  957. height: 160rpx;
  958. }
  959. .shoppingCart .invalidGoods .goodsList .item .pictrue image {
  960. width: 100%;
  961. height: 100%;
  962. border-radius: 6rpx;
  963. }
  964. .shoppingCart .invalidGoods .goodsList .item .text {
  965. width: 396rpx;
  966. font-size: 28rpx;
  967. color: #999;
  968. height: 140rpx;
  969. }
  970. .shoppingCart .invalidGoods .goodsList .item .text .name {
  971. width: 100%;
  972. }
  973. .shoppingCart .invalidGoods .goodsList .item .text .infor {
  974. font-size: 24rpx;
  975. }
  976. .shoppingCart .invalidGoods .goodsList .item .text .end {
  977. font-size: 26rpx;
  978. color: #bbb;
  979. }
  980. .footer {
  981. z-index: 9;
  982. width: 100%;
  983. height: 100rpx;
  984. background-color: #fff;
  985. position: fixed;
  986. padding: 0 24rpx;
  987. box-sizing: border-box;
  988. border-top: 1rpx solid #eee;
  989. // border-bottom: 1px solid #EEEEEE;
  990. /* #ifdef H5 */
  991. bottom: 98rpx;
  992. /* #endif */
  993. /* #ifdef MP */
  994. bottom: 0;
  995. /* #endif */
  996. /* #ifndef MP */
  997. // bottom: 98rpx;
  998. // bottom: calc(98rpx+ constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
  999. // bottom: calc(98rpx + env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
  1000. /* #endif */
  1001. }
  1002. .footer .checkAll {
  1003. font-size: 28rpx;
  1004. color: #282828;
  1005. margin-left: 14rpx;
  1006. }
  1007. .footer .money {
  1008. font-size: 30rpx;
  1009. .font-color {
  1010. font-weight: 600;
  1011. }
  1012. }
  1013. .footer .placeOrder {
  1014. color: #fff;
  1015. font-size: 30rpx;
  1016. width: 226rpx;
  1017. height: 70rpx;
  1018. border-radius: 50rpx;
  1019. text-align: center;
  1020. line-height: 70rpx;
  1021. margin-left: 22rpx;
  1022. }
  1023. .footer .button .bnt {
  1024. font-size: 28rpx;
  1025. color: #999;
  1026. border-radius: 50rpx;
  1027. border: 1px solid #999;
  1028. width: 160rpx;
  1029. height: 60rpx;
  1030. text-align: center;
  1031. line-height: 60rpx;
  1032. }
  1033. .footer .button form~form {
  1034. margin-left: 17rpx;
  1035. }
  1036. .uni-p-b-96 {
  1037. height: 96rpx;
  1038. }
  1039. </style>