Browse Source

feat: 接口对接;

fox
Fox-33 4 hours ago
parent
commit
53429bb4cf
48 changed files with 615 additions and 861 deletions
  1. +1
    -1
      App.vue
  2. +3
    -2
      api/api.js
  3. +5
    -0
      api/model/activity.js
  4. +34
    -0
      api/model/bind.js
  5. +29
    -0
      api/model/coupon.js
  6. +8
    -0
      api/model/experience.js
  7. +2
    -2
      api/model/login.js
  8. +1
    -1
      api/model/partner.js
  9. +15
    -46
      components/home/pictureLiveView.vue
  10. +1
    -1
      components/home/productView.vue
  11. +9
    -4
      components/partner/posterPopup.vue
  12. +3
    -0
      components/product/productCard.vue
  13. +64
    -16
      pages.json
  14. +10
    -64
      pages/index/category.vue
  15. +10
    -11
      pages/index/center.vue
  16. +34
    -36
      pages/index/growing.vue
  17. +4
    -1
      pages/index/index.vue
  18. +5
    -0
      pages/index/partner.vue
  19. +2
    -4
      pages_order/auth/wxLogin.vue
  20. +20
    -20
      pages_order/auth/wxUserInfo.vue
  21. +3
    -3
      pages_order/comment/commentCard.vue
  22. +29
    -19
      pages_order/comment/commentPopup.vue
  23. +12
    -10
      pages_order/comment/commentRecords.vue
  24. +61
    -26
      pages_order/comment/recordFormPopup.vue
  25. +1
    -0
      pages_order/coupon/couponList/couponCard.vue
  26. +2
    -38
      pages_order/coupon/couponList/index.vue
  27. +3
    -3
      pages_order/coupon/couponSelect/couponCard.vue
  28. +2
    -38
      pages_order/coupon/couponSelect/index.vue
  29. +16
    -0
      pages_order/growing/activity/index.vue
  30. +20
    -18
      pages_order/live/formPopup.vue
  31. +30
    -77
      pages_order/live/index.vue
  32. +21
    -62
      pages_order/live/list.vue
  33. +15
    -7
      pages_order/member/memberApplyCard.vue
  34. +11
    -9
      pages_order/member/memberBind.vue
  35. +1
    -1
      pages_order/member/memberCard.vue
  36. +9
    -54
      pages_order/member/memberList.vue
  37. +3
    -43
      pages_order/member/switch.vue
  38. +28
    -22
      pages_order/order/orderConfirm/infoPopup.vue
  39. +34
    -96
      pages_order/order/orderConfirm/peopleNumberInput.vue
  40. +2
    -3
      pages_order/order/orderConfirm/timeOptionsSelect.vue
  41. +2
    -2
      pages_order/order/orderDetail/index.vue
  42. +4
    -5
      pages_order/order/orderList/index.vue
  43. +3
    -3
      pages_order/partner/apply.vue
  44. +5
    -97
      pages_order/partner/team.vue
  45. +13
    -10
      pages_order/partner/withdraw.vue
  46. +1
    -2
      pages_order/product/productDetail.vue
  47. +1
    -1
      pages_order/traveler/travelerList.vue
  48. +23
    -3
      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() {
}


+ 3
- 2
api/api.js View File

