productWindow.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. <template>
  2. <view>
  3. <base-drawer mode="bottom" :visible="attr.cartAttr" :zIndex="12" :maskZIndex="11" background-color="transparent" mask maskClosable
  4. @close="closeAttr">
  5. <view class="scroll-content bg--w111-fff rd-t-40rpx">
  6. <view class="w-full pt-32">
  7. <view class="px-32 flex">
  8. <image class="w-180 h-180 rd-16rpx" :src="attr.productSelect.image"></image>
  9. <view class="pl-24">
  10. <baseMoney :money="attr.productSelect.price" symbolSize="32" integerSize="48"
  11. decimalSize="32" color="#FF7E00" weight></baseMoney>
  12. <view class="mt-20 fs-24 text--w111-999">库存:{{ attr.productSelect.stock }}</view>
  13. </view>
  14. </view>
  15. </view>
  16. <view class="px-32">
  17. <scroll-view scroll-y="true" style="max-height: 454rpx" >
  18. <view class="item mt-32" v-for="(item, indexw) in attr.productAttr" :key="indexw">
  19. <view class="fs-28 fw-500">{{ item.attr_name }}</view>
  20. <view class="flex-y-center flex-wrap">
  21. <view class="sku-item" :class="item.index === itemn.attr ? 'active' : ''"
  22. v-for="(itemn, indexn) in item.attr_value" @click="tapAttr(indexw, indexn)"
  23. :key="indexn">
  24. {{ itemn.attr }}
  25. </view>
  26. </view>
  27. </view>
  28. <view class="item mt-32">
  29. <view class="fs-28 fw-500">配送方式</view>
  30. <view class="flex-y-center flex-wrap">
  31. <view v-if="attr.deliveryType.includes('1')" :class="{ active: flag == 1 }" class="sku-item" @click="tapDelivery('1')">商城配送</view>
  32. <view v-if="attr.deliveryType.includes('2')" :class="{ active: flag == 2 }" class="sku-item" @click="tapDelivery('2')">门店自提</view>
  33. <view v-if="attr.deliveryType.includes('3')" :class="{ active: flag == 3 }" class="sku-item" @click="tapDelivery('3')">门店配送</view>
  34. </view>
  35. </view>
  36. <view class="address on1" v-if="flag == 1" @click="openAddress">
  37. <view class="acea-row row-middle">
  38. <view class="max-w-596 line1">{{addressInfo}}</view>
  39. <view class="iconfont icon-ic_rightarrow ml-8 fs-28"></view>
  40. </view>
  41. <view class="info">{{nameInfo}}</view>
  42. </view>
  43. <view class="address on2" v-if="flag == 3" @click="openStore">
  44. <view class="acea-row row-middle">
  45. <view class="max-w-596 line1">{{deliveryName}}</view>
  46. <view class="iconfont icon-ic_rightarrow ml-8 fs-28" v-if="attr.isType != 1"></view>
  47. </view>
  48. <view class="info">
  49. <text class="iconfont icon-ic_location51 fs-24 mr-10"></text>{{deliveryAddress}}
  50. </view>
  51. </view>
  52. <view class="address on3" v-if="flag == 2" @click="openStore">
  53. <view class="acea-row row-middle">
  54. <view class="max-w-596 line1">{{deliveryName}}</view>
  55. <view class="iconfont icon-ic_rightarrow ml-8 fs-28" v-if="attr.isType != 1"></view>
  56. </view>
  57. <view class="info">
  58. <text class="iconfont icon-ic_location51 fs-24 mr-10"></text>{{deliveryAddress}}
  59. </view>
  60. </view>
  61. </scroll-view>
  62. </view>
  63. <view class="flex-between-center mt-40 px-32">
  64. <view class="fs-28 fw-500">数量</view>
  65. <view class="flex-1 flex justify-end items-center">
  66. <text class="fs-22 text-primary">(最多可购买{{attr.productSelect.stock}}件)</text>
  67. <view class="flex-y-center pl-24">
  68. <text class="iconfont icon-ic_Reduce fs-24"
  69. :class="attr.productSelect.cart_num <= 1 ? 'text--w111-f5f5f5' : ''"
  70. @tap="CartNumDes"></text>
  71. <input type="number" v-model="attr.productSelect.cart_num"
  72. data-name="productSelect.cart_num" :always-embed="true" :adjust-position="true" cursor-spacing="30"
  73. @input="bindCode(attr.productSelect.cart_num)" class="w-88 h-44 rd-4rpx bg--w111-f5f5f5 fs-24 text-center mx-10"></input>
  74. <text class="iconfont icon-ic_increase fs-24" @tap="CartNumAdd"></text>
  75. </view>
  76. </view>
  77. </view>
  78. <view class="btn-box" v-show="attr.productSelect.stock == 0">
  79. <view class="w-full h-72 rd-40rpx flex-center fs-26 bg--w111-ccc text--w111-fff">已售罄</view>
  80. </view>
  81. <view class="btn-box flex-between-center" v-show="attr.productSelect.stock > 0">
  82. <view class="w-346 h-72 rd-40rpx flex-center fs-26 con_border text-primary"
  83. :class="{'disabled': cartButton == 0}"
  84. @tap="goCart(0)">加入购物车</view>
  85. <view class="w-346 h-72 rd-40rpx flex-center fs-26 bg-primary text--w111-fff" @tap="goCart(1)">立即下单</view>
  86. </view>
  87. </view>
  88. </base-drawer>
  89. <base-drawer mode="bottom" :visible="isStore" :zIndex="22" :maskZIndex="21" backgroundColor="transparent" @close="closeStore">
  90. <view class="product-window store">
  91. <view class="storeTitle">选择门店<text class="iconfont icon-guanbi5" @click="closeStore"></text></view>
  92. <scroll-view scroll-y="true" class="scroll-view">
  93. <view class="storeList">
  94. <view class="item" :class="active == index?'on':''" v-for="(item,index) in storeList" :key="index" @click="tapStore(index,item)">
  95. <view class="name line1">{{item.name}}</view>
  96. <view class="address acea-row row-between">
  97. <view class="iconfont icon-ic_location51"></view>
  98. <view class="info">{{item.address}}</view>
  99. </view>
  100. <view class="time acea-row row-middle">
  101. <view class="iconfont icon-icon_clock"></view>
  102. <view>营业时间:{{item.day_time}}</view>
  103. </view>
  104. <view class="iconfont icon-xuanzhong6" v-if="active == index"></view>
  105. </view>
  106. </view>
  107. </scroll-view>
  108. </view>
  109. </base-drawer>
  110. <addressWindow ref="addressWindow" :userId="userId" :pagesUrl="pagesUrl" :fromType="1" :address="address" @changeClose="changeClose" @OnChangeAddress="OnChangeAddress"></addressWindow>
  111. </view>
  112. </template>
  113. <script>
  114. import baseDrawer from '@/components/tui-drawer/tui-drawer.vue'
  115. import addressWindow from '@/components/addressWindow/index.vue'
  116. import { storeListApi } from '@/api/store.js'
  117. import { adminUserAddressList } from '@/api/admin.js'
  118. export default {
  119. name:'skuSelect',
  120. props:{
  121. userId:{
  122. type: [Number, String],
  123. default: 0
  124. },
  125. // 商品id
  126. productId: {
  127. type: Number,
  128. value: 0
  129. },
  130. attr: {
  131. type: Object,
  132. default: () => {}
  133. },
  134. cartButton:{
  135. type: Number,
  136. default: 1
  137. }
  138. },
  139. data(){
  140. return {
  141. flag: 1,
  142. nameInfo: '', //地址用户信息
  143. addressInfo: '', // 商城快递
  144. deliveryName:'', // 门店配送
  145. deliveryAddress:'',
  146. pagesUrl:'',
  147. address: {
  148. address: false
  149. },
  150. active:0,
  151. storeList: [],
  152. isStore: false
  153. }
  154. },
  155. watch: {
  156. 'attr.deliveryType'(newValue, oldValue) {
  157. if (JSON.stringify(newValue) != JSON.stringify(oldValue)) {
  158. if (newValue.length) {
  159. if(this.active<1){
  160. this.getList();
  161. }
  162. let num = 1;
  163. if (newValue.includes('1')) {
  164. num = '1';
  165. } else if (newValue.includes('2')) {
  166. num = '2';
  167. } else {
  168. num = '3';
  169. }
  170. this.flag = num
  171. this.$emit('deliveryFun',num);
  172. }
  173. }
  174. },
  175. },
  176. components:{
  177. baseDrawer,
  178. addressWindow
  179. },
  180. mounted() {
  181. uni.$on('refresh', (data) => {
  182. this.nameInfo = data.real_name+'\xa0\xa0'+data.phone
  183. this.addressInfo = data.address.province+'省'+data.address.city+data.address.district+data.address.street+data.detail
  184. this.$emit('onAddressId',data)
  185. });
  186. },
  187. methods:{
  188. goCart(type) {
  189. if(type == 0 && this.cartButton == 0) return
  190. if(this.attr.productSelect.stock == 0) return
  191. this.$emit('goCat',type);
  192. },
  193. bindCode: function(e) {
  194. this.$emit('iptCartNum', this.attr.productSelect.cart_num);
  195. },
  196. closeAttr: function() {
  197. this.$emit('myevent');
  198. },
  199. CartNumDes: function() {
  200. this.$emit('ChangeCartNum', false);
  201. },
  202. CartNumAdd: function() {
  203. this.$emit('ChangeCartNum', true);
  204. },
  205. tapAttr: function(indexw, indexn) {
  206. let that = this;
  207. that.$emit("attrVal", {
  208. indexw: indexw,
  209. indexn: indexn
  210. });
  211. this.$set(this.attr.productAttr[indexw], 'index', this.attr.productAttr[indexw].attr_values[indexn]);
  212. let value = that
  213. .getCheckedValue()
  214. .join(",");
  215. that.$emit("ChangeAttr", value);
  216. },
  217. //获取被选中属性;
  218. getCheckedValue: function() {
  219. let productAttr = this.attr.productAttr;
  220. let value = [];
  221. for (let i = 0; i < productAttr.length; i++) {
  222. for (let j = 0; j < productAttr[i].attr_values.length; j++) {
  223. if (productAttr[i].index === productAttr[i].attr_values[j]) {
  224. value.push(productAttr[i].attr_values[j]);
  225. }
  226. }
  227. }
  228. return value;
  229. },
  230. tapDelivery(value) {
  231. this.flag = value;
  232. this.active = 0;
  233. this.deliveryName = this.storeList[0].name;
  234. this.deliveryAddress = this.storeList[0].detailed_address+'\xa0';
  235. this.$emit('deliveryFun',value);
  236. this.$emit('onstoreId',this.storeList[0],value);
  237. },
  238. // 切换地址
  239. OnChangeAddress: function(e,row) {
  240. this.address.address = false;
  241. this.nameInfo = row.real_name+'\xa0\xa0'+row.phone
  242. this.addressInfo = row.province+'省'+row.city+row.district+row.street+row.detail
  243. this.$emit('onAddressId',row)
  244. },
  245. // 打开地址弹窗
  246. openAddress(){
  247. this.$refs.addressWindow.getAddressList();
  248. this.address.address = true;
  249. this.pagesUrl = '/pages/users/user_address/addClient'
  250. },
  251. // 关闭地址弹窗;
  252. changeClose: function() {
  253. this.$set(this.address, 'address', false);
  254. },
  255. getList: function(id) {
  256. let data = {
  257. // latitude: this.user_latitude || "", //纬度
  258. // longitude: this.user_longitude || "", //经度
  259. page: 1,
  260. limit: 100,
  261. product_id: this.productId,
  262. is_store:'', //查找所有门店列表
  263. // type: this.type == 'seckill'?1:0,
  264. // store_id: id?id:this.nearbyStore
  265. };
  266. storeListApi(data)
  267. .then(res => {
  268. let list = res.data.list.list;
  269. if(!id && list.length && this.attr && ((this.attr.deliveryType.indexOf('2') != -1 && this.attr.store_self_mention) || this.attr.deliveryType.indexOf('3') != -1)){
  270. this.isDelivery = true;
  271. if(this.$store.getters.isLogin){
  272. this.getAddressList()
  273. }
  274. }
  275. // 拆分自提门店列表和配送门店列表
  276. let selfStoreList = [];
  277. list.forEach(function(item,index){
  278. if(item.is_store === 1) selfStoreList.push(item);
  279. });
  280. this.storeList = this.flag==2?selfStoreList:list;
  281. this.selfStoreList = selfStoreList;//门店自提
  282. this.deliveryStoreList = list;//门店配送
  283. this.active = 0;
  284. this.deliveryName = this.storeList[0].name;
  285. this.deliveryAddress = this.storeList[0].detailed_address+'\xa0';
  286. this.$emit('onstoreId',this.storeList[0],this.flag);
  287. })
  288. .catch(err => {
  289. this.$util.Tips({
  290. title: err
  291. })
  292. });
  293. },
  294. // 配送地址
  295. getAddressList() {
  296. adminUserAddressList(this.userId, { page: 1, limit: 10 }).then(res=>{
  297. let data = res.data[0];
  298. if(res.data.length){
  299. this.nameInfo = data.real_name+'\xa0\xa0'+data.phone
  300. this.addressInfo = data.province+'省'+data.city+data.district+data.street+data.detail
  301. this.$emit('onAddressId',data)
  302. }else{
  303. this.addressInfo = '点击添加地址'
  304. }
  305. })
  306. },
  307. closeStore(){
  308. this.isStore = false;
  309. },
  310. openStore(){
  311. if(this.attr.isType != 1){
  312. this.isStore = true;
  313. }
  314. },
  315. // 切换门店
  316. tapStore(index,item){
  317. this.active = index;
  318. this.deliveryName = item.name;
  319. this.deliveryAddress = item.detailed_address+'\xa0';
  320. this.isStore = false;
  321. this.$emit('onstoreId',item,this.flag);
  322. },
  323. }
  324. }
  325. </script>
  326. <style lang="scss" scoped>
  327. .sku-item {
  328. height: 56rpx;
  329. line-height: 56rpx;
  330. border: 1rpx solid #F2F2F2;
  331. font-size: 24rpx;
  332. color: #333;
  333. padding: 0 44rpx;
  334. border-radius: 28rpx;
  335. margin: 24rpx 0 0 16rpx;
  336. background-color: #F2F2F2;
  337. word-break: break-all;
  338. }
  339. .active {
  340. color: $primary-admin;
  341. background: $light-primary-admin;
  342. border-color: $primary-admin;
  343. }
  344. .text-primary {
  345. color: $primary-admin;
  346. }
  347. .bg-primary{
  348. background: $primary-admin;
  349. }
  350. .con_border {
  351. border: 1rpx solid $primary-admin;
  352. }
  353. .btn-box{
  354. padding:0 20rpx calc(20rpx + env(safe-area-inset-bottom));
  355. margin: 78rpx auto 0;
  356. }
  357. .disabled{
  358. background-color: #ccc;
  359. color: #fff;
  360. border: 1rpx solid #ccc;
  361. }
  362. .scroll-content .address{
  363. width: 690rpx;
  364. background: #F5F5F5;
  365. padding: 24rpx 38rpx 24rpx 20rpx;
  366. margin: 28rpx auto;
  367. font-weight: 400;
  368. color: #333333;
  369. font-size: 28rpx;
  370. border-radius: 8rpx;
  371. position: relative;
  372. &::before{
  373. position: absolute;
  374. content: '';
  375. top:-12rpx;
  376. width: 0;
  377. height: 0;
  378. border-left: 14rpx solid transparent;
  379. border-right: 14rpx solid transparent;
  380. border-bottom: 12rpx solid #F5F5F5;
  381. }
  382. &.on1{
  383. &::before{
  384. left:64rpx;
  385. }
  386. }
  387. &.on2{
  388. &::before{
  389. left: 264rpx;
  390. }
  391. }
  392. &.on3{
  393. &::before{
  394. left:288rpx;
  395. }
  396. }
  397. .info{
  398. font-weight: 400;
  399. color: #999999;
  400. font-size: 24rpx;
  401. margin-top: 12rpx;
  402. .con{
  403. width: 416rpx;
  404. }
  405. }
  406. }
  407. .product-window {
  408. padding-bottom: constant(safe-area-inset-bottom); ///兼容 IOS<11.2/
  409. padding-bottom: env(safe-area-inset-bottom);///兼容 IOS>11.2/
  410. &.store{
  411. background-color: #F5F5F5;
  412. border-radius: 40rpx 40rpx 0 0;
  413. // transform: translate3d(0, 0, 0);
  414. // z-index: 102;
  415. // margin: 0;
  416. }
  417. .storeTitle{
  418. text-align: center;
  419. height: 100rpx;
  420. line-height: 100rpx;
  421. font-size: 32rpx;
  422. font-weight: 500;
  423. color: #282828;
  424. position: relative;
  425. .iconfont{
  426. position: absolute;
  427. font-size: 35rpx;
  428. right: 30rpx;
  429. }
  430. }
  431. .scroll-view{
  432. max-height: 690rpx;
  433. }
  434. .storeList{
  435. .item{
  436. width: 690rpx;
  437. background: #FFFFFF;
  438. border-radius: 12rpx;
  439. margin: 0 auto 20rpx auto;
  440. padding: 28rpx 30rpx;
  441. border: 1px solid #fff;
  442. position: relative;
  443. &.on{
  444. border-color: #2A7EFB;
  445. }
  446. .icon-xuanzhong6{
  447. position: absolute;
  448. right: -6rpx;
  449. bottom: -6rpx;
  450. color: var(--view-theme);
  451. font-size: 54rpx;
  452. }
  453. .name{
  454. font-weight: 500;
  455. color: #333333;
  456. font-size: 28rpx;
  457. }
  458. .time{
  459. font-weight: 400;
  460. color: #888888;
  461. font-size: 22rpx;
  462. margin-top: 15rpx;
  463. .iconfont{
  464. font-size: 20rpx;
  465. margin-right: 8rpx;
  466. }
  467. }
  468. .address{
  469. font-weight: 400;
  470. color: #888888;
  471. font-size: 22rpx;
  472. margin-top: 13rpx;
  473. .iconfont{
  474. font-size: 20rpx;
  475. margin-right: 8rpx;
  476. margin-top: 6rpx;
  477. }
  478. .info{
  479. width: 590rpx;
  480. line-height: 1.5;
  481. }
  482. }
  483. }
  484. }
  485. }
  486. /deep/.font-num{
  487. color: #2A7EFB !important;
  488. }
  489. /deep/.bg-color{
  490. background: #2A7EFB !important;
  491. }
  492. </style>