Browse Source

feat: 接口对接;

pull/2/head
Fox-33 2 months ago
parent
commit
877ae6e69f
40 changed files with 1006 additions and 1101 deletions
  1. +1
    -1
      App.vue
  2. +2
    -2
      api/api.js
  3. +1
    -1
      api/fetch.js
  4. +41
    -0
      api/model/address.js
  5. +37
    -0
      api/model/cart.js
  6. +22
    -195
      api/model/index.js
  7. +0
    -109
      api/model/info.js
  8. +6
    -6
      api/model/login.js
  9. +37
    -0
      api/model/order.js
  10. +22
    -0
      api/model/product.js
  11. +0
    -20
      api/model/vip.js
  12. +8
    -8
      config.js
  13. +5
    -1
      pages.json
  14. +63
    -102
      pages/index/cart.vue
  15. +5
    -0
      pages/index/center.vue
  16. +49
    -0
      pages/index/index.vue
  17. +50
    -3
      pages/index/product.vue
  18. +5
    -0
      pages/index/report.vue
  19. +5
    -5
      pages_order/address/addressCard.vue
  20. +31
    -78
      pages_order/address/addressList.vue
  21. +76
    -16
      pages_order/address/addressPopup.vue
  22. +8
    -3
      pages_order/address/addressView.vue
  23. +25
    -20
      pages_order/auth/wxUserInfo.vue
  24. +10
    -6
      pages_order/cart/productCard.vue
  25. +55
    -22
      pages_order/order/orderConfirm/index.vue
  26. +48
    -19
      pages_order/order/orderConfirm/productCard.vue
  27. +8
    -284
      pages_order/order/orderList/index.vue
  28. +24
    -12
      pages_order/order/orderList/orderCard.vue
  29. +65
    -18
      pages_order/order/payPopup.vue
  30. +9
    -2
      pages_order/product/countSelectPopup.vue
  31. +6
    -5
      pages_order/product/productCard.vue
  32. +53
    -16
      pages_order/product/productCustomView.vue
  33. +64
    -43
      pages_order/product/productDetail.vue
  34. +105
    -0
      pages_order/product/productList.vue
  35. +0
    -0
      pages_order/product/sectionHeader.vue
  36. +23
    -5
      pages_order/product/tabCourse/index.vue
  37. +0
    -77
      pages_order/product/tabDetect/detectCustomView.vue
  38. +13
    -8
      pages_order/product/tabDetect/index.vue
  39. +10
    -8
      pages_order/product/tabNutrient/index.vue
  40. +14
    -6
      store/store.js

+ 1
- 1
App.vue View File

@ -3,7 +3,7 @@
onLaunch: function() {
},
onShow: function() {
// this.$store.commit('initConfig')
this.$store.commit('initConfig')
},
onHide: function() {
}


+ 2
- 2
api/api.js View File