@ -5,7 +5,7 @@ import utils from '../utils/utils.js'
let limit = {}
let debounce = {}
const models = ['login', 'index', 'image', 'activity', 'order', 'comment', 'experience', 'partner', 'info']
const models = ['login', 'index', 'image', 'activity', 'coupon', 'order', 'comment', 'bind', 'experience', 'partner', 'info']
const config = {
// 示例
@ -14,7 +14,8 @@ const config = {
// limit : 1000
// },
getConfig : {url : '/config_common/getConfig', method : 'GET', limit : 500},
getConfig : {url : '/config/queryConfigList', method : 'GET', limit : 500},
queryConfigByParamCode : {url : '/config/queryConfigByParamCode', method : 'GET'},
}


+ 5
- 0
api/model/activity.js View File

@ -1,6 +1,11 @@
// 研学活动相关接口
const api = {
// 系统配置-查询研学活动分类列表
queryCategoryList: {
url: '/config/queryCategoryList',
method: 'GET',
},
// 首页&分类-查询研学活动列表
queryActivityList: {
url: '/activity/queryActivityList',


+ 34
- 0
api/model/bind.js View File

@ -0,0 +1,34 @@
// 成员管理相关接口
const api = {
// 成员管理-查询绑定成员列表
queryBindList: {
url: '/bind/queryBindList',
method: 'GET',
auth: true,
},
// 成员管理-查询绑定人信息
queryBindUser: {
url: '/bind/queryBindUser',
method: 'GET',
auth: true,
},
// 成员管理-绑定申请
addBind: {
url: '/bind/addBind',
method: 'POST',
auth: true,
limit : 500,
showLoading : true,
},
// 成员管理-审批绑定申请
updateBind: {
url: '/bind/updateBind',
method: 'POST',
auth: true,
limit : 500,
showLoading : true,
},
}
export default api

+ 29
- 0
api/model/coupon.js View File

@ -0,0 +1,29 @@
// 优惠券相关接口
const api = {
// 优惠券-我的优惠券列表
queryCouponList: {
url: '/coupon/queryCouponList',
method: 'GET',
auth: true,
},
// 优惠券-根据id查看优惠券详情
queryCouponById: {
url: '/coupon/queryCouponById',
method: 'GET',
},
// 优惠券-查看可领取的优惠券
queryFetchCouponList: { // todo: check use in where?
url: '/coupon/queryFetchCouponList',
method: 'GET',
auth: true,
},
// 优惠券-领取优惠券
fetchCoupon: { // todo: check use in where?
url: '/coupon/fetchCoupon',
method: 'POST',
auth: true,
},
}
export default api

+ 8
- 0
api/model/experience.js View File

@ -11,6 +11,14 @@ const api = {
url: '/experience/queryExperienceById',
method: 'GET',
},
// 成长档案-新增成长档案
addExperience: {
url: '/experience/addExperience',
method: 'POST',
auth: true,
limit : 500,
showLoading : true,
},
}
export default api

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

@ -18,7 +18,7 @@ const api = {
},
// 修改个人信息接口
updateInfo: {
url: '/info_common/updateInfo',
url: '/userInfo/updateUser',
method: 'POST',
auth: true,
limit : 500,
@ -26,7 +26,7 @@ const api = {
},
// 获取个人信息
getInfo: {
url: '/info_common/getInfo',
url: '/userInfo/queryUser',
method: 'GET',
auth: true,
},


+ 1
- 1
api/model/partner.js View File

@ -31,7 +31,7 @@ const api = {
method: 'GET',
},
// 我的团队-获取间推用户列表
queryDirectList: {
queryIndirectList: {
url: '/partner/queryIndirectList',
method: 'GET',
},


+ 15
- 46
components/home/pictureLiveView.vue View File

@ -27,7 +27,7 @@
<swiper-item v-for="item in list" :key="item.id" style="display: inline-block;">
<view class="swiper-item">
<view class="swiper-item-content" @click="jumpToLive(item.id)">
<image class="live-item-bg" :src="item.image" mode="aspectFill"></image>
<image class="live-item-bg" :src="item.url" mode="aspectFill"></image>
<view class="live-item-info">
<view class="text-ellipsis live-item-info-title">{{ item.title }}</view>
<view class="live-item-info-time">{{ item.createTime }}</view>
@ -52,57 +52,26 @@
},
methods: {
async getData() {
this.list = [
{
id: '001',
image: '/static/image/temp-15.png',
title: '苕溪露营漂流',
createTime: '2025-04-18',
},
{
id: '002',
image: '/static/image/temp-15.png',
title: '科技奇遇记',
createTime: '2025-04-18',
},
{
id: '003',
image: '/static/image/temp-15.png',
title: '满陇桂雨',
createTime: '2025-04-18',
},
{
id: '004',
image: '/static/image/temp-15.png',
title: '跟着皇帝游江南',
createTime: '2025-04-18',
},
{
id: '005',
image: '/static/image/temp-15.png',
title: '苕溪露营漂流',
createTime: '2025-04-18',
},
{
id: '006',
image: '/static/image/temp-15.png',
title: '科技奇遇记',
createTime: '2025-04-18',
},
]
return
// todo: check
try {
this.list = await this.$fetch('queryImageList', { pageNo: 1, pageSize: 8 })
this.list = (await this.$fetch('queryImageList', { pageNo: 1, pageSize: 8 }))?.records?.map(item => {
const { id, image, activityId_dictText, createTime } = item
const images = image?.split?.(',') || []
return {
id,
url: images?.[0],
images,
title: activityId_dictText,
createTime: this.$dayjs(createTime).format('YYYY-MM-DD'),
}
})
} catch (err) {
}
},
jumpToLive(id) {
this.$store.commit('setLiveInfo', this.list.find(item => item.id === id))
this.$utils.navigateTo(`/pages_order/live/index?id=${id}`)
},
showAll() {


+ 1
- 1
components/home/productView.vue View File

@ -73,7 +73,7 @@
// todo: fetch
this.tabs = [
{ name: '全部' },
{ id: '1962342791093227522', name: '研学活动一', disabled: true, },
// { id: '1962342791093227522', name: '', disabled: true, },
]
},
onClickTab(e) {


+ 9
- 4
components/partner/posterPopup.vue View File

@ -21,6 +21,8 @@
<script>
import { mapState } from 'vuex'
export default {
data() {
return {
@ -30,6 +32,9 @@
retry: 10,
}
},
computed: {
...mapState(['userInfo', 'configList']),
},
async onLoad() {
},
methods: {
@ -45,6 +50,7 @@
this.wxCodeImage = 'https://uploadfile.bizhizu.cn/up/e3/64/e0/e364e0f7f6af11f11abdafc22d17b15c.jpg'
return
try {
const path = `pages/index/index?userId=${this.userInfo.id}`
this.wxCodeImage = (await this.$fetch('getInviteCode', { path }))?.url
} catch (err) {
@ -119,8 +125,7 @@
return new Promise(resolve => {
//
const avatarImage = canvas.createImage()
// todo: fetch
avatarImage.src = 'https://i1.hdslb.com/bfs/archive/c0101b4ce06e6bdda803728408e79c8f8b8d0725.jpg'
avatarImage.src = this.userInfo.headImage
avatarImage.onload = () => {
console.log('avatarImage onload')
@ -253,8 +258,8 @@
ctx.restore();
ctx.save()
let text = '战斗世界'
let maxWidth = 220 * Ratio / dpr
let text = this.userInfo.nickName
let maxWidth = 560 * Ratio / dpr
let lineHeight = 17 * Ratio / dpr
x = 100 * Ratio / dpr
y = 474 * Ratio / dpr


+ 3
- 0
components/product/productCard.vue View File

@ -218,11 +218,13 @@
justify-content: flex-start;
align-items: baseline;
column-gap: 12rpx;
flex-wrap: wrap;
&-val {
font-size: 24rpx;
font-weight: 500;
color: #FF4800;
white-space: nowrap;
.highlight {
font-size: 32rpx;
@ -249,6 +251,7 @@
color: #FFFFFF;
background: #00A9FF;
border-radius: 24rpx;
white-space: nowrap;
}
&.small {


+ 64
- 16
pages.json View File

@ -56,13 +56,19 @@
"path": "auth/loginAndRegisterAndForgetPassword"
},
{
"path": "product/search"
"path": "product/search",
"style": {
"enablePullDownRefresh": true
}
},
{
"path": "product/productDetail"
},
{
"path": "product/collectList"
"path": "product/collectList",
"style": {
"enablePullDownRefresh": true
}
},
{
"path": "order/orderConfirm/index"
@ -83,28 +89,49 @@
}
},
{
"path": "traveler/travelerList"
"path": "traveler/travelerList",
"style": {
"enablePullDownRefresh": true
}
},
{
"path": "coupon/couponSelect/index"
"path": "coupon/couponSelect/index",
"style": {
"enablePullDownRefresh": true
}
},
{
"path": "coupon/couponList/index"
"path": "coupon/couponList/index",
"style": {
"enablePullDownRefresh": true
}
},
{
"path": "comment/commentRecordsOfProduct"
"path": "comment/commentRecordsOfProduct",
"style": {
"enablePullDownRefresh": true
}
},
{
"path": "comment/commentRecords"
"path": "comment/commentRecords",
"style": {
"enablePullDownRefresh": true
}
},
{
"path": "growing/activity/search"
"path": "growing/activity/search",
"style": {
"enablePullDownRefresh": true
}
},
{
"path": "growing/activity/index"
},
{
"path": "growing/activity/markList"
"path": "growing/activity/markList",
"style": {
"enablePullDownRefresh": true
}
},
{
"path": "growing/activity/applyEmail"
@ -113,19 +140,34 @@
"path": "growing/achievement/index"
},
{
"path": "member/memberList"
"path": "member/memberList",
"style": {
"enablePullDownRefresh": true
}
},
{
"path": "member/memberBind"
"path": "member/memberBind",
"style": {
"enablePullDownRefresh": true
}
},
{
"path": "member/switch"
"path": "member/switch",
"style": {
"enablePullDownRefresh": true
}
},
{
"path": "live/list"
"path": "live/list",
"style": {
"enablePullDownRefresh": true
}
},
{
"path": "live/index"
"path": "live/index",
"style": {
"enablePullDownRefresh": true
}
},
{
"path": "partner/apply"
@ -137,13 +179,19 @@
"path": "partner/withdraw"
},
{
"path": "article/search"
"path": "article/search",
"style": {
"enablePullDownRefresh": true
}
},
{
"path": "article/index"
},
{
"path": "message/list"
"path": "message/list",
"style": {
"enablePullDownRefresh": true
}
},
{
"path": "message/index"


+ 10
- 64
pages/index/category.vue View File

@ -204,6 +204,9 @@
}
},
async onLoad({ categoryId }) {
if(uni.getStorageSync('token')){
this.$store.commit('getUserInfo')
}
await Promise.allSettled([this.fetchCategoryList(), this.fetchFilters()])
console.log('categoryList', this.categoryList)
@ -222,6 +225,13 @@
},
methods: {
async fetchCategoryList() {
try {
this.categoryList = (await this.$fetch('queryCategoryList', { pageSize: 1000 }))?.records?.map(item => ({ id: item.id, name: item.title, children: [] }))
} catch(err) {
this.categoryList = []
}
return
this.categoryList = [
{
"key": "1962345168240185345",
@ -363,12 +373,6 @@
}
})
return
try {
this.categoryList = (await this.$fetch('getCategoryList', { pageSize: 1000 }))?.records?.map(item => ({ id: item.id, name: item.name, children: [] }))
} catch(err) {
this.categoryList = []
}
},
async fetchFilters() {
@ -499,69 +503,11 @@
// todo: fetch
},
async queryProductList(categoryId) {
try {
return (await this.$fetch('queryActivityList', { ...this.queryParams, categoryId }))?.records || []
} catch (err) {
return []
}
return [
{
id: '001',
image: '/static/image/temp-20.png',
title: '新疆天山行7/9日丨醉美伊犁&吐鲁番双套餐',
tagList: ['国内游','7-9天','12岁+'],
priceDiscount: 688.99,
priceOrigin: 1200,
applyNum: 4168,
},
{
id: '002',
image: '/static/image/temp-20.png',
title: '坝上双草原6日|乌兰布统+锡林郭勒+长城',
tagList: ['国内游','7-9天','12岁+'],
priceDiscount: 688.99,
priceOrigin: 1200,
applyNum: 4168,
},
{
id: '003',
image: '/static/image/temp-20.png',
title: '牛湖线探秘 | 清远牛湖线徒步,探秘天坑与大草原',
tagList: ['国内游','7-9天','12岁+'],
priceDiscount: 688.99,
priceOrigin: 1200,
applyNum: 4168,
},
{
id: '004',
image: '/static/image/temp-20.png',
title: '低海拔藏区草原,汉藏文化大穿越',
tagList: ['国内游','7-9天','12岁+'],
priceDiscount: 688.99,
priceOrigin: 1200,
applyNum: 4168,
},
{
id: '005',
image: '/static/image/temp-20.png',
title: '新丝路到敦煌7日 | 甘青轻松穿越,沙漠+草原',
tagList: ['国内游','7-9天','12岁+'],
priceDiscount: 688.99,
priceOrigin: 1200,
applyNum: 4168,
},
{
id: '006',
image: '/static/image/temp-20.png',
title: '呼伦贝尔6/8日|经典or环线双套餐可选',
tagList: ['国内游','7-9天','12岁+'],
priceDiscount: 688.99,
priceOrigin: 1200,
applyNum: 4168,
},
]
},
async initList() {
console.log('queryParams', this.queryParams)


+ 10
- 11
pages/index/center.vue View File

@ -9,18 +9,18 @@
<view class="flex user">
<!-- 用户信息 -->
<template v-if="isLogin">
<view class="user-avatar">
<!-- todo: check key -->
<image class="user-avatar-img" src="@/pages_order/static/temp-30.png" mode="scaleToFill"></image>
<view class="user-avatar" v-if="userInfo.headImage">
<image class="user-avatar-img" :src="userInfo.headImage" mode="scaleToFill"></image>
</view>
<view class="user-avatar is-default" v-else>
<image class="user-avatar-img" src="@/pages_order/static/center/avatar-default.png" mode="scaleToFill"></image>
</view>
<view class="user-info">
<!-- todo: check key -->
<view class="flex user-info-name">
<view class="highligt">战斗世界</view>
<view class="light">ID5625354</view>
<view class="highligt" v-if="userInfo.nickName">{{ userInfo.nickName || '' }}</view>
<view class="light">{{ `ID:${userInfo.id}` }}</view>
</view>
<!-- todo: check key -->
<view class="user-info-desc">手机号19989674531</view>
<view class="user-info-desc" v-if="userInfo.phone">{{ `手机号${userInfo.phone}` }}</view>
</view>
</template>
<template v-else>
@ -129,8 +129,6 @@
computed: {
...mapState(['userInfo', 'configList']),
isLogin() {
// todo: delete
return true
return this.userInfo && this.userInfo.id
}
},
@ -239,7 +237,8 @@
&-name {
justify-content: flex-start;
column-gap: 16rpx;
flex-wrap: wrap;
gap: 16rpx;
font-family: PingFang SC;
color: #FFFFFF;


+ 34
- 36
pages/index/growing.vue View File

@ -60,48 +60,46 @@
return {
keyword: '',
isFocusSearch: false,
// todo
mixinsListApi: '',
queryParams: {
pageNo: 1,
pageSize: 10,
userId: '',
},
}
},
computed: {
...mapState(['memberInfo']),
mixinsListApi() {
return this.queryParams.userId ? 'queryExperienceList' : ''
},
},
onLoad() {
if(uni.getStorageSync('token')){
this.$store.commit('getUserInfo')
}
},
onShow() {
// todo: set queryParams.userId by memberInfo
if (!this.memberInfo && this.userInfo.id) {
this.$store.commit('setMemberInfo', this.userInfo)
}
this.queryParams.userId = this.memberInfo.id
this.getData()
},
methods: {
// todo: delete
getData() {
this.list = [
{
id: '001',
name: '新疆天山行7/9日丨醉美伊犁&吐鲁番双套餐',
image: [
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
],
createTime: '2025-07-12',
},
{
id: '002',
name: '仙踪新昌·韩妃江古道|邂逅“江南小桂林”',
image: [
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
],
createTime: '2025-06-18',
},
{
id: '003',
name: '山水石窟·大佛寺|江南佛窟造像,新昌山水轻徒',
image: [
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
],
createTime: '2025-06-15',
},
]
getDataThen(records) {
this.list = records.map(item => {
const { id, name, image, createTime } = item
return {
id,
// todo: check key
name,
image: image?.split?.(',') || [],
createTime
}
})
},
search() {
console.log('search', this.keyword)


+ 4
- 1
pages/index/index.vue View File

@ -103,6 +103,9 @@
}
},
onLoad() {
if(uni.getStorageSync('token')){
this.$store.commit('getUserInfo')
}
},
computed: {
searchStyle() {
@ -155,7 +158,7 @@
top: 0;
left: 0;
width: 100%;
padding: 100rpx 32rpx calc(120rpx + env(safe-area-inset-bottom) + 100rpx) 32rpx;
padding: 100rpx 32rpx calc(120rpx + env(safe-area-inset-bottom) + 32rpx) 32rpx;
box-sizing: border-box;
}


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

@ -112,6 +112,11 @@
mixinsListApi: '',
}
},
onLoad() {
if(uni.getStorageSync('token')){
this.$store.commit('getUserInfo')
}
},
onShow() {
// todo: refresh is partner?
},


+ 2
- 4
pages_order/auth/wxLogin.vue View File

@ -3,10 +3,8 @@
<view class="flex flex-column content">
<!-- todo: check key -->
<image class="logo" src="@/pages_order/static/temp-29.png" mode="widthFix"></image>
<!-- todo: check key -->
<view class="name">鸿宇研学生</view>
<image class="logo" :src="configList.config_logo" mode="widthFix"></image>
<view class="name">{{ configList.app_name }}</view>
<button class="btn btn-login flex" @click="wxLogin" > </button>


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

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


+ 3
- 3
pages_order/comment/commentCard.vue View File

@ -24,15 +24,15 @@
<view class="section score">
<view class="flex score-item">
<view class="score-item-label">行程</view>
<formRate :value="data.tripNum" :readonly="true"></formRate>
<formRate :value="data.processScore" :readonly="true"></formRate>
</view>
<view class="flex score-item">
<view class="score-item-label">景点</view>
<formRate :value="data.spotNum" :readonly="true"></formRate>
<formRate :value="data.spotScore" :readonly="true"></formRate>
</view>
<view class="flex score-item">
<view class="score-item-label">导师</view>
<formRate :value="data.mentorNum" :readonly="true"></formRate>
<formRate :value="data.teacherScore" :readonly="true"></formRate>
</view>
</view>
<view class="section operate">


+ 29
- 19
pages_order/comment/commentPopup.vue View File

@ -18,31 +18,31 @@
</view>
<view class="section">
<view class="form-item">
<uv-form-item prop="tripNum" :customStyle="formItemStyle">
<uv-form-item prop="processScore" :customStyle="formItemStyle">
<view class="flex row">
<view class="form-item-label">行程</view>
<view class="form-item-content">
<formRate v-model="form.tripNum"></formRate>
<formRate v-model="form.processScore"></formRate>
</view>
</view>
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item prop="spotNum" :customStyle="formItemStyle">
<uv-form-item prop="spotScore" :customStyle="formItemStyle">
<view class="flex row">
<view class="form-item-label">景点</view>
<view class="form-item-content">
<formRate v-model="form.spotNum"></formRate>
<formRate v-model="form.spotScore"></formRate>
</view>
</view>
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item prop="mentorNum" :customStyle="formItemStyle">
<uv-form-item prop="teacherScore" :customStyle="formItemStyle">
<view class="flex row">
<view class="form-item-label">导师</view>
<view class="form-item-content">
<formRate v-model="form.mentorNum"></formRate>
<formRate v-model="form.teacherScore"></formRate>
</view>
</view>
</uv-form-item>
@ -89,23 +89,23 @@
// todo: fetch
detail: {},
form: {
tripNum: null,
spotNum: null,
mentorNum: null,
processScore: null,
spotScore: null,
teacherScore: null,
content: null,
},
rules: {
'tripNum': {
'processScore': {
type: 'number',
required: true,
message: '请为行程打分',
},
'spotNum': {
'spotScore': {
type: 'number',
required: true,
message: '请为景点打分',
},
'mentorNum': {
'teacherScore': {
type: 'number',
required: true,
message: '请为导师打分',
@ -124,15 +124,17 @@
async getData() {
// todo: fetch order product
},
async open(id) {
async open(id, detail) {
this.id = id
await this.getData()
this.detail = detail
// todo: fetch order product
// await this.getData()
this.form = {
tripNum: null,
spotNum: null,
mentorNum: null,
processScore: null,
spotScore: null,
teacherScore: null,
content: null,
}
@ -152,13 +154,21 @@
await this.$refs.form.validate()
const {
processScore,
spotScore,
teacherScore,
content,
} = this.form
const params = {
orderId: this.id,
processScore,
spotScore,
teacherScore,
content,
}
// todo: fetch
// await this.$fetch('updateAddress', params)
await this.$fetch('addComment', params)
uni.showToast({
icon: 'success',


+ 12
- 10
pages_order/comment/commentRecords.vue View File

@ -37,21 +37,23 @@
data() {
return {
// todo
mixinsListApi: '',
// mixinsListApi: '',
list: [],
total: 0,
}
},
onShow() {
console.log('onShow')
},
onLoad(arg) {
console.log('onLoad')
const { productId } = arg
this.queryParams.productId = productId
onLoad() {
this.getData()
},
methods: {
async getData() {
try {
this.list = await this.$fetch('queryMyCommentList')
this.total = this.list.length
} catch (err) {
}
},
},
}
</script>


+ 61
- 26
pages_order/comment/recordFormPopup.vue View File

@ -10,18 +10,17 @@
<uv-form
ref="form"
:model="form"
:rules="rules"
errorType="toast"
>
<view class="form-item">
<uv-form-item prop="project" :customStyle="formItemStyle">
<uv-form-item prop="activityId" :customStyle="formItemStyle">
<view class="form-item-label">
<image class="icon" src="@/pages_order/static/icon-require.png" mode="widthFix"></image>
关联项目
</view>
<view class="form-item-content">
<view class="flex row" @click="openRelatePojectPicker">
<view v-if="form.project" class="text">{{ projectDesc }}</view>
<view v-if="form.activityId" class="text">{{ projectDesc }}</view>
<view v-else class="text placeholder">请选择关联项目</view>
<uv-icon name="arrow-right" color="#C6C6C6" size="32rpx"></uv-icon>
</view>
@ -30,31 +29,31 @@
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item prop="tripNum" :customStyle="formItemStyle">
<uv-form-item prop="processScore" :customStyle="formItemStyle">
<view class="flex row">
<view class="form-item-label">行程</view>
<view class="form-item-content">
<formRate v-model="form.tripNum"></formRate>
<formRate v-model="form.processScore"></formRate>
</view>
</view>
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item prop="spotNum" :customStyle="formItemStyle">
<uv-form-item prop="spotScore" :customStyle="formItemStyle">
<view class="flex row">
<view class="form-item-label">景点</view>
<view class="form-item-content">
<formRate v-model="form.spotNum"></formRate>
<formRate v-model="form.spotScore"></formRate>
</view>
</view>
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item prop="mentorNum" :customStyle="formItemStyle">
<uv-form-item prop="teacherScore" :customStyle="formItemStyle">
<view class="flex row">
<view class="form-item-label">导师</view>
<view class="form-item-content">
<formRate v-model="form.mentorNum"></formRate>
<formRate v-model="form.teacherScore"></formRate>
</view>
</view>
</uv-form-item>
@ -89,6 +88,8 @@
</template>
<script>
import { mapState } from 'vuex'
import reloateProjectPopup from '@/pages_order/components/reloateProjectPopup.vue'
import formTextarea from '@/pages_order/components/formTextarea.vue'
import formUpload from '@/pages_order/components/formUpload.vue'
@ -105,24 +106,22 @@
return {
isShow: false,
form: {
project: null,
tripNum: null,
spotNum: null,
mentorNum: null,
activityId: null,
processScore: null,
spotScore: null,
teacherScore: null,
images: [],
texts: [],
},
rules: {
// todo
},
projects: [],
questions: [],
}
},
computed: {
...mapState(['userInfo']),
projectDesc() {
const { project } = this.form
const target = this.projects?.find?.(item => item.id === project)
const { activityId } = this.form
const target = this.projects?.find?.(item => item.id === activityId)
return target?.name || ''
},
@ -176,6 +175,26 @@
},
]
},
setRules() {
const rules = {
'activityId': {
type: 'string',
required: true,
message: '请选择关联项目',
},
}
// todo: check
this.questions.forEach((item, index) => {
rules[`texts[${index}]`] = {
type: 'string',
required: true,
message: `请回答“${item.label}`,
}
})
this.$refs.form.setRules(this.rules)
},
async open() {
await this.getData()
@ -183,10 +202,10 @@
const texts = this.questions.map(() => '')
this.form = {
project: null,
tripNum: null,
spotNum: null,
mentorNum: null,
activityId: null,
processScore: null,
spotScore: null,
teacherScore: null,
images: [],
texts,
}
@ -198,25 +217,41 @@
},
onPopupChange(e) {
this.isShow = e.show
// todo: need settimeout?
this.setRules()
},
openRelatePojectPicker() {
this.$refs.reloateProjectPopup.open(this.form.project?.id || null)
this.$refs.reloateProjectPopup.open(this.form.activityId?.id || null)
},
onRelateProjectChange(id) {
this.form.project = id
this.form.activityId = id
},
async onPublish() {
try {
await this.$refs.form.validate()
const {
activityId,
processScore,
spotScore,
teacherScore,
images,
texts,
} = this.form
const params = {
// todo: check
userId: this.userInfo.id,
activityId,
processScore,
spotScore,
teacherScore,
image: images.join(','),
content: texts.join('\r\n') // todo: check
}
// todo: fetch
// await this.$fetch('updateAddress', params)
await this.$fetch('addExperience', params)
uni.showToast({
icon: 'success',


+ 1
- 0
pages_order/coupon/couponList/couponCard.vue View File

@ -88,6 +88,7 @@
font-size: 30rpx;
font-weight: 500;
line-height: 1.4;
color: #FFFFFF;
background: linear-gradient(to right, #21FEEC, #019AF9);
border: 2rpx solid #00A9FF;
border-radius: 28rpx;


+ 2
- 38
pages_order/coupon/couponList/index.vue View File

@ -28,52 +28,16 @@
},
data() {
return {
// todo: check key
mixinsListApi: '',
mixinsListApi: 'queryCouponList',
queryParams: {
pageNo: 1,
pageSize: 10,
status: 0,
},
selectedId: null,
}
},
methods: {
// todo: delete
getData() {
this.list = [
{
id: '001',
label: '专属福利】20元红包',
price: 20,
validTime: '2026-04-28',
},
{
id: '002',
label: '专属福利】400元红包',
price: 400,
validTime: '2026-04-28',
},
{
id: '003',
label: '专属福利】400元红包',
price: 400,
validTime: '2026-04-28',
},
{
id: '004',
label: '专属福利】400元红包',
price: 400,
validTime: '2026-04-28',
},
{
id: '005',
label: '专属福利】400元红包',
price: 400,
validTime: '2026-04-28',
},
]
},
onSelect(id) {
console.log('onSelect', id)
this.selectedId = id


+ 3
- 3
pages_order/coupon/couponSelect/couponCard.vue View File

@ -4,11 +4,11 @@
<uv-radio :name="data.id"></uv-radio>
</view>
<view class="flex price">
¥<view class="highlight">{{ data.price }}</view>
¥<view class="highlight">{{ data.discountAmount }}</view>
</view>
<view class="flex flex-column info">
<view class="title">{{ data.label }}</view>
<view class="desc">{{ `有效期至 ${data.validTime}` }}</view>
<view class="title">{{ data.title }}</view>
<view class="desc">{{ `有效期至 ${data.validDate}` }}</view>
</view>
</view>
</template>


+ 2
- 38
pages_order/coupon/couponSelect/index.vue View File

@ -38,11 +38,11 @@
},
data() {
return {
// todo: check key
mixinsListApi: '',
mixinsListApi: 'queryCouponList',
queryParams: {
pageNo: 1,
pageSize: 10,
status: 0,
},
selectedId: null,
}
@ -67,42 +67,6 @@
this.$store.commit('setCouponInfo', target)
},
methods: {
// todo: delete
getData() {
this.list = [
{
id: '001',
label: '专属福利】20元红包',
price: 20,
validTime: '2026-04-28',
},
{
id: '002',
label: '专属福利】400元红包',
price: 400,
validTime: '2026-04-28',
},
{
id: '003',
label: '专属福利】400元红包',
price: 400,
validTime: '2026-04-28',
},
{
id: '004',
label: '专属福利】400元红包',
price: 400,
validTime: '2026-04-28',
},
{
id: '005',
label: '专属福利】400元红包',
price: 400,
validTime: '2026-04-28',
},
]
},
},
}
</script>


+ 16
- 0
pages_order/growing/activity/index.vue View File

@ -112,6 +112,22 @@
},
methods: {
async getData() {
try {
const result = await this.$fetch('queryExperienceById', { recordId: this.id })
const { image, thoughts } = result
this.detail = {
highlights: image?.split?.(',') || [],
// todo: check key
thoughts,
// todo: check key about ""
}
} catch (err) {
}
return
// todo
this.detail = {


+ 20
- 18
pages_order/live/formPopup.vue View File

@ -14,14 +14,14 @@
errorType="toast"
>
<view class="form-item">
<uv-form-item prop="project" :customStyle="formItemStyle">
<uv-form-item prop="activityId" :customStyle="formItemStyle">
<view class="form-item-label">
<image class="icon" src="@/pages_order/static/icon-require.png" mode="widthFix"></image>
关联项目
</view>
<view class="form-item-content">
<view class="flex row" @click="openRelatePojectPicker">
<view v-if="form.project" class="text">{{ projectDesc }}</view>
<view v-if="form.activityId" class="text">{{ projectDesc }}</view>
<view v-else class="text placeholder">请选择关联项目</view>
<uv-icon name="arrow-right" color="#C6C6C6" size="32rpx"></uv-icon>
</view>
@ -75,14 +75,14 @@
data() {
return {
form: {
project: null,
activityId: null,
area: null,
latitude: null,
longitude: null,
images: [],
},
rules: {
'project': {
'activityId': {
type: 'string',
required: true,
message: '请选择关联项目',
@ -104,8 +104,8 @@
},
computed: {
projectDesc() {
const { project } = this.form
const target = this.projects?.find?.(item => item.id === project)
const { activityId } = this.form
const target = this.projects?.find?.(item => item.id === activityId)
return target?.name || ''
},
@ -160,18 +160,15 @@
]
},
async open(id) {
// todo: auto bind project by id?
// todo: auto bind activityId by id?
await this.getData()
const texts = this.questions.map(() => '')
this.form = {
project: null,
tripNum: null,
spotNum: null,
mentorNum: null,
activityId: null,
area: null,
latitude: null,
longitude: null,
images: [],
texts,
}
this.$refs.popup.open()
@ -180,10 +177,10 @@
this.$refs.popup.close()
},
openRelatePojectPicker() {
this.$refs.reloateProjectPopup.open(this.form.project?.id || null)
this.$refs.reloateProjectPopup.open(this.form.activityId?.id || null)
},
onRelateProjectChange(id) {
this.form.project = id
this.form.activityId = id
},
//
selectAddr() {
@ -212,13 +209,18 @@
await this.$refs.form.validate()
const {
activityId,
area,
images,
} = this.form
const params = {
activityId,
address: area,
image: images.join(',')
}
// todo: fetch
// await this.$fetch('updateAddress', params)
await this.$fetch('addImage', params)
uni.showToast({
icon: 'success',


+ 30
- 77
pages_order/live/index.vue View File

@ -1,14 +1,14 @@
<template>
<view class="page__view highlight">
<navbar :title="detail.title" leftClick @leftClick="$utils.navigateBack" />
<navbar :title="liveInfo.title" leftClick @leftClick="$utils.navigateBack" />
<view class="header">
<image class="cover-img" :src="detail.image" mode="widthFix"></image>
<image class="cover-img" :src="liveInfo.url" mode="widthFix"></image>
<view class="flex" style="padding: 40rpx 40rpx 0 40rpx;">
<view class="flex flex-column">
<view class="title">{{ detail.title }}</view>
<view class="tag">{{ detail.createTime }}</view>
<view class="title">{{ liveInfo.title }}</view>
<view class="tag">{{ liveInfo.createTime }}</view>
</view>
<view v-if="isManager" class="flex operate">
<view class="btn btn-add" @click="onAdd">新增记录</view>
@ -25,7 +25,7 @@
</view>
<view class="info">
<view class="flex title">
<view>{{ item.name }}</view>
<view>{{ item.createBy }}</view>
<image class="icon" src="@/static/image/icon-location.png" mode="widthFix"></image>
<view class="address text-ellipsis">{{ item.address }}</view>
</view>
@ -34,7 +34,7 @@
</view>
<view class="section-content record">
<view class="record-item" v-for="(image, imgIdx) in item.images" :key="imgIdx">
<image class="img" :src="image" mode="scaleToFill"></image>
<image class="img" :src="image" mode="aspectFill"></image>
</view>
</view>
</view>
@ -47,6 +47,8 @@
</template>
<script>
import { mapState } from 'vuex'
import mixinsList from '@/mixins/list.js'
import SYStackedCarousel from '@/uni_modules/SY-StackedCarousel/components/SY-StackedCarousel/SY-StackedCarousel.vue'
@ -60,93 +62,44 @@
},
data() {
return {
id: null,
detail: {},
bannerList: [],
current: 0,
queryParams: {
pageNo: 1,
pageSize: 10,
id: '',
imageId: '',
},
// todo
mixinsListApi: '',
mixinsListApi: 'queryImageContentList',
// todo: fetch
isManager: false,
isManager: true,
}
},
computed: {
swiperCurrent() {
return this.bannerList[this.current]
},
...mapState(['liveInfo']),
},
onLoad(arg) {
const { id } = arg
this.id = id
this.fetchDetail()
this.queryParams.id = id
this.queryParams.imageId = id
this.getData()
},
methods: {
async fetchDetail() {
// todo: fetch
this.detail = {
id: '001',
image: '/static/image/temp-20.png',
title: '趣玩新加坡',
createTime: '2025-04-18',
}
},
// todo: delete
getData() {
this.list = [
{
id: '001',
avatar: '/pages_order/static/temp-30.png',
name: '战斗世界',
address: '241 Orchard Road, Singapore 238863',
createTime: '2023-04-18 12:00:00',
images: [
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
]
},
{
id: '001',
avatar: '/pages_order/static/temp-30.png',
name: '战斗世界',
address: '10 Bayfront Avenue, Singapore 018956',
createTime: '2023-04-18 12:00:00',
images: [
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
]
},
]
},
clickHandler(item, index) {
console.log("item: ", item);
console.log("index: ", index);
this.current = index
},
changeHandler(index) {
console.log("当前触发change事件,返回索引: ", index);
getCoverImage(image) {
return image?.split?.(',')?.[0]
},
getDataThen(records) {
this.list = records.map(item => {
const { id, avatar, createBy, address, image, createTime } = item
return {
id,
// todo: check key
avatar: avatar || '/pages_order/static/center/avatar-default.png',
createBy,
address,
images: image?.split?.(',') || [],
createTime,
}
})
},
onAdd() {
this.$refs.formPopup.open()


+ 21
- 62
pages_order/live/list.vue View File

@ -6,7 +6,7 @@
<view class="swiper">
<SYStackedCarousel
height="536rpx"
:images="bannerList"
:images="list"
:current="current"
:autoplay="true"
horizontalMargin="25"
@ -42,7 +42,7 @@
</view>
<view class="section-content record">
<view class="record-item" v-for="(image, imgIdx) in item.images" :key="imgIdx">
<image class="img" :src="image" mode="scaleToFill"></image>
<image class="img" :src="image" mode="aspectFill"></image>
</view>
</view>
</view>
@ -70,79 +70,37 @@
},
data() {
return {
bannerList: [],
current: 0,
queryParams: {
pageNo: 1,
pageSize: 10,
id: '',
},
// todo
mixinsListApi: '',
mixinsListApi: 'queryImageList',
// todo: fetch
isManager: true,
}
},
computed: {
swiperCurrent() {
return this.bannerList[this.current]
return this.list[this.current]
},
},
onLoad() {
this.fetchBanner()
async onLoad() {
this.getData()
},
methods: {
async fetchBanner() {
this.bannerList = [
{
url: '/static/image/temp-20.png',
title: '趣玩新加坡',
createTime: '2025-04-18',
},
{
url: '/static/image/temp-20.png',
title: '坝上双草原',
createTime: '2025-04-18',
},
{
url: '/static/image/temp-20.png',
title: '牛湖线',
createTime: '2025-04-18',
},
]
},
// todo: delete
getData() {
this.list = [
{
id: '001',
title: '桂林深度游',
images: [
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
]
},
{
id: '002',
title: '西双版纳雨林10+体验',
images: [
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
'/pages_order/static/temp-38.png',
]
},
]
getDataThen(records) {
this.list = records.map(item => {
const { id, image, activityId_dictText, createTime } = item
const images = image?.split?.(',') || []
return {
id,
url: images?.[0],
images,
title: activityId_dictText,
createTime: this.$dayjs(createTime).format('YYYY-MM-DD'),
}
})
},
clickHandler(item, index) {
console.log("item: ", item);
console.log("index: ", index);
this.current = index
},
changeHandler(index) {
@ -155,6 +113,7 @@
this.$refs.formPopup.open()
},
showAll(id) {
this.$store.commit('setLiveInfo', this.list.find(item => item.id === id))
this.$utils.navigateTo(`/pages_order/live/index?id=${id}`)
},
},


+ 15
- 7
pages_order/member/memberApplyCard.vue View File

@ -7,7 +7,7 @@
</view>
<view class="row">
<view class="row-label">申请人ID</view>
<view class="row-content">{{ data.userId }}</view>
<view class="row-content">{{ data.bindId }}</view>
</view>
<view class="row">
<view class="row-label">申请时间</view>
@ -44,13 +44,21 @@
}
},
methods: {
onReject() {
// todo: fetch reject
this.$emit('submitted')
async fetchUpdate(status) {
try {
await this.$fetch('updateBind', { id: this.data.id, status }) // (status)0- 1- 2-
return true
} catch (err) {
return false
}
},
async onReject() {
const succ = await this.fetchUpdate(2)
succ && this.$emit('submitted')
},
onConfirm() {
// todo: fetch confirm
this.$emit('submitted')
async onConfirm() {
const succ = await this.fetchUpdate(1)
succ && this.$emit('submitted')
},
},
}


+ 11
- 9
pages_order/member/memberBind.vue View File

@ -16,7 +16,7 @@
errorType="toast"
>
<view class="form-item">
<uv-form-item prop="id" :customStyle="formItemStyle">
<uv-form-item prop="bindId" :customStyle="formItemStyle">
<view class="form-item-label">绑定人ID</view>
<view class="form-item-content">
<view class="flex search">
@ -37,7 +37,7 @@
<view class="form-item" v-for="item in list" :key="item.id">
<view
:class="['flex', 'list-item', item.id === form.id ? 'is-active' : '']"
@click="onSelect"
@click="onSelect(item.id)"
>
<view class="avatar">
<image class="img" :src="item.avatar" mode="scaleToFill"></image>
@ -55,7 +55,7 @@
</view>
<view class="bottom">
<button class="btn" @click="onSubmit">提现</button>
<button class="btn" @click="onSubmit">申请</button>
</view>
</view>
@ -82,10 +82,10 @@
// todo
mixinsListApi: '',
form: {
id: null,
bindId: null,
},
rules: {
'id': {
'bindId': {
type: 'string',
required: true,
message: '请选择绑定人',
@ -99,21 +99,23 @@
this.queryParams.title = this.keyword
this.getData()
},
onSelect(id) {
this.form.id = id
onSelect(bindId) {
this.form.bindId = bindId
},
async onSubmit() {
try {
await this.$refs.form.validate()
const {
bindId,
} = this.form
const params = {
bindId,
userId: this.userInfo.id,
}
// todo: fetch
// await this.$fetch('updateAddress', params)
await this.$fetch('addBind', params)
uni.showToast({
icon: 'success',


+ 1
- 1
pages_order/member/memberCard.vue View File

@ -11,7 +11,7 @@
</view>
<view class="row">
<view class="row-label">申请人ID</view>
<view class="row-content">{{ data.userId }}</view>
<view class="row-content">{{ data.bindId }}</view>
</view>
</view>
</view>


+ 9
- 54
pages_order/member/memberList.vue View File

@ -8,7 +8,7 @@
<view class="tabs">
<uv-tabs
:list="tabs"
:current="current"
:current="queryParams.status"
:scrollable="false"
lineColor="#00A9FF"
lineWidth="48rpx"
@ -32,7 +32,7 @@
</view>
<view class="list">
<template v-if="current == 0">
<template v-if="queryParams.status == 0">
<view class="list-item" v-for="item in list" :key="item.id">
<memberApplyCard :data="item" @submitted="getData"></memberApplyCard>
</view>
@ -68,9 +68,12 @@
{ name: '绑定申请' },
{ name: '已绑定' },
],
// todo
mixinsListApi: '',
current: 0,
queryParams: {
pageNo: 1,
pageSize: 10,
status: 0, // (status)0- 1- 2-
},
mixinsListApi: 'queryBindList',
}
},
onShow() {
@ -80,57 +83,9 @@
this.clickTabs({ index: arg.index || 0 })
},
methods: {
// todo: delete
getData() {
this.list = [
{
id: '001',
name: '周小艺',
userId: '15558661691',
type: 0,
createTime: '2025-04-28 08:14',
},
{
id: '002',
name: '周小艺',
userId: '15558661691',
type: 0,
createTime: '2025-04-28 08:14',
},
{
id: '003',
name: '周小艺',
userId: '15558661691',
type: 1,
createTime: '2025-04-28 08:14',
},
{
id: '004',
name: '周小艺',
userId: '15558661691',
type: 0,
createTime: '2025-04-28 08:14',
},
{
id: '005',
name: '周小艺',
userId: '15558661691',
type: 0,
createTime: '2025-04-28 08:14',
},
]
},
//tab
clickTabs({ index }) {
console.log('clickTabs')
this.current = index
if (index == 0) {
delete this.queryParams.status
} else {
this.queryParams.status = index - 1
}
this.queryParams.status = index
this.getData()
},
},


+ 3
- 43
pages_order/member/switch.vue View File

@ -11,7 +11,6 @@
size="36rpx"
iconSize="36rpx"
activeColor="#00A9FF"
@change="onRadioChange"
>
<view class="list-item" v-for="item in list" :key="item.id">
<memberCard
@ -40,12 +39,12 @@
},
data() {
return {
// todo: check key
mixinsListApi: '',
queryParams: {
pageNo: 1,
pageSize: 10,
status: 1, // (status)0- 1- 2-
},
mixinsListApi: 'queryBindList',
selectedId: null,
}
},
@ -54,7 +53,7 @@
},
onLoad(arg) {
if (this.memberInfo?.id) {
this.memberInfo = this.memberInfo.id
this.selectedId = this.memberInfo.id
}
this.getData()
@ -69,49 +68,10 @@
this.$store.commit('setMemberInfo', target)
},
methods: {
// todo: delete
getData() {
this.list = [
{
id: '001',
name: '周小艺',
userId: '15558661691',
type: 0,
},
{
id: '002',
name: '周小艺',
userId: '15558661691',
type: 0,
},
{
id: '003',
name: '周小艺',
userId: '15558661691',
type: 1,
},
{
id: '004',
name: '周小艺',
userId: '15558661691',
type: 0,
},
{
id: '005',
name: '周小艺',
userId: '15558661691',
type: 0,
},
]
},
onSelect(id) {
console.log('onSelect', id)
this.selectedId = id
},
onRadioChange(e) {
console.log('onRadioChange', e)
},
},
}
</script>


+ 28
- 22
pages_order/order/orderConfirm/infoPopup.vue View File

@ -19,28 +19,24 @@
<image class="img" src="@/static/image/icon-arrow-right.png" mode="widthFix"></image>
</button>
</view>
<timeCalendarSelect ref="timeCalendarSelect" v-model="form.time" :options="data.timeOptions"></timeCalendarSelect>
<timeCalendarSelect ref="timeCalendarSelect" v-model="form.time" :options="data.dateList"></timeCalendarSelect>
<view class="flex section-content">
<timeOptionsSelect style="width: calc(100vw - 40rpx*2);"
v-model="form.time"
:options="data.timeOptions"
:options="data.dateList"
></timeOptionsSelect>
</view>
</uv-form-item>
</view>
<view class="section">
<uv-form-item prop="adults" :customStyle="formItemStyle">
<uv-form-item prop="prices" :customStyle="formItemStyle">
<view class="flex section-header">
<view>选择人数</view>
</view>
<view class="flex section-content">
<peopleNumberInput style="width: calc(100vw - 40rpx*2);"
:adults.sync="form.adults"
:teenager.sync="form.teenager"
:child.sync="form.child"
:adultsPrice="selectTimeObj.adultsPrice"
:teenagerPrice="selectTimeObj.teenagerPrice"
:childPrice="selectTimeObj.childPrice"
v-model="form.prices"
:options="priceList"
></peopleNumberInput>
</view>
</uv-form-item>
@ -77,6 +73,12 @@
import timeCalendarSelect from '@/pages_order/order/orderConfirm/timeCalendarSelect.vue'
import peopleNumberInput from '@/pages_order/order/orderConfirm/peopleNumberInput.vue'
const TYPE_INDEX_MAPPING = {
'成人': 0,
'青少年': 1,
'儿童': 2,
}
export default {
components: {
timeOptionsSelect,
@ -96,25 +98,29 @@
options: [],
form: {
time: null,
adults: 0,
teenager: 0,
child: 0,
prices: [],
members: [],
},
formItemStyle: { padding: 0 },
}
},
computed : {
...mapState(['configList', 'travelerList']),
selectTimeObj() {
...mapState(['configList', 'userInfo', 'travelerList']),
priceList() {
const { time: id } = this.form
const { timeOptions } = this.data
const { dateList } = this.data
let priceList = dateList?.[0]?.priceList || []
if (id) {
return timeOptions?.find?.(option => option.id === id) || {}
priceList = dateList?.find?.(option => option.id === id)?.priceList || []
}
return timeOptions?.[0] || {}
priceList.sort((a, b) => {
return TYPE_INDEX_MAPPING[a.period_dictText] - TYPE_INDEX_MAPPING[b.period_dictText]
})
return priceList
},
},
watch: {
@ -144,13 +150,12 @@
required: true,
message: '请选择团期',
},
'adults': {
type: 'number',
required: true,
'prices': {
type: 'array',
message: '请选择人数',
validator: (rule, value, callback) => {
if (adults || teenager || child) {
if (value.some(num => num > 0)) {
return true
}
@ -169,7 +174,8 @@
},
async getDefaultMembers() {
try {
return (await this.$fetch('queryTouristList', { isDefault: '1' })).records
// todo: check params
return (await this.$fetch('queryTouristList', { pageNo: 1, pageSize: 1000, userId: this.userInfo.id, isDefault: '1' })).records
} catch (err) {
return []
}


+ 34
- 96
pages_order/order/orderConfirm/peopleNumberInput.vue View File

@ -1,69 +1,19 @@
<template>
<view class="input__view" :style="style">
<view class="flex row">
<view class="flex row" v-for="(item, index) in options" :key="item.id">
<view class="flex row-label">
<view class="title">成人</view>
<view class="desc">(18周岁以上)</view>
<view class="title">{{ item.period_dictText }}</view>
<!-- todo: check key -->
<view class="desc" v-if="getTypeDesc(item.period_dictText)">{{ `(${getTypeDesc(item.period_dictText)})` }}</view>
<view class="flex price">
<text>¥</text>
<text class="highlight">{{ adultsPrice }}</text>
<text class="highlight">{{ item.price }}</text>
</view>
</view>
<view class="row-content">
<uv-number-box
v-model="adultsNum"
:min="0"
:integer="true"
:inputWidth="68"
bgColor="transparent"
:iconStyle="{
background: '#F7F8FA',
fontSize: '13px',
lineHeight: 1,
padding: '12px',
borderRadius: '50%',
}"
></uv-number-box>
</view>
</view>
<view class="flex row">
<view class="flex row-label">
<view class="title">青少年</view>
<view class="desc">(14周岁以上)</view>
<view class="flex price">
<text>¥</text>
<text class="highlight">{{ teenagerPrice }}</text>
</view>
</view>
<view class="row-content">
<uv-number-box
v-model="teenagerNum"
:min="0"
:integer="true"
:inputWidth="68"
bgColor="transparent"
:iconStyle="{
background: '#F7F8FA',
fontSize: '13px',
lineHeight: 1,
padding: '12px',
borderRadius: '50%',
}"
></uv-number-box>
</view>
</view>
<view class="flex row">
<view class="flex row-label">
<view class="title">儿童</view>
<view class="desc">(14周岁以下)</view>
<view class="flex price">
<text>¥</text>
<text class="highlight">{{ childPrice }}</text>
</view>
</view>
<view class="row-content">
<uv-number-box
v-model="childNum"
:value="value[index]"
@input="onInput(index, $event)"
:min="0"
:integer="true"
:inputWidth="68"
@ -82,31 +32,25 @@
</template>
<script>
const TYPE_DESC = {
'成人': '(18周岁以上)',
'青少年': '(14周岁以上)',
'儿童': '(14周岁以下)',
}
export default {
props: {
adults: {
type: Number,
default: 0,
},
teenager: {
type: Number,
default: 0,
},
child: {
type: Number,
default: 0,
},
adultsPrice: {
type: Number,
default: 0,
},
teenagerPrice: {
type: Number,
default: 0,
value: {
type: Array,
default() {
return []
}
},
childPrice: {
type: Number,
default: 0,
options: {
type: Array,
default() {
return []
}
},
style: {
type: String,
@ -114,29 +58,23 @@
},
},
computed: {
adultsNum: {
prices: {
set(val) {
this.$emit('update:adults', val)
this.$emit('input', val)
},
get() {
return this.adults
return this.value
}
},
teenagerNum: {
set(val) {
this.$emit('update:teenager', val)
},
get() {
return this.teenager
}
},
methods: {
onInput(index, value) {
let prices = [...this.prices]
prices[index] = value
this.prices = prices
},
childNum: {
set(val) {
this.$emit('update:child', val)
},
get() {
return this.child
}
getTypeDesc(type) {
return TYPE_DESC[type]
},
},
}


+ 2
- 3
pages_order/order/orderConfirm/timeOptionsSelect.vue View File

@ -8,9 +8,9 @@
>
<view class="option-item-content">
<view class="flex time">
<view class="time-val">{{ item.startDate }}</view>
<view class="time-val">{{ $dayjs(item.startDate).format('MM/DD') }}</view>
<view class="time-split">-</view>
<view class="time-val">{{ item.endDate }}</view>
<view class="time-val">{{ $dayjs(item.endDate).format('MM/DD') }}</view>
</view>
<view class="flex price">
<view class="price-val">
@ -126,7 +126,6 @@
.price {
margin-top: 4rpx;
justify-content: flex-start;
align-items: baseline;
column-gap: 8rpx;
white-space: nowrap;


+ 2
- 2
pages_order/order/orderDetail/index.vue View File

@ -239,8 +239,8 @@
uni.stopPullDownRefresh()
},
onComment(id) {
this.$refs.commentPopup.open(id)
onComment() {
this.$refs.commentPopup.open(this.id, this.detail)
},
onApplyService() {
// todo


+ 4
- 5
pages_order/order/orderList/index.vue View File

@ -35,7 +35,7 @@
<view class="card" v-for="item in list" :key="item.id">
<orderCard
:data="item"
@comment="onComment(item.id)"
@comment="onComment(item.id, item)"
@applyService="onApplyService"
@contatcMentor="onContactMentor"
@statusChange="getData"
@ -76,8 +76,7 @@
{ name: '待收货' },
{ name: '待评价' },
],
// todo
mixinsListApi: '',
mixinsListApi: 'queryOrderList',
current: 0,
}
},
@ -100,8 +99,8 @@
}
this.getData()
},
onComment(id) {
this.$refs.commentPopup.open(id)
onComment(id, detail) {
this.$refs.commentPopup.open(id, detail)
},
onApplyService(obj) {
// todo


+ 3
- 3
pages_order/partner/apply.vue View File

@ -47,10 +47,10 @@
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item prop="recommend" :customStyle="formItemStyle">
<uv-form-item prop="inviteId" :customStyle="formItemStyle">
<view class="form-item-label">推荐人</view>
<view class="form-item-content">
<formInput v-model="form.recommend"></formInput>
<formInput v-model="form.inviteId"></formInput>
</view>
</uv-form-item>
</view>
@ -78,7 +78,7 @@
form: {
name: null,
phone: null,
recommend: null,
inviteId: null,
},
rules: {
'name': {


+ 5
- 97
pages_order/partner/team.vue View File

@ -57,11 +57,14 @@
{ name: '直推用户列表' },
{ name: '间推用户列表' },
],
// todo
mixinsListApi: '',
current: 0,
}
},
computed: {
mixinsListApi() {
return this.current == 0 ? 'queryDirectList' : 'queryIndirectList'
}
},
onShow() {
console.log('onShow')
},
@ -69,105 +72,10 @@
this.clickTabs({ index: arg.index || 0 })
},
methods: {
// todo: delete
getData() {
this.list = [
{
id: '001',
avatar: '/pages_order/static/temp-30.png',
name: '李世海',
price: 10,
createTime: '2025-07-15',
},
{
id: '002',
avatar: '/pages_order/static/temp-30.png',
name: '周静',
price: 10,
createTime: '2025-07-15',
},
{
id: '003',
avatar: '/pages_order/static/temp-30.png',
name: '周海',
price: 10,
createTime: '2025-07-15',
},
{
id: '004',
avatar: '/pages_order/static/temp-30.png',
name: '冯启彬',
price: 10,
createTime: '2025-07-15',
},
{
id: '005',
avatar: '/pages_order/static/temp-30.png',
name: '李娉',
price: 10,
createTime: '2025-07-15',
},
{
id: '006',
avatar: '/pages_order/static/temp-30.png',
name: '李书萍',
price: 10,
createTime: '2025-07-15',
},
{
id: '007',
avatar: '/pages_order/static/temp-30.png',
name: '李世海',
price: 10,
createTime: '2025-07-15',
},
{
id: '008',
avatar: '/pages_order/static/temp-30.png',
name: '周静',
price: 10,
createTime: '2025-07-15',
},
{
id: '009',
avatar: '/pages_order/static/temp-30.png',
name: '周海',
price: 10,
createTime: '2025-07-15',
},
{
id: '010',
avatar: '/pages_order/static/temp-30.png',
name: '冯启彬',
price: 10,
createTime: '2025-07-15',
},
{
id: '011',
avatar: '/pages_order/static/temp-30.png',
name: '李娉',
price: 10,
createTime: '2025-07-15',
},
{
id: '012',
avatar: '/pages_order/static/temp-30.png',
name: '李书萍',
price: 10,
createTime: '2025-07-15',
},
]
},
//tab
clickTabs({ index }) {
console.log('clickTabs')
this.current = index
if (index == 0) {
delete this.queryParams.status
} else {
this.queryParams.status = index - 1
}
this.getData()
},
},


+ 13
- 10
pages_order/partner/withdraw.vue View File

@ -16,18 +16,18 @@
errorType="toast"
>
<view class="form-item">
<uv-form-item prop="name" :customStyle="formItemStyle">
<uv-form-item prop="userName" :customStyle="formItemStyle">
<view class="form-item-label">真实姓名</view>
<view class="form-item-content">
<formInput v-model="form.name"></formInput>
<formInput v-model="form.userName"></formInput>
</view>
</uv-form-item>
</view>
<view class="form-item">
<uv-form-item prop="amount" :customStyle="formItemStyle">
<uv-form-item prop="transferAmount" :customStyle="formItemStyle">
<view class="form-item-label">提现金额</view>
<view class="form-item-content">
<formInput v-model="form.amount"></formInput>
<formInput v-model="form.transferAmount"></formInput>
</view>
</uv-form-item>
</view>
@ -64,16 +64,16 @@
data() {
return {
form: {
name: null,
amount: null,
userName: null,
transferAmount: null,
},
rules: {
'name': {
'userName': {
type: 'string',
required: true,
message: '请输入真实姓名',
},
'amount': {
'transferAmount': {
type: 'string',
required: true,
message: '请输入提现金额',
@ -88,13 +88,16 @@
await this.$refs.form.validate()
const {
userName,
transferAmount,
} = this.form
const params = {
userName,
transferAmount,
}
// todo: fetch
// await this.$fetch('updateAddress', params)
await this.$fetch('cashout', params)
uni.showToast({
icon: 'success',


+ 1
- 2
pages_order/product/productDetail.vue View File

@ -44,8 +44,7 @@
<view class="card">
<view class="card-header">选择团期</view>
<view class="card-content">
<!-- todo: check key -->
<timeOptionsSelect v-model="selectTime" :options="detail.timeOptions"></timeOptionsSelect>
<timeOptionsSelect v-model="selectTime" :options="detail.dateList"></timeOptionsSelect>
</view>
</view>


+ 1
- 1
pages_order/traveler/travelerList.vue View File

@ -50,7 +50,7 @@
},
onLoad(arg) {
const { selectIds } = arg
this.selectedIdList = selectIds?.split?.(',') || []
this.selectedIdList = selectIds?.split?.(',')?.filter(val => val) || []
this.getData()
},


+ 23
- 3
store/store.js View File

@ -16,6 +16,7 @@ const store = new Vuex.Store({
orderInfo: null,
couponInfo: null,
memberInfo: null,
liveInfo: null,
},
getters: {
// 角色 true为水洗店 false为酒店 : 身份判断如果不需要,可以删除
@ -25,7 +26,24 @@ const store = new Vuex.Store({
},
mutations: {
// 初始化配置
initConfig(state){
async initConfig(state) {
const records = (await fetch('getConfig'))?.records
const configList = {
...state.configList,
}
records.forEach(n => {
configList[n.paramCode] = n.paramImage || n.paramText || n.paramTextarea;
});
state.configList = configList
// todo: fetch
// fetch('queryConfigByParamCode', { paramCode: 'studytour_period' })
uni.$emit('initConfig', state.configList)
return
api('getConfig', res => {
const configList = {
...state.configList,
@ -86,8 +104,6 @@ const store = new Vuex.Store({
},
// 获取用户个人信息
getUserInfo(state){
// todo delete
return
api('getInfo', res => {
if(res.code == 200){
state.userInfo = res.result
@ -122,6 +138,10 @@ const store = new Vuex.Store({
setMemberInfo(state, data) {
state.memberInfo = data
},
setLiveInfo(state, data) {
console.log('liveInfo', data)
state.liveInfo = data
},
},
actions: {
async collect(state, activityId) {


Loading…
Cancel
Save