first commit

This commit is contained in:
2025-08-06 17:17:48 +08:00
commit dc5fba137c
453 changed files with 85995 additions and 0 deletions
+335
View File
@@ -0,0 +1,335 @@
<template>
<!-- pages/address_edit/address_edit.wxml -->
<view class="address-edit">
<form @submit="formSubmit" report-submit="true">
<view class="form bg-white">
<view class="form-item row">
<view class="label">收货人</view>
<input
class="ml10"
v-model="addressObj.contact"
name="contact"
type="text"
placeholder="请填写收货人姓名"
/>
</view>
<view class="form-item row">
<view class="label">联系方式</view>
<input
class="ml10"
name="telephone"
v-model="addressObj.telephone"
type="number"
placeholder="请填写手机号码"
/>
</view>
<view @click="showRegion = true">
<view class="form-item row">
<view class="label">所在地区</view>
<input
class="ml10"
name="region"
v-model="region"
disabled
type="text"
placeholder="请选择省、市、区"
/>
<image class="icon-sm ml10" src="/static/images/arrow_right.png" />
</view>
</view>
<view>
<u-field
v-model="addressObj.address"
type="textarea"
label="详细地址"
placeholder="请填写小区、街道、门牌号等信息"
:field-style="{ flex: 1, 'margin-left': '20rpx', height: '160rpx' }"
/>
<!-- <view class="form-item row" style="height: 200rpx;"> -->
<!-- <view class="label mt20" style="align-self: flex-start;">详细地址</view> -->
<!-- <textarea name="address" style="height: 160rpx;padding: 20rpx 20rpx 20rpx 30rpx;" v-model="addressObj.address" @input="textareaChange" placeholder="请填写小区、街道、门牌号等信息" auto-blur /> -->
<!-- </view> -->
</view>
</view>
<view class="mt10 mb10 bg-white check-wrap">
<radio-group class="row" @click="ChangeIsDefault">
<radio
id="checkbox"
style="border-radius: 50%; transform: scale(0.7)"
:checked="addressObj.is_default ? true : false"
color="#FF2C3C"
/>
<label for="checkbox">
<text>设置为默认</text>
</label>
</radio-group>
</view>
<button class="my-btn bg-primary white br60" form-type="submit">完成</button>
</form>
<u-select
v-model="showRegion"
mode="mutil-column-auto"
@confirm="regionChange"
:list="lists"
></u-select>
</view>
</template>
<script>
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
import { editAddress, getOneAddress, hasRegionCode, addAddress } from '@/api/user'
import area from '@/utils/area'
export default {
data() {
return {
addressObj: {
contact: '',
telephone: '',
province: '',
city: '',
district: '',
address: '',
is_default: 0
},
region: '',
addressId: '',
defaultRegion: ['广东省', '广州市', '番禺区'],
defaultRegionCode: '440113',
showRegion: false,
lists: []
}
},
props: {},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.addressId = parseInt(options.id)
if (options.id) {
uni.setNavigationBarTitle({
title: '编辑地址'
})
this.getOneAddressFun()
} else {
uni.setNavigationBarTitle({
title: '添加地址'
})
this.getWxAddressFun()
}
this.$nextTick(() => {
this.lists = area
})
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
uni.removeStorageSync('wxAddress')
},
/**
* 用户点击右上角分享
*/
// onShareAppMessage: function () {},
methods: {
formSubmit(e) {
let { value } = e.detail
let {
addressObj: { province_id, city_id, district_id, is_default, address },
addressId
} = this
value.address = address
if (!value.contact)
return this.$toast({
title: '请填写收货人姓名'
})
if (!value.telephone)
return this.$toast({
title: '请填写手机号码'
})
if (!value.region)
return this.$toast({
title: '请选择省、市、区'
})
if (!value.address)
return this.$toast({
title: '请填写小区、街道、门牌号等信息'
})
value.province_id = parseInt(province_id)
value.city_id = parseInt(city_id)
value.district_id = parseInt(district_id)
value.is_default = is_default
value.id = addressId
delete value.region
if (addressId) {
editAddress(value)
.then((res) => {
if (res.code == 1) {
this.$toast(
{
title: res.msg
},
{
tab: 3,
url: 1
}
)
}
})
.catch((err) => {
return this.$toast({
title: err
})
})
} else {
addAddress(value)
.then((res) => {
if (res.code == 1) {
this.$toast(
{
title: res.msg
},
{
tab: 3,
url: 1
}
)
}
})
.catch((err) => {
return this.$toast({
title: err
})
})
}
},
regionChange(region) {
this.addressObj.province_id = region[0].value
this.addressObj.city_id = region[1].value
this.addressObj.district_id = region[2].value
this.region = region[0].label + ' ' + region[1].label + ' ' + region[2].label
},
ChangeIsDefault: function (e) {
if (this.addressObj.is_default == 0) {
this.addressObj.is_default = 1
} else {
this.addressObj.is_default = 0
}
},
textareaChange: function (e) {
this.addressObj.address = e.detail.value
},
getOneAddressFun() {
getOneAddress(this.addressId).then((res) => {
if (res.code == 1) {
let { city, province, district } = res.data
this.addressObj = res.data
this.region = `${province} ${city} ${district}`
}
})
},
getWxAddressFun() {
let wxAddress = uni.getStorageSync('wxAddress')
if (!wxAddress) return
wxAddress = JSON.parse(wxAddress)
let {
userName: contact,
telNumber: telephone,
provinceName: province,
cityName: city,
detailInfo: address
} = wxAddress
let district = wxAddress.countryName || wxAddress.countyName
hasRegionCode({
province,
city,
district
}).then((res) => {
if (res.code == 1) {
if (res.data.province && res.data.city && res.data.district) {
this.addressObj.province_id = res.data.province
this.addressObj.city_id = res.data.city
this.addressObj.district_id = res.data.district
this.region = `${province} ${city} ${district}`
}
this.addressObj.contact = contact
this.addressObj.telephone = telephone
this.addressObj.address = address
}
})
}
}
}
</script>
<style lang="scss">
/* pages/address_edit/address_edit.wxss */
.address-edit {
padding-top: 10rpx;
.form {
flex: 1;
.form-item {
padding: 0 24rpx;
height: 80rpx;
&:not(:nth-of-type(3)) {
border-bottom: $-solid-border;
}
.label {
width: 150rpx;
}
input {
height: 100%;
flex: 1;
}
}
}
.check-wrap {
padding: 20rpx;
}
.my-btn {
margin: 30rpx 26rpx;
text-align: center;
}
}
van-field view {
height: 100%;
}
van-field textarea {
height: 100% !important;
padding-top: 10rpx !important;
}
.van-cell {
padding: 20rpx !important;
}
.van-field__body--textarea,
.van-field__input {
margin-left: 15rpx;
}
</style>
+275
View File
@@ -0,0 +1,275 @@
<template>
<view>
<view class="all_comments">
<view class="header bg-white" v-if="!isEmpty">
<view class="title xs">
<text class="lighter mr10">商品好评率</text>
<text class="primary">{{ percent }}</text>
</view>
<view class="tab row">
<block v-for="(item, index) in categoryList" :key="index">
<view
:class="
'tab-item xs mr10 br60 mb20 ' +
(type == item.id ? 'bg-primary white' : 'common-bg')
"
:key="index"
:data-id="item.id"
@tap="onChangType"
v-if="item.count"
>
{{ item.name }}({{ item.count }})
</view>
</block>
</view>
</view>
<view class="main bg-white">
<view class="evaluation-list">
<view v-for="(item, index) in commentList" :key="index" class="evaluation-item">
<view class="user-info row">
<image class="avatar mr20" :src="item.avatar"></image>
<view class="user-name md mr10">{{ item.nickname }}</view>
<u-rate
disabled
size="26rpx"
color="#FF2C3C"
v-model="item.goods_comment"
></u-rate>
</view>
<view class="muted xs mt10">
<text class="mr20">{{ item.create_time }}</text>
<text v-show="item.spec_value_str">{{ item.spec_value_str }}</text>
</view>
<view v-if="item.comment" class="dec mt20">{{ item.comment }}</view>
<view class="img mt20 row" style="flex-wrap: wrap" v-if="item.image.length">
<view
v-for="(imgitem, imgindex) in item.image"
:key="imgindex"
class="img-item mr10 mb20"
:data-current="imgitem"
:data-uri="item.image"
@tap="previewImage"
>
<custom-image
width="160rpx"
fit="cover"
height="160rpx"
radius="6rpx"
lazy-load
class="goods-img"
:src="imgitem"
/>
</view>
</view>
<view class="seller-recall-container common-bg mt10" v-if="item.reply">
<view class="lighter nr" style="word-wrap: break-word">
商家回复<span class="normal two-txt-cut">{{ item.reply }}</span>
</view>
</view>
</view>
</view>
</view>
</view>
<loading-footer :status="status" slotEmpty>
<view slot="empty" class="column-center" style="padding-top: 200rpx">
<image class="img-null" src="/static/images/goods_null.png"></image>
<text class="lighter">暂无评价</text>
</view>
</loading-footer>
</view>
</template>
<script>
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
import { getCommentList, getCommentCategory } from '../../api/store'
import { loadingType } from '../../utils/type'
export default {
data() {
return {
status: loadingType.LOADING,
page: 1,
type: '',
commentList: [],
categoryList: [],
percent: '',
isEmpty: true
}
},
components: {},
props: {},
/**
* 生命周期函数--监听页面加载
*/
onLoad: async function (options) {
this.id = options.id
await this.getCommentCategoryFun()
this.getCommentListFun()
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
this.getCommentListFun()
},
/**
* 用户点击右上角分享
*/
// onShareAppMessage: function () {},
methods: {
onChangType(e) {
let { id } = e.currentTarget.dataset
let { type } = this
if (id == type) return
this.type = id
this.page = 1
this.commentList = []
this.status = loadingType.LOADING
this.$nextTick(() => this.getCommentListFun())
},
getCommentCategoryFun() {
return new Promise((resolve) => {
getCommentCategory(this.id).then((res) => {
let {
code,
data: { comment, percent }
} = res
if (code == 1) {
this.categoryList = comment
this.percent = percent
this.type = comment[0].id
this.$nextTick(() => resolve())
}
})
})
},
getCommentListFun() {
let { page, status, commentList, type } = this
if (status == loadingType.FINISHED) return
getCommentList({
id: type,
goods_id: this.id,
page_no: page
}).then((res) => {
if (res.code == 1) {
let { list, more } = res.data
commentList.push(...list)
this.commentList = commentList
this.page++
this.$nextTick(() => {
if (!more) {
this.status = loadingType.FINISHED
}
if (commentList.length <= 0) {
this.status = loadingType.EMPTY
} else {
console.log('commentList false')
this.isEmpty = false
}
})
}
})
},
previewImage(e) {
const { current, uri } = e.currentTarget.dataset
let urls = uri
uni.previewImage({
current,
// 当前显示图片的http链接
urls // 需要预览的图片http链接列表
})
}
}
}
</script>
<style lang="scss">
.all_comments {
padding-top: 20rpx;
.header {
.title {
padding: 24rpx 26rpx;
border-bottom: var(--border);
}
.tab {
padding: 30rpx 0 10rpx 20rpx;
flex-wrap: wrap;
.tab-item {
padding: 9rpx 29rpx;
}
}
}
.common-bg {
background-color: #f5f5f5;
}
.main {
.evaluation-list {
.evaluation-item {
padding: 20rpx;
&:not(:last-of-type) {
border-bottom: $-solid-border;
}
.avatar {
width: 60rpx;
height: 60rpx;
border-radius: 50%;
}
.seller-recall-container {
padding: 24rpx 20rpx;
border-radius: 12rpx;
}
}
}
}
}
</style>
+729
View File
@@ -0,0 +1,729 @@
// +---------------------------------------------------------------------- // | likeshop开源商城系统
// +---------------------------------------------------------------------- // |
欢迎阅读学习系统程序代码建议反馈是我们前进的动力 // | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github // | 访问官网:https://www.likeshop.cn // |
访问社区https://home.likeshop.cn // | 访问手册:http://doc.likeshop.cn // |
微信公众号likeshop技术社区 // |
likeshop系列产品在giteegithub等公开渠道开源版本可免费商用未经许可不能去除前后端官方版权标识 // |
likeshop系列产品收费版本务必购买商业授权购买去版权授权后方可去除前后端官方版权标识 // |
禁止对系统程序代码以任何目的任何形式的再发布 // | likeshop团队版权所有并拥有最终解释权 //
+---------------------------------------------------------------------- // | author:
likeshop.cn.team // +----------------------------------------------------------------------
<template>
<view>
<view class="confirm-order">
<view class="confirm-con">
<!-- 收货方式 -->
<view class="contain">
<u-tabs
:list="addressTabsList"
:is-scroll="addressTabsList.length === 1"
:current="addressTabsIndex"
:active-color="primaryColor"
bar-width="100"
:bar-style="{ top: '100%' }"
@change="changeDelivery"
/>
<!-- 快递配送 -->
<view
v-show="addressTabsList[addressTabsIndex]['sign'] === 'express'"
class="receiving-card"
@click="onAddressExpress"
>
<u-image
class="icon-md mr20"
width="44"
height="44"
src="/static/images/icon_address.png"
mode="scaleToFill"
/>
<view class="receiving-content">
<template v-if="address.id">
<view class="md black bold">
<text>{{ address.contact }}</text>
<text class="ml10">{{ address.telephone }}</text>
</view>
<view class="xs black mt10">{{
address.province +
address.city +
address.district +
address.address
}}</view>
</template>
<template v-else>
<view>请选择收货地址</view>
</template>
</view>
<u-icon name="arrow-right" />
</view>
<!-- 门店自提 -->
<view
v-show="addressTabsList[addressTabsIndex]['sign'] === 'store'"
class="receiving-card"
@click="onAddressStore"
>
<u-image
class="icon-md mr20"
width="44"
height="44"
src="/static/images/icon_address.png"
mode="scaleToFill"
/>
<view class="receiving-content">
<template v-if="storeInfo.id">
<text class="md black bold">{{ storeInfo.name }}</text>
<text class="xs black mt10">{{ storeInfo.shop_address }}</text>
<text class="xs muted mt10">
<text>营业时间</text>
<text
>{{ storeInfo.business_start_time }} -
{{ storeInfo.business_end_time }}</text
>
</text>
</template>
<template v-else>
<view>请选择门店地址</view>
</template>
</view>
<u-icon name="arrow-right" />
</view>
</view>
<!-- 门店自提表单 -->
<view
v-show="addressTabsList[addressTabsIndex]['sign'] === 'store'"
class="contain store-from"
>
<view class="store-from-item">
<text>提货人</text>
<u-input
v-model="userConsignee"
class="flex1"
type="text"
input-align="right"
:clearable="false"
placeholder="请输入提货人"
/>
</view>
<view class="store-from-item">
<text>联系方式</text>
<u-input
v-model="userMobile"
class="flex1"
type="text"
input-align="right"
:clearable="false"
placeholder="请输入联系方式"
/>
</view>
</view>
<view class="goods contain">
<order-goods
:team="{ need: orderInfo.team_need }"
:list="goodsLists"
:delivery="delivery"
:order_type="orderInfo.order_type"
mode="comfirm"
></order-goods>
<!-- <view class="item row-between">
<view>配送方式</view>
<view>快递</view>
</view> -->
<view class="item row-between">
<view>买家留言</view>
<u-input
v-model="userRemark"
class="flex1 ml20"
:clearable="false"
placeholder="请添加备注(150字以内)"
></u-input>
</view>
</view>
<view class="contain benefit" v-if="orderInfo.order_type == 0">
<view class="item row-between" @tap="showCoupon = true">
<view>优惠券</view>
<view class="row">
<text class="primary" v-if="orderInfo.discount_amount"
>-{{ orderInfo.discount_amount }}</text
>
<text v-else-if="usableCoupon.length" class="primary">{{
usableCoupon.length + '张可用'
}}</text>
<text v-else class="muted">无优惠券可用</text>
<image
class="icon-sm ml20"
src="/static/images/arrow_right.png"
></image>
</view>
</view>
<view class="item row" @tap="changeIntegral" v-if="orderInfo.integral_switch">
<view>积分抵扣</view>
<view class="ml20 muted xs row" style="flex: 1">
{{ orderInfo.user_integral }}积分{{
orderInfo.user_integral < orderInfo.integral_limit
? ',满' + orderInfo.integral_limit + '可用'
: ''
}}
<view style="margin-top: 10rpx" @tap.stop="dialogIntegralDesc">
<u-icon
class="ml10"
color="#999"
size="30"
name="question-circle"
></u-icon>
</view>
</view>
<checkbox
:disabled="
orderInfo.user_integral < orderInfo.integral_limit ||
orderInfo.integral_config == 0
"
:checked="Boolean(useIntegral)"
>
</checkbox>
</view>
</view>
<view class="price contain">
<view class="item row-between">
<view>商品金额</view>
<view>¥{{ orderInfo.total_goods_price }}</view>
</view>
<view class="item row-between">
<view>运费</view>
<view>¥{{ orderInfo.shipping_price }}</view>
</view>
<view class="item row-between" v-if="orderInfo.discount_amount">
<view>优惠券</view>
<view class="primary">-¥{{ orderInfo.discount_amount }}</view>
</view>
<view class="item row-between" v-if="orderInfo.integral_amount">
<view>积分抵扣</view>
<view class="primary">-¥{{ orderInfo.integral_amount }}</view>
</view>
</view>
</view>
<view class="footer bg-white row-between fixed">
<view class="all-price lg row">
<text>合计</text>
<view class="primary">
<price-format
:first-size="36"
:second-size="36"
:price="orderInfo.order_amount"
></price-format>
</view>
</view>
<button class="btn br60 white" size="md" hover-class="none" @tap="onSubmitOrder">
提交订单
</button>
</view>
</view>
<loading-view v-if="showLoading" background-color="transparent" :size="50"></loading-view>
<loading-view v-if="isFirstLoading"></loading-view>
<u-popup v-model="showCoupon" border-radius="14" mode="bottom" closeable>
<view class="pop-title row-between">
<view class="title">优惠券</view>
</view>
<view v-if="showCoupon">
<tabs :active="couponTabsIndex" :config="{ underLineWidth: 100 }">
<tab :title="'可使用优惠券 (' + usableCoupon.length + ')'">
<coupon-obj
:list="usableCoupon"
:type="0"
@change="onSelectCoupon"
:coupon-id="couponId"
></coupon-obj>
</tab>
<tab :title="'不可用优惠券 (' + unusableCoupon.length + ')'">
<coupon-obj
:list="unusableCoupon"
:type="1"
@change="onSelectCoupon"
></coupon-obj>
</tab>
</tabs>
</view>
</u-popup>
</view>
</template>
<script>
import { orderBuy, getOrderCoupon, getDelivery } from '@/api/order'
import { teamBuy } from '@/api/activity'
import { prepay, getMnpNotice, getPayway } from '@/api/app'
import { wxpay, alipay } from '@/utils/pay'
export default {
data() {
return {
isFirstLoading: true, // 首次页面加载loading
showLoading: false, // Loading: 显示 | 隐藏
address: {}, // 收货地址信息
orderInfo: {}, // 订单信息
goodsLists: [], // 商品列表
addressId: '', // 收货地址ID
useIntegral: 0, // 使用积分
userRemark: '', // 用户留言
userConsignee: '', // 取货人
userMobile: '', // 联系电话
storeInfo: {}, // 门店信息
couponId: '', // 优惠券ID
showCoupon: false, // 显示优惠券Popup
couponTabsIndex: 0, // 优惠券Tabs索引
usableCoupon: [], // 优惠券--可使用
unusableCoupon: [], // 优惠券--不可用
bargainLaunchId: -1,
addressTabsIndex: 0, // 地址Tabs索引
// 地址Tabs列表
addressTabsList: [
{
id: 1,
sign: 'express',
name: '快递配送'
},
{
id: 2,
sign: 'store',
name: '门店自提'
}
]
}
},
computed: {
delivery() {
return this.addressTabsList[this.addressTabsIndex]['id']
}
},
onLoad(options) {
const data = JSON.parse(decodeURIComponent(options.data))
this.goods = data.goods
this.type = data.type
this.teamId = data.teamId
this.bargainLaunchId = options.bargain_launch_id
this.foundId = data.foundId || 0
// 配送方式
getDelivery()
// 请求结果判断
.then(({ code, data, msg }) => {
if (code != 1) throw new Error(msg)
return data
})
// 配送方式Tabs处理
.then((data) => {
// 快递
if (!data.is_express) {
this.addressTabsList = this.addressTabsList.filter(
(item) => item.sign !== 'express'
)
}
// 自提
if (!data.is_selffetch) {
this.addressTabsList = this.addressTabsList.filter(
(item) => item.sign !== 'store'
)
}
})
// 页面数据初始化
.then(() => {
this.handleOrderMethods('info')
this.initCouponData()
})
// 监听全局事件
.then(() => {
uni.$on('selectaddress', (params) => {
this.addressId = params.id
this.handleOrderMethods('info')
})
uni.$on('payment', (params) => {
setTimeout(() => {
uni.$off('payment')
if (params.result) {
uni.redirectTo({
url: `/pages/pay_result/pay_result?id=${params.order_id}`
})
} else {
uni.redirectTo({
url: '/pages/user_order/user_order'
})
}
}, 500)
})
uni.$on('store', (params) => {
this.storeInfo = params
})
})
.catch((err) => {
console.log(err)
})
},
onUnload() {
// 取消全局监听
uni.$off(['selectaddress', 'store'])
},
methods: {
// 更改配送方式
changeDelivery(index) {
this.addressTabsIndex = index
this.handleOrderMethods('info')
},
// 点击选择收货地址
onAddressExpress() {
uni.navigateTo({
url: `/pages/user_address/user_address?type=${1}`
})
},
// 点击门店自提
onAddressStore() {
uni.navigateTo({
url: `/bundle/pages/store_list/store_list`
})
},
// 更改积分使用
changeIntegral() {
const useIntegral = this.useIntegral
const orderInfo = this.orderInfo
const integral_limit = orderInfo.integral_limit
const user_integral = orderInfo.user_integral
if (integral_limit > user_integral) return this.$toast({ title: '未满足使用条件' })
this.useIntegral = useIntegral ? 0 : 1
this.$nextTick(() => this.handleOrderMethods('info'))
},
// 积分使用说明Dialog
dialogIntegralDesc() {
const desc = this.orderInfo.integral_desc
uni.showModal({
title: '积分使用说明',
content: desc,
confirmColor: '#FF2C3C',
showCancel: false
})
},
// 选择优惠券
onSelectCoupon(value) {
this.couponId = value
this.showCoupon = false
this.handleOrderMethods('info')
},
// 获取微信授权
authWechatMessage() {
return new Promise((resolve, reject) => {
getMnpNotice({
scene: 1
})
.then(({ code, data, msg }) => {
if (code != 1) throw new Error(msg)
return data
})
.then((data) => {
if (!data.length) return reject()
uni.requestSubscribeMessage({
tmplIds: data,
success(res) {
resolve(res)
},
fail(err) {
reject(err)
}
})
})
.catch((err) => {
reject(err)
})
})
},
// 点击订单提交
onSubmitOrder() {
uni.showModal({
title: '温馨提示',
content: '是否确认下单?',
confirmColor: '#FF2C3C',
success: ({ confirm }) => {
if (!confirm) return
// #ifdef MP-WEIXIN
this.authWechatMessage()
.catch((err) => {
console.log(err)
})
.finally(() => {
this.handleOrderMethods('submit')
})
// #endif
// #ifndef MP-WEIXIN
this.handleOrderMethods('submit')
// #endif
}
})
},
// 初始化优惠券数据
initCouponData() {
getOrderCoupon({
goods: this.goods
})
.then(({ code, data, msg }) => {
if (code != 1) throw new Error(msg)
return data
})
.then((data) => {
this.usableCoupon = data.usable
this.unusableCoupon = data.unusable
})
.catch((err) => {
console.log(err)
})
},
// 初始化页面数据
async initPageData(from) {
this.showLoading = true
try {
const { code, data, msg } = this.teamId ? await teamBuy(from) : await orderBuy(from)
if (code == 1) {
this.address = data.address
this.goodsLists = data.goods_lists
//TODO
if (data.selffetch_info) {
console.log(456)
this.storeInfo = data.selffetch_info.selffetch_shop
? data.selffetch_info.selffetch_shop
: {}
this.userConsignee = data.selffetch_info.contact
this.userMobile = data.selffetch_info.mobile
}
this.orderInfo = data
this.$nextTick(() => {
this.isFirstLoading = false
})
} else {
throw new Error(msg)
}
} catch (err) {
console.log(err)
this.$toast({ title: '网络异常,请重新进入页面' })
} finally {
this.showLoading = false
}
},
// 订单提交
async handleOrderSubmit(from) {
this.showLoading = true
from.remark = this.userRemark
from.type = this.type
try {
const { code, data, msg } = this.teamId ? await teamBuy(from) : await orderBuy(from)
if (code == 1) {
uni.redirectTo({
url: `/pages/payment/payment?from=${data.type}&order_id=${data.order_id}`
})
} else {
throw new Error(msg)
}
} catch (err) {
console.log(err)
// this.$toast({ title: '下单异常,请重新操作' })
} finally {
this.showLoading = false
}
},
// 订单处理
handleOrderMethods(action) {
// 订单提交数据
const orderFrom = {
action,
goods: this.goods,
delivery_type: this.delivery,
use_integral: this.useIntegral,
address_id: this.addressId,
coupon_id: this.couponId,
bargain_launch_id: this.bargainLaunchId == -1 ? '' : this.bargainLaunchId
}
// 门店自提
if (this.addressTabsList[this.addressTabsIndex]['sign'] === 'store') {
orderFrom.selffetch_shop_id = this.storeInfo.id
orderFrom.consignee = this.userConsignee
orderFrom.mobile = this.userMobile
}
// 拼团
if (this.teamId) {
const goods = this.goods[0]
delete orderFrom.goods
orderFrom.item_id = goods.item_id
orderFrom.goods_num = goods.num
orderFrom.team_id = this.teamId
orderFrom.found_id = this.foundId
}
switch (action) {
case 'info':
this.initPageData(orderFrom)
break
case 'submit':
this.handleOrderSubmit(orderFrom)
break
}
}
}
}
</script>
<style>
.confirm-order .confirm-con {
overflow: hidden;
padding-bottom: calc(120rpx + env(safe-area-inset-bottom));
}
.confirm-order .contain {
border-radius: 14rpx;
margin: 20rpx 20rpx 0;
background-color: #fff;
overflow: hidden;
}
.confirm-order .img-line {
height: 1.5px;
width: 100%;
display: block;
}
.confirm-order .coupons {
height: 100rpx;
padding: 0 24rpx;
}
.goods .title {
padding: 22rpx 24rpx;
border-bottom: 1px solid #f6f6f6;
}
.goods .all-num {
padding: 22rpx 24rpx;
border-bottom: 1px dotted #f6f6f6;
}
.confirm-order .footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 100rpx;
padding: 0 30rpx;
box-sizing: content-box;
padding-bottom: env(safe-area-inset-bottom);
}
.confirm-order .price {
padding: 28rpx 20rpx;
}
.confirm-order .price .item:not(:last-of-type) {
margin-bottom: 20rpx;
}
.confirm-order .goods > .item,
.confirm-order .benefit > .item {
padding: 0 24rpx;
height: 80rpx;
}
.confirm-order .btn {
background: linear-gradient(90deg, rgba(249, 95, 47, 1) 0%, rgba(255, 44, 60, 1) 100%);
padding: 0 50rpx;
}
.confirm-order .van-cell:after {
border: none;
}
.goods .shop-icon {
width: 40rpx;
height: 40rpx;
}
.pop-title {
height: 100rpx;
border-bottom: 1rpx solid #f2f2f2;
}
.pop-title .title {
margin-left: 30rpx;
font-size: 34rpx;
font-weight: bold;
line-height: 36rpx;
}
.receiving-way {
margin: 20rpx 20rpx 0 20rpx;
border-radius: 7px;
background-color: #ffffff;
overflow: hidden;
}
.receiving-card {
display: flex;
align-items: center;
min-height: 160rpx;
padding: 20rpx;
border-top: 1px solid #f2f2f2;
}
.receiving-content {
flex: 1;
display: flex;
flex-direction: column;
}
.store-from {
padding: 0 20rpx;
font-size: 28rpx;
}
.store-from-item {
display: flex;
align-items: center;
height: 100rpx;
}
.store-from-item:nth-child(n + 2) {
border-top: 1px dashed #f2f2f2;
}
</style>
File diff suppressed because one or more lines are too long
+980
View File
@@ -0,0 +1,980 @@
<template>
<view class="goods-details">
<navbar title="商品详情" :background="{background: `rgba(256,256,256,${percent})`}" :titleColor="`rgba(0,0,0,${percent})`" :immersive="true"></navbar>
<!-- #ifdef H5 -->
<download-nav v-if="showDownload" :top="44"></download-nav>
<!-- #endif -->
<loading-view v-if="isFirstLoading"></loading-view>
<view class="contain" v-if="!isNull">
<bubble-tips top="180rpx"></bubble-tips>
<product-swiper :imgUrls="swiperList" :video="goodsDetail.video"></product-swiper>
<!-- 秒杀 -->
<view class="seckill row-between" v-if="goodsType == 1">
<view class="price row">
<view class="row white info">
<view style="align-items: baseline;" class="row ml20">
<view class="mr10">秒杀价</view>
<price-format :first-size="46" :second-size="32" :subscript-size="32"
:price="goodsDetail.min_price" :weight="500"></price-format>
<template v-if="goodsDetail.min_price != goodsDetail.max_price">
<text style="font-size: 46rpx;">-</text>
<price-format :first-size="46" :second-size="32" :subscript-size="32"
:show-subscript="false" :price="goodsDetail.max_price" :weight="500"></price-format>
</template>
<view class="ml10">
<price-format :subscript-size="30" :line-through="true" :first-size="30"
:second-size="30" :price="goodsDetail.market_price">
</price-format>
</view>
</view>
</view>
</view>
<view class="down column-center">
<view class="xxs primary mb10">距活动结束仅剩</view>
<u-count-down :timestamp="countTime" @end="getGoodsDetailFun" color="#fff" bg-color="#FF2C3C"
separator-color="#FF2C3C" font-size="24" height="36" separator-size="26"></u-count-down>
</view>
</view>
<!-- 拼团 -->
<view class="group" v-show="goodsType == 2">
<view class="row info" style="height: 100%">
<view class="row-between ml20 white" style="flex: 1;">
<view style="align-items: baseline;" class="row">
<view class="mr10">拼团价</view>
<price-format :subscript-size="32" :first-size="46" :second-size="32"
:price="team.team_min_price" :weight="500"></price-format>
<text class="xs"></text>
</view>
<view class="mr20 row group-num">
<view class="group-icon">
<image src="/static/images/icon_group.png" class="icon-sm"></image>
</view>
<view class="xxs ml10 mr10">{{ team.people_num }}人团</view>
</view>
</view>
<view class="down column-center">
<view class="xxs primary mb10">距活动结束仅剩</view>
<u-count-down :timestamp="countTime" color="#fff" bg-color="#FF2C3C" separator-color="#FF2C3C"
font-size="24" height="36" separator-size="26" @end="getGoodsDetailFun"></u-count-down>
</view>
</view>
</view>
<view class="goods-info bg-white">
<view class="info-header row" v-if="goodsType != 1">
<view class="price row flex1">
<view class="primary mr10">
<price-format :first-size="46" :second-size="32" :subscript-size="32"
:price="goodsDetail.min_price" :weight="500"></price-format>
<template v-if="goodsDetail.min_price != goodsDetail.max_price">
<text style="font-size: 46rpx;">-</text>
<price-format :first-size="46" :second-size="32" :subscript-size="32"
:show-subscript="false" :price="goodsDetail.max_price" :weight="500"></price-format>
</template>
</view>
<view class="line-through muted md">
<price-format :price="goodsDetail.market_price"></price-format>
</view>
</view>
<image class="icon-share" src="/static/images/icon_share.png" @tap="showShareBtn = true"></image>
</view>
<view class="row" v-if="!goodsType && (goodsDetail.member_price)">
<view class="vip-price row">
<view class="price-name xxs">会员价</view>
<view style="padding: 0 11rpx">
<price-format :price="goodsDetail.member_price " :first-size="26" :second-size="26"
:subscript-size="22" :weight="500" color="#7B3200">
</price-format>
<text class="xxs" style="color: #7B3200;"></text>
</view>
</view>
</view>
<view class="row">
<view class="name lg bold">{{ goodsDetail.name }}</view>
<image class="icon-share" src="/static/images/icon_share.png" @tap="showShareBtn = true"
v-if="goodsType == 1"></image>
</view>
<view class="row-between xs lighter" style="padding: 0 24rpx 20rpx">
<text v-if="goodsDetail.stock !== true">库存: {{ goodsDetail.stock }}</text>
<text>销量: {{ goodsDetail.sales_sum }}</text>
<text>浏览量: {{ goodsDetail.click_count }}</text>
</view>
</view>
<view class="group-play bg-white mt20" v-if="goodsType == 2">
<view class="title">拼团玩法</view>
<view class="steps row">
<view class="row step">
<view class="number xxs">1</view>
<view class="sm">开团/参团</view>
</view>
<view class="line"></view>
<view class="row step">
<view class="number xxs">2</view>
<view class="sm">团满即成新团</view>
</view>
<view class="line"></view>
<view class="row step">
<view class="number xxs">3</view>
<view class="sm">满员发货</view>
</view>
</view>
</view>
<view class="discount mt20 bg-white" v-if="couponList.length || goodsDetail.order_give_integral">
<view class="row" style="align-items: flex-start;">
<view class="text muted">优惠</view>
<view style="flex: 1">
<view :class="['row coupons', {mb30: goodsDetail.order_give_integral > 0}]"
v-if="couponList.length" @tap="showCouponFun">
<view class="flexnone">
<u-tag text="领券" size="mini" type="primary" mode="plain" />
</view>
<view class="con row ml20" style="flex: 1">
<view v-for="(item, index) in couponList" :key="index" class="coupons-item mr20">
<view v-if="index < 2" class="row xs">
<view class="line1">
{{ item.use_condition }}
</view>
</view>
</view>
</view>
<image class="icon-sm" src="/static/images/arrow_right.png"></image>
</view>
<view class="row integral" style="align-items: flex-start;"
v-if="goodsDetail.order_give_integral">
<view class="flexnone">
<u-tag text="积分" size="mini" type="primary" mode="plain" />
</view>
<view class="ml20">下单最多可获得{{goodsDetail.order_give_integral}}积分</view>
</view>
</view>
</view>
</view>
<swiper v-if="teamFound.length" class="mt20 bg-white" autoplay="true" style="height: 240rpx;"
vertical="true" circular="true" :interval="5000">
<swiper-item v-for="(sitem, index) in teamFound" :key="index">
<view class="group-list">
<view v-for="(item, index2) in sitem" :key="index2" class="group-item bg-white row-between">
<view class="row" style="max-width: 280rpx;">
<custom-image :src="item.avatar" width="80rpx" height="80rpx" radius="50%">
</custom-image>
<view class="ml20 line1 normal">{{ item.nickname }}</view>
</view>
<view class="row ml20" style="flex: none;">
<view class="column-center">
<text class="sm normal">
还差
<text class="primary">{{ item.need - item.join }}</text>
人成团
</text>
<view class="muted xs">
剩余
<u-count-down :timestamp="getTeamCountTime(item.found_end_time)"
separator-color="#999" color="#999" :separator-size="24" :font-size="24"
bg-color="transparent" @end="getGoodsDetailFun"></u-count-down>
</view>
</view>
<view class="group-btn br60 white row-center" @tap="showSpecFun(3, item.id)">去参团</view>
</view>
</view>
</view>
</swiper-item>
</swiper>
<view v-if="!goodsType" class="spec row bg-white mt20" @tap="showSpecFun(0)">
<view class="text lighter">已选</view>
<view class="line1 mr20" style="flex: 1;">{{ checkedGoods.spec_value_str || '默认' }}</view>
<image class="icon-sm" src="/static/images/arrow_right.png"></image>
</view>
<navigator class="mt20" hover-class="none" url="/bundle/pages/server_explan/server_explan?type=2">
<view class="row bg-white" style="padding: 24rpx 24rpx;">
<view class="text lighter flex1">售后保障</view>
<image class="icon-sm" src="/static/images/arrow_right.png"></image>
</view>
</navigator>
<view class="evaluation bg-white mt20">
<navigator hover-class="none" :url="'/pages/all_comments/all_comments?id=' + goodsDetail.id"
class="title row-between">
<view>
<text class="balck md mr10">用户评价</text>
<text class="primary sm">好评率{{ comment.goods_rate || '0%' }}</text>
</view>
<view class="row">
<text class="lighter">查看全部</text>
<image class="icon-sm" src="/static/images/arrow_right.png"></image>
</view>
</navigator>
<view class="con" v-if="comment.goods_rate">
<view class="user-info row">
<image class="avatar mr20" :src="comment.avatar"></image>
<view class="user-name md mr10">{{ comment.nickname }}</view>
</view>
<view class="muted xs mt10">
<text class="mr20">{{ comment.create_time }}</text>
</view>
<view v-if="comment.comment" class="dec mt20">{{ comment.comment }}</view>
</view>
<view class="con row-center muted" v-else>暂无评价</view>
</view>
<view class="goods-like mt20 bg-white" v-if="goodsLike.length">
<goods-like :list="goodsLike"></goods-like>
</view>
<view class="details mt20 bg-white">
<view class="title lg">商品详情</view>
<view class="content">
<u-parse :html="goodsDetail.content" :lazy-load="true" :show-with-animation="true"></u-parse>
</view>
</view>
<view class="footer row bg-white fixed">
<navigator class="btn column-center" hover-class="none"
url="/bundle/pages/contact_offical/contact_offical">
<image class="icon-md" src="/static/images/icon_contact.png"></image>
<text class="xxs lighter">客服</text>
</navigator>
<button class="btn column-center" hover-class="none" @tap="collectGoodsFun">
<image class="icon-md"
:src="goodsDetail.is_collect == 1 ? '/static/images/icon_collection_s.png' : '/static/images/icon_collection.png'">
</image>
<text class="xxs lighter">收藏</text>
</button>
<navigator class="btn cart column-center" hover-class="none" open-type="switchTab"
url="/pages/shop_cart/shop_cart">
<image class="icon-md" src="/static/images/icon_cart.png"></image>
<text class="xxs lighter">购物车</text>
<u-badge v-if="cartNum" bgColor="#FF2C3C" :offset="[8, 10]" :count="cartNum"></u-badge>
</navigator>
<view v-if="btnText.yellow" class="add-cart br60 white mr10 md ml20" @tap="showSpecFun(1)">
{{ btnText.yellow }}
</view>
<view class="right-buy br60 white mr20 ml10 md" @tap="showSpecFun(2)">{{ btnText.red }}</view>
</view>
</view>
<view v-else>
<view class="details-null column-center">
<image class="img-null" src="/static/images/goods_null.png"></image>
<view class="xs muted">该商品已下架或不存在去逛逛别的吧~</view>
</view>
<recommend></recommend>
</view>
<spec-popup :show="showSpec" :goods="goodsDetail" :is-seckill="goodsType == 1" @close="showSpec = false"
:show-add="popupType == 1 || popupType == 0" :show-buy="popupType == 2 || popupType == 0"
:showConfirm="popupType == 3" @buynow="onBuy" @addcart="onAddCart" @change="onChangeGoods"
:group="Boolean(isGroup)" :red-btn-text="btnText.red" :yellow-btn-text="btnText.yellow"
@confirm="onConfirm"></spec-popup>
<share-popup v-model="showShareBtn"
:share-id="id"
pagePath="pages/goods_details/goods_details"
:type="1"
:config="{
avatar: userInfo.avatar,
nickname: userInfo.nickname,
image: goodsDetail.poster || goodsDetail.image,
price: goodsDetail.min_price,
marketPrice: goodsDetail.market_price,
name: goodsDetail.name
}">
</share-popup>
<!-- 领券 -->
<u-popup v-model="showCoupon" mode="bottom" border-radius="14">
<view>
<view class="row-between" style="padding: 30rpx">
<view class="title md bold">领券</view>
<view class="close" @tap="showCoupon = false">
<image class="icon-lg" src="/static/images/icon_close.png"></image>
</view>
</view>
<view class="content bg-body">
<scroll-view scroll-y="true" style="height: 700rpx">
<coupon-list :list="couponList" @reflash="getGoodsCouponFun" :btn-type="3"></coupon-list>
</scroll-view>
</view>
</view>
</u-popup>
<view class="share-money" :class="{ show: showCommission && enableCommission}">
<view class="row-end">
<view class="share-close row-center" @tap="showCommission=false">
<u-icon name="close" size="16" color="#fff"></u-icon>
</view>
</view>
<view class="share-con mt10" @tap="showShareBtn=true">
<view class="primary" style="font-size: 45rpx;">
{{distribution.earnings}}<text class="xs"></text>
</view>
<view class="lighter xxs">
好友下单最高可赚
</view>
</view>
</view>
<u-back-top :scroll-top="scrollTop" :top="1000" :customStyle="{ backgroundColor: '#FFF', color: '#000', boxShadow: '0px 3px 6px rgba(0, 0, 0, 0.1)'}"></u-back-top>
</view>
</template>
<script>
import {
getGoodsDetail,
addCart,
getPoster,
getCartNum
} from '@/api/store';
import {
collectGoods
} from '@/api/user';
import {
getGoodsCoupon,
teamCheck
} from '@/api/activity';
import {
mapActions,
mapGetters
} from 'vuex';
import {
arraySlice,
trottle
} from '@/utils/tools';
import {
toLogin
} from '@/utils/login';
import {
getUser,
inputInviteCode
} from '@/api/user';
import Cache from '@/utils/cache';
import {
strToParams
} from '@/utils/tools'
export default {
data() {
return {
scrollTop: 0,
percent: 0,
isFirstLoading: true,
isNull: false,
showSpec: false,
showCoupon: false,
showShareBtn: false,
showCommission: true,
popupType: '',
swiperList: [],
goodsDetail: {},
goodsLike: [],
goodsType: 0,
checkedGoods: {},
couponList: [],
comment: {},
countTime: 0,
tagStyle: {
img: 'width:100%;'
},
team: {},
teamFound: [],
isGroup: 0,
id: '',
showDownload: false,
distribution: {}
};
},
onLoad(options) {
this.onPageScroll = trottle(this.onPageScroll, 500, this)
if (options && options.scene) {
let scene = strToParams(decodeURIComponent(options.scene));
console.log(scene, decodeURIComponent(options.scene))
options.id = scene.id;
}
// #ifdef H5
if (options && options.isapp == 1) {
this.showDownload = true;
}
// #endif
if (!options.id) {
return this.$toast({
title: '缺少参数,无法查看商品'
}, {
tab: 3
});
} else {
this.id = options.id;
}
this.getGoodsCouponFun();
this.getCartNum();
},
onShow() {
this.getGoodsDetailFun();
},
onPageScroll(e) {
const top = uni.upx2px(100)
const {
scrollTop
} = e
this.percent = scrollTop / top > 1 ? 1 : scrollTop / top
this.scrollTop = scrollTop
},
methods: {
...mapActions(['getCartNum']),
async getGoodsDetailFun() {
const {
data,
code
} = await getGoodsDetail({
id: this.id
});
if (code == 1) {
let {
goods_image,
content,
comment,
like,
activity,
distribution
} = data;
let {
info,
team,
team_found
} = activity; //秒杀时间
let time = info ?
info.end_time - Date.now() / 1000 //拼团时间
:
team ?
team.end_time - Date.now() / 1000 :
0;
if (team_found) {
team_found = arraySlice(team_found, [], 2);
}
this.distribution = distribution || {}
this.goodsDetail = data;
this.swiperList = goods_image;
this.comment = comment;
this.goodsLike = like;
this.countTime = time;
this.goodsType = activity.type || 0;
this.team = team ? team : {};
this.teamFound = team_found ? team_found : [];
this.$nextTick(() => {
this.isFirstLoading = false;
});
// #ifdef H5
let options = {
shareTitle: data.name,
shareLink: location.href + '&invite_code=' + this.userInfo.distribution_code,
shareImage: data.image,
shareDesc: data.remark
};
this.wxShare(options);
// #endif
} else {
this.isNull = true
this.isFirstLoading = false;
}
},
async getGoodsCouponFun() {
const {
data,
code
} = await getGoodsCoupon({
id: this.id
});
if (code == 1) {
this.couponList = data;
}
},
async collectGoodsFun() {
if (!this.isLogin) return toLogin();
const {
goodsDetail: {
is_collect
}
} = this;
const {
data,
code
} = await collectGoods({
is_collect: is_collect == 0 ? 1 : 0,
goods_id: this.id
});
if (code == 1) {
if (is_collect == 0) {
this.$toast({
title: '收藏成功'
});
} else {
this.$toast({
title: '取消收藏'
});
}
this.getGoodsDetailFun();
}
},
showCouponFun() {
if (!this.isLogin) return toLogin();
this.showCoupon = true;
},
onChangeGoods(e) {
console.log(e);
this.checkedGoods = e.detail;
},
showSpecFun(type, id) {
if (!this.isLogin) return toLogin();
if (this.goodsType == 2 && [2, 3].includes(type)) {
this.isGroup = 1;
this.foundId = id;
} else {
this.isGroup = 0;
this.foundId = '';
}
this.popupType = type;
this.showSpec = true;
},
onBuy(e) {
let {
id,
goodsNum
} = e.detail;
const {
goodsType,
team
} = this;
let goods = [{
item_id: id,
num: goodsNum
}];
const params = {
goods,
};
this.showSpec = false;
goodsType == 2 ? (params.teamId = team.team_id) : '';
this.foundId ? (params.foundId = this.foundId) : '';
uni.navigateTo({
url: '/pages/confirm_order/confirm_order?data=' + encodeURIComponent((JSON.stringify(params)))
})
console.log(1111)
},
onConfirm(e) {
const {
team: {
team_id
}
} = this;
teamCheck({
team_id,
found_id: this.foundId
}).then(res => {
if (res.code == 1) {
this.onBuy(e);
}
});
},
async onAddCart(e) {
let {
id,
goodsNum
} = e.detail;
if (this.goodsType == 2) {
// 拼团单独购买
let goods = [{
item_id: id,
num: goodsNum
}];
uni.navigateTo({
url: '/pages/confirm_order/confirm_order?data=' + encodeURIComponent((JSON.stringify({
goods
})))
})
return
}
const {
code,
data,
msg
} = await addCart({
item_id: id,
goods_num: goodsNum
});
if (code == 1) {
this.getCartNum();
this.$toast({
title: msg,
icon: 'success'
});
this.showSpec = false;
}
}
},
async onShareAppMessage() {
const {
goodsDetail,
team,
userInfo
} = this;
return {
title: team.share_title || goodsDetail.name,
imageUrl: goodsDetail.image,
path: '/pages/goods_details/goods_details?id=' + this.id + "&invite_code=" + userInfo.distribution_code
};
},
computed: {
...mapGetters(['cartNum', 'userInfo']),
btnText() {
const {
goodsType
} = this;
switch (goodsType) {
case 1:
return {
red: '立即抢购',
yellow: ''
};
case 2:
return {
red: '立即开团',
yellow: '单独购买'
};
default:
return {
red: '立即购买',
yellow: '加入购物车'
};
}
},
getTeamCountTime() {
return time => time - Date.now() / 1000;
},
enableCommission() {
const {
goodsType,
distribution: {
earnings,
is_show
}
} = this
return goodsType == 0 && earnings > 0 && is_show == 1
}
}
};
</script>
<style lang="scss" scoped>
.goods-details {
padding-bottom: calc(120rpx + env(safe-area-inset-bottom));
.seckill {
height: 100rpx;
background: #ffd4d8;
.price {
width: 504rpx;
height: 100%;
background: url(../../static/images/bg_seckill.png) no-repeat;
background-size: 100%;
}
.down {
flex: 1;
}
}
.group {
height: 100rpx;
width: 100%;
background-image: url(../../static/images/pintuan_bg.png);
background-size: 100%;
.group-num {
border: 1px solid #ffffff;
border-radius: 4rpx;
.group-icon {
background: #fff;
padding: 3rpx 7rpx;
}
}
.down {
height: 100%;
background-color: #fff5e1;
padding: 0 20rpx;
}
}
.goods-info {
position: relative;
.info-header {
padding: 20rpx 0 0rpx 24rpx;
.price {
align-items: baseline;
}
}
.vip-price {
margin: 0 24rpx;
background-color: #FFE9BA;
color: #FFD4B7;
line-height: 36rpx;
border-radius: 6rpx;
overflow: hidden;
.price-name {
background-color: #101010;
padding: 3rpx 12rpx;
position: relative;
overflow: hidden;
&::after {
content: '';
display: block;
width: 20rpx;
height: 20rpx;
position: absolute;
right: -15rpx;
background-color: #FFE9BA;
border-radius: 50%;
top: 50%;
transform: translateY(-50%);
box-sizing: border-box;
}
}
}
.name {
padding: 20rpx 24rpx;
flex: 1;
}
.icon-share {
width: 134rpx;
height: 60rpx;
}
}
.discount {
padding: 24rpx;
.text {
width: 100rpx;
flex: none;
}
.con {
width: 400rpx;
}
.coupons-item {
overflow: hidden;
&>view {
position: relative;
height: 40rpx;
line-height: 40rpx;
padding: 0 18rpx;
border-radius: 6rpx;
box-sizing: border-box;
background-color: $-color-primary;
color: #fff;
white-space: nowrap;
overflow: hidden;
&::after,
&::before {
content: '';
display: block;
width: 20rpx;
height: 20rpx;
position: absolute;
left: -14rpx;
background-color: #fff;
border-radius: 50%;
border: 1px solid currentColor;
box-sizing: border-box;
}
&::after {
right: -14rpx;
left: auto;
}
}
}
}
.details-null {
padding-top: 140rpx;
margin-bottom: 100rpx;
}
.spec {
padding: 24rpx;
.text {
width: 100rpx;
}
}
.evaluation {
.title {
height: 100rpx;
border-bottom: $-solid-border;
padding: 0 24rpx;
}
.con {
padding: 30rpx 24rpx;
}
.user-info .avatar {
width: 60rpx;
height: 60rpx;
border-radius: 50%;
}
}
.details {
.title {
line-height: 88rpx;
text-align: center;
}
&>.content {
padding: 0 20rpx 20rpx;
overflow: hidden;
::v-deep image {
vertical-align: middle;
}
// #ifdef H5
::v-deep img {
vertical-align: middle;
}
// #endif
// #ifdef MP-WEIXIN || APP-PLUS
::v-deep ._img {
display: block;
}
// #endif
}
}
.footer {
height: 100rpx;
position: fixed;
bottom: 0;
left: 0;
right: 0;
box-sizing: content-box;
padding-bottom: env(safe-area-inset-bottom);
.btn {
width: 100rpx;
height: 100rpx;
position: relative;
line-height: 1.3;
}
.cart-num {
position: absolute;
left: 60rpx;
top: 6rpx;
}
.add-cart,
.right-buy {
flex: 1;
text-align: center;
padding: 16rpx 0;
}
.add-cart {
background-color: #ffa630;
}
.right-buy {
background-color: $-color-primary;
}
}
.group-play {
.title {
padding: 20rpx 28rpx;
border-bottom: $-solid-border;
}
.steps {
padding: 20rpx 28rpx;
.step {
flex: none;
}
.line {
flex: 1;
border: 1px dashed #999999;
margin: 0 20rpx;
}
.number {
border: 1rpx solid #707070;
width: 28rpx;
height: 28rpx;
border-radius: 50%;
line-height: 28rpx;
text-align: center;
margin-right: 6rpx;
}
}
}
.group-list {
.group-item {
padding: 20rpx 24rpx;
&:not(:last-of-type) {
border-bottom: $-solid-border;
}
.group-btn {
background: linear-gradient(90deg, #f95f2f 0%, #ff2c3c 100%);
height: 58rpx;
padding-left: 28rpx;
padding-right: 28rpx;
margin-left: 30rpx;
box-shadow: 0px 6rpx 12rpx rgba(249, 47, 138, 0.4);
}
}
}
.share-money {
position: fixed;
left: 20rpx;
bottom: calc(130rpx + env(safe-area-inset-bottom));
transform: scale(0);
transition: all .3s;
&.show {
transform: scale(1);
}
.share-close {
width: 34rpx;
height: 34rpx;
background: #a7a7a7;
border-radius: 50%;
}
.share-con {
background: url('../../static/images/bg_packet_img.png');
width: 241rpx;
height: 208rpx;
background-size: 100%;
padding-top: 20rpx;
text-align: center;
}
}
}
</style>
+316
View File
@@ -0,0 +1,316 @@
<template>
<view class="goods-search">
<view class="header-wrap">
<u-sticky offset-top="0" h5-nav-height="0">
<view class="search">
<u-search v-model="keyword" @focus="showHistory = true" :focus="showHistory" @search="onSearch" bg-color="#F4F4F4"></u-search>
</view>
<view v-show="!showHistory" class="header row bg-white">
<view :class="'tag row-center ' + (comprehensive ? 'primary' : '')" @tap="onNormal">综合</view>
<view class="tag row-center" data-type="priceSort" @tap="onPriceSort">
<text :class="priceSort ? 'primary' : ''">价格</text>
<view>
<trigonometry direction="up" size="small" :color="priceSort == 'desc' ? '#FF5058' : '#333'">
</trigonometry>
<trigonometry size="small" :color="priceSort == 'asc' ? '#FF5058' : '#333'"></trigonometry>
</view>
</view>
<view class="tag row-center" data-type="saleSort" @tap="onSaleSort">
<text :class="saleSort ? 'primary' : ''">销量</text>
<view>
<trigonometry direction="up" size="small" :color="saleSort == 'desc' ? '#FF5058' : '#333'">
</trigonometry>
<trigonometry size="small" :color="saleSort == 'asc' ? '#FF5058' : '#333'"></trigonometry>
</view>
</view>
<view class="tag row-center" @tap="changeType">
<image class="icon-sm" :src=" goodsType === 'one' ? '/static/images/icon_double.png' : '/static/images/icon_one.png'"></image>
</view>
</view>
</u-sticky>
</view>
<view v-show="showHistory" class="content bg-white">
<view v-if="hotList.length" class="search-words">
<view class="title">热门搜索</view>
<view class="words row wrap">
<view v-for="(item, index) in hotList" :key="index" class="item br60 mr20 mb20 lighter sm line1" @tap="onChangeKeyword(item)">{{item}}</view>
</view>
</view>
<view v-if="historyList.length" class="search-words">
<view class="title row-between">
<view>历史搜索</view>
<view class="xs muted mr20" style="padding: 10rpx 20rpx" @tap="clearSearchFun">清空</view>
</view>
<view class="words row wrap">
<view v-for="(item, index) in historyList" :key="index" class="item br60 mr20 mb20 lighter sm line1" @tap="onChangeKeyword(item)">{{item}}</view>
</view>
</view>
</view>
<view v-show="!showHistory" class="content">
<view class="goods-list">
<view v-show="goodsType == 'double'" class="double">
<goods-list type="double" :list="goodsList"></goods-list>
</view>
<view v-show="goodsType == 'one'" class="one">
<goods-list :list="goodsList" type="one"></goods-list>
</view>
</view>
<loading-footer :status="status" :slot-empty="true">
<view slot="empty" class="column-center" style="padding-top: 200rpx">
<image class="img-null" src="/static/images/goods_null.png"></image>
<text class="lighter">暂无商品</text>
</view>
</loading-footer>
</view>
</view>
</template>
<script>
import {
getGoodsSearch,
getSearchpage,
clearSearch
} from '@/api/store';
import {
trottle,
loadingFun,
getRect
} from '@/utils/tools';
import {
loadingType
} from '@/utils/type';
export default {
data() {
return {
keyword: '',
status: loadingType.LOADING,
page: 1,
goodsType: 'double',
goodsList: [],
priceSort: '',
saleSort: '',
showHistory: false,
hotList: [],
historyList: []
};
},
components: {},
props: {},
watch: {
// 监听属性
keyword(value, old) {
if (!value && !this.id) {
this.showHistory = true
}
},
showHistory(value) {
if (value) {
this.getSearchpageFun();
}
}
},
computed: {
comprehensive() {
const {
priceSort,
saleSort
} = this
if (priceSort == '' && saleSort == '') {
return true;
}
return false;
}
},
onLoad(options) {
this.onNormal = trottle(this.onNormal, 500, this);
this.onPriceSort = trottle(this.onPriceSort, 500, this);
this.onSaleSort = trottle(this.onSaleSort, 500, this);
this.onSearch = trottle(this.onSearch, 500, this);
this.init(options);
},
onReachBottom: function() {
this.getGoodsSearchFun();
},
methods: {
onChange(e) {
this.keyword = e.value
},
changeType() {
this.goodsType = this.goodsType === 'one' ? 'double' : 'one'
},
clearSearchFun() {
clearSearch().then(res => {
if (res.code == 1) {
this.getSearchpageFun();
}
});
},
onNormal() {
this.priceSort = ''
this.saleSort = ''
this.onRefresh();
},
onPriceSort() {
let {
priceSort
} = this;
this.saleSort = ''
this.priceSort = priceSort == 'asc' ? 'desc' : 'asc'
this.onRefresh();
},
onSaleSort() {
let {
saleSort
} = this;
this.priceSort = ''
this.saleSort = saleSort == 'desc' ? 'asc' : 'desc'
this.onSearch();
},
init(option) {
let {
id,
name,
type
} = option;
this.type = type;
if (id) {
uni.setNavigationBarTitle({
title: name
});
this.id = id;
this.getGoodsSearchFun();
} else {
uni.setNavigationBarTitle({
title: '搜索'
});
this.showHistory = true
}
},
getSearchpageFun() {
getSearchpage().then(res => {
if (res.code == 1) {
let {
history_lists,
hot_lists
} = res.data;
this.hotList = hot_lists
this.historyList = history_lists
}
});
},
onClear() {
if (this.id) {
this.onSearch();
}
},
onSearch() {
this.onRefresh()
},
onRefresh() {
this.showHistory = false
this.page = 1
this.goodsList = []
this.status = loadingType.LOADING
this.$nextTick(() => {
this.getGoodsSearchFun();
});
},
onChangeKeyword(item) {
this.keyword = item
this.showHistory = false
this.onRefresh();
},
async getGoodsSearchFun() {
let {
page,
goodsList,
keyword,
priceSort,
saleSort,
status
} = this;
if (status == loadingType.FINISHED) return;
const params = {
category_id: this.type == 1 ? this.id : '',
brand_id: this.type == 0 ? this.id : '',
page_no: page,
keyword,
price: priceSort,
sales_sum: saleSort
}
const data = await loadingFun(getGoodsSearch, page, goodsList, status, params)
if (!data) return
this.page = data.page
this.goodsList = data.dataList
this.status = data.status
},
}
};
</script>
<style lang="scss">
.goods-search {
.header-wrap {
.search {
box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.03);
position: relative;
z-index: 1;
}
.header {
height: 80rpx;
.tag {
height: 100%;
flex: 1;
}
}
}
.content {
.search-words {
padding-left: 24rpx;
padding-bottom: 20rpx;
.title {
padding: 26rpx 0;
}
.words {
.item {
line-height: 52rpx;
height: 52rpx;
padding: 0 24rpx;
background-color: #F5F5F5;
}
}
}
.goods-list {
overflow: hidden;
}
}
}
</style>
+841
View File
@@ -0,0 +1,841 @@
<template>
<view class="index home-bg" :style="[navBackground]">
<!-- #ifdef H5 -->
<download-nav v-if="isShowDownload"></download-nav>
<!-- #endif -->
<u-sticky offset-top="0" h5-nav-height="0" bg-color="transparent" :enable="enable">
<u-navbar
:border-bottom="false"
:is-fixed="false"
custom-class="home-bg"
:background="navBackground"
:is-back="false"
>
<view class="row logo-wrap flex1" v-show="navBg < 1 && showLogo">
<image :src="logo" mode="heightFix" class="logo ml30"></image>
</view>
<view class="flex1 row nav-search" v-show="navSearch">
<navigator
hover-class="none"
@click="goPage('/bundle/pages/message_center/message_center')"
>
<image class="icon-md ml30" src="/static/images/icon_news.png"> </image>
</navigator>
<navigator
class="ml20 flex1 mr20"
hover-class="none"
url="/pages/goods_search/goods_search"
>
<u-search
wrap-bg-color="transparent"
:bg-color="'#fff'"
:disabled="true"
:height="62"
>
</u-search>
</navigator>
</view>
</u-navbar>
</u-sticky>
<view class="flex1 row" v-if="showLogo">
<navigator
hover-class="none"
@tap="goPage('/bundle/pages/message_center/message_center')"
>
<image class="icon-md ml30" src="/static/images/icon_news.png"> </image>
</navigator>
<navigator
class="ml20 flex1 mr20"
hover-class="none"
url="/pages/goods_search/goods_search"
>
<u-search
wrap-bg-color="transparent"
:bg-color="'#fff'"
:disabled="true"
:height="62"
></u-search>
</navigator>
</view>
<view class="contain">
<view class="main">
<bubble-tips top="50rpx" :discharge="isDischarge"></bubble-tips>
<swipers :pid="1" height="322rpx" padding="20rpx 0"></swipers>
<!-- 导航入口 -->
<view class="nav bg-white" v-if="navList.length">
<swiper :style="'height:' + navSwiperH + 'rpx;'" @change="swiperChange">
<swiper-item v-for="(items, index) in navList" :key="index">
<view class="nav-list row wrap">
<view
v-for="(item, index2) in items"
:key="index2"
@tap="tapMenu(item)"
class="nav-item column-center"
>
<image class="nav-icon" :src="item.image"></image>
<view class="name xs">{{ item.name }}</view>
</view>
</view>
</swiper-item>
</swiper>
<view class="dots" v-if="navList.length > 1">
<view
v-for="(item, index) in navList"
:key="index"
:class="'dot ' + (index == currentSwiper ? 'active' : '')"
></view>
</view>
</view>
<!-- 资讯 -->
<navigator
v-if="news.length"
class="information bg-white row mt20"
hover-class="none"
open-type="navigate"
url="/pages/news_list/news_list"
>
<image class="icon-toutiao" src="/static/images/icon_toutiao.png"></image>
<text class="gap-line"></text>
<view class="news flex1">
<view class="shade"></view>
<swiper
autoplay="true"
style="height: 76rpx; flex: 1"
vertical="true"
circular="true"
:interval="3000"
>
<swiper-item v-for="(item, index) in news" :key="index" class="row">
<view class="flexnone">
<u-tag
v-if="item.is_new"
shape="circle"
text="最新"
size="mini"
type="primary"
mode="plain"
/>
</view>
<view class="text-swiper ml10 line1">{{ item.title }}</view>
</swiper-item>
</swiper>
</view>
<image class="icon-sm ml20" src="/static/images/arrow_right.png" />
</navigator>
<!-- 领卷 -->
<swipers :is-swiper="false" :pid="23" height="170rpx" padding="20rpx 0 0"></swipers>
<!-- 活动专区 -->
<view class="special-area mt20">
<view>
<scroll-view style="white-space: nowrap" :scroll-x="true">
<navigator
class="item bg-white"
v-for="(item, index) in activityArea"
:key="index"
hover-class="none"
:url="`/bundle/pages/activity_detail/activity_detail?id=${item.id}&name=${item.title}&title=${item.name}`"
>
<view class="column-center">
<custom-image
width="300rpx"
height="436rpx"
:src="item.image"
></custom-image>
<!-- <view class="title xxl">{{item.name}}</view>
<view class="desc primary xxs line1">{{item.title}}</view> -->
</view>
</navigator>
</scroll-view>
</view>
</view>
<!-- 秒杀 -->
<view class="seckill mt20" v-if="seckillGoods.length">
<active-area type="seckill" progressBarColor="#FF2C3C" :lists="seckillGoods">
<navigator
slot="header"
hover-class="none"
class="row activity-header white"
open-type="navigate"
url="/bundle/pages/goods_seckill/goods_seckill"
>
<view class="title xxl bold">超值秒杀</view>
<view class="row flex1">
<text class="white xs ml10 line1"
>{{ seckill.start_time }}点场</text
>
<view class="dec ml20 row-center mr20 br60">
<u-count-down
:timestamp="remainTime"
separator-color="#FF2C3C"
color="#FF2C3C"
:separator-size="24"
:font-size="24"
bg-color="transparent"
></u-count-down>
</view>
</view>
<view class="row xs">
更多
<u-icon name="arrow-right" size="28"></u-icon>
</view>
</navigator>
</active-area>
</view>
<!-- 热销 -->
<view class="hot mt20" v-if="hotGoods.length && seting.hots">
<active-area type="hot" progressBarColor="#9912FE" :lists="hotGoods">
<navigator
slot="header"
hover-class="none"
class="row activity-header"
open-type="navigate"
url="/bundle/pages/hot_list/hot_list"
>
<view class="title flex1">
<image
class="title-image"
src="/static/images/hot_title.png"
></image>
</view>
<view class="row xs">
更多
<u-icon name="arrow-right" size="28"></u-icon>
</view>
</navigator>
</active-area>
</view>
<!-- 新品推荐 -->
<view v-if="newGoods.length && seting.news" class="new-goods">
<active-area type="news" progressBarColor="#9912FE" :lists="newGoods">
<navigator
slot="header"
hover-class="none"
class="row activity-header"
open-type="navigate"
url=""
>
<view class="title flex1">
<image
class="title-image"
src="/static/images/new_title.png"
></image>
</view>
<!-- <view class="row xs">
更多
<u-icon name="arrow-right" size="28"></u-icon>
</view> -->
</navigator>
</active-area>
</view>
</view>
<!-- 好物优选 -->
<view class="goods mt20" v-if="goodsList.length">
<view class="goods-title row-center">
<text class="line"></text>
<view class="row">
<image class="mr10 icon" src="/static/images/icon_like.png"></image>
<text class="bold xxl">好物优选</text>
</view>
<text class="line"></text>
</view>
<goods-list :list="goodsList"></goods-list>
<loading-footer :status="status"></loading-footer>
</view>
</view>
<u-popup class="coupons-popup" v-model="showCoupop" mode="center">
<view class="wrap">
<image class="coupon-bg" src="/static/images/home_coupon_bg.png"></image>
<scroll-view :scroll-y="true" style="height: 460rpx; margin-top: 300rpx">
<view class="item" v-for="(item, index) in couponPopList" :key="item.id">
<image class="img" src="/static/images/pop_bg_coupon.png"></image>
<view class="row item-con">
<view class="row-center price">
<price-format
color="#FF2C3C"
:showSubscript="true"
:subscriptSize="32"
:first-size="56"
:second-size="40"
:price="item.money"
/>
</view>
<view class="ml20 mr20">
<view class="bold md lighter">{{ item.name }}</view>
<view class="xs muted mt10">{{ item.use_goods_type }}</view>
</view>
</view>
</view>
</scroll-view>
</view>
<view class="white row-center bg-primary lg btn br60" @click="showCoupop = false"
>立即领取</view
>
</u-popup>
<!-- #ifdef APP-PLUS -->
<lyg-popup
v-if="appConfig.app_agreement"
title="用户使用及隐私保护政策提示"
protocolPath="/bundle/pages/server_explan/server_explan?type=0"
policyPath="/bundle/pages/server_explan/server_explan?type=1"
policyStorageKey="has_read_privacy"
>
</lyg-popup>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<!-- 用户隐私协议弹框 -->
<privacy-popup v-model="showPrivacyPopup"></privacy-popup>
<!-- #endif -->
<!-- 无网络提示 -->
<u-no-network z-index="1200" @retry="handleRetry"></u-no-network>
<u-back-top
:scroll-top="scrollTop"
:top="1000"
:customStyle="{
backgroundColor: '#FFF',
color: '#000',
boxShadow: '0px 3px 6px rgba(0, 0, 0, 0.1)'
}"
></u-back-top>
</view>
</template>
<script>
import { mapMutations, mapGetters, mapActions } from 'vuex'
import { getHome, getMenu, getBestList } from '@/api/store'
import { loadingType } from '@/utils/type'
import { loadingFun, menuJump, arraySlice, setTabbar, getRect, trottle } from '@/utils/tools'
import { toLogin } from '@/utils/login'
import Cache from '@/utils/cache'
import { getConfig, userShare, getRegisterCoupon } from '@/api/app'
const app = getApp()
export default {
data() {
return {
scrollTop: 0,
navSwiperH: 374,
logo: '',
navHeight: 0,
currentSwiper: 0,
page: 1,
status: loadingType.LOADING,
remainTime: '',
navBg: 0,
navList: [],
news: [],
goodsList: [],
seckill: {},
seckillGoods: [],
hotGoods: [],
newGoods: [],
activityArea: [],
showCoupop: false,
couponPopList: [],
coupon: [],
isDischarge: true,
enable: true,
isShowDownload: false,
showPrivacyPopup: false //微信用户隐私协议
}
},
async onLoad(options) {
// #ifdef MP-WEIXIN
if (wx.getPrivacySetting) {
wx.getPrivacySetting({
success: (res) => {
console.log(res, '------') // 返回结果为: res = { needAuthorization: true/false, privacyContractName: '《xxx隐私保护指引》' }
if (res.needAuthorization) {
// 需要弹出隐私协议
setTimeout(() => {
uni.hideTabBar()
}, 100)
this.showPrivacyPopup = true
} else {
uni.showTabBar()
}
},
fail: (err) => {
uni.showTabBar()
console.log(err)
}
})
} else {
uni.showTabBar()
}
// #endif
this.headerAction = wx.createAnimation({
delay: 0,
duration: 100,
timingFunction: 'ease-in-out'
})
this.onPageScroll = trottle(this.onPageScroll, 500, this)
setTabbar()
this.navHeight = app.globalData.navHeight
this.isDischarge = false
await this.getMenuFun()
this.getBestListFun()
console.log(this.appConfig)
// #ifdef H5
if (options && options.isapp == 1) {
this.isShowDownload = true
}
// #endif
},
async onShow() {
this.$nextTick(function () {
getRect('.index').then((res) => {
if (res.top == 0) {
this.navBg = 0
}
})
})
// #ifdef H5
this.enable = true
// #endif
await this.getHomeFun()
this.getCartNum()
this.isLogin && this.getRegisterCouponFun()
// #ifdef MP
wx.getUpdateManager().onUpdateReady(function () {
wx.showModal({
title: '更新提示',
content: '新版本已经准备好,是否重启应用?',
success(res) {
if (res.confirm) {
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
wx.getUpdateManager().applyUpdate()
}
}
})
})
// #endif
},
onHide() {
// #ifdef H5
this.enable = false
// #endif
},
onReachBottom() {
this.getBestListFun()
},
onPullDownRefresh() {
this.getHomeFun()
this.getMenuFun()
},
onShareAppMessage() {
console.log(this.inviteCode)
const shareInfo = Cache.get('shareInfo')
return {
title: shareInfo.mnp_share_title,
path: 'pages/index/index?invite_code=' + this.inviteCode,
imageUrl: shareInfo.mnp_share_image
}
},
onPageScroll(e) {
const top = uni.upx2px(100)
const { scrollTop } = e
if (!this.enable) return
let percent = scrollTop / top
this.navBg = percent > 1 ? 1 : percent
this.scrollTop = scrollTop
},
destroyed() {
this.isDischarge = true
},
methods: {
...mapMutations(['SETCONFIG']),
...mapActions(['getCartNum', 'getUser']),
// 网络重试刷新网络请求(解决在ios中首次进入时需要授权蜂窝加载空白页面问题
async handleRetry() {
console.log('网络重试刷')
try {
const { code, data } = await getConfig()
if (code == 1) {
this.SETCONFIG(data)
setTabbar()
}
} catch (e) {
uni.showTabBar()
}
this.getShareInfo()
this.getUser()
},
async getShareInfo() {
const { code, data } = await userShare()
if (code == 1) {
Cache.set('shareInfo', data)
}
},
async getHomeFun() {
const { code, data } = await getHome()
uni.stopPullDownRefresh()
if (code == 1) {
const { coupon, news, seckill, host_goods, shop_logo, new_goods, activity_area } =
data
this.remainTime = Math.abs(seckill.end_time - Date.parse(new Date()) / 1000)
this.logo = shop_logo
this.news = news
this.seckillGoods = seckill.goods
this.seckill = seckill
this.hotGoods = host_goods
this.coupon = coupon
this.newGoods = new_goods
this.activityArea = activity_area
}
},
async getMenuFun() {
const { code, data } = await getMenu({
type: 1
})
uni.stopPullDownRefresh()
if (code == 1) {
// 截取数组
if (data.length <= 5) {
this.navSwiperH = 200
} else {
this.navSwiperH = 374
}
this.navList = arraySlice(data)
}
},
async getBestListFun() {
let { page, goodsList, status } = this
const data = await loadingFun(getBestList, page, goodsList, status)
if (!data) return
this.page = data.page
this.goodsList = data.dataList
this.status = data.status
},
async tapMenu(item) {
if (!this.isLogin) return toLogin()
menuJump(item)
},
goPage(url) {
if (!this.isLogin) return toLogin()
uni.navigateTo({
url
})
},
swiperChange(e) {
this.currentSwiper = e.detail.current
},
getRegisterCouponFun() {
getRegisterCoupon().then((res) => {
if (res.code == 1) {
if (res.data && res.data.length) {
this.showCoupop = true
}
this.couponPopList = res.data
}
})
}
},
computed: {
...mapGetters(['cartNum', 'inviteCode', 'appConfig']),
navBackground() {
return this.seting.top_bg_image
? {
'background-image': `url(${this.seting.top_bg_image})`
}
: {}
},
showLogo() {
return this.seting.logo
},
navSearch() {
if (this.showLogo === 0) return true
return this.navBg < 1 ? false : true
},
seting() {
const { index_setting } = this.appConfig
return index_setting
}
}
}
</script>
<style lang="scss">
// #ifdef H5
::v-deep .home-bg {
background: url(../../static/images/bg_hometop.png) no-repeat;
background-size: 100% auto;
}
// #endif
.home-bg {
background: url(../../static/images/bg_hometop.png) no-repeat;
background-size: 100% auto;
}
.index {
.live-play {
position: fixed;
z-index: 999;
bottom: 200rpx;
right: 20rpx;
display: flex;
align-items: center;
justify-content: center;
width: 80rpx;
height: 80rpx;
border: $-solid-border;
border-radius: 50%;
font-size: 32rpx;
background-color: #ffffff;
&__icon {
animation: scale 0.5s infinite;
}
@keyframes scale {
from {
top: 0px;
transform: scale(1);
}
to {
transform: scale(1.2);
}
}
}
background-size: 100% auto;
.logo-wrap {
position: absolute;
.logo {
width: auto;
height: 52rpx;
}
}
.header {
.navigation-bar {
padding-top: var(--status-bar-height);
box-sizing: border-box;
}
}
.contain {
.main {
position: relative;
z-index: 9;
padding: 0 20rpx;
.nav {
position: relative;
border-radius: 14rpx;
.nav-item {
width: 20%;
margin-top: 30rpx;
.nav-icon {
width: 82rpx;
height: 82rpx;
margin-bottom: 15rpx;
}
}
.dots {
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 20rpx;
display: flex;
.dot {
width: 10rpx;
height: 6rpx;
border-radius: 6rpx;
margin-right: 10rpx;
background-color: rgba(255, 44, 60, 0.4);
&.active {
width: 20rpx;
background-color: $-color-primary;
}
}
}
}
.information {
height: 76rpx;
box-shadow: 0px 0px 14px rgba(0, 0, 0, 0.06);
padding: 0 20rpx;
box-sizing: border-box;
border-radius: 14rpx;
.news {
position: relative;
.shade {
position: absolute;
width: 100%;
height: 100%;
z-index: 100;
}
}
.icon-toutiao {
width: 114rpx;
height: 34rpx;
}
.gap-line {
height: 28rpx;
width: 1px;
background-color: #dcdddc;
margin: 0 30rpx;
}
}
.special-area {
.item {
width: 300rpx;
border-radius: 20rpx;
display: inline-block;
overflow: hidden;
margin-right: 20rpx;
.title {
padding: 10rpx 0;
}
.desc {
background-color: #fee9eb;
padding: 6rpx 20rpx;
border-radius: 60rpx;
max-width: 260rpx;
}
}
}
.activity-header {
height: 90rpx;
padding: 0 20rpx;
}
.seckill {
.dec {
background-color: #fffbdb;
width: 150rpx;
}
}
.hot,
.new-goods {
.title-image {
width: 144rpx;
height: 55rpx;
}
}
}
.goods {
.goods-title {
height: 100rpx;
.line {
width: 58rpx;
height: 1px;
background-color: #ccc;
margin: 0 22rpx;
}
.icon {
width: 38rpx;
height: 38rpx;
}
}
}
}
.coupon-pop-container {
background-image: url(../../static/images/home_coupon_bg.png);
width: 638rpx;
height: 804rpx;
background-size: 100% 100%;
padding-top: 323rpx;
.coupon-pop-lists {
.coupon-pop-item {
background-image: url(../../static/images/pop_bg_coupon.png);
width: 488rpx;
height: 150rpx;
background-size: 100% 100%;
margin-top: 20rpx;
.coupon-left {
width: 160rpx;
height: 100%;
}
.coupon-right {
padding-left: 30rpx;
border-left: 1rpx dashed $-color-primary;
}
}
}
}
.coupons-popup {
.wrap {
position: relative;
width: 638rpx;
height: 803rpx;
overflow: hidden;
.coupon-bg {
position: absolute;
top: 0;
width: 100%;
height: 100%;
}
.item {
position: relative;
width: 488rpx;
height: 150rpx;
margin: 0 auto 20rpx;
}
.img {
position: absolute;
width: 100%;
height: 100%;
z-index: 0;
}
.item-con {
z-index: 10;
position: relative;
padding: 20rpx 0;
height: 100%;
box-sizing: border-box;
.price {
width: 160rpx;
border-right: 1px dashed $-color-primary;
height: 100%;
}
}
}
.btn {
width: 478rpx;
height: 84rpx;
margin: 20rpx auto;
box-sizing: border-box;
border: 3px solid #f8d07c;
}
}
}
</style>
File diff suppressed because one or more lines are too long
+117
View File
@@ -0,0 +1,117 @@
<template>
<view>
<!-- pages/news_details/news_details.wxml -->
<view class="news-details">
<view class="header">
<view class="title xxl mb20">{{ articleDetail.title }}</view>
<view class="row-between">
<view class="xs lighter">发布时间{{ articleDetail.create_time }}</view>
<view class="row">
<view class="ml10 xs muted">{{ articleDetail.visit }}人浏览</view>
</view>
</view>
</view>
<view class="main">
<u-parse :html="article_content" :tag-style="tagStyle" />
</view>
</view>
<loading-view v-if="showLoading"></loading-view>
<!--<import src="/wxParse/wxParse.wxml"></import>-->
</view>
</template>
<script>
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
import { getArticleDetail } from '../../api/new';
export default {
data() {
return {
showLoading: true,
articleDetail: {},
article_content: "",
tagStyle: {
img: 'width:100%;'
}
};
},
components: {
},
props: {},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.type = options.type || '';
this.id = options.id;
if (this.type) {
uni.setNavigationBarTitle({
title: '帮助详情'
});
} else {
uni.setNavigationBarTitle({
title: '资讯详情'
});
}
this.getArticleDetailFun();
},
methods: {
getArticleDetailFun() {
getArticleDetail({
type: this.type,
id: this.id
}).then(res => {
if (res.code == 1) {
this.articleDetail = res.data
//wxParse.wxParse('content', 'html', res.data.content, this, 15)
setTimeout(() => {
this.article_content = res.data.content;
}, 200);
setTimeout(() => {
this.showLoading = false
}, 300);
}
});
}
}
};
</script>
<style>
/* pages/news_details/news_details.wxss */
page {
background-color: #fff;
}
.news-details .header{
padding: 20rpx 15px;
border-bottom: var(--border);
}
.news-details .main {
padding: 40rpx 15px;
}
.wxParse-p image {
width: 100%;
}
</style>
+212
View File
@@ -0,0 +1,212 @@
<template>
<view>
<!-- pages/news_list/news_list.wxml -->
<view class="news_list">
<view class="contain">
<view class="banner" v-if="showAd">
<!-- 存在就是10 不存在为7 -->
<swipers :pid="type ? 10 : 7" height="300rpx" radius="0rpx"></swipers>
</view>
<tabs :active="active" @change="changeActive" v-if="categoryList.length">
<tab title="全部"></tab>
<tab v-for="(item, index) in categoryList" :key="index" :title="item.name" ></tab>
</tabs>
<view class="main">
<view class="article-list">
<view v-for="(item, index) in newsList" :key="index" :data-id="item.id" class="article-item bg-white" @tap="goPage">
<view class="row">
<view class="info">
<view class="title lg line2 mb20">{{ item.title }}</view>
<view class="lighter line2">
<view>{{ item.synopsis }}</view>
</view>
</view>
<image width="240rpx" height="180rpx" lazy-load class="img ml20" :src="item.image" />
</view>
<view class="row-between mt20">
<view class="xs muted">发布时间: {{item.create_time}}</view>
<view class="row">
<!-- <image class="icon-sm" src="/static/images/icon_see.png"></image> -->
<view class="ml10 xs muted">{{ item.visit }}人浏览</view>
</view>
</view>
</view>
</view>
<loading-footer :status="status" slotEmpty>
<view slot="empty" class="column-center" style="padding-top: 100rpx">
<image class="img-null" src="/static/images/news_null.png"></image>
<text class="nr muted">暂无数据</text>
</view>
</loading-footer>
</view>
</view>
</view>
<!-- <loading-view v-if="showLoading"></loading-view> -->
</view>
</template>
<script>
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
import { getCategoryList, getArticleList } from '@/api/new';
import { loadingType } from '@/utils/type';
import {loadingFun} from '@/utils/tools'
export default {
data() {
return {
active: 0,
showLoading: true,
categoryList: [],
newsList: [],
page: 1,
status: loadingType.LOADING,
bannerList: [],
type: 0,
showAd: false
};
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
//分类id
this.id = options.id; //type存在则为帮助中心
this.type = options.type || '';
if (this.type) {
uni.setNavigationBarTitle({
title: '帮助中心'
});
} else {
uni.setNavigationBarTitle({
title: '商城资讯'
});
}
this.showAd = true
this.getCategoryListFun();
},
onReachBottom: function () {
this.getArticleListFun();
},
methods: {
changeActive(e) {
this.active = e;
this.page = 1;
this.newsList = [];
this.status = loadingType.LOADING
setTimeout(() => {
this.getArticleListFun();
}, 100);
},
getCategoryListFun() {
getCategoryList({
type: this.type
}).then(res => {
if (res.code == 1) {
this.categoryList = res.data
console.log(this.categoryList)
this.getArticleListFun();
}
});
},
getArticleListFun() {
let {
active,
page,
newsList,
status
} = this;
// active是选中的分类索引,索引0是全部,索引1开始才是的分类列表的数据
let id = active ? this.categoryList[active - 1].id : '';
loadingFun(getArticleList, page, newsList, status, {
type: this.type,
id,
page_no: page}).then(res => {
if(res) {
this.page = res.page;
this.newsList = res.dataList
this.status = res.status
}
})
},
goPage(e) {
let {
id
} = e.currentTarget.dataset;
uni.navigateTo({
url: `/pages/news_details/news_details?id=${id}&type=${this.type}`
});
}
}
};
</script>
<style lang="scss">
/* pages/information/information.wxss */
.news_list {
.banner {
}
.main {
.article-list {
padding-top: 20rpx;
.article-item {
padding: 20rpx;
border-bottom: var(--border);
align-items: flex-start;
.info {
flex: 1;
}
.img {
width: 240rpx;
height: 180rpx;
flex: none;
}
}
&:last-of-type {
border: none;
}
}
}
.footer {
padding: 30rpx 0;
}
}
page .van-tabs .van-tab--active {
color: #333;
}
.news_list .van-tab {
width: 25%;
flex: none;
}
</style>
+788
View File
@@ -0,0 +1,788 @@
// +---------------------------------------------------------------------- // |
likeshop开源商城系统 //
+---------------------------------------------------------------------- // |
欢迎阅读学习系统程序代码建议反馈是我们前进的动力 // |
gitee下载https://gitee.com/likeshop_gitee // |
github下载https://github.com/likeshop-github // |
访问官网https://www.likeshop.cn // | 访问社区:https://home.likeshop.cn // |
访问手册http://doc.likeshop.cn // | 微信公众号:likeshop技术社区 // |
likeshop系列产品在giteegithub等公开渠道开源版本可免费商用未经许可不能去除前后端官方版权标识
// |
likeshop系列产品收费版本务必购买商业授权购买去版权授权后方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布 // |
likeshop团队版权所有并拥有最终解释权 //
+---------------------------------------------------------------------- // |
author: likeshop.cn.team //
+----------------------------------------------------------------------
<template>
<view>
<navbar title="订单详情"></navbar>
<view class="order-details">
<view class="header-bg"></view>
<view class="main">
<view class="header">
<view class="item" v-if="orderDetail.order_status == 0">
<view class="white lg mb10">等待买家付款</view>
<view
class="white sm row"
style="line-height: 26rpx"
v-if="cancelTime > 0"
>支付剩余
<u-count-down
separator="zh"
:timestamp="cancelTime"
separator-color="#fff"
color="#fff"
:separator-size="26"
:font-size="26"
bg-color="transparent"
></u-count-down>
自动关闭</view
>
</view>
<template v-if="orderDetail.delivery_type == 1">
<view class="item" v-if="orderDetail.order_status == 1">
<view class="white lg mb10">等待商家发货</view>
<view class="white sm">您的商品正在打包中请耐心等待</view>
</view>
<view class="item" v-if="orderDetail.order_status == 2">
<view class="white lg mb10">已发货</view>
<view class="white sm">您的商品正在路中请耐心等待</view>
</view>
<view class="item" v-if="orderDetail.order_status == 3">
<view class="white lg mb10">已完成</view>
<view class="white sm">商品已签收期待再次购买</view>
</view>
<view class="item" v-if="orderDetail.order_status == 4">
<view class="white lg mb10">订单已关闭</view>
<!-- <view class="white sm">原因超时未支付</view> -->
</view>
</template>
<template v-if="orderDetail.delivery_type == 2">
<view class="item" v-if="orderDetail.order_status == 1">
<view class="white lg mb10">待取货</view>
<view class="white sm">请前往指定门店取货</view>
</view>
<view class="item" v-if="orderDetail.order_status == 3">
<view class="white lg mb10">已完成</view>
<view class="white sm">交易已完成感谢您的购买</view>
</view>
<view class="item" v-if="orderDetail.order_status == 4">
<view class="white lg mb10">订单已关闭</view>
</view>
</template>
</view>
<!-- 快递配送 -->
<view
v-if="orderDetail.delivery_type == 1"
class="receiving-card contain"
@click="onAddressExpress"
>
<u-image
class="icon-md mr20"
width="44"
height="44"
src="/static/images/icon_address.png"
mode="scaleToFill"
/>
<view class="receiving-content">
<view class="md black bold">
<text>{{ orderDetail.consignee }}</text>
<text class="ml10">{{ orderDetail.mobile }}</text>
</view>
<view class="xs black mt10">{{
orderDetail.delivery_address
}}</view>
</view>
</view>
<!-- 门店自提 -->
<view
v-if="orderDetail.delivery_type == 2"
class="receiving-card contain"
>
<u-image
class="icon-md mr20"
width="44"
height="44"
src="/static/images/icon_address.png"
mode="scaleToFill"
/>
<view class="receiving-content">
<text class="md black bold">{{
orderDetail.selffetch_shop.name
}}</text>
<text class="xs black mt10">{{
orderDetail.selffetch_shop.shop_address
}}</text>
<text class="xs muted mt10">
<text>营业时间</text>
<text
>{{ orderDetail.selffetch_shop.business_start_time }} -
{{ orderDetail.selffetch_shop.business_end_time }}</text
>
</text>
</view>
</view>
<!-- 扫码收货 -->
<view v-if="orderDetail.delivery_type == 2" class="contain receive">
<view v-if="orderDetail.verification_status" class="delivery--die">
<u-image
src="/static/images/delivery_die.png"
width="134"
height="98"
mode="scaleFill"
/>
</view>
<view class="receive-qr" v-if="showQRSelffetch">
<text class="xs lighter">请凭二维码取货</text>
<view
class="mt20 qr-contain"
:class="{ 'qr-contain--die': orderDetail.verification_status }"
ref="qr-image"
>
<tki-qrcode
ref="qrcode"
uni="px"
:val="orderDetail.pickup_code"
:size="118 * 2"
:showLoading="false"
/>
</view>
<view class="mt30 xs black qr-code"
>提货码{{ orderDetail.pickup_code }}</view
>
</view>
<view class="nr receive-info">
<view class="receive-info-item">
<text class="normal">提货人</text>
<text class="black">{{ orderDetail.consignee }}</text>
</view>
<view class="receive-info-item">
<text class="normal">联系方式</text>
<text class="black">{{ orderDetail.mobile }}</text>
</view>
</view>
</view>
<view class="goods contain" style="margin-bottom: 0">
<view class="status row-between" v-if="team.status != null">
<view>拼团状态</view>
<view
:style="
'padding: 6rpx 26rpx; ' +
(team.status == 2 && 'background-color: #d7d7d7')
"
class="bg-primary br60 white sm"
>
{{ teamStatus(team.status) }}
</view>
</view>
<order-goods
:team="team"
:link="true"
:list="orderDetail.order_goods"
:order_type="orderDetail.order_type"
></order-goods>
</view>
<view class="price contain" style="border-radius: 0rpx 14rpx">
<view class="row-between" v-if="priceShow">
<view>商品总价</view>
<view class="black">
<price-format :price="orderDetail.goods_price"></price-format>
</view>
</view>
<view class="row-between" v-if="priceShow">
<view>运费</view>
<view class="black"
>+
<price-format :price="orderDetail.shipping_price"></price-format>
</view>
</view>
<view
v-if="orderDetail.discount_amount != 0 && priceShow"
class="row-between"
>
<view>优惠券</view>
<view class="primary"
>-
<price-format :price="orderDetail.discount_amount"></price-format>
</view>
</view>
<view
v-if="orderDetail.integral_amount != 0 && priceShow"
class="row-between"
>
<view>积分抵扣</view>
<view class="primary"
>-
<price-format :price="orderDetail.integral_amount"></price-format>
</view>
</view>
<view class="row-between">
<view class="">
<text v-if="orderDetail.order_status === 0"></text>
<text v-else></text>
付款
</view>
<view class="primary xl">
<price-format
:first-size="34"
:second-size="34"
:price="orderDetail.order_amount"
>
</price-format>
</view>
</view>
<view
class="row-center muted"
style="padding: 40rpx 0"
@click="priceShow = !priceShow"
>
<view>
<text class="mr10" v-if="priceShow"> 收起 </text>
<text class="mr10" v-else> 查看更多 </text>
<u-icon name="arrow-up" v-if="priceShow" />
<u-icon name="arrow-down" v-else />
</view>
</view>
</view>
<view class="order-info contain">
<view class="item row" style="align-items: flex-start">
<view class="title">买家留言</view>
<view class="black">{{ orderDetail.user_remark || "无" }}</view>
</view>
</view>
<view class="order-info contain">
<view class="item row">
<view class="title">订单编号</view>
<view class="black">{{ orderDetail.order_sn }}</view>
</view>
<view class="item row">
<view class="title">订单类型</view>
<view class="black">{{ orderDetail.order_type_desc }}</view>
</view>
<view class="item row">
<view class="title">支付方式</view>
<view class="black">{{ orderDetail.pay_way_text }}</view>
</view>
<view class="item row">
<view class="title">下单时间</view>
<view class="black">{{ orderDetail.create_time }}</view>
</view>
<view v-if="orderDetail.pay_time" class="item row">
<view class="title">付款时间</view>
<view class="black">{{ orderDetail.pay_time }}</view>
</view>
<view v-if="orderDetail.shipping_time" class="item row">
<view class="title">发货时间</view>
<view class="black">{{ orderDetail.shipping_time }}</view>
</view>
<view v-if="orderDetail.confirm_take_time" class="item row">
<view class="title">成交时间</view>
<view class="black">{{ orderDetail.confirm_take_time }}</view>
</view>
<view v-if="orderDetail.cancel_time" class="item row">
<view class="title">关闭时间</view>
<view class="black">{{ orderDetail.cancel_time }}</view>
</view>
</view>
<view
class="footer bg-white row fixed"
v-if="
orderDetail.cancel_btn ||
orderDetail.delivery_btn ||
orderDetail.take_btn ||
orderDetail.del_btn ||
orderDetail.pay_btn
"
>
<view style="flex: 1"></view>
<view v-if="orderDetail.cancel_btn">
<button
size="sm"
class="plain br60"
hover-class="none"
@tap="cancelOrder"
>
取消订单
</button>
</view>
<navigator
v-if="orderDetail.delivery_btn"
hover-class="none"
:url="
'/bundle/pages/goods_logistics/goods_logistics?id=' +
orderDetail.id
"
>
<button size="sm" class="plain br60" hover-class="none">
查看物流
</button>
</navigator>
<view v-if="orderDetail.take_btn" class="ml20">
<button
size="sm"
class="plain br60 primary red"
hover-class="none"
@tap.stop="comfirmOrder"
>
确认收货
</button>
</view>
<view v-if="orderDetail.del_btn">
<button
size="sm"
class="plain br60"
hover-class="none"
@tap="delOrder"
>
删除订单
</button>
</view>
<view class="ml20" v-if="orderDetail.pay_btn">
<button size="sm" class="bg-primary br60 white" @tap="payNow">
立即付款
</button>
</view>
</view>
</view>
</view>
<loading-view v-if="isFirstLoading"></loading-view>
<order-dialog
ref="orderDialog"
:orderId="orderDetail.id"
:type="type"
@refresh="onRefresh"
></order-dialog>
<loading-view
v-if="showLoading"
background-color="transparent"
:size="50"
></loading-view>
</view>
</template>
<script>
import {
getOrderDetail,
getwechatSyncCheck,
getwxReceiveDetail,
confirmOrder,
} from "@/api/order";
import { compareWeChatVersion } from "@/utils/tools";
import { prepay } from "@/api/app";
import { wxpay, alipay } from "@/utils/pay";
export default {
data() {
return {
orderDetail: {},
team: {},
isFirstLoading: true,
type: 0,
cancelTime: 0,
showCancel: "",
showLoading: false,
imageQR: "",
priceShow: false,
};
},
components: {},
props: {},
onLoad: function (options) {
this.id = options.id;
this.getOrderDetailFun();
},
onUnload() {
uni.$off("payment");
},
onShow() {
this.getOrderDetailFun();
},
methods: {
onRefresh() {
uni.$emit("refreshorder");
const { type } = this;
if ([0, 2].includes(type)) {
this.getOrderDetailFun();
} else if (type == 1) {
setTimeout(() => {
uni.navigateBack();
}, 2000);
}
},
orderDialog() {
this.$refs.orderDialog.open();
},
delOrder() {
this.type = 1;
this.$nextTick(async () => {
this.orderDialog();
});
},
// 小程序确认收货
comfirmReceive(transaction_id) {
return new Promise((resolve, reject) => {
wx.openBusinessView({
businessType: "weappOrderConfirm",
extraData: {
transaction_id,
},
success({ extraData }) {
if (extraData.status == "success") {
resolve("确认收货");
} else {
resolve("取消收货");
}
},
fail(err) {
reject(err);
},
});
});
},
//查询是否收货成功
querycomfirmReceive(id) {
return new Promise((resolve, reject) => {
getwechatSyncCheck({ id })
.then(({ data }) => {
if (data.order.order_state === 4) {
resolve("已确认收货");
} else {
reject("未确认收货");
}
})
.catch((err) => {
reject(err);
});
});
},
comfirmOrder() {
this.type = 2;
this.$nextTick(async () => {
// #ifdef MP-WEIXIN
let res = {};
if (this.orderDetail.pay_way === 1) {
res = await getwechatSyncCheck({ id: this.id });
console.log(res);
}
if (
compareWeChatVersion("2.6.0") === 1 &&
wx.openBusinessView &&
this.orderDetail.pay_way === 1 &&
res.data.order.order_state !== 1
) {
try {
const { data } = await getwxReceiveDetail({
order_id: this.id,
});
await this.comfirmReceive(data.transaction_id);
await this.querycomfirmReceive(this.id);
await confirmOrder(this.id);
} catch (error) {
console.log(error);
}
this.getOrderDetailFun();
} else {
this.orderDialog();
}
// #endif
// #ifndef MP-WEIXIN
this.orderDialog();
// #endif
});
},
cancelOrder() {
this.type = 0;
this.$nextTick(() => {
this.orderDialog();
});
},
payNow() {
uni.$on("payment", (params) => {
setTimeout(() => {
if (params.result) {
this.$toast({
title: "支付成功",
});
this.getOrderDetailFun();
uni.$emit("refreshorder");
} else {
this.$toast({
title: "支付失败",
});
}
}, 500);
});
uni.navigateTo({
url: `/pages/payment/payment?from=${"order"}&order_id=${this.id}`,
});
},
getOrderDetailFun() {
getOrderDetail(this.id)
.then((res) => {
if (res.code == 1) {
this.cancelTime = res.data.order_cancel_time - Date.now() / 1000;
this.orderDetail = res.data;
this.team = res.data.team || {};
this.$nextTick(() => {
this.isFirstLoading = false;
});
} else {
setTimeout(() => uni.navigateBack(), 1500);
}
return res.data;
})
.then((data) => {
if (data.delivery_type === 2) {
// 提货码
this.$nextTick(function () {
const refQR = this.$refs["qrcode"];
refQR._makeCode();
});
}
});
},
},
computed: {
showQRSelffetch() {
let result = false;
if (this.orderDetail.order_status) {
result = true;
}
if (this.orderDetail.order_type == 2) {
this.orderDetail.team_status == 1 ? (result = true) : (result = false);
}
return result;
},
teamStatus() {
return (status) => {
switch (status) {
case 0:
return "拼团中";
case 1:
return "拼团成功";
case 2:
return "拼团失败";
}
};
},
getOrderType() {
return (type) => {
switch (type) {
case 0:
return "普通订单";
case 1:
return "秒杀订单";
case 2:
return "拼团订单";
case 3:
return "砍价订单";
}
};
},
},
};
</script>
<style lang="scss">
.order-details {
position: relative;
padding-bottom: calc(120rpx + env(safe-area-inset-bottom));
}
.order-details .header-bg {
position: absolute;
top: 0;
width: 100%;
height: 200rpx;
background-color: $-color-primary;
z-index: 0;
}
.order-details .goods .status {
height: 88rpx;
padding: 0 20rpx;
}
.order-details .main {
position: relative;
z-index: 1;
}
.order-details .contain {
margin: 0 20rpx 20rpx;
border-radius: 14rpx;
background-color: #fff;
}
.order-details .header {
padding: 24rpx 40rpx;
box-sizing: border-box;
}
.order-details .img-line {
height: 1.5px;
width: 100%;
display: block;
}
.order-details .address-wrap {
height: 164rpx;
padding: 0 24rpx;
}
.order-details .order-info {
padding: 12rpx 0;
}
.order-details .order-info .item {
padding: 12rpx 24rpx;
}
.order-details .order-info .item .title {
width: 180rpx;
flex: none;
}
.order-details .price > view {
height: 60rpx;
padding: 0 24rpx;
}
.order-details .footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 100rpx;
padding: 0 24rpx;
box-sizing: content-box;
padding-bottom: env(safe-area-inset-bottom);
}
.footer .plain {
border: 1px solid #bbbbbb;
}
.footer .plain.red {
border: 1px solid $-color-primary;
}
.tips-dialog {
height: 230rpx;
width: 100%;
}
.order-details .invite-btn {
background: linear-gradient(270deg, #ff2c3c 0%, #f95f2f 100%);
margin: 30rpx 26rpx 40rpx;
}
.receiving-card {
display: flex;
align-items: center;
min-height: 160rpx;
padding: 20rpx;
border-top: 1px solid #f2f2f2;
}
.receiving-content {
flex: 1;
display: flex;
flex-direction: column;
}
.receive {
position: relative;
}
.delivery--die {
position: absolute;
top: 0;
right: 30rpx;
}
.receive-qr {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 460rpx;
}
.qr-contain {
box-sizing: border-box;
display: flex;
justify-content: center;
align-items: center;
width: 140px;
height: 140px;
padding: 8px;
border: 1px solid #cccccc;
border-radius: 5px;
}
.qr-contain--die {
position: relative;
}
.qr-contain--die::before {
position: absolute;
z-index: 99;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: block;
content: "";
background-color: rgba(255, 255, 255, 0.5);
}
.qr-code {
padding: 8rpx 30rpx;
border-radius: 60px;
background-color: #f6f6f6;
}
.receive-info {
padding-left: 20rpx;
}
.receive-info-item {
display: flex;
justify-content: space-between;
align-items: center;
height: 100rpx;
padding-right: 30rpx;
}
.receive-info-item:nth-child(n + 2) {
border-top: $-dashed-border;
}
</style>
+160
View File
@@ -0,0 +1,160 @@
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
<template>
<view class="pay-result column-center">
<view class="contain bg-white">
<view class="header column-center">
<view>
<image class="tips-icon" src="/static/images/icon_paySuccess.png"></image>
</view>
<view class="xl mt20">订单支付成功</view>
</view>
<view style="height:181rpx"></view>
<view class="info">
<view class="order-num row-between mt20">
<view class="ml20">订单编号</view>
<view class="mr20">
{{payInfo.order_sn}}
</view>
</view>
<view v-if="payInfo.pay_time" class="order-time row-between mt20">
<view class="ml20">付款时间</view>
<view class="mr20">{{payInfo.pay_time}}</view>
</view>
<view class="order-pay-type row-between mt20">
<view class="ml20">支付方式</view>
<view class="mr20">{{payInfo.pay_way_text}}</view>
</view>
<view class="order-pay-money row-between mt20">
<view class="ml20">支付金额</view>
<view class="mr20">
<price-format :price="payInfo.order_amount"></price-format>
</view>
</view>
</view>
<view class="line ml20"></view>
<view class="opt-btn-contain row-center wrap">
<navigator open-type="redirect" hover-class="none" class="check-order-btn row-center bg-primary br60 mt20" url="/pages/user_order/user_order">
<view class="white bg-primary lg">查看订单</view>
</navigator>
<navigator hover-class="none" class="go-back-btn row-center br60 mt20" open-type="switchTab" url="/pages/index/index">
<view class="primary br60 lg">返回首页</view>
</navigator>
</view>
</view>
<view class="xs muted" style="margin: 50rpx 0;">
<view class="row-center">
likeshop 提供免费开源商城系统
</view>
<view class="row-center">
© likeshop.cn
</view>
</view>
</view>
</template>
<script>
import {
getOrderDetail
} from '@/api/order';
export default {
data() {
return {
payInfo: {}
};
},
components: {
},
props: {},
onLoad: function(options) {
this.id = options.id;
this.getOrderResultFun();
},
methods: {
getOrderResultFun() {
getOrderDetail(this.id).then(res => {
if (res.code == 1) {
this.payInfo = res.data
}
});
},
}
};
</script>
<style lang="scss">
.pay-result {
.contain {
width: 682rpx;
margin-left: 20rpx;
margin-right: 20rpx;
border-radius: 10rpx;
margin-top: 78rpx;
padding-left: 20rpx;
padding-right: 20rpx;
padding-bottom: 40rpx;
position: relative;
.tips-icon {
width: 112rpx;
height: 112rpx;
}
.header {
position: absolute;
left: 50%;
transform: translateX(-50%);
top: -50rpx;
}
.order-num {
align-items: flex-start;
}
.info {
margin-bottom: 40rpx;
}
.opt-btn-contain {
margin-top: 40rpx;
.check-order-btn {
width: 650rpx;
height: 84rpx;
}
.go-back-btn {
width: 650rpx;
height: 84rpx;
border:1px solid $-color-primary;
box-sizing: border-box;
}
}
.line {
width: 650rpx;
border-top: 1px solid rgba(229, 229, 229, 1);
}
}
}
</style>
+340
View File
@@ -0,0 +1,340 @@
<template>
<view class="payment-pages">
<view class="payment u-skeleton">
<!-- Header -->
<view class="payment-header">
<price-format class="u-skeleton-fillet" :subscript-size="40" :first-size="56" :second-size="40"
:price="amount" :weight="500" />
<template v-if="timeout > 0">
<view class="payment-count-down">
<text>支付剩余时间</text>
<u-count-down :timestamp="timeout" :font-size="22" />
</view>
</template>
</view>
<!-- Main -->
<view class="payment-main">
<view class="payway-container u-skeleton-fillet">
<!-- Payway -->
<u-radio-group v-model="payway" style="width: 100%;">
<view class="payway">
<view class="payway-item" v-for="(item, index) in paywayList" :key="item.id"
@click="changePayway(item.pay_way)">
<u-image :src="item.icon" width="48" height="48" mode="scaleToFill" />
<view class="payway-item-content">
<text class="payway-item-content-name">{{ item.name }}</text>
<text class="payway-item-content-tips">{{ item.extra }}</text>
</view>
<u-radio shape="circle" :name="item.pay_way" :active-color="primaryColor" />
</view>
</view>
</u-radio-group>
<template v-if="!paywayList.length">
<view class="payway-empty">暂无支付方式</view>
</template>
</view>
</view>
<!-- Footer -->
<view class="payment-footer u-skeleton-fillet">
<view :class="['payment-submit', {'payment-submit--disabled': loadingPay}]" @tap="handlePrepay">
<u-loading mode="circle" :show="loadingPay" />
<text v-show="!loadingPay">立即支付</text>
</view>
</view>
</view>
<u-skeleton :loading="loadingSkeleton" :animation="true" bgColor="#FFF" />
</view>
</template>
<script>
/**
* @description 支付页面
* @query {String} from 订单来源: order-商品订单; recharge-充值订单;
* @query {Number} order_id 订单ID
*/
import {
prepay,
getPayway
} from '@/api/app'
import {
wxpay,
alipay
} from '@/utils/pay'
export default {
name: 'Payment',
data() {
return {
from: '', // 订单来源
order_id: '', // 订单ID
amount: 0, // 支付金额
timeout: 0, // 倒计时间戳
payway: '', // 支付方式
paywayList: [], // 支付方式列表
loadingSkeleton: true, // 骨架屏Loading
loadingPay: false, // 支付处理中Loading
}
},
methods: {
// 更改支付方式
changePayway(value) {
this.$set(this, 'payway', value)
},
// 初始化页面数据
initPageData() {
// 获取支付方式
getPayway({
from: this.from,
order_id: this.order_id,
}).then(res => {
if (res.code != 1) throw new Error(res.msg)
return res.data
}).then(data => {
this.loadingSkeleton = false
this.amount = data.order_amount
this.paywayList = data.pay
this.payway = this.paywayList[0]?.pay_way
// 倒计时
const startTimestamp = new Date().getTime() / 1000
const endTimestamp = data.cancel_time * 1
this.timeout = endTimestamp - startTimestamp
}).catch(err => {
throw new Error(err)
})
},
// 预支付处理
handlePrepay() {
if (this.loadingPay) return
this.loadingPay = true
prepay({
from: this.from,
order_id: this.order_id,
pay_way: this.payway,
}).then(({
code,
data
}) => {
switch (code) {
case 1:
this.handleWechatPay(data);
break;
case 10001:
this.handleAlipayPay(data);
break;
case 20001:
this.handleWalletPay();
break;
}
}).catch(err => {
}).finally(() => {
setTimeout(() => {
this.loadingPay = false
}, 500)
})
},
// 微信支付
handleWechatPay(data) {
wxpay(data).then(res => {
console.log(res)
this.handPayResult(res)
})
},
// 支付宝支付
handleAlipayPay(data) {
alipay(data).then(res => {
console.log(res)
this.handPayResult(res)
})
},
// 钱包余额支付
handleWalletPay() {
console.log('支付成功')
//余额支付成功
this.handPayResult('success')
},
// 支付后处理
handPayResult(result) {
switch (result) {
case 'success':
uni.$emit('payment', {
result: true,
order_id: this.order_id
});
break;
case 'fail':
default:
uni.$emit('payment', {
result: false,
order_id: this.order_id
})
}
// 页面出栈
// uni.navigateBack()
}
},
onLoad(options) {
const from = options.from
const order_id = options.order_id
try {
if (!from && !order_id) throw new Error('页面参数有误')
this.from = from
this.order_id = order_id
this.initPageData()
} catch (err) {
console.log(err)
uni.navigateBack()
}
},
onUnload() {
this.handPayResult('fail')
},
}
</script>
<style lang="scss">
page {
height: 100%;
padding: 0;
}
.payment-pages {
height: 100%;
.payment {
display: flex;
flex-direction: column;
height: calc(100% - env(safe-area-inset-bottom));
&-header {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 300rpx;
background: linear-gradient(270deg, #FF2C3C 0%, #F95F2F 100%);
color: #FFFFFF;
}
&-main {
flex: 1;
margin-top: -40rpx;
padding: 0 20rpx;
overflow: hidden;
}
&-footer {
display: flex;
align-items: center;
height: 100rpx;
padding: 0 20rpx;
background-color: #FFFFFF;
}
.payway-container {
padding: 0 20rpx;
border-radius: 7px;
background-color: #FFFFFF;
.payway-empty {
display: flex;
justify-content: center;
padding: 20rpx 0;
font-size: 26rpx;
color: $-color-muted;
}
}
.payway {
width: 100%;
&-item {
width: 100%;
display: flex;
align-items: center;
height: 120rpx;
&:nth-child(n+2) {
border-top: $-dashed-border;
}
&-content {
flex: 1;
display: flex;
flex-direction: column;
margin-left: 16rpx;
&-name {
font-size: 28rpx;
color: $-color-black;
}
&-tips {
font-size: 22rpx;
color: $-color-muted;
}
}
}
}
&-count-down {
display: flex;
justify-content: center;
align-items: center;
padding: 7rpx 25rpx;
border-radius: 60px;
margin-top: 10rpx;
font-size: 22rpx;
background-color: #FFFFFF;
color: $-color-normal;
}
&-submit {
flex: 1;
position: relative;
display: flex;
justify-content: center;
align-items: center;
height: 74rpx;
font-size: 28rpx;
border-radius: 60px;
background: linear-gradient(270deg, #FF2C3C 0%, #F95F2F 100%);
color: #FFFFFF;
&--disabled::before {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
height: 100%;
display: block;
content: "";
background: rgba(255, 255, 255, .3) !important;
}
}
}
}
</style>
File diff suppressed because one or more lines are too long
+402
View File
@@ -0,0 +1,402 @@
<template>
<view class="shop-cart">
<view
class="main"
:style="{ 'padding-bottom': cartType == 1 ? '100rpx' : 0 }"
>
<view
v-for="(item, index) in cartLists"
:key="index"
class="cart-list mb20"
v-show="!(cartType != 1)"
>
<view
class="cart-item bg-white"
:class="{ invalid: item.cart_status != 0 }"
>
<view class="row-between select" v-if="item.cart_status == 0">
<checkbox
:value="item.cart_id + ''"
:checked="item.selected == 1"
@click="changOneSelect(item.cart_id, item.selected)"
>选择</checkbox
>
<view
:data-cartid="item.cart_id"
@click="changeDelPopup(item.cart_id)"
>
<image class="icon-xl" src="/static/images/icon_del.png" />
</view>
</view>
<view class="select row-between sm muted" v-else>
已失效
<view
:data-cartid="item.cart_id"
@click="changeDelPopup(item.cart_id)"
>
<image class="icon-xl" src="/static/images/icon_del.png" />
</view>
</view>
<view
class="row"
style="padding: 20rpx"
@tap="goPage"
:data-url="'/pages/goods_details/goods_details?id=' + item.goods_id"
>
<custom-image
width="180rpx"
height="180rpx"
radius="10rpx"
class="goods-img mr20"
lazy-load
:src="item.img"
/>
<view class="info" style="flex: 1">
<view class="line2 nr">{{ item.name }}</view>
<view class="muted xs line1 mt10">
{{ item.spec_value_str }}
</view>
<view class="row-between mt20">
<view class="price row primary">
<price-format
:price="item.price"
:firstSize="32"
:secondSize="32"
:showSubscript="true"
:subscriptSize="32"
></price-format>
</view>
<view class="cartNum" @tap.stop="">
<u-number-box
:disabled="item.cart_status != 0"
:value="item.goods_num"
:min="1"
:max="item.item_stock"
@change="countChange($event, item.cart_id, item)"
/>
</view>
</view>
</view>
</view>
</view>
</view>
<view
class="cart-null column-center bg-white mb20"
style="padding: 80rpx 0 50rpx"
v-show="!(cartType != 2)"
>
<image class="img-null" src="/static/images/cart_null.png"></image>
<view class="muted mb20">购物车暂无任何商品~</view>
<navigator
open-type="switchTab"
url="/pages/index/index"
hover-class="none"
class="primary br60 btn row-center"
>去逛逛</navigator
>
</view>
<view v-if="!isLogin" class="login column-center">
<image class="img-null" src="/static/images/cart_null.png"></image>
<view class="muted mt20">登录后才能查看购物车哦</view>
<navigator class="white br60 row-center btn" url="/pages/login/login">
<!-- <image class="mr10" src="/static/images/icon_wechat.png"></image> -->
<text>去登录</text>
</navigator>
</view>
<recommend v-if="isShow"></recommend>
</view>
<view class="footer row bg-white" v-show="!(cartType != 1)">
<checkbox-group class="row" @change="changeAllSelect">
<checkbox id="checkAll" value="all" :checked="isSelectedAll"></checkbox>
<label for="checkAll" class="ml10">全选</label>
</checkbox-group>
<view class="all-price lg mr20 row-end">
<view>合计:</view>
<view class="primary">¥{{ totalPrice || 0 }}</view>
</view>
<view
class="right-btn br60 white"
:style="' ' + (nullSelect ? 'background: #d7d7d7' : '')"
@tap="goToConfirm"
>去结算</view
>
</view>
<u-modal
v-model="delPopup"
:showCancelButton="true"
comfirm-text="狠心删除"
confirm-color="#FF2C3C"
:show-title="false"
@confirm="goodsDelete"
@cancel="changeDelPopup"
>
<view class="column-center tips-dialog" style="padding-top: 40rpx">
<image class="icon-lg" src="/static/images/icon_warning.png" />
<view style="margin: 30rpx 0">确认删除该商品吗</view>
</view>
</u-modal>
</view>
</template>
<script>
import {
getCartList,
changeCartSelect,
changeGoodsCount,
deleteGoods,
} from "@/api/store";
import { getUser } from "@/api/user";
import { mapGetters, mapActions } from "vuex";
import Cache from "@/utils/cache";
import { setTabbar } from "@/utils/tools";
export default {
data() {
return {
//购物车状态 1为有 2为空 0则什么都不显示
cartType: 0,
isShow: false,
cartLists: [],
delPopup: false,
totalPrice: "",
};
},
components: {},
computed: {
...mapGetters(["cartNum"]),
nullSelect() {
let index = this.cartLists.findIndex(
(item) => item.selected == 1 && item.cart_status == 0
);
if (index == -1) {
return true;
}
return false;
},
isSelectedAll() {
let index = this.cartLists.findIndex(
(item) => item.selected == 0 && item.cart_status == 0
);
if (index == -1) {
return true;
}
return false;
},
},
onLoad() {
setTabbar();
},
onShow() {
this.isLogin && this.getCartListFun();
},
onPullDownRefresh() {
this.getCartListFun();
},
// onShareAppMessage() {
// const shareInfo = Cache.get('shareInfo')
// return {
// title: shareInfo.mnp_share_title,
// path: "pages/index/index?invite_code=" + this.userInfo.distribution_code
// };
// },
methods: {
...mapActions(["getCartNum"]),
goodsDelete() {
this.delPopup = false;
deleteGoods({
cart_id: this.cartId,
}).then((res) => {
if (res.code == 1) {
this.getCartListFun();
}
});
},
changeDelPopup(cartId) {
if (cartId) {
this.cartId = cartId;
}
this.delPopup = !this.delPopup;
},
getCartListFun() {
getCartList().then((res) => {
uni.stopPullDownRefresh({
success: (res) => {},
});
if (res.code == 1) {
let { lists, total_amount } = res.data;
let cartType = 0;
if (lists.length == 0) {
cartType = 2;
} else {
cartType = 1;
}
this.cartLists = lists;
this.cartType = cartType;
this.totalPrice = total_amount;
this.isShow = true;
this.getCartNum();
}
});
},
changOneSelect(cartId, selected) {
selected = !selected;
this.changeCartSelectFun([cartId], selected);
},
// 更改全选状态
changeAllSelect() {
const { isSelectedAll, cartLists } = this;
console.log(cartLists, "###");
let cartid = cartLists.map((item) => item.cart_id);
this.changeCartSelectFun(cartid, !isSelectedAll);
},
changeCartSelectFun(cartId, selected) {
console.log("selected ", selected);
changeCartSelect({
cart_id: cartId,
selected: selected ? 1 : 0,
}).then((res) => {
if (res.code == 1) {
this.getCartListFun();
}
});
},
countChange({ value }, cartId, item) {
console.log("countChange", value, cartId, item);
changeGoodsCount({
cart_id: cartId,
goods_num: value,
}).then((res) => {
if (res.code == 1) {
this.getCartListFun();
} else {
this.getCartListFun();
}
});
},
goToConfirm() {
let { cartLists } = this;
let goods = [];
cartLists.forEach((item) => {
if (item.selected && item.cart_status == 0) {
goods.push({
item_id: item.item_id,
num: item.goods_num,
});
}
});
if (goods.length == 0)
return this.$toast({
title: "您还没有选择商品哦",
});
uni.navigateTo({
url:
"/pages/confirm_order/confirm_order?data=" +
encodeURIComponent(
JSON.stringify({
goods,
type: "cart",
})
),
});
},
goPage(e) {
const { url } = e.currentTarget.dataset;
uni.navigateTo({
url,
});
},
},
};
</script>
<style lang="scss">
.shop-cart {
.main {
padding-bottom: 100rpx;
}
.cart-list {
.cart-item {
margin: 20rpx 20rpx 0;
border-radius: 10rpx;
// &.invalid {
// background-color: $-color-body;
// }
}
.select {
height: 80rpx;
padding: 0 20rpx;
border-bottom: $-solid-border;
}
}
.cart-null {
.btn {
border: 1px solid $-color-primary;
width: 184rpx;
margin-left: auto;
margin-right: auto;
padding: 8rpx 24rpx;
}
}
.footer {
position: fixed;
padding: 0 24rpx;
width: 100%;
height: 100rpx;
box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.1);
bottom: var(--window-bottom);
box-sizing: border-box;
z-index: 20;
.all-price {
text-align: right;
flex: 1;
}
.right-btn {
padding: 13rpx 45rpx;
background: linear-gradient(
90deg,
rgba(249, 95, 47, 1) 0%,
rgba(255, 44, 60, 1) 100%
);
}
}
.login {
height: calc(100vh - var(--window-bottom));
background: #fff;
text-align: center;
.btn {
background-color: #09bb07;
width: 280rpx;
line-height: 70rpx;
margin: 40rpx auto 0;
image {
width: 50rpx;
height: 50rpx;
}
}
}
}
</style>
+95
View File
@@ -0,0 +1,95 @@
<template>
<view class="sort">
<navigator class="header" hover-class="none" url="/pages/goods_search/goods_search">
<u-search bg-color="#F4F4F4" :disabled="true"></u-search>
</navigator>
<view class="content">
<cate-one v-if="appConfig.cate_style == 2" :list="cateList"></cate-one>
<cate-two v-if="appConfig.cate_style == 3" :list="cateList"></cate-two>
<cate-three v-if="appConfig.cate_style == 4" :list="cateList"></cate-three>
<cate-four v-if="appConfig.cate_style == 1" :list="cateList"></cate-four>
</view>
</view>
</template>
<script>
import {
getCatrgory
} from '@/api/store';
import {
getRect,
setTabbar
} from '@/utils/tools';
import {
mapGetters,
mapActions
} from 'vuex'
import Cache from '@/utils/cache'
export default {
data() {
return {
cateList: []
};
},
components: {},
onLoad(options) {
setTabbar()
this.getCatrgoryFun();
},
onShow() {
this.getCartNum()
},
onShareAppMessage() {
const shareInfo = Cache.get('shareInfo')
return {
title: shareInfo.mnp_share_title,
path: "pages/index/index?invite_code=" + this.inviteCode,
imageUrl: shareInfo.mnp_share_image,
};
},
methods: {
...mapActions(['getCartNum']),
getCatrgoryFun() {
getCatrgory().then(res => {
if (res.code == 1) {
this.cateList = res.data
}
});
},
},
computed: {
...mapGetters(["cartNum", "inviteCode", "appConfig"])
}
};
</script>
<style lang="scss">
$header-height: 94rpx;
$nav-height: 80rpx;
page {
.sort {
.header {
box-sizing: border-box;
height: $header-height;
border-bottom: $-solid-border;
.search {
flex: 1;
height: 60rpx;
input {
flex: 1;
height: 100%;
}
}
}
.content {
height: calc(100vh - #{$header-height} - var(--window-top) - var(--window-bottom));
}
}
}
</style>
+435
View File
@@ -0,0 +1,435 @@
<template>
<view class="user" :style="[background]">
<view class="header">
<!-- #ifndef H5 -->
<u-sticky offset-top="0" h5-nav-height="0" bg-color="transparent">
<u-navbar
:is-back="false"
title="个人中心"
:title-bold="true"
:is-fixed="false"
:border-bottom="false"
:background="{ background: 'rgba(256,256, 256,' + navBg + ')' }"
:title-color="navBg > 0.5 ? '#000' : '#fff'"
></u-navbar>
</u-sticky>
<!-- #endif -->
<view class="user-info row-between">
<view class="info row">
<image
class="avatar mr20 flexnone"
@tap="goLogin"
:src="isLogin ? userInfo.avatar : '/static/images/my_portrait_empty.png'"
></image>
<view class="white" v-if="isLogin">
<view class="name xxl line1">{{ userInfo.nickname }}</view>
<view class="user-id row-between" v-if="userInfo.sn">
<view class="xs white ml20 mr20">会员ID: {{ userInfo.sn || '' }}</view>
<view class="xs normal copy-btn row-center ml5" @tap.stop="onCopy"
>复制</view
>
</view>
</view>
<view class="white" v-else @tap="goLogin">
<view style="font-size: 42rpx">点击登录</view>
<view class="sm">登录体验更多功能</view>
</view>
</view>
<view class="row" style="align-self: flex-start">
<view
class="user-opt"
style="margin-right: 30rpx"
@tap="goPage('/bundle/pages/message_center/message_center')"
>
<view class="dot row-center" v-if="userInfo.notice_num"></view>
<image
style="width: 58rpx; height: 58rpx"
src="/static/images/icon_my_news.png"
></image>
</view>
<view class="user-opt" @tap="goPage('/bundle/pages/user_profile/user_profile')">
<image
style="width: 58rpx; height: 58rpx"
src="/static/images/icon_my_setting.png"
></image>
</view>
</view>
</view>
<view class="member column-end" @tap="goPage('/pages/user_vip/user_vip')">
<view class="member-entery row-between">
<view class="row">
<image class="icon-md" src="/static/images/icon_member.png"></image>
<view class="ml10">{{
isLogin ? userInfo.level : '登录查看会员权益'
}}</view>
</view>
<view class="row">
<view class="sm">{{ userInfo.next_level_tips || '查看会员权益' }}</view>
<u-icon name="arrow-right"></u-icon>
</view>
</view>
</view>
</view>
<view class="my-assets bg-white">
<view class="title row lg">我的资产</view>
<view class="nav row">
<view
class="column-center mb20 assets-item"
@tap="goPage('/bundle/pages/user_wallet/user_wallet')"
>
<view class="xl primary">{{ userInfo.user_money }}</view>
<view class="sm">余额</view>
</view>
<view
class="column-center mb20 assets-item"
@tap="goPage('/bundle/pages/user_sign/user_sign')"
>
<view class="xl primary">{{ userInfo.user_integral }}</view>
<view class="sm">积分</view>
</view>
<view
class="column-center mb20 assets-item"
@tap="goPage('/pages/user_coupon/user_coupon')"
>
<view class="xl primary">{{ userInfo.coupon }}</view>
<view class="sm">优惠券</view>
</view>
</view>
</view>
<view class="order-nav bg-white">
<view class="title row-between" @tap="goPage('/pages/user_order/user_order')">
<view class="lg">我的订单</view>
<view class="muted sm row">
全部订单
<image class="icon-sm ml10" src="/static/images/arrow_right.png"></image>
</view>
</view>
<view class="nav row">
<view
class="item column-center mb20"
@tap="goPage('/pages/user_order/user_order?type=pay')"
>
<view class="icon-contain">
<view v-if="userInfo.wait_pay" class="badge xs row-center bg-white">
{{ userInfo.wait_pay }}
</view>
<image class="nav-icon" src="/static/images/icon_my_payment.png"></image>
</view>
<view class="sm mt10">待付款</view>
</view>
<view
class="item column-center mb20"
@tap="goPage('/pages/user_order/user_order?type=delivery')"
>
<view class="icon-contain">
<view v-if="userInfo.wait_delivery" class="badge xs row-center bg-white">
{{ userInfo.wait_delivery }}
</view>
<image class="nav-icon mb10" src="/static/images/icon_my_fahuo.png"></image>
</view>
<view class="sm">待发货</view>
</view>
<view
class="item column-center mb20"
@tap="goPage('/pages/user_order/user_order?type=delivery')"
>
<view class="icon-contain">
<view v-if="userInfo.wait_take" class="badge xs row-center bg-white">
{{ userInfo.wait_take }}
</view>
<image class="nav-icon" src="/static/images/icon_my_shouhuo.png"></image>
</view>
<view class="sm mt10">待收货</view>
</view>
<view
class="item column-center mb20"
@tap="goPage('/bundle/pages/goods_comment_list/goods_comment_list')"
>
<view class="icon-contain">
<view v-if="userInfo.wait_comment" class="badge xs row-center bg-white">
{{ userInfo.wait_comment }}
</view>
<image class="nav-icon" src="/static/images/icon_my_pingjia.png"></image>
</view>
<view class="sm mt10">商品评价</view>
</view>
<view
class="item column-center mb20"
@tap="goPage('/bundle/pages/post_sale/post_sale')"
>
<view class="icon-contain">
<view v-if="userInfo.after_sale" class="badge xs row-center bg-white">
{{ userInfo.after_sale }}
</view>
<image class="nav-icon" src="/static/images/icon_my_shouhou.png"></image>
</view>
<view class="sm mt10">退款/售后</view>
</view>
</view>
</view>
<view class="server-nav bg-white" v-if="menuList && menuList.length > 0">
<view>
<view class="title row-between">
<view class="lg">我的功能</view>
</view>
</view>
<view class="nav row wrap">
<button
v-for="(item, index) in menuList"
:key="index"
class="item column-center mb20"
hover-class="none"
:open-type="item.link_type == 3 ? 'contact' : ''"
@tap="tapMenu(item)"
style="width: 25%"
>
<image class="nav-icon" :src="item.image"></image>
<view class="sm mt10">{{ item.name }}</view>
</button>
</view>
</view>
<recommend />
<view class="xs muted" style="margin: 50rpx 0;">
<view class="row-center">
由 likeshop 提供免费开源商城系统
</view>
<view class="row-center">
© likeshop.cn
</view>
</view>
</view>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
import { getUser } from '@/api/user'
import { getMenu } from '@/api/store'
import { toLogin, wxMnpLogin } from '@/utils/login'
import { menuJump, copy, setTabbar } from '@/utils/tools'
import Cache from '@/utils/cache'
const app = getApp()
export default {
data() {
return {
showNav: false,
navH: 0,
navBg: 0,
menuList: [],
statusBarH: ''
}
},
components: {},
props: {},
onLoad(options) {
setTabbar()
this.getMenuFun()
},
onShow() {
this.getUser()
this.getCartNum()
},
onPageScroll(e) {
const top = uni.upx2px(100)
const { scrollTop } = e
let percent = scrollTop / top > 1 ? 1 : scrollTop / top
this.navBg = percent
},
onUnload() {},
onPullDownRefresh() {
this.getUser().then(() => {
uni.stopPullDownRefresh()
})
this.getMenuFun()
},
onShareAppMessage() {
const shareInfo = Cache.get('shareInfo')
return {
title: shareInfo.mnp_share_title,
path: 'pages/index/index?invite_code=' + this.inviteCode,
imageUrl: shareInfo.mnp_share_image
}
},
methods: {
...mapActions(['getCartNum', 'getUser']),
goLogin() {
let { isLogin } = this
if (isLogin) {
uni.navigateTo({
url: '/bundle/pages/user_set/user_set'
})
return
}
toLogin()
},
goPage(url) {
if (!this.isLogin) return toLogin()
uni.navigateTo({
url
})
},
tapMenu(item) {
if (!this.isLogin) return toLogin()
console.log(item)
menuJump(item)
},
async getMenuFun() {
const { data, code } = await getMenu({
type: 2
})
if (code == 1) {
this.menuList = data
}
},
onCopy(e) {
copy(this.userInfo.sn)
}
},
computed: {
...mapGetters(['cartNum', 'userInfo', 'inviteCode', 'appConfig']),
background() {
const { center_setting } = this.appConfig
return center_setting.top_bg_image
? {
'background-image': `url(${center_setting.top_bg_image})`
}
: {}
}
}
}
</script>
<style lang="scss">
.user {
background-image: url(../../static/images/my_topbg.png);
background-size: 100% 420rpx;
background-repeat: no-repeat;
.header {
display: flex;
flex-direction: column;
height: 420rpx;
.user-info {
padding: 10rpx 30rpx;
//#ifdef H5
padding-top: 90rpx;
//#endif
.avatar {
height: 110rpx;
width: 110rpx;
border-radius: 50%;
overflow: hidden;
}
.name {
text-align: left;
margin-bottom: 5rpx;
max-width: 400rpx;
}
.user-id {
border: 1px solid white;
border-radius: 100rpx;
.copy-btn {
background-color: #ffdfda;
height: 40rpx;
width: 90rpx;
border-radius: 100rpx;
}
}
.user-opt {
position: relative;
.dot {
position: absolute;
background-color: #ee0a24;
border: 2rpx solid #ffffff;
color: $-color-primary;
border-radius: 100%;
top: 6rpx;
right: 0rpx;
font-size: 22rpx;
min-width: 16rpx;
height: 16rpx;
}
}
.buyer-type {
background-color: #ffa200;
height: 38rpx;
padding: 0 10rpx;
}
}
.member {
flex: 1;
padding: 0 20rpx;
.member-entery {
color: #ffe0a1;
padding: 0 16rpx;
width: 100%;
height: 80rpx;
background: url(../../static/images/bg_member_grade.png);
background-size: 100%;
}
}
}
.order-nav {
.icon-contain {
position: relative;
}
}
.order-nav,
.my-assets {
margin: 20rpx 20rpx 0;
border-radius: 8rpx;
}
.server-nav {
margin: 20rpx;
border-radius: 8rpx;
}
.title {
height: 88rpx;
padding: 0 30rpx;
border-bottom: $-dashed-border;
}
.nav {
padding: 26rpx 0 0;
.assets-item {
flex: 1;
}
.item {
width: 25%;
}
.badge {
padding: 0 6rpx;
min-width: 28rpx;
height: 28rpx;
border-radius: 28rpx;
box-sizing: border-box;
border: 1rpx solid $-color-primary;
color: $-color-primary;
position: absolute;
left: 33rpx;
top: -10rpx;
z-index: 2;
}
.nav-icon {
width: 52rpx;
height: 52rpx;
}
}
}
</style>
+306
View File
@@ -0,0 +1,306 @@
<template>
<!-- pages/user_address/user_address.wxml -->
<view class="user-address">
<view class="no-address column-center" v-if="!hasAddress">
<image class="img-null mt20" src="/static/images/address_null.png"></image>
<view class="sm muted">暂无添加地址请添加~</view>
</view>
<view class="address-list" v-else>
<radio-group class="radio-group" @change="radioChange">
<view
v-for="(item, index) in addressList"
:key="index"
class="item bg-white mb20"
:data-id="item.id"
@tap="onSelect"
>
<view class="address">
<view class="consignee md bold">
{{ item.contact }}
<text class="phone ml10">{{ item.telephone }}</text>
</view>
<view class="lighter sm mt10">
{{ item.province }} {{ item.city }} {{ item.district }}
{{ item.address }}
</view>
</view>
<view class="operation row-between">
<view>
<radio
class="radio row"
color="#FF2C3C"
:value="item.id + ''"
:checked="item.is_default == '1' ? true : false"
>
<text>设为默认</text>
</radio>
</view>
<view class="row-center">
<view class="row mr20" @click.stop="editAddress(item.id)">
<image
class="icon-md mr10"
src="/static/images/icon_edit.png"
></image>
编辑
</view>
<view class="row ml20" :data-id="item.id" @tap.stop="showSurePop">
<image
class="icon-md mr10"
src="/static/images/icon_del_1.png"
></image>
删除
</view>
</view>
</view>
</view>
</radio-group>
</view>
<u-modal
id="delete-dialog"
v-model="deleteSure"
:showCancelButton="true"
confirm-text="狠心删除"
confirm-color="#FF2C3C"
:show-title="false"
@confirm="delAddressFun"
@cancel="hidePop"
>
<view class="column-center tips-dialog">
<image class="icon-lg" src="/static/images/icon_warning.png"></image>
<view style="margin-top: 30rpx">确认删除该地址吗</view>
</view>
</u-modal>
<view class="footer row-between fixed bg-white">
<!-- #ifdef H5 || MP-WEIXIN -->
<view class="btn row-center bg-gray br60 mr20" @click="getWxAddressFun" v-if="isWeixin">
<image class="icon-lg mr10" src="/static/images/icon_wechat.png"></image>
<text class="md">微信导入</text>
</view>
<!-- #endif -->
<view class="btn bg-primary white md row-center br60" @click="addAddress"
>新增收货地址</view
>
</view>
</view>
</template>
<script>
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
import { getAddressLists, delAddress, setDefaultAddress } from '@/api/user'
import wechath5 from '@/utils/wechath5'
import { isWeixinClient } from '@/utils/tools'
export default {
data() {
return {
addressList: [],
hasAddress: true,
deleteSure: false,
currentId: 0,
isWeixin: true
}
},
props: {},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.type = options.type
//#ifdef H5
this.isWeixin = isWeixinClient()
//#endif
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
this.getAddressListsFun()
},
methods: {
onSelect(e) {
if (this.type) {
let { id } = e.currentTarget.dataset
uni.$emit('selectaddress', {
id
})
uni.navigateBack()
}
},
addAddress() {
uni.navigateTo({
url: '/pages/address_edit/address_edit'
})
},
editAddress(id) {
uni.navigateTo({
url: `/pages/address_edit/address_edit?id=${id}`
})
},
getAddressListsFun() {
getAddressLists().then((res) => {
if (res.code == 1) {
if (res.data.length) {
this.addressList = res.data
this.hasAddress = true
} else {
this.hasAddress = false
}
} else {
this.hasAddress = false
}
})
},
radioChange(e) {
let id = e.detail.value
console.log(e)
setDefaultAddress(id).then((res) => {
if (res.code == 1) this.getAddressListsFun()
})
},
onLoadFun() {
this.getAddressListsFun()
},
delAddressFun(e) {
let id = this.currentId
delAddress(id).then((res) => {
if (res.code == 1) {
this.$toast({
title: res.msg
})
this.deleteSure = false
this.getAddressListsFun()
}
})
},
getWxAddressFun() {
// #ifdef H5
wechath5.getWxAddress().then((res) => {
uni.setStorageSync('wxAddress', JSON.stringify(res))
setTimeout(() => {
uni.navigateTo({
url: `/pages/address_edit/address_edit`
})
}, 200)
})
// #endif
// #ifdef MP-WEIXIN
uni.authorize({
scope: 'scope.address',
success: function (res) {
uni.chooseAddress({
success: function (res) {
uni.setStorageSync('wxAddress', JSON.stringify(res))
setTimeout(() => {
uni.navigateTo({
url: `/pages/address_edit/address_edit`
})
}, 200)
},
fail: function (res) {
if (res.errMsg == 'chooseAddress:cancel')
return this.$toast({
title: '取消选择'
})
}
})
},
fail: function (res) {
uni.showModal({
title: '您已拒绝导入微信地址权限',
content: '是否进入权限管理,调整授权?',
success(res) {
if (res.confirm) {
uni.openSetting({
success: function (res) {}
})
} else if (res.cancel) {
return this.$toast({
title: '已取消!'
})
}
}
})
}
})
// #endif
},
showSurePop: function (e) {
this.deleteSure = true
this.currentId = e.currentTarget.dataset.id
},
hidePop: function (e) {
this.deleteSure = false
}
}
}
</script>
<style lang="scss">
/* pages/user_address/user_address.wxss */
.user-address {
padding-bottom: calc(140rpx + env(safe-area-inset-bottom));
.no-address {
padding-top: 300rpx;
text-align: center;
}
.address-list {
padding: 10rpx 0;
.item {
padding: 0 30rpx;
.address {
padding: 20rpx 0;
border-bottom: $-solid-border;
}
.operation {
height: 80rpx;
}
}
}
.footer {
position: fixed;
left: 0;
right: 0;
bottom: 0;
height: 118rpx;
padding: 0 30rpx;
box-sizing: content-box;
padding-bottom: env(safe-area-inset-bottom);
.btn {
flex: 1;
height: 80rpx;
}
}
}
.tips-dialog {
height: 230rpx;
width: 100%;
}
</style>
+205
View File
@@ -0,0 +1,205 @@
<template>
<!-- pages/user_collection/user_collection.wxml -->
<view class="user-collection">
<view class="goods-list mt20">
<view v-for="(item, index) in collectionList" :key="index" class="collection-item row bg-white" @tap="goToGoodsDetail" :data-id="item.id">
<custom-image width="160rpx" height="160rpx" radius="6rpx" lazy-load class="mr20 goods-img" :src="item.image" />
<view class="info">
<view class="row-between">
<view class="name line2">{{item.name}}</view>
<image style="height: 56rpx;width: 56rpx;flex: none;margin-left: 14rpx" src="/static/images/icon_del.png" @tap.stop="deleteConfirm" :data-id="item.id"></image>
</view>
<view class="row-between mt20">
<price-format :first-size="30" :second-size="26" :price="item.price" :weight="400" :subscriptSize="30" :showSubscript="true" color="#FF2C3C" />
<view class="btn primary br60 sm">去购买</view>
</view>
</view>
</view>
<loading-footer :status="status" slotEmpty>
<view class="data-null column-center" slot="empty">
<image src="/static/images/profit_null.png" class="img-null" />
<text class="sm muted">暂无收藏</text>
</view>
</loading-footer>
</view>
<u-modal
v-model="deleteSure"
confirm-text="狠心删除"
confirm-color="#FF2C3C"
:showCancelButton="true"
:show-title="false"
@confirm="cancelCollect"
@cancel="deleteCancel"
>
<view class="column-center tips-dialog" style="padding: 20rpx 0;">
<image class="icon-lg" src="/static/images/icon_warning.png"></image>
<view style="margin-top:30rpx">确认删除该收藏吗</view>
</view>
</u-modal>
</view>
</template>
<script>
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
import { getCollectGoods, collectGoods } from "@/api/user";
import { CollectType, loadingType } from "@/utils/type";
import {loadingFun} from "@/utils/tools"
export default {
data() {
return {
page: 1,
status: loadingType.LOADING,
collectionList: [],
collectionGoods: CollectType.COLLECTION,
deleteSure: false,
};
},
components: {
},
props: {},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.getCollectGoodsFun();
},
onReachBottom: function () {
this.$nextTick(() => {
this.getCollectGoodsFun();
})
},
methods: {
deleteCancel: function (e) {
this.deleteSure = false;
},
deleteConfirm: function (e) {
this.id = e.currentTarget.dataset.id;
this.deleteSure = true;
},
getCollectGoodsFun() {
let {
page,
collectionList,
status
} = this;
loadingFun(getCollectGoods, page, collectionList, status).then(res => {
if(res) {
this.page = res.page;
this.collectionList = res.dataList
this.status = res.status
}
})
},
reflesh() {
this.collectionList = [];
this.page = 1;
this.status = loadingType.LOADING;
this.getCollectGoodsFun();
},
cancelCollect() {
collectGoods({
is_collect: CollectType.CANCEL_COLLECTION,
goods_id: this.id
}).then(res => {
if (res.code == 1) {
this.collectionList = [];
this.page = 1;
this.status = loadingType.LOADING;
this.getCollectGoodsFun();
this.deleteSure = false;
}
});
},
goToGoodsDetail: function (e) {
let {
id
} = e.currentTarget.dataset;
uni.navigateTo({
url: '/pages/goods_details/goods_details?id=' + id
});
}
}
};
</script>
<style lang="scss">
.user-collection {
.goods-list {
.collection-item {
padding: 20rpx;
&:not(:last-of-type) {
border-bottom: $-solid-border;
}
.info {
flex: 1;
}
.goods-img {
width: 160rpx;
height: 160rpx;
flex: none;
}
.btn {
width: 148rpx;
height: 52rpx;
right: 20rpx;
border: 1px solid $-color-primary;
display: flex;
justify-content: center;
align-items: center;
}
}
.del-btn {
height: 100%;
width: 65px;
}
.store-list {
height: calc(100vh - 100rpx);
overflow: hidden;
}
.store-item {
height: 140rpx;
border-bottom: 1rpx solid #E5E5E5;
.store-img {
height: 80rpx;
width: 80rpx;
border-radius: 50%;
overflow: hidden;
}
}
.tips-dialog {
height: 230rpx;
width: 100%;
}
.data-null {
padding-top: 100rpx;
}
}
}
</style>
+52
View File
@@ -0,0 +1,52 @@
<template>
<!-- pages/user_coupon/user_coupon.wxml -->
<view class="user-coupon">
<tabs :active="active" sticky line-width="40" @change="onChange">
<tab v-for="(item, index) in coupons" :key="index" :title="item.title + '(' + item.num + ')'">
<my-coupons :type="item.type" @getnum="onChangeNum($event, index)"></my-coupons>
</tab>
</tabs>
</view>
</template>
<script>
export default {
data() {
return {
active: 0,
coupons: [{
title: '可使用',
num: '0',
type: 0
}, {
title: '已使用',
num: '0',
type: 1
}, {
title: '已过期',
num: '0',
type: 2
}]
};
},
components: {
},
props: {},
methods: {
onChangeNum(e, index) {
this.coupons[index].num = e.detail
},
onChange(e) {
console.log(e)
}
}
};
</script>
<style>
/* pages/user_coupon/user_coupon.wxss */
</style>
+66
View File
@@ -0,0 +1,66 @@
<template>
<view class="user-getcoupon">
<coupon-list v-if="!showNull" :list="couponList" :btn-type="3" @reflash="getCouponListFun"></coupon-list>
<view v-else class="column-center" style="padding-top: 200rpx">
<image class="img-null" src="/static/images/coupon_null.png"></image>
<text class="muted">暂无优惠券可领</text>
</view>
</view>
</template>
<script>
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
import { getCouponList } from '../../api/activity';
import {getCoupon} from "../../api/user"
export default {
data() {
return {
couponList: [],
showNull: false
};
},
components: {
},
props: {},
onLoad (options) {
this.getCouponListFun();
},
methods: {
getCouponListFun() {
getCouponList().then(res => {
if (res.code == 1) {
if (res.data.length <= 0) {
this.showNull = true;
return;
}
this.couponList = res.data;
}
});
}
}
};
</script>
<style>
</style>
+94
View File
@@ -0,0 +1,94 @@
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
<template>
<view class="user-order">
<navbar title="我的订单"></navbar>
<tabs :active="active" @change="changeShow" :config="{itemWidth: 150}">
<tab v-for="(item, index) in order" :key="index" :title="item.name" :name="item.type">
<order-list v-if="item.isShow" :order-type="item.type" :ref="'order' + item.type"></order-list>
</tab>
</tabs>
</view>
</template>
<script>
import { orderType } from '@/utils/type';
export default {
data() {
return {
active: orderType.ALL,
order: [{
name: '全部',
type: orderType.ALL,
isShow: false
}, {
name: '待付款',
type: orderType.PAY,
isShow: false
}, {
name: '待收货',
type: orderType.DELIVERY,
isShow: false
}, {
name: '已完成',
type: orderType.FINISH,
isShow: false
}, {
name: '已关闭',
type: orderType.CLOSE,
isShow: false
}]
};
},
components: {
},
props: {},
onLoad: function (options) {
const{order} = this
let type = options.type || orderType.ALL;
let index = order.findIndex(item => item.type == type)
this.changeShow(index);
},
onPullDownRefresh: function () {
const {active, order} = this
console.log(this.$refs['order' + order[active].type])
this.$refs['order' + order[active].type][0].reflesh()
},
onReachBottom: function () {
const {active, order} = this
console.log(this.$refs['order' + order[active].type])
this.$refs['order' + order[active].type][0].getOrderListFun()
},
methods: {
changeShow(index) {
if(index != -1) {
this.active = index
this.order[index].isShow = true
}
},
}
};
</script>
<style>
</style>
+249
View File
@@ -0,0 +1,249 @@
<template>
<view>
<view class="user-vip">
<view class="header">
<view class="user-vip-info row">
<custom-image width="110rpx" height="110rpx" round :src="userInfo.avatar"></custom-image>
<view class="ml20 column">
<view class="user-text white xxl row">{{userInfo.nickname}}</view>
<view class="user-level white xs row-center">当前等级{{userInfo.level_name || "无"}}</view>
</view>
</view>
</view>
<view class="content">
<view class="vip-swiper-container">
<swiper class="swiper" style="height: 320rpx" previous-margin="60rpx" next-margin="60rpx" display-multiple-items="1"
:current="currentIndex" @change="bindchange">
<swiper-item v-for="(item, index) in levelList" :key="index">
<view class="vip-card-item" :style="'background-image: url(' + item.background_image + ');'">
<view class="row-between">
<view>
<view v-if="item.current_level_status == 1" class="row grade white sm">当前等级</view>
<view v-else-if="item.current_level_status == -1" class="row white sm ml20">未解锁</view>
<view v-else-if="item.current_level_status == 0" class="row white sm ml20">已解锁</view>
</view>
<image class="grade-icon" :src="item.image"></image>
</view>
<view class="row-between vip-name white">
<view class="bold">{{item.name}}</view>
<view class="sm">{{item.next_level}}</view>
</view>
<view class="row-center" v-if="item.diff_growth_percent">
<view class="vip-progress bg-white row">
<view class="vip-progress-bar" :style="'width: ' + (item.diff_growth_percent*100) + '%'"></view>
</view>
</view>
<view class="row-between mt20" style="padding: 0 30rpx">
<navigator hover-class="none" class="row">
<view class="sm white" style="line-height: 36rpx">
{{item.current_level_status == 0 ? '当前高于该等级' : item.current_growth_tips}}
</view>
</navigator>
<view class="white">{{item.diff_growth_tips}}</view>
</view>
</view>
</swiper-item>
</swiper>
</view>
<view class="vip-grade-rule">
<view class="title row">
<view class="line br60"></view>
<view class="xl ml20 bold">成长值规则</view>
</view>
<text class="rule-content column lighter ml20">
{{growthRule}}
</text>
</view>
<view class="vip-rights">
<view class="title row">
<view class="line br60"></view>
<view class="xl ml20 bold">会员权益</view>
</view>
<view class="rights-list row">
<view v-for="(item, index) in privilegeList" :key="index" class="rights-item column-center">
<image class="mb10" :src="item.image"></image>
<view class="sm">{{item.name}}</view>
</view>
</view>
</view>
</view>
</view>
<loading-view v-if="!userInfo.nickname"></loading-view>
</view>
</template>
<script>
import {
getLevelList
} from '@/api/user';
export default {
data() {
return {
userInfo: {},
currentIndex: 0,
levelList: [],
growthRule: "",
privilegeList: []
};
},
components: {},
props: {},
onLoad: function(options) {
this.getLevelListFun();
},
methods: {
bindchange(e) {
let {
current
} = e.detail;
let currentLevel = this.levelList[current];
this.currentIndex = current
this.privilegeList = currentLevel.level_privilege
},
getLevelListFun() {
getLevelList().then(res => {
const {
code,
data
} = res;
if (code != 1) return;
const {
user,
growth_rule,
level_list
} = data;
let index = level_list.findIndex(item => item.current_level_status == 1);
if (index == -1) index = 0;
this.userInfo = user
this.growthRule = growth_rule
this.levelList = level_list
this.currentIndex = index
this.privilegeList = level_list[index].level_privilege
});
},
}
};
</script>
<style lang="scss">
page {
background-color: #fff;
.user-vip {
.header {
background-image: url(../../static/images/vip_grade_bg.png);
padding-top: 30rpx;
background-size: 100% 100%;
height: 382rpx;
.user-vip-info {
padding-left: 30rpx;
.user-level {
border: 1px solid white;
border-radius: 100rpx;
padding: 4rpx 20rpx;
line-height: 30rpx;
}
.user-text {
line-height: 50rpx;
font-weight: bold;
}
}
}
.content {
margin-top: -200rpx;
.vip-card-item {
height: 320rpx;
width: 600rpx;
position: relative;
background-size: 100% 100%;
.grade {
line-height: 36rpx;
background-color: rgba(0, 0, 0, 0.5);
border-top-right-radius: 100rpx;
border-bottom-right-radius: 100rpx;
height: 50rpx;
padding: 0 28rpx;
}
.user-grade {
line-height: 36rpx;
margin-left: 30rpx;
}
.grade-icon {
width: 120rpx;
height: 100rpx;
}
.vip-name {
padding: 10rpx 30rpx;
font-size: 46rpx;
text-align: center;
align-items: flex-end;
margin-bottom: 30rpx;
}
.vip-progress {
height: 8rpx;
width: 540rpx;
.vip-progress-bar {
background-color: #f8d07c;
height: 100%;
}
}
}
.vip-grade-rule {
margin: 24rpx 40rpx;
.title {
.line {
width: 8rpx;
height: 34rpx;
background-color: #f79c0c;
}
}
}
.vip-rights {
margin: 24rpx 40rpx;
.title {
padding: 28rpx 0;
.line {
width: 8rpx;
height: 34rpx;
background-color: #f79c0c;
}
}
.rights-item {
width: 25%;
padding-bottom: 30rpx;
image {
width: 82rpx;
height: 82rpx;
}
}
}
}
}
}
</style>
+36
View File
@@ -0,0 +1,36 @@
<template>
<view class="page-body">
<view class="page-section page-section-gap">
<web-view :src="url"></web-view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
url: ''
};
},
components: {},
props: {},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.url = options.url
},
methods: {}
};
</script>
<style>
/* pages/webview/webview.wxss */
.page-section-gap{
box-sizing: border-box;
padding: 0 30rpx;
}
</style>