@ -5,7 +5,7 @@ import utils from '../utils/utils.js'
let limit = {}
let debounce = {}
const models = ['login', 'index', 'vip', 'info']
const models = ['login', 'index', 'cart', 'product', 'order', 'address', 'info']
const config = {
// 示例
@ -14,7 +14,7 @@ const config = {
// limit : 1000
// },
getConfig : {url : '/config_common/getConfig', method : 'GET', limit : 500},
getConfig : {url : '/config/list', method : 'GET', limit : 500},
}


+ 1
- 1
api/fetch.js View File

@ -1,7 +1,7 @@
import api from './api.js'
const fetch = (key, data = {}, transform = true, loadingTitle) => {
return new Promise(resolve => {
return new Promise((resolve, reject) => {
const callback = (res) => {
if (!transform) {


+ 41
- 0
api/model/address.js View File

@ -0,0 +1,41 @@
// 收货地址相关接口
const api = {
// 小程序收货地址-地址列表查询
getAddressList: {
url: '/address/list',
method: 'GET',
auth: true,
showLoading : true,
},
// 小程序收货地址-通过id查询
getAddressById: {
url: '/address/getById',
method: 'GET',
showLoading : true,
},
// 小程序收货地址-添加地址
addAddress: {
url: '/address/add',
method: 'POST',
limit : 500,
showLoading : true,
},
// 小程序收货地址-修改地址
updateAddress: {
url: '/address/update',
method: 'PUT',
limit : 500,
showLoading : true,
},
// 小程序收货地址-设置默认地址
setAddressDefault: {
url: '/address/setDefault',
method: 'PUT',
limit : 500,
showLoading : true,
},
}
export default api

+ 37
- 0
api/model/cart.js View File

@ -0,0 +1,37 @@
// 购物车相关接口
const api = {
// 购物车-列表查询
getCartList: {
url: '/cart/list',
method: 'GET',
auth: true,
showLoading : true,
},
// 购物车-添加
addCart: {
url: '/cart/add',
method: 'POST',
auth: true,
limit : 500,
showLoading : true,
},
// 购物车-批量删除
deleteCartBatch: {
url: '/cart/deleteBatch',
method: 'DELETE',
auth: true,
showLoading: true,
},
// 购物车-编辑购物车
editCart: {
url: '/cart/edit',
method: 'PUT',
auth: true,
limit : 500,
showLoading : true,
},
}
export default api

+ 22
- 195
api/model/index.js View File

@ -1,215 +1,42 @@
// 首页相关接口
const api = {
// 获取首页轮播图
getRiceBanner: {
url: '/index_common/getRiceBanner',
// Banner列表查询
getBanner: {
url: '/index/banner',
method: 'GET',
},
// 获取首页常规产品【废弃】
// getRiceCommonProductList: {
// url: '/index_common/getRiceCommonProductList',
// method: 'GET',
// },
// 获取首页跳转图标
getRiceIconList: {
url: '/index_common/getRiceIconList',
// 个性化推荐
getPersonalized: {
url: '/index/personalized',
method: 'GET',
},
// 获取首页新闻详情
getRiceNewsDetail: {
url: '/index_common/getCommonNewsDetail',
// 关于普兆
getAbout: {
url: '/index/about',
method: 'GET',
},
// 获取首页新闻列表
getRiceNewsList: {
url: '/index_common/getRiceNewsList',
// 关于普兆详情
getAboutDetail: {
url: '/index/aboutDetail',
method: 'GET',
},
// 获取首页公告列表
getRiceNoticeList: {
url: '/index_common/getRiceNoticeList',
// 普兆介绍->视频介绍
getVideo: {
url: '/index/video',
method: 'GET',
},
// 获取首页商品详情
getRiceProductDetail: {
url: '/index_common/getRiceProductDetail',
// 推荐产品
getRecommendProduct: {
url: '/index/recommendProduct',
method: 'GET',
},
// 获取首页体验产品
getRiceProductList: {
url: '/index_common/getRiceProductList',
// 普兆介绍->步骤条《左右滑动的内容》
getIntroduce: {
url: '/index/getIntroduce',
method: 'GET',
},
// 查询分类接口
getCategoryList: {
url: '/index_common/getCategoryList',
method: 'GET',
},
// 新查询分类以及商品数据接口
getCategoryPidList: {
url: '/index_common/getCategoryPidList',
method: 'GET',
debounce : 250,
},
// 查询一级分类接口
getPidList: {
url: '/index_common/getCategoryPidList',
method: 'GET',
},
// 获取分类分页商品列表接口
getClassShopPageList: {
url: '/index_common/getClassShopPageList',
method: 'GET',
},
// 加入购物车
addCart: {
url: '/index_common/addCart',
method: 'GET',
auth: true,
showLoading: true,
limit : 500,
},
// 删除购物车信息
deleteCart: {
url: '/index_common/deleteCart',
method: 'DELETE',
auth: true,
showLoading: true,
},
// 修改购物车信息数量
updateCartNum: {
url: '/index_common/updateCartNum',
method: 'POST',
auth: true,
debounce: 300,
},
// 创建订单
createOrder: {
url: '/index_common/createOrder',
method: 'GET',
auth: true,
limit: 1000,
showLoading: true,
},
// 创建订单-再次支付
createOrderTwo: {
url: '/index_common/createOrderTwo',
method: 'GET',
auth: true,
limit: 1000,
showLoading: true,
},
// 多商品创建订单
createSumOrder: {
url: '/index_common/createSumOrder',
method: 'POST',
auth: true,
limit: 1000,
showLoading: true,
},
// 多商品订单再次支付
createSumOrderAgain: {
url: '/index_common/createSumOrderAgain',
method: 'POST',
auth: true,
limit: 1000,
showLoading: true,
},
// 确认收货
confirmOrder: {
url: '/index_common/confirmOrder',
method: 'GET',
auth: true,
limit: 1000,
showLoading: true,
},
// 取消订单
cancelOrder: {
url: '/index_common/cancelOrder',
method: 'GET',
auth: true,
limit: 1000,
showLoading: true,
},
// 获取首页广告列表
getRiceProductList: {
url: '/index_common/getRiceAdList',
method: 'GET',
},
// 获取首页广告列表
getRiceAdDetail: {
url: '/index_common/getRiceAdDetail',
method: 'GET',
},
//获取优惠券信息
getRiceCouponList: {
url: '/info_common/getRiceCouponList',
method: 'GET',
},
//增加或者修改合伙人申请信息
addOrUpdateCommonUser: {
url: '/index_common/addOrUpdateCommonUser',
method: 'POST',
},
//根据用户查询渠合伙人申请信息表单
getCommonUser: {
url: '/index_common/getCommonUser',
method: 'GET'
},
//提交反馈信息
addFeedback: {
url: '/info_common/addFeedback',
method: 'POST'
},
// 获取我的直接推荐间接推荐用户列表带分页
getHanHaiMemberUser: {
url: '/info_common/getHanHaiMemberUser',
method: 'GET'
},
// 获取祝福背景图
getRiceBlessing: {
url: '/index_common/getRiceBlessing',
method: 'GET'
},
// 随机获取祝福语
getRiceBlessingWords: {
url: '/index_common/getRiceBlessingWords',
method: 'GET'
},
// 根据订单标识修改订单祝福语背景
updateOrderBlessing: {
url: '/index_common/updateOrderBlessing',
method: 'POST',
auth : true,
limit : 1000,
},
// 1.收礼流程 =》点击收礼
getGiveShop: {
url: '/index_common/getGiveShop',
method: 'GET',
auth : true,
limit : 1000,
},
// 2.点击抽奖 =》抽奖
getGiveShopLottery: {
url: '/index_common/getGiveShopLottery',
method: 'GET',
auth : true,
limit : 1000,
},
// 获取我的礼品订单
getMyGiftOrder: {
url: '/index_common/getMyGiftOrder',
method: 'GET',
auth : true,
},
// 获取我的礼品订单详情
getMyGiftOrderDetail: {
url: '/index_common/getMyGiftOrderDetail',
method: 'GET',
auth : true,
},
}
export default api

+ 0
- 109
api/model/info.js View File

@ -1,115 +1,6 @@
// 个人相关接口
const api = {
// 充值
recharge: {
url: '/info_common/withdraw',
method: 'GET',
auth: true,
limit: 1000,
showLoading: true,
},
// 提现
withdraw: {
url: '/info_common/withdraw',
method: 'GET',
auth: true,
limit: 1000,
showLoading: true,
},
// 获取地址列表带分页
getAddressPageList: {
url: '/info_common/getAddressPageList',
method: 'GET',
auth: true,
},
// 增加或修改地址信息
addOrUpdateAddress: {
url: '/info_common/addOrUpdateAddress',
method: 'POST',
limit: 500,
auth: true,
showLoading: true,
},
// 删除地址
deleteAddress: {
url: '/info_common/deleteAddress',
method: 'GET',
limit: 500,
auth: true,
showLoading: true,
},
// 修改默认地址
updateDefaultAddress: {
url: '/info_common/updateDefaultAddress',
method: 'GET',
auth: true,
limit: 1000,
},
// 获取粉丝列表带分页
getFansPageList: {
url: '/info_common/getFansPageList',
method: 'GET',
auth: true,
},
// 获取相关介绍
getInfoIntroduce: {
url: '/info_common/getInfoIntroduce',
method: 'GET',
auth: true,
},
// 获取个人邀请码
getInviteCode: {
url: '/info_common/getInviteCode',
method: 'GET',
auth: true,
},
// 获取订单列表带分页
getOrderPageList: {
url: '/info_common/getOrderPageList',
method: 'GET',
auth: true,
},
// 获取订单详情
getOrderDetail: {
url: '/info_common/getOrderDetail',
method: 'GET',
auth: true,
},
// 获取流水记录带分页
getWaterPageList: {
url: '/info_common/getWaterPageList',
method: 'GET',
auth: true,
},
// 获取相关介绍
getInfoIntroduce: {
url: '/info_common/getInfoIntroduce',
method: 'GET',
},
// 获取相关介绍详情
getInfoIntroduceDetail: {
url: '/info_common/getRiceNewsDetail',
method: 'GET',
},
// 查询个人信息相关
getRiceInfo: {
url: '/info_common/getRiceInfo',
method: 'GET',
limit: 500,
},
// 获取购物车信息列表带分页
getCartPageList: {
url: '/info_common/getCartPageList',
method: 'GET',
},
// 领取新人优惠券
getRiceCoupon: {
url: '/info_common/getRiceCoupon',
method: 'GET',
limit: 500,
auth: true,
},
}
export default api

+ 6
- 6
api/model/login.js View File

@ -5,20 +5,20 @@
const api = {
// 微信登录接口
wxLogin: {
url: '/login_common/appletLogin',
method: 'GET',
url: '/login/wxLogin',
method: 'POST',
limit : 500,
showLoading : true,
},
// 获取绑定手机号码
bindPhone: {
url: '/login_common/bindPhone',
method: 'GET',
url: '/login/getPhoneNumber',
method: 'POST',
auth: true,
},
// 修改个人信息接口
updateInfo: {
url: '/info_common/updateInfo',
url: '/login/updateUserInfo',
method: 'POST',
auth: true,
limit : 500,
@ -26,7 +26,7 @@ const api = {
},
// 获取个人信息
getInfo: {
url: '/info_common/getInfo',
url: '/login/getUserInfo',
method: 'GET',
auth: true,
},


+ 37
- 0
api/model/order.js View File

@ -0,0 +1,37 @@
// 订单相关接口
const api = {
// 订单-列表查询
getOrderList: {
url: '/order/list',
method: 'GET',
auth: true,
showLoading : true,
},
// 订单详情
getOrderDetail: {
url: '/order/detail',
method: 'GET',
auth: true,
showLoading : true,
},
// 创建订单
createOrder: {
url: '/order/create',
method: 'POST',
auth: true,
limit : 500,
showLoading : true,
},
// 再次支付
payOrder: {
url: '/order/pay',
method: 'POST',
auth: true,
limit : 500,
showLoading : true,
},
}
export default api

+ 22
- 0
api/model/product.js View File

@ -0,0 +1,22 @@
// 产品相关接口
const api = {
// 产品分类查询
getProductCategory: {
url: '/product/category',
method: 'GET',
},
// 产品列表查询
getProductList: {
url: '/product/list',
method: 'GET',
},
// 产品详情查询
getProductDetail: {
url: '/product/detail',
method: 'GET',
},
}
export default api

+ 0
- 20
api/model/vip.js View File

@ -1,20 +0,0 @@
// vip相关接口
const api = {
// 获取会员权益列表
getRiceVipList: {
url: '/index_common/getVipInfoList',
method: 'GET',
},
// 申请成为会员
applyRiceVip: {
url: '/rice_vip/applyRiceVip',
method: 'POST',
limit : 500,
auth : true,
showLoading : true,
},
}
export default api

+ 8
- 8
config.js View File

@ -8,7 +8,7 @@ import uvUI from '@/uni_modules/uv-ui-tools'
Vue.use(uvUI);
// 当前环境
const type = 'dev'
const type = 'prod'
// 环境配置
@ -17,26 +17,26 @@ const config = {
baseUrl : 'http://www.gcosc.fun:82',
},
prod : {
baseUrl : 'http://xxx.xxx.xxx/xxx',
baseUrl : 'https://www.petualmedical.com/health-admin/appletApi',
}
}
// 默认配置
const defaultConfig = {
mapKey : 'XMBBZ-BCPCV-SXPPQ-5Y7MY-PHZXK-YFFVU',
mapKey : 'WH3BZ-5M4EA-RT3KU-CCBEN-OGGWF-T5BVB',
aliOss: {
url: 'https://image.hhlm1688.com/',
config: {
//桶的地址
region: 'oss-cn-guangzhou',
region: 'oss-cn-shanghai',
//id
accessKeyId: 'LTAI5tQSs47izVy8DLVdwUU9',
accessKeyId: 'LTAI5tRbkjEJmdibzfCT8ymy',
//密钥
accessKeySecret: 'qHI7C3PaXYZySr84HTToviC71AYlFq',
accessKeySecret: 'gE6BnsfaEGk23Zv2lOUvkvaWwhS6BV',
//桶的名字
bucket: 'hanhaiimage',
endpoint: 'oss-cn-shenzhen.aliyuncs.com',
bucket: 'petualmedical',
endpoint: 'oss-cn-shanghai.aliyuncs.com',
}
},
}


+ 5
- 1
pages.json View File

@ -31,7 +31,8 @@
"componentPlaceholder": {
"tab-nutrient": "view",
"tab-detect": "view",
"tab-course": "view"
"tab-course": "view",
"product-custom-view": "view"
}
}
},
@ -96,6 +97,9 @@
{
"path": "report/compare/result"
},
{
"path": "product/productList"
},
{
"path": "product/productDetail"
},


+ 63
- 102
pages/index/cart.vue View File

@ -69,7 +69,7 @@
<template v-if="mode == 'edit'">
<view class="flex bar bar-edit">
<button class="btn" @click="onLeaveEdit">取消</button>
<button class="btn" @click="onDelete">删除</button>
<button :class="['btn', selectedList.length ? '' : 'is-disabled']" @click="onDelete" :disabled="!selectedList.length">an class="p">>删除</button>
</view>
</template>
<template v-else>
@ -108,8 +108,7 @@
},
data() {
return {
// todo
mixinsListApi: '',
mixinsListApi: 'getCartList',
// todo
keyword: '',
mode: 'read',
@ -125,108 +124,49 @@
// },
totalPrice() {
return this.selectedList.reduce((price, item) => {
// todo: check key
// return price + item.price * (item.count || 1)
return price + item.price
return price + item.currentPrice
}, 0)
},
},
onLoad() {
if(uni.getStorageSync('token')){
this.$store.commit('getUserInfo')
}
},
methods: {
//
search() {
// todo
},
// todo: delete
getData() {
this.list = [
{
id: '001',
url: '',
name: '月度装定制营养包',
price: 688,
count: 1,
countDesc: '1月装',
options: [
{ id: '001', label: '1月装', count: 1, value: 688 },
{ id: '002', label: '3月装', count: 3, value: 688*3 },
{ id: '003', label: '6月装', count: 6, value: 688*6 },
],
customized: true,
checked: false,
},
{
id: '002',
url: '',
name: '月度装定制营养包',
price: 688,
count: 1,
countDesc: '1月装',
options: [
{ id: '001', label: '1月装', count: 1, value: 688 },
{ id: '002', label: '3月装', count: 3, value: 688*3 },
{ id: '003', label: '6月装', count: 6, value: 688*6 },
],
free: true,
checked: false,
},
{
id: '003',
url: '',
name: '月度装定制营养包',
price: 688,
count: 1,
countDesc: '1月装',
options: [
{ id: '001', label: '1月装', count: 1, value: 688 },
{ id: '002', label: '3月装', count: 3, value: 688*3 },
{ id: '003', label: '6月装', count: 6, value: 688*6 },
],
free: true,
checked: false,
},
{
id: '004',
url: '',
name: '月度装定制营养包',
price: 688,
count: 1,
countDesc: '1月装',
options: [
{ id: '001', label: '1月装', count: 1, value: 688 },
{ id: '002', label: '3月装', count: 3, value: 688*3 },
{ id: '003', label: '6月装', count: 6, value: 688*6 },
],
free: true,
checked: false,
},
{
id: '005',
url: '',
name: '月度装定制营养包',
price: 688,
count: 1,
countDesc: '1月装',
options: [
{ id: '001', label: '1月装', count: 1, value: 688 },
{ id: '002', label: '3月装', count: 3, value: 688*3 },
{ id: '003', label: '6月装', count: 6, value: 688*6 },
],
free: true,
checked: false,
},
]
this.total = this.list.length
this.getDataThen && this.getDataThen(this.list, this.total)
},
getDataThen(records, total) {
console.log('getDataThen')
// todo
if (total) {
this.selectedList.forEach(selectedItem => {
let target = records.find(item => item.id === selectedItem.id)
target.selected = true
})
this.list = records.map(item => {
const { skuId, product } = item
const { currentPrice, specs } = product || {}
return {
...item,
// todo: check key
currentPrice,
specName: specs?.find?.(spec => spec.id === skuId)?.specName || ''
}
})
this.recommendList = []
return
}
// todo: check
this.recommendList = [
{
id: '001',
@ -270,21 +210,28 @@
console.log('onSelect', index, selected)
this.list[index].selected = selected
// todo
this.updateSelectedList()
},
onChange(index, obj) {
async onChange(index, obj) {
console.log('onChange', index, obj)
// todo: check
this.list[index].price = obj.price
this.list[index].count = obj.count
this.list[index].countDesc = obj.countDesc
// todo
try {
// todo
// await this.$fetch('editCart', obj)
// todo: check
// this.list[index].price = obj.price
// this.list[index].count = obj.count
this.list[index].skuId = obj.id
this.list[index].specName = obj.specName
this.updateSelectedList()
} catch (err) {
}
this.updateSelectedList()
},
onEnterEdit() {
this.mode = 'edit'
@ -292,18 +239,32 @@
onLeaveEdit() {
this.mode = 'read'
},
async fetchDelete() {
try {
const ids = this.selectedList.map(item => item.id)
await this.$fetch('deleteCartBatch', { ids })
this.getData()
uni.showToast({
icon: 'success',
title: '删除成功',
});
} catch (err) {
}
},
onDelete() {
uni.showModal({
title: '确认删除?',
success : e => {
if(e.confirm){
// todo
this.list = this.list.filter(item => !item.selected)
this.total = this.list.length
this.fetchDelete()
}
}
})
},
onBuy() {
this.$store.commit('createOrder', this.selectedList)


+ 5
- 0
pages/index/center.vue View File

@ -138,6 +138,11 @@
return this.userInfo && this.userInfo.id
}
},
onLoad() {
if(uni.getStorageSync('token')){
this.$store.commit('getUserInfo')
}
},
methods: {
onClick(target) {
const { key, path } = target


+ 49
- 0
pages/index/index.vue View File

@ -72,6 +72,13 @@
}
},
onLoad() {
this.fetchBanner()
this.fetchPersonalized()
this.fetchAbout()
if(uni.getStorageSync('token')){
this.$store.commit('getUserInfo')
}
this.productSwiperList = [
{
@ -115,6 +122,7 @@
},
]
return
this.recommendList = [
{
id: '001',
@ -266,6 +274,47 @@
]
},
methods: {
async fetchBanner() {
try {
await this.$fetch('getBanner')
} catch (err) {
}
},
async fetchPersonalized() {
try {
let result = await this.$fetch('getPersonalized')
this.recommendList = result.map(item => {
const { id, title, subTitle, info, btnTxt } = item
return {
id,
// todo: check img url?
// url
arr: [
{ text: title, class: 'font1' },
{ text: subTitle, class: 'font2' },
{ text: info, class: 'font3' },
],
// btn: { text: btnTxt, path: '/pages_order/auth/wxLogin' },
// todo: check path?
btn: { text: btnTxt },
}
})
} catch (err) {
}
},
async fetchAbout() {
try {
await this.$fetch('getAbout')
this.followReasonList
} catch (err) {
}
},
},
}
</script>


+ 50
- 3
pages/index/product.vue View File

@ -29,11 +29,23 @@
</navbar>
<!-- 营养素 -->
<tab-nutrient v-if="current == 0"></tab-nutrient>
<tab-nutrient v-if="current == 0">
<template #custom>
<product-custom-view :type="0" :list="list" @categoryChange="onCategoryChange"></product-custom-view>
</template>
</tab-nutrient>
<!-- 检测 -->
<tab-detect v-else-if="current == 1"></tab-detect>
<tab-detect v-else-if="current == 1">
<template #custom>
<product-custom-view :type="1" :list="list" @categoryChange="onCategoryChange"></product-custom-view>
</template>
</tab-detect>
<!-- 课程 -->
<tab-course v-else-if="current == 2"></tab-course>
<tab-course v-else-if="current == 2">
<template #custom>
<product-custom-view :type="2" :list="list" @categoryChange="onCategoryChange"></product-custom-view>
</template>
</tab-course>
<tabber select="product" />
@ -41,16 +53,21 @@
</template>
<script>
import mixinsList from '@/mixins/list.js'
import tabber from '@/components/base/tabbar.vue'
import tabNutrient from '@/pages_order/product/tabNutrient/index.vue'
import tabDetect from '@/pages_order/product/tabDetect/index.vue'
import tabCourse from '@/pages_order/product/tabCourse/index.vue'
import productCustomView from '@/pages_order/product/productCustomView.vue'
export default {
mixins: [mixinsList],
components: {
tabNutrient,
tabDetect,
tabCourse,
productCustomView,
tabber,
},
data() {
@ -61,13 +78,43 @@
{ name: '课程' },
],
current: 0,
mixinsListApi: 'getProductList',
queryParams: {
pageNo: 1,
pageSize: 10,
type: 0, // 012
},
}
},
onLoad() {
if(uni.getStorageSync('token')){
this.$store.commit('getUserInfo')
}
},
methods: {
onTabChange(e) {
console.log('current', e.index)
this.current = e.index
// todo
this.queryParams.pageNo = 1
this.queryParams.pageSize = 10
this.queryParams.type = this.current
this.getData()
},
onCategoryChange(e) {
const { classId } = e || {}
if (classId) {
this.queryParams.classId = classId
} else {
delete this.queryParams.classId
}
this.queryParams.pageNo = 1
this.queryParams.pageSize = 10
this.getData()
},
},
}


+ 5
- 0
pages/index/report.vue View File

@ -66,6 +66,11 @@
mixinsListApi: '',
}
},
onLoad() {
if(uni.getStorageSync('token')){
this.$store.commit('getUserInfo')
}
},
methods: {
onSelectFilter(val) {
this.queryParams.status = val


+ 5
- 5
pages_order/address/addressCard.vue View File

@ -57,9 +57,9 @@
computed: {
isDefault: {
set(val) {
this.radiovalue = val ? 1 : null
this.radiovalue = val
if (this.data.default == val) {
if (this.data.defaultFlag == val) {
return
}
@ -68,14 +68,14 @@
this.$emit('defaultChange', val)
},
get() {
return this.radiovalue == 1 ? true : false
return this.radiovalue
}
},
},
watch: {
data: {
handler(val) {
this.isDefault = val.default
this.isDefault = val.defaultFlag
},
immediate: true,
deep: true,
@ -83,7 +83,7 @@
},
methods: {
onRadioChange() {
this.isDefault = true
this.isDefault = 1
},
onEdit() {
// todo


+ 31
- 78
pages_order/address/addressList.vue View File

@ -5,12 +5,12 @@
<view class="main">
<view class="card" v-for="(item, index) in list" :key="item.id">
<view class="card" v-for="item in list" :key="item.id">
<addressCard
:data="item"
@defaultChange="onDefaultChange(index, $event)"
@defaultChange="onDefaultChange(item.id, $event)"
@click="onSelect(item)"
@edit="onEdit(item)"
@edit="onEdit(item.id)"
@delete="onDelete(item.id)"
></addressCard>
</view>
@ -41,82 +41,26 @@
},
data() {
return {
// todo
mixinsListApi: '',
mixinsListApi: 'getAddressList',
queryParams: {
pageNo: 1,
pageSize: 10,
},
}
},
onLoad() {
this.queryParams.userId = this.userInfo.id
this.getData()
},
methods: {
getData() {
this.list = [
{
id: '001',
name: '郑文锦',
phone: '18108341643',
area: ['海南省', '海口市', '秀英区'],
address: '秀英街道5单元183室',
default: true,
},
{
id: '002',
name: '周俊',
phone: '13293992217',
area: ['贵州省', '遵义市', '道真仡佬族苗族自治县'],
address: '洛龙镇5幢172室',
default: false,
},
{
id: '003',
name: '何炜',
phone: '18108341643',
area: ['新疆维吾尔自治区', '乌鲁木齐市', '沙依巴克区'],
address: '仓房沟片区街道4单元50室',
default: false,
},
{
id: '004',
name: '赵萸艳',
phone: '15022123314',
area: ['海南省', '海口市', '秀英区'],
address: '海南省海口市秀英区秀英街道5单元183室',
default: false,
},
{
id: '005',
name: '周俊',
phone: '13293992217',
area: ['贵州省', '遵义市', '道真仡佬族苗族自治县'],
address: '贵州省遵义市道真仡佬族苗族自治县洛龙镇5幢172室',
default: false,
},
{
id: '006',
name: '何炜',
phone: '18108341643',
area: ['新疆维吾尔自治区', '乌鲁木齐市', '沙依巴克区'],
address: '新疆维吾尔自治区乌鲁木齐市沙依巴克区仓房沟片区街道4单元50室',
default: false,
},
{
id: '007',
name: '赵萸艳',
phone: '15022123314',
area: ['海南省', '海口市', '秀英区'],
address: '海南省海口市秀英区秀英街道5单元183室',
default: false,
},
]
this.total = this.list.length
},
onDefaultChange(index) {
console.log('onDefaultChange', index)
this.list.forEach((item, idx) => {
if (idx === index) {
item.default = true
} else {
item.default = false
}
})
async onDefaultChange(addressId) {
console.log('onDefaultChange', addressId)
try {
await this.$fetch('setAddressDefault', { addressId })
this.getData()
} catch (err) {
}
},
onSelect(data) {
this.$store.commit('setAddressInfo', data)
@ -129,6 +73,15 @@
icon: 'loading',
title: '正在删除',
});
// uni.showLoading({
// title: '...'
// });
try {
// todo: fetch delete
} catch (err) {
}
setTimeout(() => {
this.list = this.list.filter(item => item.id !== id)
@ -145,8 +98,8 @@
// });
}, 1000)
},
onEdit(data) {
this.$refs.addressPopup.open(data)
onEdit(id) {
this.$refs.addressPopup.open(id)
},
onAdd() {
this.$refs.addressPopup.open()


+ 76
- 16
pages_order/address/addressPopup.vue View File

@ -3,7 +3,7 @@
<uv-popup ref="popup" mode="bottom" bgColor="none" >
<view class="popup__view">
<view class="flex header">
<view class="title">新建地址</view>
<view class="title">{{ title }}</view>
<button class="btn" @click="close">关闭</button>
</view>
<view class="form">
@ -43,10 +43,10 @@
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item prop="address" :customStyle="formItemStyle">
<uv-form-item prop="detail" :customStyle="formItemStyle">
<view class="form-item-label">详细地址</view>
<view class="form-item-content">
<formInput v-model="form.address" placeholder="小区楼栋、门牌号、村等"></formInput>
<formInput v-model="form.detail" placeholder="小区楼栋、门牌号、村等"></formInput>
</view>
</uv-form-item>
</view>
@ -69,11 +69,13 @@
},
data() {
return {
id: null,
title: null,
form: {
name: null,
phone: null,
area: null,
address: null,
detail: null,
},
rules: {
'name': {
@ -91,7 +93,7 @@
required: true,
message: '请选择省市区',
},
'address': {
'detail': {
type: 'string',
required: true,
message: '请输入详细地址',
@ -101,21 +103,44 @@
}
},
methods: {
open(data) {
if (data) {
async fetchAddressDetail(id) {
try {
const result = await this.$fetch('getAddressById', { id })
const {
name,
phone,
area,
address,
} = data
province,
city,
district,
detail,
} = result
this.form = {
name,
phone,
area,
address,
area: [province, city, district].filter(val => val),
detail,
}
} catch (err) {
}
},
open(id) {
if (id) {
this.id = id
this.title = '编辑地址'
this.fetchAddressDetail(id)
} else {
this.id = null
this.title = '新建地址'
this.form = {
name: null,
phone: null,
area: null,
detail: null,
}
}
@ -130,11 +155,46 @@
async onSave() {
try {
const res = await this.$refs.form.validate()
await this.$refs.form.validate()
const {
name,
phone,
area,
detail,
} = this.form
console.log('onSave res', res)
const [province, city, district] = area
// todo: save
const params = {
name,
phone,
province,
city,
district,
detail,
}
if (this.id) {
params.id = this.id
await this.$fetch('updateAddress', params)
uni.showToast({
icon: 'success',
title: '修改地址成功',
});
} else {
await this.$fetch('addAddress', params)
uni.showToast({
icon: 'success',
title: '新建地址成功',
});
}
this.$emit('submitted')


+ 8
- 3
pages_order/address/addressView.vue View File

@ -7,7 +7,7 @@
<text>{{ data.phone }}</text>
<button v-if="enableCopy" class="btn btn-copy" @click="$utils.copyText(data.phone)">复制</button>
</view>
<view class="tag" v-if="data.default">默认</view>
<view class="tag" v-if="data.defaultFlag">默认</view>
</view>
<view class="flex address">
<image v-if="showIcon" class="icon" src="@/pages_order/static/address/icon-address.png" mode="scaleToFill"></image>
@ -46,9 +46,14 @@
if (!this.data) {
return ''
}
const { area, address } = this.data
const {
province,
city,
district,
detail,
} = this.data
return `${area.join('')}${address}`
return `${[province, city, district].join('')}${detail}`
},
},
}


+ 25
- 20
pages_order/auth/wxUserInfo.vue View File

@ -15,10 +15,15 @@
errorType="toast"
>
<view class="form-item">
<uv-form-item prop="nickName" :customStyle="formItemStyle">
<uv-form-item prop="name" :customStyle="formItemStyle">
<view class="form-item-label">昵称</view>
<view class="form-item-content input">
<formInput v-model="form.nickName"></formInput>
<input
type="nickname"
placeholder="请输入"
placeholderStyle="color: #C6C6C6; font-size: 32rpx; font-weight: 400;"
v-model="form.name"
/>
</view>
</uv-form-item>
</view>
@ -44,8 +49,8 @@
<view class="form-item-label">头像</view>
<view class="form-item-content input">
<button class="btn btn-avatar" :plain="true" :hairline="false" open-type="chooseAvatar" @chooseavatar="onChooseAvatar">
<view v-if="form.headImage" class="avatar">
<image class="img" :src="form.headImage" mode="aspectFill"></image>
<view v-if="form.avatar" class="avatar">
<image class="img" :src="form.avatar" mode="aspectFill"></image>
<view class="flex mask">
<image class="icon" src="@/pages_order/static/center/icon-change.png" mode="widthFix" />
</view>
@ -88,12 +93,12 @@
data() {
return {
form: {
nickName: null,
name: null,
phone: null,
headImage: null,
avatar: null,
},
rules: {
'nickName': {
'name': {
type: 'string',
required: true,
message: '请输入昵称',
@ -103,7 +108,7 @@
required: true,
message: '请输入手机号',
},
'headImage': {
'avatar': {
type: 'array',
required: true,
message: '请选择头像',
@ -118,29 +123,28 @@
onLoad(arg) {
this.mode = arg.mode
this.form.nickName = this.userInfo.nickName || ''
this.form.name = this.userInfo.name || ''
this.form.phone = this.userInfo.phone || ''
this.form.headImage = this.userInfo.headImage || ''
this.form.avatar = this.userInfo.avatar || ''
},
methods: {
onChooseAvatar(res) {
this.$Oss.ossUpload(res.target.avatarUrl)
.then(url => {
this.form.headImage = url
this.form.avatar = url
})
},
getPhone(e){
this.$api('bindPhone', {
phoneCode : e.detail.code
code : e.detail.code
}, res => {
if(res.code == 200){
let phoneObj = JSON.parse(res.result)
if(phoneObj.errmsg == 'ok'){
this.form.phone = phoneObj.phone_info.phoneNumber
if(res.success){
this.form.phone = res.result
}else{
uni.showModal({
title: phoneObj.errmsg
title: res.message
})
}
}
@ -151,17 +155,18 @@
await this.$refs.form.validate()
const {
nickName,
name,
phone,
headImage,
avatar,
} = this.form
const params = {
nickName,
name,
phone,
headImage,
avatar,
}
// todo: check 415 Unsupported Media Type
const res = await this.$fetch('updateInfo', params, false)
if (res.code == 200) {


+ 10
- 6
pages_order/cart/productCard.vue View File

@ -16,17 +16,19 @@
</view>
<view class="flex right" @click="jumpToProductDetail">
<view class="img-box">
<!-- todo: check key -->
<image class="img" :src="data.url" mode="aspectFit"></image>
</view>
<view class="info">
<view class="title">{{ data.name }}</view>
<view class="desc">{{ data.desc }}</view>
<view class="title">{{ data.product.name }}</view>
<!-- <view class="desc">{{ data.desc }}</view> -->
<view class="flex price-box">
<view class="flex price">¥<text class="highlight">{{ data.price.toFixed(2) }}</text></view>
<view class="flex price">¥<text class="highlight">{{ data.currentPrice.toFixed(2) }}</text></view>
</view>
<view class="flex tool">
<view class="flex count">
规格<text class="highlight">{{ data.countDesc || data.count }}</text>
<!-- todo: check: skuId? -->
规格<text class="highlight">{{ data.skuId || '' }}</text>
<uv-icon name="arrow-down" color="#7451DE" size="24rpx" :bold="true"></uv-icon>
</view>
<button class="flex btn" @click.stop="openPicker">编辑</button>
@ -41,7 +43,7 @@
自定组合
</view>
<uv-picker ref="picker" :columns="[data.options]" keyName="label" confirmColor="#7451DE" @confirm="onChange"></uv-picker>
<uv-picker ref="picker" :columns="[data.product.specs]" keyName="specName" confirmColor="#7451DE" @confirm="onChange"></uv-picker>
</view>
</template>
@ -83,6 +85,7 @@
watch: {
data: {
handler(val) {
console.log('card data', val)
this.checked = val.selected
},
immediate: true,
@ -101,7 +104,8 @@
const target = e.value[0]
console.log('onChange', target)
this.$emit('change', { price: target.value, count: target.count, countDesc: target.label })
// this.$emit('change', { price: target.value, count: target.count, countDesc: target.label })
this.$emit('change', target)
},
jumpToProductDetail() {
console.log(this.data.id, 'jumpToProductDetail')


+ 55
- 22
pages_order/order/orderConfirm/index.vue View File

@ -9,8 +9,8 @@
<uv-icon name="arrow-right" color="#C6C6C6" size="32rpx"></uv-icon>
</view>
<view class="card" v-for="item in payOrderProduct" :key="item.id">
<productCard :data="item"></productCard>
<view class="card" v-for="(item, index) in productList" :key="item.id">
<productCard :data="item" @change="onChange(index, $event)"></productCard>
</view>
<view class="order" v-if="orderData">
@ -93,40 +93,41 @@
},
data() {
return {
addressData: null,
id: null,
defaultAddressInfo: null,
orderData: null,
checkboxValue : [],
productList: [],
checkboxValue: [],
}
},
computed: {
...mapState(['configList', 'userInfo', 'payOrderProduct', 'addressInfo']),
totalPrice() {
return this.payOrderProduct.reduce((price, item) => {
return this.productList.reduce((price, item) => {
// return price + item.price * (item.count || 1)
return price + item.price
return price + item.currentPrice
}, 0)
},
addressData() {
return this.addressInfo || this.defaultAddressInfo || null
},
},
onShow() {
async onShow() {
console.log('onShow')
console.log('address', this.addressInfo)
this.addressData = this.addressInfo || {
id: '001',
name: '郑文锦',
phone: '18108341643',
area: ['海南省', '海口市', '秀英区'],
address: '秀英街道5单元183室',
default: true,
}
this.fetchDefaultAddress()
},
onLoad() {
onLoad(arg) {
console.log('onLoad')
console.log('payOrderProduct', this.payOrderProduct)
console.log('payOrderProduct', this.payOrderProduct)
this.productList = JSON.parse(JSON.stringify(this.payOrderProduct))
// todo: check include Overseas Product ?
this.$utils.navigateTo('/pages_order/order/userInfo/infoFill')
// this.$utils.navigateTo('/pages_order/order/userInfo/infoFill')
return
this.orderData = {
id: '001',
number: 'BH872381728321983929',
@ -140,9 +141,31 @@
this.$store.commit('setAddressInfo', null)
},
methods: {
async fetchDefaultAddress() {
try {
const params = {
pageNo: 1,
pageSize: 1,
userId: this.userInfo.id,
defaultFlag: 1,
}
let { records, total } = await this.$fetch('getAddressList', params)
this.defaultAddressInfo = total ? records[0] : null
} catch (err) {
this.defaultAddressInfo = null
}
},
jumpToSelectAddress() {
this.$utils.navigateTo('/pages_order/address/addressList')
},
onChange(index, obj) {
console.log('onChange', index, obj)
// todo: check skuId? currentPrice ?
this.list[index].skuId = obj.id
this.list[index].specName = obj.specName
},
onConfirmAgreement(confirm) {
if (confirm) {
this.checkboxValue = [1]
@ -150,7 +173,7 @@
this.checkboxValue = []
}
},
onPay() {
async onPay() {
if(!this.checkboxValue.length){
return uni.showToast({
title: '请先同意《用户协议》《隐私协议》《消费者告知》',
@ -158,11 +181,21 @@
})
}
const { id } = this.orderData
if (!this.addressData?.id) {
return uni.showToast({
title: '请选择地址',
icon:'none'
})
}
// const { id } = this.orderData
const obj = {
title: '营养套餐消费',
orderId: id,
// todo: check title
title: '营养套餐消费',
// orderId: id,
list: this.productList,
addressId: this.addressData.id,
amount: this.totalPrice,
}


+ 48
- 19
pages_order/order/orderConfirm/productCard.vue View File

@ -1,28 +1,37 @@
<template>
<view class="flex card" @click="jumpToProductDetail">
<view class="img-box">
<image class="img" :src="data.url" mode="aspectFit"></image>
</view>
<view class="info">
<view class="title">{{ data.name }}</view>
<view class="desc">{{ data.desc }}</view>
<view class="flex price-box">
<view class="flex price">¥<text class="highlight">{{ data.price.toFixed(2) }}</text></view>
<view>
<view class="flex card" @click="jumpToProductDetail">
<view class="img-box">
<image class="img" :src="data.url" mode="aspectFit"></image>
</view>
<view class="flex tool">
<view class="flex count">
规格<text class="highlight">{{ data.countDesc || data.count }}</text>
<view class="info">
<view class="title">{{ data.name }}</view>
<!-- <view class="desc">{{ data.desc }}</view> -->
<view class="flex price-box">
<view class="flex price">¥<text class="highlight">{{ data.currentPrice.toFixed(2) }}</text></view>
</view>
<view class="flex tool">
<view class="flex count">
<!-- 规格<text class="highlight">{{ data.countDesc || data.count }}</text> -->
<!-- todo: check: skuId? -->
规格<text class="highlight">{{ data.skuId || '' }}</text>
<uv-icon name="arrow-down" color="#7451DE" size="24rpx" :bold="true"></uv-icon>
</view>
<button class="flex btn" @click.stop="openPicker">编辑</button>
</view>
<view class="sales" v-if="data.product.sold">{{ `已售出${data.product.sold}` }}</view>
</view>
</view>
<view v-if="data.customized" class="sup customized">
定制组合
</view>
<view v-else-if="data.free" class="sup free">
自定组合
<view v-if="data.customized" class="sup customized">
定制组合
</view>
<view v-else-if="data.free" class="sup free">
自定组合
</view>
</view>
<uv-picker ref="picker" :columns="[data.product.specs]" keyName="specName" confirmColor="#7451DE" @confirm="onChange"></uv-picker>
</view>
</template>
@ -44,6 +53,17 @@
jumpToProductDetail() {
console.log(this.data.id, 'jumpToProductDetail')
this.$utils.navigateTo(`/pages_order/product/productDetail?id=${this.data.id}`)
},
openPicker() {
console.log(this.data.id, 'openPicker')
this.$refs.picker.open();
},
onChange(e) {
const target = e.value[0]
console.log('onChange', target)
// this.$emit('change', { price: target.value, count: target.count, countDesc: target.label })
this.$emit('change', target)
},
},
}
@ -142,6 +162,15 @@
border-radius: 30rpx;
}
}
.sales {
margin-top: 8rpx;
font-family: PingFang SC;
font-weight: 400;
font-size: 24rpx;
line-height: 1;
color: #8B8B8B;
}
}
.sup {


+ 8
- 284
pages_order/order/orderList/index.vue View File

@ -66,6 +66,7 @@
},
data() {
return {
// 0 1 2 3 4
tabs: [
{ name: '全部' },
{ name: '待支付' },
@ -73,8 +74,7 @@
{ name: '待收货' },
{ name: '待评价' },
],
// todo
mixinsListApi: '',
mixinsListApi: 'getOrderList',
current: 0,
}
},
@ -97,296 +97,20 @@
}
this.getData()
},
// todo: delete
getData() {
console.log('getData')
this.list = [
{
id: '001',
url: '/pages_order/static/index/recommend-pic.png',
title: '月度装定制营养包',
amount: 688,
productList: [
{
id: '0011',
url: '/pages_order/static/index/recommend-pic.png',
name: '月度装定制营养包',
type: '保健品',
content: '控糖精华萃 x30颗、膳食纤维 ×30颗',
price: 688.00,
count: 1,
countDesc: '1月装',
customized: true,
},
{
id: '0012',
url: '/pages_order/static/index/recommend-pic.png',
name: '月度装定制营养包',
type: '保健品',
content: '控糖精华萃 x30颗、膳食纤维 ×30颗',
price: 688.00,
count: 1,
countDesc: '1月装',
free: true,
},
{
id: '0013',
url: '/pages_order/static/index/recommend-pic.png',
name: '月度装定制营养包',
type: '保健品',
content: '控糖精华萃 x30颗、膳食纤维 ×30颗',
price: 688.00,
count: 1,
countDesc: '1月装',
free: true,
},
],
userName: '周小艺',
phone: '15558661691',
createTime: '2025-04-28 08:14',
status: 4,
},
{
id: '002',
url: '/pages_order/static/index/recommend-pic.png',
title: '月度装定制营养包',
amount: 688,
productList: [
{
id: '0011',
url: '/pages_order/static/index/recommend-pic.png',
name: '月度装定制营养包',
type: '保健品',
content: '控糖精华萃 x30颗、膳食纤维 ×30颗',
price: 688.00,
count: 1,
countDesc: '1月装',
customized: true,
},
{
id: '0012',
url: '/pages_order/static/index/recommend-pic.png',
name: '月度装定制营养包',
type: '保健品',
content: '控糖精华萃 x30颗、膳食纤维 ×30颗',
price: 688.00,
count: 1,
countDesc: '1月装',
free: true,
},
{
id: '0013',
url: '/pages_order/static/index/recommend-pic.png',
name: '月度装定制营养包',
type: '保健品',
content: '控糖精华萃 x30颗、膳食纤维 ×30颗',
price: 688.00,
count: 1,
countDesc: '1月装',
free: true,
},
],
userName: '周小艺',
phone: '15558661691',
createTime: '2025-04-28 08:14',
status: 3,
},
{
id: '003',
url: '/pages_order/static/index/recommend-pic.png',
title: '月度装定制营养包',
amount: 688,
productList: [
{
id: '0011',
url: '/pages_order/static/index/recommend-pic.png',
name: '月度装定制营养包',
type: '保健品',
content: '控糖精华萃 x30颗、膳食纤维 ×30颗',
price: 688.00,
count: 1,
countDesc: '1月装',
customized: true,
},
{
id: '0012',
url: '/pages_order/static/index/recommend-pic.png',
name: '月度装定制营养包',
type: '保健品',
content: '控糖精华萃 x30颗、膳食纤维 ×30颗',
price: 688.00,
count: 1,
countDesc: '1月装',
free: true,
},
{
id: '0013',
url: '/pages_order/static/index/recommend-pic.png',
name: '月度装定制营养包',
type: '保健品',
content: '控糖精华萃 x30颗、膳食纤维 ×30颗',
price: 688.00,
count: 1,
countDesc: '1月装',
free: true,
},
],
userName: '周小艺',
phone: '15558661691',
createTime: '2025-04-28 08:14',
status: 0,
},
{
id: '004',
url: '/pages_order/static/index/recommend-pic.png',
title: '月度装定制营养包',
amount: 688,
productList: [
{
id: '0011',
url: '/pages_order/static/index/recommend-pic.png',
name: '月度装定制营养包',
type: '保健品',
content: '控糖精华萃 x30颗、膳食纤维 ×30颗',
price: 688.00,
count: 1,
countDesc: '1月装',
customized: true,
},
{
id: '0012',
url: '/pages_order/static/index/recommend-pic.png',
name: '月度装定制营养包',
type: '保健品',
content: '控糖精华萃 x30颗、膳食纤维 ×30颗',
price: 688.00,
count: 1,
countDesc: '1月装',
free: true,
},
{
id: '0013',
url: '/pages_order/static/index/recommend-pic.png',
name: '月度装定制营养包',
type: '保健品',
content: '控糖精华萃 x30颗、膳食纤维 ×30颗',
price: 688.00,
count: 1,
countDesc: '1月装',
free: true,
},
],
userName: '周小艺',
phone: '15558661691',
createTime: '2025-04-28 08:14',
status: 1,
},
{
id: '005',
url: '/pages_order/static/index/recommend-pic.png',
title: '月度装定制营养包',
amount: 688,
productList: [
{
id: '0011',
url: '/pages_order/static/index/recommend-pic.png',
name: '月度装定制营养包',
type: '保健品',
content: '控糖精华萃 x30颗、膳食纤维 ×30颗',
price: 688.00,
count: 1,
countDesc: '1月装',
customized: true,
},
{
id: '0012',
url: '/pages_order/static/index/recommend-pic.png',
name: '月度装定制营养包',
type: '保健品',
content: '控糖精华萃 x30颗、膳食纤维 ×30颗',
price: 688.00,
count: 1,
countDesc: '1月装',
free: true,
},
{
id: '0013',
url: '/pages_order/static/index/recommend-pic.png',
name: '月度装定制营养包',
type: '保健品',
content: '控糖精华萃 x30颗、膳食纤维 ×30颗',
price: 688.00,
count: 1,
countDesc: '1月装',
free: true,
},
],
userName: '周小艺',
phone: '15558661691',
createTime: '2025-04-28 08:14',
status: 2,
},
{
id: '006',
url: '/pages_order/static/index/recommend-pic.png',
title: '月度装定制营养包',
amount: 688,
productList: [
{
id: '0011',
url: '/pages_order/static/index/recommend-pic.png',
name: '月度装定制营养包',
type: '保健品',
content: '控糖精华萃 x30颗、膳食纤维 ×30颗',
price: 688.00,
count: 1,
countDesc: '1月装',
customized: true,
},
{
id: '0012',
url: '/pages_order/static/index/recommend-pic.png',
name: '月度装定制营养包',
type: '保健品',
content: '控糖精华萃 x30颗、膳食纤维 ×30颗',
price: 688.00,
count: 1,
countDesc: '1月装',
free: true,
},
{
id: '0013',
url: '/pages_order/static/index/recommend-pic.png',
name: '月度装定制营养包',
type: '保健品',
content: '控糖精华萃 x30颗、膳食纤维 ×30颗',
price: 688.00,
count: 1,
countDesc: '1月装',
free: true,
},
],
userName: '周小艺',
phone: '15558661691',
createTime: '2025-04-28 08:14',
status: 5,
},
]
this.total = this.list.length
},
onPay(data) {
const {
id,
title,
amount
orderNo,
orderAmount
} = data
const obj = {
title,
orderId: id,
amount,
id,
// todo: check title
title: orderNo,
amount: orderAmount,
}
this.$refs.payPopup.open(obj)


+ 24
- 12
pages_order/order/orderList/orderCard.vue View File

@ -1,56 +1,57 @@
<template>
<view class="card" @click="jumpToOrderDetail">
<view class="flex top">
<!-- todo: check key -->
<view class="title">{{ data.title }}</view>
<view :class="['flex', 'status', `status-${data.status}`]">{{ statusDesc }}</view>
<view :class="['flex', 'status', `status-${status}`]">{{ statusDesc }}</view>
</view>
<view class="flex main">
<image class="img" :src="data.url" mode="scaleToFill"></image>
<view class="info">
<view class="flex row">
<view class="row-label">客户姓名</view>
<view class="row-content">{{ data.userName }}</view>
<view class="row-content">{{ data.customerName }}</view>
</view>
<view class="flex row">
<view class="row-label">下单时间</view>
<view class="row-content">{{ data.createTime }}</view>
<view class="row-content">{{ data.orderDate }}</view>
</view>
<view class="flex row">
<view class="row-label">联系电话</view>
<view class="row-content">{{ data.phone }}</view>
<view class="row-content">{{ data.customerPhone }}</view>
</view>
</view>
</view>
<view class="flex bottom">
<view class="flex price">
<text class="price-label">总价格</text>
<text class="price-unit">¥</text><text class="price-value">{{ data.amount.toFixed(2) }}</text>
<text class="price-unit">¥</text><text class="price-value">{{ data.orderAmount.toFixed(2) }}</text>
</view>
<view class="flex btns">
<!-- 待支付 -->
<template v-if="data.status == 0">
<template v-if="status == 0">
<button class="btn" @click.stop="onPay">立即支付</button>
</template>
<!-- 待发货 -->
<template v-else-if="data.status == 1">
<template v-else-if="status == 1">
<button class="btn" @click.stop="onApplyService">申请售后</button>
</template>
<!-- 待收货 -->
<template v-else-if="data.status == 2">
<template v-else-if="status == 2">
<button class="btn" @click.stop="onApplyService">申请售后</button>
<button class="btn" @click.stop="onConfirmReceipt">确认收货</button>
</template>
<!-- 待评价 -->
<template v-else-if="data.status == 3">
<template v-else-if="status == 3">
<button class="btn" @click.stop="onApplyService">申请售后</button>
<button class="btn" @click.stop="onComment">立即评价</button>
</template>
<!-- 已完成 -->
<template v-else-if="data.status == 4">
<template v-else-if="status == 4">
<button class="btn" @click.stop="onApplyService">申请售后</button>
</template>
<!-- 售后 -->
<template v-else-if="data.status == 5">
<template v-else-if="status == 5">
</template>
</view>
@ -59,6 +60,8 @@
</template>
<script>
// 0 1 2 3 4
// todo: check "" ?
const STATUS_AND_DESC_MAPPING = {
0: '待支付',
1: '待发货',
@ -78,8 +81,17 @@
}
},
computed: {
status() {
const { orderStatus, process } = this.data || {}
if (orderStatus == 4 && process?.length) {
return 5
}
return orderStatus
},
statusDesc() {
return STATUS_AND_DESC_MAPPING[this.data.status]
return STATUS_AND_DESC_MAPPING[this.status]
},
},
methods: {


+ 65
- 18
pages_order/order/payPopup.vue View File

@ -70,29 +70,56 @@
}
},
methods: {
open(data) {
const {
title,
orderId,
amount,
} = data
this.orderData = {
title,
orderId,
amount,
}
async open(data) {
try {
const {
id,
title,
list,
addressId,
amount,
} = data || {}
let wxPayParams
if (id) {
wxPayParams = await this.$fetch('payOrder', { id })
} else {
// todo: check is the time to create order?
// todo: check 415 Unsupported Media Type
wxPayParams = await this.$fetch('createOrder', { list, addressId })
}
this.orderData = {
title,
amount,
wxPayParams,
}
console.log('orderData', this.orderData)
this.$refs.popup.open()
this.$refs.popup.open()
console.log('orderData', this.orderData)
} catch (err) {
}
},
close() {
this.$refs.popup.close()
},
onCancel() {
// todo: jump to order list page?
uni.redirectTo({
url: `/order/orderList/index`
});
// uni.navigateTo({
// url: `/order/orderList/index`
// });
this.close()
},
onConfirmAgreement(confirm) {
@ -102,11 +129,31 @@
this.checkboxValue = []
}
},
onPay() {
// todo: pay
async onPay() {
if(!this.checkboxValue.length){
return uni.showToast({
title: '请先同意《应用内支付用户协议》《支付与隐私的声明》',
icon:'none'
})
}
// todo: check pay
await uni.requestPaymentWxPay(this.orderData.wxPayParams)
// todo: jump to order list page
this.$emit('submitted')
uni.showToast({
title: '支付成功',
icon: 'none'
})
setTimeout(() => {
// todo: check jump to order list page ?
uni.redirectTo({
url: `/order/orderList/index`
});
}, 700)
},
},
}


+ 9
- 2
pages_order/product/countSelectPopup.vue View File

@ -19,12 +19,12 @@
</view>
<view class="section option">
<view
v-for="item in data.options"
v-for="item in options"
:key="item.id"
:class="['option-item', selectId == item.id ? 'is-active' : '']"
@click="selectId = item.id"
>
{{ item.label }}
{{ item.specName }}
</view>
</view>
<view class="footer">
@ -65,6 +65,13 @@ export default {
return arr[0]
},
options() {
const { specs } = this.data
let arr = [...specs]
return arr.sort((a, b) => a.sortOrder - b.sortOrder)
},
},
methods: {
open() {


+ 6
- 5
pages_order/product/productCard.vue View File

@ -1,20 +1,21 @@
<template>
<view class="card product-card__view" :style="cardStyle" @click="jumpToProductDetail">
<view class="card-img flex" :style="imgStyle">
<!-- todo: check url key -->
<image class="img" :src="data.url" mode="scaleToFill"></image>
</view>
<view class="card-detail">
<view class="product-name">{{ data.name }}</view>
<view class="product-sales" v-if="data.sales">{{ `已售出${data.sales}+` }}</view>
<view class="product-sales" v-if="data.sold">{{ `已售出${data.sold}` }}</view>
<view class="flex product-price">
<view>
<view class="product-price-val">
<text>¥</text>
<text class="highlight">{{ data.price }}</text>
<text>/</text>
<text class="highlight">{{ data.currentPrice }}</text>
<text>{{ `/${data.unit}` }}</text>
</view>
<view class="product-price-bef">
{{ `¥${data.originalPrice}/` }}
<view class="product-price-bef" v-if="data.originalPrice">
{{ `¥${data.originalPrice}/${data.unit}` }}
</view>
</view>
<button class="btn flex" @click.stop="onAddCart(data.id)">


pages_order/product/tabNutrient/nutrientCustomView.vue → pages_order/product/productCustomView.vue View File

@ -52,7 +52,7 @@
></uv-tabs>
</view>
</view>
<view class="content">
<view v-if="list.length" class="content">
<view v-for="item in list" :key="item.id">
<productCard
:data="item"
@ -61,6 +61,9 @@
></productCard>
</view>
</view>
<template v-else>
<uv-empty mode="list"></uv-empty>
</template>
</view>
</template>
@ -71,29 +74,30 @@
components: {
productCard,
},
props: {
type: {
type: Number,
default: 0,
},
list: {
type: Array,
default() {
return []
}
},
},
data() {
return {
tabs: [],
level1: 0,
level2: null,
list: [],
}
},
mounted() {
let children = [
{ name: '草本类' },
{ name: '蔬菜类' },
{ name: '维生素类' },
{ name: '草本类' },
{ name: '蔬菜类' },
]
this.tabs = [
{ name: '全部' },
{ name: '皮肤', children, },
{ name: '身材管理', children, },
{ name: '精力', children, },
]
this.fetchCategory()
return
this.list = [
{
@ -121,13 +125,46 @@
originalPrice: 1664,
},
]
let children = [
{ name: '草本类' },
{ name: '蔬菜类' },
{ name: '维生素类' },
{ name: '草本类' },
{ name: '蔬菜类' },
]
this.tabs = [
{ name: '全部' },
{ name: '皮肤', children, },
{ name: '身材管理', children, },
{ name: '精力', children, },
]
},
methods: {
async fetchCategory() {
try {
let result = await this.$fetch('getProductCategory', { type: this.type }) // type: 012
this.tabs = result.reduce((arr, item) => {
const { id, name } = item
// todo: check children?
let obj = { id, name }
arr.push(obj)
return arr
}, [{ name: '全部' }])
} catch (err) {
}
},
onLevel1TabChange(e) {
console.log('level1', e.index)
this.level1 = e.index
this.level2 = this.tabs[this.level1].children?.length ? 0 : null
// todo
this.$emit('categoryChange', { classId: this.tabs[this.level1].id })
},
onLevel2TabChange(e) {
console.log('level2', e.index)

+ 64
- 43
pages_order/product/productDetail.vue View File

@ -7,28 +7,32 @@
<view class="summary">
<view class="card info">
<view class="name">{{ detail.fullName }}</view>
<view class="flex tags">
<!-- todo: check key -->
<view class="name">{{ detail.info }}</view>
<!-- todo: check key -->
<view class="flex tags" v-if="detail.tags">
<view class="tag" v-for="(tag, tIdx) in detail.tags" :key="tIdx">
{{ tag }}
</view>
</view>
<view class="flex price">
<view class="flex price-val">¥<text class="highlight">{{ (detail.price || 0).toFixed(2) }}</text>/</view>
<view class="price-bef">¥<text>{{ detail.originalPrice }}</text>/</view>
<view class="flex price-val">¥<text class="highlight">{{ (detail.currentPrice || 0).toFixed(2) }}</text>/{{ detail.unit }}</view>
<view class="price-bef" v-if="detail.originalPrice">¥<text>{{ detail.originalPrice }}</text>/{{ detail.unit }}</view>
</view>
</view>
<view class="card bar">
<view class="flex row">
<view class="flex row-content">
<view class="label">品类</view>
<!-- todo: check key -->
<view class="value">{{ detail.category }}</view>
</view>
</view>
<view class="flex row" @click="openPicker">
<view class="flex row-content">
<view class="label">规格</view>
<view class="value">{{ detail.countDesc || '请选择规格' }}</view>
<!-- todo: check key -->
<view class="value">{{ detail.specName || '请选择规格' }}</view>
</view>
<uv-picker ref="picker" :columns="[detail.options]" keyName="label" confirmColor="#7451DE" @confirm="onChange"></uv-picker>
<uv-icon name="arrow-right" color="#C6C6C6" size="24rpx"></uv-icon>
@ -36,14 +40,15 @@
<view class="flex row">
<view class="flex row-content">
<view class="label">服务</view>
<!-- todo: check key -->
<view class="value">{{ detail.deliverService }}</view>
</view>
</view>
</view>
</view>
<view class="detail">
<uv-parse :content="detail.details"></uv-parse>
<view class="detail" v-if="detail.detail">
<uv-parse :content="detail.detail"></uv-parse>
</view>
<view class="comment">
@ -51,6 +56,7 @@
<view class="highlight">用户评价</view>
<view>User reviews</view>
</view>
<!-- todo: check api -->
<view class="comment-item" v-for="item in commentList" :key="item.id">
<commentCard :data="item"></commentCard>
</view>
@ -93,6 +99,7 @@
},
computed: {
bannerList() {
// todo: check key
const { image } = this.detail
if (!image) {
@ -104,38 +111,19 @@
},
onLoad(arg) {
console.log('onLoad', arg)
this.id = arg.id
// todo: fetch detail data
const { id } = arg
this.detail = {
id: '001',
image: new Array(4).fill('/pages_order/static/product/product-detail.png'),
name: 'NMN',
fullName: 'NMN 是 NAD* 的前体,在细胞能量代谢、DNA 修复和抗衰老等方面发挥重要作用。提高 NAD*水平能改善代谢健康1-8。',
tags: ['专业设备', '科学流程', '质量保证'],
sales: 24770,
price: 688.00,
originalPrice: 1664,
category: '逆龄抗衰',
count: null,
countDesc: null,
options: [
{ id: '001', label: '每天1颗', count: 1, value: 688, originValue: 1664 },
{ id: '002', label: '每天2颗', count: 2, value: 688*2, originValue: 1664*2 },
{ id: '003', label: '每天3颗', count: 3, value: 688*3, originValue: 1664*3 },
{ id: '004', label: '每天4颗', count: 4, value: 688*4, originValue: 1664*4 },
],
deliverService: '上门取件·送货上门',
details: `<p>商品详情↓<br/><br/><br/><br/>商品详情↑</p>`
}
this.id = id
this.getData(id)
this.commentList = [
{
id: '001',
userName: '战斗世界',
avatar: '/pages_order/static/report/avatar.png',
countDesc: '三月装',
specName: '三月装',
createTime: '2023-04-18',
content: '包装很精致,性价比非常高,终于收到啦,期待效果,每日一包,超级方便,真的能坚持服用',
images: [
@ -151,7 +139,7 @@
id: '002',
userName: '战斗世界',
avatar: '/pages_order/static/report/avatar.png',
countDesc: '三月装',
specName: '三月装',
createTime: '2023-04-18',
content: '包装很精致,性价比非常高,终于收到啦,期待效果,每日一包,超级方便,真的能坚持服用',
images: [
@ -167,7 +155,7 @@
id: '003',
userName: '战斗世界',
avatar: '/pages_order/static/report/avatar.png',
countDesc: '三月装',
specName: '三月装',
createTime: '2023-04-18',
content: '包装很精致,性价比非常高,终于收到啦,期待效果,每日一包,超级方便,真的能坚持服用',
images: [
@ -180,8 +168,39 @@
deliverySpeedScore: 4.5,
},
]
return
this.detail = {
id: '001',
image: new Array(4).fill('/pages_order/static/product/product-detail.png'),
name: 'NMN',
fullName: 'NMN 是 NAD* 的前体,在细胞能量代谢、DNA 修复和抗衰老等方面发挥重要作用。提高 NAD*水平能改善代谢健康1-8。',
tags: ['专业设备', '科学流程', '质量保证'],
sales: 24770,
price: 688.00,
originalPrice: 1664,
category: '逆龄抗衰',
count: null,
specName: null,
options: [
{ id: '001', label: '每天1颗', count: 1, value: 688, originValue: 1664 },
{ id: '002', label: '每天2颗', count: 2, value: 688*2, originValue: 1664*2 },
{ id: '003', label: '每天3颗', count: 3, value: 688*3, originValue: 1664*3 },
{ id: '004', label: '每天4颗', count: 4, value: 688*4, originValue: 1664*4 },
],
deliverService: '上门取件·送货上门',
details: `<p>商品详情↓<br/><br/><br/><br/>商品详情↑</p>`
}
},
methods: {
async getData(id) {
try {
this.detail = await this.$fetch('getProductDetail', { id })
} catch (err) {
}
},
openPicker() {
this.$refs.picker.open();
},
@ -191,7 +210,7 @@
this.detail.price = target.value
this.detail.count = target.count
this.detail.countDesc = target.label
this.detail.specName = target.label
},
jumpToComment() {
this.$utils.navigateTo('/pages_order/comment/commentRecords')
@ -199,14 +218,17 @@
jumpToCreateOrder() {
// todo
},
onSelectCount(optionId) {
const { options } = this.detail
onSelectCount(id) {
const { specs } = this.detail
let target = options.find(item => item.id === optionId)
let target = specs.find(item => item.id === id)
this.detail.price = target.value
this.detail.count = target.count
this.detail.countDesc = target.label
// todo: check price
// this.detail.price = target.value
// todo: check count ?
// this.detail.count = target.count
this.detail.skuId = target.id
this.detail.specName = target.specName
this.onBuy()
},
@ -222,9 +244,8 @@
return
}
// todo
this.$refs.agreementPopup.open()
// todo: check timing
// this.$refs.agreementPopup.open()
this.$store.commit('createOrder', [this.detail])
},


+ 105
- 0
pages_order/product/productList.vue View File

@ -0,0 +1,105 @@
<template>
<view>
<navbar :title="title" leftClick @leftClick="$utils.navigateBack" color="#191919" bgColor="#FFFFFF" />
<!-- 搜索栏 -->
<view class="search">
<uv-search
v-model="keyword"
placeholder="请输入要查询的内容"
placeholderColor="#C6C6C6"
searchIconColor="#8B8B8B"
:searchIconSize="40"
:inputStyle="{
'font-family': 'PingFang SC',
'font-weight': 400,
'font-size': '28rpx',
'line-height': 1.4,
'padding': '12rpx 0',
}"
bgColor="#fff"
:showAction="false"
@search="search"
></uv-search>
</view>
<view class="content">
<productCustomView :type="queryParams.type" :list="list" @categoryChange="onCategoryChange"></productCustomView>
</view>
</view>
</template>
<script>
import mixinsList from '@/mixins/list.js'
import productCustomView from './productCustomView.vue'
export default {
mixins: [mixinsList],
components: {
productCustomView,
},
data() {
return {
title: '',
keyword: '',
mixinsListApi: 'getProductList',
queryParams: {
pageNo: 1,
pageSize: 10,
type: 0, // 012
},
}
},
onLoad(arg) {
const { title, type, search } = arg
if (title) {
this.title = title
}
this.queryParams.type = type
if (search) {
this.keyword = search
}
this.search()
},
methods: {
search() {
this.queryParams.pageNo = 1
this.queryParams.pageSize = 10
if (this.keyword) {
this.queryParams.keyword = this.keyword
} else {
delete this.queryParams.keyword
}
this.getData()
},
onCategoryChange(e) {
const { classId } = e || {}
if (classId) {
this.queryParams.classId = classId
} else {
delete this.queryParams.classId
}
this.queryParams.pageNo = 1
this.queryParams.pageSize = 10
this.getData()
},
},
}
</script>
<style scoped lang="scss">
@import './styles/tab.scss';
.content {
margin-top: 24rpx;
}
</style>

components/product/sectionHeader.vue → pages_order/product/sectionHeader.vue View File


+ 23
- 5
pages_order/product/tabCourse/index.vue View File

@ -30,15 +30,21 @@
<courseLiveCard v-for="item in liveList" :key="item.id" :data="item"></courseLiveCard>
</view>
</view>
<view class="section">
<!-- <view class="section">
<sectionHeader title="推荐课程" @showAll="jumpToRecommendCourse"></sectionHeader>
<courseRecommendView></courseRecommendView>
</view> -->
<!-- todo: check -->
<view class="section section-custom">
<sectionHeader title="推荐课程" @showAll="jumpToRecommendCourse"></sectionHeader>
<!-- <sectionHeader title="自选课程" @showAll="jumpToCustomCourse"></sectionHeader> -->
<slot name="custom"></slot>
</view>
</view>
</template>
<script>
import sectionHeader from '@/components/home/sectionHeader.vue'
import sectionHeader from '../sectionHeader.vue'
import courseLiveCard from './courseLiveCard.vue'
import courseRecommendView from './courseRecommendView.vue'
@ -66,17 +72,29 @@
methods: {
//
search() {
// todo
// todo: check
uni.navigateTo({
url: '/pages/index/category?search=' + this.keyword
url: `/pages_order/product/productList?type=2&search=${this.keyword}&title=课程`
})
this.keyword = ''
// this.keyword = ''
},
jumpToLive() {
// todo
uni.navigateTo({
url: `/pages_order/product/productList?type=2&title=直播`
})
},
jumpToRecommendCourse() {
// todo
uni.navigateTo({
url: `/pages_order/product/productList?type=2&title=推荐课程`
})
},
jumpToCustomCourse() {
// todo
uni.navigateTo({
url: `/pages_order/product/productList?type=2&title=自选课程`
})
},
},
}


+ 0
- 77
pages_order/product/tabDetect/detectCustomView.vue View File

@ -1,77 +0,0 @@
<template>
<view class="view">
<view v-for="item in list" :key="item.id">
<productCard
:data="item"
cardStyle="width: 100%; height: 210px;"
imgStyle="width: 100%; height: 110px;"
></productCard>
</view>
</view>
</template>
<script>
import productCard from '@/pages_order/product/productCard.vue'
export default {
components: {
productCard,
},
data() {
return {
list: [],
}
},
mounted() {
this.list = [
{
id: '001',
url: '',
name: '腹部超声',
sales: 24770,
price: 688.00,
originalPrice: 1664,
},
{
id: '002',
url: '',
name: '血常规',
sales: 24770,
price: 688.00,
originalPrice: 1664,
},
{
id: '003',
url: '',
name: '腹部超声',
sales: 24770,
price: 688.00,
originalPrice: 1664,
},
]
},
methods: {
onLevel1TabChange(e) {
console.log('level1', e.index)
this.level1 = e.index
this.level2 = this.tabs[this.level1].children?.length ? 0 : null
// todo
},
onLevel2TabChange(e) {
console.log('level2', e.index)
this.level2 = e.index
// todo
},
},
}
</script>
<style scoped lang="scss">
.view {
padding: 0 32rpx 24rpx 32rpx;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 32rpx;
}
</style>

+ 13
- 8
pages_order/product/tabDetect/index.vue View File

@ -51,23 +51,21 @@
<view class="section-header">
<sectionHeader title="自选检测" @showAll="jumpToCustomDetect"></sectionHeader>
</view>
<detectCustomView></detectCustomView>
<slot name="custom"></slot>
</view>
</view>
</template>
<script>
import sectionHeader from '@/components/home/sectionHeader.vue'
import sectionHeader from '../sectionHeader.vue'
import detectRecommendSwiper from './detectRecommendSwiper.vue'
import detectPackageViewVue from './detectPackageView.vue'
import detectCustomView from './detectCustomView.vue'
export default {
components: {
sectionHeader,
detectRecommendSwiper,
detectPackageViewVue,
detectCustomView,
},
data() {
return {
@ -77,20 +75,27 @@
methods: {
//
search() {
// todo
uni.navigateTo({
url: '/pages/index/category?search=' + this.keyword
url: `/pages_order/product/productList?type=1&search=${this.keyword}&title=检测`
})
this.keyword = ''
// this.keyword = ''
},
jumpToRecommendDetect() {
// todo
uni.navigateTo({
url: `/pages_order/product/productList?type=1&title=自选检测`
})
},
jumpToPersonalDetect() {
// todo
uni.navigateTo({
url: `/pages_order/product/productList?type=1&title=自选检测`
})
},
jumpToCustomDetect() {
// todo
uni.navigateTo({
url: `/pages_order/product/productList?type=1&title=自选检测`
})
},
},
}


+ 10
- 8
pages_order/product/tabNutrient/index.vue View File

@ -43,21 +43,19 @@
</view>
<view class="section section-custom">
<sectionHeader title="自选补剂" @showAll="jumpToCustomNutrient"></sectionHeader>
<nutrientCustomView></nutrientCustomView>
<slot name="custom"></slot>
</view>
</view>
</template>
<script>
import sectionHeader from '@/components/home/sectionHeader.vue'
import sectionHeader from '../sectionHeader.vue'
import nutrientRecommendSwiper from './nutrientRecommendSwiper.vue'
import nutrientCustomView from './nutrientCustomView.vue'
export default {
components: {
sectionHeader,
nutrientRecommendSwiper,
nutrientCustomView,
},
data() {
return {
@ -69,17 +67,21 @@
methods: {
//
search() {
// todo
uni.navigateTo({
url: '/pages/index/category?search=' + this.keyword
url: `/pages_order/product/productList?type=0&search=${this.keyword}&title=营养素`
})
this.keyword = ''
// this.keyword = ''
},
jumpToRecommendNutrient() {
// todo
uni.navigateTo({
url: `/pages_order/product/productList?type=0&title=推荐产品`
})
},
jumpToCustomNutrient() {
// todo
uni.navigateTo({
url: `/pages_order/product/productList?type=0&title=自选补剂`
})
},
},
}


+ 14
- 6
store/store.js View File

@ -4,6 +4,7 @@ import Vuex from 'vuex'
Vue.use(Vuex); //vue的插件机制
import api from '@/api/api.js'
import fetch from '@/api/fetch.js'
//Vuex.Store 构造器选项
const store = new Vuex.Store({
@ -30,8 +31,7 @@ const store = new Vuex.Store({
}
if (res.code == 200) {
res.result.forEach(n => {
configList[n.keyName] = n.keyContent;
configList[n.keyName + '_keyValue'] = n.keyValue;
configList[n.code] = n.content;
});
}
state.configList = configList
@ -71,7 +71,7 @@ const store = new Vuex.Store({
state.userInfo = res.result.userInfo
uni.setStorageSync('token', res.result.token)
if(!state.userInfo.nickName || !state.userInfo.headImage){
if(!state.userInfo.name || !state.userInfo.avatar){
uni.navigateTo({
url: '/pages_order/auth/wxUserInfo'
})
@ -109,11 +109,19 @@ const store = new Vuex.Store({
}
})
},
addCart(state, data) {
// todo: fetch
async addCart(state, data) {
console.log('addCart', data)
try {
await fetch('addCart', { productId: data.id })
uni.showToast({
icon: 'success',
title: '成功加入购物车',
});
} catch (err) {
}
},
setAddressInfo(state, data) {
state.addressInfo = data


Loading…
Cancel
Save