| @ -1,215 +1,11 @@ | |||
| // 首页相关接口 | |||
| const api = { | |||
| // 获取首页轮播图 | |||
| getRiceBanner: { | |||
| url: '/index_common/getRiceBanner', | |||
| // 首页-查询banner图列表 | |||
| queryBannerList: { | |||
| url: '/index/queryBannerList', | |||
| method: 'GET', | |||
| }, | |||
| // 获取首页常规产品【废弃】 | |||
| // getRiceCommonProductList: { | |||
| // url: '/index_common/getRiceCommonProductList', | |||
| // method: 'GET', | |||
| // }, | |||
| // 获取首页跳转图标 | |||
| getRiceIconList: { | |||
| url: '/index_common/getRiceIconList', | |||
| method: 'GET', | |||
| }, | |||
| // 获取首页新闻详情 | |||
| getRiceNewsDetail: { | |||
| url: '/index_common/getCommonNewsDetail', | |||
| method: 'GET', | |||
| }, | |||
| // 获取首页新闻列表 | |||
| getRiceNewsList: { | |||
| url: '/index_common/getRiceNewsList', | |||
| method: 'GET', | |||
| }, | |||
| // 获取首页公告列表 | |||
| getRiceNoticeList: { | |||
| url: '/index_common/getRiceNoticeList', | |||
| method: 'GET', | |||
| }, | |||
| // 获取首页商品详情 | |||
| getRiceProductDetail: { | |||
| url: '/index_common/getRiceProductDetail', | |||
| method: 'GET', | |||
| }, | |||
| // 获取首页体验产品 | |||
| getRiceProductList: { | |||
| url: '/index_common/getRiceProductList', | |||
| 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,0 +1,113 @@ | |||
| <template> | |||
| <view class="records__view"> | |||
| <uv-steps direction="column"> | |||
| <uv-steps-item v-for="(record, index) in list" :key="record.id"> | |||
| <template #icon> | |||
| <view class="flex mark is-active" v-if="index === 0"> | |||
| <image class="icon" src="@/static/image/icon-mark-highlight.png" mode="widthFix"></image> | |||
| </view> | |||
| <view class="flex mark" v-else> | |||
| <image class="icon" src="@/static/image/icon-mark.png" mode="widthFix"></image> | |||
| </view> | |||
| </template> | |||
| <template #title> | |||
| <view class="title" @click="onClickActivity(record.id)">{{ record.createTime }}</view> | |||
| </template> | |||
| <template #desc> | |||
| <view class="content" @click="onClickActivity(record.id)"> | |||
| <view class="desc">{{ record.name }}</view> | |||
| <view class="image"> | |||
| <view class="image-item" v-for="(image, imgIdx) in record.image" :key="imgIdx"> | |||
| <image class="img" :src="image" mode="scaleToFill"></image> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| </template> | |||
| </uv-steps-item> | |||
| </uv-steps> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| export default { | |||
| props: { | |||
| list: { | |||
| type: Array, | |||
| default() { | |||
| return [] | |||
| } | |||
| } | |||
| }, | |||
| methods: { | |||
| onClickActivity(id) { | |||
| this.$utils.navigateTo(`/pages_order/growing/activity/index?id=${id}`) | |||
| }, | |||
| }, | |||
| } | |||
| </script> | |||
| <style scoped lang="scss"> | |||
| .records__view { | |||
| padding-left: 40rpx; | |||
| } | |||
| .mark { | |||
| margin-top: 8rpx; | |||
| width: 36rpx; | |||
| height: 36rpx; | |||
| background: #F3F3F3; | |||
| border-radius: 50%; | |||
| .icon { | |||
| width: 24rpx; | |||
| height: auto; | |||
| } | |||
| &.is-active { | |||
| background: linear-gradient(to right, #21FEEC, #019AF9); | |||
| } | |||
| } | |||
| .title { | |||
| font-family: PingFang SC; | |||
| font-size: 36rpx; | |||
| font-weight: 600; | |||
| line-height: 1.4; | |||
| color: $uni-color; | |||
| } | |||
| .content { | |||
| width: calc(100vw - 92rpx); | |||
| } | |||
| .desc { | |||
| font-family: PingFang SC; | |||
| font-size: 28rpx; | |||
| font-weight: 400; | |||
| line-height: 1.4; | |||
| color: #191919; | |||
| } | |||
| .image { | |||
| display: flex; | |||
| column-gap: 16rpx; | |||
| flex-wrap: nowrap; | |||
| overflow-x: auto; | |||
| &-item { | |||
| flex: none; | |||
| width: 208rpx; | |||
| height: 296rpx; | |||
| border: 2rpx solid #CDCDCD; | |||
| border-radius: 12rpx; | |||
| overflow: hidden; | |||
| .img { | |||
| width: 100%; | |||
| height: 100%; | |||
| } | |||
| } | |||
| } | |||
| </style> | |||
| @ -0,0 +1,212 @@ | |||
| <template> | |||
| <view class="card"> | |||
| <view class="flex card-header"> | |||
| <view> | |||
| <view class="title">我的档案</view> | |||
| <button class="flex btn btn-question"> | |||
| <image class="btn-icon" src="@/static/image/icon-question.png" mode="widthFix"></image> | |||
| <view>如何完善我的档案?</view> | |||
| </button> | |||
| </view> | |||
| <view class="flex"> | |||
| <button class="btn btn-switch" @click="onSwitch">切换</button> | |||
| <button class="btn btn-add" @click="onAdd">新增记录</button> | |||
| </view> | |||
| </view> | |||
| <view class="card-content"> | |||
| <view class="flex info"> | |||
| <view class="avatar"> | |||
| <image class="img" src="@/static/image/temp-30.png" mode="scaleToFill"></image> | |||
| <view class="tag">学生</view> | |||
| </view> | |||
| <view class="flex summary"> | |||
| <view class="flex flex-column summary-item name"> | |||
| <view class="summary-item-content">战斗世界</view> | |||
| <view class="summary-item-label">ID:5625354</view> | |||
| </view> | |||
| <view class="flex flex-column summary-item" @click="jumpToAchievement"> | |||
| <view class="summary-item-content">8</view> | |||
| <view class="summary-item-label">成就</view> | |||
| </view> | |||
| <view class="flex flex-column summary-item"> | |||
| <view class="summary-item-content">68</view> | |||
| <view class="summary-item-label">足迹</view> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <view class="flex medal"> | |||
| <image class="medal-item" src="@/static/image/temp-47.png" mode="widthFix"></image> | |||
| <image class="medal-item" src="@/static/image/temp-48.png" mode="widthFix"></image> | |||
| <image class="medal-item" src="@/static/image/temp-49.png" mode="widthFix"></image> | |||
| <image class="medal-item" src="@/static/image/temp-47.png" mode="widthFix"></image> | |||
| <image class="medal-item" src="@/static/image/temp-48.png" mode="widthFix"></image> | |||
| <image class="medal-item" src="@/static/image/temp-49.png" mode="widthFix"></image> | |||
| <image class="medal-item" src="@/static/image/temp-47.png" mode="widthFix"></image> | |||
| <image class="medal-item" src="@/static/image/temp-48.png" mode="widthFix"></image> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| export default { | |||
| data() { | |||
| return { | |||
| } | |||
| }, | |||
| onLoad() { | |||
| }, | |||
| methods: { | |||
| getData() { | |||
| // todo | |||
| }, | |||
| onAdd() { | |||
| this.$emit('addRecord') | |||
| }, | |||
| onSwitch() { | |||
| this.$emit('switchMember') | |||
| }, | |||
| jumpToAchievement() { | |||
| uni.navigateTo({ | |||
| url: '/pages_order/growing/achievement/index' | |||
| }) | |||
| }, | |||
| }, | |||
| } | |||
| </script> | |||
| <style scoped lang="scss"> | |||
| .card { | |||
| font-family: PingFang SC; | |||
| font-weight: 400; | |||
| line-height: 1.4; | |||
| background: linear-gradient(to right, #DDF4FF, #9FE1FF); | |||
| border-radius: 48rpx; | |||
| &-header { | |||
| justify-content: space-between; | |||
| padding: 24rpx 40rpx 20rpx 40rpx; | |||
| .title { | |||
| font-size: 32rpx; | |||
| font-weight: 600; | |||
| color: #000000; | |||
| } | |||
| .btn-question { | |||
| margin-top: 4rpx; | |||
| column-gap: 8rpx; | |||
| font-size: 26rpx; | |||
| color: #21607D; | |||
| .btn-icon { | |||
| width: 32rpx; | |||
| height: auto; | |||
| } | |||
| } | |||
| .btn-switch { | |||
| padding: 6rpx 22rpx; | |||
| font-size: 28rpx; | |||
| font-weight: 400; | |||
| line-height: 1.4; | |||
| color: #252545; | |||
| border: 2rpx solid #252545; | |||
| border-radius: 28rpx; | |||
| } | |||
| .btn-add { | |||
| padding: 8rpx 24rpx; | |||
| font-size: 28rpx; | |||
| font-weight: 500; | |||
| line-height: 1.4; | |||
| color: #FFFFFF; | |||
| background: linear-gradient(to right, #21FEEC, #019AF9); | |||
| border-radius: 28rpx; | |||
| } | |||
| .btn + .btn { | |||
| margin-left: 26rpx; | |||
| } | |||
| } | |||
| &-content { | |||
| padding: 38rpx 38rpx 14rpx 38rpx; | |||
| background: linear-gradient(to right, #FBFEFF, #DAF3FF); | |||
| border: 2rpx solid #FFFFFF; | |||
| border-radius: 48rpx; | |||
| box-shadow: 0 2px 12px 0 #009AE717; | |||
| .info { | |||
| column-gap: 24rpx; | |||
| .avatar { | |||
| flex: none; | |||
| position: relative; | |||
| width: 128rpx; | |||
| height: 128rpx; | |||
| border-radius: 24rpx; | |||
| overflow: hidden; | |||
| .img { | |||
| width: 100%; | |||
| height: 100%; | |||
| } | |||
| .tag { | |||
| position: absolute; | |||
| left: 0; | |||
| bottom: 0; | |||
| width: 100%; | |||
| padding: 2rpx 0; | |||
| box-sizing: border-box; | |||
| text-align: center; | |||
| font-size: 24rpx; | |||
| color: #03C25C; | |||
| background: #E9FFF5; | |||
| } | |||
| } | |||
| .summary { | |||
| flex: 1; | |||
| column-gap: 26rpx; | |||
| &-item { | |||
| flex: 1; | |||
| row-gap: 8rpx; | |||
| &.name { | |||
| flex: none; | |||
| } | |||
| &-content { | |||
| font-size: 32rpx; | |||
| font-weight: 600; | |||
| color: #000000; | |||
| } | |||
| &-label { | |||
| font-size: 24rpx; | |||
| color: #939393; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| .medal { | |||
| margin-top: 16rpx; | |||
| justify-content: flex-start; | |||
| flex-wrap: wrap; | |||
| gap: 16rpx; | |||
| &-item { | |||
| width: 50rpx; | |||
| height: auto; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| </style> | |||
| @ -0,0 +1,193 @@ | |||
| <template> | |||
| <view class="page__view highlight"> | |||
| <!-- 搜索栏 --> | |||
| <view :class="['flex', 'search', isFocusSearch ? 'is-focus' : '']" > | |||
| <uv-search | |||
| v-model="keyword" | |||
| placeholder="请输入" | |||
| color="#181818" | |||
| bgColor="transparent" | |||
| :showAction="isFocusSearch" | |||
| @custom="search" | |||
| @search="search" | |||
| @focus="isFocusSearch = true" | |||
| @blur="isFocusSearch = false" | |||
| > | |||
| <template #prefix> | |||
| <image class="search-icon" src="@/static/image/icon-search-dark.png" mode="widthFix"></image> | |||
| </template> | |||
| </uv-search> | |||
| </view> | |||
| <view class="archives"> | |||
| <userCard @switchMember="jumpToChooseMember" @addRecord="onAdd"></userCard> | |||
| </view> | |||
| <view class="list" v-if="memberInfo"> | |||
| <recordsView :list="list"></recordsView> | |||
| </view> | |||
| <view class="flex" v-else> | |||
| <button class="btn btn-choose" @click="jumpToChooseMember">请先选择人员</button> | |||
| </view> | |||
| <record-form-popup ref="recordFormPopup" @submitted="getData"></record-form-popup> | |||
| <tabber select="growing" /> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| import { mapState } from 'vuex' | |||
| import mixinsList from '@/mixins/list.js' | |||
| import tabber from '@/components/base/tabbar.vue' | |||
| import userCard from '@/components/growing/userCard.vue' | |||
| import recordsView from '@/components/growing/recordsView.vue' | |||
| import recordFormPopup from '@/pages_order/growing/activity/recordFormPopup.vue' | |||
| export default { | |||
| mixins: [mixinsList], | |||
| components: { | |||
| userCard, | |||
| recordsView, | |||
| recordFormPopup, | |||
| tabber, | |||
| }, | |||
| data() { | |||
| return { | |||
| keyword: '', | |||
| isFocusSearch: false, | |||
| // todo | |||
| mixinsListApi: '', | |||
| } | |||
| }, | |||
| computed: { | |||
| ...mapState(['memberInfo']), | |||
| }, | |||
| methods: { | |||
| // todo: delete | |||
| getData() { | |||
| this.list = [ | |||
| { | |||
| id: '001', | |||
| name: '新疆天山行7/9日丨醉美伊犁&吐鲁番双套餐', | |||
| image: [ | |||
| '/static/image/temp-38.png', | |||
| '/static/image/temp-39.png', | |||
| '/static/image/temp-40.png', | |||
| ], | |||
| createTime: '2025-07-12', | |||
| }, | |||
| { | |||
| id: '002', | |||
| name: '仙踪新昌·韩妃江古道|邂逅“江南小桂林”', | |||
| image: [ | |||
| '/static/image/temp-41.png', | |||
| '/static/image/temp-42.png', | |||
| '/static/image/temp-43.png', | |||
| ], | |||
| createTime: '2025-06-18', | |||
| }, | |||
| { | |||
| id: '003', | |||
| name: '山水石窟·大佛寺|江南佛窟造像,新昌山水轻徒', | |||
| image: [ | |||
| '/static/image/temp-44.png', | |||
| '/static/image/temp-45.png', | |||
| '/static/image/temp-46.png', | |||
| ], | |||
| createTime: '2025-06-15', | |||
| }, | |||
| ] | |||
| }, | |||
| search() { | |||
| console.log('search', this.keyword) | |||
| uni.navigateTo({ | |||
| url: '/pages_order/growing/activity/search?search=' + this.keyword | |||
| }) | |||
| // this.keyword = '' | |||
| }, | |||
| onAdd() { | |||
| this.$refs.recordFormPopup.open() | |||
| }, | |||
| jumpToChooseMember() { | |||
| uni.navigateTo({ | |||
| url: `/pages_order/member/switch` | |||
| }) | |||
| }, | |||
| }, | |||
| } | |||
| </script> | |||
| <style scoped lang="scss"> | |||
| .page__view { | |||
| /deep/ .tabbar-box { | |||
| .tabbar { | |||
| z-index: 10000; | |||
| } | |||
| } | |||
| } | |||
| .search { | |||
| $w: 474rpx; | |||
| $h: 64rpx; | |||
| $radius: 32rpx; | |||
| $borderWidth: 4rpx; | |||
| width: $w; | |||
| height: $h; | |||
| position: relative; | |||
| padding: 94rpx 32rpx 6rpx 32rpx; | |||
| border-radius: $radius; | |||
| &-icon { | |||
| margin: 0 13rpx 0 26rpx; | |||
| width: 30rpx; | |||
| height: auto; | |||
| } | |||
| /deep/ .uv-search__content { | |||
| padding: 12rpx 0; | |||
| border: 4rpx solid transparent; | |||
| } | |||
| /deep/ .uv-search__content { | |||
| background: #FFFFFF !important; | |||
| border-color: #CFEFFF !important; | |||
| } | |||
| &.is-focus { | |||
| /deep/ .uv-search__action { | |||
| padding: 19rpx 24rpx; | |||
| font-size: 26rpx; | |||
| font-weight: 500; | |||
| line-height: 1; | |||
| color: #FFFFFF; | |||
| background: #00A9FF; | |||
| border-radius: 32rpx; | |||
| } | |||
| } | |||
| } | |||
| .archives { | |||
| padding: 32rpx 40rpx 16rpx 40rpx; | |||
| } | |||
| .btn-choose { | |||
| margin-top: 84rpx; | |||
| padding: 14rpx 125rpx; | |||
| font-size: 36rpx; | |||
| font-weight: 500; | |||
| line-height: 1.4; | |||
| color: #FFFFFF; | |||
| background: linear-gradient(to right, #21FEEC, #019AF9); | |||
| border: 2rpx solid #00A9FF; | |||
| border-radius: 41rpx; | |||
| } | |||
| </style> | |||
| @ -0,0 +1,28 @@ | |||
| <template> | |||
| <uv-rate | |||
| :value="value" | |||
| @input="$emit('input', $event)" | |||
| @change="$emit('input', $event)" | |||
| activeIcon="star-fill" | |||
| inactiveIcon="star-fill" | |||
| size="48rpx" | |||
| gutter="16rpx" | |||
| activeColor="#F7BA1E" | |||
| :allowHalf="true" | |||
| :minCount="0.5" | |||
| ></uv-rate> | |||
| </template> | |||
| <script> | |||
| export default { | |||
| props: { | |||
| value: { | |||
| default: null | |||
| }, | |||
| }, | |||
| } | |||
| </script> | |||
| <style> | |||
| </style> | |||
| @ -0,0 +1,49 @@ | |||
| <template> | |||
| <uv-textarea | |||
| :value="value" | |||
| @input="$emit('input', $event)" | |||
| :placeholder="placeholder" | |||
| :height="height" | |||
| border="none" | |||
| :customStyle="{ | |||
| backgroundColor: '#F7F8FA', | |||
| padding: '8rpx 16rpx', | |||
| borderRadius: '16rpx', | |||
| }" | |||
| :placeholderStyle="{ | |||
| color: '#C6C6C6', | |||
| fontSize: '32rpx', | |||
| }" | |||
| :textStyle="{ | |||
| fontSize: '32rpx', | |||
| }" | |||
| ></uv-textarea> | |||
| </template> | |||
| <script> | |||
| export default { | |||
| props: { | |||
| value: { | |||
| default: null | |||
| }, | |||
| placeholder: { | |||
| type: String, | |||
| default: '请输入' | |||
| }, | |||
| height: { | |||
| type: String, | |||
| default: '230rpx' | |||
| }, | |||
| }, | |||
| data() { | |||
| return { | |||
| } | |||
| }, | |||
| methods: { | |||
| }, | |||
| } | |||
| </script> | |||
| <style scoped lang="scss"> | |||
| </style> | |||
| @ -0,0 +1,105 @@ | |||
| <template> | |||
| <view> | |||
| <uv-upload | |||
| :fileList="displayFileList" | |||
| :accept="accept" | |||
| :maxCount="maxCount" | |||
| :width="width" | |||
| :height="height" | |||
| @afterRead="afterRead" | |||
| @delete="deleteFile" | |||
| > | |||
| <button class="flex btn"> | |||
| <image class="btn-icon" src="@/static/image/icon-plus.png" mode="widthFix" /> | |||
| </button> | |||
| </uv-upload> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| export default { | |||
| props: { | |||
| value: { | |||
| type: Array, | |||
| default() { | |||
| return [] | |||
| } | |||
| }, | |||
| accept: { | |||
| type: String, | |||
| default: 'image' // all | media | image | file | video | |||
| }, | |||
| width: { | |||
| type: Number | String, | |||
| default: 190, | |||
| }, | |||
| height: { | |||
| type: Number | String, | |||
| default: 190, | |||
| }, | |||
| maxCount: { | |||
| type: Number | String, | |||
| default: 100, | |||
| } | |||
| }, | |||
| data() { | |||
| return { | |||
| } | |||
| }, | |||
| computed: { | |||
| fileList: { | |||
| set(val) { | |||
| this.$emit('input', val) | |||
| }, | |||
| get() { | |||
| return this.value | |||
| } | |||
| }, | |||
| displayFileList() { | |||
| return this.fileList.map(url => ({ url })) | |||
| }, | |||
| }, | |||
| watch: { | |||
| fileList: { | |||
| handler(val) { | |||
| console.log('watch fileList', val) | |||
| }, | |||
| deep: true, | |||
| }, | |||
| displayFileList: { | |||
| handler(val) { | |||
| console.log('watch displayFileList', val) | |||
| }, | |||
| deep: true, | |||
| }, | |||
| }, | |||
| methods: { | |||
| deleteFile(e){ | |||
| console.log('deleteFile', e) | |||
| const fileList = [...this.fileList] | |||
| fileList.splice(e.index, 1) | |||
| this.fileList = fileList | |||
| }, | |||
| afterRead(e){ | |||
| this.$Oss.ossUpload(e.file.url).then(url => { | |||
| this.fileList = this.fileList.concat(url) | |||
| }) | |||
| }, | |||
| }, | |||
| } | |||
| </script> | |||
| <style scoped lang="scss"> | |||
| .btn { | |||
| width: 190rpx; | |||
| height: 190rpx; | |||
| background: #F3F2F7; | |||
| border-radius: 16rpx; | |||
| &-icon { | |||
| width: 61rpx; | |||
| height: auto; | |||
| } | |||
| } | |||
| </style> | |||
| @ -0,0 +1,175 @@ | |||
| <template> | |||
| <view class="page__view highlight"> | |||
| <!-- 导航栏 --> | |||
| <navbar title="我的成就" leftClick @leftClick="$utils.navigateBack" /> | |||
| <view class="main"> | |||
| <view class="flex summary"> | |||
| <view class="info"> | |||
| <view class="flex title">共获得<view class="highlight">8</view>枚成就</view> | |||
| <view class="tag">新获得</view> | |||
| </view> | |||
| <view class="icon"> | |||
| <image class="img" src="@/static/image/temp-49.png" mode="widthFix"></image> | |||
| </view> | |||
| </view> | |||
| <view class="list"> | |||
| <recordsView :list="list"></recordsView> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| import mixinsList from '@/mixins/list.js' | |||
| import recordsView from './recordsView.vue' | |||
| export default { | |||
| mixins: [mixinsList], | |||
| components: { | |||
| recordsView, | |||
| }, | |||
| data() { | |||
| return { | |||
| keyword: '', | |||
| // todo | |||
| mixinsListApi: '', | |||
| } | |||
| }, | |||
| onLoad({ search }) { | |||
| if (search) { | |||
| this.keyword = search | |||
| this.queryParams.title = search | |||
| } | |||
| this.getData() | |||
| }, | |||
| methods: { | |||
| // todo: delete | |||
| getData() { | |||
| this.list = [ | |||
| { | |||
| id: '001', | |||
| name: '呼伦贝尔6/8日丨经典or环线 双套餐可选', | |||
| children: [ | |||
| { | |||
| id: '0011', | |||
| icon: '/static/image/temp-47.png', | |||
| label: '言值认证', | |||
| createTime: '2025-07-12', | |||
| }, | |||
| { | |||
| id: '0012', | |||
| icon: '/static/image/temp-48.png', | |||
| label: '国际旅行', | |||
| createTime: '2025-07-12', | |||
| }, | |||
| { | |||
| id: '0013', | |||
| icon: '/static/image/temp-48.png', | |||
| label: '萌新毕业证', | |||
| createTime: '2025-07-12', | |||
| }, | |||
| ], | |||
| }, | |||
| { | |||
| id: '002', | |||
| name: '新疆天山行7/9日丨醉美伊犁&吐鲁番双套餐新疆天山行7/9日丨醉美伊犁&吐鲁番双套餐', | |||
| children: [ | |||
| { | |||
| id: '0011', | |||
| icon: '/static/image/temp-48.png', | |||
| label: '言值认证', | |||
| createTime: '2025-05-15', | |||
| }, | |||
| ], | |||
| }, | |||
| { | |||
| id: '003', | |||
| name: '呼伦贝尔6/8日丨经典or环线 双套餐可选', | |||
| children: [ | |||
| { | |||
| id: '0011', | |||
| icon: '/static/image/temp-47.png', | |||
| label: '言值认证', | |||
| createTime: '2025-07-12', | |||
| }, | |||
| { | |||
| id: '0012', | |||
| icon: '/static/image/temp-48.png', | |||
| label: '国际旅行', | |||
| createTime: '2025-07-12', | |||
| }, | |||
| ], | |||
| }, | |||
| { | |||
| id: '004', | |||
| name: '新丝路到敦煌7日丨甘青轻松穿越,沙漠+草原', | |||
| children: [ | |||
| { | |||
| id: '0012', | |||
| icon: '/static/image/temp-48.png', | |||
| label: '国际旅行', | |||
| createTime: '2025-07-12', | |||
| }, | |||
| { | |||
| id: '0013', | |||
| icon: '/static/image/temp-47.png', | |||
| label: '萌新毕业证', | |||
| createTime: '2025-07-12', | |||
| }, | |||
| ], | |||
| }, | |||
| ] | |||
| }, | |||
| }, | |||
| } | |||
| </script> | |||
| <style scoped lang="scss"> | |||
| .summary { | |||
| padding: 16rpx 72rpx 32rpx 64rpx; | |||
| justify-content: space-between; | |||
| font-family: PingFang SC; | |||
| font-weight: 400; | |||
| line-height: 1.4; | |||
| .info { | |||
| .title { | |||
| font-size: 32rpx; | |||
| font-weight: 600; | |||
| color: #000000; | |||
| .highlight { | |||
| margin: 0 8rpx; | |||
| color: $uni-color; | |||
| } | |||
| } | |||
| .tag { | |||
| margin-top: 4rpx; | |||
| display: inline-block; | |||
| padding: 4rpx 16rpx; | |||
| font-size: 26rpx; | |||
| color: #21607D; | |||
| background: #DBF4FF; | |||
| border-radius: 22rpx; | |||
| } | |||
| } | |||
| .icon { | |||
| width: 160rpx; | |||
| height: auto; | |||
| .img { | |||
| width: 100%; | |||
| height: auto; | |||
| } | |||
| } | |||
| } | |||
| </style> | |||
| @ -0,0 +1,112 @@ | |||
| <template> | |||
| <view class="records__view"> | |||
| <uv-steps direction="column"> | |||
| <uv-steps-item v-for="(record, index) in list" :key="record.id"> | |||
| <template #icon> | |||
| <view class="flex mark is-active" v-if="index === 0"> | |||
| <image class="icon" src="@/static/image/icon-mark-highlight.png" mode="widthFix"></image> | |||
| </view> | |||
| <view class="flex mark" v-else> | |||
| <image class="icon" src="@/static/image/icon-mark.png" mode="widthFix"></image> | |||
| </view> | |||
| </template> | |||
| <template #title> | |||
| <view class="title">{{ record.name }}</view> | |||
| </template> | |||
| <template #desc> | |||
| <view class="content"> | |||
| <view class="list"> | |||
| <view class="flex flex-column list-item" v-for="(child, cIdx) in record.children" :key="cIdx"> | |||
| <image class="list-item-icon" :src="child.icon" mode="aspectFill"></image> | |||
| <view class="list-item-title">{{ child.label }}</view> | |||
| <view class="list-item-desc">{{ child.createTime }}</view> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| </template> | |||
| </uv-steps-item> | |||
| </uv-steps> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| export default { | |||
| props: { | |||
| list: { | |||
| type: Array, | |||
| default() { | |||
| return [] | |||
| } | |||
| } | |||
| }, | |||
| } | |||
| </script> | |||
| <style scoped lang="scss"> | |||
| .records__view { | |||
| padding-left: 40rpx; | |||
| } | |||
| .mark { | |||
| margin-top: 8rpx; | |||
| width: 36rpx; | |||
| height: 36rpx; | |||
| background: #F3F3F3; | |||
| border-radius: 50%; | |||
| .icon { | |||
| width: 24rpx; | |||
| height: auto; | |||
| } | |||
| &.is-active { | |||
| background: linear-gradient(to right, #21FEEC, #019AF9); | |||
| } | |||
| } | |||
| .title { | |||
| font-family: PingFang SC; | |||
| font-size: 30rpx; | |||
| font-weight: 500; | |||
| line-height: 1.4; | |||
| color: #191919; | |||
| } | |||
| .content { | |||
| width: calc(100vw - 92rpx); | |||
| } | |||
| .list { | |||
| display: flex; | |||
| flex-wrap: nowrap; | |||
| overflow-x: auto; | |||
| font-family: PingFang SC; | |||
| line-height: 1.4; | |||
| &-item { | |||
| flex: none; | |||
| row-gap: 4rpx; | |||
| width: 206rpx; | |||
| height: 226rpx; | |||
| &-icon { | |||
| width: 110rpx; | |||
| height: 110rpx; | |||
| } | |||
| &-title { | |||
| font-size: 28rpx; | |||
| font-weight: 500; | |||
| color: #080808; | |||
| } | |||
| &-desc { | |||
| font-size: 26rpx; | |||
| font-weight: 400; | |||
| color: #999999; | |||
| } | |||
| } | |||
| } | |||
| </style> | |||
| @ -0,0 +1,277 @@ | |||
| <template> | |||
| <view class="page__view highlight"> | |||
| <!-- 导航栏 --> | |||
| <navbar title="活动详情" leftClick @leftClick="$utils.navigateBack" /> | |||
| <view class="tabs"> | |||
| <uv-tabs | |||
| :list="tabs" | |||
| :scrollable="false" | |||
| lineColor="#00A9FF" | |||
| lineWidth="48rpx" | |||
| lineHeight="4rpx" | |||
| :activeStyle="{ | |||
| 'font-family': 'PingFang SC', | |||
| 'font-weight': 500, | |||
| 'font-size': '32rpx', | |||
| 'line-height': 1.4, | |||
| 'color': '#00A9FF', | |||
| }" | |||
| :inactiveStyle="{ | |||
| 'font-family': 'PingFang SC', | |||
| 'font-weight': 400, | |||
| 'font-size': '32rpx', | |||
| 'line-height': 1.4, | |||
| 'color': '#191919', | |||
| }" | |||
| @click="clickTabs" | |||
| ></uv-tabs> | |||
| </view> | |||
| <scroll-view type="custom" scroll-y="true" :scroll-into-view="scrollIntoView" class="scroll-view"> | |||
| <view class="scroll-view-content"> | |||
| <view class="cover-img"> | |||
| <image class="img" src="@/static/image/temp-20.png" mode="aspectFill"></image> | |||
| </view> | |||
| <view class="section" id="highlights"> | |||
| <view class="flex section-header"> | |||
| <view class="flex"> | |||
| <view class="flex icon"> | |||
| <image class="img" src="@/static/image/icon-mark.png" mode="widthFix"></image> | |||
| </view> | |||
| <view>活动掠影</view> | |||
| </view> | |||
| <view class="btn btn-mark">标记有我</view> | |||
| </view> | |||
| <view class="section-content highlights"> | |||
| <view class="highlights-item" v-for="(image, idx) in detail.highlights" :key="idx"> | |||
| <image class="img" :src="image" mode="scaleToFill"></image> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <view class="section" id="thoughts"> | |||
| <view class="section-header">学员心得</view> | |||
| <view class="section-content thoughts"> | |||
| <view class="card" v-for="item in detail.thoughts" :key="item.id"> | |||
| <commentCard :data="item" @change="onCommentChange"></commentCard> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <view class="section report" id="report"> | |||
| <view class="section-header">行后报告</view> | |||
| <view class="section-content report"> | |||
| <!-- todo --> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| </scroll-view> | |||
| <view class="flex bottom"> | |||
| <button class="flex btn btn-palin" @click="jumpToPoster">生成海报</button> | |||
| <button class="flex btn btn-primary" @click="onApplyEmail">申请邮件</button> | |||
| </view> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| import commentCard from '@/pages_order/comment/commentCard.vue' | |||
| export default { | |||
| components: { | |||
| commentCard, | |||
| }, | |||
| data() { | |||
| return { | |||
| tabs: [ | |||
| { id: 'highlights', name: '活动掠影' }, | |||
| { id: 'thoughts', name: '学员心得' }, | |||
| { id: 'report', name: '行后报告' }, | |||
| ], | |||
| current: 0, | |||
| detail: {}, | |||
| scrollIntoView: null, | |||
| } | |||
| }, | |||
| onLoad() { | |||
| this.getData() | |||
| }, | |||
| methods: { | |||
| async getData() { | |||
| // todo | |||
| this.detail = { | |||
| highlights: [ | |||
| '/static/image/temp-38.png', | |||
| '/static/image/temp-39.png', | |||
| '/static/image/temp-40.png', | |||
| '/static/image/temp-41.png', | |||
| '/static/image/temp-42.png', | |||
| '/static/image/temp-43.png', | |||
| '/static/image/temp-44.png', | |||
| '/static/image/temp-45.png', | |||
| '/static/image/temp-46.png', | |||
| ], | |||
| thoughts: [], | |||
| } | |||
| }, | |||
| //点击tab栏 | |||
| clickTabs({ index }) { | |||
| this.current = index | |||
| this.scrollIntoView = this.tabs[this.current].id | |||
| }, | |||
| onCommentChange() { | |||
| // todo: refresh comment list | |||
| }, | |||
| jumpToPoster() { | |||
| // todo | |||
| }, | |||
| onApplyEmail() { | |||
| // todo | |||
| }, | |||
| }, | |||
| } | |||
| </script> | |||
| <style scoped lang="scss"> | |||
| .tabs { | |||
| background: #D8F2FF; | |||
| } | |||
| .scroll-view { | |||
| $tab-height: 44px; | |||
| $bottom-height: 73px; | |||
| height: calc(100vh - env(safe-area-inset-bottom) - #{$bottom-height} - #{$tab-height} - #{$navbar-height} - var(--status-bar-height) - 20rpx); | |||
| &-content { | |||
| padding: 32rpx; | |||
| } | |||
| } | |||
| .cover-img { | |||
| width: 100%; | |||
| height: 348rpx; | |||
| border-radius: 12rpx; | |||
| overflow: hidden; | |||
| .img { | |||
| width: 100%; | |||
| height: 100%; | |||
| } | |||
| } | |||
| .section { | |||
| margin-top: 32rpx; | |||
| &-header { | |||
| justify-content: space-between; | |||
| font-size: 36rpx; | |||
| font-weight: 600; | |||
| color: #080808; | |||
| .icon { | |||
| margin-right: 24rpx; | |||
| width: 36rpx; | |||
| height: 36rpx; | |||
| background: #080808; | |||
| border-radius: 50%; | |||
| overflow: hidden; | |||
| .img { | |||
| width: 24rpx; | |||
| height: auto; | |||
| } | |||
| } | |||
| .btn-mark { | |||
| padding: 6rpx 22rpx; | |||
| font-family: PingFang SC; | |||
| font-size: 28rpx; | |||
| font-weight: 500; | |||
| line-height: 1.5; | |||
| color: #FFFFFF; | |||
| background: linear-gradient(to right, #21FEEC, #019AF9); | |||
| border: 2rpx solid #00A9FF; | |||
| border-radius: 30rpx; | |||
| } | |||
| } | |||
| &-content { | |||
| } | |||
| } | |||
| .highlights { | |||
| margin-top: 18rpx; | |||
| display: grid; | |||
| grid-template-columns: repeat(3, 1fr); | |||
| gap: 16rpx; | |||
| &-item { | |||
| min-width: 0; | |||
| border: 2rpx solid #CDCDCD; | |||
| border-radius: 12rpx; | |||
| overflow: hidden; | |||
| .img { | |||
| width: 100%; | |||
| height: 304rpx; | |||
| } | |||
| } | |||
| } | |||
| .thoughts { | |||
| margin-top: 24rpx; | |||
| .card + .card { | |||
| margin-top: 24rpx; | |||
| } | |||
| } | |||
| .report { | |||
| margin-top: 24rpx; | |||
| } | |||
| .bottom { | |||
| position: fixed; | |||
| left: 0; | |||
| bottom: 0; | |||
| z-index: 999; | |||
| justify-content: space-between; | |||
| column-gap: 32rpx; | |||
| width: 100vw; | |||
| padding: 32rpx 40rpx; | |||
| padding-bottom: calc(env(safe-area-inset-bottom) + 32rpx); | |||
| background: #FFFFFF; | |||
| box-sizing: border-box; | |||
| .btn { | |||
| flex: 1; | |||
| font-size: 36rpx; | |||
| font-weight: 500; | |||
| border-radius: 41rpx; | |||
| line-height: 1.4; | |||
| &-palin { | |||
| padding: 14rpx 0; | |||
| color: #252545; | |||
| border: 2rpx solid #252545; | |||
| } | |||
| &-primary { | |||
| padding: 14rpx 0; | |||
| color: #FFFFFF; | |||
| background: linear-gradient(to right, #21FEEC, #019AF9); | |||
| border: 2rpx solid #00A9FF; | |||
| } | |||
| } | |||
| } | |||
| </style> | |||
| @ -0,0 +1,261 @@ | |||
| <template> | |||
| <view> | |||
| <uv-popup ref="popup" mode="bottom" bgColor="none" > | |||
| <view class="popup__view"> | |||
| <view class="flex header"> | |||
| <view class="title">标记有我</view> | |||
| <button class="btn" @click="close">关闭</button> | |||
| </view> | |||
| <view class="form"> | |||
| <uv-form | |||
| ref="form" | |||
| :model="form" | |||
| :rules="rules" | |||
| errorType="toast" | |||
| > | |||
| <view class="form-item"> | |||
| <uv-form-item prop="image" :customStyle="formItemStyle"> | |||
| <view class="form-item-label"> | |||
| <image class="icon" src="@/static/image/icon-require.png" mode="widthFix"></image> | |||
| 上传图片 | |||
| </view> | |||
| <view class="form-item-content"> | |||
| <button class="flex btn"> | |||
| <view v-if="form.image" class="avatar"> | |||
| <image class="img" :src="form.image" mode="aspectFill"></image> | |||
| <view class="flex mask"> | |||
| <image class="icon" src="@/static/image/icon-change.png" mode="widthFix" /> | |||
| </view> | |||
| </view> | |||
| <view v-else class="flex avatar is-empty"> | |||
| <image class="icon" src="@/static/image/icon-plus.png" mode="widthFix" /> | |||
| </view> | |||
| </button> | |||
| </view> | |||
| </uv-form-item> | |||
| </view> | |||
| </uv-form> | |||
| </view> | |||
| <view class="footer"> | |||
| <button class="flex btn" @click="onSubmit">提交</button> | |||
| </view> | |||
| </view> | |||
| </uv-popup> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| export default { | |||
| data() { | |||
| return { | |||
| form: { | |||
| image: null, | |||
| }, | |||
| rules: { | |||
| 'content': { | |||
| type: 'image', | |||
| required: true, | |||
| message: '请上传图片', | |||
| }, | |||
| }, | |||
| } | |||
| }, | |||
| methods: { | |||
| onUpload() { | |||
| uni.chooseImage({ | |||
| count: 1, | |||
| sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有 | |||
| success: res => { | |||
| let image = res.tempFilePaths[0] // 将选择的图片赋值给我们定义的cover | |||
| this.$Oss.ossUpload(image) | |||
| .then(url => { | |||
| this.form.image = url | |||
| }) | |||
| } | |||
| }); | |||
| }, | |||
| async onSubmit() { | |||
| try { | |||
| await this.$refs.form.validate() | |||
| const { | |||
| } = this.form | |||
| const params = { | |||
| } | |||
| // todo: fetch | |||
| // await this.$fetch('updateAddress', params) | |||
| uni.showToast({ | |||
| icon: 'success', | |||
| title: '提交成功', | |||
| }); | |||
| this.$emit('submitted') | |||
| this.close() | |||
| } catch (err) { | |||
| console.log('onSave err', err) | |||
| } | |||
| }, | |||
| }, | |||
| } | |||
| </script> | |||
| <style lang="scss" scoped> | |||
| .popup__view { | |||
| width: 100vw; | |||
| display: flex; | |||
| flex-direction: column; | |||
| box-sizing: border-box; | |||
| background: #FFFFFF; | |||
| border-top-left-radius: 32rpx; | |||
| border-top-right-radius: 32rpx; | |||
| } | |||
| .header { | |||
| position: relative; | |||
| width: 100%; | |||
| padding: 24rpx 0; | |||
| box-sizing: border-box; | |||
| border-bottom: 2rpx solid #EEEEEE; | |||
| .title { | |||
| font-family: PingFang SC; | |||
| font-weight: 500; | |||
| font-size: 34rpx; | |||
| line-height: 1.4; | |||
| color: #181818; | |||
| } | |||
| .btn { | |||
| font-family: PingFang SC; | |||
| font-weight: 500; | |||
| font-size: 32rpx; | |||
| line-height: 1.4; | |||
| color: #8B8B8B; | |||
| position: absolute; | |||
| top: 26rpx; | |||
| left: 40rpx; | |||
| } | |||
| } | |||
| .form { | |||
| max-height: 75vh; | |||
| padding: 32rpx 40rpx; | |||
| box-sizing: border-box; | |||
| overflow-y: auto; | |||
| &-item { | |||
| padding: 8rpx 0 6rpx 0; | |||
| & + & { | |||
| padding-top: 24rpx; | |||
| border-top: 2rpx solid #EEEEEE; | |||
| } | |||
| &-label { | |||
| margin-bottom: 14rpx; | |||
| display: flex; | |||
| align-items: center; | |||
| font-family: PingFang SC; | |||
| font-weight: 400; | |||
| font-size: 26rpx; | |||
| line-height: 1.4; | |||
| color: #181818; | |||
| .icon { | |||
| margin-right: 8rpx; | |||
| width: 16rpx; | |||
| height: auto; | |||
| } | |||
| } | |||
| &-content { | |||
| .text { | |||
| padding: 2rpx 0; | |||
| font-family: PingFang SC; | |||
| font-weight: 400; | |||
| font-size: 32rpx; | |||
| line-height: 1.4; | |||
| &.placeholder { | |||
| color: #C6C6C6; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| .footer { | |||
| width: 100%; | |||
| padding: 32rpx 40rpx; | |||
| box-sizing: border-box; | |||
| border-top: 2rpx solid #F1F1F1; | |||
| .btn { | |||
| width: 100%; | |||
| padding: 14rpx 0; | |||
| box-sizing: border-box; | |||
| font-family: PingFang SC; | |||
| font-weight: 500; | |||
| font-size: 36rpx; | |||
| line-height: 1.4; | |||
| color: #FFFFFF; | |||
| background-image: linear-gradient(to right, #21FEEC, #019AF9); | |||
| border: 2rpx solid #00A9FF; | |||
| border-radius: 41rpx; | |||
| } | |||
| } | |||
| .btn-avatar { | |||
| display: inline-block; | |||
| width: auto; | |||
| border: none; | |||
| } | |||
| .avatar { | |||
| position: relative; | |||
| width: 200rpx; | |||
| height: 200rpx; | |||
| border-radius: 24rpx; | |||
| overflow: hidden; | |||
| .img { | |||
| width: 100%; | |||
| height: 100%; | |||
| } | |||
| .mask { | |||
| position: absolute; | |||
| top: 0; | |||
| left: 0; | |||
| width: 100%; | |||
| height: 100%; | |||
| background: #00000080; | |||
| border-radius: 24rpx; | |||
| .icon { | |||
| width: 64rpx; | |||
| height: 64rpx; | |||
| } | |||
| } | |||
| &.is-empty { | |||
| background: #F3F2F7; | |||
| .icon { | |||
| width: 61rpx; | |||
| height: auto; | |||
| } | |||
| } | |||
| } | |||
| </style> | |||
| @ -0,0 +1,353 @@ | |||
| <template> | |||
| <view> | |||
| <uv-popup ref="popup" mode="bottom" bgColor="none" > | |||
| <view class="popup__view"> | |||
| <view class="flex header"> | |||
| <view class="title">新增记录</view> | |||
| <button class="btn" @click="close">关闭</button> | |||
| </view> | |||
| <view class="form"> | |||
| <uv-form | |||
| ref="form" | |||
| :model="form" | |||
| :rules="rules" | |||
| errorType="toast" | |||
| > | |||
| <view class="form-item"> | |||
| <uv-form-item prop="project" :customStyle="formItemStyle"> | |||
| <view class="form-item-label"> | |||
| <image class="icon" src="@/static/image/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-else class="text placeholder">请选择关联项目</view> | |||
| <uv-icon name="arrow-right" color="#C6C6C6" size="32rpx"></uv-icon> | |||
| </view> | |||
| <reloateProjectPopup ref="reloateProjectPopup" :options="projects" @confirm="onRelateProjectChange"></reloateProjectPopup> | |||
| </view> | |||
| </uv-form-item> | |||
| </view> | |||
| <view class="form-item"> | |||
| <uv-form-item prop="tripNum" :customStyle="formItemStyle"> | |||
| <view class="flex row"> | |||
| <view class="form-item-label">行程</view> | |||
| <view class="form-item-content"> | |||
| <formRate v-model="form.tripNum"></formRate> | |||
| </view> | |||
| </view> | |||
| </uv-form-item> | |||
| </view> | |||
| <view class="form-item"> | |||
| <uv-form-item prop="spotNum" :customStyle="formItemStyle"> | |||
| <view class="flex row"> | |||
| <view class="form-item-label">景点</view> | |||
| <view class="form-item-content"> | |||
| <formRate v-model="form.spotNum"></formRate> | |||
| </view> | |||
| </view> | |||
| </uv-form-item> | |||
| </view> | |||
| <view class="form-item"> | |||
| <uv-form-item prop="mentorNum" :customStyle="formItemStyle"> | |||
| <view class="flex row"> | |||
| <view class="form-item-label">导师</view> | |||
| <view class="form-item-content"> | |||
| <formRate v-model="form.mentorNum"></formRate> | |||
| </view> | |||
| </view> | |||
| </uv-form-item> | |||
| </view> | |||
| <view class="form-item"> | |||
| <uv-form-item prop="images" :customStyle="formItemStyle"> | |||
| <view class="form-item-label">上传图片</view> | |||
| <view class="form-item-content"> | |||
| <formUpload v-model="form.images"></formUpload> | |||
| </view> | |||
| </uv-form-item> | |||
| </view> | |||
| <view class="form-item" v-for="(item, index) in questions" :key="item.id"> | |||
| <uv-form-item :prop="`texts[${index}]`" :customStyle="formItemStyle"> | |||
| <view class="form-item-label"> | |||
| <image class="icon" src="@/static/image/icon-require.png" mode="widthFix"></image> | |||
| {{ item.label }} | |||
| </view> | |||
| <view class="form-item-content"> | |||
| <formTextarea v-model="form.texts[index]"></formTextarea> | |||
| </view> | |||
| </uv-form-item> | |||
| </view> | |||
| </uv-form> | |||
| </view> | |||
| <view class="footer"> | |||
| <button class="flex btn" @click="onPublish">发布</button> | |||
| </view> | |||
| </view> | |||
| </uv-popup> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| import reloateProjectPopup from './reloateProjectPopup.vue' | |||
| import formTextarea from '@/pages_order/components/formTextarea.vue' | |||
| import formUpload from '@/pages_order/components/formUpload.vue' | |||
| import formRate from '@/pages_order/components/formRate.vue' | |||
| export default { | |||
| components: { | |||
| reloateProjectPopup, | |||
| formTextarea, | |||
| formUpload, | |||
| formRate, | |||
| }, | |||
| data() { | |||
| return { | |||
| form: { | |||
| project: null, | |||
| tripNum: null, | |||
| spotNum: null, | |||
| mentorNum: null, | |||
| images: [], | |||
| texts: [], | |||
| }, | |||
| rules: { | |||
| // todo | |||
| }, | |||
| projects: [], | |||
| questions: [], | |||
| } | |||
| }, | |||
| computed: { | |||
| projectDesc() { | |||
| const { project } = this.form | |||
| const target = this.projects?.find?.(item => item.id === project) | |||
| return target?.name || '' | |||
| }, | |||
| }, | |||
| methods: { | |||
| getData() { | |||
| // todo | |||
| this.projects = [ | |||
| { | |||
| id: '001', | |||
| name: '亲子•坝上双草原6日 |乌兰布统+锡林郭勒+长城', | |||
| }, | |||
| { | |||
| id: '002', | |||
| name: '青青草原•云中岭 |5-10公里AB线强度可选', | |||
| }, | |||
| { | |||
| id: '003', | |||
| name: '新疆天山行7/9日丨醉美伊犁&吐鲁番双套餐', | |||
| }, | |||
| { | |||
| id: '004', | |||
| name: '九色甘南|人间净土6日/7日深度游', | |||
| }, | |||
| { | |||
| id: '005', | |||
| name: '北疆全景12日| 入疆首推!阿勒泰+伊犁+吐鲁番', | |||
| }, | |||
| { | |||
| id: '006', | |||
| name: '塞上江南•神奇宁夏5日|穿越大漠与历史对话', | |||
| }, | |||
| { | |||
| id: '007', | |||
| name: '尊享•天山环线9日| 伊犁全景+独库,头等舱大巴', | |||
| }, | |||
| ] | |||
| this.questions = [ | |||
| { | |||
| id: '001', | |||
| label: '这次研学之旅,整体给你留下了怎样的印象?用几个词或几句话简单概括一下', | |||
| }, | |||
| { | |||
| id: '002', | |||
| label: '在整个行程中,你最喜欢的部分是哪里?为什么?', | |||
| }, | |||
| { | |||
| id: '003', | |||
| label: '你觉得这次研学的行程安排是否合理?有没有哪些地方让你觉得特别满意或需要改进的?', | |||
| }, | |||
| ] | |||
| }, | |||
| async open() { | |||
| await this.getData() | |||
| const texts = this.questions.map(() => '') | |||
| this.form = { | |||
| project: null, | |||
| tripNum: null, | |||
| spotNum: null, | |||
| mentorNum: null, | |||
| images: [], | |||
| texts, | |||
| } | |||
| this.$refs.popup.open() | |||
| }, | |||
| close() { | |||
| this.$refs.popup.close() | |||
| }, | |||
| openRelatePojectPicker() { | |||
| this.$refs.reloateProjectPopup.open(this.form.project?.id || null) | |||
| }, | |||
| onRelateProjectChange(id) { | |||
| this.form.project = id | |||
| }, | |||
| async onPublish() { | |||
| try { | |||
| await this.$refs.form.validate() | |||
| const { | |||
| } = this.form | |||
| const params = { | |||
| } | |||
| // todo: fetch | |||
| // await this.$fetch('updateAddress', params) | |||
| uni.showToast({ | |||
| icon: 'success', | |||
| title: '发布成功', | |||
| }); | |||
| this.$emit('submitted') | |||
| this.close() | |||
| } catch (err) { | |||
| console.log('onSave err', err) | |||
| } | |||
| }, | |||
| }, | |||
| } | |||
| </script> | |||
| <style lang="scss" scoped> | |||
| .popup__view { | |||
| width: 100vw; | |||
| display: flex; | |||
| flex-direction: column; | |||
| box-sizing: border-box; | |||
| background: #FFFFFF; | |||
| border-top-left-radius: 32rpx; | |||
| border-top-right-radius: 32rpx; | |||
| } | |||
| .header { | |||
| position: relative; | |||
| width: 100%; | |||
| padding: 24rpx 0; | |||
| box-sizing: border-box; | |||
| border-bottom: 2rpx solid #EEEEEE; | |||
| .title { | |||
| font-family: PingFang SC; | |||
| font-weight: 500; | |||
| font-size: 34rpx; | |||
| line-height: 1.4; | |||
| color: #181818; | |||
| } | |||
| .btn { | |||
| font-family: PingFang SC; | |||
| font-weight: 500; | |||
| font-size: 32rpx; | |||
| line-height: 1.4; | |||
| color: #8B8B8B; | |||
| position: absolute; | |||
| top: 26rpx; | |||
| left: 40rpx; | |||
| } | |||
| } | |||
| .form { | |||
| max-height: 75vh; | |||
| padding: 32rpx 40rpx; | |||
| box-sizing: border-box; | |||
| overflow-y: auto; | |||
| &-item { | |||
| padding: 8rpx 0 6rpx 0; | |||
| & + & { | |||
| padding-top: 24rpx; | |||
| border-top: 2rpx solid #EEEEEE; | |||
| } | |||
| &-label { | |||
| margin-bottom: 14rpx; | |||
| display: flex; | |||
| align-items: center; | |||
| font-family: PingFang SC; | |||
| font-weight: 400; | |||
| font-size: 26rpx; | |||
| line-height: 1.4; | |||
| color: #181818; | |||
| .icon { | |||
| margin-right: 8rpx; | |||
| width: 16rpx; | |||
| height: auto; | |||
| } | |||
| } | |||
| &-content { | |||
| .text { | |||
| padding: 2rpx 0; | |||
| font-family: PingFang SC; | |||
| font-weight: 400; | |||
| font-size: 32rpx; | |||
| line-height: 1.4; | |||
| &.placeholder { | |||
| color: #C6C6C6; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| .row { | |||
| justify-content: space-between; | |||
| .form-label { | |||
| margin: 0; | |||
| } | |||
| } | |||
| .footer { | |||
| width: 100%; | |||
| padding: 32rpx 40rpx; | |||
| box-sizing: border-box; | |||
| border-top: 2rpx solid #F1F1F1; | |||
| .btn { | |||
| width: 100%; | |||
| padding: 14rpx 0; | |||
| box-sizing: border-box; | |||
| font-family: PingFang SC; | |||
| font-weight: 500; | |||
| font-size: 36rpx; | |||
| line-height: 1.4; | |||
| color: #FFFFFF; | |||
| background-image: linear-gradient(to right, #21FEEC, #019AF9); | |||
| border: 2rpx solid #00A9FF; | |||
| border-radius: 41rpx; | |||
| } | |||
| } | |||
| </style> | |||
| @ -0,0 +1,121 @@ | |||
| <template> | |||
| <view> | |||
| <uv-popup ref="popup" mode="bottom" bgColor="none" > | |||
| <view class="popup__view"> | |||
| <view class="flex header"> | |||
| <view class="title">选择关联项目</view> | |||
| <button class="btn" @click="onConfirm">确认</button> | |||
| </view> | |||
| <view class="content"> | |||
| <uv-radio-group | |||
| v-model="selectedId" | |||
| placement="column" | |||
| shape="circle" | |||
| size="36rpx" | |||
| iconSize="36rpx" | |||
| activeColor="#00A9FF" | |||
| > | |||
| <view class="flex option" v-for="item in options" :key="item.id"> | |||
| <view class="radio"> | |||
| <uv-radio :name="item.id"></uv-radio> | |||
| </view> | |||
| <view class="text-ellipsis"> | |||
| {{ item.name }} | |||
| </view> | |||
| </view> | |||
| </uv-radio-group> | |||
| </view> | |||
| </view> | |||
| </uv-popup> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| export default { | |||
| props: { | |||
| options: { | |||
| type: Array, | |||
| default() { | |||
| return [] | |||
| } | |||
| }, | |||
| }, | |||
| data() { | |||
| return { | |||
| selectedId: null, | |||
| } | |||
| }, | |||
| onLoad() {}, | |||
| methods: { | |||
| async open(projectId) { | |||
| this.selectedId = projectId | |||
| this.$refs.popup.open() | |||
| }, | |||
| close() { | |||
| this.$refs.popup.close() | |||
| }, | |||
| onConfirm() { | |||
| this.$emit('confirm', this.selectedId) | |||
| this.close() | |||
| }, | |||
| }, | |||
| } | |||
| </script> | |||
| <style lang="scss" scoped> | |||
| .popup__view { | |||
| width: 100vw; | |||
| display: flex; | |||
| flex-direction: column; | |||
| box-sizing: border-box; | |||
| background: #FFFFFF; | |||
| border-top-left-radius: 32rpx; | |||
| border-top-right-radius: 32rpx; | |||
| } | |||
| .header { | |||
| position: relative; | |||
| width: 100%; | |||
| padding: 24rpx 0; | |||
| box-sizing: border-box; | |||
| border-bottom: 2rpx solid #EEEEEE; | |||
| .title { | |||
| font-family: PingFang SC; | |||
| font-weight: 500; | |||
| font-size: 34rpx; | |||
| line-height: 1.4; | |||
| color: #181818; | |||
| } | |||
| .btn { | |||
| font-family: PingFang SC; | |||
| font-weight: 500; | |||
| font-size: 32rpx; | |||
| line-height: 1.4; | |||
| color: $uni-color; | |||
| position: absolute; | |||
| top: 26rpx; | |||
| right: 40rpx; | |||
| } | |||
| } | |||
| .content { | |||
| padding: 8rpx 40rpx; | |||
| } | |||
| .option { | |||
| justify-content: flex-start; | |||
| column-gap: 16rpx; | |||
| padding: 32rpx 0; | |||
| font-family: PingFang SC; | |||
| font-size: 32rpx; | |||
| font-weight: 400; | |||
| line-height: 1.4; | |||
| color: #181818; | |||
| border-bottom: 2rpx solid #EEEEEE; | |||
| } | |||
| </style> | |||
| @ -0,0 +1,171 @@ | |||
| <template> | |||
| <view class="page__view"> | |||
| <!-- 导航栏 --> | |||
| <navbar title="搜索结果" leftClick @leftClick="$utils.navigateBack" bgColor="transparent" color="#191919" /> | |||
| <!-- 搜索栏 --> | |||
| <view class="flex search"> | |||
| <uv-search | |||
| v-model="keyword" | |||
| placeholder="输入关键词搜索" | |||
| color="#181818" | |||
| bgColor="transparent" | |||
| :showAction="true" | |||
| @custom="search" | |||
| @search="search" | |||
| @focus="isFocusSearch = true" | |||
| @blur="isFocusSearch = false" | |||
| > | |||
| <template #prefix> | |||
| <image class="search-icon" src="/static/image/icon-search-dark.png" mode="widthFix"></image> | |||
| </template> | |||
| </uv-search> | |||
| </view> | |||
| <view class="main"> | |||
| <sortBar v-model="queryParams.sort" @change="onSortChange"></sortBar> | |||
| <view v-if="list.length" class="list"> | |||
| <recordsView :list="list"></recordsView> | |||
| </view> | |||
| <template v-else> | |||
| <uv-empty mode="list"></uv-empty> | |||
| </template> | |||
| </view> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| import mixinsList from '@/mixins/list.js' | |||
| import sortBar from './sortBar.vue' | |||
| import recordsView from '@/components/growing/recordsView.vue' | |||
| export default { | |||
| mixins: [mixinsList], | |||
| components: { | |||
| sortBar, | |||
| recordsView, | |||
| }, | |||
| data() { | |||
| return { | |||
| keyword: '', | |||
| queryParams: { | |||
| pageNo: 1, | |||
| pageSize: 10, | |||
| title: '', | |||
| sort: 'comprehensive', | |||
| }, | |||
| // todo | |||
| mixinsListApi: '', | |||
| } | |||
| }, | |||
| onLoad({ search }) { | |||
| if (search) { | |||
| this.keyword = search | |||
| this.queryParams.title = search | |||
| } | |||
| this.getData() | |||
| }, | |||
| methods: { | |||
| // todo: delete | |||
| getData() { | |||
| this.list = [ | |||
| { | |||
| id: '001', | |||
| name: '新疆天山行7/9日丨醉美伊犁&吐鲁番双套餐', | |||
| image: [ | |||
| '/static/image/temp-38.png', | |||
| '/static/image/temp-39.png', | |||
| '/static/image/temp-40.png', | |||
| ], | |||
| createTime: '2025-07-12', | |||
| }, | |||
| { | |||
| id: '002', | |||
| name: '仙踪新昌·韩妃江古道|邂逅“江南小桂林”', | |||
| image: [ | |||
| '/static/image/temp-41.png', | |||
| '/static/image/temp-42.png', | |||
| '/static/image/temp-43.png', | |||
| ], | |||
| createTime: '2025-06-18', | |||
| }, | |||
| { | |||
| id: '003', | |||
| name: '山水石窟·大佛寺|江南佛窟造像,新昌山水轻徒', | |||
| image: [ | |||
| '/static/image/temp-44.png', | |||
| '/static/image/temp-45.png', | |||
| '/static/image/temp-46.png', | |||
| ], | |||
| createTime: '2025-06-15', | |||
| }, | |||
| ] | |||
| }, | |||
| search() { | |||
| this.queryParams.pageNo = 1 | |||
| this.queryParams.pageSize = 10 | |||
| this.queryParams.title = this.keyword | |||
| this.getData() | |||
| }, | |||
| onSortChange(sort) { | |||
| console.log('onSortChange', sort) | |||
| }, | |||
| }, | |||
| } | |||
| </script> | |||
| <style scoped lang="scss"> | |||
| .search { | |||
| $h: 64rpx; | |||
| $radius: 32rpx; | |||
| $borderWidth: 4rpx; | |||
| margin: 24rpx 32rpx 0 32rpx; | |||
| width: calc(100% - 32rpx * 2); | |||
| height: $h; | |||
| position: relative; | |||
| border-radius: $radius; | |||
| &-icon { | |||
| margin: 0 13rpx 0 26rpx; | |||
| width: 30rpx; | |||
| height: auto; | |||
| } | |||
| /deep/ .uv-search__content { | |||
| padding: 12rpx 0; | |||
| background: #FFFFFF !important; | |||
| border-color: #CFEFFF !important; | |||
| border: 4rpx solid transparent; | |||
| } | |||
| /deep/ .uv-search__action { | |||
| padding: 19rpx 24rpx; | |||
| font-size: 26rpx; | |||
| font-weight: 500; | |||
| line-height: 1; | |||
| color: #FFFFFF; | |||
| background: #00A9FF; | |||
| border-radius: 32rpx; | |||
| } | |||
| } | |||
| .main { | |||
| margin-top: 24rpx; | |||
| padding: 0 32rpx 100rpx 32rpx; | |||
| } | |||
| .content { | |||
| margin-top: 24rpx; | |||
| display: grid; | |||
| grid-template-columns: repeat(2, 1fr); | |||
| gap: 16rpx; | |||
| } | |||
| </style> | |||
| @ -0,0 +1,107 @@ | |||
| <template> | |||
| <view class="flex sort" :style="style"> | |||
| <view :class="['flex', 'sort-item', sort == 'comprehensive' ? 'is-active' : '']" @click="onClickSort('comprehensive')">地点</view> | |||
| <view :class="['flex', 'sort-item', ['sale-asc', 'sale-desc'].includes(sort) ? 'is-active' : '']" @click="onClickSort('sale')"> | |||
| <view>主题</view> | |||
| <view class="sort-item-icon"> | |||
| <uv-icon v-if="sort == 'sale-asc'" name="arrow-up-fill" color="#00A9FF" size="16rpx" :bold="true"></uv-icon> | |||
| <uv-icon v-else-if="sort == 'sale-desc'" name="arrow-down-fill" color="#00A9FF" size="16rpx" :bold="true"></uv-icon> | |||
| <image v-else style="width: 8rpx; height: auto;" src="/static/image/icon-sort.png" mode="widthFix"></image> | |||
| </view> | |||
| </view> | |||
| <view :class="['flex', 'sort-item', ['price-asc', 'price-desc'].includes(sort) ? 'is-active' : '']" @click="onClickSort('price')"> | |||
| <view>时间</view> | |||
| <view class="sort-item-icon"> | |||
| <uv-icon v-if="sort == 'price-asc'" name="arrow-up-fill" color="#00A9FF" size="16rpx" :bold="true"></uv-icon> | |||
| <uv-icon v-else-if="sort == 'price-desc'" name="arrow-down-fill" color="#00A9FF" size="16rpx" :bold="true"></uv-icon> | |||
| <image v-else style="width: 8rpx; height: auto;" src="/static/image/icon-sort.png" mode="widthFix"></image> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| export default { | |||
| props: { | |||
| value: { | |||
| type: String, | |||
| default: 'comprehensive' | |||
| }, | |||
| style: { | |||
| type: String, | |||
| default: '' | |||
| } | |||
| }, | |||
| computed: { | |||
| sort: { | |||
| set(val) { | |||
| this.$emit('input', val) | |||
| }, | |||
| get() { | |||
| return this.value | |||
| } | |||
| } | |||
| }, | |||
| methods: { | |||
| onClickSort(key) { | |||
| let sort = 'comprehensive' | |||
| switch(key) { | |||
| case 'comprehensive': | |||
| sort = 'comprehensive' | |||
| break; | |||
| case 'sale': | |||
| if (this.sort == 'sale-desc') { | |||
| sort = 'sale-asc' | |||
| } else { | |||
| sort = 'sale-desc' | |||
| } | |||
| break; | |||
| case 'price': | |||
| if (this.sort == 'price-desc') { | |||
| sort = 'price-asc' | |||
| } else { | |||
| sort = 'price-desc' | |||
| } | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| this.sort = sort | |||
| this.$emit('change', sort) | |||
| }, | |||
| }, | |||
| } | |||
| </script> | |||
| <style scoped lang="scss"> | |||
| .sort { | |||
| width: 100%; | |||
| justify-content: space-between; | |||
| &-item { | |||
| padding: 12rpx 32rpx; | |||
| font-size: 28rpx; | |||
| line-height: 1.5; | |||
| color: #191919; | |||
| column-gap: 4rpx; | |||
| &.is-active { | |||
| font-weight: 600; | |||
| color: #00A9FF; | |||
| } | |||
| &-icon { | |||
| width: 32rpx; | |||
| display: inline-flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| } | |||
| } | |||
| } | |||
| </style> | |||
| @ -0,0 +1,95 @@ | |||
| <template> | |||
| <view class="flex card"> | |||
| <view class="radio" v-if="showRadio"> | |||
| <uv-radio :name="data.id"></uv-radio> | |||
| </view> | |||
| <view class="info"> | |||
| <view class="title">{{ typeDesc }}</view> | |||
| <view class="row"> | |||
| <view class="row-label">绑定人:</view> | |||
| <view class="row-content">{{ data.name }}</view> | |||
| </view> | |||
| <view class="row"> | |||
| <view class="row-label">申请人ID:</view> | |||
| <view class="row-content">{{ data.userId }}</view> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| const TYPE_AND_DESC_MAPPING = { | |||
| 0: '学生', | |||
| 1: '家长', | |||
| } | |||
| export default { | |||
| props: { | |||
| data: { | |||
| type: Object, | |||
| default() { | |||
| return {} | |||
| } | |||
| }, | |||
| value: { | |||
| type: String, | |||
| default: null, | |||
| }, | |||
| showRadio: { | |||
| type: Boolean, | |||
| default: false | |||
| }, | |||
| }, | |||
| data() { | |||
| return { | |||
| } | |||
| }, | |||
| computed: { | |||
| typeDesc() { | |||
| const { type } = this.data | |||
| return TYPE_AND_DESC_MAPPING[type] || '' | |||
| }, | |||
| }, | |||
| methods: { | |||
| }, | |||
| } | |||
| </script> | |||
| <style scoped lang="scss"> | |||
| .card { | |||
| justify-content: flex-start; | |||
| column-gap: 24rpx; | |||
| padding: 40rpx 32rpx; | |||
| font-family: PingFang SC; | |||
| font-weight: 400; | |||
| line-height: 1.4; | |||
| background: #FFFFFF; | |||
| border-radius: 32rpx; | |||
| } | |||
| .title { | |||
| font-size: 32rpx; | |||
| font-weight: 500; | |||
| color: #181818; | |||
| } | |||
| .row { | |||
| margin-top: 16rpx; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: flex-start; | |||
| column-gap: 4rpx; | |||
| font-size: 28rpx; | |||
| &-label { | |||
| color: #8B8B8B; | |||
| } | |||
| &-content { | |||
| color: #393939; | |||
| } | |||
| } | |||
| </style> | |||
| @ -0,0 +1,139 @@ | |||
| <template> | |||
| <view class="page__view"> | |||
| <navbar title="我的优惠券" leftClick @leftClick="$utils.navigateBack" color="#191919" bgColor="#FFFFFF" /> | |||
| <view class="list"> | |||
| <uv-radio-group | |||
| v-model="selectedId" | |||
| placement="column" | |||
| shape="circle" | |||
| size="36rpx" | |||
| iconSize="36rpx" | |||
| activeColor="#00A9FF" | |||
| @change="onRadioChange" | |||
| > | |||
| <view class="list-item" v-for="item in list" :key="item.id"> | |||
| <memberCard | |||
| :data="item" | |||
| :showRadio="true" | |||
| ></memberCard> | |||
| </view> | |||
| </uv-radio-group> | |||
| </view> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| import { mapState } from 'vuex' | |||
| import mixinsList from '@/mixins/list.js' | |||
| import memberCard from './memberCard.vue' | |||
| export default { | |||
| mixins: [mixinsList], | |||
| components: { | |||
| memberCard, | |||
| }, | |||
| data() { | |||
| return { | |||
| // todo: check key | |||
| mixinsListApi: '', | |||
| queryParams: { | |||
| pageNo: 1, | |||
| pageSize: 10, | |||
| }, | |||
| selectedId: null, | |||
| } | |||
| }, | |||
| computed: { | |||
| ...mapState(['memberInfo']), | |||
| }, | |||
| onLoad(arg) { | |||
| if (this.memberInfo?.id) { | |||
| this.memberInfo = this.memberInfo.id | |||
| } | |||
| this.getData() | |||
| }, | |||
| onUnload() { | |||
| if (!this.selectedId) { | |||
| this.$store.commit('setMemberInfo', null) | |||
| return | |||
| } | |||
| const target = this.list.find(item => item.id === this.selectedId) | |||
| 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> | |||
| <style scoped lang="scss"> | |||
| .page__view { | |||
| width: 100vw; | |||
| min-height: 100vh; | |||
| background-color: $uni-bg-color; | |||
| position: relative; | |||
| } | |||
| .list { | |||
| padding: 32rpx 40rpx; | |||
| &-item { | |||
| & + & { | |||
| margin-top: 24rpx; | |||
| } | |||
| } | |||
| } | |||
| </style> | |||