Browse Source

add tid1878 index logic

tid1878
刘嘉炜 4 months ago
parent
commit
2800c5609c
  1. 47
      src/subpackage/mall/components/goods_item.vue
  2. 28
      src/subpackage/mall/components/index_classify_bar.vue
  3. 9
      src/subpackage/mall/components/index_search_bar.vue
  4. 23
      src/subpackage/mall/components/number_operate.vue
  5. 93
      src/subpackage/mall/components/specification_modal.vue
  6. 8
      src/subpackage/mall/js/api.js
  7. 10
      src/subpackage/mall/js/server.js
  8. 197
      src/subpackage/mall/pages/index.vue
  9. 15
      src/utils/util.js

47
src/subpackage/mall/components/goods_item.vue

@ -1,28 +1,58 @@
<template>
<view class="goods-item">
<image class="gi-img" mode="aspeceFill" :src="poster"></image>
<view class="gi-tit">克洛斯威羽毛球拍2支装C8正品碳素成人进攻型羽毛成人进攻型羽毛</view>
<view class="gi-tag">特价</view>
<view class="goods-item" @click="itemClick">
<image class="gi-img" mode="aspectFill" :src="poster"></image>
<view class="gi-tit">{{ name || '-' }}</view>
<!-- 特价标签 现在不做 -->
<!-- <view class="gi-tag">特价</view> -->
<view class="gi-bot-line">
<view class="gbl-price">
<view class="gp-num">
<text class="gn-symbol">¥</text>
59.9
{{ price || '0' }}
</view>
<view class="gp-unit">/2</view>
<!-- 单位: /2 -->
<!-- <view class="gp-unit">/2</view> -->
</view>
<view class="gbl-del-price">¥69.9</view>
<view class="gbl-add" @click="$emit('click:add')"></view>
<!-- product_spec_multi等于0是单规格 才显示划线价格 -->
<view class="gbl-del-price" v-if="isDelPrice">¥{{ delPrice || 0 }}</view>
<view class="gbl-add" @click.stop="$emit('click:add')"></view>
</view>
</view>
</template>
<script>
import { routeTo } from '@/utils/util';
export default {
props: {
id: {
type: Number,
default: 0
},
poster: {
type: String,
default: ''
},
name: {
type: String,
default: ''
},
price: {
type: Number,
default: 0
},
isDelPrice: {
type: Boolean,
default: false
},
delPrice: {
default: 0
}
},
methods: {
itemClick(){
let { id } = this;
routeTo(`/subpackage/mall/pages/goods_info/goods_info?product_id=${id}`,'nT')
}
}
}
@ -41,6 +71,7 @@ export default {
background: #fff;
.gi-img{
display: block;
width: 100%;
height: 340upx;
}
.gi-tit{

28
src/subpackage/mall/components/index_classify_bar.vue

@ -2,7 +2,13 @@
<view class="index-classify-bar">
<scroll-view enable-flex class="icb-sview" scroll-x>
<view class="is-ls">
<view class="il-item" v-for="i in 6" :key="i">户外装备</view>
<view
class="il-item"
:class="{ 'il-active': value === i }"
v-for="(e, i) in classifyLs"
:key="i"
@click="itemClick(i)"
>{{ e || '-' }}</view>
</view>
</scroll-view>
@ -15,7 +21,21 @@
<script>
export default {
props: {
classifyLs: {
type: Array,
default: ()=>[]
},
value: {
type: Number,
default: -1
}
},
methods: {
itemClick(idx){
this.$emit('input', idx)
}
}
}
</script>
@ -40,6 +60,10 @@ export default {
&+.il-item{
margin-left: 80upx;
}
&.il-active{
color: $mColor;
font-weight: 500;
}
}
}
}

9
src/subpackage/mall/components/index_search_bar.vue

@ -5,7 +5,7 @@
<input class="if-ipt" />
<view class="if-btn">搜索</view>
</view>
<view class="isb-box" @click="toShoppingCart">
<view class="isb-box" v-if="shoppingCart" @click="toShoppingCart">
<image class="ib-icon" src="/subpackage/mall/static/images/shopping_cart_333.png"></image>
<view class="ib-num">88</view>
</view>
@ -14,7 +14,12 @@
<script>
export default {
props: {
shoppingCart: {
type: Boolean,
default: false
}
}
}
</script>

23
src/subpackage/mall/components/number_operate.vue

