50 changed files with 0 additions and 10178 deletions
@ -1,11 +0,0 @@ |
|||
import request from '@/utils/request' |
|||
|
|||
// api地址
|
|||
const api = { |
|||
list: 'article.category/list' |
|||
} |
|||
|
|||
// 页面数据
|
|||
export function list() { |
|||
return request.get(api.list) |
|||
} |
|||
@ -1,17 +0,0 @@ |
|||
import request from '@/utils/request' |
|||
|
|||
// api地址
|
|||
const api = { |
|||
list: 'article/list', |
|||
detail: 'article/detail' |
|||
} |
|||
|
|||
// 文章列表
|
|||
export function list(param, option) { |
|||
return request.get(api.list, param, option) |
|||
} |
|||
|
|||
// 文章详情
|
|||
export function detail(articleId) { |
|||
return request.get(api.detail, { articleId }) |
|||
} |
|||
@ -1,11 +0,0 @@ |
|||
import request from '@/utils/request' |
|||
|
|||
// api地址
|
|||
const api = { |
|||
list: 'balance.log/list' |
|||
} |
|||
|
|||
// 余额账单明细
|
|||
export const list = (param) => { |
|||
return request.get(api.list, param) |
|||
} |
|||
@ -1,35 +0,0 @@ |
|||
import request from '@/utils/request' |
|||
|
|||
// api地址
|
|||
const api = { |
|||
list: 'cart/list', |
|||
total: 'cart/total', |
|||
add: 'cart/add', |
|||
update: 'cart/update', |
|||
clear: 'cart/clear' |
|||
} |
|||
|
|||
// 购物车列表
|
|||
export const list = () => { |
|||
return request.get(api.list, {}, { load: false }) |
|||
} |
|||
|
|||
// 购物车商品总数量
|
|||
export const total = () => { |
|||
return request.get(api.total, {}, { load: false }) |
|||
} |
|||
|
|||
// 加入购物车
|
|||
export const add = (goodsId, goodsSkuId, goodsNum) => { |
|||
return request.post(api.add, { goodsId, goodsSkuId, goodsNum }) |
|||
} |
|||
|
|||
// 更新购物车商品数量
|
|||
export const update = (goodsId, goodsSkuId, goodsNum) => { |
|||
return request.post(api.update, { goodsId, goodsSkuId, goodsNum }, { isPrompt: false }) |
|||
} |
|||
|
|||
// 删除购物车中指定记录
|
|||
export const clear = (cartIds = []) => { |
|||
return request.post(api.clear, { cartIds }) |
|||
} |
|||
@ -1,11 +0,0 @@ |
|||
import request from '@/utils/request' |
|||
|
|||
// api地址
|
|||
const api = { |
|||
list: 'category/list' |
|||
} |
|||
|
|||
// 页面数据
|
|||
export function list() { |
|||
return request.get(api.list) |
|||
} |
|||
@ -1,19 +0,0 @@ |
|||
import request from '@/utils/request' |
|||
|
|||
// api地址
|
|||
const api = { |
|||
order: 'checkout/order', |
|||
submit: 'checkout/submit', |
|||
} |
|||
|
|||
// mode: 结算模式 (buyNow立即购买 cart购物车)
|
|||
|
|||
// 结算台订单信息
|
|||
export const order = (mode, param) => { |
|||
return request.get(api.order, { mode, ...param }) |
|||
} |
|||
|
|||
// 结算台订单提交
|
|||
export const submit = (mode, data) => { |
|||
return request.post(api.submit, { mode, ...data }) |
|||
} |
|||
@ -1,23 +0,0 @@ |
|||
import request from '@/utils/request' |
|||
|
|||
// api地址
|
|||
const api = { |
|||
list: 'comment/list', |
|||
listRows: 'comment/listRows', |
|||
total: 'comment/total' |
|||
} |
|||
|
|||
// 商品评价列表
|
|||
export const list = (goodsId, param, option) => { |
|||
return request.get(api.list, { ...param, goodsId }, option) |
|||
} |
|||
|
|||
// 商品评价列表 (限制数量, 用于商品详情页展示)
|
|||
export const listRows = (goodsId, limit = 5) => { |
|||
return request.get(api.listRows, { goodsId, limit }) |
|||
} |
|||
|
|||
// 商品评分总数
|
|||
export const total = (goodsId) => { |
|||
return request.get(api.total, { goodsId }) |
|||
} |
|||
@ -1,16 +0,0 @@ |
|||
import request from '@/utils/request' |
|||
|
|||
// api地址
|
|||
const api = { |
|||
list: 'coupon/list' |
|||
} |
|||
|
|||
// 优惠券列表
|
|||
export const list = (param, option) => { |
|||
const options = { |
|||
isPrompt: true, //(默认 true 说明:本接口抛出的错误是否提示)
|
|||
load: true, //(默认 true 说明:本接口是否提示加载动画)
|
|||
...option |
|||
} |
|||
return request.get(api.list, param, options) |
|||
} |
|||
@ -1,11 +0,0 @@ |
|||
import request from '@/utils/request' |
|||
|
|||
// api地址
|
|||
const api = { |
|||
list: 'express/list' |
|||
} |
|||
|
|||
// 物流公司列表
|
|||
export const list = (param) => { |
|||
return request.get(api.list, param) |
|||
} |
|||
@ -1,23 +0,0 @@ |
|||
import request from '@/utils/request' |
|||
|
|||
// api地址
|
|||
const api = { |
|||
list: 'goods/list', |
|||
detail: 'goods/detail', |
|||
specData: 'goods/specData' |
|||
} |
|||
|
|||
// 商品列表
|
|||
export const list = param => { |
|||
return request.get(api.list, param) |
|||
} |
|||
|
|||
// 商品详情
|
|||
export const detail = goodsId => { |
|||
return request.get(api.detail, { goodsId }) |
|||
} |
|||
|
|||
// 获取商品规格数据
|
|||
export const specData = (goodsId) => { |
|||
return request.get(api.specData, { goodsId }) |
|||
} |
|||
@ -1,11 +0,0 @@ |
|||
import request from '@/utils/request' |
|||
|
|||
// api地址
|
|||
const api = { |
|||
list: 'goods.service/list' |
|||
} |
|||
|
|||
// 商品评价列表
|
|||
export function list(goodsId) { |
|||
return request.get(api.list, { goodsId }) |
|||
} |
|||
@ -1,22 +0,0 @@ |
|||
import request from '@/utils/request' |
|||
|
|||
// api地址
|
|||
const api = { |
|||
list: 'myCoupon/list', |
|||
receive: 'myCoupon/receive' |
|||
} |
|||
|
|||
// 我的优惠券列表
|
|||
export const list = (param, option) => { |
|||
const options = { |
|||
isPrompt: true, //(默认 true 说明:本接口抛出的错误是否提示)
|
|||
load: true, //(默认 true 说明:本接口是否提示加载动画)
|
|||
...option |
|||
} |
|||
return request.get(api.list, param, options) |
|||
} |
|||
|
|||
// 领取优惠券
|
|||
export const receive = (couponId, data) => { |
|||
return request.post(api.receive, { couponId, ...couponId, data }) |
|||
} |
|||
@ -1,47 +0,0 @@ |
|||
import request from '@/utils/request' |
|||
|
|||
// api地址
|
|||
const api = { |
|||
todoCounts: 'order/todoCounts', |
|||
list: 'order/list', |
|||
detail: 'order/detail', |
|||
express: 'order/express', |
|||
cancel: 'order/cancel', |
|||
receipt: 'order/receipt', |
|||
pay: 'order/pay' |
|||
} |
|||
|
|||
// 当前用户待处理的订单数量
|
|||
export function todoCounts(param, option) { |
|||
return request.get(api.todoCounts, param, option) |
|||
} |
|||
|
|||
// 我的订单列表
|
|||
export function list(param, option) { |
|||
return request.get(api.list, param, option) |
|||
} |
|||
|
|||
// 订单详情
|
|||
export function detail(orderId, param) { |
|||
return request.get(api.detail, { orderId, ...param }) |
|||
} |
|||
|
|||
// 获取物流信息
|
|||
export function express(orderId, param) { |
|||
return request.get(api.express, { orderId, ...param }) |
|||
} |
|||
|
|||
// 取消订单
|
|||
export function cancel(orderId, data) { |
|||
return request.post(api.cancel, { orderId, ...data }) |
|||
} |
|||
|
|||
// 确认收货
|
|||
export function receipt(orderId, data) { |
|||
return request.post(api.receipt, { orderId, ...data }) |
|||
} |
|||
|
|||
// 立即支付
|
|||
export function pay(orderId, payType, param) { |
|||
return request.get(api.pay, { orderId, payType, ...param }) |
|||
} |
|||
@ -1,11 +0,0 @@ |
|||
import request from '@/utils/request' |
|||
|
|||
// api地址
|
|||
const api = { |
|||
list: 'recharge.order/list' |
|||
} |
|||
|
|||
// 我的充值记录列表
|
|||
export const list = (param) => { |
|||
return request.get(api.list, param) |
|||
} |
|||
@ -1,11 +0,0 @@ |
|||
import request from '@/utils/request' |
|||
|
|||
// api地址
|
|||
const api = { |
|||
list: 'recharge.plan/list' |
|||
} |
|||
|
|||
// 充值套餐列表
|
|||
export const list = (param) => { |
|||
return request.get(api.list, param) |
|||
} |
|||
@ -1,35 +0,0 @@ |
|||
import request from '@/utils/request' |
|||
|
|||
// api地址
|
|||
const api = { |
|||
list: 'refund/list', |
|||
goods: 'refund/goods', |
|||
apply: 'refund/apply', |
|||
detail: 'refund/detail', |
|||
delivery: 'refund/delivery' |
|||
} |
|||
|
|||
// 售后单列表
|
|||
export const list = (param, option) => { |
|||
return request.get(api.list, param, option) |
|||
} |
|||
|
|||
// 订单商品详情
|
|||
export const goods = (orderGoodsId, param) => { |
|||
return request.get(api.goods, { orderGoodsId, ...param }) |
|||
} |
|||
|
|||
// 申请售后
|
|||
export const apply = (orderGoodsId, data) => { |
|||
return request.post(api.apply, { orderGoodsId, form: data }) |
|||
} |
|||
|
|||
// 售后单详情
|
|||
export const detail = (orderRefundId, param) => { |
|||
return request.get(api.detail, { orderRefundId, ...param }) |
|||
} |
|||
|
|||
// 用户发货
|
|||
export const delivery = (orderRefundId, data) => { |
|||
return request.post(api.delivery, { orderRefundId, form: data }) |
|||
} |
|||
@ -1,18 +0,0 @@ |
|||
import request from '@/utils/request' |
|||
|
|||
// api地址
|
|||
const api = { |
|||
image: 'upload/image' |
|||
} |
|||
|
|||
// 图片上传
|
|||
export const image = files => { |
|||
// 文件上传大小, 2M
|
|||
const maxSize = 1024 * 1024 * 2 |
|||
// 执行上传
|
|||
return new Promise((resolve, reject) => { |
|||
request.urlFileUpload({ files, maxSize }) |
|||
.then(result => resolve(result.map(item => item.data.fileInfo.file_id), result)) |
|||
.catch(reject) |
|||
}) |
|||
} |
|||
@ -1,331 +0,0 @@ |
|||
<template> |
|||
<!-- 打卡日历页面 --> |
|||
<view class='all'> |
|||
<view class="bar"> |
|||
<!-- 上一个月 --> |
|||
<view class="previous" @click="handleCalendar(0)"> |
|||
<button class="barbtn">上一月</button> |
|||
</view> |
|||
<!-- 显示年月 --> |
|||
<view class="date">{{cur_year || "--"}} 年 {{cur_month || "--"}} 月</view> |
|||
<!-- 下一个月 --> |
|||
<view class="next" @click="handleCalendar(1)"> |
|||
<button class="barbtn">下一月</button> |
|||
</view> |
|||
</view> |
|||
<!-- 显示星期 --> |
|||
<view class="week"> |
|||
<view class="week_ri" v-for="(item,index) in weeks_ch" :key="index">{{item}}</view> |
|||
</view> |
|||
<view class="myDateTable"> |
|||
<view v-for="(item,j) in days" :key="j" class='dateCell'> |
|||
<view v-if="item.date==undefined || item.date == null" class='cell'> |
|||
<text :decode="true"> </text> |
|||
</view> |
|||
<view v-else @click="clickSignUp(item.date)"> |
|||
<!-- 已订餐到日期 --> |
|||
<view v-if="item.isSign == 5" class='cell yellow' style="background: #0000a8;color: #ffffff;"> |
|||
<text>{{item.date}}</text> |
|||
</view> |
|||
<view class="cell white bg-red" style="background: #0000e7;color: #ffffff;" v-else-if="item.isSign == 2"> |
|||
<text>{{item.date}}</text> |
|||
</view> |
|||
<!-- 点击的日期 --> |
|||
<view class="cell white bg-red" style="background: #ffaa7f;color: #ffffff;" v-else-if="item.isSign == 3"> |
|||
<text>{{item.date}}</text> |
|||
</view> |
|||
<!-- 今天的日期 --> |
|||
<view v-else-if="item.date == today" class='cell yellow curday' style="color: #fa2299;">{{item.date}}</view> |
|||
<!-- 当前日期之后 --> |
|||
<view class="whiteColor cell" v-else> |
|||
<text>{{item.date}}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 活动列表 --> |
|||
<view class="actlist"> |
|||
<view class="act-item"> |
|||
<view class="act-title">五月端午,邀你去踏青</view> |
|||
<view class="act-desc">端午时节,踏青开始</view> |
|||
</view> |
|||
|
|||
<view class="act-item"> |
|||
<view class="act-title">五月端午,邀你去踏青</view> |
|||
<view class="act-desc">端午时节,踏青开始</view> |
|||
</view> |
|||
|
|||
<view class="act-item"> |
|||
<view class="act-title">五月端午,邀你去踏青</view> |
|||
<view class="act-desc">端午时节,踏青开始</view> |
|||
</view> |
|||
|
|||
|
|||
|
|||
</view> |
|||
</view> |
|||
|
|||
|
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
days: [],//日历 |
|||
SignUp: [{'type':1,t:1},{'type':2,t:10}],//已经订餐 |
|||
cur_year: 0, //当前选的年 |
|||
cur_month: 0, //当前选的月 |
|||
today: parseInt(new Date().getDate()), //今天 |
|||
toMonth: parseInt(new Date().getMonth() + 1), //本月 |
|||
toYear: parseInt(new Date().getFullYear()), //本年 |
|||
weeks_ch: ['日', '一', '二', '三', '四', '五', '六'], |
|||
}; |
|||
}, |
|||
props: { |
|||
//年 |
|||
sendYear: { |
|||
type: Number, |
|||
default: new Date().getFullYear() |
|||
}, |
|||
//月 |
|||
sendMonth: { |
|||
type: Number, |
|||
default: new Date().getMonth() + 1 |
|||
}, |
|||
}, |
|||
created() { |
|||
this.cur_year = this.sendYear;//年 |
|||
this.cur_month = this.sendMonth;//月 |
|||
this.calculateEmptyGrids(this.cur_year, this.cur_month); |
|||
this.calculateDays(this.cur_year, this.cur_month); |
|||
//网络请求 |
|||
this.onJudgeSign(this.SignUp); |
|||
}, |
|||
methods: { |
|||
// 获取当月共多少天 |
|||
getThisMonthDays(year, month) { |
|||
return new Date(year, month, 0).getDate() |
|||
}, |
|||
// 获取当月第一天星期几 |
|||
getFirstDayOfWeek(year, month) { |
|||
return new Date(Date.UTC(year, month - 1, 1)).getDay(); |
|||
}, |
|||
// 计算当月1号前空了几个格子,把它填充在days数组的前面 |
|||
calculateEmptyGrids(year, month) { |
|||
//计算每个月时要清零 |
|||
this.days = []; |
|||
const firstDayOfWeek = this.getFirstDayOfWeek(year, month); |
|||
if (firstDayOfWeek > 0) { |
|||
for (let i = 0; i < firstDayOfWeek; i++) { |
|||
var obj = { |
|||
date: null, |
|||
isSign: false |
|||
} |
|||
this.days.push(obj); |
|||
} |
|||
} |
|||
}, |
|||
// 绘制当月天数占的格子,并把它放到days数组中 |
|||
calculateDays(year, month) { |
|||
const thisMonthDays = this.getThisMonthDays(year, month); |
|||
for (let i = 1; i <= thisMonthDays; i++) { |
|||
var obj = { |
|||
date: i, |
|||
isSign: false |
|||
} |
|||
this.days.push(obj); |
|||
} |
|||
//console.log(this.days); |
|||
}, |
|||
//匹配判断当月与当月哪些日子订餐 |
|||
onJudgeSign(date) { |
|||
var signs = date; |
|||
var daysArr = this.days; |
|||
//日期相同,订过餐 |
|||
for(var i=0;i<signs.length;i++){ |
|||
for (var j=0; j<daysArr.length;j++) { |
|||
if (daysArr[j].date == signs[i]['t']) { |
|||
if(signs[i]['type'] == 1){ |
|||
daysArr[j].isSign = 2;//订一餐 |
|||
}else{ |
|||
daysArr[j].isSign = 5;//订两餐 |
|||
} |
|||
|
|||
} |
|||
} |
|||
} |
|||
this.days = daysArr; |
|||
}, |
|||
// 切换控制年月,上一个月,下一个月 |
|||
handleCalendar(type) { |
|||
const cur_year = parseInt(this.cur_year); |
|||
const cur_month = parseInt(this.cur_month); |
|||
var newMonth; |
|||
var newYear = cur_year; |
|||
if (type === 0) { //上个月 |
|||
newMonth = cur_month - 1; |
|||
if (newMonth < 1) { |
|||
newYear = cur_year - 1; |
|||
newMonth = 12; |
|||
} |
|||
} else { |
|||
newMonth = cur_month + 1; |
|||
if (newMonth > 12) { |
|||
newYear = cur_year + 1; |
|||
newMonth = 1; |
|||
} |
|||
} |
|||
this.calculateEmptyGrids(newYear, newMonth); |
|||
this.calculateDays(newYear, newMonth); |
|||
|
|||
//网络请求 |
|||
this.SignUp =[{'type':1,t:3},{'type':2,t:11}],//已经订餐 |
|||
this.onJudgeSign(this.SignUp); |
|||
|
|||
this.cur_year = newYear; |
|||
this.cur_month = newMonth; |
|||
|
|||
// this.SignUp = []; //清空 |
|||
this.$emit('dateChange',this.cur_year+"-"+this.cur_month); //传给调用模板页面去拿新数据 |
|||
}, |
|||
//点击日期 |
|||
clickSignUp(t){ |
|||
// console.log(this.cur_year)//年 |
|||
// console.log(this.cur_month)//月 |
|||
var t = t;//点击的天 |
|||
|
|||
var signs = this.SignUp; |
|||
|
|||
var daysArr = this.days; |
|||
//日期相同,订过餐,点击的日期 |
|||
for(var i=0;i<signs.length;i++){ |
|||
for (var j=0; j<daysArr.length;j++) { |
|||
if (daysArr[j].date == signs[i]['t']) { |
|||
if(signs[i]['type'] == 1){ |
|||
daysArr[j].isSign = 2;//订一餐 |
|||
}else{ |
|||
daysArr[j].isSign = 5;//订两餐 |
|||
} |
|||
} |
|||
if(t == daysArr[j].date){ |
|||
daysArr[j].isSign = 3 |
|||
} |
|||
if(daysArr[j].isSign != 2 && t != daysArr[j].date && daysArr[j].isSign != 5){ |
|||
daysArr[j].isSign = 1; |
|||
} |
|||
} |
|||
} |
|||
this.days = daysArr; |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
|
|||
.all .bar { |
|||
display: flex; |
|||
flex-direction: row; |
|||
justify-content: space-between; |
|||
padding: 10rpx; |
|||
} |
|||
|
|||
.bar .barbtn { |
|||
height: 30px; |
|||
line-height: 30px; |
|||
font-size: 12px; |
|||
} |
|||
/* 星期 */ |
|||
.all .week { |
|||
display: flex; |
|||
/* flex-direction: row; */ |
|||
/* justify-content: space-between; */ |
|||
padding: 20rpx; |
|||
border-radius: 10px; |
|||
background-color: #fff; |
|||
width: 90%; |
|||
margin-left: 2%; |
|||
} |
|||
.week_ri{ |
|||
margin-left: 19rpx; |
|||
padding: 0 48rpx 0 0; |
|||
} |
|||
.myDateTable { |
|||
margin: 2.5vw; |
|||
border-radius: 10px; |
|||
background: #fff; |
|||
} |
|||
.myDateTable .dateCell { |
|||
width: 11vw; |
|||
padding: 1vw; |
|||
display: inline-block; |
|||
text-align: center; |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.dateCell .cell { |
|||
display: flex; |
|||
border-radius: 50%; |
|||
height: 9vw; |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
|
|||
.greenColor { |
|||
color: #01b90b; |
|||
font-weight: bold; |
|||
} |
|||
|
|||
.bgWhite { |
|||
background-color: #fff; |
|||
} |
|||
|
|||
.bgGray { |
|||
background-color: rgba(255, 255, 255, 0.42); |
|||
} |
|||
|
|||
.bgBlue { |
|||
font-size: 14px; |
|||
background-color: #4b95e6; |
|||
} |
|||
|
|||
.redColor { |
|||
color: #ff0000; |
|||
} |
|||
.curday{ |
|||
color: #fa2209; |
|||
font-size: 36rpx; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.TipArea{ |
|||
word-break:break-all; |
|||
word-wrap:break-word; |
|||
|
|||
font-size: 14px; |
|||
padding: 10px; |
|||
} |
|||
.impTip{ |
|||
display: inline-block; |
|||
color: #ff0000; |
|||
} |
|||
|
|||
.actlist{ |
|||
padding: 10rpx; |
|||
|
|||
.act-item{ |
|||
padding:20rpx; |
|||
color: #333; |
|||
border-bottom: #ccc 1px solid; |
|||
margin-top: 20rpx; |
|||
background: #fff; |
|||
|
|||
.act-title{ |
|||
font-size: 36rpx; |
|||
line-height: 1.8; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,500 +0,0 @@ |
|||
<template> |
|||
<view class="container"> |
|||
<!-- 页面顶部 --> |
|||
<view v-if="list.length" class="head-info"> |
|||
<view class="cart-total"> |
|||
<text>共</text> |
|||
<text class="active">{{ total }}</text> |
|||
<text>件商品</text> |
|||
</view> |
|||
<view class="cart-edit" @click="handleToggleMode"> |
|||
<view v-if="mode == 'normal'" class="normal"> |
|||
<text class="icon iconfont icon-bianji"></text> |
|||
<text>编辑</text> |
|||
</view> |
|||
<view v-if="mode == 'edit'" class="edit"> |
|||
<text>完成</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- 购物车商品列表 --> |
|||
<view v-if="list.length" class="cart-list"> |
|||
<view class="cart-item" v-for="(item, index) in list" :key="index"> |
|||
<label class="item-radio" @click.stop="handleCheckItem(item.id)"> |
|||
<radio class="radio" color="#fa2209" :checked="inArray(item.id, checkedIds)" /> |
|||
</label> |
|||
<view class="goods-image" @click="onTargetGoods(item.goods_id)"> |
|||
<image class="image" :src="item.goods.goods_image" mode="scaleToFill"></image> |
|||
</view> |
|||
<view class="item-content"> |
|||
<view class="goods-title" @click="onTargetGoods(item.goods_id)"> |
|||
<text class="twoline-hide">{{ item.goods.goods_name }}</text> |
|||
</view> |
|||
<view class="goods-props clearfix"> |
|||
<view class="goods-props-item" v-for="(props, idx) in item.goods.skuInfo.goods_props" :key="idx"> |
|||
<text>{{ props.value.name }}</text> |
|||
</view> |
|||
</view> |
|||
<view class="item-foot"> |
|||
<view class="goods-price"> |
|||
<text class="unit">¥</text> |
|||
<text class="value">{{ item.goods.skuInfo.goods_price }}</text> |
|||
</view> |
|||
<view class="stepper"> |
|||
<u-number-box :min="1" :value="item.goods_num" :step="1" @change="onChangeStepper($event, item)" /> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- 购物车数据为空 --> |
|||
<empty v-if="!list.length" :isLoading="isLoading" :custom-style="{ padding: '180rpx 50rpx' }" tips="您的购物车是空的, 快去逛逛吧"> |
|||
<view slot="slot" class="empty-ipt" @click="onTargetIndex"> |
|||
<text>去逛逛</text> |
|||
</view> |
|||
</empty> |
|||
<!-- 底部操作栏 --> |
|||
<view v-if="list.length" class="footer-fixed"> |
|||
<label class="all-radio" @click="handleCheckAll"> |
|||
<radio class="radio" color="#fa2209" :checked="checkedIds.length > 0 && checkedIds.length === list.length" /> |
|||
<text>全选</text> |
|||
</label> |
|||
<view class="total-info"> |
|||
<text>合计:</text> |
|||
<view class="goods-price"> |
|||
<text class="unit">¥</text> |
|||
<text class="value">{{ totalPrice }}</text> |
|||
</view> |
|||
</view> |
|||
<view class="cart-action"> |
|||
<view class="btn-wrapper"> |
|||
<!-- dev:下面的disabled条件使用checkedIds.join方式判断 --> |
|||
<!-- dev:通常情况下vue项目使用checkedIds.length更合理, 但是length属性在微信小程序中不起作用 --> |
|||
<view v-if="mode == 'normal'" class="btn-item btn-main" :class="{ disabled: checkedIds.join() == '' }" @click="handleOrder()"> |
|||
<text>去结算 {{ checkedIds.length > 0 ? `(${checkedIds.length})` : '' }}</text> |
|||
</view> |
|||
<view v-if="mode == 'edit'" class="btn-item btn-main" :class="{ disabled: !checkedIds.length }" @click="handleDelete()"> |
|||
<text>删除</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { inArray, arrayIntersect, debounce } from '@/utils/util' |
|||
import { checkLogin, setCartTotalNum, setCartTabBadge } from '@/core/app' |
|||
import * as CartApi from '@/api/cart' |
|||
import Empty from '@/components/empty' |
|||
|
|||
const CartIdsIndex = 'CartIds' |
|||
|
|||
export default { |
|||
components: { |
|||
Empty |
|||
}, |
|||
data() { |
|||
return { |
|||
inArray, |
|||
// 正在加载 |
|||
isLoading: true, |
|||
// 当前模式: normal正常 edit编辑 |
|||
mode: 'normal', |
|||
// 购物车商品列表 |
|||
list: [], |
|||
// 购物车商品总数量 |
|||
total: null, |
|||
// 选中的商品ID记录 |
|||
checkedIds: [], |
|||
// 选中的商品总金额 |
|||
totalPrice: '0.00' |
|||
} |
|||
}, |
|||
watch: { |
|||
// 监听选中的商品 |
|||
checkedIds: { |
|||
handler(val) { |
|||
// 计算合计金额 |
|||
this.onCalcTotalPrice() |
|||
// 记录到缓存中 |
|||
uni.setStorageSync(CartIdsIndex, val) |
|||
}, |
|||
immediate: false |
|||
}, |
|||
// 监听购物车商品总数量 |
|||
total(val) { |
|||
// 缓存并设置角标 |
|||
setCartTotalNum(val) |
|||
setCartTabBadge() |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面显示 |
|||
*/ |
|||
onShow(options) { |
|||
// 获取购物车商品列表 |
|||
checkLogin() ? this.getCartList() : this.isLoading = false |
|||
// 获取缓存中的选中记录 |
|||
this.checkedIds = uni.getStorageSync(CartIdsIndex) |
|||
}, |
|||
|
|||
methods: { |
|||
|
|||
// 计算合计金额 (根据选中的商品) |
|||
onCalcTotalPrice() { |
|||
const app = this |
|||
// 选中的商品记录 |
|||
const checkedList = app.list.filter(item => inArray(item.id, app.checkedIds)) |
|||
// 计算总金额 |
|||
let tempPrice = 0; |
|||
checkedList.forEach(item => { |
|||
// 商品单价, 为了方便计算先转换单位为分 (整数) |
|||
const unitPrice = item.goods.skuInfo.goods_price * 100 |
|||
tempPrice += unitPrice * item.goods_num |
|||
}) |
|||
app.totalPrice = (tempPrice / 100).toFixed(2) |
|||
}, |
|||
|
|||
// 获取购物车商品列表 |
|||
getCartList() { |
|||
const app = this |
|||
app.isLoading = true |
|||
CartApi.list() |
|||
.then(result => { |
|||
app.list = result.data.list |
|||
app.total = result.data.cartTotal |
|||
// 清除checkedIds中无效的ID |
|||
app.onClearInvalidId() |
|||
}) |
|||
.finally(() => app.isLoading = false) |
|||
}, |
|||
|
|||
// 清除checkedIds中无效的ID |
|||
onClearInvalidId() { |
|||
const app = this |
|||
const listIds = app.list.map(item => item.id) |
|||
app.checkedIds = arrayIntersect(listIds, app.checkedIds) |
|||
}, |
|||
|
|||
// 切换当前模式 |
|||
handleToggleMode() { |
|||
this.mode = this.mode == 'normal' ? 'edit' : 'normal' |
|||
}, |
|||
|
|||
// 监听步进器更改事件 |
|||
onChangeStepper({ value }, item) { |
|||
// 这里是组织首次启动时的执行 |
|||
if (item.goods_num == value) return |
|||
// 记录一个节流函数句柄 |
|||
if (!item.debounceHandle) { |
|||
item.oldValue = item.goods_num |
|||
item.debounceHandle = debounce(this.onUpdateCartNum, 500) |
|||
} |
|||
// 更新商品数量 |
|||
item.goods_num = value |
|||
// 提交更新购物车数量 (节流) |
|||
item.debounceHandle(item, item.oldValue, value) |
|||
}, |
|||
|
|||
// 提交更新购物车数量 |
|||
onUpdateCartNum(item, oldValue, newValue) { |
|||
const app = this |
|||
CartApi.update(item.goods_id, item.goods_sku_id, newValue) |
|||
.then(result => { |
|||
// 更新商品数量 |
|||
app.total = result.data.cartTotal |
|||
// 重新计算合计金额 |
|||
app.onCalcTotalPrice() |
|||
// 清除节流函数句柄 |
|||
item.debounceHandle = null |
|||
}) |
|||
.catch(err => { |
|||
// 还原商品数量 |
|||
item.goods_num = oldValue |
|||
setTimeout(() => app.$toast(err.errMsg), 10) |
|||
}) |
|||
}, |
|||
|
|||
// 跳转到商品详情页 |
|||
onTargetGoods(goodsId) { |
|||
this.$navTo('pages/goods/detail', { goodsId }) |
|||
}, |
|||
|
|||
// 点击去逛逛按钮, 跳转到首页 |
|||
onTargetIndex() { |
|||
this.$navTo('pages/index/index') |
|||
}, |
|||
|
|||
// 选中商品 |
|||
handleCheckItem(cartId) { |
|||
const { checkedIds } = this |
|||
const index = checkedIds.findIndex(id => id === cartId) |
|||
index < 0 ? checkedIds.push(cartId) : checkedIds.splice(index, 1) |
|||
}, |
|||
|
|||
// 全选事件 |
|||
handleCheckAll() { |
|||
const { checkedIds, list } = this |
|||
this.checkedIds = checkedIds.length === list.length ? [] : list.map(item => item.id) |
|||
}, |
|||
|
|||
// 结算选中的商品 |
|||
handleOrder() { |
|||
const app = this |
|||
if (app.checkedIds.length) { |
|||
const cartIds = app.checkedIds.join() |
|||
app.$navTo('pages/checkout/index', { mode: 'cart', cartIds }) |
|||
} |
|||
}, |
|||
|
|||
// 删除选中的商品弹窗事件 |
|||
handleDelete() { |
|||
const app = this |
|||
if (!app.checkedIds.length) { |
|||
return false |
|||
} |
|||
uni.showModal({ |
|||
title: '友情提示', |
|||
content: '您确定要删除该商品吗?', |
|||
showCancel: true, |
|||
success({ confirm }) { |
|||
// 确认删除 |
|||
confirm && app.onClearCart() |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
// 确认删除商品 |
|||
onClearCart() { |
|||
const app = this |
|||
CartApi.clear(app.checkedIds) |
|||
.then(result => { |
|||
app.getCartList() |
|||
app.handleToggleMode() |
|||
}) |
|||
} |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
page { |
|||
background: #f5f5f5; |
|||
} |
|||
</style> |
|||
<style lang="scss" scoped> |
|||
// 页面顶部 |
|||
.head-info { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 4rpx 30rpx; |
|||
// background-color: #fff; |
|||
height: 80rpx; |
|||
|
|||
.cart-total { |
|||
font-size: 28rpx; |
|||
color: #333; |
|||
|
|||
.active { |
|||
color: #FA2209; |
|||
margin: 0 2rpx; |
|||
} |
|||
} |
|||
|
|||
.cart-edit { |
|||
padding-left: 20rpx; |
|||
|
|||
.icon { |
|||
margin-right: 12rpx; |
|||
} |
|||
|
|||
.edit { |
|||
color: #fa2209; |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
// 购物车列表 |
|||
.cart-list { |
|||
padding: 0 16rpx 110rpx 16rpx; |
|||
} |
|||
|
|||
.cart-item { |
|||
background: #fff; |
|||
border-radius: 12rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 30rpx 16rpx; |
|||
margin-bottom: 24rpx; |
|||
|
|||
|
|||
.item-radio { |
|||
width: 56rpx; |
|||
height: 80rpx; |
|||
line-height: 80rpx; |
|||
margin-right: 10rpx; |
|||
text-align: center; |
|||
|
|||
.radio { |
|||
transform: scale(0.76) |
|||
} |
|||
} |
|||
|
|||
.goods-image { |
|||
width: 200rpx; |
|||
height: 200rpx; |
|||
|
|||
.image { |
|||
display: block; |
|||
width: 100%; |
|||
height: 100%; |
|||
border-radius: 8rpx; |
|||
} |
|||
} |
|||
|
|||
.item-content { |
|||
flex: 1; |
|||
padding-left: 24rpx; |
|||
|
|||
.goods-title { |
|||
font-size: 28rpx; |
|||
max-height: 76rpx; |
|||
} |
|||
|
|||
.goods-props { |
|||
margin-top: 14rpx; |
|||
height: 40rpx; |
|||
color: #ababab; |
|||
font-size: 24rpx; |
|||
overflow: hidden; |
|||
|
|||
.goods-props-item { |
|||
display: inline-block; |
|||
margin-right: 14rpx; |
|||
padding: 4rpx 16rpx; |
|||
border-radius: 12rpx; |
|||
background-color: #F5F5F5; |
|||
width: auto; |
|||
} |
|||
} |
|||
|
|||
|
|||
.item-foot { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-top: 20rpx; |
|||
|
|||
.goods-price { |
|||
vertical-align: bottom; |
|||
color: $uni-text-color-active; |
|||
|
|||
.unit { |
|||
font-size: 24rpx; |
|||
} |
|||
|
|||
.value { |
|||
font-size: 32rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
// 空数据按钮 |
|||
.empty-ipt { |
|||
width: 220rpx; |
|||
margin: 0 auto; |
|||
font-size: 32rpx; |
|||
height: 64rpx; |
|||
line-height: 64rpx; |
|||
text-align: center; |
|||
color: #fff; |
|||
border-radius: 50rpx; |
|||
background: linear-gradient(to right, #f9211c, #ff6335); |
|||
} |
|||
|
|||
// 底部操作栏 |
|||
.footer-fixed { |
|||
display: flex; |
|||
align-items: center; |
|||
height: 96rpx; |
|||
background: #fff; |
|||
padding: 0 30rpx; |
|||
position: fixed; |
|||
bottom: var(--window-bottom); |
|||
left: 0; |
|||
right: 0; |
|||
z-index: 11; |
|||
|
|||
.all-radio { |
|||
width: 140rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
|
|||
.radio { |
|||
margin-bottom: -4rpx; |
|||
transform: scale(0.76) |
|||
} |
|||
} |
|||
|
|||
.total-info { |
|||
flex: 1; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: flex-end; |
|||
padding-right: 30rpx; |
|||
|
|||
.goods-price { |
|||
vertical-align: bottom; |
|||
color: #fa2209; |
|||
|
|||
.unit { |
|||
font-size: 24rpx; |
|||
} |
|||
|
|||
.value { |
|||
font-size: 32rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.cart-action { |
|||
width: 200rpx; |
|||
|
|||
.btn-wrapper { |
|||
height: 100%; |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
.btn-item { |
|||
flex: 1; |
|||
font-size: 28rpx; |
|||
height: 72rpx; |
|||
line-height: 72rpx; |
|||
text-align: center; |
|||
color: #fff; |
|||
border-radius: 50rpx; |
|||
} |
|||
|
|||
// 立即购买按钮 |
|||
.btn-main { |
|||
background: linear-gradient(to right, #f9211c, #ff6335); |
|||
|
|||
// 禁用按钮 |
|||
&.disabled { |
|||
background: #ff9779; |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
} |
|||
</style> |
|||
@ -1,402 +0,0 @@ |
|||
<template> |
|||
<view class="container"> |
|||
<!-- 一级分类 --> |
|||
<scroll-view class="cate-left" :scroll-y="true" :style="{ height: `${scrollHeight}px` }" @touchmove.stop.prevent> |
|||
<text class="type-nav" :class="{ selected: curIndex == -1 }" @click="handleSelectNav(-1)">全部</text> |
|||
<text class="type-nav" :class="{ selected: curIndex == index }" v-for="(item, index) in list" :key="index" @click="handleSelectNav(index)">{{ item.name }}</text> |
|||
</scroll-view> |
|||
|
|||
<mescroll-body ref="mescrollRef" :sticky="true" @init="mescrollInit" :down="{ use: false }" :up="upOption" :bottombar="false" @up="upCallback"> |
|||
|
|||
<view class="cate-content"> |
|||
|
|||
<!-- 子分类 --> |
|||
<view v-if="subCateList.length" class="sub-cate-list clearfix" :class="{ 'display-fold': !showSubCate }" @touchmove.stop.prevent> |
|||
<view class="nav-icon" @click="handleShowSubCate"> |
|||
<text class="iconfont" :class="[ showSubCate ? 'icon-arrow-up' : 'icon-arrow-down' ]"></text> |
|||
</view> |
|||
<view class="sub-cate-item" :class="{ selected: curIndex2 == -1 }" @click="handleSelectSubCate(-1)"> |
|||
<text>全部</text> |
|||
</view> |
|||
<view class="sub-cate-item" v-for="(item, index) in subCateList" :key="index" :class="{ selected: curIndex2 == index }" @click="handleSelectSubCate(index)"> |
|||
<text>{{ item.name }}</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 商品列表 --> |
|||
<view class="goods-list"> |
|||
<view class="goods-item--container" v-for="(item, index) in goodsList.data" :key="index"> |
|||
<view class="goods-item" @click="onTargetGoods(item.goods_id)"> |
|||
<!-- 商品图片 --> |
|||
<view class="goods-item_left"> |
|||
<image class="image" :src="item.goods_image"></image> |
|||
</view> |
|||
<view class="goods-item_right"> |
|||
<!-- 商品标题 --> |
|||
<view class="goods-name"> |
|||
<text class="twoline-hide">{{ item.goods_name }}</text> |
|||
</view> |
|||
<!-- 商品信息 --> |
|||
<view class="goods-item_desc"> |
|||
<view class="desc_footer"> |
|||
<view class="item-prices oneline-hide"> |
|||
<text class="price_x">¥{{ item.goods_price_min }}</text> |
|||
<text v-if="item.line_price_min > 0" class="price_y">¥{{ item.line_price_min }}</text> |
|||
</view> |
|||
<add-cart-btn v-if="setting.showAddCart" :btnStyle="setting.cartStyle" @click="handleAddCart(item)" /> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- 遮罩层 --> |
|||
<view class="mask" v-show="showSubCate" @touchmove.stop.prevent @click="handleShowSubCate"></view> |
|||
<!-- 加入购物车组件 --> |
|||
<AddCartPopup ref="AddCartPopup" @addCart="onUpdateCartTabBadge" /> |
|||
|
|||
</view> |
|||
</mescroll-body> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import MescrollBody from '@/components/mescroll-uni/mescroll-body.vue' |
|||
import MescrollMixin from '@/components/mescroll-uni/mescroll-mixins' |
|||
import { getEmptyPaginateObj, getMoreListData, setCartTabBadge } from '@/core/app' |
|||
import { PageCategoryStyleEnum } from '@/common/enum/store/page/category' |
|||
import Empty from '@/components/empty' |
|||
import AddCartBtn from '@/components/add-cart-btn' |
|||
import AddCartPopup from '@/components/add-cart-popup' |
|||
import { rpx2px } from '@/utils/util' |
|||
import * as GoodsApi from '@/api/goods' |
|||
|
|||
const pageSize = 15 |
|||
|
|||
export default { |
|||
components: { |
|||
MescrollBody, |
|||
Empty, |
|||
AddCartBtn, |
|||
AddCartPopup |
|||
}, |
|||
mixins: [MescrollMixin], |
|||
props: { |
|||
// 分类列表 |
|||
list: { |
|||
type: Array, |
|||
default: [] |
|||
}, |
|||
// 分类设置 |
|||
setting: { |
|||
type: Object, |
|||
default: () => {} |
|||
}, |
|||
}, |
|||
data() { |
|||
return { |
|||
// 枚举类 |
|||
PageCategoryStyleEnum, |
|||
// 列表高度 |
|||
scrollHeight: 0, |
|||
// 一级分类:指针 |
|||
curIndex: -1, |
|||
// 是否显示子分类 |
|||
showSubCate: false, |
|||
// 二级分类:指针 |
|||
curIndex2: -1, |
|||
// 商品列表 |
|||
goodsList: getEmptyPaginateObj(), |
|||
// 上拉加载配置 |
|||
upOption: { |
|||
// 首次自动执行 |
|||
auto: true, |
|||
// 每页数据的数量; 默认10 |
|||
page: { size: pageSize }, |
|||
// 数量要大于3条才显示无更多数据 |
|||
noMoreSize: 3, |
|||
// 返回顶部 |
|||
toTop: { right: 30, bottom: 48, zIndex: 9 } |
|||
} |
|||
} |
|||
}, |
|||
created() { |
|||
// 设置分类列表高度 |
|||
this.setListHeight() |
|||
}, |
|||
computed: { |
|||
// 二级分类列表 |
|||
subCateList() { |
|||
if (this.list[this.curIndex] && this.list[this.curIndex].children) { |
|||
return this.list[this.curIndex].children |
|||
} |
|||
return [] |
|||
} |
|||
}, |
|||
methods: { |
|||
|
|||
/** |
|||
* 上拉加载的回调 (页面初始化时也会执行一次) |
|||
* 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10 |
|||
* @param {Object} page |
|||
*/ |
|||
upCallback(page) { |
|||
const app = this |
|||
// 设置列表数据 |
|||
app.getGoodsList(page.num) |
|||
.then(list => { |
|||
const curPageLen = list.data.length |
|||
const totalSize = list.data.total |
|||
app.mescroll.endBySize(curPageLen, totalSize) |
|||
}) |
|||
.catch(() => app.mescroll.endErr()) |
|||
}, |
|||
|
|||
/** |
|||
* 获取商品列表 |
|||
* @param {Number} pageNo 页码 |
|||
*/ |
|||
getGoodsList(pageNo = 1) { |
|||
const app = this |
|||
const categoryId = app.getCategoryId() |
|||
return new Promise((resolve, reject) => { |
|||
GoodsApi.list({ categoryId, page: pageNo }, { load: false }) |
|||
.then(result => { |
|||
const newList = result.data.list |
|||
app.goodsList.data = getMoreListData(newList, app.goodsList, pageNo) |
|||
app.goodsList.last_page = newList.last_page |
|||
resolve(newList) |
|||
}) |
|||
.catch(reject) |
|||
}) |
|||
}, |
|||
|
|||
// 获取当前选择的分类ID |
|||
getCategoryId() { |
|||
const app = this |
|||
if (app.curIndex2 > -1) { |
|||
return app.subCateList[app.curIndex2].category_id |
|||
} |
|||
return app.curIndex > -1 ? app.list[app.curIndex].category_id : 0 |
|||
}, |
|||
|
|||
// 设置列表内容的高度 |
|||
setListHeight() { |
|||
const { windowHeight } = uni.getSystemInfoSync() |
|||
this.scrollHeight = windowHeight - rpx2px(88) |
|||
}, |
|||
|
|||
// 一级分类:选中分类 |
|||
handleSelectNav(index) { |
|||
this.curIndex = index |
|||
this.onRefreshList() |
|||
this.showSubCate = false |
|||
this.curIndex2 = -1 |
|||
}, |
|||
|
|||
// 二级分类:选中分类 |
|||
handleSelectSubCate(index) { |
|||
this.curIndex2 = index |
|||
this.showSubCate = false |
|||
this.onRefreshList() |
|||
}, |
|||
|
|||
// 刷新列表数据 |
|||
onRefreshList() { |
|||
this.goodsList = getEmptyPaginateObj() |
|||
setTimeout(() => this.mescroll.resetUpScroll(), 120) |
|||
}, |
|||
|
|||
// 跳转至商品列表页 |
|||
onTargetGoods(goodsId) { |
|||
this.$navTo('pages/goods/detail', { goodsId }) |
|||
}, |
|||
|
|||
// 点击加入购物车 |
|||
handleAddCart(item) { |
|||
this.$refs.AddCartPopup.handle(item) |
|||
}, |
|||
|
|||
// 更新购物车角标 |
|||
onUpdateCartTabBadge() { |
|||
console.log('onUpdateCartTabBadge') |
|||
setCartTabBadge() |
|||
}, |
|||
|
|||
// 切换子分类显示状态 |
|||
handleShowSubCate() { |
|||
this.showSubCate = !this.showSubCate |
|||
} |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.container { |
|||
padding-left: 173rpx; |
|||
} |
|||
|
|||
// 分类内容 |
|||
.cate-content { |
|||
z-index: 1; |
|||
background: #fff; |
|||
padding-top: 88rpx; |
|||
min-height: 300rpx; |
|||
} |
|||
|
|||
// 一级分类+二级分类 20 |
|||
.cate-left { |
|||
position: fixed; |
|||
top: calc(88rpx + var(--window-top)); |
|||
left: var(--window-left); |
|||
bottom: var(--window-bottom); |
|||
width: 173rpx; |
|||
height: 100%; |
|||
background: #f8f8f8; |
|||
color: #444; |
|||
} |
|||
|
|||
// 左侧一级分类 |
|||
.type-nav { |
|||
position: relative; |
|||
height: 90rpx; |
|||
z-index: 10; |
|||
display: block; |
|||
font-size: 26rpx; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
|
|||
&.selected { |
|||
background: #fff; |
|||
border-right: none; |
|||
font-size: 28rpx; |
|||
color: #fa2209; |
|||
} |
|||
} |
|||
|
|||
// 商品列表 |
|||
.goods-list { |
|||
background: #fff; |
|||
position: relative; |
|||
} |
|||
|
|||
.goods-item { |
|||
padding: 28rpx 22rpx; |
|||
display: flex; |
|||
} |
|||
|
|||
.goods-item_left { |
|||
position: relative; |
|||
background: #fff; |
|||
margin-right: 20rpx; |
|||
|
|||
.image { |
|||
display: block; |
|||
width: 180rpx; |
|||
height: 180rpx; |
|||
} |
|||
} |
|||
|
|||
.goods-item_right { |
|||
position: relative; |
|||
flex: 1; |
|||
|
|||
.goods-name { |
|||
display: block; |
|||
width: 100%; |
|||
min-height: 68rpx; |
|||
font-size: 28rpx; |
|||
line-height: 1.3; |
|||
color: #333; |
|||
} |
|||
} |
|||
|
|||
.goods-item_desc { |
|||
margin-top: 20rpx; |
|||
|
|||
.people { |
|||
margin-right: 14rpx; |
|||
} |
|||
|
|||
.desc_footer { |
|||
width: 100%; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
position: absolute; |
|||
right: 0rpx; |
|||
bottom: 0rpx; |
|||
min-height: 44rpx; |
|||
|
|||
.item-prices { |
|||
padding-right: 6rpx; |
|||
|
|||
.price_x { |
|||
margin-right: 14rpx; |
|||
color: rgb(240, 60, 60); |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
.price_y { |
|||
color: #999; |
|||
text-decoration: line-through; |
|||
font-size: 24rpx; |
|||
} |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
|
|||
// 子分类 |
|||
.sub-cate-list { |
|||
background-color: #fff; |
|||
width: 100%; |
|||
z-index: 9; |
|||
padding: 8rpx 40rpx 0 14rpx; |
|||
overflow: hidden; |
|||
position: sticky; |
|||
top: calc(88rpx + var(--window-top)); |
|||
|
|||
&.display-fold { |
|||
height: 86rpx; |
|||
} |
|||
|
|||
.nav-icon { |
|||
position: absolute; |
|||
right: 16rpx; |
|||
top: 12rpx; |
|||
font-size: 32rpx; |
|||
} |
|||
|
|||
.sub-cate-item { |
|||
float: left; |
|||
background: #f8f8f8; |
|||
padding: 10rpx 30rpx; |
|||
margin-right: 22rpx; |
|||
margin-bottom: 24rpx; |
|||
font-size: 26rpx; |
|||
border-radius: 14rpx; |
|||
border: 1rpx solid #f8f8f8; |
|||
|
|||
&.selected { |
|||
color: #fa2209; |
|||
border: 1rpx solid #fa2209; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 子分类遮罩层 |
|||
.mask { |
|||
position: absolute; |
|||
top: 0; |
|||
bottom: 0; |
|||
right: 0; |
|||
left: 0; |
|||
z-index: 8; |
|||
background-color: rgba(0, 0, 0, 0.4); |
|||
transition: all 0.3s ease-in-out 0s; |
|||
} |
|||
</style> |
|||
@ -1,110 +0,0 @@ |
|||
<template> |
|||
<view class="primary"> |
|||
<!-- 一级分类(大图) 10 --> |
|||
<view v-if="list.length > 0 && display == PageCategoryStyleEnum.ONE_LEVEL_BIG.value" class="cate-content"> |
|||
<view class="cate-wrapper cate_style__10 clearfix"> |
|||
<view class="cate-item" v-for="(item, index) in list" :key="index" @click="onTargetGoodsList(item.category_id)"> |
|||
<image v-if="item.image" class="image" mode="widthFix" :src="item.image.preview_url"></image> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- 一级分类(小图) 11 --> |
|||
<view v-if="list.length > 0 && display == PageCategoryStyleEnum.ONE_LEVEL_SMALL.value" class="cate-content"> |
|||
<view class="cate-wrapper cate_style__11 clearfix"> |
|||
<view class="cate-item" v-for="(item, index) in list" :key="index" @click="onTargetGoodsList(item.category_id)"> |
|||
<image v-if="item.image" class="image" mode="widthFix" :src="item.image.preview_url"></image> |
|||
<view class="cate-name">{{ item.name }}</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<empty v-if="!list.length" :tips="'亲,暂无商品分类' + display" /> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { PageCategoryStyleEnum } from '@/common/enum/store/page/category' |
|||
import Empty from '@/components/empty' |
|||
|
|||
export default { |
|||
components: { |
|||
Empty |
|||
}, |
|||
props: { |
|||
// 分类页样式 |
|||
display: { |
|||
type: Number, |
|||
default: 10 |
|||
}, |
|||
// 分类列表 |
|||
list: { |
|||
type: Array, |
|||
default: [] |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
// 枚举类 |
|||
PageCategoryStyleEnum, |
|||
} |
|||
}, |
|||
|
|||
methods: { |
|||
|
|||
// 跳转至商品列表页 |
|||
onTargetGoodsList(categoryId) { |
|||
this.$navTo('pages/goods/list', { categoryId }) |
|||
} |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
// 分类内容 |
|||
.cate-content { |
|||
z-index: 1; |
|||
background: #fff; |
|||
padding-top: 96rpx; |
|||
|
|||
.cate-wrapper { |
|||
padding: 0 20rpx 20rpx 20rpx; |
|||
box-sizing: border-box; |
|||
} |
|||
} |
|||
|
|||
// 一级分类(大图) 10 |
|||
.cate_style__10 .cate-item { |
|||
margin-bottom: 20rpx; |
|||
|
|||
&:last-child { |
|||
margin-bottom: 0; |
|||
} |
|||
|
|||
.image { |
|||
display: block; |
|||
width: 100%; |
|||
height: auto; |
|||
} |
|||
} |
|||
|
|||
// 一级分类(小图) 11 |
|||
.cate_style__11 .cate-item { |
|||
float: left; |
|||
padding: 25rpx; |
|||
width: 33.3333%; |
|||
text-align: center; |
|||
box-sizing: border-box; |
|||
|
|||
.image { |
|||
display: block; |
|||
width: 100%; |
|||
height: 33vw; |
|||
margin-bottom: 12rpx; |
|||
} |
|||
|
|||
.cate-name { |
|||
font-size: 28rpx; |
|||
color: #555; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,180 +0,0 @@ |
|||
<template> |
|||
<view v-if="list.length > 0" class="secondary"> |
|||
<!-- 二级分类 20 --> |
|||
<view class="cate-content"> |
|||
<!-- 左侧 一级分类 --> |
|||
<scroll-view class="cate-left" :scroll-y="true" :style="{ height: `${scrollHeight}px` }"> |
|||
<text class="type-nav" :class="{ selected: curIndex == index }" v-for="(item, index) in list" :key="index" |
|||
@click="handleSelectNav(index)">{{ item.name }}</text> |
|||
</scroll-view> |
|||
<!-- 右侧 二级分类 --> |
|||
<scroll-view class="cate-right" :scroll-top="scrollTop" :scroll-y="true" :style="{ height: `${scrollHeight}px` }"> |
|||
<view v-if="list[curIndex]" class="cate-right-cont"> |
|||
<view class="cate-two-box"> |
|||
<view class="cate-cont-box"> |
|||
<view class="flex-three" v-for="(item, idx) in list[curIndex].children" :key="idx" @click="onTargetGoodsList(item.category_id)"> |
|||
<view class="cate-img-padding"> |
|||
<view v-if="item.image" class="cate-img"> |
|||
<image class="image" mode="scaleToFill" :src="item.image.preview_url"></image> |
|||
</view> |
|||
</view> |
|||
<text class="name oneline-hide">{{ item.name }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</scroll-view> |
|||
</view> |
|||
<empty v-if="!list.length" /> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { PageCategoryStyleEnum } from '@/common/enum/store/page/category' |
|||
import Empty from '@/components/empty' |
|||
import { rpx2px } from '@/utils/util' |
|||
|
|||
export default { |
|||
components: { |
|||
Empty |
|||
}, |
|||
props: { |
|||
// 分类列表 |
|||
list: { |
|||
type: Array, |
|||
default: [] |
|||
}, |
|||
}, |
|||
data() { |
|||
return { |
|||
// 枚举类 |
|||
PageCategoryStyleEnum, |
|||
// 列表高度 |
|||
scrollHeight: 0, |
|||
// 一级分类:指针 |
|||
curIndex: 0, |
|||
// 内容区竖向滚动条位置 |
|||
scrollTop: 0, |
|||
} |
|||
}, |
|||
created() { |
|||
// 设置分类列表高度 |
|||
this.setListHeight() |
|||
}, |
|||
methods: { |
|||
|
|||
// 设置列表内容的高度 |
|||
setListHeight() { |
|||
const { windowHeight } = uni.getSystemInfoSync() |
|||
this.scrollHeight = windowHeight - rpx2px(96) |
|||
}, |
|||
|
|||
// 一级分类:选中分类 |
|||
handleSelectNav(index) { |
|||
this.curIndex = index |
|||
this.scrollTop = 0 |
|||
}, |
|||
|
|||
// 跳转至商品列表页 |
|||
onTargetGoodsList(categoryId) { |
|||
this.$navTo('pages/goods/list', { categoryId }) |
|||
} |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
// 分类内容 |
|||
.cate-content { |
|||
display: flex; |
|||
z-index: 1; |
|||
background: #fff; |
|||
padding-top: 96rpx; |
|||
} |
|||
|
|||
// 一级分类+二级分类 20 |
|||
.cate-left { |
|||
height: 100%; |
|||
display: flex; |
|||
flex-direction: column; |
|||
flex: 0 0 23%; |
|||
background: #f8f8f8; |
|||
color: #444; |
|||
} |
|||
|
|||
.cate-right { |
|||
display: flex; |
|||
flex-direction: column; |
|||
height: 100%; |
|||
overflow: hidden; |
|||
|
|||
.cate-right-cont { |
|||
width: 100%; |
|||
display: flex; |
|||
flex-flow: row wrap; |
|||
align-content: flex-start; |
|||
padding-top: 15rpx; |
|||
|
|||
.cate-two-box { |
|||
width: 100%; |
|||
padding: 0 10px; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 左侧一级分类 |
|||
.type-nav { |
|||
position: relative; |
|||
height: 90rpx; |
|||
z-index: 10; |
|||
display: block; |
|||
font-size: 26rpx; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
|
|||
&.selected { |
|||
background: #fff; |
|||
color: #fa2209; |
|||
border-right: none; |
|||
font-size: 28rpx; |
|||
} |
|||
} |
|||
|
|||
// 右侧二级分类 |
|||
.cate-cont-box { |
|||
margin-bottom: 30rpx; |
|||
padding-bottom: 10rpx; |
|||
background: #fff; |
|||
overflow: hidden; |
|||
|
|||
.name { |
|||
display: block; |
|||
padding-bottom: 30rpx; |
|||
text-align: center; |
|||
font-size: 26rpx; |
|||
color: #444444; |
|||
} |
|||
|
|||
.cate-img-padding { |
|||
padding: 16rpx 16rpx 4rpx 16rpx; |
|||
} |
|||
|
|||
.cate-img { |
|||
position: relative; |
|||
width: 100%; |
|||
padding-top: 100%; |
|||
|
|||
.image { |
|||
width: 100%; |
|||
height: 100%; |
|||
position: absolute; |
|||
top: 0; |
|||
left: 0; |
|||
border-radius: 10rpx; |
|||
} |
|||
} |
|||
|
|||
} |
|||
</style> |
|||
@ -1,165 +0,0 @@ |
|||
<template> |
|||
<view class="container"> |
|||
<!-- 搜索框 --> |
|||
<search class="search" tips="搜索商品" @event="$navTo('pages/search/index')" /> |
|||
|
|||
<!-- 一级分类 --> |
|||
<primary v-if="setting.style == PageCategoryStyleEnum.ONE_LEVEL_BIG.value || setting.style == PageCategoryStyleEnum.ONE_LEVEL_SMALL.value" |
|||
:display="setting.style" :list="list" /> |
|||
|
|||
<!-- 二级分类 --> |
|||
<secondary v-if="setting.style == PageCategoryStyleEnum.TWO_LEVEL.value" :list="list" /> |
|||
|
|||
<!-- 分类+商品 --> |
|||
<commodity v-if="setting.style == PageCategoryStyleEnum.COMMODITY.value" ref="mescrollItem" :list="list" :setting="setting" /> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import MescrollCompMixin from '@/components/mescroll-uni/mixins/mescroll-comp' |
|||
import { setCartTabBadge } from '@/core/app' |
|||
import SettingKeyEnum from '@/common/enum/setting/Key' |
|||
import { PageCategoryStyleEnum } from '@/common/enum/store/page/category' |
|||
import SettingModel from '@/common/model/Setting' |
|||
import * as CategoryApi from '@/api/category' |
|||
import Empty from '@/components/empty' |
|||
import Search from '@/components/search' |
|||
import Primary from './components/primary' |
|||
import Secondary from './components/secondary' |
|||
import Commodity from './components/commodity' |
|||
|
|||
// 最后一次刷新时间 |
|||
let lastRefreshTime; |
|||
|
|||
export default { |
|||
components: { |
|||
Search, |
|||
Empty, |
|||
Primary, |
|||
Secondary, |
|||
Commodity |
|||
}, |
|||
mixins: [MescrollCompMixin], |
|||
data() { |
|||
return { |
|||
// 枚举类 |
|||
PageCategoryStyleEnum, |
|||
// 分类列表 |
|||
list: [], |
|||
// 分类模板设置 |
|||
setting: {}, |
|||
// 正在加载中 |
|||
isLoading: true |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
onLoad() { |
|||
// 加载页面数据 |
|||
this.onRefreshPage() |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面显示 |
|||
*/ |
|||
onShow() { |
|||
// 每间隔5分钟自动刷新一次页面数据 |
|||
const curTime = new Date().getTime() |
|||
if ((curTime - lastRefreshTime) > 5 * 60 * 1000) { |
|||
this.onRefreshPage() |
|||
} |
|||
}, |
|||
methods: { |
|||
|
|||
// 刷新页面 |
|||
onRefreshPage() { |
|||
// 记录刷新时间 |
|||
lastRefreshTime = new Date().getTime() |
|||
// 获取页面数据 |
|||
this.getPageData() |
|||
// 更新购物车角标 |
|||
setCartTabBadge() |
|||
}, |
|||
|
|||
// 获取页面数据 |
|||
getPageData() { |
|||
const app = this |
|||
app.isLoading = true |
|||
Promise.all([ |
|||
// 获取分类模板设置 |
|||
// 优化建议: 可以将此处的false改为true 启用缓存 |
|||
SettingModel.data(false), |
|||
// 获取分类列表 |
|||
CategoryApi.list() |
|||
]) |
|||
.then(result => { |
|||
// 初始化分类模板设置 |
|||
app.initSetting(result[0]) |
|||
// 初始化分类列表数据 |
|||
app.initCategory(result[1]) |
|||
}) |
|||
.finally(() => app.isLoading = false) |
|||
}, |
|||
|
|||
/** |
|||
* 初始化分类模板设置 |
|||
* @param {Object} result |
|||
*/ |
|||
initSetting(setting) { |
|||
this.setting = setting[SettingKeyEnum.PAGE_CATEGORY_TEMPLATE.value] |
|||
}, |
|||
|
|||
/** |
|||
* 初始化分类列表数据 |
|||
* @param {Object} result |
|||
*/ |
|||
initCategory(result) { |
|||
this.list = result.data.list |
|||
}, |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 设置分享内容 |
|||
*/ |
|||
onShareAppMessage() { |
|||
const app = this |
|||
return { |
|||
title: _this.templet.shareTitle, |
|||
path: '/pages/category/index?' + app.$getShareUrlParams() |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 分享到朋友圈 |
|||
* 本接口为 Beta 版本,暂只在 Android 平台支持,详见分享到朋友圈 (Beta) |
|||
* https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share-timeline.html |
|||
*/ |
|||
onShareTimeline() { |
|||
const app = this |
|||
return { |
|||
title: _this.templet.shareTitle, |
|||
path: '/pages/category/index?' + app.$getShareUrlParams() |
|||
} |
|||
} |
|||
|
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
page { |
|||
background: #fff; |
|||
} |
|||
</style> |
|||
<style lang="scss" scoped> |
|||
// 搜索框 |
|||
.search { |
|||
position: fixed; |
|||
top: var(--window-top); |
|||
left: var(--window-left); |
|||
right: var(--window-right); |
|||
z-index: 9; |
|||
} |
|||
</style> |
|||
@ -1,523 +0,0 @@ |
|||
<template> |
|||
<view class="container p-bottom" v-if="order.goodsList.length"> |
|||
|
|||
<!-- 快递配送:配送地址 --> |
|||
<view v-if="curDelivery == DeliveryTypeEnum.EXPRESS.value" @click="onSelectAddress" class="flow-delivery"> |
|||
<view class="flow-delivery__detail dis-flex flex-y-center"> |
|||
<view class="detail-location dis-flex"> |
|||
<text class="iconfont icon-dingwei"></text> |
|||
</view> |
|||
<view class="detail-content flex-box"> |
|||
<block v-if="order.address"> |
|||
<view class="detail-content__title dis-flex"> |
|||
<text class="f-30">{{ order.address.name }}</text> |
|||
<text class="detail-content__title-phone f-28">{{ order.address.phone }}</text> |
|||
</view> |
|||
<view class="address detail-content__describe"> |
|||
<text class="region" v-for="(region, idx) in order.address.region" :key="idx">{{ region }}</text> |
|||
<text class="detail">{{ order.address.detail }}</text> |
|||
</view> |
|||
</block> |
|||
<block v-else> |
|||
<view class="detail-content__describe dis-flex"> |
|||
<text class="col-6">请选择配送地址</text> |
|||
</view> |
|||
</block> |
|||
</view> |
|||
<view class="detail-arrow dis-flex"> |
|||
<text class="iconfont icon-arrow-right"></text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 商品列表 --> |
|||
<view class="m-top20"> |
|||
<view class="checkout_list" v-for="(item, index) in order.goodsList" :key="index"> |
|||
<view class="flow-shopList dis-flex" data-index="index" @click="onTargetGoods(item.goods_id)"> |
|||
<!-- 商品图片 --> |
|||
<view class="flow-list-left"> |
|||
<image mode="scaleToFill" :src="item.goods_image"></image> |
|||
</view> |
|||
<view class="flow-list-right flex-box"> |
|||
<!-- 商品名称 --> |
|||
<text class="goods-name twoline-hide">{{ item.goods_name }}</text> |
|||
<!-- 商品规格 --> |
|||
<view class="goods-props clearfix"> |
|||
<view class="goods-props-item" v-for="(props, idx) in item.skuInfo.goods_props" :key="idx"> |
|||
<text class="group-name">{{ props.group.name }}: </text> |
|||
<text>{{ props.value.name }};</text> |
|||
</view> |
|||
</view> |
|||
<!-- 商品数量和单价 --> |
|||
<view class="flow-list-cont dis-flex flex-x-between flex-y-center"> |
|||
<text class="small">×{{ item.total_num }}</text> |
|||
<text class="flow-cont" :class="[item.is_user_grade ? 'price-delete' : '']">¥{{ item.goods_price }}</text> |
|||
</view> |
|||
<!-- 会员折扣价 --> |
|||
<view v-if="item.is_user_grade" class="grade-price"> |
|||
<text>会员折扣价:¥{{ item.grade_goods_price }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view class="flow-num-box b-f"> |
|||
<text>共{{ order.orderTotalNum }}件商品,合计:</text> |
|||
<text class="flow-money col-m">¥{{ order.orderTotalPrice }}</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 商品金额 --> |
|||
<view class="flow-all-money b-f m-top20"> |
|||
<view class="flow-all-list dis-flex"> |
|||
<text class="flex-five">订单总金额:</text> |
|||
<view class="flex-five t-r"> |
|||
<text class="col-m">¥{{ order.orderTotalPrice }}</text> |
|||
</view> |
|||
</view> |
|||
<!-- 优惠券 --> |
|||
<view class="flow-all-list dis-flex"> |
|||
<text class="flex-five">优惠券:</text> |
|||
<view class="flex-five t-r"> |
|||
<view v-if="order.couponList.length > 0" @click="handleShowPopup()"> |
|||
<text class="col-m" v-if="order.couponId > 0">-¥{{ order.couponMoney }}</text> |
|||
<text class="col-m" v-else>有{{ order.couponList.length }}张优惠券</text> |
|||
<text class="right-arrow iconfont icon-arrow-right"></text> |
|||
</view> |
|||
<text v-else class="">无优惠券可用</text> |
|||
</view> |
|||
</view> |
|||
<!-- 积分抵扣 --> |
|||
<view v-if="order.isAllowPoints" class="points flow-all-list dis-flex flex-y-center"> |
|||
<view class="block-left flex-five" @click="handleShowPoints()"> |
|||
<text class="title">可用{{ setting.points_name }}抵扣:</text> |
|||
<text class="iconfont icon-help"></text> |
|||
</view> |
|||
<view class="flex-five dis-flex flex-x-end flex-y-center"> |
|||
<text class="points-money col-m">-¥{{ order.pointsMoney }}</text> |
|||
<u-switch v-model="isUsePoints" size="48" active-color="#07c160" @change="getOrderData()"></u-switch> |
|||
</view> |
|||
</view> |
|||
<!-- 配送费用 --> |
|||
<view v-if="curDelivery == DeliveryTypeEnum.EXPRESS.value" class="dis-flex flow-all-list"> |
|||
<text class="flex-five">配送费用:</text> |
|||
<view class="flex-five t-r"> |
|||
<view v-if="order.address"> |
|||
<text class="col-m" v-if="order.isIntraRegion">+¥{{ order.expressPrice }}</text> |
|||
<text v-else>不在配送范围</text> |
|||
</view> |
|||
<view v-else> |
|||
<text class="col-7">请先选择配送地址</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 支付方式 --> |
|||
<view class="pay-method flow-all-money b-f m-top20"> |
|||
<view class="flow-all-list dis-flex"> |
|||
<text class="flex-five">支付方式</text> |
|||
</view> |
|||
<!-- 微信支付 --> |
|||
<!-- #ifdef MP-WEIXIN --> |
|||
<view class="pay-item dis-flex flex-x-between" @click="handleSelectPayType(PayTypeEnum.WECHAT.value)"> |
|||
<view class="item-left dis-flex flex-y-center"> |
|||
<view class="item-left_icon wechat"> |
|||
<text class="iconfont icon-wechat-pay"></text> |
|||
</view> |
|||
<view class="item-left_text"> |
|||
<text>{{ PayTypeEnum.WECHAT.name }}</text> |
|||
</view> |
|||
</view> |
|||
<view class="item-right col-m" v-if="curPayType == PayTypeEnum.WECHAT.value"> |
|||
<text class="iconfont icon-check"></text> |
|||
</view> |
|||
</view> |
|||
<!-- #endif --> |
|||
<!-- 余额支付 --> |
|||
<view class="pay-item dis-flex flex-x-between" @click="handleSelectPayType(PayTypeEnum.BALANCE.value)"> |
|||
<view class="item-left dis-flex flex-y-center"> |
|||
<view class="item-left_icon balance"> |
|||
<text class="iconfont icon-balance-pay"></text> |
|||
</view> |
|||
<view class="item-left_text"> |
|||
<text>{{ PayTypeEnum.BALANCE.name }}</text> |
|||
</view> |
|||
<view class="user-balance"> |
|||
<text>(可用¥{{ personal.balance }}元)</text> |
|||
</view> |
|||
</view> |
|||
<view class="item-right col-m" v-if="curPayType == PayTypeEnum.BALANCE.value"> |
|||
<text class="iconfont icon-check"></text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 买家留言 --> |
|||
<view class="flow-all-money b-f m-top20"> |
|||
<view class="ipt-wrapper dis-flex flow-all-list"> |
|||
<input v-model="remark" placeholder="选填:买家留言(50字以内)"></input> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 提交订单 --> |
|||
<view class="flow-fixed-footer b-f m-top10"> |
|||
<view class="dis-flex chackout-box"> |
|||
<view class="chackout-left pl-12">实付款: |
|||
<text class="col-m">¥{{ order.orderPayPrice }}</text> |
|||
</view> |
|||
<view class="chackout-right" @click="onSubmitOrder()"> |
|||
<view class="flow-btn f-32" :class="{ disabled }">提交订单</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 积分说明弹窗 --> |
|||
<u-modal v-model="showPoints" :title="`${setting.points_name}说明`"> |
|||
<scroll-view class="points-content" :scroll-y="true"> |
|||
<text>{{ setting.points_describe }}</text> |
|||
</scroll-view> |
|||
</u-modal> |
|||
|
|||
<!-- 优惠券弹出框 --> |
|||
<u-popup v-model="showPopup" mode="bottom"> |
|||
<view class="popup__coupon"> |
|||
<view class="coupon__title f-30">选择优惠券</view> |
|||
<!-- 优惠券列表 --> |
|||
<view class="coupon-list"> |
|||
<scroll-view :scroll-y="true" style="height: 565rpx;"> |
|||
<view class="coupon-item" v-for="(item, index) in order.couponList" :key="index"> |
|||
<view class="item-wrapper" |
|||
:class="[item.is_apply ? 'color-' + CouponColors[index % CouponColors.length] : 'color-gray']" |
|||
@click="handleSelectCoupon(index)"> |
|||
<view class="coupon-type">{{ CouponTypeEnum[item.coupon_type].name }}</view> |
|||
<view class="tip dis-flex flex-dir-column flex-x-center"> |
|||
<view v-if="item.coupon_type == CouponTypeEnum.FULL_DISCOUNT.value"> |
|||
<text class="f-30">¥</text> |
|||
<text class="money">{{ item.reduce_price }}</text> |
|||
</view> |
|||
<text class="money" |
|||
v-if="item.coupon_type == CouponTypeEnum.DISCOUNT.value">{{ item.discount }}折</text> |
|||
<text class="pay-line">满{{ item.min_price }}元可用</text> |
|||
</view> |
|||
<view class="split-line"></view> |
|||
<view class="content dis-flex flex-dir-column flex-x-between"> |
|||
<view class="title">{{ item.name }}</view> |
|||
<view class="bottom dis-flex flex-y-center"> |
|||
<view class="time flex-box"> |
|||
<block v-if="item.start_time === item.end_time">{{ item.start_time }}</block> |
|||
<block v-else>{{ item.start_time }}~{{ item.end_time }}</block> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</scroll-view> |
|||
</view> |
|||
<!-- 不使用优惠券 --> |
|||
<view class="coupon__do_not dis-flex flex-y-center flex-x-center"> |
|||
<view class="control dis-flex flex-y-center flex-x-center" @click="handleNotUseCoupon()"> |
|||
<text class="f-26">不使用优惠券</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</u-popup> |
|||
|
|||
</view> |
|||
|
|||
</template> |
|||
|
|||
<script> |
|||
import * as Verify from '@/utils/verify' |
|||
import * as CheckoutApi from '@/api/checkout' |
|||
import { CouponTypeEnum } from '@/common/enum/coupon' |
|||
import DeliveryTypeEnum from '@/common/enum/order/DeliveryType' |
|||
import PayTypeEnum from '@/common/enum/order/PayType' |
|||
import { wxPayment } from '@/core/app' |
|||
|
|||
const CouponColors = ['red', 'blue', 'violet', 'yellow'] |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
// 枚举类 |
|||
DeliveryTypeEnum, |
|||
PayTypeEnum, |
|||
CouponTypeEnum, |
|||
// 当前页面参数 |
|||
options: {}, |
|||
// 优惠券颜色组 |
|||
CouponColors, |
|||
// 当前选中的配送方式 |
|||
curDelivery: null, |
|||
// 当前选中的支付方式 |
|||
curPayType: PayTypeEnum.BALANCE.value, |
|||
// 选择的优惠券 |
|||
selectCouponId: 0, |
|||
// 是否使用积分抵扣 |
|||
isUsePoints: false, |
|||
// 买家留言 |
|||
remark: '', |
|||
// 禁用submit按钮 |
|||
disabled: false, |
|||
// 是否显示积分说明 |
|||
showPoints: false, |
|||
// 是否显示优惠券弹窗 |
|||
showPopup: false, |
|||
// 按钮禁用 |
|||
disabled: false, |
|||
// 订单信息 (从后端api中获取) |
|||
order: { |
|||
// 商品列表 |
|||
goodsList: [], |
|||
// 优惠券列表 |
|||
couponList: [], |
|||
// 是否存在收货地址 |
|||
existAddress: false, |
|||
// 默认收货地址 |
|||
address: null, |
|||
// 是否存在收货地址 |
|||
existAddress: false, |
|||
// 当前用户收货城市是否存在配送规则中 |
|||
isIntraRegion: true, |
|||
// 是否存在错误 |
|||
hasError: false, |
|||
// 错误信息 |
|||
errorMsg: '' |
|||
}, |
|||
// 个人信息 |
|||
personal: {}, |
|||
// 商城设置 |
|||
setting: {} |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
onLoad(options) { |
|||
this.options = options |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面显示 |
|||
*/ |
|||
onShow() { |
|||
// 获取当前订单信息 |
|||
this.getOrderData() |
|||
}, |
|||
|
|||
methods: { |
|||
|
|||
// 获取订单数据 |
|||
getOrderData() { |
|||
const app = this |
|||
// 请求的参数 |
|||
const params = { |
|||
delivery: app.curDelivery || 0, |
|||
couponId: app.selectCouponId || 0, |
|||
isUsePoints: app.isUsePoints ? 1 : 0, |
|||
} |
|||
// 请求api |
|||
CheckoutApi.order(app.options.mode, app.getRequestParam()) |
|||
.then(result => { |
|||
app.initData(result.data) |
|||
}) |
|||
.catch(err => err) |
|||
}, |
|||
|
|||
// 初始化数据 |
|||
initData({ order, setting, personal }) { |
|||
const app = this |
|||
app.order = order |
|||
app.personal = personal |
|||
app.setting = setting |
|||
// 显示错误信息 |
|||
if (order.hasError) { |
|||
app.$toast(order.errorMsg) |
|||
} |
|||
// 当前选择的配送方式 |
|||
app.curDelivery = order.delivery |
|||
// 如果只有一种配送方式则不显示选项卡 |
|||
app.isShowTab = setting.deliveryType.length > 1 |
|||
// 当前选择支付方式 (如果是微信小程序默认使用微信支付) |
|||
if (app.$platform === 'MP-WEIXIN') { |
|||
app.curPayType = PayTypeEnum.WECHAT.value |
|||
} |
|||
}, |
|||
|
|||
// 获取api请求的参数 |
|||
getRequestParam() { |
|||
const app = this |
|||
const { options } = app |
|||
// 结算模式的固定参数 |
|||
const modeParam = {} |
|||
// 结算模式: 立即购买 |
|||
if (options.mode === 'buyNow') { |
|||
modeParam.goodsId = options.goodsId |
|||
modeParam.goodsNum = options.goodsNum |
|||
modeParam.goodsSkuId = options.goodsSkuId |
|||
} |
|||
// 结算模式: 购物车 |
|||
if (options.mode === 'cart') { |
|||
modeParam.cartIds = options.cartIds |
|||
} |
|||
// 订单结算参数(用户选择) |
|||
const orderParam = { |
|||
delivery: app.curDelivery || 0, |
|||
couponId: app.selectCouponId || 0, |
|||
isUsePoints: app.isUsePoints ? 1 : 0, |
|||
} |
|||
return { ...orderParam, ...modeParam } |
|||
}, |
|||
|
|||
// 显示积分说明 |
|||
handleShowPoints() { |
|||
this.showPoints = true |
|||
}, |
|||
|
|||
// 显示优惠券弹窗 |
|||
handleShowPopup() { |
|||
this.showPopup = true |
|||
}, |
|||
|
|||
// 选择优惠券 |
|||
handleSelectCoupon(index) { |
|||
const app = this |
|||
const { couponList } = app.order |
|||
// 当前选择的优惠券 |
|||
const couponItem = couponList[index] |
|||
// 判断是否在适用范围 |
|||
if (!couponItem.is_apply) { |
|||
app.$toast(couponItem.not_apply_info) |
|||
return |
|||
} |
|||
// 记录选中的优惠券id |
|||
app.selectCouponId = couponItem.user_coupon_id |
|||
// 重新获取订单信息 |
|||
app.getOrderData() |
|||
// 隐藏优惠券弹层 |
|||
app.showPopup = false |
|||
}, |
|||
|
|||
// 不使用优惠券 |
|||
handleNotUseCoupon() { |
|||
const app = this |
|||
app.selectCouponId = 0 |
|||
// 重新获取订单信息 |
|||
app.getOrderData() |
|||
// 隐藏优惠券弹层 |
|||
app.showPopup = false |
|||
}, |
|||
|
|||
// 选择支付方式 |
|||
handleSelectPayType(value) { |
|||
this.curPayType = value |
|||
}, |
|||
|
|||
// 快递配送:选择收货地址 |
|||
onSelectAddress() { |
|||
this.$navTo('pages/address/index', { from: 'checkout' }) |
|||
}, |
|||
|
|||
// 跳转到商品详情页 |
|||
onTargetGoods(goodsId) { |
|||
this.$navTo('pages/goods/detail', { goodsId }) |
|||
}, |
|||
|
|||
// 订单提交 |
|||
onSubmitOrder() { |
|||
const app = this |
|||
if (app.disabled) { |
|||
return false |
|||
} |
|||
// 表单验证 |
|||
if (!app.onVerifyFrom()) { |
|||
return false |
|||
} |
|||
// 按钮禁用 |
|||
app.disabled = true |
|||
// 请求api |
|||
CheckoutApi.submit(app.options.mode, app.getFormData()) |
|||
.then(result => app.onSubmitCallback(result)) |
|||
.catch(err => { |
|||
if (err.result) { |
|||
const errData = err.result.data |
|||
if (errData.is_created) { |
|||
app.navToMyOrder() |
|||
return false |
|||
} |
|||
} |
|||
app.disabled = false |
|||
}) |
|||
}, |
|||
|
|||
// 订单提交成功后回调 |
|||
onSubmitCallback(result) { |
|||
const app = this |
|||
// 发起微信支付 |
|||
if (result.data.payType == PayTypeEnum.WECHAT.value) { |
|||
wxPayment(result.data.payment) |
|||
.then(() => app.$success('支付成功')) |
|||
.catch(err => app.$error('订单未支付')) |
|||
.finally(() => { |
|||
app.disabled = false |
|||
app.navToMyOrder() |
|||
}) |
|||
} |
|||
// 余额支付 |
|||
if (result.data.payType == PayTypeEnum.BALANCE.value) { |
|||
app.$success('支付成功') |
|||
app.disabled = false |
|||
app.navToMyOrder() |
|||
} |
|||
}, |
|||
|
|||
// 跳转到我的订单(等待1秒) |
|||
navToMyOrder() { |
|||
setTimeout(() => { |
|||
this.$navTo('pages/order/index') |
|||
}, 1000) |
|||
}, |
|||
|
|||
// 表单提交的数据 |
|||
getFormData() { |
|||
const app = this |
|||
const { options } = app |
|||
// 表单数据 |
|||
const form = { |
|||
delivery: app.curDelivery, |
|||
payType: app.curPayType, |
|||
couponId: app.selectCouponId || 0, |
|||
isUsePoints: app.isUsePoints ? 1 : 0, |
|||
remark: app.remark || '', |
|||
} |
|||
// 创建订单-立即购买 |
|||
if (options.mode === 'buyNow') { |
|||
form.goodsId = options.goodsId |
|||
form.goodsNum = options.goodsNum |
|||
form.goodsSkuId = options.goodsSkuId |
|||
} |
|||
// 创建订单-购物车结算 |
|||
if (options.mode === 'cart') { |
|||
form.cartIds = options.cartIds || null |
|||
} |
|||
return form |
|||
}, |
|||
|
|||
// 表单验证 |
|||
onVerifyFrom() { |
|||
const app = this |
|||
if (app.hasError) { |
|||
app.$toast(app.errorMsg) |
|||
return false |
|||
} |
|||
return true |
|||
}, |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
@import "./style.scss"; |
|||
</style> |
|||
@ -1,445 +0,0 @@ |
|||
|
|||
// 配送信息 |
|||
.flow-delivery { |
|||
padding: 34rpx 30rpx; |
|||
background: #fff url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANYAAAANCAYAAADVGpDCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA4ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo3Yjk4M2ExYy1jMDhkLTQ1OTktYTI0Ny1kZjNjYzdiYTQ5ZTgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDQwNkY3RkU5N0NGMTFFNUI3N0M4NTU4MzM2RjlFODIiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDQwNkY3RkQ5N0NGMTFFNUI3N0M4NTU4MzM2RjlFODIiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowNzgwZWI1NS03OGFhLTQzOTUtODQ4OC1lOWI5YmVlYTY1ZDciIHN0UmVmOmRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDo1OTRiYzUyMy1jMzc3LTExNzgtYTdkZS04NGY3YmM1ZGIxMDMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz556PLxAAACBElEQVR42tyaSyhEYRTHP48imlKibDQeSSlkSlEWLCRFsZNH5FE2FqQ8ErIRC9lIkTwXSpMkWWChhEJCSnlkoUZGSsr78f98n43CMFPu/Z/6NZuZ2zn33/+cb869XkmLx8IDEQaGQJbgiytQDSY3MyL+LYnL/HxPXSoHDIJQQq2WQQk4Dbbb/yUB29LJ+6e3B66VB3ZITbUIEqSpCGoJBP1ghtBUD6ARpEtTGSEhXzd+awE9oJzQUPegWdf3QlBPMhgDMYRa7YNisGWkpP5qrBQtVBShUHugUE9hs4fUtwG0utlEjRivoA/Ug1sj3vjffr8FNJEK1auPFHcE9UTq5pdK2PwcoAzMG7mjuRrRYEIfK9jiDJSCBZJ6ynSTsBBqNQ0qgdPISbq6vJCFbJOaagrEk5gqWNczRGiqG1Ah1LLMafRkf5pYIUKtZnMJDXUNasAIST2ZYFioRx9ssQaKwJFZEv5uYmWDXVJTrYBEElP562PfPKGpnkAbSDOTqb6aWAGgW6iHol5kQj2CdtAJngnqkc1hHMQRNr9DPaXWzZj8Z2PZtFCxhEIdaKE2CGqRJ4060AH8CLUaALX6f5VpBZLhI9SaeZXQVHKNLt84SCIxVbhQi5YuQlNd6OVElZlN9TGxrGBUn2PZ4lyoTdIsST0FQj0UDSLUak6ot3gcBLVY3wQYAJoVXxmNERajAAAAAElFTkSuQmCC') bottom left repeat-x; |
|||
background-size: 120rpx auto; |
|||
|
|||
.detail-location { |
|||
font-size: 36rpx; |
|||
} |
|||
.detail-content { |
|||
padding: 0 20rpx; |
|||
.detail-content__title-phone { |
|||
margin-left: 10rpx; |
|||
} |
|||
.detail-content__describe { |
|||
font-size: 28rpx; |
|||
color: #777; |
|||
} |
|||
} |
|||
.detail-content__title { |
|||
margin-bottom: 6rpx; |
|||
} |
|||
} |
|||
|
|||
// 买家留言 |
|||
.flow-all-money { |
|||
.ipt-wrapper { |
|||
input { |
|||
font-size: 28rpx; |
|||
width: 100%; |
|||
height: 75rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 商品列表 |
|||
.checkout_list { |
|||
padding: 20rpx 30rpx 4rpx 30rpx; |
|||
background: #fff; |
|||
border-bottom: 1rpx solid rgb(248, 248, 248); |
|||
.flow-shopList { |
|||
padding: 5rpx 0 10rpx; |
|||
border-bottom: 1rpx solid rgb(248, 248, 248); |
|||
&:last-child { |
|||
border-bottom: 0; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.flow-header-left { |
|||
padding-left: 90rpx; |
|||
} |
|||
|
|||
/* 会员价 */ |
|||
.flow-shopList { |
|||
|
|||
.flow-list-right { |
|||
.flow-cont { |
|||
|
|||
&.price-delete { |
|||
font-size: 26rpx; |
|||
color: #777; |
|||
text-decoration: line-through; |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
.grade-price { |
|||
padding-top: 8rpx; |
|||
font-size: 28rpx; |
|||
color: #ff495e; |
|||
text-align: right; |
|||
} |
|||
|
|||
.goods-name{ |
|||
font-size: 28rpx; |
|||
color: #333; |
|||
} |
|||
|
|||
} |
|||
|
|||
/* 优惠券选择 */ |
|||
.popup__coupon { |
|||
width: 750rpx; |
|||
background: #fff; |
|||
box-sizing: border-box; |
|||
padding: 30rpx; |
|||
|
|||
.coupon__do_not { |
|||
.control { |
|||
width: 90%; |
|||
height: 72rpx; |
|||
margin-bottom: 24rpx; |
|||
color: #888; |
|||
border: 1rpx solid #e3e3e3; |
|||
border-radius: 10rpx; |
|||
/* #ifdef H5 */ |
|||
max-width: 1120rpx; |
|||
/* #endif */ |
|||
} |
|||
} |
|||
|
|||
.coupon__title { |
|||
text-align: center; |
|||
margin-bottom: 30rpx; |
|||
} |
|||
|
|||
.coupon-list { |
|||
/* #ifdef H5 */ |
|||
max-width: 1120rpx; |
|||
margin: 0 auto; |
|||
/* #endif */ |
|||
} |
|||
|
|||
.coupon-item { |
|||
overflow: hidden; |
|||
margin-bottom: 22rpx; |
|||
} |
|||
|
|||
.item-wrapper { |
|||
width: 100%; |
|||
display: flex; |
|||
background: #fff; |
|||
border-radius: 8rpx; |
|||
color: #fff; |
|||
height: 180rpx; |
|||
|
|||
.coupon-type { |
|||
position: absolute; |
|||
top: 0; |
|||
right: 0; |
|||
z-index: 10; |
|||
width: 128rpx; |
|||
padding: 6rpx 0; |
|||
background: #a771ff; |
|||
font-size: 20rpx; |
|||
text-align: center; |
|||
color: #ffffff; |
|||
transform: rotate(45deg); |
|||
transform-origin: 64rpx 64rpx; |
|||
} |
|||
|
|||
&.color-blue { |
|||
background: linear-gradient(-125deg, #57bdbf, #2f9de2); |
|||
} |
|||
|
|||
&.color-red { |
|||
background: linear-gradient(-128deg, #ff6d6d, #ff3636); |
|||
} |
|||
|
|||
&.color-violet { |
|||
background: linear-gradient(-113deg, #ef86ff, #b66ff5); |
|||
|
|||
.coupon-type { |
|||
background: #55b5ff; |
|||
} |
|||
} |
|||
|
|||
&.color-yellow { |
|||
background: linear-gradient(-141deg, #f7d059, #fdb054); |
|||
} |
|||
|
|||
&.color-gray { |
|||
background: linear-gradient(-113deg, #bdbdbd, #a2a1a2); |
|||
|
|||
.coupon-type { |
|||
background: #9e9e9e; |
|||
} |
|||
} |
|||
|
|||
.content { |
|||
flex: 1; |
|||
padding: 30rpx 20rpx; |
|||
border-radius: 16rpx 0 0 16rpx; |
|||
|
|||
.title { |
|||
font-size: 32rpx; |
|||
} |
|||
|
|||
.bottom { |
|||
.time { |
|||
font-size: 24rpx; |
|||
} |
|||
|
|||
.receive { |
|||
height: 46rpx; |
|||
width: 122rpx; |
|||
line-height: 46rpx; |
|||
text-align: center; |
|||
border: 1rpx solid #fff; |
|||
border-radius: 30rpx; |
|||
color: #fff; |
|||
font-size: 24rpx; |
|||
|
|||
&.state { |
|||
border: none; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.tip { |
|||
position: relative; |
|||
flex: 0 0 32%; |
|||
text-align: center; |
|||
border-radius: 0 16rpx 16rpx 0; |
|||
|
|||
.money { |
|||
font-weight: bold; |
|||
font-size: 52rpx; |
|||
} |
|||
|
|||
.pay-line { |
|||
font-size: 22rpx; |
|||
} |
|||
} |
|||
|
|||
.split-line { |
|||
position: relative; |
|||
flex: 0 0 0; |
|||
border-left: 4rpx solid #fff; |
|||
margin: 0 10rpx 0 6rpx; |
|||
background: #fff; |
|||
|
|||
&:before, |
|||
{ |
|||
border-radius: 0 0 16rpx 16rpx; |
|||
top: 0; |
|||
} |
|||
|
|||
&:after { |
|||
border-radius: 16rpx 16rpx 0 0; |
|||
bottom: 0; |
|||
} |
|||
|
|||
&:before, |
|||
&:after { |
|||
content: ''; |
|||
position: absolute; |
|||
width: 24rpx; |
|||
height: 12rpx; |
|||
background: #f7f7f7; |
|||
left: -14rpx; |
|||
z-index: 1; |
|||
} |
|||
|
|||
|
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
/* 积分抵扣 */ |
|||
.points { |
|||
|
|||
.title { |
|||
margin-right: 5rpx; |
|||
} |
|||
|
|||
.icon-help { |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
.points-money { |
|||
margin-right: 20rpx; |
|||
} |
|||
|
|||
} |
|||
/* 支付方式 */ |
|||
.pay-method { |
|||
|
|||
.pay-item { |
|||
padding: 24rpx 0; |
|||
font-size: 28rpx; |
|||
border-bottom: 1rpx solid rgb(248, 248, 248); |
|||
|
|||
.item-left_icon { |
|||
margin-right: 20rpx; |
|||
font-size: 32rpx; |
|||
|
|||
&.wechat { |
|||
color: #00c800; |
|||
} |
|||
|
|||
&.balance { |
|||
color: #ff9700; |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
.user-balance { |
|||
margin-left: 20rpx; |
|||
font-size: 26rpx; |
|||
// color: #464646; |
|||
} |
|||
|
|||
} |
|||
|
|||
// 商品规格 |
|||
.goods-props { |
|||
padding-top: 10rpx; |
|||
font-size: 24rpx; |
|||
color: #999; |
|||
|
|||
.goods-props-item { |
|||
float: left; |
|||
.group-name { |
|||
margin-right: 6rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 右侧箭头 |
|||
.right-arrow { |
|||
margin-left: 16rpx; |
|||
// color: #777; |
|||
font-size: 26rpx; |
|||
} |
|||
|
|||
// 底部操作栏 |
|||
.flow-fixed-footer { |
|||
position: fixed; |
|||
bottom: var(--window-bottom); |
|||
left: var(--window-left); |
|||
right: var(--window-right); |
|||
// width: 100%; |
|||
background: #fff; |
|||
border-top: 1px solid #eee; |
|||
z-index: 11; |
|||
// 设置ios刘海屏底部横线安全区域 |
|||
padding-bottom: calc(constant(safe-area-inset-bottom) + var(--window-bottom)); |
|||
padding-bottom: calc(env(safe-area-inset-bottom) + var(--window-bottom)); |
|||
|
|||
.chackout-left { |
|||
font-size: 28rpx; |
|||
line-height: 92rpx; |
|||
color: #777; |
|||
flex: 4; |
|||
padding-left: 12px; |
|||
} |
|||
|
|||
.chackout-right { |
|||
font-size: 34rpx; |
|||
flex: 2; |
|||
} |
|||
|
|||
|
|||
// 提交按钮 |
|||
.flow-btn { |
|||
background: linear-gradient(to right, #f9211c, #ff6335); |
|||
color: #fff; |
|||
text-align: center; |
|||
line-height: 92rpx; |
|||
display: block; |
|||
font-size: 28rpx; |
|||
// 禁用按钮 |
|||
&.disabled { |
|||
background: #ff9779; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 积分说明 |
|||
.points-content { |
|||
padding: 30rpx 48rpx; |
|||
font-size: 28rpx; |
|||
line-height: 50rpx; |
|||
text-align: left; |
|||
color: #606266; |
|||
height: 620rpx; |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
/* 共几件商品 */ |
|||
.flow-num-box { |
|||
font-size: 28rpx; |
|||
color: #777; |
|||
padding: 16rpx 24rpx; |
|||
text-align: right; |
|||
} |
|||
|
|||
/* app.scss */ |
|||
.flow-shopList { |
|||
padding: 18rpx 0; |
|||
|
|||
.flow-list-left { |
|||
margin-right: 20rpx; |
|||
|
|||
image { |
|||
width: 180rpx; |
|||
height: 180rpx; |
|||
border: 1rpx solid #eee; |
|||
background: #fff; |
|||
} |
|||
|
|||
} |
|||
|
|||
.flow-list-right { |
|||
|
|||
.flow-cont { |
|||
font-size: 28rpx; |
|||
color: #fa2209; |
|||
} |
|||
|
|||
.small { |
|||
font-size: 26rpx; |
|||
color: #777; |
|||
} |
|||
|
|||
.flow-list-cont { |
|||
padding-top: 10rpx; |
|||
} |
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
.flow-all-money { |
|||
padding: 0 24rpx; |
|||
color: #444; |
|||
|
|||
.flow-all-list { |
|||
font-size: 28rpx; |
|||
padding: 20rpx 0; |
|||
border-bottom: 1rpx solid rgb(248, 248, 248); |
|||
} |
|||
|
|||
.flow-all-list:last-child { |
|||
border-bottom: none; |
|||
} |
|||
|
|||
.flow-all-list-cont { |
|||
font-size: 28rpx; |
|||
padding: 10rpx 0; |
|||
} |
|||
|
|||
.flow-arrow { |
|||
justify-content: flex-end; |
|||
align-items: center; |
|||
} |
|||
|
|||
} |
|||
@ -1,274 +0,0 @@ |
|||
<template> |
|||
<mescroll-body ref="mescrollRef" :sticky="true" @init="mescrollInit" :down="{ use: false }" :up="upOption" @up="upCallback"> |
|||
<!-- tab栏 --> |
|||
<u-tabs :list="tabs" :is-scroll="false" :current="curTab" active-color="#FA2209" :duration="0.2" @change="onChangeTab" /> |
|||
|
|||
<!-- 商品评价列表 --> |
|||
<view class="comment-list"> |
|||
<view class="comment-item" v-for="(item, index) in list.data" :key="index"> |
|||
<view class="item-head"> |
|||
<!-- 用户信息 --> |
|||
<view class="user-info"> |
|||
<avatar-image class="user-avatar" :url="item.user.avatar_url" :width="50" /> |
|||
<text class="user-name f-26">{{ item.user.nick_name }}</text> |
|||
</view> |
|||
<!-- 评星 --> |
|||
<u-rate active-color="#f4a213" :current="rates[item.score]" :disabled="true" /> |
|||
<!-- 评价日期--> |
|||
<view class="flex-box f-22 col-9 t-r">{{ item.create_time }}</view> |
|||
</view> |
|||
<!-- 评价内容 --> |
|||
<view class="item-content m-top20"> |
|||
<text class="f-26">{{ item.content }}</text> |
|||
</view> |
|||
<!-- 评价图片 --> |
|||
<view class="images-list clearfix" v-if="item.images.length"> |
|||
<view class="image-preview" v-for="(image, imgIdx) in item.images" :key="imgIdx"> |
|||
<image class="image" mode="aspectFill" :src="image.image_url" @click="onPreviewImages(index, imgIdx)"></image> |
|||
</view> |
|||
</view> |
|||
<!-- 商品规格 --> |
|||
<view class="goods-props clearfix"> |
|||
<view class="goods-props-item" v-for="(props, idx) in item.orderGoods.goods_props" :key="idx"> |
|||
<text class="group-name">{{ props.group.name }}: </text> |
|||
<text>{{ props.value.name }};</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</mescroll-body> |
|||
</template> |
|||
|
|||
<script> |
|||
import MescrollBody from '@/components/mescroll-uni/mescroll-body.vue' |
|||
import MescrollMixin from '@/components/mescroll-uni/mescroll-mixins' |
|||
import AvatarImage from '@/components/avatar-image' |
|||
import { getEmptyPaginateObj, getMoreListData } from '@/core/app' |
|||
import * as CommentApi from '@/api/comment' |
|||
|
|||
const pageSize = 15 |
|||
const tabs = [{ |
|||
name: `全部`, |
|||
scoreType: -1 |
|||
}, { |
|||
name: `好评`, |
|||
scoreType: 10 |
|||
}, { |
|||
name: `中评`, |
|||
scoreType: 20 |
|||
}, { |
|||
name: `差评`, |
|||
scoreType: 30 |
|||
}] |
|||
|
|||
export default { |
|||
components: { |
|||
MescrollBody, |
|||
AvatarImage |
|||
}, |
|||
mixins: [MescrollMixin], |
|||
data() { |
|||
return { |
|||
// 当前商品ID |
|||
goodsId: null, |
|||
// 当前标签索引 |
|||
curTab: 0, |
|||
// 评价列表数据 |
|||
list: getEmptyPaginateObj(), |
|||
// 评价总数量 |
|||
total: { all: 0, negative: 0, praise: 0, review: 0 }, |
|||
// 评星数据转换 |
|||
rates: { 10: 5, 20: 3, 30: 1 }, |
|||
// 标签栏数据 |
|||
tabs, |
|||
// 上拉加载配置 |
|||
upOption: { |
|||
// 首次自动执行 |
|||
auto: true, |
|||
// 每页数据的数量; 默认10 |
|||
page: { size: pageSize }, |
|||
// 数量要大于4条才显示无更多数据 |
|||
noMoreSize: 4, |
|||
// 空布局 |
|||
empty: { |
|||
tip: '亲,暂无相关商品评价' |
|||
} |
|||
}, |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
onLoad(options) { |
|||
// 记录属性值 |
|||
this.goodsId = options.goodsId |
|||
// 获取指定评分总数 |
|||
this.getTotal() |
|||
}, |
|||
|
|||
methods: { |
|||
|
|||
/** |
|||
* 上拉加载的回调 (页面初始化时也会执行一次) |
|||
* 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10 |
|||
* @param {Object} page |
|||
*/ |
|||
upCallback(page) { |
|||
const app = this |
|||
// 设置列表数据 |
|||
app.getCommentList(page.num) |
|||
.then(list => { |
|||
const curPageLen = list.data.length |
|||
const totalSize = list.data.total |
|||
app.mescroll.endBySize(curPageLen, totalSize) |
|||
}) |
|||
.catch(() => app.mescroll.endErr()) |
|||
}, |
|||
|
|||
// 加载评价列表数据 |
|||
getCommentList(pageNo = 1) { |
|||
const app = this |
|||
return new Promise((resolve, reject) => { |
|||
CommentApi.list(app.goodsId, { scoreType: app.getScoreType(), page: pageNo }, { load: false }) |
|||
.then(result => { |
|||
// 合并新数据 |
|||
const newList = result.data.list |
|||
app.list.data = getMoreListData(newList, app.list, pageNo) |
|||
resolve(newList) |
|||
}) |
|||
}) |
|||
}, |
|||
|
|||
// 评分类型 |
|||
getScoreType() { |
|||
return this.tabs[this.curTab].scoreType |
|||
}, |
|||
|
|||
// 获取指定评分总数 |
|||
getTotal() { |
|||
const app = this |
|||
CommentApi.total(app.goodsId) |
|||
.then(result => { |
|||
// tab标签内容 |
|||
const total = result.data.total |
|||
app.getTabs(total) |
|||
}) |
|||
}, |
|||
|
|||
// 获取tab标签内容 |
|||
getTabs(total) { |
|||
const tabs = this.tabs |
|||
tabs[0].name = `全部(${total.all})` |
|||
tabs[1].name = `好评(${total.praise})` |
|||
tabs[2].name = `中评(${total.review})` |
|||
tabs[3].name = `差评(${total.negative})` |
|||
}, |
|||
|
|||
// 切换标签项 |
|||
onChangeTab(index) { |
|||
const app = this |
|||
// 设置当前选中的标签 |
|||
app.curTab = index |
|||
// 刷新评价列表 |
|||
app.onRefreshList() |
|||
}, |
|||
|
|||
// 刷新评价列表 |
|||
onRefreshList() { |
|||
this.list = getEmptyPaginateObj() |
|||
setTimeout(() => { |
|||
this.mescroll.resetUpScroll() |
|||
}, 120) |
|||
}, |
|||
|
|||
// 预览评价图片 |
|||
onPreviewImages(dataIdx, imgIndex) { |
|||
const app = this |
|||
const images = app.list.data[dataIdx].images |
|||
const imageUrls = images.map(item => item.image_url) |
|||
uni.previewImage({ |
|||
current: imageUrls[imgIndex], |
|||
urls: imageUrls |
|||
}) |
|||
} |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.comment-item { |
|||
padding: 30rpx; |
|||
box-sizing: border-box; |
|||
border-bottom: 1rpx solid #f7f7f7; |
|||
background: #fff; |
|||
} |
|||
|
|||
.item-head { |
|||
display: flex; |
|||
align-items: center; |
|||
|
|||
// 用户信息 |
|||
.user-info { |
|||
margin-right: 15rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
|
|||
.user-avatar { |
|||
margin-right: 15rpx; |
|||
} |
|||
|
|||
.user-name { |
|||
color: #999; |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
// 评价内容 |
|||
.item-content { |
|||
font-size: 30rpx; |
|||
color: #333; |
|||
margin: 16rpx 0; |
|||
} |
|||
|
|||
// 评价图片 |
|||
.images-list { |
|||
&::after { |
|||
clear: both; |
|||
content: " "; |
|||
display: table; |
|||
} |
|||
|
|||
.image-preview { |
|||
float: left; |
|||
margin-bottom: 15rpx; |
|||
margin-right: 15rpx; |
|||
|
|||
&:nth-child(3n+0) { |
|||
margin-right: 0; |
|||
} |
|||
|
|||
.image { |
|||
display: block; |
|||
width: 220rpx; |
|||
height: 220rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 商品规格 |
|||
.goods-props { |
|||
font-size: 24rpx; |
|||
color: #999; |
|||
|
|||
.goods-props-item { |
|||
float: left; |
|||
|
|||
.group-name { |
|||
margin-right: 6rpx; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,250 +0,0 @@ |
|||
<template> |
|||
<view class="container"> |
|||
<view v-if="list.length" class="coupon-list"> |
|||
<view class="coupon-item" v-for="(item, index) in list" :key="index"> |
|||
<view class="item-wrapper" |
|||
:class="[ item.state.value ? 'color-' + color[index % color.length] : 'color-gray' ]"> |
|||
<view class="coupon-type">{{ CouponTypeEnum[item.coupon_type].name }}</view> |
|||
<view class="tip dis-flex flex-dir-column flex-x-center"> |
|||
<view v-if="item.coupon_type == CouponTypeEnum.FULL_DISCOUNT.value"> |
|||
<text class="f-30">¥</text> |
|||
<text class="money">{{ item.reduce_price }}</text> |
|||
</view> |
|||
<text class="money" v-if="item.coupon_type == CouponTypeEnum.DISCOUNT.value">{{ item.discount }}折</text> |
|||
<text class="pay-line">满{{ item.min_price }}元可用</text> |
|||
</view> |
|||
<view class="split-line"></view> |
|||
<view class="content dis-flex flex-dir-column flex-x-between"> |
|||
<view class="title oneline-hide">{{ item.name }}</view> |
|||
<view class="bottom dis-flex flex-y-center"> |
|||
<view class="time flex-box"> |
|||
<text v-if="item.expire_type == 10">领取{{ item.expire_day }}天内有效</text> |
|||
<text v-if="item.expire_type == 20"> |
|||
<block v-if="item.start_time === item.end_time">{{ item.start_time }} 当天有效</block> |
|||
<block v-else>{{ item.start_time }}~{{ item.end_time }}</block> |
|||
</text> |
|||
</view> |
|||
<view class="receive" v-if="item.state.value" @click="receive(item.coupon_id)"> |
|||
<text>立即领取</text> |
|||
</view> |
|||
<view v-else class="receive state"> |
|||
<text>{{ item.state.text }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<empty v-if="!list.length" :isLoading="isLoading" /> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import * as CouponApi from '@/api/coupon' |
|||
import * as MyCouponApi from '@/api/myCoupon' |
|||
import { CouponTypeEnum } from '@/common/enum/coupon' |
|||
import Empty from '@/components/empty' |
|||
|
|||
const color = ['red', 'blue', 'violet', 'yellow'] |
|||
|
|||
export default { |
|||
components: { |
|||
Empty |
|||
}, |
|||
data() { |
|||
return { |
|||
// 枚举类 |
|||
CouponTypeEnum, |
|||
// 颜色组 |
|||
color, |
|||
// 优惠券列表 |
|||
list: [], |
|||
// 正在加载中 |
|||
isLoading: true |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
onLoad(options) { |
|||
// 获取优惠券列表 |
|||
this.getCouponList() |
|||
}, |
|||
|
|||
methods: { |
|||
|
|||
/** |
|||
* 获取优惠券列表 |
|||
* @param {bool} load 是否显示loading弹窗 |
|||
*/ |
|||
getCouponList(load = true) { |
|||
const app = this |
|||
app.isLoading = true |
|||
CouponApi.list({}, { load }) |
|||
.then(result => { |
|||
app.list = result.data.list |
|||
}) |
|||
.finally(() => app.isLoading = false) |
|||
}, |
|||
|
|||
// 立即领取 |
|||
receive(couponId) { |
|||
const app = this |
|||
MyCouponApi.receive(couponId) |
|||
.then(result => { |
|||
// 显示领取成功提示 |
|||
app.$success(result.message) |
|||
// 刷新优惠券列表 |
|||
app.getCouponList(false) |
|||
}) |
|||
} |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.coupon-list { |
|||
padding: 20rpx; |
|||
} |
|||
|
|||
|
|||
.coupon-item { |
|||
position: relative; |
|||
overflow: hidden; |
|||
margin-bottom: 22rpx; |
|||
} |
|||
|
|||
.item-wrapper { |
|||
width: 100%; |
|||
display: flex; |
|||
background: #fff; |
|||
border-radius: 8rpx; |
|||
color: #fff; |
|||
height: 180rpx; |
|||
|
|||
.coupon-type { |
|||
position: absolute; |
|||
top: 0; |
|||
right: 0; |
|||
z-index: 10; |
|||
width: 128rpx; |
|||
padding: 3px 0; |
|||
background: #a771ff; |
|||
font-size: 20rpx; |
|||
text-align: center; |
|||
color: #ffffff; |
|||
transform: rotate(45deg); |
|||
transform-origin: 64rpx 64rpx; |
|||
} |
|||
|
|||
&.color-blue { |
|||
background: linear-gradient(-125deg, #57bdbf, #2f9de2); |
|||
} |
|||
|
|||
&.color-red { |
|||
background: linear-gradient(-128deg, #ff6d6d, #ff3636); |
|||
} |
|||
|
|||
&.color-violet { |
|||
background: linear-gradient(-113deg, #ef86ff, #b66ff5); |
|||
|
|||
.coupon-type { |
|||
background: #55b5ff; |
|||
} |
|||
} |
|||
|
|||
&.color-yellow { |
|||
background: linear-gradient(-141deg, #f7d059, #fdb054); |
|||
} |
|||
|
|||
&.color-gray { |
|||
background: linear-gradient(-113deg, #bdbdbd, #a2a1a2); |
|||
|
|||
.coupon-type { |
|||
background: #9e9e9e; |
|||
} |
|||
} |
|||
|
|||
.content { |
|||
flex: 1; |
|||
padding: 30rpx 20rpx; |
|||
border-radius: 8px 0 0 8px; |
|||
|
|||
.title { |
|||
width: 400rpx; |
|||
font-size: 32rpx; |
|||
} |
|||
|
|||
.bottom { |
|||
.time { |
|||
font-size: 24rpx; |
|||
} |
|||
|
|||
.receive { |
|||
height: 46rpx; |
|||
width: 122rpx; |
|||
line-height: 46rpx; |
|||
text-align: center; |
|||
border: 1px solid #fff; |
|||
border-radius: 30rpx; |
|||
color: #fff; |
|||
font-size: 24rpx; |
|||
|
|||
&.state { |
|||
border: none; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.tip { |
|||
position: relative; |
|||
flex: 0 0 32%; |
|||
text-align: center; |
|||
border-radius: 0 8px 8px 0; |
|||
|
|||
.money { |
|||
font-weight: bold; |
|||
font-size: 52rpx; |
|||
} |
|||
|
|||
.pay-line { |
|||
font-size: 22rpx; |
|||
} |
|||
} |
|||
|
|||
.split-line { |
|||
position: relative; |
|||
flex: 0 0 0; |
|||
border-left: 4rpx solid #fff; |
|||
margin: 0 5px 0 3px; |
|||
background: #fff; |
|||
|
|||
&:before, |
|||
{ |
|||
border-radius: 0 0 16rpx 16rpx; |
|||
top: 0; |
|||
} |
|||
|
|||
&:after { |
|||
border-radius: 16rpx 16rpx 0 0; |
|||
bottom: 0; |
|||
} |
|||
|
|||
&:before, |
|||
&:after { |
|||
content: ''; |
|||
position: absolute; |
|||
width: 24rpx; |
|||
height: 12rpx; |
|||
background: #f7f7f7; |
|||
left: -14rpx; |
|||
z-index: 1; |
|||
} |
|||
|
|||
|
|||
} |
|||
} |
|||
</style> |
|||
@ -1,120 +0,0 @@ |
|||
<template> |
|||
<view class="container"> |
|||
<!-- 店铺页面组件 --> |
|||
<Page :items="items" /> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import * as Api from '@/api/page' |
|||
import Page from '@/components/page' |
|||
|
|||
const App = getApp() |
|||
|
|||
export default { |
|||
components: { |
|||
Page |
|||
}, |
|||
data() { |
|||
return { |
|||
// 页面参数 |
|||
options: {}, |
|||
// 页面属性 |
|||
page: {}, |
|||
// 页面元素 |
|||
items: [] |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
onLoad(options) { |
|||
// 当前页面参数 |
|||
this.options = options |
|||
// 加载页面数据 |
|||
this.getPageData() |
|||
}, |
|||
methods: { |
|||
|
|||
/** |
|||
* 加载页面数据 |
|||
* @param {Object} callback |
|||
*/ |
|||
getPageData(callback) { |
|||
const app = this |
|||
const pageId = app.options.pageId || 0 |
|||
Api.detail(pageId) |
|||
.then(result => { |
|||
// 设置页面数据 |
|||
const { data: { pageData } } = result |
|||
app.page = pageData.page |
|||
app.items = pageData.items |
|||
// 设置顶部导航栏栏 |
|||
app.setPageBar(); |
|||
}) |
|||
.finally(() => callback && callback()) |
|||
}, |
|||
|
|||
/** |
|||
* 设置顶部导航栏 |
|||
*/ |
|||
setPageBar() { |
|||
const { page } = this |
|||
// 设置页面标题 |
|||
uni.setNavigationBarTitle({ |
|||
title: page.params.title |
|||
}) |
|||
// 设置navbar标题、颜色 |
|||
uni.setNavigationBarColor({ |
|||
frontColor: page.style.titleTextColor === 'white' ? '#ffffff' : '#000000', |
|||
backgroundColor: page.style.titleBackgroundColor |
|||
}) |
|||
} |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 下拉刷新 |
|||
*/ |
|||
onPullDownRefresh() { |
|||
// 获取首页数据 |
|||
this.getPageData(() => { |
|||
uni.stopPullDownRefresh() |
|||
}) |
|||
}, |
|||
|
|||
/** |
|||
* 分享当前页面 |
|||
*/ |
|||
onShareAppMessage() { |
|||
const app = this |
|||
const { page } = app |
|||
return { |
|||
title: page.params.share_title, |
|||
path: "/pages/index/index?" + app.$getShareUrlParams() |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 分享到朋友圈 |
|||
* 本接口为 Beta 版本,暂只在 Android 平台支持,详见分享到朋友圈 (Beta) |
|||
* https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share-timeline.html |
|||
*/ |
|||
onShareTimeline() { |
|||
const app = this |
|||
const { page } = app |
|||
return { |
|||
title: page.params.share_title, |
|||
path: "/pages/index/index?" + app.$getShareUrlParams() |
|||
} |
|||
} |
|||
|
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.container { |
|||
background: #fff; |
|||
} |
|||
</style> |
|||
@ -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,158 +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> |
|||
import * as ServiceApi from '@/api/goods/service' |
|||
|
|||
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,173 +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.$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,146 +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 class="swiper-count"> |
|||
<text>{{ currentIndex }}</text> |
|||
<text>/</text> |
|||
<text>{{ images.length + (video ? 1 : 0) }}</text> |
|||
</view> |
|||
</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,227 +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; |
|||
min-width: 214rpx; |
|||
line-height: 1; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-evenly; |
|||
margin-right: 12rpx; |
|||
|
|||
.fast-item { |
|||
position: relative; |
|||
padding: 4rpx 0; |
|||
line-height: 1; |
|||
text-align: center; |
|||
width: 84rpx; |
|||
|
|||
&--cart { |
|||
margin-left: 6rpx; |
|||
.fast-icon { margin-left: -12rpx; } |
|||
} |
|||
|
|||
// 角标 |
|||
.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: 44rpx; |
|||
margin-bottom: 8rpx; |
|||
} |
|||
|
|||
.fast-text { |
|||
font-size: 22rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 操作按钮 |
|||
.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,290 +0,0 @@ |
|||
<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 --> |
|||
<!-- 购物车 --> |
|||
<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> |
|||
</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 * as GoodsApi from '@/api/goods' |
|||
import * as CartApi from '@/api/cart' |
|||
// import Shortcut from '@/components/shortcut' |
|||
import SlideImage from './components/SlideImage' |
|||
import SkuPopup from './components/SkuPopup' |
|||
import Comment from './components/Comment' |
|||
import Service from './components/Service' |
|||
|
|||
export default { |
|||
components: { |
|||
// Shortcut, |
|||
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) => { |
|||
GoodsApi.detail(app.goodsId) |
|||
.then(result => { |
|||
app.goods = result.data.detail |
|||
resolve(result) |
|||
}) |
|||
.catch(reject) |
|||
}) |
|||
}, |
|||
|
|||
// 获取购物车总数量 |
|||
getCartTotal() { |
|||
const app = this |
|||
return new Promise((resolve, reject) => { |
|||
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> |
|||
@ -1,463 +0,0 @@ |
|||
<template> |
|||
<mescroll-body ref="mescrollRef" :sticky="true" @init="mescrollInit" :down="{ native: true }" @down="downCallback" :up="upOption" @up="upCallback"> |
|||
<!-- 页面头部 --> |
|||
<view class="header"> |
|||
<search class="search" :tips="options.search ? options.search : '搜索商品'" @event="handleSearch" /> |
|||
<!-- 切换列表显示方式 --> |
|||
<view class="show-view" @click="handleShowView"> |
|||
<text class="iconfont icon-view-tile" v-if="showView"></text> |
|||
<text class="iconfont icon-view-list" v-else></text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 排序标签 --> |
|||
<view class="store-sort"> |
|||
<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> |
|||
|
|||
<!-- 商品列表 --> |
|||
<view class="goods-list clearfix" :class="['column-' + (showView ? '1' : '2')]"> |
|||
<view class="goods-item" v-for="(item, index) in list.data" :key="index" @click="onTargetDetail(item.goods_id)"> |
|||
<!-- 单列显示 --> |
|||
<view v-if="showView" class="dis-flex"> |
|||
<!-- 商品图片 --> |
|||
<view class="goods-item_left"> |
|||
<image class="image" :src="item.goods_image"></image> |
|||
</view> |
|||
<view class="goods-item_right"> |
|||
<!-- 商品名称 --> |
|||
<view class="goods-name"> |
|||
<text class="twoline-hide">{{ item.goods_name }}</text> |
|||
</view> |
|||
<view class="goods-item_desc"> |
|||
<!-- 商品卖点 --> |
|||
<view class="desc-selling_point dis-flex"> |
|||
<text class="oneline-hide">{{ item.selling_point }}</text> |
|||
</view> |
|||
<!-- 商品销量 --> |
|||
<view class="desc-goods_sales dis-flex"> |
|||
<text>已售{{ item.goods_sales }}件</text> |
|||
</view> |
|||
<!-- 商品价格 --> |
|||
<view class="desc_footer"> |
|||
<text class="price_x">¥{{ item.goods_price_min }}</text> |
|||
<text class="price_y col-9" v-if="item.line_price_min > 0">¥{{ item.line_price_min }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- 多列显示 --> |
|||
<view v-else class=""> |
|||
<!-- 商品图片 --> |
|||
<view class="goods-image"> |
|||
<image class="image" mode="aspectFill" :src="item.goods_image"></image> |
|||
</view> |
|||
<view class="detail"> |
|||
<!-- 商品标题 --> |
|||
<view class="goods-name"> |
|||
<text class="twoline-hide">{{ item.goods_name }}</text> |
|||
</view> |
|||
<!-- 商品价格 --> |
|||
<view class="detail-price oneline-hide"> |
|||
<text class="goods-price f-30 col-m">¥{{ item.goods_price_min }}</text> |
|||
<text v-if="item.line_price_min > 0" class="line-price col-9 f-24">¥{{ item.line_price_min }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</mescroll-body> |
|||
</template> |
|||
|
|||
<script> |
|||
import MescrollBody from '@/components/mescroll-uni/mescroll-body.vue' |
|||
import MescrollMixin from '@/components/mescroll-uni/mescroll-mixins' |
|||
import * as GoodsApi from '@/api/goods' |
|||
import { getEmptyPaginateObj, getMoreListData } from '@/core/app' |
|||
import Search from '@/components/search' |
|||
|
|||
const pageSize = 15 |
|||
const showViewKey = 'GoodsList-ShowView'; |
|||
|
|||
export default { |
|||
components: { |
|||
MescrollBody, |
|||
Search |
|||
}, |
|||
|
|||
mixins: [MescrollMixin], |
|||
|
|||
data() { |
|||
return { |
|||
showView: false, // 列表显示方式 (true列表、false平铺) |
|||
sortType: 'all', // 排序类型 |
|||
sortPrice: false, // 价格排序 (true高到低 false低到高) |
|||
options: {}, // 当前页面参数 |
|||
list: getEmptyPaginateObj(), // 商品列表数据 |
|||
|
|||
// 上拉加载配置 |
|||
upOption: { |
|||
// 首次自动执行 |
|||
auto: true, |
|||
// 每页数据的数量; 默认10 |
|||
page: { size: pageSize }, |
|||
// 数量要大于4条才显示无更多数据 |
|||
noMoreSize: 4, |
|||
} |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
onLoad(options) { |
|||
// 记录options |
|||
this.options = options |
|||
// 设置默认列表显示方式 |
|||
this.setShowView() |
|||
}, |
|||
|
|||
methods: { |
|||
|
|||
/** |
|||
* 上拉加载的回调 (页面初始化时也会执行一次) |
|||
* 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10 |
|||
* @param {Object} page |
|||
*/ |
|||
upCallback(page) { |
|||
const app = this |
|||
// 设置列表数据 |
|||
app.getGoodsList(page.num) |
|||
.then(list => { |
|||
const curPageLen = list.data.length |
|||
const totalSize = list.data.total |
|||
app.mescroll.endBySize(curPageLen, totalSize) |
|||
}) |
|||
.catch(() => app.mescroll.endErr()) |
|||
}, |
|||
|
|||
// 设置默认列表显示方式 |
|||
setShowView() { |
|||
this.showView = uni.getStorageSync(showViewKey) || false |
|||
}, |
|||
|
|||
/** |
|||
* 获取商品列表 |
|||
* @param {number} pageNo 页码 |
|||
*/ |
|||
getGoodsList(pageNo = 1) { |
|||
const app = this |
|||
console.log(app.options) |
|||
const param = { |
|||
sortType: app.sortType, |
|||
sortPrice: Number(app.sortPrice), |
|||
categoryId: app.options.categoryId || 0, |
|||
goodsName: app.options.search || '', |
|||
page: pageNo |
|||
} |
|||
return new Promise((resolve, reject) => { |
|||
GoodsApi.list(param) |
|||
.then(result => { |
|||
// 合并新数据 |
|||
const newList = result.data.list |
|||
app.list.data = getMoreListData(newList, app.list, pageNo) |
|||
resolve(newList) |
|||
}) |
|||
.catch(reject) |
|||
}) |
|||
}, |
|||
|
|||
// 切换排序方式 |
|||
handleSortType(newSortType) { |
|||
const app = this |
|||
const newSortPrice = newSortType === 'price' ? !app.sortPrice : true |
|||
app.sortType = newSortType |
|||
app.sortPrice = newSortPrice |
|||
// 刷新列表数据 |
|||
app.list = getEmptyPaginateObj() |
|||
app.mescroll.resetUpScroll() |
|||
}, |
|||
|
|||
// 切换列表显示方式 |
|||
handleShowView() { |
|||
const app = this |
|||
app.showView = !app.showView |
|||
uni.setStorageSync(showViewKey, app.showView) |
|||
}, |
|||
|
|||
// 跳转商品详情页 |
|||
onTargetDetail(goodsId) { |
|||
this.$navTo('pages/goods/detail', { goodsId }) |
|||
}, |
|||
|
|||
/** |
|||
* 商品搜索 |
|||
*/ |
|||
handleSearch() { |
|||
const searchPageUrl = 'pages/search/index' |
|||
// 判断来源页面 |
|||
let pages = getCurrentPages() |
|||
if (pages.length > 1 && |
|||
pages[pages.length - 2].route === searchPageUrl) { |
|||
uni.navigateBack() |
|||
return |
|||
} |
|||
// 跳转到商品搜索页 |
|||
this.$navTo(searchPageUrl) |
|||
} |
|||
|
|||
}, |
|||
|
|||
|
|||
/** |
|||
* 设置分享内容 |
|||
*/ |
|||
onShareAppMessage() { |
|||
// 构建分享参数 |
|||
return { |
|||
title: "全部分类", |
|||
path: "/pages/category/index?" + this.$getShareUrlParams() |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 分享到朋友圈 |
|||
* 本接口为 Beta 版本,暂只在 Android 平台支持,详见分享到朋友圈 (Beta) |
|||
* https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share-timeline.html |
|||
*/ |
|||
onShareTimeline() { |
|||
// 构建分享参数 |
|||
return { |
|||
title: "全部分类", |
|||
path: "/pages/category/index?" + this.$getShareUrlParams() |
|||
} |
|||
} |
|||
|
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
// 页面头部 |
|||
.header { |
|||
display: flex; |
|||
align-items: center; |
|||
background-color: #fff; |
|||
|
|||
// 搜索框 |
|||
.search { |
|||
flex: 1; |
|||
} |
|||
|
|||
// 切换显示方式 |
|||
.show-view { |
|||
width: 60rpx; |
|||
height: 60rpx; |
|||
line-height: 60rpx; |
|||
font-size: 36rpx; |
|||
color: #505050; |
|||
} |
|||
} |
|||
|
|||
// 排序组件 |
|||
.store-sort { |
|||
position: sticky; |
|||
top: var(--window-top); |
|||
display: flex; |
|||
padding: 20rpx 0; |
|||
font-size: 28rpx; |
|||
background: #fff; |
|||
color: #000; |
|||
z-index: 99; |
|||
|
|||
.sort-item { |
|||
flex-basis: 33.3333%; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
height: 50rpx; |
|||
|
|||
&.active { |
|||
color: #e49a3d; |
|||
} |
|||
} |
|||
|
|||
.sort-item-price .price-arrow { |
|||
margin-left: 20rpx; |
|||
font-size: 24rpx; |
|||
color: #000; |
|||
|
|||
.icon { |
|||
&.active { |
|||
color: #e49a3d; |
|||
} |
|||
|
|||
&.up { |
|||
margin-bottom: -16rpx; |
|||
} |
|||
|
|||
&.down { |
|||
margin-top: -16rpx; |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
// 商品列表 |
|||
.goods-list { |
|||
padding: 4rpx; |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
// 单列显示 |
|||
.goods-list.column-1 { |
|||
.goods-item { |
|||
width: 100%; |
|||
height: 280rpx; |
|||
margin-bottom: 12rpx; |
|||
padding: 20rpx; |
|||
box-sizing: border-box; |
|||
background: #fff; |
|||
line-height: 1.6; |
|||
|
|||
&:last-child { |
|||
margin-bottom: 0; |
|||
} |
|||
} |
|||
|
|||
.goods-item_left { |
|||
display: flex; |
|||
width: 300rpx; |
|||
background: #fff; |
|||
align-items: center; |
|||
|
|||
.image { |
|||
display: block; |
|||
width: 240rpx; |
|||
height: 240rpx; |
|||
} |
|||
} |
|||
|
|||
.goods-item_right { |
|||
position: relative; |
|||
// width: 450rpx; |
|||
flex: 1; |
|||
|
|||
.goods-name { |
|||
margin-top: 10rpx; |
|||
min-height: 68rpx; |
|||
line-height: 1.3; |
|||
white-space: normal; |
|||
color: #484848; |
|||
font-size: 26rpx; |
|||
} |
|||
} |
|||
|
|||
.goods-item_desc { |
|||
margin-top: 8rpx; |
|||
} |
|||
|
|||
.desc-selling_point { |
|||
width: 400rpx; |
|||
font-size: 24rpx; |
|||
color: #e49a3d; |
|||
} |
|||
|
|||
.desc-goods_sales { |
|||
color: #999; |
|||
font-size: 24rpx; |
|||
} |
|||
|
|||
.desc_footer { |
|||
font-size: 24rpx; |
|||
|
|||
.price_x { |
|||
margin-right: 16rpx; |
|||
color: #f03c3c; |
|||
font-size: 30rpx; |
|||
} |
|||
|
|||
.price_y { |
|||
text-decoration: line-through; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 平铺显示 |
|||
.goods-list.column-2 { |
|||
.goods-item { |
|||
width: 50%; |
|||
} |
|||
} |
|||
|
|||
.goods-item { |
|||
float: left; |
|||
box-sizing: border-box; |
|||
padding: 6rpx; |
|||
|
|||
.goods-image { |
|||
position: relative; |
|||
width: 100%; |
|||
height: 0; |
|||
padding-bottom: 100%; |
|||
overflow: hidden; |
|||
background: #fff; |
|||
|
|||
&:after { |
|||
content: ''; |
|||
display: block; |
|||
margin-top: 100%; |
|||
} |
|||
|
|||
.image { |
|||
position: absolute; |
|||
width: 100%; |
|||
height: 100%; |
|||
top: 0; |
|||
left: 0; |
|||
-o-object-fit: cover; |
|||
object-fit: cover; |
|||
} |
|||
} |
|||
|
|||
.detail { |
|||
padding: 8rpx; |
|||
background: #fff; |
|||
|
|||
.goods-name { |
|||
min-height: 68rpx; |
|||
line-height: 32rpx; |
|||
white-space: normal; |
|||
color: #484848; |
|||
font-size: 26rpx; |
|||
} |
|||
|
|||
.detail-price { |
|||
.goods-price { |
|||
margin-right: 8rpx; |
|||
} |
|||
|
|||
.line-price { |
|||
text-decoration: line-through; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,306 +0,0 @@ |
|||
<template> |
|||
<view class="container"> |
|||
<mescroll-body ref="mescrollRef" :sticky="true" @init="mescrollInit" :down="{ use: false }" :up="upOption" |
|||
@up="upCallback"> |
|||
|
|||
<!-- tab栏 --> |
|||
<u-tabs :list="tabs" :is-scroll="false" :current="curTab" active-color="#FA2209" :duration="0.2" |
|||
@change="onChangeTab" /> |
|||
|
|||
<!-- 优惠券列表 --> |
|||
<view class="coupon-list"> |
|||
<view class="coupon-item" v-for="(item, index) in list.data" :key="index"> |
|||
<view class="item-wrapper" :class="['color-' + (item.state.value ? color[index % color.length] : 'gray')]"> |
|||
<view class="coupon-type">{{ CouponTypeEnum[item.coupon_type].name }}</view> |
|||
<view class="tip dis-flex flex-dir-column flex-x-center"> |
|||
<view v-if="item.coupon_type == CouponTypeEnum.FULL_DISCOUNT.value"> |
|||
<text class="f-30">¥</text> |
|||
<text class="money">{{ item.reduce_price }}</text> |
|||
</view> |
|||
<text class="money" v-if="item.coupon_type == CouponTypeEnum.DISCOUNT.value">{{ item.discount }}折</text> |
|||
<text class="pay-line">满{{ item.min_price }}元可用</text> |
|||
</view> |
|||
<view class="split-line"></view> |
|||
<view class="content dis-flex flex-dir-column flex-x-between"> |
|||
<view class="title">{{ item.name }}</view> |
|||
<view class="bottom dis-flex flex-y-center"> |
|||
<view class="time flex-box"> |
|||
<block v-if="item.start_time === item.end_time">{{ item.start_time }} 当天有效</block> |
|||
<block v-else>{{ item.start_time }}~{{ item.end_time }}</block> |
|||
</view> |
|||
<view class="receive state"> |
|||
<text>{{ item.state.text }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</mescroll-body> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import MescrollBody from '@/components/mescroll-uni/mescroll-body.vue' |
|||
import MescrollMixin from '@/components/mescroll-uni/mescroll-mixins' |
|||
import { getEmptyPaginateObj, getMoreListData } from '@/core/app' |
|||
import * as MyCouponApi from '@/api/myCoupon' |
|||
import { CouponTypeEnum } from '@/common/enum/coupon' |
|||
|
|||
const color = ['red', 'blue', 'violet', 'yellow'] |
|||
const pageSize = 15 |
|||
const tabs = [{ |
|||
name: `未使用`, |
|||
value: 'isUnused' |
|||
}, { |
|||
name: `已使用`, |
|||
value: 'isUse' |
|||
}, { |
|||
name: `已过期`, |
|||
value: 'isExpire' |
|||
}] |
|||
|
|||
export default { |
|||
components: { |
|||
MescrollBody |
|||
}, |
|||
mixins: [MescrollMixin], |
|||
data() { |
|||
return { |
|||
// 枚举类 |
|||
CouponTypeEnum, |
|||
// 颜色组 |
|||
color, |
|||
// 标签栏数据 |
|||
tabs, |
|||
// 当前标签索引 |
|||
curTab: 0, |
|||
// 优惠券列表数据 |
|||
list: getEmptyPaginateObj(), |
|||
// 上拉加载配置 |
|||
upOption: { |
|||
// 首次自动执行 |
|||
auto: true, |
|||
// 每页数据的数量; 默认10 |
|||
page: { size: pageSize }, |
|||
// 数量要大于4条才显示无更多数据 |
|||
noMoreSize: 4, |
|||
// 空布局 |
|||
empty: { |
|||
tip: '亲,暂无相关优惠券' |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
onLoad(options) { |
|||
|
|||
}, |
|||
|
|||
methods: { |
|||
|
|||
/** |
|||
* 上拉加载的回调 (页面初始化时也会执行一次) |
|||
* 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10 |
|||
* @param {Object} page |
|||
*/ |
|||
upCallback(page) { |
|||
const app = this |
|||
// 设置列表数据 |
|||
app.getCouponList(page.num) |
|||
.then(list => { |
|||
const curPageLen = list.data.length |
|||
const totalSize = list.data.total |
|||
app.mescroll.endBySize(curPageLen, totalSize) |
|||
}) |
|||
.catch(() => app.mescroll.endErr()) |
|||
}, |
|||
|
|||
/** |
|||
* 获取优惠券列表 |
|||
*/ |
|||
getCouponList(pageNo = 1) { |
|||
const app = this |
|||
return new Promise((resolve, reject) => { |
|||
MyCouponApi.list({ dataType: app.getTabValue(), page: pageNo }, { load: false }) |
|||
.then(result => { |
|||
// 合并新数据 |
|||
const newList = result.data.list |
|||
app.list.data = getMoreListData(newList, app.list, pageNo) |
|||
resolve(newList) |
|||
}) |
|||
}) |
|||
}, |
|||
|
|||
// 评分类型 |
|||
getTabValue() { |
|||
return this.tabs[this.curTab].value |
|||
}, |
|||
|
|||
// 切换标签项 |
|||
onChangeTab(index) { |
|||
const app = this |
|||
// 设置当前选中的标签 |
|||
app.curTab = index |
|||
// 刷新优惠券列表 |
|||
app.onRefreshList() |
|||
}, |
|||
|
|||
// 刷新优惠券列表 |
|||
onRefreshList() { |
|||
this.list = getEmptyPaginateObj() |
|||
setTimeout(() => { |
|||
this.mescroll.resetUpScroll() |
|||
}, 120) |
|||
}, |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.coupon-list { |
|||
padding: 20rpx; |
|||
} |
|||
|
|||
|
|||
.coupon-item { |
|||
position: relative; |
|||
overflow: hidden; |
|||
margin-bottom: 22rpx; |
|||
} |
|||
|
|||
.item-wrapper { |
|||
width: 100%; |
|||
display: flex; |
|||
background: #fff; |
|||
border-radius: 8rpx; |
|||
color: #fff; |
|||
height: 180rpx; |
|||
|
|||
.coupon-type { |
|||
position: absolute; |
|||
top: 0; |
|||
right: 0; |
|||
z-index: 10; |
|||
width: 128rpx; |
|||
padding: 6rpx 0; |
|||
background: #a771ff; |
|||
font-size: 20rpx; |
|||
text-align: center; |
|||
color: #ffffff; |
|||
transform: rotate(45deg); |
|||
transform-origin: 64rpx 64rpx; |
|||
} |
|||
|
|||
&.color-blue { |
|||
background: linear-gradient(-125deg, #57bdbf, #2f9de2); |
|||
} |
|||
|
|||
&.color-red { |
|||
background: linear-gradient(-128deg, #ff6d6d, #ff3636); |
|||
} |
|||
|
|||
&.color-violet { |
|||
background: linear-gradient(-113deg, #ef86ff, #b66ff5); |
|||
|
|||
.coupon-type { |
|||
background: #55b5ff; |
|||
} |
|||
} |
|||
|
|||
&.color-yellow { |
|||
background: linear-gradient(-141deg, #f7d059, #fdb054); |
|||
} |
|||
|
|||
&.color-gray { |
|||
background: linear-gradient(-113deg, #bdbdbd, #a2a1a2); |
|||
|
|||
.coupon-type { |
|||
background: #9e9e9e; |
|||
} |
|||
} |
|||
|
|||
.content { |
|||
flex: 1; |
|||
padding: 30rpx 20rpx; |
|||
border-radius: 16rpx 0 0 16rpx; |
|||
|
|||
.title { |
|||
font-size: 32rpx; |
|||
} |
|||
|
|||
.bottom { |
|||
.time { |
|||
font-size: 24rpx; |
|||
} |
|||
|
|||
.receive { |
|||
height: 46rpx; |
|||
width: 122rpx; |
|||
line-height: 46rpx; |
|||
text-align: center; |
|||
border: 1rpx solid #fff; |
|||
border-radius: 30rpx; |
|||
color: #fff; |
|||
font-size: 24rpx; |
|||
|
|||
&.state { |
|||
border: none; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.tip { |
|||
position: relative; |
|||
flex: 0 0 32%; |
|||
text-align: center; |
|||
border-radius: 0 16rpx 16rpx 0; |
|||
|
|||
.money { |
|||
font-weight: bold; |
|||
font-size: 52rpx; |
|||
} |
|||
|
|||
.pay-line { |
|||
font-size: 22rpx; |
|||
} |
|||
} |
|||
|
|||
.split-line { |
|||
position: relative; |
|||
flex: 0 0 0; |
|||
border-left: 4rpx solid #fff; |
|||
margin: 0 10rpx 0 6rpx; |
|||
background: #fff; |
|||
|
|||
&:before, |
|||
{ |
|||
border-radius: 0 0 16rpx 16rpx; |
|||
top: 0; |
|||
} |
|||
|
|||
&:after { |
|||
border-radius: 16rpx 16rpx 0 0; |
|||
bottom: 0; |
|||
} |
|||
|
|||
&:before, |
|||
&:after { |
|||
content: ''; |
|||
position: absolute; |
|||
width: 24rpx; |
|||
height: 12rpx; |
|||
background: #f7f7f7; |
|||
left: -14rpx; |
|||
z-index: 1; |
|||
} |
|||
|
|||
|
|||
} |
|||
} |
|||
</style> |
|||
@ -1,136 +0,0 @@ |
|||
<template> |
|||
<view class="container"> |
|||
<!-- 订单页列表 --> |
|||
<view class="order-list"> |
|||
<view class="order-item" v-for="(item, index) in orderList" :key="index" @click="$navTo(item.path)"> |
|||
<view class="order-item-icon" :style="{ color: item.color }"> |
|||
<text class="iconfont" :class="item.icon"></text> |
|||
</view> |
|||
<view class="order-item-name">{{ item.name }}</view> |
|||
<view class="icon-arrow"> |
|||
<text class="iconfont icon-arrow-right"></text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- 操作按钮 --> |
|||
<view class="footer"> |
|||
<view class="btn-wrapper"> |
|||
<view class="btn-item btn-item-main" @click="$navTo('pages/index/index')"> |
|||
<view class="btn-item-icon"> |
|||
<text class="iconfont icon-shouye2"></text> |
|||
</view> |
|||
<view class="btn-item-name"> |
|||
<text>返回首页</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import * as UserApi from '@/api/user' |
|||
|
|||
// 订单页数据 |
|||
const orderList = [{ |
|||
name: '商城订单', |
|||
icon: 'icon-qpdingdan', |
|||
color: 'rgb(253 65 0)', |
|||
path: 'pages/order/index' |
|||
}, |
|||
{ |
|||
name: '充值订单', |
|||
icon: 'icon-jifen', |
|||
color: 'rgb(191, 150, 7)', |
|||
path: 'pages/wallet/recharge/order' |
|||
} |
|||
] |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
orderList |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
onLoad(options) { |
|||
// 获取当前用户信息 |
|||
this.getUserInfo() |
|||
}, |
|||
|
|||
methods: { |
|||
|
|||
// 获取当前用户信息(验证是否登录) |
|||
getUserInfo() { |
|||
const app = this |
|||
UserApi.info() |
|||
}, |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.order-list { |
|||
padding: 0 25rpx; |
|||
background-color: #fff; |
|||
|
|||
.order-item { |
|||
position: relative; |
|||
padding: 26rpx 16rpx; |
|||
border-bottom: 1rpx solid #eee; |
|||
display: flex; |
|||
justify-content: flex-start; |
|||
align-items: center; |
|||
font-size: 30rpx; |
|||
|
|||
&:last-child { |
|||
border-bottom: none; |
|||
} |
|||
} |
|||
|
|||
.order-item-icon { |
|||
font-size: 34rpx; |
|||
margin-right: 18rpx; |
|||
} |
|||
|
|||
.icon-arrow { |
|||
position: absolute; |
|||
top: 26rpx; |
|||
right: 6rpx; |
|||
} |
|||
} |
|||
|
|||
// 底部操作栏 |
|||
.footer { |
|||
position: fixed; |
|||
bottom: var(--window-bottom); |
|||
left: 0; |
|||
right: 0; |
|||
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); |
|||
|
|||
.btn-item { |
|||
font-size: 30rpx; |
|||
height: 90rpx; |
|||
border-radius: 50rpx; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
|
|||
.btn-item-icon { |
|||
font-size: 34rpx; |
|||
margin-right: 18rpx; |
|||
} |
|||
|
|||
} |
|||
</style> |
|||
@ -1,571 +0,0 @@ |
|||
<template> |
|||
<view v-if="!isLoading" class="container"> |
|||
<view class="goods-list"> |
|||
<view class="goods-item" v-for="(item, index) in goodsList" :key="index"> |
|||
<!-- 商品详情 --> |
|||
<view class="goods-main"> |
|||
<!-- 商品图片 --> |
|||
<view class="goods-image"> |
|||
<image class="image" :src="item.goods_image" mode="scaleToFill"></image> |
|||
</view> |
|||
<!-- 商品信息 --> |
|||
<view class="goods-content"> |
|||
<view class="goods-title"><text class="twoline-hide">{{ item.goods_name }}</text></view> |
|||
<view class="goods-props clearfix"> |
|||
<view class="goods-props-item" v-for="(props, idx) in item.goods_props" :key="idx"> |
|||
<text>{{ props.value.name }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- 交易信息 --> |
|||
<view class="goods-trade"> |
|||
<view class="goods-price"> |
|||
<text class="unit">¥</text> |
|||
<text class="value">{{ item.goods_price }}</text> |
|||
</view> |
|||
<view class="goods-num"> |
|||
<text>×{{ item.total_num }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- 选择评价 --> |
|||
<view class="score-row"> |
|||
<view class="score-item score-praise" :class="{ active: formData[index].score == 10 }" |
|||
@click="setScore(index, 10)"> |
|||
<view class="score"> |
|||
<text class="score-icon iconfont icon-haoping"></text> |
|||
<text class="score-text">好评</text> |
|||
</view> |
|||
</view> |
|||
<view class="score-item score-review" :class="{ active: formData[index].score == 20 }" |
|||
@click="setScore(index, 20)"> |
|||
<view class="score"> |
|||
<text class="score-icon iconfont icon-zhongping"></text> |
|||
<text class="score-text">中评</text> |
|||
</view> |
|||
</view> |
|||
<view class="score-item score-negative" :class="{ active: formData[index].score == 30 }" |
|||
@click="setScore(index, 30)"> |
|||
<view class="score"> |
|||
<text class="score-icon iconfont icon-chaping"></text> |
|||
<text class="score-text">差评</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 评价内容 --> |
|||
<view class="form-content"> |
|||
<textarea class="textarea" v-model="formData[index].content" maxlength="500" |
|||
placeholder="请输入评价内容 (留空则不评价)"></textarea> |
|||
</view> |
|||
|
|||
<!-- 图片列表 --> |
|||
<view class="image-list"> |
|||
<view class="image-preview" v-for="(image, imageIndex) in formData[index].imageList" :key="imageIndex"> |
|||
<text class="image-delete iconfont icon-shanchu" @click="deleteImage(index, imageIndex)"></text> |
|||
<image class="image" mode="aspectFill" :src="image.path"></image> |
|||
</view> |
|||
<view v-if="!formData[index].imageList || formData[index].imageList.length < maxImageLength" |
|||
class="image-picker" @click="chooseImage(index)"> |
|||
<text class="choose-icon iconfont icon-camera"></text> |
|||
<text class="choose-text">上传图片</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 底部操作按钮 --> |
|||
<view class="footer-fixed"> |
|||
<view class="btn-wrapper"> |
|||
<view class="btn-item btn-item-main" :class="{ disabled }" @click="handleSubmit()">确认提交</view> |
|||
</view> |
|||
</view> |
|||
|
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import * as UploadApi from '@/api/upload' |
|||
import * as OrderCommentApi from '@/api/order/comment' |
|||
|
|||
const maxImageLength = 6 |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
// 正在加载 |
|||
isLoading: true, |
|||
// 当前订单ID |
|||
orderId: null, |
|||
// 待评价商品列表 |
|||
goodsList: [], |
|||
// 表单数据 |
|||
formData: [], |
|||
// 最大图片数量 |
|||
maxImageLength, |
|||
// 按钮禁用 |
|||
disabled: false |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
onLoad({ orderId }) { |
|||
this.orderId = orderId |
|||
// 获取待评价商品列表 |
|||
this.getGoodsList() |
|||
}, |
|||
|
|||
methods: { |
|||
|
|||
// 获取待评价商品列表 |
|||
getGoodsList() { |
|||
const app = this |
|||
app.isLoading = true |
|||
OrderCommentApi.list(app.orderId) |
|||
.then(result => { |
|||
app.goodsList = result.data.goodsList |
|||
app.initFormData() |
|||
app.isLoading = false |
|||
}) |
|||
}, |
|||
|
|||
// 初始化form数据 |
|||
initFormData() { |
|||
const { goodsList } = this |
|||
const formData = goodsList.map(item => { |
|||
return { |
|||
goods_id: item.goods_id, |
|||
order_goods_id: item.order_goods_id, |
|||
score: 10, |
|||
content: '', |
|||
imageList: [], |
|||
uploaded: [] |
|||
} |
|||
}) |
|||
this.formData = formData |
|||
}, |
|||
|
|||
// 设置评分 |
|||
setScore(index, score) { |
|||
this.formData[index].score = score |
|||
}, |
|||
|
|||
// 选择图片 |
|||
chooseImage(index) { |
|||
const app = this |
|||
const oldImageList = app.formData[index].imageList |
|||
// 选择图片 |
|||
uni.chooseImage({ |
|||
count: maxImageLength - oldImageList.length, |
|||
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有 |
|||
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有 |
|||
success({ tempFiles }) { |
|||
// tempFiles = [{path:'xxx', size:100}] |
|||
app.formData[index].imageList = oldImageList.concat(tempFiles) |
|||
} |
|||
}); |
|||
}, |
|||
|
|||
// 删除图片 |
|||
deleteImage(index, imageIndex) { |
|||
this.formData[index].imageList.splice(imageIndex, 1) |
|||
}, |
|||
|
|||
// 表单提交 |
|||
handleSubmit() { |
|||
const app = this |
|||
// 判断是否重复提交 |
|||
if (app.disabled === true) return false |
|||
// 按钮禁用 |
|||
app.disabled = true |
|||
// 判断是否需要上传图片 |
|||
const imagesLength = app.getImagesLength() |
|||
if (imagesLength > 0) { |
|||
app.uploadFile() |
|||
.then(() => { |
|||
console.log('then') |
|||
app.onSubmit() |
|||
}) |
|||
.catch(err => { |
|||
console.log('catch') |
|||
app.disabled = false |
|||
if (err.statusCode !== 0) { |
|||
app.$toast(err.errMsg) |
|||
} |
|||
console.log('err', err) |
|||
}) |
|||
} else { |
|||
app.onSubmit() |
|||
} |
|||
}, |
|||
|
|||
// 统计图片数量 |
|||
getImagesLength() { |
|||
const { formData } = this |
|||
let imagesLength = 0 |
|||
formData.forEach(item => { |
|||
if (item.content.trim()) { |
|||
imagesLength += item.imageList.length |
|||
} |
|||
}) |
|||
return imagesLength |
|||
}, |
|||
|
|||
// 提交到后端 |
|||
onSubmit() { |
|||
const app = this |
|||
OrderCommentApi.submit(app.orderId, app.formData) |
|||
.then(result => { |
|||
app.$toast(result.message) |
|||
setTimeout(() => { |
|||
app.disabled = false |
|||
uni.navigateBack() |
|||
}, 1500) |
|||
}) |
|||
.catch(err => app.disabled = false) |
|||
}, |
|||
|
|||
// 上传图片 |
|||
uploadFile() { |
|||
const app = this |
|||
const { formData } = app |
|||
// 整理上传文件路径 |
|||
const files = [] |
|||
formData.forEach((item, index) => { |
|||
if (item.content.trim() && item.imageList.length) { |
|||
const images = item.imageList.map(image => image) |
|||
files.push({ formDataIndex: index, images }) |
|||
} |
|||
}) |
|||
// 批量上传 |
|||
return new Promise((resolve, reject) => { |
|||
Promise.all(files.map((file, index) => { |
|||
return new Promise((resolve, reject) => { |
|||
UploadApi.image(file.images) |
|||
.then(fileIds => { |
|||
app.formData[index].uploaded = fileIds |
|||
resolve(fileIds) |
|||
}) |
|||
.catch(reject) |
|||
}) |
|||
})) |
|||
.then(resolve, reject) |
|||
}) |
|||
} |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.container { |
|||
// 设置ios刘海屏底部横线安全区域 |
|||
padding-bottom: constant(env(safe-area-inset-bottom) + 140rpx); |
|||
padding-bottom: calc(env(safe-area-inset-bottom) + 140rpx); |
|||
} |
|||
|
|||
.goods-list { |
|||
font-size: 28rpx; |
|||
padding-top: 30rpx; |
|||
} |
|||
|
|||
.goods-item { |
|||
width: 94%; |
|||
background: #fff; |
|||
padding: 24rpx 24rpx; |
|||
box-shadow: 0 1rpx 5rpx 0px rgba(0, 0, 0, 0.05); |
|||
margin: 0 auto 30rpx auto; |
|||
border-radius: 20rpx; |
|||
|
|||
.goods-detail { |
|||
padding: 24rpx 20rpx; |
|||
|
|||
.left { |
|||
.goods-image { |
|||
display: block; |
|||
width: 150rpx; |
|||
height: 150rpx; |
|||
} |
|||
} |
|||
|
|||
.right { |
|||
padding-left: 20rpx; |
|||
} |
|||
} |
|||
|
|||
.score-row { |
|||
display: flex; |
|||
justify-content: space-around; |
|||
padding: 24rpx 20rpx; |
|||
|
|||
.score-item { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
|
|||
&.score-praise { |
|||
color: #ff4544; |
|||
|
|||
.score-icon { |
|||
background: #ff4544; |
|||
} |
|||
} |
|||
|
|||
&.score-review { |
|||
color: #fcb500; |
|||
|
|||
.score-icon { |
|||
background: #fcb500; |
|||
} |
|||
} |
|||
|
|||
&.score-negative { |
|||
color: #9b9b9b; |
|||
|
|||
.score-icon { |
|||
background: #9b9b9b; |
|||
} |
|||
} |
|||
|
|||
.score { |
|||
padding: 10rpx 20rpx 10rpx 10rpx; |
|||
border-radius: 30rpx; |
|||
|
|||
.score-icon { |
|||
margin-right: 10rpx; |
|||
padding: 10rpx; |
|||
border-radius: 50%; |
|||
font-size: 30rpx; |
|||
color: #fff; |
|||
} |
|||
} |
|||
|
|||
&.active { |
|||
.score { |
|||
color: #fff; |
|||
} |
|||
|
|||
&.score-praise { |
|||
.score { |
|||
background: #ff4544; |
|||
} |
|||
} |
|||
|
|||
&.score-review { |
|||
.score { |
|||
background: #fcb500; |
|||
} |
|||
} |
|||
|
|||
&.score-negative { |
|||
.score { |
|||
background: #9b9b9b; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 评价内容 |
|||
.form-content { |
|||
padding: 14rpx 10rpx; |
|||
|
|||
.textarea { |
|||
width: 100%; |
|||
height: 220rpx; |
|||
padding: 12rpx; |
|||
border: 1rpx solid #e8e8e8; |
|||
border-radius: 5rpx; |
|||
box-sizing: border-box; |
|||
font-size: 26rpx; |
|||
} |
|||
} |
|||
|
|||
.image-list { |
|||
padding: 0 20rpx; |
|||
margin-top: 20rpx; |
|||
margin-bottom: -20rpx; |
|||
|
|||
&:after { |
|||
clear: both; |
|||
content: " "; |
|||
display: table; |
|||
} |
|||
|
|||
.image { |
|||
display: block; |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
|
|||
.image-picker, |
|||
.image-preview { |
|||
width: 184rpx; |
|||
height: 184rpx; |
|||
margin-right: 30rpx; |
|||
margin-bottom: 30rpx; |
|||
float: left; |
|||
|
|||
&:nth-child(3n+0) { |
|||
margin-right: 0; |
|||
} |
|||
} |
|||
|
|||
.image-picker { |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
align-items: center; |
|||
border: 1rpx dashed #ccc; |
|||
color: #ccc; |
|||
|
|||
.choose-icon { |
|||
font-size: 48rpx; |
|||
margin-bottom: 6rpx; |
|||
} |
|||
|
|||
.choose-text { |
|||
font-size: 24rpx; |
|||
} |
|||
} |
|||
|
|||
.image-preview { |
|||
position: relative; |
|||
|
|||
.image-delete { |
|||
position: absolute; |
|||
top: -15rpx; |
|||
right: -15rpx; |
|||
height: 42rpx; |
|||
width: 42rpx; |
|||
line-height: 42rpx; |
|||
background: rgba(0, 0, 0, 0.64); |
|||
border-radius: 50%; |
|||
color: #fff; |
|||
font-weight: bolder; |
|||
font-size: 22rpx; |
|||
z-index: 10; |
|||
text-align: center; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
// 商品项 |
|||
.goods-main { |
|||
display: flex; |
|||
margin-bottom: 20rpx; |
|||
|
|||
// 商品图片 |
|||
.goods-image { |
|||
width: 180rpx; |
|||
height: 180rpx; |
|||
|
|||
.image { |
|||
display: block; |
|||
width: 100%; |
|||
height: 100%; |
|||
border-radius: 8rpx; |
|||
} |
|||
} |
|||
|
|||
// 商品内容 |
|||
.goods-content { |
|||
flex: 1; |
|||
padding-left: 16rpx; |
|||
padding-top: 16rpx; |
|||
|
|||
.goods-title { |
|||
font-size: 26rpx; |
|||
max-height: 76rpx; |
|||
} |
|||
|
|||
.goods-props { |
|||
margin-top: 14rpx; |
|||
height: 40rpx; |
|||
color: #ababab; |
|||
font-size: 24rpx; |
|||
overflow: hidden; |
|||
|
|||
.goods-props-item { |
|||
display: inline-block; |
|||
margin-right: 14rpx; |
|||
padding: 4rpx 16rpx; |
|||
border-radius: 12rpx; |
|||
background-color: #F5F5F5; |
|||
width: auto; |
|||
} |
|||
} |
|||
|
|||
|
|||
} |
|||
|
|||
// 交易信息 |
|||
.goods-trade { |
|||
padding-top: 16rpx; |
|||
width: 150rpx; |
|||
text-align: right; |
|||
color: $uni-text-color-grey; |
|||
font-size: 26rpx; |
|||
|
|||
.goods-price { |
|||
vertical-align: bottom; |
|||
margin-bottom: 16rpx; |
|||
|
|||
.unit { |
|||
margin-right: -2rpx; |
|||
font-size: 24rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
|
|||
// 底部操作栏 |
|||
.footer-fixed { |
|||
position: fixed; |
|||
bottom: var(--window-bottom); |
|||
left: 0; |
|||
right: 0; |
|||
height: 96rpx; |
|||
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); |
|||
|
|||
.btn-wrapper { |
|||
height: 100%; |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 0 20rpx; |
|||
} |
|||
|
|||
.btn-item { |
|||
flex: 1; |
|||
font-size: 28rpx; |
|||
height: 80rpx; |
|||
line-height: 80rpx; |
|||
text-align: center; |
|||
color: #fff; |
|||
border-radius: 50rpx; |
|||
} |
|||
|
|||
.btn-item-main { |
|||
background: linear-gradient(to right, #f9211c, #ff6335); |
|||
|
|||
// 禁用按钮 |
|||
&.disabled { |
|||
background: #ff9779; |
|||
} |
|||
} |
|||
|
|||
} |
|||
</style> |
|||
@ -1,866 +0,0 @@ |
|||
<template> |
|||
<view v-if="!isLoading" class="container"> |
|||
|
|||
<view class="header"> |
|||
<!-- 订单状态 --> |
|||
<view class="order-status"> |
|||
<view class="status-icon"> |
|||
<!-- 进行中的订单 --> |
|||
<block v-if="order.order_status == OrderStatusEnum.NORMAL.value"> |
|||
<!-- 待支付 --> |
|||
<block v-if="order.pay_status == PayStatusEnum.PENDING.value"> |
|||
<image class="image" src="/static/order/status/wait_pay.png" mode="aspectFit"></image> |
|||
</block> |
|||
<!-- 待发货 --> |
|||
<block v-else-if="order.delivery_status == DeliveryStatusEnum.NOT_DELIVERED.value"> |
|||
<image class="image" src="/static/order/status/wait_deliver.png" mode="aspectFit"></image> |
|||
</block> |
|||
<!-- 待收货 --> |
|||
<block v-else-if="order.receipt_status == ReceiptStatusEnum.NOT_RECEIVED.value"> |
|||
<image class="image" src="/static/order/status/wait_receipt.png" mode="aspectFit"></image> |
|||
</block> |
|||
</block> |
|||
<!-- 已完成 --> |
|||
<block v-if="order.order_status == OrderStatusEnum.COMPLETED.value"> |
|||
<image class="image" src="/static/order/status/received.png" mode="aspectFit"></image> |
|||
</block> |
|||
<!-- 已取消/待取消 --> |
|||
<block v-if="order.order_status == OrderStatusEnum.CANCELLED.value || order.order_status == OrderStatusEnum.APPLY_CANCEL.value"> |
|||
<image class="image" src="/static/order/status/close.png" mode="aspectFit"></image> |
|||
</block> |
|||
</view> |
|||
<view class="status-text"> |
|||
<text>{{ order.state_text }}</text> |
|||
</view> |
|||
</view> |
|||
<!-- 下一步操作 --> |
|||
<view class="next-action" v-if="order.order_status == OrderStatusEnum.NORMAL.value"> |
|||
<view v-if="order.pay_status == PayStatusEnum.PENDING.value" class="action-btn" @click="onPay()">去支付</view> |
|||
<view v-if="order.delivery_status == DeliveryStatusEnum.DELIVERED.value && order.receipt_status == ReceiptStatusEnum.NOT_RECEIVED.value" class="action-btn" @click="onReceipt(order.order_id)">确认收货</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 快递配送:配送地址 --> |
|||
<view class="delivery-address i-card"> |
|||
<view class="link-man"> |
|||
<text class="name">{{ order.address.name }}</text> |
|||
<text class="phone">{{ order.address.phone }}</text> |
|||
</view> |
|||
<view class="address"> |
|||
<text class="region" v-for="(region, idx) in order.address.region" :key="idx">{{ region }}</text> |
|||
<text class="detail">{{ order.address.detail }}</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 物流信息 --> |
|||
<view v-if="order.delivery_type == DeliveryTypeEnum.EXPRESS.value && order.delivery_status == DeliveryStatusEnum.DELIVERED.value && order.express" class="express i-card" @click="handleTargetExpress()"> |
|||
<view class="main"> |
|||
<view class="info-item"> |
|||
<view class="item-lable">物流公司</view> |
|||
<view class="item-content"> |
|||
<text>{{ order.express.express_name }}</text> |
|||
</view> |
|||
</view> |
|||
<view class="info-item"> |
|||
<view class="item-lable">物流单号</view> |
|||
<view class="item-content"> |
|||
<text>{{ order.express_no }}</text> |
|||
<view class="act-copy" @click.stop="handleCopy(order.express_no)"> |
|||
<text>复制</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view class="right-arrow"> |
|||
<text class="iconfont icon-arrow-right"></text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 商品列表 --> |
|||
<view class="goods-list i-card"> |
|||
<view class="goods-item" v-for="(goods, idx) in order.goods" :key="idx"> |
|||
<view class="goods-main" @click="handleTargetGoods(goods.goods_id)"> |
|||
<!-- 商品图片 --> |
|||
<view class="goods-image"> |
|||
<image class="image" :src="goods.goods_image" mode="scaleToFill"></image> |
|||
</view> |
|||
<!-- 商品信息 --> |
|||
<view class="goods-content"> |
|||
<view class="goods-title"><text class="twoline-hide">{{ goods.goods_name }}</text></view> |
|||
<view class="goods-props clearfix"> |
|||
<view class="goods-props-item" v-for="(props, idx) in goods.goods_props" :key="idx"> |
|||
<text>{{ props.value.name }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- 交易信息 --> |
|||
<view class="goods-trade"> |
|||
<view class="goods-price"> |
|||
<text class="unit">¥</text> |
|||
<text class="value">{{ goods.is_user_grade ? goods.grade_goods_price : goods.goods_price }}</text> |
|||
</view> |
|||
<view class="goods-num"> |
|||
<text>×{{ goods.total_num }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- 商品售后 --> |
|||
<view class="goods-refund"> |
|||
<text v-if="goods.refund" class="stata-text">已申请售后</text> |
|||
<view v-else-if="order.isAllowRefund" class="action-btn" @click.stop="handleApplyRefund(goods.order_goods_id)">申请售后</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 订单信息 --> |
|||
<view class="order-info i-card"> |
|||
<view class="info-item"> |
|||
<view class="item-lable">订单编号</view> |
|||
<view class="item-content"> |
|||
<text>{{ order.order_no }}</text> |
|||
<view class="act-copy" @click="handleCopy(order.order_no)"> |
|||
<text>复制</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view class="info-item"> |
|||
<view class="item-lable">下单时间</view> |
|||
<view class="item-content"> |
|||
<text>{{ order.create_time }}</text> |
|||
</view> |
|||
</view> |
|||
<view class="info-item"> |
|||
<view class="item-lable">买家留言</view> |
|||
<view class="item-content"> |
|||
<text>{{ order.buyer_remark ? order.buyer_remark : '--' }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 结算信息 --> |
|||
<view class="trade-info i-card"> |
|||
<view class="info-item"> |
|||
<view class="item-lable">订单金额</view> |
|||
<view class="item-content"> |
|||
<text>¥{{ order.total_price }}</text> |
|||
</view> |
|||
</view> |
|||
<view v-if="order.coupon_money > 0" class="info-item"> |
|||
<view class="item-lable">优惠券抵扣</view> |
|||
<view class="item-content"> |
|||
<text>-¥{{ order.coupon_money }}</text> |
|||
</view> |
|||
</view> |
|||
<view v-if="order.points_money > 0" class="info-item"> |
|||
<view class="item-lable">{{ setting.points_name }}抵扣</view> |
|||
<view class="item-content"> |
|||
<text>-¥{{ order.points_money }}</text> |
|||
</view> |
|||
</view> |
|||
<view class="info-item"> |
|||
<view class="item-lable">运费</view> |
|||
<view class="item-content"> |
|||
<text>+¥{{ order.express_price }}</text> |
|||
</view> |
|||
</view> |
|||
<view v-if="order.update_price.value != '0.00'" class="info-item"> |
|||
<view class="item-lable">后台改价</view> |
|||
<view class="item-content"> |
|||
<text>{{ order.update_price.symbol }}</text> |
|||
<text>¥{{ order.update_price.value }}</text> |
|||
</view> |
|||
</view> |
|||
<view class="divider"></view> |
|||
<view class="trade-total"> |
|||
<text class="lable">实付款</text> |
|||
<view class="goods-price"> |
|||
<text class="unit">¥</text> |
|||
<text class="value">{{ order.pay_price }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 底部操作按钮 --> |
|||
<view v-if="order.order_status != OrderStatusEnum.CANCELLED.value" class="footer-fixed"> |
|||
<view class="btn-wrapper"> |
|||
<!-- 未支付取消订单 --> |
|||
<block v-if="order.pay_status == PayStatusEnum.PENDING.value"> |
|||
<view class="btn-item" @click="onCancel(order.order_id)">取消</view> |
|||
</block> |
|||
<!-- 已支付进行中的订单 --> |
|||
<block v-if="order.order_status != OrderStatusEnum.APPLY_CANCEL.value"> |
|||
<block v-if="order.pay_status == PayStatusEnum.SUCCESS.value && order.delivery_status == DeliveryStatusEnum.NOT_DELIVERED.value"> |
|||
<view class="btn-item" @click="onCancel(order.order_id)">申请取消</view> |
|||
</block> |
|||
</block> |
|||
<!-- 已申请取消 --> |
|||
<view v-else class="f-28 col-8">取消申请中</view> |
|||
<!-- 未支付的订单 --> |
|||
<block v-if="order.pay_status == PayStatusEnum.PENDING.value"> |
|||
<view class="btn-item active" @click="onPay()">去支付</view> |
|||
</block> |
|||
<!-- 确认收货 --> |
|||
<block v-if="order.delivery_status == DeliveryStatusEnum.DELIVERED.value && order.receipt_status == ReceiptStatusEnum.NOT_RECEIVED.value"> |
|||
<view class="btn-item active" @click="onReceipt(order.order_id)">确认收货</view> |
|||
</block> |
|||
<!-- 订单评价 --> |
|||
<block v-if="order.order_status == OrderStatusEnum.COMPLETED.value && order.is_comment == 0"> |
|||
<view class="btn-item" @click="handleTargetComment(order.order_id)">评价</view> |
|||
</block> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 支付方式弹窗 --> |
|||
<u-popup v-model="showPayPopup" mode="bottom" border-radius="26" :closeable="true"> |
|||
<view class="pay-popup"> |
|||
<view class="title">请选择支付方式</view> |
|||
<view class="pop-content"> |
|||
<!-- 微信支付 --> |
|||
<!-- #ifdef MP-WEIXIN --> |
|||
<view class="pay-item dis-flex flex-x-between" @click="onSelectPayType(PayTypeEnum.WECHAT.value)"> |
|||
<view class="item-left dis-flex flex-y-center"> |
|||
<view class="item-left_icon wechat"> |
|||
<text class="iconfont icon-wechat-pay"></text> |
|||
</view> |
|||
<view class="item-left_text"> |
|||
<text>{{ PayTypeEnum.WECHAT.name }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- #endif --> |
|||
<!-- 余额支付 --> |
|||
<view class="pay-item dis-flex flex-x-between" @click="onSelectPayType(PayTypeEnum.BALANCE.value)"> |
|||
<view class="item-left dis-flex flex-y-center"> |
|||
<view class="item-left_icon balance"> |
|||
<text class="iconfont icon-balance-pay"></text> |
|||
</view> |
|||
<view class="item-left_text"> |
|||
<text>{{ PayTypeEnum.BALANCE.name }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</u-popup> |
|||
|
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { |
|||
DeliveryStatusEnum, |
|||
DeliveryTypeEnum, |
|||
OrderStatusEnum, |
|||
PayStatusEnum, |
|||
PayTypeEnum, |
|||
ReceiptStatusEnum |
|||
} from '@/common/enum/order' |
|||
import * as OrderApi from '@/api/order' |
|||
import { wxPayment } from '@/core/app' |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
// 枚举类 |
|||
DeliveryStatusEnum, |
|||
DeliveryTypeEnum, |
|||
OrderStatusEnum, |
|||
PayStatusEnum, |
|||
PayTypeEnum, |
|||
ReceiptStatusEnum, |
|||
// 当前订单ID |
|||
orderId: null, |
|||
// 加载中 |
|||
isLoading: true, |
|||
// 当前订单详情 |
|||
order: {}, |
|||
// 当前设置 |
|||
setting: {}, |
|||
// 支付方式弹窗 |
|||
showPayPopup: false, |
|||
// 控制onShow事件是否刷新订单信息 |
|||
canReset: false, |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
onLoad({ orderId }) { |
|||
// 当前订单ID |
|||
this.orderId = orderId |
|||
// 获取当前订单信息 |
|||
this.getOrderDetail() |
|||
// 注册全局事件订阅: 是否刷新当前订单数据 |
|||
uni.$on('syncRefresh', (val, isCur) => { |
|||
if (!isCur) { |
|||
this.canReset = val |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面显示 |
|||
*/ |
|||
onShow() { |
|||
this.canReset && this.getOrderDetail() |
|||
this.canReset = false |
|||
}, |
|||
|
|||
methods: { |
|||
|
|||
// 获取当前订单信息 |
|||
getOrderDetail(canReset = false) { |
|||
const app = this |
|||
app.isLoading = true |
|||
OrderApi.detail(app.orderId) |
|||
.then(result => { |
|||
app.order = result.data.order |
|||
app.setting = result.data.setting |
|||
app.isLoading = false |
|||
}) |
|||
// 相应全局事件订阅: 刷新上级页面数据 |
|||
canReset && uni.$emit('syncRefresh', true, true) |
|||
}, |
|||
|
|||
// 复制指定内容 |
|||
handleCopy(value) { |
|||
const app = this |
|||
uni.setClipboardData({ |
|||
data: value, |
|||
success() { |
|||
app.$toast('复制成功') |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
// 跳转到物流跟踪页面 |
|||
handleTargetExpress() { |
|||
this.$navTo('pages/order/express/index', { orderId: this.orderId }) |
|||
}, |
|||
|
|||
// 跳转到商品详情页面 |
|||
handleTargetGoods(goodsId) { |
|||
this.$navTo('pages/goods/detail', { goodsId }) |
|||
}, |
|||
|
|||
// 跳转到申请售后页面 |
|||
handleApplyRefund(orderGoodsId) { |
|||
this.$navTo('pages/refund/apply', { orderGoodsId }) |
|||
}, |
|||
|
|||
// 取消订单 |
|||
onCancel(orderId) { |
|||
const app = this |
|||
uni.showModal({ |
|||
title: '友情提示', |
|||
content: '确认要取消该订单吗?', |
|||
success(o) { |
|||
if (o.confirm) { |
|||
OrderApi.cancel(orderId) |
|||
.then(result => { |
|||
// 显示成功信息 |
|||
app.$toast(result.message) |
|||
// 刷新当前订单数据 |
|||
app.getOrderDetail(true) |
|||
}) |
|||
} |
|||
} |
|||
}); |
|||
}, |
|||
|
|||
// 确认收货 |
|||
onReceipt(orderId) { |
|||
const app = this |
|||
uni.showModal({ |
|||
title: '友情提示', |
|||
content: '确认收到商品了吗?', |
|||
success(o) { |
|||
if (o.confirm) { |
|||
OrderApi.receipt(orderId) |
|||
.then(result => { |
|||
// 显示成功信息 |
|||
app.$success(result.message) |
|||
// 刷新当前订单数据 |
|||
app.getOrderDetail(true) |
|||
}) |
|||
} |
|||
} |
|||
}); |
|||
}, |
|||
|
|||
// 点击去支付 |
|||
onPay() { |
|||
// 显示支付方式弹窗 |
|||
this.showPayPopup = true |
|||
}, |
|||
|
|||
// 选择支付方式 |
|||
onSelectPayType(payType) { |
|||
const app = this |
|||
// 隐藏支付方式弹窗 |
|||
this.showPayPopup = false |
|||
// 发起支付请求 |
|||
OrderApi.pay(app.orderId, payType) |
|||
.then(result => app.onSubmitCallback(result)) |
|||
.catch(err => err) |
|||
}, |
|||
|
|||
// 订单提交成功后回调 |
|||
onSubmitCallback(result) { |
|||
const app = this |
|||
// 发起微信支付 |
|||
if (result.data.pay_type == PayTypeEnum.WECHAT.value) { |
|||
wxPayment(result.data.payment) |
|||
.then(() => { |
|||
app.$success('支付成功') |
|||
setTimeout(() => app.getOrderDetail(true), 1500) |
|||
}) |
|||
.catch(err => app.$error('订单未支付')) |
|||
.finally(() => app.disabled = false) |
|||
} |
|||
// 余额支付 |
|||
if (result.data.pay_type == PayTypeEnum.BALANCE.value) { |
|||
app.$success('支付成功') |
|||
app.disabled = false |
|||
// 刷新当前订单数据 |
|||
setTimeout(() => app.getOrderDetail(true), 1500) |
|||
} |
|||
}, |
|||
|
|||
// 跳转到订单评价页 |
|||
handleTargetComment(orderId) { |
|||
this.$navTo('pages/order/comment/index', { orderId }) |
|||
}, |
|||
|
|||
}, |
|||
|
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
page { |
|||
background: #f4f4f4; |
|||
} |
|||
</style> |
|||
<style lang="scss" scoped> |
|||
.container { |
|||
// 设置ios刘海屏底部横线安全区域 |
|||
padding-bottom: constant(env(safe-area-inset-bottom) + 106rpx + 6rpx); |
|||
padding-bottom: calc(env(safe-area-inset-bottom) + 106rpx + 6rpx); |
|||
} |
|||
|
|||
// 页面顶部 |
|||
.header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
background-color: #e8c269; |
|||
height: 280rpx; |
|||
padding: 56rpx 30rpx 0 30rpx; |
|||
|
|||
.order-status { |
|||
display: flex; |
|||
align-items: center; |
|||
height: 128rpx; |
|||
|
|||
.status-icon { |
|||
width: 128rpx; |
|||
height: 128rpx; |
|||
|
|||
.image { |
|||
display: block; |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
} |
|||
|
|||
.status-text { |
|||
padding-left: 20rpx; |
|||
color: #fff; |
|||
font-size: 38rpx; |
|||
font-weight: bold; |
|||
} |
|||
} |
|||
|
|||
.next-action { |
|||
display: flex; |
|||
align-items: center; |
|||
height: 128rpx; |
|||
|
|||
.action-btn { |
|||
min-width: 152rpx; |
|||
height: 56rpx; |
|||
padding: 0 30rpx; |
|||
line-height: 56rpx; |
|||
background-color: #fff; |
|||
text-align: center; |
|||
border-radius: 28rpx; |
|||
border-color: rgb(102, 102, 102); |
|||
cursor: pointer; |
|||
user-select: none; |
|||
color: #c7a157; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 通栏卡片 |
|||
.i-card { |
|||
background: #fff; |
|||
padding: 24rpx 24rpx; |
|||
width: 94%; |
|||
box-shadow: 0 1rpx 5rpx 0px rgba(0, 0, 0, 0.05); |
|||
margin: 0 auto 20rpx auto; |
|||
border-radius: 20rpx; |
|||
} |
|||
|
|||
// 收货地址 |
|||
.delivery-address { |
|||
margin-top: -50rpx; |
|||
|
|||
.link-man { |
|||
line-height: 46rpx; |
|||
color: #333; |
|||
|
|||
.name { |
|||
margin-right: 10rpx; |
|||
} |
|||
} |
|||
|
|||
.address { |
|||
margin-top: 12rpx; |
|||
color: #999; |
|||
font-size: 24rpx; |
|||
|
|||
.detail { |
|||
margin-left: 6rpx; |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
// 物流公司 |
|||
.express { |
|||
display: flex; |
|||
align-items: center; |
|||
|
|||
.main { |
|||
flex: 1; |
|||
} |
|||
|
|||
.info-item { |
|||
display: flex; |
|||
margin-bottom: 24rpx; |
|||
|
|||
&:last-child { |
|||
margin-bottom: 0; |
|||
} |
|||
|
|||
.item-lable { |
|||
display: flex; |
|||
align-items: center; |
|||
font-size: 24rpx; |
|||
color: #999; |
|||
margin-right: 30rpx; |
|||
} |
|||
|
|||
.item-content { |
|||
flex: 1; |
|||
display: flex; |
|||
align-items: center; |
|||
font-size: 26rpx; |
|||
color: #333; |
|||
|
|||
.act-copy { |
|||
margin-left: 20rpx; |
|||
padding: 2rpx 20rpx; |
|||
font-size: 22rpx; |
|||
color: #666; |
|||
border: 1rpx solid #c1c1c1; |
|||
border-radius: 16rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
// 右侧箭头 |
|||
.right-arrow { |
|||
margin-left: 16rpx; |
|||
// color: #777; |
|||
font-size: 26rpx; |
|||
} |
|||
|
|||
} |
|||
|
|||
// 商品列表 |
|||
.goods-list { |
|||
|
|||
// 商品项 |
|||
.goods-item { |
|||
margin-bottom: 40rpx; |
|||
|
|||
&:last-child { |
|||
margin-bottom: 0; |
|||
} |
|||
|
|||
// 商品信息 |
|||
.goods-main { |
|||
display: flex; |
|||
} |
|||
|
|||
// 商品图片 |
|||
.goods-image { |
|||
width: 180rpx; |
|||
height: 180rpx; |
|||
|
|||
.image { |
|||
display: block; |
|||
width: 100%; |
|||
height: 100%; |
|||
border-radius: 8rpx; |
|||
} |
|||
} |
|||
|
|||
// 商品内容 |
|||
.goods-content { |
|||
flex: 1; |
|||
padding-left: 16rpx; |
|||
padding-top: 16rpx; |
|||
|
|||
.goods-title { |
|||
font-size: 26rpx; |
|||
max-height: 76rpx; |
|||
} |
|||
|
|||
.goods-props { |
|||
margin-top: 14rpx; |
|||
height: 40rpx; |
|||
color: #ababab; |
|||
font-size: 24rpx; |
|||
overflow: hidden; |
|||
|
|||
.goods-props-item { |
|||
display: inline-block; |
|||
margin-right: 14rpx; |
|||
padding: 4rpx 16rpx; |
|||
border-radius: 12rpx; |
|||
background-color: #F5F5F5; |
|||
width: auto; |
|||
} |
|||
} |
|||
|
|||
|
|||
} |
|||
|
|||
// 交易信息 |
|||
.goods-trade { |
|||
padding-top: 16rpx; |
|||
width: 150rpx; |
|||
text-align: right; |
|||
color: $uni-text-color-grey; |
|||
font-size: 26rpx; |
|||
|
|||
.goods-price { |
|||
vertical-align: bottom; |
|||
margin-bottom: 16rpx; |
|||
|
|||
.unit { |
|||
margin-right: -2rpx; |
|||
font-size: 24rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 商品售后 |
|||
.goods-refund { |
|||
display: flex; |
|||
justify-content: flex-end; |
|||
|
|||
.stata-text { |
|||
font-size: 24rpx; |
|||
color: #999; |
|||
} |
|||
|
|||
.action-btn { |
|||
border-radius: 28rpx; |
|||
padding: 8rpx 26rpx; |
|||
font-size: 24rpx; |
|||
color: #383838; |
|||
border: 1rpx solid #a8a8a8; |
|||
} |
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
// 订单信息 |
|||
.order-info { |
|||
|
|||
.info-item { |
|||
display: flex; |
|||
margin-bottom: 24rpx; |
|||
|
|||
&:last-child { |
|||
margin-bottom: 0; |
|||
} |
|||
|
|||
.item-lable { |
|||
display: flex; |
|||
align-items: center; |
|||
font-size: 24rpx; |
|||
color: #999; |
|||
margin-right: 30rpx; |
|||
} |
|||
|
|||
.item-content { |
|||
flex: 1; |
|||
display: flex; |
|||
align-items: center; |
|||
font-size: 26rpx; |
|||
color: #333; |
|||
|
|||
.act-copy { |
|||
margin-left: 20rpx; |
|||
padding: 2rpx 20rpx; |
|||
font-size: 22rpx; |
|||
color: #666; |
|||
border: 1rpx solid #c1c1c1; |
|||
border-radius: 16rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
// 交易信息 |
|||
.trade-info { |
|||
|
|||
.info-item { |
|||
display: flex; |
|||
margin-bottom: 24rpx; |
|||
|
|||
.item-lable { |
|||
font-size: 24rpx; |
|||
color: #999; |
|||
margin-right: 24rpx; |
|||
} |
|||
|
|||
.item-content { |
|||
flex: 1; |
|||
font-size: 26rpx; |
|||
color: #333; |
|||
text-align: right; |
|||
} |
|||
} |
|||
|
|||
.divider { |
|||
height: 1rpx; |
|||
background: #f1f1f1; |
|||
margin-bottom: 24rpx; |
|||
} |
|||
|
|||
.trade-total { |
|||
display: flex; |
|||
justify-content: flex-end; |
|||
|
|||
.goods-price { |
|||
margin-left: 12rpx; |
|||
vertical-align: bottom; |
|||
color: $uni-text-color-active; |
|||
|
|||
.unit { |
|||
margin-right: -2rpx; |
|||
font-size: 24rpx; |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
|
|||
/* 底部操作栏 */ |
|||
|
|||
.footer-fixed { |
|||
position: fixed; |
|||
bottom: var(--window-bottom); |
|||
left: 0; |
|||
right: 0; |
|||
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); |
|||
|
|||
.btn-wrapper { |
|||
height: 106rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: flex-end; |
|||
padding: 0 30rpx; |
|||
} |
|||
|
|||
.btn-item { |
|||
min-width: 164rpx; |
|||
border-radius: 28rpx; |
|||
padding: 10rpx 24rpx; |
|||
font-size: 28rpx; |
|||
color: #383838; |
|||
text-align: center; |
|||
border: 1rpx solid #a8a8a8; |
|||
margin-left: 24rpx; |
|||
|
|||
&.active { |
|||
color: #fff; |
|||
border: none; |
|||
background: linear-gradient(to right, #f9211c, #ff6335); |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
// 弹出层-支付方式 |
|||
.pay-popup { |
|||
padding: 24rpx; |
|||
|
|||
.title { |
|||
font-size: 30rpx; |
|||
margin-bottom: 50rpx; |
|||
font-weight: bold; |
|||
text-align: center; |
|||
} |
|||
|
|||
.pop-content { |
|||
min-height: 260rpx; |
|||
padding: 0 10rpx; |
|||
|
|||
.pay-item { |
|||
padding: 20rpx 35rpx; |
|||
font-size: 28rpx; |
|||
border-bottom: 1rpx solid #f1f1f1; |
|||
|
|||
&:last-child { |
|||
border-bottom: none; |
|||
} |
|||
|
|||
.item-left_icon { |
|||
margin-right: 20rpx; |
|||
font-size: 32rpx; |
|||
|
|||
&.wechat { |
|||
color: #00c800; |
|||
} |
|||
|
|||
&.balance { |
|||
color: #ff9700; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
// |
|||
</style> |
|||
@ -1,202 +0,0 @@ |
|||
<template> |
|||
<view v-if="!isLoading" class="container"> |
|||
<!-- 物流信息 --> |
|||
<view class="express i-card"> |
|||
<view class="info-item"> |
|||
<view class="item-lable">物流公司</view> |
|||
<view class="item-content"> |
|||
<text>{{ express.express_name }}</text> |
|||
</view> |
|||
</view> |
|||
<view class="info-item"> |
|||
<view class="item-lable">物流单号</view> |
|||
<view class="item-content"> |
|||
<text>{{ express.express_no }}</text> |
|||
<view class="act-copy" @click.stop="handleCopy(express.express_no)"> |
|||
<text>复制</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- 物流动态 --> |
|||
<view class="logis-detail"> |
|||
<view class="logis-item" :class="{ first: index === 0 }" v-for="(item, index) in express.list" :key="index"> |
|||
<view class="logis-item-content"> |
|||
<view class="logis-item-content__describe"> |
|||
<text class="f-26">{{ item.context }}</text> |
|||
</view> |
|||
<view class="logis-item-content__time"> |
|||
<text class="f-22">{{ item.ftime }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import * as OrderApi from '@/api/order' |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
// 正在加载 |
|||
isLoading: true, |
|||
// 当前订单ID |
|||
orderId: null, |
|||
// 物流信息 |
|||
express: {} |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
onLoad({ orderId }) { |
|||
this.orderId = orderId |
|||
// 获取当前订单的物流信息 |
|||
this.getExpress() |
|||
}, |
|||
|
|||
methods: { |
|||
|
|||
// 获取当前订单的物流信息 |
|||
getExpress() { |
|||
const app = this |
|||
app.isLoading = true |
|||
OrderApi.express(app.orderId) |
|||
.then(result => { |
|||
app.express = result.data.express |
|||
app.isLoading = false |
|||
}) |
|||
}, |
|||
|
|||
// 复制指定内容 |
|||
handleCopy(value) { |
|||
const app = this |
|||
uni.setClipboardData({ |
|||
data: value, |
|||
success() { |
|||
app.$toast('复制成功') |
|||
} |
|||
}) |
|||
} |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
// 通栏卡片 |
|||
.i-card { |
|||
background: #fff; |
|||
padding: 24rpx 24rpx; |
|||
// width: 94%; |
|||
box-shadow: 0 1rpx 5rpx 0px rgba(0, 0, 0, 0.05); |
|||
// margin: 0 auto 20rpx auto; |
|||
// border-radius: 20rpx; |
|||
} |
|||
|
|||
|
|||
// 物流公司 |
|||
.express { |
|||
|
|||
// margin-top: 24rpx; |
|||
|
|||
.info-item { |
|||
display: flex; |
|||
margin-bottom: 24rpx; |
|||
|
|||
&:last-child { |
|||
margin-bottom: 0; |
|||
} |
|||
|
|||
.item-lable { |
|||
display: flex; |
|||
align-items: center; |
|||
font-size: 24rpx; |
|||
color: #999; |
|||
margin-right: 30rpx; |
|||
} |
|||
|
|||
.item-content { |
|||
flex: 1; |
|||
display: flex; |
|||
align-items: center; |
|||
font-size: 26rpx; |
|||
color: #333; |
|||
|
|||
.act-copy { |
|||
margin-left: 20rpx; |
|||
padding: 2rpx 20rpx; |
|||
font-size: 22rpx; |
|||
color: #666; |
|||
border: 1rpx solid #c1c1c1; |
|||
border-radius: 16rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
|
|||
.logis-detail { |
|||
padding: 30rpx; |
|||
background-color: #fff; |
|||
|
|||
.logis-item { |
|||
position: relative; |
|||
padding: 10px 0 10px 25px; |
|||
box-sizing: border-box; |
|||
border-left: 2px solid #ccc; |
|||
|
|||
&.first { |
|||
border-left: 2px solid #f40; |
|||
|
|||
&:after { |
|||
background: #f40; |
|||
} |
|||
|
|||
.logis-item-content { |
|||
background: #ff6e39; |
|||
color: #fff; |
|||
|
|||
&:after { |
|||
border-bottom-color: #ff6e39; |
|||
} |
|||
} |
|||
} |
|||
|
|||
&:after { |
|||
content: ' '; |
|||
display: inline-block; |
|||
position: absolute; |
|||
left: -6px; |
|||
top: 30px; |
|||
width: 6px; |
|||
height: 6px; |
|||
border-radius: 10px; |
|||
background: #bdbdbd; |
|||
border: 2px solid #fff; |
|||
} |
|||
|
|||
.logis-item-content { |
|||
position: relative; |
|||
background: #f9f9f9; |
|||
padding: 10rpx 20rpx; |
|||
box-sizing: border-box; |
|||
color: #666; |
|||
|
|||
&:after { |
|||
content: ''; |
|||
display: inline-block; |
|||
position: absolute; |
|||
left: -10px; |
|||
top: 18px; |
|||
border-left: 10px solid #fff; |
|||
border-bottom: 10px solid #f3f3f3; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,596 +0,0 @@ |
|||
<template> |
|||
<view class="container"> |
|||
<mescroll-body ref="mescrollRef" :sticky="true" @init="mescrollInit" :down="{ native: true }" @down="downCallback" :up="upOption" @up="upCallback"> |
|||
|
|||
<!-- tab栏 --> |
|||
<u-tabs :list="tabs" :is-scroll="false" :current="curTab" active-color="#FA2209" :duration="0.2" @change="onChangeTab" /> |
|||
|
|||
<!-- 订单列表 --> |
|||
<view class="order-list"> |
|||
<view class="order-item" v-for="(item, index) in list.data" :key="index"> |
|||
<view class="item-top"> |
|||
<view class="item-top-left"> |
|||
<text class="order-time">{{ item.create_time }}</text> |
|||
</view> |
|||
<view class="item-top-right"> |
|||
<text class="state-text">{{ item.state_text }}</text> |
|||
</view> |
|||
</view> |
|||
<!-- 商品列表 --> |
|||
<view class="goods-list" @click="handleTargetDetail(item.order_id)"> |
|||
<view class="goods-item" v-for="(goods, idx) in item.goods" :key="idx"> |
|||
<!-- 商品图片 --> |
|||
<view class="goods-image"> |
|||
<image class="image" :src="goods.goods_image" mode="scaleToFill"></image> |
|||
</view> |
|||
<!-- 商品信息 --> |
|||
<view class="goods-content"> |
|||
<view class="goods-title"><text class="twoline-hide">{{ goods.goods_name }}</text></view> |
|||
<view class="goods-props clearfix"> |
|||
<view class="goods-props-item" v-for="(props, idx) in goods.goods_props" :key="idx"> |
|||
<text>{{ props.value.name }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- 交易信息 --> |
|||
<view class="goods-trade"> |
|||
<view class="goods-price"> |
|||
<text class="unit">¥</text> |
|||
<text class="value">{{ goods.is_user_grade ? goods.grade_goods_price : goods.goods_price }}</text> |
|||
</view> |
|||
<view class="goods-num"> |
|||
<text>×{{ goods.total_num }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- 订单合计 --> |
|||
<view class="order-total"> |
|||
<text>共{{ item.total_num }}件商品,总金额</text> |
|||
<text class="unit">¥</text> |
|||
<text class="money">{{ item.pay_price }}</text> |
|||
</view> |
|||
<!-- 订单操作 --> |
|||
<view v-if="item.order_status != OrderStatusEnum.CANCELLED.value" class="order-handle"> |
|||
<view class="btn-group clearfix"> |
|||
<!-- 未支付取消订单 --> |
|||
<block v-if="item.pay_status == PayStatusEnum.PENDING.value"> |
|||
<view class="btn-item" @click="onCancel(item.order_id)">取消</view> |
|||
</block> |
|||
<!-- 已支付进行中的订单 --> |
|||
<block v-if="item.order_status != OrderStatusEnum.APPLY_CANCEL.value"> |
|||
<block v-if="item.pay_status == PayStatusEnum.SUCCESS.value && item.delivery_status == DeliveryStatusEnum.NOT_DELIVERED.value"> |
|||
<view class="btn-item" @click="onCancel(item.order_id)">申请取消</view> |
|||
</block> |
|||
</block> |
|||
<!-- 已申请取消 --> |
|||
<view v-else class="f-28 col-8">取消申请中</view> |
|||
<!-- 未支付的订单 --> |
|||
<block v-if="item.pay_status == PayStatusEnum.PENDING.value"> |
|||
<view class="btn-item active" @click="onPay(item.order_id)">去支付</view> |
|||
</block> |
|||
<!-- 确认收货 --> |
|||
<block v-if="item.delivery_status == DeliveryStatusEnum.DELIVERED.value && item.receipt_status == ReceiptStatusEnum.NOT_RECEIVED.value"> |
|||
<view class="btn-item active" @click="onReceipt(item.order_id)">确认收货</view> |
|||
</block> |
|||
<!-- 订单评价 --> |
|||
<block v-if="item.order_status == OrderStatusEnum.COMPLETED.value && item.is_comment == 0"> |
|||
<view class="btn-item" @click="handleTargetComment(item.order_id)">评价</view> |
|||
</block> |
|||
</view> |
|||
</view> |
|||
|
|||
</view> |
|||
</view> |
|||
</mescroll-body> |
|||
|
|||
<!-- 支付方式弹窗 --> |
|||
<u-popup v-model="showPayPopup" mode="bottom" border-radius="26" :closeable="true"> |
|||
<view class="pay-popup"> |
|||
<view class="title">请选择支付方式</view> |
|||
<view class="pop-content"> |
|||
<!-- 微信支付 --> |
|||
<!-- #ifdef MP-WEIXIN --> |
|||
<view class="pay-item dis-flex flex-x-between" @click="onSelectPayType(PayTypeEnum.WECHAT.value)"> |
|||
<view class="item-left dis-flex flex-y-center"> |
|||
<view class="item-left_icon wechat"> |
|||
<text class="iconfont icon-wechat-pay"></text> |
|||
</view> |
|||
<view class="item-left_text"> |
|||
<text>{{ PayTypeEnum.WECHAT.name }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- #endif --> |
|||
<!-- 余额支付 --> |
|||
<view class="pay-item dis-flex flex-x-between" @click="onSelectPayType(PayTypeEnum.BALANCE.value)"> |
|||
<view class="item-left dis-flex flex-y-center"> |
|||
<view class="item-left_icon balance"> |
|||
<text class="iconfont icon-balance-pay"></text> |
|||
</view> |
|||
<view class="item-left_text"> |
|||
<text>{{ PayTypeEnum.BALANCE.name }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</u-popup> |
|||
|
|||
</view> |
|||
|
|||
</template> |
|||
|
|||
<script> |
|||
import { |
|||
DeliveryStatusEnum, |
|||
DeliveryTypeEnum, |
|||
OrderStatusEnum, |
|||
PayStatusEnum, |
|||
PayTypeEnum, |
|||
ReceiptStatusEnum |
|||
} from '@/common/enum/order' |
|||
import MescrollBody from '@/components/mescroll-uni/mescroll-body.vue' |
|||
import MescrollMixin from '@/components/mescroll-uni/mescroll-mixins' |
|||
import { getEmptyPaginateObj, getMoreListData } from '@/core/app' |
|||
import * as OrderApi from '@/api/order' |
|||
import { wxPayment } from '@/core/app' |
|||
|
|||
// 每页记录数量 |
|||
const pageSize = 15 |
|||
|
|||
// tab栏数据 |
|||
const tabs = [{ |
|||
name: `全部`, |
|||
value: 'all' |
|||
}, { |
|||
name: `待支付`, |
|||
value: 'payment' |
|||
}, { |
|||
name: `待发货`, |
|||
value: 'delivery' |
|||
}, { |
|||
name: `待收货`, |
|||
value: 'received' |
|||
}, { |
|||
name: `待评价`, |
|||
value: 'comment' |
|||
}] |
|||
|
|||
export default { |
|||
components: { |
|||
MescrollBody |
|||
}, |
|||
mixins: [MescrollMixin], |
|||
data() { |
|||
return { |
|||
// 枚举类 |
|||
DeliveryStatusEnum, |
|||
DeliveryTypeEnum, |
|||
OrderStatusEnum, |
|||
PayStatusEnum, |
|||
PayTypeEnum, |
|||
ReceiptStatusEnum, |
|||
|
|||
// 当前页面参数 |
|||
options: { dataType: 'all' }, |
|||
// tab栏数据 |
|||
tabs, |
|||
// 当前标签索引 |
|||
curTab: 0, |
|||
// 订单列表数据 |
|||
list: getEmptyPaginateObj(), |
|||
|
|||
// 上拉加载配置 |
|||
upOption: { |
|||
// 首次自动执行 |
|||
auto: true, |
|||
// 每页数据的数量; 默认10 |
|||
page: { size: pageSize }, |
|||
// 数量要大于4条才显示无更多数据 |
|||
noMoreSize: 4, |
|||
// 空布局 |
|||
empty: { |
|||
tip: '亲,暂无订单记录' |
|||
} |
|||
}, |
|||
// 控制onShow事件是否刷新订单列表 |
|||
canReset: false, |
|||
// 支付方式弹窗 |
|||
showPayPopup: false |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
onLoad(options) { |
|||
// 初始化当前选中的标签 |
|||
this.initCurTab(options) |
|||
// 注册全局事件订阅: 是否刷新订单列表 |
|||
uni.$on('syncRefresh', canReset => { |
|||
this.canReset = canReset |
|||
}) |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面显示 |
|||
*/ |
|||
onShow() { |
|||
this.canReset && this.onRefreshList() |
|||
this.canReset = false |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面的卸载 |
|||
*/ |
|||
onUnload() { |
|||
// 卸载全局事件订阅 |
|||
uni.$off('syncRefresh') |
|||
}, |
|||
|
|||
methods: { |
|||
|
|||
// 初始化当前选中的标签 |
|||
initCurTab(options) { |
|||
const app = this |
|||
if (options.dataType) { |
|||
const index = app.tabs.findIndex(item => item.value == options.dataType) |
|||
app.curTab = index > -1 ? index : 0 |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 上拉加载的回调 (页面初始化时也会执行一次) |
|||
* 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10 |
|||
* @param {Object} page |
|||
*/ |
|||
upCallback(page) { |
|||
const app = this |
|||
// 设置列表数据 |
|||
app.getOrderList(page.num) |
|||
.then(list => { |
|||
const curPageLen = list.data.length |
|||
const totalSize = list.data.total |
|||
app.mescroll.endBySize(curPageLen, totalSize) |
|||
}) |
|||
.catch(() => app.mescroll.endErr()) |
|||
}, |
|||
|
|||
// 获取订单列表 |
|||
getOrderList(pageNo = 1) { |
|||
const app = this |
|||
return new Promise((resolve, reject) => { |
|||
OrderApi.list({ dataType: app.getTabValue(), page: pageNo }, { load: false }) |
|||
.then(result => { |
|||
// 合并新数据 |
|||
const newList = app.initList(result.data.list) |
|||
app.list.data = getMoreListData(newList, app.list, pageNo) |
|||
resolve(newList) |
|||
}) |
|||
}) |
|||
}, |
|||
|
|||
// 初始化订单列表数据 |
|||
initList(newList) { |
|||
newList.data.forEach(item => { |
|||
item.total_num = 0 |
|||
item.goods.forEach(goods => { |
|||
item.total_num += goods.total_num |
|||
}) |
|||
}) |
|||
return newList |
|||
}, |
|||
|
|||
// 获取当前标签项的值 |
|||
getTabValue() { |
|||
return this.tabs[this.curTab].value |
|||
}, |
|||
|
|||
// 切换标签项 |
|||
onChangeTab(index) { |
|||
const app = this |
|||
// 设置当前选中的标签 |
|||
app.curTab = index |
|||
// 刷新订单列表 |
|||
app.onRefreshList() |
|||
}, |
|||
|
|||
// 刷新订单列表 |
|||
onRefreshList() { |
|||
this.list = getEmptyPaginateObj() |
|||
setTimeout(() => { |
|||
this.mescroll.resetUpScroll() |
|||
}, 120) |
|||
}, |
|||
|
|||
// 取消订单 |
|||
onCancel(orderId) { |
|||
const app = this |
|||
uni.showModal({ |
|||
title: '友情提示', |
|||
content: '确认要取消该订单吗?', |
|||
success(o) { |
|||
if (o.confirm) { |
|||
OrderApi.cancel(orderId) |
|||
.then(result => { |
|||
// 显示成功信息 |
|||
app.$toast(result.message) |
|||
// 刷新订单列表 |
|||
app.onRefreshList() |
|||
}) |
|||
} |
|||
} |
|||
}); |
|||
}, |
|||
|
|||
// 确认收货 |
|||
onReceipt(orderId) { |
|||
const app = this |
|||
uni.showModal({ |
|||
title: '友情提示', |
|||
content: '确认收到商品了吗?', |
|||
success(o) { |
|||
if (o.confirm) { |
|||
OrderApi.receipt(orderId) |
|||
.then(result => { |
|||
// 显示成功信息 |
|||
app.$success(result.message) |
|||
// 刷新订单列表 |
|||
app.onRefreshList() |
|||
}) |
|||
} |
|||
} |
|||
}); |
|||
}, |
|||
|
|||
// 点击去支付 |
|||
onPay(orderId) { |
|||
// 记录订单id |
|||
this.payOrderId = orderId |
|||
// 显示支付方式弹窗 |
|||
this.showPayPopup = true |
|||
}, |
|||
|
|||
// 选择支付方式 |
|||
onSelectPayType(payType) { |
|||
const app = this |
|||
// 隐藏支付方式弹窗 |
|||
this.showPayPopup = false |
|||
// 发起支付请求 |
|||
OrderApi.pay(app.payOrderId, payType) |
|||
.then(result => app.onSubmitCallback(result)) |
|||
}, |
|||
|
|||
// 订单提交成功后回调 |
|||
onSubmitCallback(result) { |
|||
const app = this |
|||
// 发起微信支付 |
|||
if (result.data.pay_type == PayTypeEnum.WECHAT.value) { |
|||
wxPayment(result.data.payment) |
|||
.then(() => { |
|||
app.$success('支付成功') |
|||
setTimeout(() => { |
|||
app.onRefreshList() |
|||
}, 1500) |
|||
}) |
|||
.catch(err => { |
|||
app.$error('订单未支付') |
|||
}) |
|||
.finally(() => { |
|||
app.disabled = false |
|||
}) |
|||
} |
|||
// 余额支付 |
|||
if (result.data.pay_type == PayTypeEnum.BALANCE.value) { |
|||
app.$success('支付成功') |
|||
app.disabled = false |
|||
setTimeout(() => { |
|||
app.onRefreshList() |
|||
}, 1500) |
|||
} |
|||
}, |
|||
|
|||
// 跳转到订单详情页 |
|||
handleTargetDetail(orderId) { |
|||
this.$navTo('pages/order/detail', { orderId }) |
|||
}, |
|||
|
|||
// 跳转到订单评价页 |
|||
handleTargetComment(orderId) { |
|||
this.$navTo('pages/order/comment/index', { orderId }) |
|||
} |
|||
|
|||
}, |
|||
|
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
// 项目内容 |
|||
.order-item { |
|||
margin: 20rpx auto 20rpx auto; |
|||
padding: 30rpx 30rpx; |
|||
width: 94%; |
|||
box-shadow: 0 1rpx 5rpx 0px rgba(0, 0, 0, 0.05); |
|||
border-radius: 16rpx; |
|||
background: #fff; |
|||
} |
|||
|
|||
// 项目顶部 |
|||
.item-top { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
font-size: 26rpx; |
|||
margin-bottom: 40rpx; |
|||
|
|||
.order-time { |
|||
color: #777; |
|||
} |
|||
|
|||
.state-text { |
|||
color: $uni-text-color-active; |
|||
} |
|||
} |
|||
|
|||
// 商品列表 |
|||
.goods-list { |
|||
|
|||
// 商品项 |
|||
.goods-item { |
|||
display: flex; |
|||
margin-bottom: 40rpx; |
|||
|
|||
// 商品图片 |
|||
.goods-image { |
|||
width: 180rpx; |
|||
height: 180rpx; |
|||
|
|||
.image { |
|||
display: block; |
|||
width: 100%; |
|||
height: 100%; |
|||
border-radius: 8rpx; |
|||
} |
|||
} |
|||
|
|||
// 商品内容 |
|||
.goods-content { |
|||
flex: 1; |
|||
padding-left: 16rpx; |
|||
padding-top: 16rpx; |
|||
|
|||
.goods-title { |
|||
font-size: 26rpx; |
|||
max-height: 76rpx; |
|||
} |
|||
|
|||
.goods-props { |
|||
margin-top: 14rpx; |
|||
height: 40rpx; |
|||
color: #ababab; |
|||
font-size: 24rpx; |
|||
overflow: hidden; |
|||
|
|||
.goods-props-item { |
|||
display: inline-block; |
|||
margin-right: 14rpx; |
|||
padding: 4rpx 16rpx; |
|||
border-radius: 12rpx; |
|||
background-color: #F5F5F5; |
|||
width: auto; |
|||
} |
|||
} |
|||
|
|||
|
|||
} |
|||
|
|||
// 交易信息 |
|||
.goods-trade { |
|||
padding-top: 16rpx; |
|||
width: 150rpx; |
|||
text-align: right; |
|||
color: $uni-text-color-grey; |
|||
font-size: 26rpx; |
|||
|
|||
.goods-price { |
|||
vertical-align: bottom; |
|||
margin-bottom: 16rpx; |
|||
|
|||
.unit { |
|||
margin-right: -2rpx; |
|||
font-size: 24rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
// 订单合计 |
|||
.order-total { |
|||
font-size: 26rpx; |
|||
vertical-align: bottom; |
|||
text-align: right; |
|||
height: 40rpx; |
|||
margin-bottom: 30rpx; |
|||
|
|||
.unit { |
|||
margin-left: 8rpx; |
|||
margin-right: -2rpx; |
|||
font-size: 26rpx; |
|||
} |
|||
|
|||
.money { |
|||
font-size: 28rpx; |
|||
} |
|||
} |
|||
|
|||
// 订单操作 |
|||
.order-handle { |
|||
.btn-group { |
|||
|
|||
.btn-item { |
|||
border-radius: 10rpx; |
|||
padding: 6rpx 20rpx; |
|||
margin-left: 15rpx; |
|||
font-size: 28rpx; |
|||
float: right; |
|||
color: #383838; |
|||
border: 1rpx solid #a8a8a8; |
|||
|
|||
&:last-child { |
|||
margin-left: 0; |
|||
} |
|||
|
|||
&.active { |
|||
color: $uni-text-color-active; |
|||
border: 1rpx solid $uni-text-color-active; |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
// 弹出层-支付方式 |
|||
.pay-popup { |
|||
padding: 24rpx; |
|||
|
|||
.title { |
|||
font-size: 30rpx; |
|||
margin-bottom: 40rpx; |
|||
font-weight: bold; |
|||
text-align: center; |
|||
} |
|||
|
|||
.pop-content { |
|||
min-height: 260rpx; |
|||
padding: 0 10rpx; |
|||
|
|||
.pay-item { |
|||
padding: 24rpx 35rpx; |
|||
font-size: 28rpx; |
|||
border-bottom: 1rpx solid #f1f1f1; |
|||
|
|||
&:last-child { |
|||
border-bottom: none; |
|||
} |
|||
|
|||
.item-left_icon { |
|||
margin-right: 20rpx; |
|||
font-size: 32rpx; |
|||
|
|||
&.wechat { |
|||
color: #00c800; |
|||
} |
|||
|
|||
&.balance { |
|||
color: #ff9700; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,127 +0,0 @@ |
|||
<template> |
|||
<view class="container"> |
|||
<mescroll-body ref="mescrollRef" :sticky="true" @init="mescrollInit" :down="{ use: false }" :up="upOption" |
|||
@up="upCallback"> |
|||
<view class="log-list"> |
|||
<view v-for="(item, index) in list.data" :key="index" class="log-item"> |
|||
<view class="item-left flex-box"> |
|||
<view class="rec-status"> |
|||
<text>{{ item.describe }}</text> |
|||
</view> |
|||
<view class="rec-time"> |
|||
<text>{{ item.create_time }}</text> |
|||
</view> |
|||
</view> |
|||
<view class="item-right" :class="[item.value > 0 ? 'col-green' : 'col-6']"> |
|||
<text>{{ item.value > 0 ? '+' : '' }}{{ item.value }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</mescroll-body> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import MescrollBody from '@/components/mescroll-uni/mescroll-body.vue' |
|||
import MescrollMixin from '@/components/mescroll-uni/mescroll-mixins' |
|||
import * as LogApi from '@/api/points/log' |
|||
import { getEmptyPaginateObj, getMoreListData } from '@/core/app' |
|||
|
|||
const pageSize = 15 |
|||
|
|||
export default { |
|||
components: { |
|||
MescrollBody |
|||
}, |
|||
mixins: [MescrollMixin], |
|||
data() { |
|||
return { |
|||
// 充值记录 |
|||
list: getEmptyPaginateObj(), |
|||
// 上拉加载配置 |
|||
upOption: { |
|||
// 首次自动执行 |
|||
auto: true, |
|||
// 每页数据的数量; 默认10 |
|||
page: { size: pageSize }, |
|||
// 数量要大于12条才显示无更多数据 |
|||
noMoreSize: 12, |
|||
// 空布局 |
|||
empty: { |
|||
tip: '亲,暂无相关数据' |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
onLoad(options) {}, |
|||
|
|||
methods: { |
|||
|
|||
/** |
|||
* 上拉加载的回调 (页面初始化时也会执行一次) |
|||
* 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10 |
|||
* @param {Object} page |
|||
*/ |
|||
upCallback(page) { |
|||
const app = this |
|||
// 设置列表数据 |
|||
app.getLogList(page.num) |
|||
.then(list => { |
|||
const curPageLen = list.data.length |
|||
const totalSize = list.data.total |
|||
app.mescroll.endBySize(curPageLen, totalSize) |
|||
}) |
|||
.catch(() => app.mescroll.endErr()) |
|||
}, |
|||
|
|||
// 获取积分明细列表 |
|||
getLogList(pageNo = 1) { |
|||
const app = this |
|||
return new Promise((resolve, reject) => { |
|||
LogApi.list({ page: pageNo }) |
|||
.then(result => { |
|||
// 合并新数据 |
|||
const newList = result.data.list |
|||
app.list.data = getMoreListData(newList, app.list, pageNo) |
|||
resolve(newList) |
|||
}) |
|||
}) |
|||
} |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
page, |
|||
.container { |
|||
background: #fff; |
|||
} |
|||
|
|||
.log-list { |
|||
padding: 0 30rpx; |
|||
} |
|||
|
|||
.log-item { |
|||
font-size: 28rpx; |
|||
padding: 20rpx 20rpx; |
|||
line-height: 1.8; |
|||
border-bottom: 1rpx solid rgb(238, 238, 238); |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
|
|||
.rec-status { |
|||
color: #333; |
|||
|
|||
.rec-time { |
|||
color: rgb(160, 160, 160); |
|||
font-size: 26rpx; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,429 +0,0 @@ |
|||
<template> |
|||
<view v-if="!isLoading" class="container"> |
|||
|
|||
<!-- 商品详情 --> |
|||
<view class="goods-detail b-f dis-flex flex-dir-row"> |
|||
<view class="left"> |
|||
<image class="goods-image" :src="goods.goods_image"></image> |
|||
</view> |
|||
<view class="right dis-flex flex-box flex-dir-column flex-x-around"> |
|||
<view class="goods-name"> |
|||
<text class="twoline-hide">{{ goods.goods_name }}</text> |
|||
</view> |
|||
<view class="dis-flex col-9 f-24"> |
|||
<view class="flex-box"> |
|||
<view class="goods-props clearfix"> |
|||
<view class="goods-props-item" v-for="(props, idx) in goods.goods_props" :key="idx"> |
|||
<text>{{ props.value.name }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<text class="t-r">×{{ goods.total_num }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 服务类型 --> |
|||
<view class="row-service b-f m-top20"> |
|||
<view class="row-title">服务类型</view> |
|||
<view class="service-switch dis-flex"> |
|||
<view class="switch-item" v-for="(item, index) in RefundTypeEnum.data" :key="index" :class="{ active: formData.type == item.value }" |
|||
@click="onSwitchService(item.value)">{{ item.name }}</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 申请原因 --> |
|||
<view class="row-textarea b-f m-top20"> |
|||
<view class="row-title">申请原因</view> |
|||
<view class="content"> |
|||
<textarea class="textarea" v-model="formData.content" maxlength="2000" placeholder="请详细填写申请原因,注意保持商品的完好,建议您先与卖家沟通" |
|||
placeholderStyle="color:#ccc"></textarea> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 退款金额 --> |
|||
<view v-if="formData.type == RefundTypeEnum.RETURN.value" class="row-money b-f m-top20 dis-flex"> |
|||
<view class="row-title">退款金额</view> |
|||
<view class="money col-m">¥{{ goods.total_pay_price }}</view> |
|||
</view> |
|||
|
|||
<!-- 上传凭证 --> |
|||
<view class="row-voucher b-f m-top20"> |
|||
<view class="row-title">上传凭证 (最多6张)</view> |
|||
<view class="image-list"> |
|||
<!-- 图片列表 --> |
|||
<view class="image-preview" v-for="(image, imageIndex) in imageList" :key="imageIndex"> |
|||
<text class="image-delete iconfont icon-shanchu" @click="deleteImage(imageIndex)"></text> |
|||
<image class="image" mode="aspectFill" :src="image.path"></image> |
|||
</view> |
|||
<!-- 上传图片 --> |
|||
<view v-if="imageList.length < maxImageLength" class="image-picker" @click="chooseImage()"> |
|||
<text class="choose-icon iconfont icon-camera"></text> |
|||
<text class="choose-text">上传图片</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 底部操作按钮 --> |
|||
<view class="footer-fixed"> |
|||
<view class="btn-wrapper"> |
|||
<view class="btn-item btn-item-main" :class="{ disabled }" @click="handleSubmit()">确认提交</view> |
|||
</view> |
|||
</view> |
|||
|
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { RefundTypeEnum } from '@/common/enum/order/refund' |
|||
import * as UploadApi from '@/api/upload' |
|||
import * as RefundApi from '@/api/refund' |
|||
|
|||
const maxImageLength = 6 |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
// 枚举类 |
|||
RefundTypeEnum, |
|||
// 正在加载 |
|||
isLoading: true, |
|||
// 订单商品id |
|||
orderGoodsId: null, |
|||
// 订单商品详情 |
|||
goods: {}, |
|||
// 表单数据 |
|||
formData: { |
|||
// 图片上传成功的文件ID集 |
|||
images: [], |
|||
// 服务类型 |
|||
type: 10, |
|||
// 申请原因 |
|||
content: '' |
|||
}, |
|||
// 用户选择的图片列表 |
|||
imageList: [], |
|||
// 最大图片数量 |
|||
maxImageLength, |
|||
// 按钮禁用 |
|||
disabled: false |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
onLoad({ orderGoodsId }) { |
|||
this.orderGoodsId = orderGoodsId |
|||
// 获取订单商品详情 |
|||
this.getGoodsDetail() |
|||
}, |
|||
|
|||
methods: { |
|||
|
|||
// 获取订单商品详情 |
|||
getGoodsDetail() { |
|||
const app = this |
|||
app.isLoading = true |
|||
RefundApi.goods(app.orderGoodsId) |
|||
.then(result => { |
|||
app.goods = result.data.goods |
|||
app.isLoading = false |
|||
}) |
|||
}, |
|||
|
|||
// 切换类型 |
|||
onSwitchService(value) { |
|||
this.formData.type = value |
|||
}, |
|||
|
|||
// 选择图片 |
|||
chooseImage() { |
|||
const app = this |
|||
const oldImageList = app.imageList |
|||
// 选择图片 |
|||
uni.chooseImage({ |
|||
count: maxImageLength - oldImageList.length, |
|||
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有 |
|||
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有 |
|||
success({ tempFiles }) { |
|||
// tempFiles = [{path:'xxx', size:100}] |
|||
app.imageList = oldImageList.concat(tempFiles) |
|||
} |
|||
}); |
|||
}, |
|||
|
|||
// 删除图片 |
|||
deleteImage(imageIndex) { |
|||
this.imageList.splice(imageIndex, 1) |
|||
}, |
|||
|
|||
// 表单提交 |
|||
handleSubmit() { |
|||
const app = this |
|||
const { imageList } = app |
|||
// 判断是否重复提交 |
|||
if (app.disabled === true) return false |
|||
// 按钮禁用 |
|||
app.disabled = true |
|||
// 判断是否需要上传图片 |
|||
if (imageList.length > 0) { |
|||
app.uploadFile() |
|||
.then(() => app.onSubmit()) |
|||
.catch(err => { |
|||
app.disabled = false |
|||
if (err.statusCode !== 0) { |
|||
app.$toast(err.errMsg) |
|||
} |
|||
console.log('err', err) |
|||
}) |
|||
} else { |
|||
app.onSubmit() |
|||
} |
|||
}, |
|||
|
|||
// 提交到后端 |
|||
onSubmit() { |
|||
const app = this |
|||
RefundApi.apply(app.orderGoodsId, app.formData) |
|||
.then(result => { |
|||
app.$toast(result.message) |
|||
setTimeout(() => { |
|||
app.disabled = false |
|||
uni.navigateBack() |
|||
}, 1500) |
|||
}) |
|||
.catch(err => app.disabled = false) |
|||
}, |
|||
|
|||
// 上传图片 |
|||
uploadFile() { |
|||
const app = this |
|||
const { imageList } = app |
|||
// 批量上传 |
|||
return new Promise((resolve, reject) => { |
|||
if (imageList.length > 0) { |
|||
UploadApi.image(imageList) |
|||
.then(fileIds => { |
|||
app.formData.images = fileIds |
|||
resolve(fileIds) |
|||
}) |
|||
.catch(reject) |
|||
} else { |
|||
resolve() |
|||
} |
|||
}) |
|||
} |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.container { |
|||
// 设置ios刘海屏底部横线安全区域 |
|||
padding-bottom: calc(constant(safe-area-inset-bottom) + 140rpx); |
|||
padding-bottom: calc(env(safe-area-inset-bottom) + 140rpx); |
|||
} |
|||
|
|||
.row-title { |
|||
color: #888; |
|||
margin-bottom: 20rpx; |
|||
} |
|||
|
|||
// 商品信息 |
|||
.goods-detail { |
|||
padding: 24rpx 20rpx; |
|||
|
|||
.left { |
|||
.goods-image { |
|||
display: block; |
|||
width: 150rpx; |
|||
height: 150rpx; |
|||
} |
|||
} |
|||
|
|||
.right { |
|||
padding-left: 20rpx; |
|||
} |
|||
|
|||
.goods-props { |
|||
margin-top: 14rpx; |
|||
height: 40rpx; |
|||
color: #ababab; |
|||
font-size: 24rpx; |
|||
overflow: hidden; |
|||
|
|||
.goods-props-item { |
|||
display: inline-block; |
|||
margin-right: 14rpx; |
|||
padding: 4rpx 16rpx; |
|||
border-radius: 12rpx; |
|||
background-color: #F5F5F5; |
|||
width: auto; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/* 服务类型 */ |
|||
.row-service { |
|||
padding: 24rpx 20rpx; |
|||
} |
|||
|
|||
.service-switch { |
|||
.switch-item { |
|||
padding: 6rpx 30rpx; |
|||
margin-right: 25rpx; |
|||
border-radius: 10rpx; |
|||
border: 1px solid rgb(177, 177, 177); |
|||
color: #888; |
|||
|
|||
&.active { |
|||
color: #fc1e56; |
|||
border: 1px solid #fc1e56; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/* 申请原因 */ |
|||
.row-textarea { |
|||
padding: 24rpx 20rpx; |
|||
|
|||
.textarea { |
|||
width: 100%; |
|||
height: 220rpx; |
|||
padding: 12rpx; |
|||
border: 1rpx solid #e8e8e8; |
|||
border-radius: 5rpx; |
|||
box-sizing: border-box; |
|||
font-size: 26rpx; |
|||
} |
|||
} |
|||
|
|||
/* 退款金额 */ |
|||
.row-money { |
|||
padding: 24rpx 20rpx; |
|||
|
|||
.row-title { |
|||
margin-bottom: 0; |
|||
margin-right: 30rpx; |
|||
} |
|||
} |
|||
|
|||
// 上传凭证 |
|||
.row-voucher { |
|||
padding: 24rpx 20rpx; |
|||
|
|||
.image-list { |
|||
padding: 0 20rpx; |
|||
margin-top: 20rpx; |
|||
margin-bottom: -20rpx; |
|||
|
|||
&:after { |
|||
clear: both; |
|||
content: " "; |
|||
display: table; |
|||
} |
|||
|
|||
.image { |
|||
display: block; |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
|
|||
.image-picker, |
|||
.image-preview { |
|||
width: 184rpx; |
|||
height: 184rpx; |
|||
margin-right: 30rpx; |
|||
margin-bottom: 30rpx; |
|||
float: left; |
|||
|
|||
&:nth-child(3n+0) { |
|||
margin-right: 0; |
|||
} |
|||
} |
|||
|
|||
.image-picker { |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
align-items: center; |
|||
border: 1rpx dashed #ccc; |
|||
color: #ccc; |
|||
|
|||
.choose-icon { |
|||
font-size: 48rpx; |
|||
margin-bottom: 6rpx; |
|||
} |
|||
|
|||
.choose-text { |
|||
font-size: 24rpx; |
|||
} |
|||
} |
|||
|
|||
.image-preview { |
|||
position: relative; |
|||
|
|||
.image-delete { |
|||
position: absolute; |
|||
top: -15rpx; |
|||
right: -15rpx; |
|||
height: 42rpx; |
|||
width: 42rpx; |
|||
line-height: 42rpx; |
|||
background: rgba(0, 0, 0, 0.64); |
|||
border-radius: 50%; |
|||
color: #fff; |
|||
font-weight: bolder; |
|||
font-size: 22rpx; |
|||
z-index: 10; |
|||
text-align: center; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
// 底部操作栏 |
|||
.footer-fixed { |
|||
position: fixed; |
|||
bottom: var(--window-bottom); |
|||
left: 0; |
|||
right: 0; |
|||
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); |
|||
|
|||
.btn-wrapper { |
|||
height: 120rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 0 20rpx; |
|||
} |
|||
|
|||
.btn-item { |
|||
flex: 1; |
|||
font-size: 28rpx; |
|||
height: 80rpx; |
|||
line-height: 80rpx; |
|||
text-align: center; |
|||
color: #fff; |
|||
border-radius: 50rpx; |
|||
} |
|||
|
|||
.btn-item-main { |
|||
background: linear-gradient(to right, #f9211c, #ff6335); |
|||
|
|||
// 禁用按钮 |
|||
&.disabled { |
|||
background: #ff9779; |
|||
} |
|||
} |
|||
|
|||
} |
|||
</style> |
|||
@ -1,483 +0,0 @@ |
|||
<template> |
|||
<view v-if="!isLoading" class="container p-bottom"> |
|||
|
|||
<!-- 顶部状态栏 --> |
|||
<view class="detail-header dis-flex flex-y-center"> |
|||
<view class="header-backdrop"> |
|||
<image class="image" src="/static/order/refund-bg.png"></image> |
|||
</view> |
|||
<view class="header-state"> |
|||
<text class="f-32 col-f">{{ detail.state_text }}</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 商品详情 --> |
|||
<view class="detail-goods b-f m-top20 dis-flex flex-dir-row" @click="onGoodsDetail(detail.orderGoods.goods_id)"> |
|||
<view class="left"> |
|||
<image class="goods-image" :src="detail.orderGoods.goods_image"></image> |
|||
</view> |
|||
<view class="right dis-flex flex-box flex-dir-column flex-x-around"> |
|||
<view class="goods-name"> |
|||
<text class="twoline-hide">{{ detail.orderGoods.goods_name }}</text> |
|||
</view> |
|||
<view class="dis-flex col-9 f-24"> |
|||
<view class="flex-box"> |
|||
<view class="goods-props clearfix"> |
|||
<view class="goods-props-item" v-for="(props, idx) in detail.orderGoods.goods_props" :key="idx"> |
|||
<text>{{ props.value.name }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<text class="t-r">×{{ detail.orderGoods.total_num }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 商品金额 --> |
|||
<view class="detail-order b-f row-block"> |
|||
<view class="item dis-flex flex-x-end flex-y-center"> |
|||
<text class="">商品金额:</text> |
|||
<text class="col-m">¥{{ detail.orderGoods.total_pay_price }}</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 已退款金额 --> |
|||
<view v-if="detail.status == RefundStatusEnum.COMPLETED.value && detail.type == 10" |
|||
class="detail-order b-f row-block dis-flex flex-x-end flex-y-center"> |
|||
<text class="">已退款金额:</text> |
|||
<text class="col-m">¥{{ detail.refund_money }}</text> |
|||
</view> |
|||
|
|||
<!-- 售后信息 --> |
|||
<view v-if="detail.status == RefundStatusEnum.REJECTED.value" class="detail-refund b-f m-top20"> |
|||
<view class="detail-refund__row dis-flex"> |
|||
<view class="text"> |
|||
<text>售后类型:</text> |
|||
</view> |
|||
<view class="flex-box"> |
|||
<text>{{ RefundTypeEnum[detail.type].name }}</text> |
|||
</view> |
|||
</view> |
|||
<view class="detail-refund__row dis-flex"> |
|||
<view class="text"> |
|||
<text>申请原因:</text> |
|||
</view> |
|||
<view class="flex-box"> |
|||
<text>{{ detail.apply_desc }}</text> |
|||
</view> |
|||
</view> |
|||
<view v-if="detail.images.length > 0" class="detail-refund__row dis-flex"> |
|||
<view class="text"> |
|||
<text>申请凭证:</text> |
|||
</view> |
|||
<view class="image-list flex-box"> |
|||
<view class="image-preview" v-for="(item, index) in detail.images" :key="index"> |
|||
<image class="image" mode="aspectFill" :src="item.image_url" @click="handlePreviewImages(index)"></image> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 售后信息 --> |
|||
<view v-if="detail.status.value == RefundStatusEnum.REJECTED.value" class="detail-refund b-f m-top20"> |
|||
<view class="detail-refund__row dis-flex"> |
|||
<view class="text"> |
|||
<text class="col-m">拒绝原因:</text> |
|||
</view> |
|||
<view class="flex-box"> |
|||
<text>{{ detail.refuse_desc }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 退货物流信息 --> |
|||
<view v-if="detail.audit_status == AuditStatusEnum.REVIEWED.value && detail.is_user_send" |
|||
class="detail-address b-f m-top20"> |
|||
<view class="detail-address__row address-title"> |
|||
<text class="col-m">退货物流信息</text> |
|||
</view> |
|||
<view class="detail-address__row address-details"> |
|||
<view class="address-details__row"> |
|||
<text>物流公司:{{ detail.express.express_name }}</text> |
|||
</view> |
|||
<view class="address-details__row"> |
|||
<text>物流单号:{{ detail.express_no }}</text> |
|||
</view> |
|||
<!-- <view class="address-details__row"> |
|||
<text>发货状态:{{ detail.is_user_send ? '已发货' : '未发货' }}</text> |
|||
</view> --> |
|||
<view class="address-details__row"> |
|||
<text>发货时间:{{ detail.send_time }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 商家收货地址 --> |
|||
<view v-if="detail.audit_status == AuditStatusEnum.REVIEWED.value" class="detail-address b-f m-top20"> |
|||
<view class="detail-address__row address-title"> |
|||
<text class="col-m">商家退货地址</text> |
|||
</view> |
|||
<view class="detail-address__row address-details"> |
|||
<view class="address-details__row"> |
|||
<text>收货人:{{ detail.address.name }}</text> |
|||
</view> |
|||
<view class="address-details__row"> |
|||
<text>联系电话:{{ detail.address.phone }}</text> |
|||
</view> |
|||
<view class="address-details__row dis-flex"> |
|||
<view class="text"> |
|||
<text>详细地址:</text> |
|||
</view> |
|||
<view class="address flex-box"> |
|||
<text class="region" v-for="(region, idx) in detail.address.region" :key="idx">{{ region }}</text> |
|||
<text class="detail">{{ detail.address.detail }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view class="detail-address__row address-tips"> |
|||
<view class="f-26 col-9"> |
|||
<text>· 未与卖家协商一致情况下,请勿寄到付或平邮</text> |
|||
</view> |
|||
<view class="f-26 col-9"> |
|||
<text>· 请填写真实有效物流信息</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 填写物流信息 --> |
|||
<form |
|||
v-if="detail.type == RefundTypeEnum.RETURN.value && detail.audit_status == AuditStatusEnum.REVIEWED.value && !detail.is_user_send" |
|||
@submit="onSubmit()"> |
|||
<view class="detail-express b-f m-top20"> |
|||
<view class="form-group dis-flex flex-y-center"> |
|||
<view class="field">物流公司:</view> |
|||
<view class="flex-box"> |
|||
<picker mode="selector" :range="expressList" range-key="express_name" :value="expressIndex" |
|||
@change="onChangeExpress"> |
|||
<text v-if="expressIndex > -1">{{ expressList[expressIndex].express_name }}</text> |
|||
<text v-else class="col-80">请选择物流公司</text> |
|||
</picker> |
|||
</view> |
|||
</view> |
|||
<view class="form-group dis-flex flex-y-center"> |
|||
<view class="field">物流单号:</view> |
|||
<view class="flex-box"> |
|||
<input class="input" v-model="formData.expressNo" placeholder="请填写物流单号"></input> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- 操作按钮 --> |
|||
<view class="footer"> |
|||
<view class="btn-wrapper"> |
|||
<button class="btn-item btn-item-main btn-normal" :class="{ disabled }" formType="submit">确认发货</button> |
|||
</view> |
|||
</view> |
|||
</form> |
|||
|
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { AuditStatusEnum, RefundStatusEnum, RefundTypeEnum } from '@/common/enum/order/refund' |
|||
import * as RefundApi from '@/api/refund' |
|||
import * as ExpressApi from '@/api/express' |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
// 枚举类 |
|||
AuditStatusEnum, |
|||
RefundStatusEnum, |
|||
RefundTypeEnum, |
|||
// 正在加载 |
|||
isLoading: true, |
|||
// 售后单ID |
|||
orderRefundId: null, |
|||
// 售后单详情 |
|||
detail: {}, |
|||
// 物流公司列表 |
|||
expressList: [], |
|||
// 表单数据 |
|||
formData: { |
|||
// 物流公司ID |
|||
expressId: null, |
|||
// 物流单号 |
|||
expressNo: '' |
|||
}, |
|||
// 选择的物流公司索引 |
|||
expressIndex: -1, |
|||
// 按钮禁用 |
|||
disabled: false |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
onLoad({ orderRefundId }) { |
|||
// 售后单ID |
|||
this.orderRefundId = orderRefundId |
|||
// 获取页面数据 |
|||
this.getPageData() |
|||
}, |
|||
|
|||
methods: { |
|||
|
|||
// 获取页面数据 |
|||
getPageData() { |
|||
const app = this |
|||
app.isLoading = true |
|||
Promise.all([app.getRefundDetail(), app.getExpressList()]) |
|||
.then(result => { |
|||
app.isLoading = false |
|||
}) |
|||
}, |
|||
|
|||
// 获取售后单详情 |
|||
getRefundDetail() { |
|||
const app = this |
|||
return new Promise((resolve, reject) => { |
|||
RefundApi.detail(app.orderRefundId) |
|||
.then(result => { |
|||
app.detail = result.data.detail |
|||
resolve() |
|||
}) |
|||
.catch(reject) |
|||
}) |
|||
}, |
|||
|
|||
// 获取物流公司列表 |
|||
getExpressList() { |
|||
const app = this |
|||
return new Promise((resolve, reject) => { |
|||
ExpressApi.list() |
|||
.then(result => { |
|||
app.expressList = result.data.list |
|||
resolve() |
|||
}) |
|||
.catch(reject) |
|||
}) |
|||
}, |
|||
|
|||
// 跳转商品详情页 |
|||
onGoodsDetail(goodsId) { |
|||
this.$navTo('pages/goods/detail', { goodsId }) |
|||
}, |
|||
|
|||
// 凭证图片预览 |
|||
handlePreviewImages(index) { |
|||
const { detail: { images } } = this |
|||
const imageUrls = images.map(item => item.image_url) |
|||
uni.previewImage({ |
|||
current: imageUrls[index], |
|||
urls: imageUrls |
|||
}) |
|||
}, |
|||
|
|||
// 选择物流公司 |
|||
onChangeExpress(e) { |
|||
const expressIndex = e.detail.value |
|||
const { expressList } = this |
|||
this.expressIndex = expressIndex |
|||
this.formData.expressId = expressList[expressIndex].express_id |
|||
}, |
|||
|
|||
// 表单提交 |
|||
onSubmit() { |
|||
const app = this |
|||
// 判断是否重复提交 |
|||
if (app.disabled === true) return false |
|||
// 按钮禁用 |
|||
app.disabled = true |
|||
// 提交到后端 |
|||
RefundApi.delivery(app.orderRefundId, app.formData) |
|||
.then(result => { |
|||
app.$toast(result.message) |
|||
setTimeout(() => { |
|||
app.disabled = false |
|||
uni.navigateBack() |
|||
}, 1500) |
|||
}) |
|||
.catch(err => app.disabled = false) |
|||
} |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
// 顶部状态栏 |
|||
.detail-header { |
|||
position: relative; |
|||
width: 100%; |
|||
height: 140rpx; |
|||
|
|||
.header-backdrop { |
|||
width: 100%; |
|||
position: absolute; |
|||
top: 0; |
|||
left: 0; |
|||
z-index: 0; |
|||
|
|||
.image { |
|||
display: block; |
|||
width: 100%; |
|||
height: 140rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.header-state { |
|||
z-index: 1; |
|||
padding: 0 50rpx; |
|||
} |
|||
|
|||
/* 商品详情 */ |
|||
.detail-goods { |
|||
padding: 24rpx 20rpx; |
|||
|
|||
.left { |
|||
.goods-image { |
|||
display: block; |
|||
width: 150rpx; |
|||
height: 150rpx; |
|||
} |
|||
} |
|||
|
|||
.right { |
|||
padding-left: 20rpx; |
|||
} |
|||
|
|||
.goods-props { |
|||
margin-top: 14rpx; |
|||
height: 40rpx; |
|||
color: #ababab; |
|||
font-size: 24rpx; |
|||
overflow: hidden; |
|||
|
|||
.goods-props-item { |
|||
display: inline-block; |
|||
margin-right: 14rpx; |
|||
padding: 4rpx 16rpx; |
|||
border-radius: 12rpx; |
|||
background-color: #F5F5F5; |
|||
width: auto; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.detail-order { |
|||
padding: 15rpx 20rpx; |
|||
font-size: 26rpx; |
|||
|
|||
.item { |
|||
margin-bottom: 10rpx; |
|||
|
|||
&:last-child { |
|||
margin-bottom: 0; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/* 售后详情 */ |
|||
.detail-refund { |
|||
padding: 15rpx 20rpx; |
|||
} |
|||
|
|||
.detail-refund__row { |
|||
margin: 20rpx 0; |
|||
} |
|||
|
|||
/* 申请凭证 */ |
|||
.image-list { |
|||
margin-bottom: -15rpx; |
|||
|
|||
.image-preview { |
|||
margin: 0 15rpx 15rpx 0; |
|||
float: left; |
|||
|
|||
.image { |
|||
display: block; |
|||
width: 180rpx; |
|||
height: 180rpx; |
|||
} |
|||
|
|||
&:nth-child(3n+0) { |
|||
margin-right: 0; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/* 商家收货地址 */ |
|||
.detail-address { |
|||
padding: 20rpx 34rpx; |
|||
} |
|||
|
|||
.address-details { |
|||
padding: 8rpx 0; |
|||
border-bottom: 1px solid #eee; |
|||
|
|||
.address-details__row { |
|||
margin: 14rpx 0; |
|||
} |
|||
} |
|||
|
|||
.address-tips { |
|||
margin-top: 16rpx; |
|||
line-height: 46rpx; |
|||
} |
|||
|
|||
.detail-address__row { |
|||
// margin: 18rpx 0; |
|||
} |
|||
|
|||
/* 填写物流信息 */ |
|||
.detail-express { |
|||
padding: 10rpx 30rpx; |
|||
} |
|||
|
|||
.form-group { |
|||
height: 60rpx; |
|||
margin: 14rpx 0; |
|||
|
|||
.input { |
|||
height: 100%; |
|||
font-size: 28rpx; |
|||
} |
|||
} |
|||
|
|||
|
|||
/* 底部操作栏 */ |
|||
|
|||
.footer { |
|||
margin-top: 60rpx; |
|||
|
|||
.btn-wrapper { |
|||
height: 100%; |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 0 20rpx; |
|||
} |
|||
|
|||
.btn-item { |
|||
flex: 1; |
|||
font-size: 28rpx; |
|||
height: 80rpx; |
|||
color: #fff; |
|||
border-radius: 50rpx; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
|
|||
.btn-item-main { |
|||
background: linear-gradient(to right, #f9211c, #ff6335); |
|||
|
|||
// 禁用按钮 |
|||
&.disabled { |
|||
background: #ff9779; |
|||
} |
|||
} |
|||
|
|||
} |
|||
</style> |
|||
@ -1,263 +0,0 @@ |
|||
<template> |
|||
<view class="container"> |
|||
<mescroll-body ref="mescrollRef" :sticky="true" @init="mescrollInit" :down="{ native: true }" @down="downCallback" |
|||
:up="upOption" @up="upCallback"> |
|||
|
|||
<!-- tab栏 --> |
|||
<u-tabs :list="tabs" :is-scroll="false" :current="curTab" active-color="#FA2209" :duration="0.2" |
|||
@change="onChangeTab" /> |
|||
|
|||
<!-- 退款/售后单 --> |
|||
<view class="widget-list"> |
|||
<view class="widget-detail" v-for="(item, index) in list.data" :key="index"> |
|||
<view class="row-block dis-flex flex-y-center"> |
|||
<view class="flex-box">{{ item.create_time }}</view> |
|||
<view class="flex-box t-r"> |
|||
<text class="col-m">{{ item.state_text }}</text> |
|||
</view> |
|||
</view> |
|||
<view class="detail-goods row-block dis-flex" @click.stop="handleTargetDetail(item.order_refund_id)"> |
|||
<view class="goods-image"> |
|||
<image class="image" :src="item.orderGoods.goods_image" mode="aspectFit"></image> |
|||
</view> |
|||
<view class="goods-right flex-box"> |
|||
<view class="goods-name"> |
|||
<text class="twoline-hide">{{ item.orderGoods.goods_name }}</text> |
|||
</view> |
|||
<view class="goods-props clearfix"> |
|||
<view class="goods-props-item" v-for="(props, idx) in item.orderGoods.goods_props" :key="idx"> |
|||
<text>{{ props.value.name }}</text> |
|||
</view> |
|||
</view> |
|||
<view class="goods-num t-r"> |
|||
<text class="f-26 col-8">×{{ item.orderGoods.total_num }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view class="detail-order row-block"> |
|||
<view class="item dis-flex flex-x-end flex-y-center"> |
|||
<text class="">付款金额:</text> |
|||
<text class="col-m">¥{{ item.orderGoods.total_pay_price }}</text> |
|||
</view> |
|||
</view> |
|||
<view class="detail-operate row-block dis-flex flex-x-end flex-y-center"> |
|||
<view class="detail-btn btn-detail" @click.stop="handleTargetDetail(item.order_refund_id)">查看详情</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
</mescroll-body> |
|||
|
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import MescrollBody from '@/components/mescroll-uni/mescroll-body.vue' |
|||
import MescrollMixin from '@/components/mescroll-uni/mescroll-mixins' |
|||
import { getEmptyPaginateObj, getMoreListData } from '@/core/app' |
|||
import * as RefundApi from '@/api/refund' |
|||
|
|||
// 每页记录数量 |
|||
const pageSize = 15 |
|||
|
|||
// tab栏数据 |
|||
const tabs = [{ |
|||
name: '全部', |
|||
value: -1 |
|||
}, { |
|||
name: '待处理', |
|||
value: 0 |
|||
}] |
|||
|
|||
export default { |
|||
components: { |
|||
MescrollBody |
|||
}, |
|||
mixins: [MescrollMixin], |
|||
data() { |
|||
return { |
|||
// 订单列表数据 |
|||
list: getEmptyPaginateObj(), |
|||
// tabs栏数据 |
|||
tabs, |
|||
// 当前标签索引 |
|||
curTab: 0, |
|||
// 上拉加载配置 |
|||
upOption: { |
|||
// 首次自动执行 |
|||
auto: true, |
|||
// 每页数据的数量; 默认10 |
|||
page: { size: pageSize }, |
|||
// 数量要大于2条才显示无更多数据 |
|||
noMoreSize: 2, |
|||
// 空布局 |
|||
empty: { |
|||
tip: '亲,暂无售后单记录' |
|||
} |
|||
}, |
|||
// 控制首次触发onShow事件时不刷新列表 |
|||
canReset: false, |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
onLoad(options) { |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面显示 |
|||
*/ |
|||
onShow() { |
|||
this.canReset && this.onRefreshList() |
|||
// this.canReset = true |
|||
}, |
|||
|
|||
methods: { |
|||
|
|||
/** |
|||
* 上拉加载的回调 (页面初始化时也会执行一次) |
|||
* 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10 |
|||
* @param {Object} page |
|||
*/ |
|||
upCallback(page) { |
|||
const app = this |
|||
// 设置列表数据 |
|||
app.getRefundList(page.num) |
|||
.then(list => { |
|||
const curPageLen = list.data.length |
|||
const totalSize = list.data.total |
|||
app.mescroll.endBySize(curPageLen, totalSize) |
|||
}) |
|||
.catch(() => app.mescroll.endErr()) |
|||
}, |
|||
|
|||
// 获取退款/售后单列表 |
|||
getRefundList(pageNo = 1) { |
|||
const app = this |
|||
return new Promise((resolve, reject) => { |
|||
RefundApi.list({ state: app.getTabValue(), page: pageNo }, { load: false }) |
|||
.then(result => { |
|||
// 合并新数据 |
|||
const newList = result.data.list |
|||
app.list.data = getMoreListData(newList, app.list, pageNo) |
|||
resolve(newList) |
|||
}) |
|||
}) |
|||
}, |
|||
|
|||
// 切换标签项 |
|||
onChangeTab(index) { |
|||
const app = this |
|||
// 设置当前选中的标签 |
|||
app.curTab = index |
|||
// 刷新售后单列表 |
|||
app.onRefreshList() |
|||
}, |
|||
|
|||
// 刷新订单列表 |
|||
onRefreshList() { |
|||
this.list = getEmptyPaginateObj() |
|||
setTimeout(() => { |
|||
this.mescroll.resetUpScroll() |
|||
}, 120) |
|||
}, |
|||
|
|||
// 获取当前标签项的值 |
|||
getTabValue() { |
|||
return this.tabs[this.curTab].value |
|||
}, |
|||
|
|||
// 跳转到售后单详情页 |
|||
handleTargetDetail(orderRefundId) { |
|||
this.$navTo('pages/refund/detail', { orderRefundId }) |
|||
}, |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.widget-detail { |
|||
box-sizing: border-box; |
|||
background: #fff; |
|||
margin-bottom: 20rpx; |
|||
|
|||
.row-block { |
|||
padding: 0 20rpx; |
|||
min-height: 70rpx; |
|||
} |
|||
|
|||
.detail-goods { |
|||
padding: 20rpx; |
|||
background: #f9f9f9; |
|||
|
|||
.goods-image { |
|||
margin-right: 20rpx; |
|||
|
|||
.image { |
|||
display: block; |
|||
width: 200rpx; |
|||
height: 200rpx; |
|||
} |
|||
} |
|||
|
|||
.goods-right { |
|||
padding: 15rpx 0; |
|||
} |
|||
|
|||
.goods-name { |
|||
margin-bottom: 10rpx; |
|||
} |
|||
|
|||
|
|||
.goods-props { |
|||
margin-top: 14rpx; |
|||
height: 40rpx; |
|||
color: #ababab; |
|||
font-size: 24rpx; |
|||
overflow: hidden; |
|||
|
|||
.goods-props-item { |
|||
display: inline-block; |
|||
margin-right: 14rpx; |
|||
padding: 4rpx 16rpx; |
|||
border-radius: 12rpx; |
|||
background-color: #F5F5F5; |
|||
width: auto; |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
.detail-operate { |
|||
padding-bottom: 20rpx; |
|||
|
|||
.detail-btn { |
|||
border-radius: 4px; |
|||
border: 1rpx solid #ccc; |
|||
padding: 8rpx 20rpx; |
|||
font-size: 28rpx; |
|||
color: #555; |
|||
margin-left: 10rpx; |
|||
} |
|||
} |
|||
|
|||
.detail-order { |
|||
padding: 10rpx 20rpx; |
|||
font-size: 26rpx; |
|||
line-height: 50rpx; |
|||
height: 50rpx; |
|||
|
|||
.item { |
|||
margin-bottom: 10rpx; |
|||
|
|||
&:last-child { |
|||
margin-bottom: 0; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,227 +0,0 @@ |
|||
<template> |
|||
<view class="container"> |
|||
<view class="search-wrapper"> |
|||
<view class="search-input"> |
|||
<view class="search-input-wrapper"> |
|||
<view class="left"> |
|||
<text class="search-icon iconfont icon-search"></text> |
|||
</view> |
|||
<view class="right"> |
|||
<input v-model="searchValue" class="input" focus="true" placeholder="请输入您搜索的商品" type="text"></input> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view class="search-button"> |
|||
<view class="button" @click="onSearch">搜索</view> |
|||
</view> |
|||
</view> |
|||
<view class="history" v-if="historySearch.length"> |
|||
<view class="his-head"> |
|||
<text class="title">最近搜索</text> |
|||
<text class="icon iconfont icon-delete" @click="clearSearch"></text> |
|||
</view> |
|||
<view class="his-list"> |
|||
<view class="his-item" v-for="(val, index) in historySearch" :key="index"> |
|||
<view class="history-button" @click="handleQuick(val)">{{ val }}</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- </view> --> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
const HISTORY_SEARCH = 'historySearch' |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
historySearch: [], |
|||
searchValue: '' |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
onLoad(options) { |
|||
// 获取历史搜索 |
|||
this.historySearch = this.getHistorySearch() |
|||
}, |
|||
|
|||
methods: { |
|||
|
|||
/** |
|||
* 获取历史搜索 |
|||
*/ |
|||
getHistorySearch() { |
|||
return uni.getStorageSync(HISTORY_SEARCH) || [] |
|||
}, |
|||
|
|||
/** |
|||
* 搜索提交 |
|||
*/ |
|||
onSearch() { |
|||
const { searchValue } = this |
|||
if (searchValue) { |
|||
// 记录历史搜索 |
|||
this.setHistory(searchValue) |
|||
// 跳转到商品列表页 |
|||
this.$navTo('pages/goods/list', { search: searchValue }) |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 记录历史搜索 |
|||
*/ |
|||
setHistory(searchValue) { |
|||
const data = this.getHistorySearch() |
|||
const index = data.indexOf(searchValue) |
|||
index > -1 && data.splice(index, 1) |
|||
data.unshift(searchValue) |
|||
this.historySearch = data |
|||
this.onUpdateStorage() |
|||
}, |
|||
|
|||
/** |
|||
* 清空最近搜索记录 |
|||
*/ |
|||
clearSearch() { |
|||
this.historySearch = [] |
|||
this.onUpdateStorage() |
|||
}, |
|||
|
|||
/** |
|||
* 更新历史搜索缓存 |
|||
* @param {Object} data |
|||
*/ |
|||
onUpdateStorage(data) { |
|||
uni.setStorageSync(HISTORY_SEARCH, this.historySearch) |
|||
}, |
|||
|
|||
/** |
|||
* 跳转到最近搜索 |
|||
*/ |
|||
handleQuick(search) { |
|||
this.$navTo('pages/goods/list', { search }) |
|||
} |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.container { |
|||
padding: 20rpx; |
|||
min-height: 100vh; |
|||
background: #f7f7f7; |
|||
} |
|||
|
|||
.search-wrapper { |
|||
display: flex; |
|||
height: 64rpx; |
|||
} |
|||
|
|||
// 搜索输入框 |
|||
.search-input { |
|||
width: 80%; |
|||
background: #fff; |
|||
border-radius: 10rpx 0 0 10rpx; |
|||
box-sizing: border-box; |
|||
overflow: hidden; |
|||
|
|||
.search-input-wrapper { |
|||
display: flex; |
|||
|
|||
.left { |
|||
display: flex; |
|||
width: 60rpx; |
|||
justify-content: center; |
|||
align-items: center; |
|||
|
|||
.search-icon { |
|||
display: block; |
|||
color: #b4b4b4; |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
} |
|||
|
|||
.right { |
|||
flex: 1; |
|||
|
|||
input { |
|||
font-size: 28rpx; |
|||
height: 64rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
|
|||
.input-placeholder { |
|||
color: #aba9a9; |
|||
} |
|||
} |
|||
|
|||
} |
|||
} |
|||
} |
|||
|
|||
// 搜索按钮 |
|||
.search-button { |
|||
width: 20%; |
|||
box-sizing: border-box; |
|||
|
|||
.button { |
|||
height: 64rpx; |
|||
font-size: 28rpx; |
|||
border-radius: 0 10rpx 10rpx 0; |
|||
background: #fa2209; |
|||
color: #fff; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
} |
|||
|
|||
|
|||
// 最近搜索 |
|||
.history { |
|||
|
|||
.his-head { |
|||
font-size: 28rpx; |
|||
padding: 50rpx 0 0 0; |
|||
color: #777; |
|||
|
|||
.icon { |
|||
float: right; |
|||
} |
|||
|
|||
} |
|||
|
|||
.his-list { |
|||
padding: 20rpx 0; |
|||
overflow: hidden; |
|||
|
|||
.his-item { |
|||
width: 33.3%; |
|||
float: left; |
|||
padding: 10rpx; |
|||
box-sizing: border-box; |
|||
|
|||
.history-button { |
|||
text-align: center; |
|||
padding: 14rpx; |
|||
line-height: 30rpx; |
|||
border-radius: 100rpx; |
|||
background: #fff; |
|||
font-size: 26rpx; |
|||
border: 1rpx solid #efefef; |
|||
overflow: hidden; |
|||
white-space: nowrap; |
|||
text-overflow: ellipsis; |
|||
} |
|||
|
|||
} |
|||
|
|||
} |
|||
} |
|||
</style> |
|||
@ -1,127 +0,0 @@ |
|||
<template> |
|||
<view class="container"> |
|||
<mescroll-body ref="mescrollRef" :sticky="true" @init="mescrollInit" :down="{ use: false }" :up="upOption" |
|||
@up="upCallback"> |
|||
<view class="log-list"> |
|||
<view v-for="(item, index) in list.data" :key="index" class="log-item"> |
|||
<view class="item-left flex-box"> |
|||
<view class="rec-status"> |
|||
<text>{{ item.describe }}</text> |
|||
</view> |
|||
<view class="rec-time"> |
|||
<text>{{ item.create_time }}</text> |
|||
</view> |
|||
</view> |
|||
<view class="item-right"> |
|||
<text>{{ item.money > 0 ? '+' : '' }}{{ item.money }}元</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</mescroll-body> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import MescrollBody from '@/components/mescroll-uni/mescroll-body.vue' |
|||
import MescrollMixin from '@/components/mescroll-uni/mescroll-mixins' |
|||
import * as LogApi from '@/api/balance/log' |
|||
import { getEmptyPaginateObj, getMoreListData } from '@/core/app' |
|||
|
|||
const pageSize = 15 |
|||
|
|||
export default { |
|||
components: { |
|||
MescrollBody |
|||
}, |
|||
mixins: [MescrollMixin], |
|||
data() { |
|||
return { |
|||
// 余额账单明细列表 |
|||
list: getEmptyPaginateObj(), |
|||
// 上拉加载配置 |
|||
upOption: { |
|||
// 首次自动执行 |
|||
auto: true, |
|||
// 每页数据的数量; 默认10 |
|||
page: { size: pageSize }, |
|||
// 数量要大于12条才显示无更多数据 |
|||
noMoreSize: 12, |
|||
// 空布局 |
|||
empty: { |
|||
tip: '亲,暂无账单明细' |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
onLoad(options) {}, |
|||
|
|||
methods: { |
|||
|
|||
/** |
|||
* 上拉加载的回调 (页面初始化时也会执行一次) |
|||
* 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10 |
|||
* @param {Object} page |
|||
*/ |
|||
upCallback(page) { |
|||
const app = this |
|||
// 设置列表数据 |
|||
app.getLogList(page.num) |
|||
.then(list => { |
|||
const curPageLen = list.data.length |
|||
const totalSize = list.data.total |
|||
app.mescroll.endBySize(curPageLen, totalSize) |
|||
}) |
|||
.catch(() => app.mescroll.endErr()) |
|||
}, |
|||
|
|||
// 获取余额账单明细列表 |
|||
getLogList(pageNo = 1) { |
|||
const app = this |
|||
return new Promise((resolve, reject) => { |
|||
LogApi.list({ page: pageNo }) |
|||
.then(result => { |
|||
// 合并新数据 |
|||
const newList = result.data.list |
|||
app.list.data = getMoreListData(newList, app.list, pageNo) |
|||
resolve(newList) |
|||
}) |
|||
}) |
|||
} |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
page, |
|||
.container { |
|||
background: #fff; |
|||
} |
|||
|
|||
.log-list { |
|||
padding: 0 30rpx; |
|||
} |
|||
|
|||
.log-item { |
|||
font-size: 28rpx; |
|||
padding: 20rpx 20rpx; |
|||
line-height: 1.8; |
|||
border-bottom: 1rpx solid rgb(238, 238, 238); |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
|
|||
.rec-status { |
|||
color: #333; |
|||
|
|||
.rec-time { |
|||
color: rgb(160, 160, 160); |
|||
font-size: 26rpx; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,167 +0,0 @@ |
|||
<template> |
|||
<view class="container" v-if="!isLoading"> |
|||
<view class="space-upper"> |
|||
<view class="wallet-image"> |
|||
<image src="/static/wallet.png" mode="widthFix"></image> |
|||
</view> |
|||
<view class="wallet-account"> |
|||
<view class="wallet-account_balance"> |
|||
<text>{{ userInfo.balance }}</text> |
|||
</view> |
|||
<view class="wallet-account_lable"> |
|||
<text>账户余额(元)</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view class="space-lower"> |
|||
<view v-if="setting.is_entrance" class="space-lower_item btn-recharge"> |
|||
<view class="btn-submit" @click="onTargetRecharge()">充 值</view> |
|||
</view> |
|||
<view class="space-lower_item item-lable dis-flex flex-x-around"> |
|||
<view class="lable-text" @click="onTargetRechargeOrder()"> |
|||
<text>充值记录</text> |
|||
</view> |
|||
<view class="lable-text" @click="onTargetBalanceLog()"> |
|||
<text>账单详情</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import * as UserApi from '@/api/user' |
|||
import SettingModel from '@/common/model/Setting' |
|||
import SettingKeyEnum from '@/common/enum/setting/Key' |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
// 正在加载 |
|||
isLoading: true, |
|||
// 会员信息 |
|||
userInfo: {}, |
|||
// 充值设置 |
|||
setting: {}, |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
onShow(options) { |
|||
// 获取页面数据 |
|||
this.getPageData() |
|||
}, |
|||
|
|||
methods: { |
|||
|
|||
// 获取页面数据 |
|||
getPageData() { |
|||
const app = this |
|||
app.isLoading = true |
|||
Promise.all([app.getUserInfo(), app.getSetting()]) |
|||
.then(() => app.isLoading = false) |
|||
}, |
|||
|
|||
// 获取会员信息 |
|||
getUserInfo() { |
|||
const app = this |
|||
return new Promise((resolve, reject) => { |
|||
UserApi.info() |
|||
.then(result => { |
|||
app.userInfo = result.data.userInfo |
|||
resolve(app.userInfo) |
|||
}) |
|||
}) |
|||
}, |
|||
|
|||
// 获取充值设置 |
|||
getSetting() { |
|||
const app = this |
|||
return new Promise((resolve, reject) => { |
|||
SettingModel.item(SettingKeyEnum.RECHARGE.value, false) |
|||
.then(data => { |
|||
app.setting = data |
|||
resolve(data) |
|||
}) |
|||
}) |
|||
}, |
|||
|
|||
// 跳转充值页面 |
|||
onTargetRecharge() { |
|||
this.$navTo('pages/wallet/recharge/index') |
|||
}, |
|||
|
|||
// 跳转充值记录页面 |
|||
onTargetRechargeOrder() { |
|||
this.$navTo('pages/wallet/recharge/order') |
|||
}, |
|||
|
|||
// 跳转账单详情页面 |
|||
onTargetBalanceLog() { |
|||
this.$navTo('pages/wallet/balance/log') |
|||
} |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
<style> |
|||
page { |
|||
background: #fff; |
|||
} |
|||
</style> |
|||
<style lang="scss" scoped> |
|||
.container { |
|||
background: #fff; |
|||
} |
|||
|
|||
.space-upper { |
|||
padding: 150rpx 0; |
|||
text-align: center; |
|||
} |
|||
|
|||
.wallet-image image { |
|||
width: 360rpx; |
|||
height: 261.72rpx; |
|||
} |
|||
|
|||
.wallet-account { |
|||
margin-top: 20rpx; |
|||
} |
|||
|
|||
.wallet-account_balance { |
|||
font-size: 56rpx; |
|||
} |
|||
|
|||
.wallet-account_lable { |
|||
margin-top: 14rpx; |
|||
color: #cec1c1; |
|||
font-size: 26rpx; |
|||
} |
|||
|
|||
.space-lower { |
|||
margin-top: 30rpx; |
|||
padding: 0 110rpx; |
|||
} |
|||
|
|||
.btn-recharge .btn-submit { |
|||
width: 460rpx; |
|||
height: 84rpx; |
|||
margin: 0 auto; |
|||
border-radius: 50rpx; |
|||
background: #786cff; |
|||
color: white; |
|||
font-size: 30rpx; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
|
|||
.item-lable { |
|||
margin-top: 80rpx; |
|||
font-size: 28rpx; |
|||
color: rgb(94, 94, 94); |
|||
padding: 0 100rpx; |
|||
} |
|||
</style> |
|||
@ -1,300 +0,0 @@ |
|||
<template> |
|||
<view class="container" v-if="userInfo.user_id"> |
|||
<view class="account-panel dis-flex flex-y-center"> |
|||
<view class="panel-lable"> |
|||
<text>账户余额</text> |
|||
</view> |
|||
<view class="panel-balance flex-box"> |
|||
<text>¥{{ userInfo.balance }}</text> |
|||
</view> |
|||
</view> |
|||
<view class="recharge-panel"> |
|||
<view class="recharge-label"> |
|||
<text>充值金额</text> |
|||
</view> |
|||
<view class="recharge-plan clearfix"> |
|||
<block v-for="(item, index) in planList" :key="index"> |
|||
<view class="recharge-plan_item" :class="{ active: selectedPlanId == item.plan_id }" @click="onSelectPlan(item.plan_id)"> |
|||
<view class="plan_money"> |
|||
<text>{{ item.money }}</text> |
|||
</view> |
|||
<view class="plan_gift" v-if="item.gift_money > 0"> |
|||
<text>送{{ item.gift_money }}</text> |
|||
</view> |
|||
</view> |
|||
</block> |
|||
</view> |
|||
<!-- 手动充值输入框 --> |
|||
<view class="recharge-input" v-if="setting.is_custom == 1"> |
|||
<input type="digit" placeholder="请输入充值金额" v-model="inputValue" @input="onChangeMoney" /> |
|||
</view> |
|||
<!-- 确认按钮 --> |
|||
<view class="recharge-submit btn-submit"> |
|||
<form @submit="onSubmit"> |
|||
<button class="button" formType="submit" :disabled="disabled">立即充值</button> |
|||
</form> |
|||
</view> |
|||
</view> |
|||
<!-- 充值描述 --> |
|||
<view class="recharge-describe"> |
|||
<view class="recharge-label"> |
|||
<text>充值说明</text> |
|||
</view> |
|||
<view class="content"> |
|||
<text space="ensp">{{ setting.describe }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import * as UserApi from '@/api/user' |
|||
import * as RechargeApi from '@/api/recharge' |
|||
import * as PlanApi from '@/api/recharge/plan' |
|||
import SettingModel from '@/common/model/Setting' |
|||
import SettingKeyEnum from '@/common/enum/setting/Key' |
|||
import { wxPayment } from '@/core/app' |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
// 正在加载 |
|||
isLoading: true, |
|||
// 会员信息 |
|||
userInfo: {}, |
|||
// 充值设置 |
|||
setting: {}, |
|||
// 充值方案列表 |
|||
planList: [], |
|||
// 按钮禁用 |
|||
disabled: false, |
|||
// 当前选中的套餐id |
|||
selectedPlanId: 0, |
|||
// 自定义金额 |
|||
inputValue: '', |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
onLoad(options) { |
|||
// 获取页面数据 |
|||
this.getPageData() |
|||
}, |
|||
|
|||
methods: { |
|||
|
|||
/** |
|||
* 选择充值套餐 |
|||
*/ |
|||
onSelectPlan(planId) { |
|||
this.selectedPlanId = planId |
|||
this.inputValue = '' |
|||
}, |
|||
|
|||
// 金额输入框 |
|||
onChangeMoney(e) { |
|||
this.inputValue = e.target.value |
|||
this.selectedPlanId = 0 |
|||
}, |
|||
|
|||
// 获取页面数据 |
|||
getPageData() { |
|||
const app = this |
|||
app.isLoading = true |
|||
Promise.all([app.getUserInfo(), app.getSetting(), app.getPlanList()]) |
|||
.then(() => app.isLoading = false) |
|||
}, |
|||
|
|||
// 获取充值方案列表 |
|||
getPlanList() { |
|||
const app = this |
|||
return new Promise((resolve, reject) => { |
|||
PlanApi.list() |
|||
.then(result => { |
|||
app.planList = result.data.list |
|||
resolve(app.planList) |
|||
}) |
|||
}) |
|||
}, |
|||
|
|||
// 获取会员信息 |
|||
getUserInfo() { |
|||
const app = this |
|||
return new Promise((resolve, reject) => { |
|||
UserApi.info() |
|||
.then(result => { |
|||
app.userInfo = result.data.userInfo |
|||
resolve(app.userInfo) |
|||
}) |
|||
}) |
|||
}, |
|||
|
|||
// 获取充值设置 |
|||
getSetting() { |
|||
const app = this |
|||
return new Promise((resolve, reject) => { |
|||
SettingModel.item(SettingKeyEnum.RECHARGE.value, false) |
|||
.then(data => { |
|||
app.setting = data |
|||
resolve(data) |
|||
}) |
|||
}) |
|||
}, |
|||
|
|||
// 立即充值 |
|||
onSubmit(e) { |
|||
const app = this |
|||
// 按钮禁用 |
|||
app.disabled = true |
|||
// 提交到后端 |
|||
RechargeApi.submit({ planId: app.selectedPlanId, customMoney: app.inputValue }) |
|||
.then(result => app.wxPayment(result.data.payment)) |
|||
.finally(() => app.disabled = false) |
|||
}, |
|||
|
|||
// 发起微信支付 |
|||
wxPayment(option) { |
|||
const app = this |
|||
wxPayment(option) |
|||
.then(() => { |
|||
app.$success('支付成功') |
|||
setTimeout(() => { |
|||
// 获取页面数据 |
|||
app.getPageData() |
|||
}, 1500) |
|||
}) |
|||
.catch(err => app.$error('订单未支付')) |
|||
} |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
page, |
|||
.container { |
|||
background: #fff; |
|||
} |
|||
|
|||
.container { |
|||
padding-bottom: 70rpx; |
|||
} |
|||
|
|||
/* 账户面板 */ |
|||
.account-panel { |
|||
width: 650rpx; |
|||
height: 180rpx; |
|||
margin: 50rpx auto; |
|||
padding: 0 60rpx; |
|||
box-sizing: border-box; |
|||
border-radius: 12rpx; |
|||
color: #fff; |
|||
background: linear-gradient(-125deg, #a46bff, #786cff); |
|||
box-shadow: 0 5px 22px 0 rgba(0, 0, 0, 0.26); |
|||
} |
|||
|
|||
.panel-lable { |
|||
font-size: 32rpx; |
|||
} |
|||
|
|||
.recharge-label { |
|||
color: rgb(51, 51, 51); |
|||
font-size: 28rpx; |
|||
margin-bottom: 25rpx; |
|||
} |
|||
|
|||
.panel-balance { |
|||
text-align: right; |
|||
font-size: 46rpx; |
|||
} |
|||
|
|||
.recharge-panel { |
|||
margin-top: 60rpx; |
|||
padding: 0 60rpx; |
|||
} |
|||
|
|||
/* 充值套餐 */ |
|||
.recharge-plan { |
|||
.recharge-plan_item { |
|||
width: 192rpx; |
|||
padding: 15rpx 0; |
|||
float: left; |
|||
text-align: center; |
|||
color: #888; |
|||
border: 1rpx solid rgb(228, 228, 228); |
|||
border-radius: 10rpx; |
|||
margin: 0 20rpx 20rpx 0; |
|||
|
|||
&:nth-child(3n + 0) { |
|||
margin-right: 0; |
|||
} |
|||
|
|||
&.active { |
|||
color: #786cff; |
|||
border: 1rpx solid #786cff; |
|||
|
|||
.plan_money { |
|||
color: #786cff; |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
.plan_money { |
|||
font-size: 32rpx; |
|||
color: rgb(82, 82, 82); |
|||
} |
|||
|
|||
.plan_gift { |
|||
font-size: 25rpx; |
|||
} |
|||
|
|||
.recharge-input { |
|||
margin-top: 25rpx; |
|||
|
|||
input { |
|||
border: 1rpx solid rgb(228, 228, 228); |
|||
border-radius: 10rpx; |
|||
padding: 15rpx 16rpx; |
|||
font-size: 26rpx; |
|||
} |
|||
} |
|||
|
|||
/* 立即充值 */ |
|||
.recharge-submit { |
|||
margin-top: 70rpx; |
|||
} |
|||
|
|||
.btn-submit { |
|||
.button { |
|||
font-size: 30rpx; |
|||
background: #786cff; |
|||
border: none; |
|||
color: white; |
|||
border-radius: 50rpx; |
|||
padding: 0 120rpx; |
|||
line-height: 3; |
|||
} |
|||
|
|||
.button[disabled] { |
|||
background: #a098ff; |
|||
border-color: #a098ff; |
|||
color: white; |
|||
} |
|||
} |
|||
|
|||
/* 充值说明 */ |
|||
.recharge-describe { |
|||
margin-top: 50rpx; |
|||
padding: 0 60rpx; |
|||
|
|||
.content { |
|||
font-size: 26rpx; |
|||
line-height: 1.6; |
|||
color: #888; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,127 +0,0 @@ |
|||
<template> |
|||
<view class="container"> |
|||
<mescroll-body ref="mescrollRef" :sticky="true" @init="mescrollInit" :down="{ use: false }" :up="upOption" |
|||
@up="upCallback"> |
|||
<view class="log-list"> |
|||
<view v-for="(item, index) in list.data" :key="index" class="log-item"> |
|||
<view class="item-left flex-box"> |
|||
<view class="rec-status"> |
|||
<text>{{ '充值成功' }}</text> |
|||
</view> |
|||
<view class="rec-time"> |
|||
<text>{{ item.pay_time }}</text> |
|||
</view> |
|||
</view> |
|||
<view class="item-right"> |
|||
<text>+{{ item.actual_money }}元</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</mescroll-body> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import MescrollBody from '@/components/mescroll-uni/mescroll-body.vue' |
|||
import MescrollMixin from '@/components/mescroll-uni/mescroll-mixins' |
|||
import * as OrderApi from '@/api/recharge/order' |
|||
import { getEmptyPaginateObj, getMoreListData } from '@/core/app' |
|||
|
|||
const pageSize = 15 |
|||
|
|||
export default { |
|||
components: { |
|||
MescrollBody |
|||
}, |
|||
mixins: [MescrollMixin], |
|||
data() { |
|||
return { |
|||
// 余额账单明细列表 |
|||
list: getEmptyPaginateObj(), |
|||
// 上拉加载配置 |
|||
upOption: { |
|||
// 首次自动执行 |
|||
auto: true, |
|||
// 每页数据的数量; 默认10 |
|||
page: { size: pageSize }, |
|||
// 数量要大于12条才显示无更多数据 |
|||
noMoreSize: 12, |
|||
// 空布局 |
|||
empty: { |
|||
tip: '亲,暂无充值记录' |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 生命周期函数--监听页面加载 |
|||
*/ |
|||
onLoad(options) {}, |
|||
|
|||
methods: { |
|||
|
|||
/** |
|||
* 上拉加载的回调 (页面初始化时也会执行一次) |
|||
* 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10 |
|||
* @param {Object} page |
|||
*/ |
|||
upCallback(page) { |
|||
const app = this |
|||
// 设置列表数据 |
|||
app.getLogList(page.num) |
|||
.then(list => { |
|||
const curPageLen = list.data.length |
|||
const totalSize = list.data.total |
|||
app.mescroll.endBySize(curPageLen, totalSize) |
|||
}) |
|||
.catch(() => app.mescroll.endErr()) |
|||
}, |
|||
|
|||
// 获取余额账单明细列表 |
|||
getLogList(pageNo = 1) { |
|||
const app = this |
|||
return new Promise((resolve, reject) => { |
|||
OrderApi.list({ page: pageNo }) |
|||
.then(result => { |
|||
// 合并新数据 |
|||
const newList = result.data.list |
|||
app.list.data = getMoreListData(newList, app.list, pageNo) |
|||
resolve(newList) |
|||
}) |
|||
}) |
|||
} |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
page, |
|||
.container { |
|||
background: #fff; |
|||
} |
|||
|
|||
.log-list { |
|||
padding: 0 30rpx; |
|||
} |
|||
|
|||
.log-item { |
|||
font-size: 28rpx; |
|||
padding: 20rpx 20rpx; |
|||
line-height: 1.8; |
|||
border-bottom: 1rpx solid rgb(238, 238, 238); |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
|
|||
.rec-status { |
|||
color: #333; |
|||
|
|||
.rec-time { |
|||
color: rgb(160, 160, 160); |
|||
font-size: 26rpx; |
|||
} |
|||
} |
|||
</style> |
|||
Loading…
Reference in new issue