修改商品

msb_beta
ch 3 years ago
parent 019197fc61
commit c347578bef

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-04-02 09:54:53
* @LastEditors: ch
* @LastEditTime: 2022-04-06 10:15:32
* @LastEditTime: 2022-04-07 15:06:26
* @Description: file content
*/
import {ToAsyncAwait, MsbRequest} from '@/common/utils';
@ -26,3 +26,23 @@ export const ApiGetGoodsDetail = (params) =>
*/
export const ApiGetGoodsSkus = (params) =>
ToAsyncAwait(MsbRequest.get(`${BASE_URL}/app/product/sku`,params));
/**
* 获取首页分类导航
*/
export const ApiGetCategoryNav = () =>
ToAsyncAwait(MsbRequest.get(`${BASE_URL}/app/product/categoryNavigation`));
/**
* 获取一级分类列表
*/
export const ApiGetCategoryOneList = () =>
ToAsyncAwait(MsbRequest.get(`${BASE_URL}/app/productCategory/levelOne`));
/**
* 获取二级分类和商品列表
*/
export const ApiGetCategoryTwoAndGoods = (params) =>
ToAsyncAwait(MsbRequest.get(`${BASE_URL}/app/productCategory/listCategoryAndProduct/${params.categoryId}`));

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-17 17:42:32
* @LastEditors: ch
* @LastEditTime: 2022-04-07 10:26:32
* @LastEditTime: 2022-04-07 16:10:37
* @Description: 项目接口请求统一处理器返回一个需要token和不需要token的请求封装方法
*/
@ -53,8 +53,10 @@ MsbRequestTk.baseUrl = BASE_URL[ENV];
MsbRequestTk.use('request', (option) => {
const token = $store.state.token
if(!token){
uni.redirectTo({url:'/login'});
return Promise.reject({message:'请您先登录'});
const pages = getCurrentPages();
const page = pages[pages.length - 1];
page.$Router.replace({path : '/login',query:{h : page.__page__.path}})
return Promise.reject({message:'要先登录才能操作哦~'});
}else{
option.header = {...option.header, Authorization:$store.state.token}
return option;

@ -0,0 +1,58 @@
<!--
* @Author: ch
* @Date: 2022-03-20 16:45:27
* @LastEditors: ch
* @LastEditTime: 2022-04-07 18:24:25
* @Description: file content
-->
<template>
<view>
<UiGoodsGroup :listData="listData"></UiGoodsGroup>
<u-loadmore :status="loadingStatus" />
</view>
</template>
<script>
import {ApiGetGoodsList} from '@/common/api/goods';
import BsEmpty from './BsEmpty.vue';
import UiGoodsGroup from './UiGoodsGroup.vue';
export default {
components: { BsEmpty, UiGoodsGroup },
data(){
return {
loadingStatus : 'loading',
listData : [],
params : {
length : 10,
pageIndex : 1
}
}
},
mounted(){
this.getGoodsList();
},
methods : {
async getGoodsList(){
this.loadingStatus = 'loading';
const query = this.$Route.query;
const {error, result} = await ApiGetGoodsList({
...this.params
});
this.listData = this.listData.concat(result.records);
//
if(!result.records.length){
this.loadingStatus = 'nomore';
}
},
next(){
if(this.loadingStatus === 'nomore'){
return false
}
this.params.pageIndex++;
this.getGoodsList();
}
}
}
</script>
<style lang="scss" scoped>
</style>

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-20 13:11:55
* @LastEditors: ch
* @LastEditTime: 2022-03-29 15:04:36
* @LastEditTime: 2022-04-07 15:34:03
* @Description: file content
-->
<template>

@ -1,12 +1,12 @@
<!--
* @Author: ch
* @Date: 2022-03-20 16:45:27
* @Date: 2022-04-07 17:22:44
* @LastEditors: ch
* @LastEditTime: 2022-04-02 11:15:46
* @LastEditTime: 2022-04-07 18:30:02
* @Description: file content
-->
<template>
<view>
<view class="goods">
<view class="goods--column">
<view class="goods-item" v-for="item in goodsLeftData" :key="item.id"
@ -16,16 +16,16 @@
<view class="goods-item--pirce-box">
<view>
<text class="goods-item--pirce">{{item.startingPrice}}</text>
<text class="goods-item--original-pirce">50</text>
<!-- <text class="goods-item--original-pirce">50</text> -->
</view>
<view>
<!-- <view>
<image class="goods-item--icon" src='@/static/index/bz.png'></image>
</view> -->
</view>
</view>
<view class="goods-item--activity">
<!-- <view class="goods-item--activity">
<text class="goods-item--activity-title">秒杀</text>
<text class="goods-item--activity-desc">正在抢购中</text>
</view>
</view> -->
</view>
</view>
<view class="goods--column">
@ -36,79 +36,65 @@
<view class="goods-item--pirce-box">
<view>
<text class="goods-item--pirce">{{item.startingPrice}}</text>
<text class="goods-item--original-pirce">50</text>
<!-- <text class="goods-item--original-pirce">50</text> -->
</view>
<view>
<!-- <view>
<image class="goods-item--icon" src='@/static/index/bz.png'></image>
</view> -->
</view>
</view>
<view class="goods-item--activity">
<!-- <view class="goods-item--activity">
<text class="goods-item--activity-title">秒杀</text>
<text class="goods-item--activity-desc">正在抢购中</text>
</view> -->
</view>
</view>
</view>
</view>
<u-loadmore :status="loadingStatus" />
</view>
</template>
<script>
import {ApiGetGoodsList} from '@/common/api/goods';
export default {
data(){
return {
loadingStatus : 'loading',
goodsLeftData : [],
goodsRightData : [],
params : {
length : 10,
pageIndex : 1
}
}
},
mounted(){
this.getGoodsList();
props: {
listData : {
type : Array,
defalut : []
}
},
methods : {
async getGoodsList(){
this.loadingStatus = 'loading';
const {error, result} = await ApiGetGoodsList({
...this.params
});
const abs = this.goodsLeftData.length - this.goodsRightData.length;
watch : {
listData (data){
// const abs = this.goodsLeftData.length - this.goodsRightData.length;
const newLeftData = [];
const newRightData = [];
if(abs < 1){
result.records.forEach((item, index) => {
// if(abs < 1){
data.forEach((item, index) => {
if(index % 2 === 0){
newLeftData.push(item);
}else{
newRightData.push(item);
}
})
}else{
result.records.forEach((item, index) => {
if(index % 2 !== 0){
newLeftData.push(item);
}else{
newRightData.push(item);
}
})
}
this.goodsLeftData = this.goodsLeftData.concat(newLeftData);
this.goodsRightData = this.goodsRightData.concat(newRightData);
//
if(!result.records.length){
this.loadingStatus = 'nomore';
// }else{
// data.forEach((item, index) => {
// if(index % 2 !== 0){
// newLeftData.push(item);
// }else{
// newRightData.push(item);
// }
// })
// }
this.goodsLeftData = newLeftData; // this.goodsLeftData.concat(newLeftData);
this.goodsRightData = newRightData; //this.goodsRightData.concat(newRightData);
}
},
next(){
if(this.loadingStatus === 'nomore'){
return false
}
this.params.pageIndex++;
this.getGoodsList();
}
mounted(){
},
methods : {
}
}
</script>

@ -2,12 +2,12 @@
* @Author: ch
* @Date: 2022-03-25 10:11:37
* @LastEditors: ch
* @LastEditTime: 2022-03-31 15:23:53
* @LastEditTime: 2022-04-07 15:17:28
* @Description: file content
-->
<template>
<view class="header">
<image class="header--back" src="@/static/search/arrow.png" @click="$Router.back()"></image>
<image class="header--back" v-if="back" src="@/static/search/arrow.png" @click="$Router.back()"></image>
<slot name="custom">
<text class="header--title">{{title}}</text>
<view class="header--operation">
@ -22,6 +22,10 @@ export default {
title : {
type : String,
default : ''
},
back : {
type : Boolean,
default : true
}
}
}

File diff suppressed because it is too large Load Diff

@ -1,450 +0,0 @@
<!-- 步进器 -->
<template>
<view class="number-box">
<view class="u-icon-minus" @touchstart.prevent="btnTouchStart('minus')" @touchend.stop.prevent="clearTimer" :class="{ 'u-icon-disabled': disabled || inputVal <= min }"
:style="{
background: bgColor,
height: inputHeight + 'rpx',
color: color,
fontSize: size + 'rpx',
minHeight: '1.4em'
}">
<view :style="'font-size:'+(Number(size)+10)+'rpx'" class="num-btn"></view>
</view>
<input :disabled="disabledInput || disabled" :cursor-spacing="getCursorSpacing" :class="{ 'u-input-disabled': disabled }"
v-model="inputVal" class="u-number-input" @blur="onBlur"
type="number" :style="{
color: color,
fontSize: size + 'rpx',
background: bgColor,
height: inputHeight + 'rpx',
width: inputWidth + 'rpx',
}" />
<view class="u-icon-plus" @touchstart.prevent="btnTouchStart('plus')" @touchend.stop.prevent="clearTimer" :class="{ 'u-icon-disabled': disabled || inputVal >= max }"
:style="{
background: bgColor,
height: inputHeight + 'rpx',
color: color,
fontSize: size + 'rpx',
minHeight: '1.4em',
}">
<view :style="'font-size:'+(Number(size)+10)+'rpx'" class="num-btn"></view>
</view>
</view>
</template>
<script>
/**
* numberBox 步进器
* @description 该组件一般用于商城购物选择物品数量的场景注意该输入框只能输入大于或等于0的整数不支持小数输入
* @tutorial https://www.uviewui.com/components/numberBox.html
* @property {Number} value 输入框初始值默认1
* @property {String} bg-color 输入框和按钮的背景颜色默认#F2F3F5
* @property {Number} min 用户可输入的最小值默认0
* @property {Number} max 用户可输入的最大值默认99999
* @property {Number} step 步长每次加或减的值默认1
* @property {Number} stepFirst 步进值首次增加或最后减的值(默认step值和一致
* @property {Boolean} disabled 是否禁用操作禁用后无法加减或手动修改输入框的值默认false
* @property {Boolean} disabled-input 是否禁止输入框手动输入值默认false
* @property {Boolean} positive-integer 是否只能输入正整数默认true
* @property {String | Number} size 输入框文字和按钮字体大小单位rpx默认26
* @property {String} color 输入框文字和加减按钮图标的颜色默认#323233
* @property {String | Number} input-width 输入框宽度单位rpx默认80
* @property {String | Number} input-height 输入框和按钮的高度单位rpx默认50
* @property {String | Number} index 事件回调时用以区分当前发生变化的是哪个输入框
* @property {Boolean} long-press 是否开启长按连续递增或递减(默认true)
* @property {String | Number} press-time 开启长按触发后每触发一次需要多久单位ms(默认250)
* @property {String | Number} cursor-spacing 指定光标于键盘的距离避免键盘遮挡输入框单位rpx默认200
* @event {Function} change 输入框内容发生变化时触发对象形式
* @event {Function} blur 输入框失去焦点时触发对象形式
* @event {Function} minus 点击减少按钮时触发(按钮可点击情况下)对象形式
* @event {Function} plus 点击增加按钮时触发(按钮可点击情况下)对象形式
* @example <number-box :min="1" :max="100"></number-box>
*/
export default {
name: "NumberBox",
emits: ["update:modelValue", "input", "change", "blur", "plus", "minus"],
props: {
//
value: {
type: Number,
default: 1
},
modelValue: {
type: Number,
default: 1
},
//
bgColor: {
type: String,
default: '#F2F3F5'
},
//
min: {
type: Number,
default: 0
},
//
max: {
type: Number,
default: 99999
},
//
step: {
type: Number,
default: 1
},
//
stepFirst: {
type: Number,
default: 0
},
// step
stepStrictly: {
type: Boolean,
default: false
},
//
disabled: {
type: Boolean,
default: false
},
// inputrpx
size: {
type: [Number, String],
default: 26
},
//
color: {
type: String,
default: '#323233'
},
// inputrpx
inputWidth: {
type: [Number, String],
default: 80
},
// inputrpx
inputHeight: {
type: [Number, String],
default: 50
},
// index使numberbox使forindex
index: {
type: [Number, String],
default: ''
},
// disabledOR
// disabledfalsedisabledInputtrue
disabledInput: {
type: Boolean,
default: false
},
//
cursorSpacing: {
type: [Number, String],
default: 100
},
//
longPress: {
type: Boolean,
default: true
},
//
pressTime: {
type: [Number, String],
default: 250
},
// 0()
positiveInteger: {
type: Boolean,
default: true
}
},
watch: {
value(v1, v2) {
// valueinputVal
if(!this.changeFromInner) {
this.inputVal = v1;
// inputValthis.handleChange()changeFromInnertrue
// this.$nextTick
// changeFromInnerfalse
this.$nextTick(function(){
this.changeFromInner = false;
})
}
},
modelValue(v1, v2) {
// valueinputVal
if(!this.changeFromInner) {
this.inputVal = v1;
// inputValthis.handleChange()changeFromInnertrue
// this.$nextTick
// changeFromInnerfalse
this.$nextTick(function(){
this.changeFromInner = false;
})
}
},
inputVal(v1, v2) {
//
if (v1 == '') return;
let value = 0;
// minmax使
let tmp = this.isNumber(v1);
if (tmp && v1 >= this.min && v1 <= this.max) value = v1;
else value = v2;
// 0
if(this.positiveInteger) {
// 0
if(v1 < 0 || String(v1).indexOf('.') !== -1) {
value = v2;
// input使$nextTick
this.$nextTick(() => {
this.inputVal = v2;
})
}
}
// change
this.handleChange(value, 'change');
},
min(v1){
if(v1 !== undefined && v1!="" && this.getValue() < v1){
this.$emit("input",v1);
}
},
max(v1){
if(v1 !== undefined && v1!="" && this.getValue() > v1){
this.$emit("input",v1);
}
}
},
data() {
return {
inputVal: 1, // 使propsvalueprops
timer: null, //
changeFromInner: false, //
innerChangeTimer: null, //
};
},
created() {
this.inputVal = Number(this.getValue());
},
computed: {
getCursorSpacing() {
// px
return Number(uni.upx2px(this.cursorSpacing));
}
},
methods: {
getValue(){
// #ifndef VUE3
return this.value;
// #endif
// #ifdef VUE3
return this.modelValue;
// #endif
},
// 退
btnTouchStart(callback) {
// clearTimer
this[callback]();
//
if (!this.longPress) return;
clearInterval(this.timer); //
this.timer = null;
this.timer = setInterval(() => {
//
this[callback]();
}, this.pressTime);
},
clearTimer() {
this.$nextTick(() => {
clearInterval(this.timer);
this.timer = null;
})
},
minus() {
this.computeVal('minus');
},
plus() {
this.computeVal('plus');
},
//
calcPlus(num1, num2) {
let baseNum, baseNum1, baseNum2;
try {
baseNum1 = num1.toString().split('.')[1].length;
} catch (e) {
baseNum1 = 0;
}
try {
baseNum2 = num2.toString().split('.')[1].length;
} catch (e) {
baseNum2 = 0;
}
baseNum = Math.pow(10, Math.max(baseNum1, baseNum2));
let precision = baseNum1 >= baseNum2 ? baseNum1 : baseNum2; //
return ((num1 * baseNum + num2 * baseNum) / baseNum).toFixed(precision);
},
//
calcMinus(num1, num2) {
let baseNum, baseNum1, baseNum2;
try {
baseNum1 = num1.toString().split('.')[1].length;
} catch (e) {
baseNum1 = 0;
}
try {
baseNum2 = num2.toString().split('.')[1].length;
} catch (e) {
baseNum2 = 0;
}
baseNum = Math.pow(10, Math.max(baseNum1, baseNum2));
let precision = baseNum1 >= baseNum2 ? baseNum1 : baseNum2;
return ((num1 * baseNum - num2 * baseNum) / baseNum).toFixed(precision);
},
computeVal(type) {
uni.hideKeyboard();
if (this.disabled) return;
let value = 0;
// stepFirst
//
if (type === 'minus') {
if(this.stepFirst > 0 && this.inputVal == this.stepFirst){
value = this.min;
}else{
value = this.calcMinus(this.inputVal, this.step);
}
} else if (type === 'plus') {
if(this.stepFirst > 0 && this.inputVal < this.stepFirst){
value = this.stepFirst;
}else{
value = this.calcPlus(this.inputVal, this.step);
}
}
if(this.stepStrictly){
let strictly = value % this.step;
if(strictly > 0){
value -= strictly;
}
}
if (value > this.max ) {
value = this.max;
}else if (value < this.min) {
value = this.min;
}
// stepFirst
this.inputVal = value;
this.handleChange(value, type);
},
//
onBlur(event) {
let val = 0;
let value = event.detail.value;
// 0-90min
// props min0
if (!/(^\d+$)/.test(value) || value[0] == 0) val = this.min;
val = +value;
// stepFirst
if(this.stepFirst > 0 && this.inputVal < this.stepFirst && this.inputVal>0){
val = this.stepFirst;
}
// stepFirst
if(this.stepStrictly){
let strictly = val % this.step;
if(strictly > 0){
val -= strictly;
}
}
if (val > this.max) {
val = this.max;
} else if (val < this.min) {
val = this.min;
}
this.$nextTick(() => {
this.inputVal = val;
})
this.handleChange(val, 'blur');
},
handleChange(value, type) {
if (this.disabled) return;
//
if(this.innerChangeTimer) {
clearTimeout(this.innerChangeTimer);
this.innerChangeTimer = null;
}
// inputv-model
this.changeFromInner = true;
// changeFromInner
// value
this.innerChangeTimer = setTimeout(() => {
this.changeFromInner = false;
}, 150);
this.$emit('input', Number(value));
this.$emit("update:modelValue", Number(value));
this.$emit(type, {
// Number
value: Number(value),
index: this.index
})
},
/**
* 验证十进制数字
*/
isNumber(value) {
return /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value)
}
}
};
</script>
<style lang="scss" scoped>
.number-box {
display: inline-flex;
align-items: center;
}
.u-number-input {
position: relative;
text-align: center;
padding: 0;
margin: 0 6rpx;
display: flex;
align-items: center;
justify-content: center;
}
.u-icon-plus,
.u-icon-minus {
width: 60rpx;
display: flex;
justify-content: center;
align-items: center;
}
.u-icon-plus {
border-radius: 0 8rpx 8rpx 0;
}
.u-icon-minus {
border-radius: 8rpx 0 0 8rpx;
}
.u-icon-disabled {
color: #c8c9cc !important;
background: #f7f8fa !important;
}
.u-input-disabled {
color: #c8c9cc !important;
background-color: #f2f3f5 !important;
}
.num-btn{
font-weight:550;
position: relative;
top:-4rpx;
}
</style>

@ -47,13 +47,6 @@
"navigationBarTitleText": "uni-app"
}
},
{
"path": "pages/goods/detail",
"style": {
"navigationStyle" : "custom",
"navigationBarTitleText": "uni-app"
}
},
{
"path": "pages/goods/detail/index",
"aliasPath" : "/goodsDetail",

@ -54,7 +54,7 @@
</view>
<template v-if="!isLoading">
<view class="title">为您推荐</view>
<BsGoodsGroup></BsGoodsGroup>
<BsChoiceGoods></BsChoiceGoods>
</template>
<!-- 底部操作栏 -->
@ -91,7 +91,7 @@
<script>import { Debounce } from '@/common/utils';
import BsEmpty from '@/components/BsEmpty.vue';
import BsGoodsGroup from '@/components/BsGoodsGroup.vue';
import BsChoiceGoods from '@/components/BsChoiceGoods.vue';
import UiPageHeader from '../../components/UiPageHeader.vue';
import {ApiGetCartList, ApiPutCartNum, ApiDeleteCartGoods} from '@/common/api/cart';
@ -100,7 +100,7 @@ const CartIdsIndex = 'CartIds'
export default {
components: {
BsEmpty,
BsGoodsGroup,
BsChoiceGoods,
UiPageHeader
},
data() {

@ -3,7 +3,7 @@
components: { UiCell },: ch
* @Date: 2019-08-22 19:41:20
* @LastEditors: ch
* @LastEditTime: 2022-03-30 18:47:31
* @LastEditTime: 2022-04-07 11:43:37
* @Description: file content
-->
<template>
@ -76,7 +76,7 @@ export default {
async getUserInfo(){
const {error, result} = await ApiGetCurrentUser();
if(error){
uin.$u.totas(error.message);
uni.$u.toast(error.message);
return false;
}
this.userInfo = result;

@ -1,44 +1,52 @@
<template>
<view class="container">
<!-- 搜索框 -->
<!-- <search tips="搜索商品" @event="$navTo('pages/search/index')" /> -->
<view class="cate-content" v-if="list.length > 0">
<UiPageHeader :back="false" class="search">
<u--input slot="custom" class="search--input" prefixIconStyle="font-size:48rpx;color:#ccc"
prefixIcon="search" placeholderClass="search--input__placeholder" clearable
placeholder="请输入您想要搜索的商品名称"
@focus="$Router.push('/search')"/>
</UiPageHeader>
<view class="cate-content" v-if="categoryData.length > 0">
<!-- 左侧 一级分类 -->
<scroll-view class="cate-left" :scroll-y="true">
<text class="type-nav" :class="{ selected: curIndex == index }"
v-for="(item, index) in list" @click="handleSelectNav(index)"
v-for="(item, index) in categoryData" @click="handleSelectNav(index)"
:key="index" >{{ item.name }}</text>
</scroll-view>
<!-- 右侧 二级分类 -->
<scroll-view class="cate-right" :scroll-top="scrollTop" :scroll-y="true">
<!-- <image class="cate-tow-img" :src="list[curIndex].image ? list[curIndex].image.preview_url : ''"></image> -->
<scroll-view class="cate-right" @scrolltolower="reachBottom" :scroll-top="scrollTop" :scroll-y="true">
<image class="cate-tow-img" src="@/static/goods/category_banner.jpg"></image>
<view v-for="(item, idx) in list[curIndex].productList"
:key="idx" @click="onTargetGoodsList(item.category_id)">
<view class="cate-tow-group">
<!-- <view @click="onTargetGoodsList(item.id)"> -->
<view class="cate-tow-group" :class="idx === categoryData[curIndex].children.length - 1 ? 'cate-tow-group__last' :''"
v-for="(item, idx) in categoryData[curIndex].children" :key="idx">
<text class="cate-tow-group--title">{{item.name}}</text>
<view class="cate-tow-group--item" v-for="i in item.productList" :key="i.id">
<view class="cate-tow-group--item" v-for="i in item.productList" :key="i.id"
@click="$Router.push(`/goodsDetail?id=${i.id}`)">
<image class="cate-tow-group--img" mode="scaleToFill"
:src="i.image.preview_url"></image>
:src="i.mainPicture"></image>
<text class="cate-tow-group--name">{{i.name}}</text>
</view>
</view>
</view>
<!-- </view> -->
<BsEmpty v-if="!categoryData[curIndex].children.length && !categoryData[curIndex].isLoading" />
<u-loadmore status="loading" v-if="categoryData[curIndex].isLoading" />
</scroll-view>
</view>
<BsEmpty v-if="!list.length" :isLoading="isLoading" />
<BsEmpty v-if="!categoryData.length && !isLoading" />
<u-loadmore status="loading" v-if="isLoading" />
</view>
</template>
<script>
import categoryData from "@/mock/category.json";
import {ApiGetCategoryOneList, ApiGetCategoryTwoAndGoods} from '@/common/api/goods';
import BsEmpty from "@/components/BsEmpty";
import UiPageHeader from '../../components/UiPageHeader.vue';
export default {
components: { BsEmpty },
components: { BsEmpty, UiPageHeader },
data() {
return {
//
@ -46,20 +54,20 @@ export default {
//
scrollTop: 0,
//
list: [],
categoryData: [],
//
isLoading: true,
};
},
onLoad() {
//
this.getPageData();
this.getCategoryData();
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
this.getPageData();
// this.getCategoryData();
},
methods: {
@ -68,14 +76,26 @@ export default {
this.curIndex = index;
this.scrollTop = 0;
},
reachBottom(){
if(this.curIndex >= this.categoryData.length){
return false
}
this.handleSelectNav(this.curIndex+1);
},
/**
* 获取页面数据
* 获取分类数据
*/
getPageData() {
async getCategoryData() {
this.isLoading = true;
//
this.initCategory(categoryData.data.list);
const {error, result } = await ApiGetCategoryOneList();
this.categoryData = result.map((item) => {
item.children = [];
item.isLoading = true;
this.getTwoCategoryData(item);
return item;
});
this.isLoading = false;
},
@ -83,9 +103,11 @@ export default {
* 初始化分类列表数据
* @param {Object} result
*/
initCategory(list) {
this.list = list;
},
async getTwoCategoryData(item) {
const {error, result} = await ApiGetCategoryTwoAndGoods({categoryId : item.id});
this.$set(item, 'children', result);
this.$set(item, 'isLoading', false);
}
},
};
</script>
@ -95,9 +117,24 @@ page {
}
</style>
<style lang="scss" scoped>
.search{
padding: 0 30rpx;
}
.search--input{
display: block;
height: 70rpx;
border:none;
box-sizing: border-box;
background: #F8F8F8;
&__placeholder{
font-size: 26rpx;
color: #666;
}
}
.cate-content {
background: #fff;
height: calc(100vh - 120rpx);
height: calc(100vh - 220rpx);
display: flex;
}
@ -110,8 +147,9 @@ page {
.cate-right {
height: 100%;
padding: 40rpx 0;
padding: 40rpx 0 0;
overflow: hidden;
box-sizing: border-box;
}
.type-nav {
display: block;
@ -157,10 +195,20 @@ page {
}
&--name{
display: block;
width: 130rpx;
text-align: center;
font-size: 24rpx;
line-height: 36rpx;
margin: 10rpx 0 40rpx;
color: #333;
display: -webkit-box;
/*! autoprefixer: off */
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
&__last{
padding-bottom: 200rpx;
}
}

@ -1,162 +0,0 @@
<template>
<!-- 商品评价 -->
<view v-if="!isLoading && list.length" class="goods-comment m-top20">
<view class="item-title dis-flex">
<view class="block-left flex-box">
商品评价 (<text class="total">{{ total }}</text>)
</view>
<view class="block-right">
<text @click="onTargetToComment" class="show-more col-9">查看更多</text>
<text class="iconfont icon-arrow-right"></text>
</view>
</view>
<!-- 评论列表 -->
<view class="comment-list">
<view class="comment-item" v-for="(item, index) in list" :key="index">
<view class="comment-item_row dis-flex flex-y-center">
<view class="user-info dis-flex flex-y-center">
<avatar-image class="user-avatar" :url="item.user.avatar_url" :width="50" />
<text class="user-name">{{ item.user.nick_name }}</text>
</view>
<!-- 评星 -->
<view class="star-rating">
<u-rate active-color="#f4a213" :current="rates[item.score]" :disabled="true" />
</view>
</view>
<view class="item-content m-top20">
<text class="f-26 twoline-hide">{{ item.content }}</text>
</view>
<view class="comment-time">{{ item.create_time }}</view>
</view>
</view>
</view>
</template>
<script>
import AvatarImage from '@/components/avatar-image'
import * as CommentApi from '@/api/comment'
export default {
components: {
AvatarImage
},
props: {
// ID
goodsId: {
type: Number,
default: null
},
// 2
limit: {
type: Number,
default: 2
}
},
data() {
return {
//
isLoading: true,
//
rates: { 10: 5, 20: 3, 30: 1 },
//
list: [],
//
total: 0
}
},
created() {
//
this.getCommentList()
},
methods: {
//
getCommentList() {
const app = this
app.isLoading = true
CommentApi.listRows(app.goodsId, app.limit)
.then(result => {
app.list = result.data.list
app.total = result.data.total
})
.catch(err => err)
.finally(() => app.isLoading = false)
},
//
onTargetToComment() {
const app = this
app.$navTo('pages/comment/index', { goodsId: app.goodsId })
}
}
}
</script>
<style lang="scss" scoped>
.goods-comment {
padding: 20rpx 30rpx;
background-color: #fff;
}
.item-title {
font-size: 28rpx;
margin-bottom: 25rpx;
.total {
margin: 0 4rpx;
}
.show-more {
margin-right: 8rpx;
font-size: 24rpx;
}
}
.comment-item {
padding: 15rpx 5rpx;
margin-bottom: 10rpx;
border-bottom: 1rpx solid #f5f5f5;
&:last-child {
margin-bottom: 0;
border-bottom: none;
}
.comment-item_row {
margin-bottom: 10rpx;
}
}
.user-info {
margin-right: 15rpx;
.user-avatar {
width: 50rpx;
height: 50rpx;
border-radius: 50%;
margin-right: 10rpx;
}
.user-name {
font-size: 24rpx;
}
}
.item-content {
color: #333;
margin: 16rpx 0;
max-height: 76rpx;
line-height: 38rpx;
}
.comment-time {
font-size: 24rpx;
color: #999;
margin-top: 10rpx;
}
</style>

@ -1,157 +0,0 @@
<template>
<view v-if="list.length" class="service-wrapper">
<!-- 服务简述 -->
<view class="service-simple" @click="handlePopup">
<view class="s-list">
<view class="s-item" v-for="(item, index) in list" :key="index">
<text class="item-icon iconfont icon-fuwu"></text>
<text class="item-val">{{ item.name }}</text>
</view>
</view>
<!-- 扩展箭头 -->
<view class="s-arrow f-26 col-9 t-r">
<text class="iconfont icon-arrow-right"></text>
</view>
</view>
<!-- 详情内容弹窗 -->
<u-popup v-model="showPopup" mode="bottom" :closeable="true" :border-radius="26">
<view class="service-content">
<view class="title">服务</view>
<scroll-view class="content-scroll" :scroll-y="true">
<view class="s-list clearfix">
<view class="s-item" v-for="(item, index) in list" :key="index">
<text class="item-icon iconfont icon-fuwu"></text>
<view class="item-val">{{ item.name }}</view>
<view class="item-summary">{{ item.summary }}</view>
</view>
</view>
</scroll-view>
</view>
</u-popup>
</view>
</template>
<script>
export default {
props: {
// ID
goodsId: {
type: Number,
default: null
}
},
data() {
return {
//
isLoading: true,
//
showPopup: false,
//
list: []
}
},
created() {
//
this.getServiceList()
},
methods: {
//
getServiceList() {
const app = this
app.isLoading = true
// ServiceApi.list(app.goodsId)
// .then(result => app.list = result.data.list)
// .finally(() => app.isLoading = false)
},
//
handlePopup() {
this.showPopup = !this.showPopup
}
}
}
</script>
<style lang="scss" scoped>
.service-wrapper {
min-height: 24rpx;
margin-bottom: -24rpx;
}
//
.service-simple {
padding: 24rpx 30rpx;
display: flex;
align-items: center;
.s-list {
flex: 1;
margin-left: -15rpx;
}
.s-item {
float: left;
font-size: 26rpx;
margin: 8rpx 15rpx;
.item-icon {
color: #FA2209;
}
.item-val {
margin-left: 12rpx;
}
}
}
//
.service-content {
padding: 24rpx;
.title {
font-size: 30rpx;
margin-bottom: 50rpx;
font-weight: bold;
text-align: center;
}
.content-scroll {
min-height: 400rpx;
max-height: 760rpx;
}
.s-list {
padding: 0 30rpx 0 80rpx;
}
.s-item {
position: relative;
margin-bottom: 60rpx;
.item-icon {
position: absolute;
top: 6rpx;
left: -50rpx;
color: #FA2209;
}
.item-val {
font-size: 28rpx;
}
.item-summary {
font-size: 26rpx;
margin-top: 20rpx;
color: #6d6d6d;
}
}
}
</style>

@ -1,179 +0,0 @@
<template>
<goods-sku-popup :value="value" @input="onChangeValue" border-radius="20" :localdata="goodsInfo" :mode="skuMode"
:maskCloseAble="true" @open="openSkuPopup" @close="closeSkuPopup" @add-cart="addCart" @buy-now="buyNow"
buyNowText="立即购买" />
</template>
<script>
// import { setCartTotalNum } from '@/core/app'
// import * as CartApi from '@/api/cart'
import GoodsSkuPopup from '@/components/goods-sku-popup'
export default {
components: {
GoodsSkuPopup
},
model: {
prop: 'value',
event: 'input'
},
props: {
// true false
value: {
Type: Boolean,
default: false
},
// 1: 2: 3:
skuMode: {
type: Number,
default: 1
},
//
goods: {
type: Object,
default: {}
}
},
data() {
return {
goodsInfo: {}
}
},
created() {
const app = this
const { goods } = app
app.goodsInfo = {
_id: goods.goods_id,
name: goods.goods_name,
goods_thumb: goods.goods_image,
sku_list: app.getSkuList(),
spec_list: app.getSpecList()
}
},
methods: {
//
onChangeValue(val) {
this.$emit('input', val)
},
// SKU
getSkuList() {
const app = this
const { goods: { goods_name, goods_image, skuList } } = app
const skuData = []
skuList.forEach(item => {
skuData.push({
_id: item.id,
goods_sku_id: item.goods_sku_id,
goods_id: item.goods_id,
goods_name: goods_name,
image: item.image_url ? item.image_url : goods_image,
price: item.goods_price * 100,
stock: item.stock_num,
spec_value_ids: item.spec_value_ids,
sku_name_arr: app.getSkuNameArr(item.spec_value_ids)
})
})
return skuData
},
// sku
getSkuNameArr(specValueIds) {
const app = this
const defaultData = ['默认']
const skuNameArr = []
if (specValueIds) {
specValueIds.forEach((valueId, groupIndex) => {
const specValueName = app.getSpecValueName(valueId, groupIndex)
skuNameArr.push(specValueName)
})
}
return skuNameArr.length ? skuNameArr : defaultData
},
//
getSpecValueName(valueId, groupIndex) {
const app = this
const { goods: { specList } } = app
const res = specList[groupIndex].valueList.find(specValue => {
return specValue.spec_value_id == valueId
})
return res.spec_value
},
//
getSpecList() {
const { goods: { specList } } = this
const defaultData = [{ name: '默认', list: [{ name: '默认' }] }]
const specData = []
specList.forEach(group => {
const children = []
group.valueList.forEach(specValue => {
children.push({ name: specValue.spec_value })
})
specData.push({
name: group.spec_name,
list: children
})
})
return specData.length ? specData : defaultData
},
// sku -----------------------------------------------------------
openSkuPopup() {
// console.log(" - sku")
},
closeSkuPopup() {
// console.log(" - sku")
},
//
addCart(selectShop) {
const app = this
const { goods_id, goods_sku_id, buy_num } = selectShop
// CartApi.add(goods_id, goods_sku_id, buy_num)
// .then(result => {
// //
// app.$toast(result.message)
// //
// app.onChangeValue(false)
// //
// const cartTotal = result.data.cartTotal
// //
// setCartTotalNum(cartTotal)
// //
// app.$emit('addCart', cartTotal)
// })
},
//
buyNow(selectShop) {
//
this.$Router.push({path : '/orderSubmit', query:{
mode: 'buyNow',
skuId: selectShop.goods_sku_id,
num: selectShop.buy_num
}})
// this.$navTo('pages/checkout/index', {
// mode: 'buyNow',
// goodsId: selectShop.goods_id,
// goodsSkuId: selectShop.goods_sku_id,
// goodsNum: selectShop.buy_num
// })
//
this.onChangeValue(false)
}
}
}
</script>
<style lang="scss" scoped>
</style>

@ -1,141 +0,0 @@
<template>
<!-- 商品图片 -->
<view class="images-swiper">
<swiper class="swiper-box" :autoplay="autoplay" :duration="duration" :indicator-dots="indicatorDots"
:interval="interval" :circular="true" @change="setCurrent">
<!-- 主图视频 -->
<swiper-item v-if="video">
<view class="slide-video">
<video id="myVideo" class="video" :poster="videoCover.preview_url" :src="video.external_url" controls
x5-playsinline playsinline webkit-playsinline webkit-playsinline x5-video-player-type="h5"
x5-video-player-fullscreen x5-video-orientation="portrait" :enable-progress-gesture="false"
@play="onVideoPlay"></video>
</view>
</swiper-item>
<!-- 轮播图片 -->
<swiper-item v-for="(item, index) in images" :key="index" @click="onPreviewImages(index)">
<view class="slide-image">
<image class="image" :draggable="false" :src="item.preview_url"></image>
</view>
</swiper-item>
</swiper>
</view>
</template>
<script>
export default {
props: {
//
video: {
type: Object,
default () {
return null
}
},
//
videoCover: {
type: Object,
default () {
return null
}
},
//
images: {
type: Array,
default: []
}
},
data() {
return {
indicatorDots: true, //
autoplay: true, //
interval: 4000, //
duration: 800, //
currentIndex: 1, //
}
},
methods: {
//
onVideoPlay(e) {
this.autoplay = false
},
//
setCurrent({ detail }) {
const app = this
app.currentIndex = detail.current + 1
},
//
onPreviewImages(index) {
const app = this
const imageUrls = []
app.images.forEach(item => {
imageUrls.push(item.preview_url);
});
uni.previewImage({
current: imageUrls[index],
urls: imageUrls
})
}
}
}
</script>
<style lang="scss" scoped>
// swiper
.images-swiper {
position: relative;
}
.swiper-box {
width: 100%;
height: 100vw;
/* #ifdef H5 */
max-width: 480px;
max-height: 480px;
margin: 0 auto;
/* #endif */
//
.slide-video {
width: 100%;
height: 100%;
.video {
display: block;
width: 100%;
height: 100%;
}
}
//
.slide-image {
position: relative;
width: 100%;
height: 100%;
.image {
display: block;
width: 100%;
height: 100%;
}
}
}
// swiper
.swiper-count {
position: absolute;
right: 36rpx;
bottom: 72rpx;
padding: 2rpx 18rpx;
background: rgba(0, 0, 0, 0.363);
border-radius: 50rpx;
color: #fff;
font-size: 26rpx;
}
</style>

@ -1,230 +0,0 @@
.container {
// ios线
// 110 - 18 + 4
padding-bottom: calc(constant(safe-area-inset-bottom) + 106rpx + 6rpx);
padding-bottom: calc(env(safe-area-inset-bottom) + 106rpx + 6rpx);
}
//
.goods-info {
background: #fff;
padding: 25rpx 30rpx;
}
.info-item__top {
min-height: 40rpx;
margin-bottom: 20rpx;
line-height: 1;
}
.floor-price__samll {
font-size: 26rpx;
line-height: 1;
color: #FA2209;
margin-bottom: -10rpx;
}
//
.floor-price {
color: #FA2209;
margin-right: 15rpx;
font-size: 42rpx;
}
.original-price {
font-size: 26rpx;
text-decoration: line-through;
color: #959595;
margin-right: 15rpx;
margin-bottom: -6rpx;
}
//
.user-grade {
background: #3c3c3c;
border-radius: 6rpx;
padding: 8rpx 14rpx;
margin-right: 15rpx;
font-size: 24rpx;
color: #EEE0C3;
}
.goods-sales {
font-size: 24rpx;
color: #959595;
}
.info-item__name .goods-name {
font-size: 30rpx;
}
/* 商品分享 */
.goods-share__line {
border-left: 1rpx solid #f4f4f4;
height: 60rpx;
margin: 0 30rpx;
}
.goods-share .share-btn {
line-height: normal;
padding: 0;
background: none;
border-radius: 0;
box-shadow: none;
font-size: 8pt;
border: none;
color: #191919;
}
.goods-share .share-btn::after {
border: none;
}
.goods-share .share__icon {
font-size: 40rpx;
margin-bottom: 5rpx;
}
//
.info-item_selling-point {
margin-top: 8rpx;
font-size: 24rpx;
color: #808080;
}
//
.goods-choice {
padding: 26rpx 30rpx;
font-size: 28rpx;
.spec-list {
display: flex;
align-items: center;
.spec-name {
margin-right: 10rpx;
}
}
}
//
.goods-content .item-title {
padding: 26rpx 30rpx;
font-size: 28rpx;
}
//
.footer-fixed {
position: fixed;
bottom: var(--window-bottom);
left: 0;
right: 0;
display: flex;
z-index: 11;
box-shadow: 0 -4rpx 40rpx 0 rgba(151, 151, 151, 0.24);
background: #fff;
// ios线
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
.footer-container {
width: 100%;
display: flex;
height: 106rpx;
}
//
.foo-item-fast {
box-sizing: border-box;
width: 256rpx;
line-height: 1;
display: flex;
justify-content: center;
align-items: center;
.fast-item {
position: relative;
padding: 4rpx 10rpx;
line-height: 1;
// text-align: center;
.fast-icon {
margin-bottom: 6rpx;
}
&--home {
margin-right: 30rpx;
}
&--cart {
.fast-icon { padding-left: 3px; }
}
//
.fast-badge {
display: inline-block;
box-sizing: border-box;
min-width: 16px;
padding: 0 3px;
color: #fff;
font-weight: 500;
font-size: 12px;
font-family: -apple-system-font, Helvetica Neue, Arial, sans-serif;
line-height: 1.2;
text-align: center;
background-color: #ee0a24;
border: 1px solid #fff;
border-radius: 999px;
}
.fast-badge--fixed {
position: absolute;
top: 0;
right: 0;
transform-origin: 100%
}
.fast-icon {
font-size: 46rpx;
}
.fast-text {
font-size: 24rpx;
}
}
}
//
.foo-item-btn {
flex: 1;
.btn-wrapper {
height: 100%;
display: flex;
align-items: center;
}
.btn-item {
flex: 1;
font-size: 28rpx;
height: 72rpx;
margin-right: 16rpx;
color: #fff;
border-radius: 50rpx;
display: flex;
justify-content: center;
align-items: center;
}
//
.btn-item-main {
background: linear-gradient(to right, #f9211c, #ff6335);
}
//
.btn-item-deputy {
background: linear-gradient(to right, #ffa600, #ffbb00);
}
}

@ -1,304 +0,0 @@
<!--
* @Author: ch
* @Date: 2022-03-21 10:43:45
* @LastEditors: ch
* @LastEditTime: 2022-03-21 11:25:56
* @Description: file content
-->
<template>
<view v-show="!isLoading" class="container">
<!-- 商品图片轮播 -->
<SlideImage v-if="!isLoading" :video="goods.video" :videoCover="goods.videoCover" :images="goods.goods_images" />
<!-- 商品信息 -->
<view v-if="!isLoading" class="goods-info m-top20">
<!-- 价格销量 -->
<view class="info-item info-item__top dis-flex flex-x-between flex-y-end">
<view class="block-left dis-flex flex-y-center">
<!-- 商品售价 -->
<text class="floor-price__samll"></text>
<text class="floor-price">{{ goods.goods_price_min }}</text>
<!-- 会员价标签 -->
<view v-if="goods.is_user_grade" class="user-grade">
<text>会员价</text>
</view>
<!-- 划线价 -->
<text v-if="goods.line_price_min > 0" class="original-price">{{ goods.line_price_min }}</text>
</view>
<view class="block-right dis-flex">
<!-- 销量 -->
<view class="goods-sales">
<text>已售{{ goods.goods_sales }}</text>
</view>
</view>
</view>
<!-- 标题分享 -->
<view class="info-item info-item__name dis-flex flex-y-center">
<view class="goods-name flex-box">
<text class="twoline-hide">{{ goods.goods_name }}</text>
</view>
<!-- #ifdef MP-WEIXIN -->
<view class="goods-share__line"></view>
<view class="goods-share">
<button class="share-btn dis-flex flex-dir-column" open-type="share">
<text class="share__icon iconfont icon-fenxiang"></text>
<text class="f-24">分享</text>
</button>
</view>
<!-- #endif -->
</view>
<!-- 商品卖点 -->
<view v-if="goods.selling_point" class="info-item info-item_selling-point">
<text>{{ goods.selling_point }}</text>
</view>
</view>
<!-- 选择商品规格 -->
<view v-if="goods.spec_type == 20" class="goods-choice m-top20 b-f" @click="onShowSkuPopup(1)">
<view class="spec-list">
<view class="flex-box">
<text class="col-8">选择</text>
<text class="spec-name" v-for="(item, index) in goods.specList" :key="index">{{ item.spec_name }}</text>
</view>
<view class="f-26 col-9 t-r">
<text class="iconfont icon-arrow-right"></text>
</view>
</view>
</view>
<!-- 商品服务 -->
<Service v-if="!isLoading" :goods-id="goodsId" />
<!-- 商品SKU弹窗 -->
<SkuPopup v-if="!isLoading" v-model="showSkuPopup" :skuMode="skuMode" :goods="goods" @addCart="onAddCart" />
<!-- 商品评价 -->
<!-- <Comment v-if="!isLoading" :goods-id="goodsId" :limit="2" /> -->
<!-- 商品描述 -->
<view v-if="!isLoading" class="goods-content m-top20">
<view class="item-title b-f">
<text>商品描述</text>
</view>
<block v-if="goods.content != ''">
<view class="goods-content__detail b-f">
<mp-html :content="goods.content" />
</view>
</block>
<empty v-else tips="亲,暂无商品描述" />
</view>
<!-- 底部选项卡 -->
<view class="footer-fixed">
<view class="footer-container">
<!-- 导航图标 -->
<view class="foo-item-fast">
<!-- 首页 -->
<view class="fast-item fast-item--home" @click="onTargetHome">
<view class="fast-icon">
<text class="iconfont icon-shouye"></text>
</view>
<view class="fast-text">
<text>首页</text>
</view>
</view>
<!-- 客服 (仅微信小程序端显示) -->
<!-- #ifdef MP-WEIXIN -->
<button class="btn-normal" open-type="contact">
<view class="fast-item">
<view class="fast-icon">
<text class="iconfont icon-kefu1"></text>
</view>
<view class="fast-text">
<text>客服</text>
</view>
</view>
</button>
<!-- #endif -->
<!-- 购物车 (非微信小程序端显示) -->
<!-- #ifndef MP-WEIXIN -->
<view class="fast-item fast-item--cart" @click="onTargetCart">
<view v-if="cartTotal > 0" class="fast-badge fast-badge--fixed">{{ cartTotal > 99 ? '99+' : cartTotal }}
</view>
<view class="fast-icon">
<text class="iconfont icon-gouwuche"></text>
</view>
<view class="fast-text">
<text>购物车</text>
</view>
</view>
<!-- #endif -->
</view>
<!-- 操作按钮 -->
<view class="foo-item-btn">
<view class="btn-wrapper">
<view class="btn-item btn-item-deputy" @click="onShowSkuPopup(2)">
<text>加入购物车</text>
</view>
<view class="btn-item btn-item-main" @click="onShowSkuPopup(3)">
<text>立即购买</text>
</view>
</view>
</view>
</view>
</view>
<!-- 快捷导航 -->
<!-- <shortcut bottom="120rpx" /> -->
</view>
</template>
<script>
import goodsDetailData from '@/mock/goodsDetail.json';
// import Shortcut from '@/components/shortcut'
import SlideImage from './components/SlideImage';
import SkuPopup from './components/SkuPopup';
import Service from './components/Service';
import mpHtml from 'mp-html/dist/uni-app/components/mp-html/mp-html';
export default {
components: {
// Shortcut,
mpHtml,
SlideImage,
SkuPopup,
Comment,
Service
},
data() {
return {
//
isLoading: true,
// ID
goodsId: null,
//
goods: {},
//
cartTotal: 0,
// /SKU
showSkuPopup: false,
// 1: 2: 3:
skuMode: 1
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
// ID
this.goodsId = parseInt(options.goodsId)
//
this.onRefreshPage()
},
methods: {
//
onRefreshPage() {
const app = this
app.isLoading = true
Promise.all([app.getGoodsDetail(), app.getCartTotal()])
.finally(() => app.isLoading = false)
},
//
getGoodsDetail() {
const app = this
return new Promise((resolve, reject) => {
app.goods = goodsDetailData.data.detail
resolve(goodsDetailData.data.detail)
// console.log(goodsDetailData.data.detail)
// GoodsApi.detail(app.goodsId)
// .then(result => {
// app.goods = result.data.detail
// resolve(result)
// })
// .catch(reject)
})
},
//
getCartTotal() {
const app = this
return new Promise((resolve, reject) => {
app.cartTotal = 2
resolve({"status":200,"message":"success","data":{"cartTotal":2}})
// CartApi.total()
// .then(result => {
// app.cartTotal = result.data.cartTotal
// resolve(result)
// })
// .catch(reject)
})
},
//
onAddCart(total) {
this.cartTotal = total
},
/**
* 显示/隐藏SKU弹窗
* @param {skuMode} 模式 1:都显示 2:只显示购物车 3:只显示立即购买
*/
onShowSkuPopup(skuMode = 1) {
this.skuMode = skuMode
this.showSkuPopup = !this.showSkuPopup
},
//
onTargetHome(e) {
this.$navTo('pages/index/index')
},
//
onTargetCart() {
this.$navTo('pages/cart/index')
},
},
/**
* 分享当前页面
*/
onShareAppMessage() {
const app = this
//
const params = app.$getShareUrlParams({
goodsId: app.goodsId,
})
return {
title: app.goods.goods_name,
path: `/pages/goods/detail?${params}`
}
},
/**
* 分享到朋友圈
* 本接口为 Beta 版本暂只在 Android 平台支持详见分享到朋友圈 (Beta)
* https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share-timeline.html
*/
onShareTimeline() {
const app = this
//
const params = app.$getShareUrlParams({
goodsId: app.goodsId,
})
return {
title: app.goods.goods_name,
path: `/pages/goods/detail?${params}`
}
}
}
</script>
<style>
page {
background: #fafafa;
}
</style>
<style lang="scss" scoped>
@import "./detail.scss";
</style>

@ -2,34 +2,19 @@
* @Author: ch
* @Date: 2022-03-23 16:37:30
* @LastEditors: ch
* @LastEditTime: 2022-03-23 17:16:03
* @LastEditTime: 2022-04-07 18:50:29
* @Description: file content
-->
<template>
<view class="sort">
<view class="sort--item" :class="item.value == 'all' && 'sort--item__active'" v-for="item in sortData" :key="item.value">
<view class="sort--item" :class="item.value == active.value && 'sort--item__active'"
v-for="item in sortData" :key="item.value" @click="change(item)">
<text class="sort--label">{{item.label}}</text>
<view>
<view class="sort--icon sort--icon__up sort--icon__active"></view>
<view class="sort--icon sort--icon__down"></view>
<view v-if="item.sort">
<view class="sort--icon sort--icon__up" :class="{'sort--icon__active' : item.sort === 'ASC' && item.value === active.value}"></view>
<view class="sort--icon sort--icon__down" :class="{'sort--icon__active' : item.sort === 'DESC' && item.value === active.value}"></view>
</view>
</view>
<!-- <view class="sort-item" :class="{ active: sortType === 'all' }" @click="handleSortType('all')">
<text>综合</text>
</view>
<view class="sort-item" :class="{ active: sortType === 'sales' }" @click="handleSortType('sales')">
<text>销量</text>
</view>
<view class="sort-item sort-item-price" :class="{ active: sortType === 'price' }" @click="handleSortType('price')">
<text>价格</text>
<view class="price-arrow">
<view class="icon up" :class="{ active: sortType === 'price' && !sortPrice }">
<text class="iconfont icon-arrow-up"></text>
</view>
<view class="icon down" :class="{ active: sortType === 'price' && sortPrice }">
<text class="iconfont icon-arrow-down"></text> </view>
</view>
</view> -->
</view>
</template>
<script>
@ -38,26 +23,40 @@ export default {
return {
sortData : [
{
value : 'all',
label : '综合',
sort : 'ASC'
value : '',
label : '综合'
},
{
value : 'pirce',
value : 'starting_price',
label : '价格',
sort : 'ASC'
},
{
value : 'num',
label : '销量',
sort : 'ASC'
value : 'sales',
label : '销量'
},
{
value : 'new',
label : '上新',
sort : 'ASC'
value : 'create_time',
label : '上新'
}
],
active: {
value : '',
label : '综合'
}
}
},
methods:{
change(item){
if(item.sort){
item.sort === 'ASC' ? item.sort = 'DESC' : item.sort = 'ASC';
}
console.log(item.value + item.sort , this.active.value + this.active.sort);
if(item.value + item.sort === this.active.value + this.active.sort){
return false;
}
]
this.active = {...item};
this.$emit('change',this.active)
}
}
}

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-21 10:31:54
* @LastEditors: ch
* @LastEditTime: 2022-04-02 11:12:11
* @LastEditTime: 2022-04-07 19:12:18
* @Description: file content
-->
<template>
@ -11,36 +11,99 @@
<UiPageHeader>
<u--input slot="custom" class="search--input" prefixIconStyle="font-size:48rpx;color:#ccc"
prefixIcon="search" placeholderClass="search--input__placeholder" clearable
:placeholder="placeholder" :value="$Route.query.search"
placeholder="请输入您想要搜索的商品名称" :value="$Route.query.search"
@focus="$Router.push('/search')"/>
</UiPageHeader>
<!-- 排序标签 -->
<Sort></Sort>
<Sort @change="sortChange"></Sort>
</view>
<BsGoodsGroup class="goods-group" ref="goodsGroup" ></BsGoodsGroup>
<UiGoodsGroup v-if="listData.length" class="goods-group" :listData="listData"></UiGoodsGroup>
<u-loadmore :status="loadingStatus" v-if="!listData.length && params.pageIndex > 1"/>
<!-- 当前条件无数据时展示 -->
<template v-if="showEmpty">
<BsEmpty tips="没搜到您想要的相关商品">
<UiButton slot="btn" @click="$Router.replace('/')"></UiButton>
</BsEmpty>
<view class="title">为您精选</view>
<BsChoiceGoods class="goods-group" ref="choiceGoods"></BsChoiceGoods>
</template>
</view>
</template>
<script>
import BsGoodsGroup from "@/components/BsGoodsGroup.vue";
import {ApiGetGoodsList} from '@/common/api/goods';
import BsChoiceGoods from "@/components/BsChoiceGoods.vue";
import Sort from "./components/Sort.vue";
import UiPageHeader from '@/components/UiPageHeader.vue';
import UiGoodsGroup from '../../../components/UiGoodsGroup.vue';
import BsEmpty from '../../../components/BsEmpty.vue';
import UiButton from '../../../components/UiButton.vue';
export default {
components: { BsGoodsGroup, Sort, UiPageHeader },
components: { BsChoiceGoods, Sort, UiPageHeader, UiGoodsGroup, BsEmpty, UiButton },
data() {
return {
sortType: "all", //
sortPrice: false, // (true false)
loadingStatus : 'loading',
listData : [],
params : {
length : 10,
pageIndex : 1,
name : this.$Route.query.search,
categoryId : this.$Route.query.categoryId,
order : ''
}
};
},
mounted(){
// console.log(getCurrentPages())
computed:{
showEmpty(){
return !this.listData.length && this.params.pageIndex == 1 && this.loadingStatus != 'loading'
}
},
onLoad(){
this.getGoodsList();
},
onReachBottom(){
this.$refs.goodsGroup.next()
if(this.showEmpty){
this.$refs.choiceGoods.next();
}else{
this.next();
}
},
onHide(){
// console.log(getCurrentPages());
methods:{
sortChange(order){
this.params.order = order.sort ? `${order.value}:${order.sort}` : order.value;
this.params.pageIndex = 1;
this.listData = [];
this.getGoodsList();
},
/**
* 获取搜索的商品列表
*/
async getGoodsList(){
this.loadingStatus = 'loading';
const {error, result} = await ApiGetGoodsList(this.params);
if(error){
uni.$u.toast(error.message);
return false;
}
this.listData = this.listData.concat(result.records);
//
if(!result.records.length){
this.loadingStatus = 'nomore';
}
},
next(){
if(this.loadingStatus === 'nomore'){
return false
}
this.params.pageIndex++;
this.getGoodsList();
}
}
};
</script>
@ -65,7 +128,30 @@ page {
color: #666;
}
}
.goods-group {
padding-top: 30rpx;
}
.title{
font-size: 32rpx;
text-align: center;
margin: 51rpx auto 30rpx auto;
display: flex;
align-items: center;
justify-content: space-between;
width: 500rpx;
&::after,&::before{
display: inline-block;
content: '';
width: 160rpx;
height: 2rpx;
background: linear-gradient(90deg, #CCCCCC 0%, rgba(204, 204, 204, 0) 100%);
}
&::before{
background: linear-gradient(270deg, #CCCCCC 0%, rgba(204, 204, 204, 0) 100%);
}
}
</style>

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-21 11:29:38
* @LastEditors: ch
* @LastEditTime: 2022-03-29 10:59:01
* @LastEditTime: 2022-04-07 16:17:35
* @Description: file content
-->
<template>
@ -10,8 +10,8 @@
<UiPageHeader>
<view slot="custom" class="search">
<u--input class="search--input" placeholder="请输入您想搜索的商品名称"
prefixIcon="search" clearable prefixIconStyle="font-size:48rpx;color:#ccc"
<u--input class="search--input" focus placeholder="请输入您想搜索的商品名称"
prefixIcon="search" ref="search" clearable prefixIconStyle="font-size:48rpx;color:#ccc"
v-model="searchValue" placeholderClass="search--input__placeholder"></u--input>
<text class="search--btn" @click="onSearch"></text>
</view>
@ -49,7 +49,10 @@ export default {
onHide(){
// console.log(getCurrentPages());
},
mounted(){
console.log(this.$refs.search); //.search.focus();
},
methods: {
/**
* 搜索提交

@ -2,12 +2,14 @@
* @Author: ch
* @Date: 2022-03-23 10:31:12
* @LastEditors: ch
* @LastEditTime: 2022-03-25 10:04:56
* @LastEditTime: 2022-04-07 10:52:51
* @Description: file content
-->
<template>
<view class="banner">
<u-swiper :list="bannerList" height="240rpx" indicator indicatorMode="dot"></u-swiper>
<u-swiper keyName="img" :list="bannerList" height="240rpx" indicator indicatorMode="dot">
</u-swiper>
<view class="desc">
<view class="desc--item">
<image class="desc--icon" src='@/static/index/bz.png'></image>

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-23 10:07:48
* @LastEditors: ch
* @LastEditTime: 2022-03-23 10:08:58
* @LastEditTime: 2022-04-07 11:24:38
* @Description: file content
-->
<template>
@ -21,32 +21,6 @@
<image class="sekill-title--more-icon" src="@/static/common/arrow.png"></image>
</view>
</view>
<view class="sekill--group">
<view>
<image class="sekill--item-img"></image>
<view class="sekill--item-pirce-box">
<text>秒杀价</text>
<text class="sekill--item-pirce">29</text>
</view>
<text class="sekill--item-original-pirce">50</text>
</view>
<view>
<image class="sekill--item-img"></image>
<view class="sekill--item-pirce-box">
<text>秒杀价</text>
<text class="sekill--item-pirce">29</text>
</view>
<text class="sekill--item-original-pirce">50</text>
</view>
<view>
<image class="sekill--item-img"></image>
<view class="sekill--item-pirce-box">
<text>秒杀价</text>
<text class="sekill--item-pirce">29</text>
</view>
<text class="sekill--item-original-pirce">50</text>
</view>
</view>
</view>
</template>
<script>

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2019-08-22 19:41:20
* @LastEditors: ch
* @LastEditTime: 2022-04-02 11:12:22
* @LastEditTime: 2022-04-07 16:47:31
* @Description: file content
-->
<template>
@ -19,15 +19,15 @@
<view class="search" @click="$Router.push('/search')">
<text class="search--input">请输入您想搜索的商品名称</text>
</view>
<Banner :bannerList="bannerList"></Banner>
<view class="category">
<view class="category--item" v-for="item in categoryList" :key="item.url">
<view class="category--item" v-for="item in categoryList" :key="item.id"
@click="$Router.push(`/goodsList?categoryId=${item.id}`)">
<view class="category--image-box">
<image class="category--image" src="@/static/tabbar/home-active.png"></image>
<image class="category--image" :src="item.picture"></image>
</view>
<text class="category--title">{{item.title}}</text>
<text class="category--title">{{item.name}}</text>
</view>
</view>
<Sekill></Sekill>
@ -36,21 +36,26 @@
<Pick></Pick>
<view class="title">为您推荐</view>
<BsGoodsGroup ref="goodsGroup" ></BsGoodsGroup>
<BsChoiceGoods ref="goodsGroup" ></BsChoiceGoods>
</view>
</template>
<script>
import BsGoodsGroup from '@/components/BsGoodsGroup';
import BsChoiceGoods from '@/components/BsChoiceGoods';
import Sekill from './components/Sekill';
import Pick from './components/Pick';
import Banner from './components/Banner';
import {ApiGetBannerData} from '@/common/api/index.js';
import {ApiGetCategoryNav} from '@/common/api/goods.js';
export default {
components : {BsGoodsGroup, Pick, Banner, Sekill},
components : {BsChoiceGoods, Pick, Banner, Sekill},
data(){
return {
scrollTop : 0,
bannerList: [],
bannerList: [
'https://cdn.uviewui.com/uview/swiper/swiper1.png',
'https://cdn.uviewui.com/uview/swiper/swiper2.png',
'https://cdn.uviewui.com/uview/swiper/swiper3.png',
],
categoryList : [
{ url : 'bz2.png', title : '数码周边'},
{ url : 'bz1.png', title : '数码周边'},
@ -63,7 +68,7 @@ export default {
}
},
onLoad(){
this.getBannerList();
this.getCategoryList();
},
onReachBottom(){
this.$refs.goodsGroup.next()
@ -87,6 +92,10 @@ export default {
// const {error, result} = await ApiGetBannerData({pageIndex:1, length:999});
// console.log(result)
// this.bannerList = result.concat(result).map(i => i.imgUrl);
},
async getCategoryList(){
const {error, result} = await ApiGetCategoryNav();
this.categoryList = result;
}
}
}

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-22 15:36:46
* @LastEditors: ch
* @LastEditTime: 2022-04-07 10:33:33
* @LastEditTime: 2022-04-07 14:41:24
* @Description: file content
-->
<template>
@ -98,9 +98,20 @@ export default {
this.$store.commit('SET_TOKEN',result.token);
this.goBack();
},
/**
* 登录返回 登录后的跳转逻辑
* 如果是从首页或者直接打开的页面则直接跳转至首页
* 否则返回上一个页面
*/
goBack(){
const pagesLength = getCurrentPages().length;
pagesLength > 1 ? this.$Router.back() : this.$Router.replace('/');
const pages = getCurrentPages();
const len = pages.length;
const prevPage = pages[len - 2];
if(len > 1 && prevPage.route !== 'pages/index/index'){
this.$Router.back();
}else{
this.$Router.replaceAll('/');
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Loading…
Cancel
Save