@ -1,19 +1,30 @@
<template>
<view class="number-operate">
<view class="no-opt" @click="iptVal--"></view>
<input type="digit" class="no-ipt" v-model="iptVal" >
<view class="no-opt" @click="iptVal++"></view>
<view class="no-opt" @click="optBtn(-1)"></view>
<input type="digit" class="no-ipt" :value="value" @input="iptChange" >
<view class="no-opt" @click="optBtn(1)"></view>
</view>
</template>
<script>
export default {
data(){
return {
iptVal: '1'
props: {
value: {
type: Number,
default: 1
}
},
methods: {
optBtn(val){
let { value } = this;
this.$emit('input', val + value);
},
iptChange(e){
this.$emit('input', +e.detail.value);
}
}
}
</script>

93
src/subpackage/mall/components/specification_modal.vue

@ -2,13 +2,13 @@
<modal-box :is-show="isShow" @click:close="hide">
<view class="specification-modal">
<view class="sm-goods">
<image class="sg-img"></image>
<image v-if="initData.poster" class="sg-img" mode="aspectFill" :src="initData.poster"></image>
<view class="sg-right">
<view class="sr-name">克洛斯威羽毛球拍2支装C8正品碳素成人进攻型羽毛球克洛斯威羽毛球拍2支装C8正品碳素成人进攻型羽毛球</view>
<view class="sr-name">{{ initData.name || '-' }}</view>
<view class="sr-bottom">
<view class="sb-price">
<view class="sp-amount">¥59.9</view>
<view class="sp-unit">/2</view>
<view class="sp-amount">¥{{ initData.price || '0' }}</view>
<!-- <view class="sp-unit">/2</view> -->
</view>
<view class="sb-stock">库存6</view>
</view>
@ -16,17 +16,25 @@
</view>
<scroll-view class="sm-scroll" scroll-y>
<view class="ss-ls">
<view class="sl-item" v-for="i in 3" :key="i">
<view class="si-tit">规格</view>
<view class="sl-item" v-for="(e, i) in goodsSpecArr" :key="i">
<view class="si-tit">{{ e.name || '-' }}</view>
<view class="si-tags">
<view class="st-item" v-for="k in 10" :key="k">比赛专用</view>
<view
class="st-item"
:class="{ 'si-active': getActiveBol(e.id + '_' +k)}"
v-for="(k, j) in e.value"
:key="j"
@click="specItemClick(e, k)"
>
{{ k || '-' }}
</view>
</view>
</view>
</view>
</scroll-view>
<view class="num-bar">
<view class="nb-txt">购买数量</view>
<number-operate></number-operate>
<number-operate v-model="goodsNum"></number-operate>
</view>
<line-button>加入购物车</line-button>
</view>
@ -37,24 +45,83 @@
import modalBox from "./modal_box.vue";
import lineButton from "./line_button.vue";
import numberOperate from "./number_operate.vue";
import { routeTo, debounce, showLoad, hideLoad, showModal, showNone, tsRoute, jsonStr } from "@/utils/util.js";
import { MALL_API } from "../js/api";
import server from "../js/server";
export default {
components: {
modalBox,
lineButton,
numberOperate
},
computed: {
goodsSpecArr(){
let { initData } = this;
return initData?.specArr ?? []
}
},
data() {
return {
isShow: false,
goodsNum: 0,
initData: {
/**
* @param {Number} poster 海报
* @param {Number} id 商品id
* @param {String} name 商品名称
* @param {Number} price 商品价格
*
*/
},
specArr: [],
specSelectedArr: [],
}
},
methods: {
alert(){
specItemClick(e, k){
this.specSelectedArr.push({ pid: e?.id, val: k });
},
getActiveBol(val){
let { specSelectedArr } = this;
return specSelectedArr.some(item => {
let [ id, spec] = val.split('_');
return item.pid === id && item.val === spec;
});
},
alert(data){
this.isShow = true;
this.initData = data ?? {};
},
hide(){
this.isShow = false;
}
},
goodsCartAdd({ brand_id, id = '', nums = 1, spec_arr = [] }){
showLoad();
return server.post({
url: MALL_API.goodsCartAdd,
data: { brand_id, id, nums, spec_arr },
isDefaultGet: false,
})
.then(res => {
hideLoad();
let _data = res?.data || {};
if(_data.code === 0){
console.log('subpackage mall components specification goodsCartAdd res --->', _data);
showNone('加入购物车成功~');
return _data?.data;
}else{
return Promise.reject(_data);
}
})
.catch(err => {
hideLoad();
showModal({
title: '提示',
content: err.message || '操作失败!'
})
console.warn('subpackage mall components specification goodsCartAdd err --->', err);
})
},
}
}
</script>
@ -72,7 +139,6 @@ export default {
margin-right: 20upx;
width: 172upx;
height: 172upx;
background: skyblue;
}
.sg-right{
flex-grow: 1;
@ -133,6 +199,11 @@ export default {
border-radius: 10upx;
background: #F2F2F7;
@include flcw(24upx, 34upx, #333333);
&.si-active{
color: $mColor !important;
background: rgba($color: $mColor, $alpha: .14);
border: rgba($color: $mColor, $alpha: .2);
}
}
}
}

8
src/subpackage/mall/js/api.js

@ -0,0 +1,8 @@
import { ORIGIN } from '@/js/api';
export const MALL_API = {
homeShow:`${ORIGIN}/shop2/homeShow`, // 首页设置信息
goodsCartAdd:`${ORIGIN}/shop2/goodsCartAdd`, //购物车 - 添加商品
}
export default { ORIGIN, MALL_API };

10
src/subpackage/mall/js/server.js

@ -0,0 +1,10 @@
import { Server } from '@/js/server';
class Servers extends Server {
constructor(props){
super(props)
}
}
export default new Servers();

197
src/subpackage/mall/pages/index.vue

@ -1,42 +1,70 @@
<template>
<view class="mall-index">
<view class="mi-header">
<index-search-bar></index-search-bar>
<view class="mh-graph"></view>
<swiper class="mh-swiper" indicator-dots indicator-active-color='#009874'>
<swiper-item v-for="i in 3" :key=i>
<image class="ms-img" mode="aspectFill" :src="tImg"></image>
</swiper-item>
</swiper>
<index-search-bar v-if="isShow('搜索栏')"></index-search-bar>
<block v-if="isShow('轮播图')&&banner.length">
<view class="mh-graph"></view>
<swiper class="mh-swiper" autoplay indicator-dots indicator-active-color='#009874'>
<swiper-item v-for="(e, i) in banner" :key=i>
<image @click="bannerClick(e)" class="ms-img" mode="aspectFill" :src="e.banner_imgs"></image>
</swiper-item>
</swiper>
</block>
</view>
<!-- 分类tab -->
<view class="mi-tags" v-if="false">
<view class="mc-item" v-for="i in 7" :key='i'>
<image class="mi-img"></image>
<view class="mi-txt">健身训练</view>
<view class="mi-tags" v-if="isShow('首页菜单入口')&&getGridLsFor('home_menus').length">
<view class="mc-item" v-for="(e, i) in getGridLsFor('home_menus')" :key='i'>
<image class="mi-img" mode="aspectFit" :src="e.icon"></image>
<view class="mi-txt">{{ e.name || '-' }}</view>
</view>
</view>
<view class="mi-ad-pic" v-if="false">
<image class="map-img" mode="aspectFill" :src="tImg"></image>
<!-- 营销广告图 最多展示1个-->
<view class="mi-ad-pic" v-if="isShow('广告图')&&getGridLsFor('home_advert').length">
<block v-for="(e, i) in getGridLsFor('home_advert')" :key='i'>
<image
v-if="i <= 0"
class="map-img"
mode="aspectFill"
:src="e.image || ''"
@click="linkClick(e)"
></image>
</block>
</view>
<!-- 精选 -->
<view class="mi-choiceness" v-if="false">
<image class="mc-img"></image>
<image class="mc-img"></image>
<image class="mc-img"></image>
<view class="mi-choiceness" v-if="isShow('快捷入口宣传栏')&&getGridLsFor('home_quick').length">
<block v-for="(e, i) in getGridLsFor('home_quick')" :key='i'>
<image
v-if="i < showdata.home_quick.grid_count"
class="mc-img"
:src="e.image || ''"
@click="linkClick(e)"
></image>
</block>
</view>
<!-- 分类 -->
<index-classify-bar></index-classify-bar>
<view class="mi-classify-list">
<view class="mcl-item" v-for="i in 7" :key="i">
<goods-item
:poster="tImg"
@click:add="goodsItemAddBtn"
></goods-item>
<block v-if="isShow('商品分类模块')">
<index-classify-bar
:classify-ls="goodsCateClassify"
v-model="goodsCateIdx"
></index-classify-bar>
<view class="mi-classify-list">
<view class="mcl-item" v-for="(e, i) in goodsCateList" :key="i">
<goods-item
:poster="(e.product_imgs&&e.product_imgs[0]) || ''"
:name="e.product_name"
:price="e.product_price"
:id="e.id"
:is-del-price="e.product_spec_multi === 0&&e.product_price_show != 0"
:del-price="e.product_price_show || 0"
@click:add="goodsItemAddBtn(e)"
></goods-item>
</view>
</view>
</view>
</block>
<!-- 分类 -->
<spacification-modal
ref="spacificationModal"
></spacification-modal>
@ -48,6 +76,9 @@ import indexSearchBar from "../components/index_search_bar.vue";
import indexClassifyBar from "../components/index_classify_bar.vue";
import goodsItem from "../components/goods_item.vue";
import spacificationModal from "../components/specification_modal.vue";
import { routeTo, debounce, showLoad, hideLoad, showModal, showNone, tsRoute, jsonStr } from "@/utils/util.js";
import { MALL_API } from "../js/api";
import server from "../js/server";
export default {
components: {
indexSearchBar,
@ -55,15 +86,117 @@ export default {
goodsItem,
spacificationModal
},
computed: {
banner(){
return this.indexData?.banner ?? [];
},
showdata(){
return this.indexData?.showdata ?? {};
},
goodsCate(){
return this.indexData?.goodsCate ?? [];
},
goodsCateClassify(){
let { goodsCate } = this;
return goodsCate.map(item=> item?.product_cate_name ?? '');
},
goodsCateList(){
let { goodsCate, goodsCateIdx } = this;
if(goodsCateIdx < 0)return [];
return goodsCate?.[goodsCateIdx]?.cate_goods ?? []
}
},
data() {
return {
tImg: 'http://imgcdn.ouxuanzhineng.cn/upload/shopBanner/6b77330084b3732bad96250beeded038.png'
brand_id: '',
indexData: {},
goodsCateIdx: 0,
}
},
onLoad(options) {
let _bid = options?.brand_id ?? '';
this.brand_id = _bid;
this.getHomeData({ brand_id: _bid });
},
methods: {
goodsItemAddBtn(){
this.$refs.spacificationModal.alert();
}
getGridLsFor(key){
let { showdata } = this;
return showdata?.[key]?.grid_setting ?? [];
},
bannerClick(info){
// 20210823
// banner_jump=1/0(/)
// banner_jump_type=0/1(/)
// banner_jump_link
if(info&&info.banner_jump == 1){
if(info.banner_jump_type == 0)return tsRoute(info.banner_jump_link);
if(info.banner_jump_type == 1)return routeTo(`/pages/web_view/web_view?link=${jsonStr(info.banner_jump_link)}`,'nT');
}
},
linkClick(info) {
// 20210407
// type link_address
// link_type: 0->/1->
// link_status link_type
// link_type 0 type
// link_type == 0 link_address
if(info&&info.link_status == 1){
if(info.link_type == 0)return tsRoute(info.link_address);
if(info.link_type == 1)return routeTo(`/pages/web_view/web_view?link=${jsonStr(info.link_address)}`,'nT');
}
},
goodsItemAddBtn(e){
let { brand_id } = this;
//
// product_spec_multi 1
if(e.product_spec_multi == 1){
this.$refs.spacificationModal.alert({
poster: e?.product_imgs?.[0] ?? '',
name: e?.product_name ?? '',
price: e?.product_price ?? '',
specArr: e?.product_spec ?? [],
});
return
}
this.$refs?.spacificationModal?.goodsCartAdd({ brand_id, id: e?.id, });
},
//
isShow(val) {
let { showdata } = this;
let _home_mods = showdata?.home_mods || [];
let _isModsArr = _home_mods.filter(item => item.is_show === 1);
let _isModsNames = _isModsArr.map(item => item.name);
return _isModsNames.includes(val);
},
getHomeData({ brand_id }){
showLoad();
return server.post({
url: MALL_API.homeShow,
data: { brand_id },
isDefaultGet: false,
})
.then(res => {
hideLoad();
let _data = res?.data || {};
if(_data.code === 0){
console.log('subpackage mall pages index getHomeData res --->', _data);
return this.indexData = _data?.data ?? {};
}else{
return Promise.reject(_data);
}
})
.catch(err => {
hideLoad();
showModal({
title: '提示',
content: err.message || '加载失败!'
})
console.warn('subpackage mall pages index getHomeData err --->', err);
})
},
}
}
</script>
@ -119,7 +252,6 @@ export default {
height: 88upx;
border-radius: 50%;
overflow: hidden;
background: skyblue;
}
.mi-txt{
margin-top: 12upx;
@ -155,7 +287,6 @@ export default {
flex-shrink: 0;
width: 340upx;
height: 236upx;
background: skyblue;
}
}
.mi-classify-list{

15
src/utils/util.js

@ -50,6 +50,21 @@ export const routeTo = (url,type) => {
}
}
export const tsRoute = url => {
uni.navigateTo({
url,
fail: event =>{
console.warn(url, 'util nt 跳转失败---->', event);
uni.switchTab({
url,
fail: ele=>{
console.warn(url, 'util st 跳转失败---->', ele);
}
})
}
})
}
export function showNone(txt,duration=1500){
uni.hideToast();
uni.hideLoading();

Loading…
Cancel
Save