- 新增任务中心页面,支持任务列表展示、任务接受、任务提交等功能 - 新增订单详情页面,展示订单详细信息及服务记录 - 新增个人信息页面,支持用户头像、昵称等信息修改 - 新增配置信息初始化功能,优化全局配置管理 - 新增新用户优惠券弹窗,提升用户体验master
| @ -0,0 +1,12 @@ | |||||
| // 小程序-配置信息 | |||||
| import request from '@/utils/request' | |||||
| // 小程序-配置信息列表数据查询 | |||||
| export function getConfigList() { | |||||
| return request({ | |||||
| 'url': '/applet/config/configList', | |||||
| 'method': 'get' | |||||
| }).then(res => { | |||||
| return res.data | |||||
| }) | |||||
| } | |||||
| @ -0,0 +1,39 @@ | |||||
| import request from '@/utils/request' | |||||
| // 获取任务列表 | |||||
| export function getTaskList(data={}){ | |||||
| return request({ | |||||
| url: `/h5/task/list`, | |||||
| headers:{ "isToken":true}, | |||||
| method: 'get', | |||||
| params: data | |||||
| }) | |||||
| } | |||||
| // 接受任务 | |||||
| export function acceptTask(taskId){ | |||||
| return request({ | |||||
| url: `/h5/task/accept/${taskId}`, | |||||
| headers:{ "isToken":true}, | |||||
| method: 'post' | |||||
| }) | |||||
| } | |||||
| // 提交任务 | |||||
| export function submitTask(data){ | |||||
| return request({ | |||||
| url: `/h5/task/submit`, | |||||
| headers:{ "isToken":true}, | |||||
| method: 'post', | |||||
| data | |||||
| }) | |||||
| } | |||||
| // 获取任务详情 | |||||
| export function getTaskDetail(taskId){ | |||||
| return request({ | |||||
| url: `/h5/task/detail/${taskId}`, | |||||
| headers:{ "isToken":true}, | |||||
| method: 'get' | |||||
| }) | |||||
| } | |||||
| @ -0,0 +1,61 @@ | |||||
| import { mapState } from 'vuex' | |||||
| export default { | |||||
| data() { | |||||
| return { | |||||
| // 默认的全局分享内容 | |||||
| Gshare: { | |||||
| // title: '三只青蛙', | |||||
| path: '/pages_order/auth/wxLogin', // 全局分享的路径,比如 首页 | |||||
| // imageUrl: '/static/image/login/logo.png', // 全局分享的图片(可本地可网络) | |||||
| } | |||||
| } | |||||
| }, | |||||
| computed: { | |||||
| ...mapState(['configList', 'userInfo', 'riceInfo']), | |||||
| currentPagePath() { | |||||
| const pages = getCurrentPages(); | |||||
| const currentPage = pages[pages.length - 1]; | |||||
| let path = `/${currentPage.route}`; | |||||
| // 获取当前页面的参数 | |||||
| const options = currentPage.options; | |||||
| if (options && Object.keys(options).length > 0) { | |||||
| const params = this.$utils.objectToUrlParams(options); | |||||
| path += `?${params}`; | |||||
| } | |||||
| return path; | |||||
| }, | |||||
| }, | |||||
| // 定义全局分享 | |||||
| // 1.发送给朋友 | |||||
| onShareAppMessage(res) { | |||||
| let o = { | |||||
| title : this.configList.logo_name, | |||||
| ...this.Gshare, | |||||
| } | |||||
| if(this.userInfo.id){ | |||||
| if(this.Gshare.path.includes('?')){ | |||||
| o.path += '&shareId=' + this.userInfo.id | |||||
| }else{ | |||||
| o.path += '?shareId=' + this.userInfo.id | |||||
| } | |||||
| } | |||||
| return o | |||||
| }, | |||||
| //2.分享到朋友圈 | |||||
| onShareTimeline(res) { | |||||
| let o = { | |||||
| ...this.Gshare, | |||||
| title : this.configList.logo_name, | |||||
| } | |||||
| if(this.userInfo.id){ | |||||
| o.path = this.Gshare.path + '?shareId=' + this.userInfo.id | |||||
| } | |||||
| return o | |||||
| }, | |||||
| methods: { | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,78 @@ | |||||
| /** | |||||
| * 处理查询参数 | |||||
| * @param {Object} self - 组件实例 | |||||
| * @param {Object} queryParams - 额外的查询参数 | |||||
| * @returns {Object} 合并后的查询参数 | |||||
| */ | |||||
| function query(self, queryParams){ | |||||
| // 深度合并对象 | |||||
| return self.$utils.deepMergeObject( | |||||
| self.$utils.deepMergeObject(self.queryParams, | |||||
| (self.beforeGetData && self.beforeGetData()) || {}), | |||||
| queryParams) | |||||
| } | |||||
| /** | |||||
| * 列表数据加载混入 | |||||
| * 提供列表数据的加载、分页、下拉刷新、上拉加载更多等功能 | |||||
| */ | |||||
| export default { | |||||
| data() { | |||||
| return { | |||||
| queryParams: { | |||||
| pageNo: 1, | |||||
| pageSize: 10, | |||||
| }, | |||||
| total : 0, | |||||
| list : [], | |||||
| } | |||||
| }, | |||||
| // 下拉刷新 | |||||
| onPullDownRefresh() { | |||||
| this.getData() | |||||
| }, | |||||
| // 上拉加载更多 | |||||
| onReachBottom() { | |||||
| this.loadMoreData() | |||||
| }, | |||||
| // 页面显示时加载数据 | |||||
| onShow() { | |||||
| this.getData() | |||||
| }, | |||||
| methods: { | |||||
| /** | |||||
| * 获取列表数据 | |||||
| * @param {Object} queryParams - 查询参数 | |||||
| * @returns {Promise} 返回Promise对象 | |||||
| */ | |||||
| getData(queryParams){ | |||||
| return new Promise((success, error) => { | |||||
| if(!this.mixinsListApi){ | |||||
| return console.error('mixinsListApi 缺失'); | |||||
| } | |||||
| this.$api(this.mixinsListApi, | |||||
| query(this, queryParams), res => { | |||||
| uni.stopPullDownRefresh() | |||||
| if(res.code == 200){ | |||||
| success(res.result) | |||||
| // 更新列表数据 | |||||
| this[this.mixinsListKey || 'list'] = res.result.records || res.result | |||||
| // 更新总数 | |||||
| this.total = res.result.total || res.result.length | |||||
| // 调用数据加载完成的回调 | |||||
| this.getDataThen && this.getDataThen(res.result.records, res.result.total, res.result) | |||||
| } | |||||
| }) | |||||
| }) | |||||
| }, | |||||
| /** | |||||
| * 加载更多数据 | |||||
| */ | |||||
| loadMoreData(){ | |||||
| if(this.queryParams.pageSize < this.total){ | |||||
| this.queryParams.pageSize += 10 | |||||
| this.getData() | |||||
| } | |||||
| }, | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,120 @@ | |||||
| <template> | |||||
| <view class="new-user-coupon" v-if="showPopup"> | |||||
| <view class="mask" @click="closePopup"></view> | |||||
| <view class="coupon-container"> | |||||
| <view class="coupon-content"> | |||||
| <image class="coupon-image" src="https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/coupon/new-user-coupon.png" mode="widthFix"></image> | |||||
| <view class="coupon-btn" @click="getCoupon">立即领取</view> | |||||
| </view> | |||||
| <view class="close-btn" @click="closePopup"> | |||||
| <text class="close-icon">×</text> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| </template> | |||||
| <script> | |||||
| import { getToken } from '@/utils/auth' | |||||
| export default { | |||||
| name: 'NewUserCoupon', | |||||
| data() { | |||||
| return { | |||||
| showPopup: true | |||||
| } | |||||
| }, | |||||
| methods: { | |||||
| closePopup() { | |||||
| this.showPopup = false | |||||
| this.$emit('close') | |||||
| }, | |||||
| getCoupon() { | |||||
| // 检查用户是否已登录 | |||||
| if (!getToken()) { | |||||
| // 未登录,跳转到登录页面 | |||||
| uni.navigateTo({ | |||||
| url: '/pages/login/index' | |||||
| }) | |||||
| } else { | |||||
| // 已登录,触发领券事件 | |||||
| this.$emit('getCoupon') | |||||
| this.closePopup() | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style lang="scss"> | |||||
| .new-user-coupon { | |||||
| position: fixed; | |||||
| top: 0; | |||||
| left: 0; | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| z-index: 999; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: center; | |||||
| .mask { | |||||
| position: absolute; | |||||
| top: 0; | |||||
| left: 0; | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| background-color: rgba(0, 0, 0, 0.6); | |||||
| } | |||||
| .coupon-container { | |||||
| position: relative; | |||||
| width: 560rpx; | |||||
| z-index: 1000; | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| align-items: center; | |||||
| } | |||||
| .coupon-content { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| align-items: center; | |||||
| } | |||||
| .coupon-image { | |||||
| width: 560rpx; | |||||
| border-radius: 20rpx; | |||||
| } | |||||
| .coupon-btn { | |||||
| margin-top: -80rpx; | |||||
| width: 300rpx; | |||||
| height: 80rpx; | |||||
| background: #FFB13F; | |||||
| color: #FFFFFF; | |||||
| font-size: 32rpx; | |||||
| font-weight: bold; | |||||
| border-radius: 40rpx; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: center; | |||||
| } | |||||
| .close-btn { | |||||
| margin-top: 40rpx; | |||||
| width: 60rpx; | |||||
| height: 60rpx; | |||||
| background: rgba(255, 255, 255, 0.8); | |||||
| border-radius: 50%; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: center; | |||||
| .close-icon { | |||||
| color: #666; | |||||
| font-size: 40rpx; | |||||
| font-weight: bold; | |||||
| } | |||||
| } | |||||
| } | |||||
| </style> | |||||
| @ -1,464 +1,483 @@ | |||||
| <template> | <template> | ||||
| <view class="personal-pet"> | |||||
| <view v-if="petList.length>0" class="personal-pet-list"> | |||||
| <view v-for="(item,index) in petList" :key="index"> | |||||
| <view :class="['personal-pet-list-item',item.gender=='男生'?'.personal-pet-list-item_backgroud_m':'.personal-pet-list-item_backgroud_f' ]"> | |||||
| <view class="personal-pet-info"> | |||||
| <view> | |||||
| <u-avatar :src="item.photo?item.photo:defaultPhoto" size="60" shape="circle"></u-avatar> | |||||
| </view> | |||||
| <view class="personal-pet-info-1" style="width: calc(100% - 120px);"> | |||||
| <view class="personal-pet-info-2"> | |||||
| <view class="personal-pet-name ellipsis"> | |||||
| {{item.name}} | |||||
| </view> | |||||
| <view class="personal-pet-sex"> | |||||
| <img :src="item.gender=='男生'?'../../static/images/details/boy.svg':'../../static/images/details/girl.svg'" alt="sex" | |||||
| style="width: 16px;height: 16px;"/> | |||||
| </view> | |||||
| </view> | |||||
| <view class="personal-pet-info-3" style="width: 100%;"> | |||||
| <view class="ellipsis" style="max-width: 25%;" > | |||||
| {{item.breed || '未知'}} | |||||
| </view> | |||||
| <view class="personal-pet-info-age" style="max-width: 90px;"> | |||||
| {{item.birthDate || '未知'}} | |||||
| </view> | |||||
| <view class="ellipsis" style="max-width: 25%;"> | |||||
| {{item.bodyType || '未知'}} | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| <view style="margin-left: auto; width: 20px;"> | |||||
| <u-checkbox-group v-model="item.checked"> | |||||
| <u-checkbox shape="circle" activeColor="#ffbf60"></u-checkbox> | |||||
| </u-checkbox-group> | |||||
| </view> | |||||
| </view> | |||||
| <view class="personal-pet-info-disposition ellipsis"> | |||||
| 性格: {{item.personality}} | |||||
| </view> | |||||
| <view class="personal-pet-info-btns"> | |||||
| <view style="display: flex; align-items: center;"> | |||||
| <u-button v-if="item.selectedDate.length==0" color="#FFBF60" size="mini" iconPlacement="right" shape="circle" plain @click="selectDate(item)"> | |||||
| <view style="font-size: 14px;">请选择服务日期</view> | |||||
| <u-icon name="arrow-right" color="#FFBF60" size="14" style="margin-right: 5px;"></u-icon> | |||||
| </u-button> | |||||
| <u-button v-else color="#FFBF60" type="primary" size="mini" iconPlacement="right" shape="circle" @click="selectDate(item)"> | |||||
| <view style="font-size: 14px;">{{ showSelectedDate(item.selectedDate) }}</view> | |||||
| <u-icon name="arrow-right" color="#ffffff" size="14" style="margin-right: 5px;"></u-icon> | |||||
| </u-button> | |||||
| </view> | |||||
| <view style="display: flex; align-items: center; justify-content: flex-end;"> | |||||
| <view class="personal-pet-info-btn" @click="editPet(item)"> | |||||
| <u-icon name="edit-pen" color="#7d8196" size="16" style="margin-right: 5px;"></u-icon> | |||||
| <view style="margin-left: 5px;"> | |||||
| 编辑 | |||||
| </view> | |||||
| </view> | |||||
| <view class="personal-pet-info-btn" @click="deletePet(item)"> | |||||
| <u-icon name="trash" color="#7d8196" size="16"></u-icon> | |||||
| <view style="margin-left: 5px;"> | |||||
| 删除 | |||||
| <view class="personal-pet"> | |||||
| <view v-if="petList.length > 0" class="personal-pet-list"> | |||||
| <view v-for="(item, index) in petList" :key="index"> | |||||
| <view | |||||
| :class="['personal-pet-list-item', item.gender == '男生' ? '.personal-pet-list-item_backgroud_m' : '.personal-pet-list-item_backgroud_f']"> | |||||
| <view class="personal-pet-info"> | |||||
| <view> | |||||
| <u-avatar :src="item.photo ? item.photo : defaultPhoto" size="60" shape="circle"></u-avatar> | |||||
| </view> | |||||
| <view class="personal-pet-info-1" style="width: calc(100% - 120px);"> | |||||
| <view class="personal-pet-info-2"> | |||||
| <view class="personal-pet-name ellipsis"> | |||||
| {{ item.name }} | |||||
| </view> | |||||
| <view class="personal-pet-sex"> | |||||
| <img :src="item.gender == '男生' ? '../../static/images/details/boy.svg' : '../../static/images/details/girl.svg'" | |||||
| alt="sex" style="width: 16px;height: 16px;" /> | |||||
| </view> | |||||
| </view> | |||||
| <view class="personal-pet-info-3" style="width: 100%;"> | |||||
| <view class="ellipsis" style="max-width: 25%;"> | |||||
| {{ item.breed || '未知' }} | |||||
| </view> | |||||
| <view class="personal-pet-info-age" style="max-width: 90px;"> | |||||
| {{ item.birthDate || '未知' }} | |||||
| </view> | |||||
| <view class="ellipsis" style="max-width: 25%;"> | |||||
| {{ item.bodyType || '未知' }} | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| <view style="margin-left: auto; width: 20px;"> | |||||
| <u-checkbox-group v-model="item.checked"> | |||||
| <u-checkbox shape="circle" activeColor="#ffbf60"></u-checkbox> | |||||
| </u-checkbox-group> | |||||
| </view> | |||||
| </view> | |||||
| <view class="personal-pet-info-disposition ellipsis"> | |||||
| 性格: {{ item.personality }} | |||||
| </view> | |||||
| <view class="personal-pet-info-btns"> | |||||
| <view style="display: flex; align-items: center;"> | |||||
| <u-button v-if="item.selectedDate.length == 0" color="#FFBF60" size="mini" | |||||
| iconPlacement="right" shape="circle" plain @click="selectDate(item)"> | |||||
| <view style="font-size: 14px;">请选择服务日期</view> | |||||
| <u-icon name="arrow-right" color="#FFBF60" size="14" | |||||
| style="margin-right: 5px;"></u-icon> | |||||
| </u-button> | |||||
| <u-button v-else color="#FFBF60" type="primary" size="mini" iconPlacement="right" | |||||
| shape="circle" @click="selectDate(item)"> | |||||
| <view style="font-size: 14px;">{{ showSelectedDate(item.selectedDate) }}</view> | |||||
| <u-icon name="arrow-right" color="#ffffff" size="14" | |||||
| style="margin-right: 5px;"></u-icon> | |||||
| </u-button> | |||||
| </view> | |||||
| <view style="display: flex; align-items: center; justify-content: flex-end;"> | |||||
| <view class="personal-pet-info-btn" @click="editPet(item)"> | |||||
| <u-icon name="edit-pen" color="#7d8196" size="16" style="margin-right: 5px;"></u-icon> | |||||
| <view style="margin-left: 5px;"> | |||||
| 编辑 | |||||
| </view> | |||||
| </view> | |||||
| <view class="personal-pet-info-btn" @click="deletePet(item)"> | |||||
| <u-icon name="trash" color="#7d8196" size="16"></u-icon> | |||||
| <view style="margin-left: 5px;"> | |||||
| 删除 | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| </view> | </view> | ||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| <view v-else class="personal-pet-none"> | |||||
| <img src="https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/pet/catdog.png" alt="pet" | |||||
| style="width: 149px;height: 124px;" mode="widthFix" /> | |||||
| <view class="personal-pet-none-text">这里还没有您的宠物,请点击添加吧~</view> | |||||
| </view> | |||||
| <view class="personal-pet-add"> | |||||
| <view style="width: 45%;"> | |||||
| <u-button class="personal-pet-add-btn" color="#FFF4E4" @click="addPet"> | |||||
| <view style="font-size: 32rpx;font-weight: 500;color: #FFAA48;"> | |||||
| 新增宠物 | |||||
| </view> | |||||
| </u-button> | |||||
| </view> | |||||
| <view style="width: 45%;"> | |||||
| <u-button class="personal-pet-add-btn" color="#FFBF60" @click="confirm"> | |||||
| <view style="font-size: 32rpx;font-weight: 500;color: #fff;"> | |||||
| 确定 | |||||
| </view> | |||||
| </u-button> | |||||
| </view> | |||||
| </view> | |||||
| <view class=""> | |||||
| <u-picker :showToolbar='false' :show="show" :columns="petTypes" @change="petTypeChange" @cancel="cancel" | |||||
| @confirm="confirmPetType"></u-picker> | |||||
| </view> | |||||
| <u-modal :show="showDel" @confirm="confirmDel" @cancel="cancelDel" ref="uModal" showCancelButton | |||||
| :asyncClose="true" :content='delContent'> | |||||
| </u-modal> | |||||
| <view v-if="showCalendar" class="calendar-popup"> | |||||
| <view class="calendar-mask"></view> | |||||
| <view class="calendar-content"> | |||||
| <uni-calendar class="uni-calendar--hook" :selected="selectedDate" :startDate="startDate" | |||||
| :endDate="endDate" @change="change" :showMonth="false" /> | |||||
| <u-button color="#FFBF60" type="primary" @click="confirmCanlendar">确定</u-button> | |||||
| </view> | </view> | ||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| <view v-else class="personal-pet-none"> | |||||
| <img src="https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/pet/catdog.png" alt="pet" | |||||
| style="width: 149px;height: 124px;" mode="widthFix"/> | |||||
| <view class="personal-pet-none-text">这里还没有您的宠物,请点击添加吧~</view> | |||||
| </view> | |||||
| <view class="personal-pet-add"> | |||||
| <view style="width: 45%;"> | |||||
| <u-button class="personal-pet-add-btn" color="#FFF4E4" @click="addPet"> | |||||
| <view style="font-size: 32rpx;font-weight: 500;color: #FFAA48;"> | |||||
| 新增宠物 | |||||
| </view> | |||||
| </u-button> | |||||
| </view> | |||||
| <view style="width: 45%;"> | |||||
| <u-button class="personal-pet-add-btn" color="#FFBF60" @click="confirm"> | |||||
| <view style="font-size: 32rpx;font-weight: 500;color: #fff;"> | |||||
| 确定 | |||||
| </view> | |||||
| </u-button> | |||||
| </view> | |||||
| </view> | |||||
| <view class=""> | |||||
| <u-picker | |||||
| :showToolbar='false' | |||||
| :show="show" | |||||
| :columns="petTypes" | |||||
| @change="petTypeChange" | |||||
| @cancel="cancel" | |||||
| @confirm="confirmPetType" | |||||
| ></u-picker> | |||||
| </view> | |||||
| <u-modal :show="showDel" | |||||
| @confirm="confirmDel" | |||||
| @cancel="cancelDel" | |||||
| ref="uModal" | |||||
| showCancelButton | |||||
| :asyncClose="true" | |||||
| :content='delContent'> | |||||
| </u-modal> | |||||
| <view v-if="showCalendar" class="calendar-popup"> | |||||
| <view class="calendar-mask" ></view> | |||||
| <view class="calendar-content"> | |||||
| <uni-calendar class="uni-calendar--hook" :selected="selectedDate" :startDate="startDate" :endDate="endDate" | |||||
| @change="change" :showMonth="false" /> | |||||
| <u-button color="#FFBF60" type="primary" @click="confirmCanlendar">确定</u-button> | |||||
| </view> | |||||
| </view> | |||||
| </view> | </view> | ||||
| </view> | |||||
| </template> | </template> | ||||
| <script> | <script> | ||||
| import { getDictList } from "@/api/system/user.js" | |||||
| import { getPetList,delPet } from "@/api/system/pet" | |||||
| export default{ | |||||
| data(){ | |||||
| return{ | |||||
| defaultPhoto:'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/pet/catdog.png', | |||||
| petList:[], | |||||
| show:false, | |||||
| showDel:false, | |||||
| petTypes:[], | |||||
| delContent:'', | |||||
| deleteId:'', | |||||
| petType:'', | |||||
| startDate: '', | |||||
| endDate: '', | |||||
| showCalendar: false, | |||||
| selectedDate:[], | |||||
| currentPets:[] | |||||
| } | |||||
| }, | |||||
| onShow() { | |||||
| this.getPetList(); | |||||
| }, | |||||
| onPullDownRefresh() { | |||||
| this.getPetList(); | |||||
| }, | |||||
| mounted() { | |||||
| this.getPetTypeList(); | |||||
| this.getPetList(); | |||||
| this.getCalendarDate(); | |||||
| }, | |||||
| methods:{ | |||||
| getPetList(){ | |||||
| this.petList=[] | |||||
| getPetList().then(res=>{ | |||||
| let currentPets = this.$globalData.newOrderData.currentPets | |||||
| if(res&&res.content){ | |||||
| this.petList=res.content.map(e=>{ | |||||
| const currentPet = currentPets.find(item => item.id === e.id) | |||||
| if(currentPet) { | |||||
| e.selectedDate = currentPet.selectedDate | |||||
| e.checked = currentPet.checked | |||||
| } else { | |||||
| e.selectedDate = [] | |||||
| e.checked = false | |||||
| } | |||||
| return e | |||||
| }) | |||||
| this.showDel = false; | |||||
| } | |||||
| }) | |||||
| }, | |||||
| getPetTypeList(){ | |||||
| getDictList('pet_type').then(res=>{ | |||||
| if (res.code == 200) { | |||||
| let petType = res.data.map(e=>e.dictLabel) | |||||
| this.petTypes=[petType] | |||||
| console.log(this.petTypes) | |||||
| } else { | |||||
| this.$modal.showToast('获取pet type失败') | |||||
| } | |||||
| }) | |||||
| }, | |||||
| addPet(){ | |||||
| this.show = true; | |||||
| }, | |||||
| cancel() { | |||||
| this.show = false | |||||
| }, | |||||
| petTypeChange(e){ | |||||
| console.log(e) | |||||
| this.petType=e.value[0] | |||||
| }, | |||||
| confirmPetType(e) { | |||||
| console.log(e) | |||||
| this.show = false | |||||
| // 获取宠物类型,优先使用已选择的petType,否则使用e.value[0] | |||||
| const type = this.petType || e.value[0] | |||||
| // 根据宠物类型映射到英文类型 | |||||
| const petTypeMap = { | |||||
| '猫猫': 'cat', | |||||
| '狗狗': 'dog' | |||||
| } | |||||
| const petType = petTypeMap[type] | |||||
| if(petType) { | |||||
| uni.navigateTo({ | |||||
| url: `/pages/personalCenter/petInfo?petType=${petType}&optionType=add&isNewOrder=true` | |||||
| }); | |||||
| } | |||||
| }, | |||||
| editPet(item){ | |||||
| const petTypeMap = { | |||||
| '猫猫': 'cat', | |||||
| 'cat': 'cat', | |||||
| '狗狗': 'dog', | |||||
| 'dog': 'dog' | |||||
| } | |||||
| const petType = petTypeMap[item.petType] | |||||
| if(petType) { | |||||
| uni.navigateTo({ | |||||
| url: `/pages/personalCenter/petInfo?petType=${petType}&optionType=edit&petId=${item.id}&isNewOrder=true` | |||||
| }); | |||||
| } | |||||
| }, | |||||
| deletePet(item){ | |||||
| this.delContent = "确定要删除"+item.name+'?'; | |||||
| this.showDel = true; | |||||
| this.deleteId=item.id; | |||||
| }, | |||||
| confirmDel(){ | |||||
| delPet(this.deleteId).then(res=>{ | |||||
| console.log(res); | |||||
| this.$modal.showToast('删除成功'); | |||||
| this.getPetList() | |||||
| }) | |||||
| }, | |||||
| cancelDel(){ | |||||
| this.showDel = false; | |||||
| this.deleteId=''; | |||||
| }, | |||||
| getCalendarDate() { | |||||
| let tomorrow = new Date() | |||||
| tomorrow.setDate(tomorrow.getDate()); | |||||
| this.startDate = this.formatDate(tomorrow); | |||||
| // 获取三个月后的日期 | |||||
| let threeMonthsLater = new Date(); | |||||
| threeMonthsLater.setMonth(threeMonthsLater.getMonth() + 3); | |||||
| this.endDate = this.formatDate(threeMonthsLater); | |||||
| }, | |||||
| formatDate(date) { | |||||
| let year = date.getFullYear(); | |||||
| let month = (date.getMonth() + 1).toString().padStart(2, '0'); | |||||
| let day = date.getDate().toString().padStart(2, '0'); | |||||
| return year + '-' + month + '-' + day; | |||||
| }, | |||||
| selectDate(item){ | |||||
| this.currentId= item.id | |||||
| this.selectedDate = item.selectedDate | |||||
| this.showCalendar = true; | |||||
| }, | |||||
| confirmCanlendar(){ | |||||
| this.petList.find(e=>e.id==this.currentId).selectedDate = this.selectedDate.sort((a,b) => new Date(a.date) - new Date(b.date)) | |||||
| this.selectedDate = [] | |||||
| this.showCalendar = false; | |||||
| }, | |||||
| change(e){ | |||||
| const selectedValue = this.selectedDate.find(item => item.date === e.fulldate) | |||||
| if (selectedValue) { | |||||
| // 存在则移除 | |||||
| this.selectedDate = this.selectedDate.filter(item => item.date !== e.fulldate); | |||||
| } else { | |||||
| this.selectedDate.push({ | |||||
| date: e.fulldate, | |||||
| info: '预定' | |||||
| }) | |||||
| } | |||||
| }, | |||||
| confirm(){ | |||||
| const selectedPets = this.petList.filter(e=>e.checked) | |||||
| const unselectedDatePets = selectedPets.filter(pet => !pet.selectedDate || pet.selectedDate.length === 0) | |||||
| if(unselectedDatePets.length > 0) { | |||||
| const petNames = unselectedDatePets.map(pet => pet.name).join('、') | |||||
| this.$modal.showToast(`请为${petNames}选择服务时间`) | |||||
| return | |||||
| import { getDictList } from "@/api/system/user.js" | |||||
| import { getPetList, delPet } from "@/api/system/pet" | |||||
| export default { | |||||
| data() { | |||||
| return { | |||||
| defaultPhoto: 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/pet/catdog.png', | |||||
| petList: [], | |||||
| show: false, | |||||
| showDel: false, | |||||
| petTypes: [], | |||||
| delContent: '', | |||||
| deleteId: '', | |||||
| petType: '', | |||||
| startDate: '', | |||||
| endDate: '', | |||||
| showCalendar: false, | |||||
| selectedDate: [], | |||||
| currentPets: [] | |||||
| } | } | ||||
| this.$globalData.newOrderData.currentPets = selectedPets | |||||
| uni.redirectTo({ | |||||
| url: '/pages/newOrder/serviceNew' | |||||
| }) | |||||
| }, | |||||
| showSelectedDate(selectedDate){ | |||||
| // 显示格式:首日...最后一日 共几天 | |||||
| // 日期格式只需要月份和日期 例如:01/01...01/07 | |||||
| const firstDate = selectedDate[0].date.substring(5).replace('-', '/') | |||||
| const lastDate = selectedDate[selectedDate.length - 1].date.substring(5).replace('-', '/') | |||||
| const days = selectedDate.length | |||||
| return `${firstDate}${days>2?'...':''}${days==2?',':''}${days>1?lastDate:''} 共${days}天` | |||||
| } | |||||
| } | |||||
| } | |||||
| }, | |||||
| onShow() { | |||||
| this.getPetList(); | |||||
| }, | |||||
| onPullDownRefresh() { | |||||
| this.getPetList(); | |||||
| }, | |||||
| mounted() { | |||||
| this.getPetTypeList(); | |||||
| this.getPetList(); | |||||
| this.getCalendarDate(); | |||||
| }, | |||||
| methods: { | |||||
| getPetList() { | |||||
| this.petList = [] | |||||
| getPetList().then(res => { | |||||
| let currentPets = this.$globalData.newOrderData.currentPets | |||||
| if (res && res.content) { | |||||
| this.petList = res.content.map(e => { | |||||
| const currentPet = currentPets.find(item => item.id === e.id) | |||||
| if (currentPet) { | |||||
| e.selectedDate = currentPet.selectedDate | |||||
| e.checked = currentPet.checked | |||||
| } else { | |||||
| e.selectedDate = [] | |||||
| e.checked = false | |||||
| } | |||||
| return e | |||||
| }) | |||||
| this.showDel = false; | |||||
| } | |||||
| }) | |||||
| }, | |||||
| getPetTypeList() { | |||||
| getDictList('pet_type').then(res => { | |||||
| if (res.code == 200) { | |||||
| let petType = res.data.map(e => e.dictLabel) | |||||
| this.petTypes = [petType] | |||||
| console.log(this.petTypes) | |||||
| } else { | |||||
| this.$modal.showToast('获取pet type失败') | |||||
| } | |||||
| }) | |||||
| }, | |||||
| addPet() { | |||||
| this.show = true; | |||||
| }, | |||||
| cancel() { | |||||
| this.show = false | |||||
| }, | |||||
| petTypeChange(e) { | |||||
| console.log(e) | |||||
| this.petType = e.value[0] | |||||
| }, | |||||
| confirmPetType(e) { | |||||
| console.log(e) | |||||
| this.show = false | |||||
| // 获取宠物类型,优先使用已选择的petType,否则使用e.value[0] | |||||
| const type = this.petType || e.value[0] | |||||
| // 根据宠物类型映射到英文类型 | |||||
| const petTypeMap = { | |||||
| '猫猫': 'cat', | |||||
| '狗狗': 'dog' | |||||
| } | |||||
| const petType = petTypeMap[type] | |||||
| if (petType) { | |||||
| uni.navigateTo({ | |||||
| url: `/pages/personalCenter/petInfo?petType=${petType}&optionType=add&isNewOrder=true` | |||||
| }); | |||||
| } | |||||
| }, | |||||
| editPet(item) { | |||||
| const petTypeMap = { | |||||
| '猫猫': 'cat', | |||||
| 'cat': 'cat', | |||||
| '狗狗': 'dog', | |||||
| 'dog': 'dog' | |||||
| } | |||||
| const petType = petTypeMap[item.petType] | |||||
| if (petType) { | |||||
| uni.navigateTo({ | |||||
| url: `/pages/personalCenter/petInfo?petType=${petType}&optionType=edit&petId=${item.id}&isNewOrder=true` | |||||
| }); | |||||
| } | |||||
| }, | |||||
| deletePet(item) { | |||||
| this.delContent = "确定要删除" + item.name + '?'; | |||||
| this.showDel = true; | |||||
| this.deleteId = item.id; | |||||
| }, | |||||
| confirmDel() { | |||||
| delPet(this.deleteId).then(res => { | |||||
| console.log(res); | |||||
| this.$modal.showToast('删除成功'); | |||||
| this.getPetList() | |||||
| }) | |||||
| }, | |||||
| cancelDel() { | |||||
| this.showDel = false; | |||||
| this.deleteId = ''; | |||||
| }, | |||||
| getCalendarDate() { | |||||
| let tomorrow = new Date() | |||||
| tomorrow.setDate(tomorrow.getDate()); | |||||
| this.startDate = this.formatDate(tomorrow); | |||||
| // 获取三个月后的日期 | |||||
| let threeMonthsLater = new Date(); | |||||
| threeMonthsLater.setMonth(threeMonthsLater.getMonth() + 3); | |||||
| this.endDate = this.formatDate(threeMonthsLater); | |||||
| }, | |||||
| formatDate(date) { | |||||
| let year = date.getFullYear(); | |||||
| let month = (date.getMonth() + 1).toString().padStart(2, '0'); | |||||
| let day = date.getDate().toString().padStart(2, '0'); | |||||
| return year + '-' + month + '-' + day; | |||||
| }, | |||||
| selectDate(item) { | |||||
| this.currentId = item.id | |||||
| this.selectedDate = item.selectedDate | |||||
| this.showCalendar = true; | |||||
| }, | |||||
| confirmCanlendar() { | |||||
| this.petList.find(e => e.id == this.currentId).selectedDate = this.selectedDate.sort((a, b) => new Date(a.date) - new Date(b.date)) | |||||
| this.selectedDate = [] | |||||
| this.showCalendar = false; | |||||
| }, | |||||
| change(e) { | |||||
| const selectedValue = this.selectedDate.find(item => item.date === e.fulldate) | |||||
| if (selectedValue) { | |||||
| // 存在则移除 | |||||
| this.selectedDate = this.selectedDate.filter(item => item.date !== e.fulldate); | |||||
| } else { | |||||
| this.selectedDate.push({ | |||||
| date: e.fulldate, | |||||
| info: '预定' | |||||
| }) | |||||
| } | |||||
| }, | |||||
| confirm() { | |||||
| const selectedPets = this.petList.filter(e => e.checked) | |||||
| const unselectedDatePets = selectedPets.filter(pet => !pet.selectedDate || pet.selectedDate.length === 0) | |||||
| if (unselectedDatePets.length > 0) { | |||||
| const petNames = unselectedDatePets.map(pet => pet.name).join('、') | |||||
| this.$modal.showToast(`请为${petNames}选择服务时间`) | |||||
| return | |||||
| } | |||||
| this.$globalData.newOrderData.currentPets = selectedPets | |||||
| uni.redirectTo({ | |||||
| url: '/pages/newOrder/serviceNew' | |||||
| }) | |||||
| }, | |||||
| showSelectedDate(selectedDate) { | |||||
| // 显示格式:首日...最后一日 共几天 | |||||
| // 日期格式只需要月份和日期 例如:01/01...01/07 | |||||
| const firstDate = selectedDate[0].date.substring(5).replace('-', '/') | |||||
| const lastDate = selectedDate[selectedDate.length - 1].date.substring(5).replace('-', '/') | |||||
| const days = selectedDate.length | |||||
| return `${firstDate}${days > 2 ? '...' : ''}${days == 2 ? ',' : ''}${days > 1 ? lastDate : ''} 共${days}天` | |||||
| } | |||||
| } | |||||
| } | |||||
| </script> | </script> | ||||
| <style lang="scss"> | |||||
| .personal-pet{ | |||||
| position: relative; | |||||
| height: 100%; | |||||
| padding-bottom: 90px; | |||||
| .personal-pet-add{ | |||||
| background-color: #FFFFFF; | |||||
| padding:10px 20px 40px; | |||||
| width: 100%; | |||||
| height: 90px; | |||||
| position: fixed; | |||||
| bottom: 0; | |||||
| z-index: 100; | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| .personal-pet-add-btn{ | |||||
| width: 100%; | |||||
| border-radius: 6px; | |||||
| font-size: 16px; | |||||
| } | |||||
| } | |||||
| .personal-pet-list{ | |||||
| .personal-pet-list-add{ | |||||
| width: 100%; | |||||
| height: 44px; | |||||
| background-color: #FFFFFF; | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| align-items: center; | |||||
| padding: 0 15px; | |||||
| .personal-pet-list-add-btn{ | |||||
| font-size: 14px; | |||||
| color:#AAA; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| } | |||||
| } | |||||
| .personal-pet-list-item_backgroud_m{ | |||||
| background: linear-gradient(179deg, #EDF5FE 0.75%, #FFF 34.11%); | |||||
| } | |||||
| .personal-pet-list-item_backgroud_f{ | |||||
| background: linear-gradient(179deg, #FFF4F6 0.75%, #FFF 34.11%); | |||||
| } | |||||
| .personal-pet-list-item{ | |||||
| margin: 10px 10px 0 10px; | |||||
| border-radius: 5px; | |||||
| padding: 20px 10px 10px; | |||||
| .personal-pet-info{ | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: flex-start; | |||||
| .personal-pet-info-1{ | |||||
| margin-left: 10px; | |||||
| .personal-pet-info-2{ | |||||
| display: flex; | |||||
| flex-wrap: wrap; | |||||
| .personal-pet-name{ | |||||
| color: #333; | |||||
| font-size: 16px; | |||||
| margin-right: 10px; | |||||
| } | |||||
| } | |||||
| .personal-pet-info-3 { | |||||
| display: flex; | |||||
| align-items: baseline; | |||||
| font-size: 14px; | |||||
| margin-top: 5px; | |||||
| color: #7D8196; | |||||
| .personal-pet-info-age{ | |||||
| padding: 0 10px; | |||||
| margin: 0 10px; | |||||
| border-left: solid 2px #7D8196; | |||||
| border-right: solid 2px #7D8196; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| .personal-pet-info-disposition{ | |||||
| padding: 10px; | |||||
| color: #7D8196; | |||||
| font-size: 14px; | |||||
| background: #f9f9f9; | |||||
| border-radius: 5px; | |||||
| margin-top: 10px; | |||||
| } | |||||
| .personal-pet-info-btns{ | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| margin-top: 10px; | |||||
| .personal-pet-info-btn{ | |||||
| display: flex; | |||||
| font-size: 14px; | |||||
| color: #7D8196; | |||||
| margin-left: 20px; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| .personal-pet-none{ | |||||
| display:flex; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| flex-wrap: wrap; | |||||
| margin-top: 40%; | |||||
| .personal-pet-none-text{ | |||||
| color: #666; | |||||
| text-align: center; | |||||
| font-size: 14px; | |||||
| width: 100%; | |||||
| margin-top: 10px; | |||||
| } | |||||
| } | |||||
| .calendar-popup{ | |||||
| position: fixed; | |||||
| bottom: 0; | |||||
| left: 0; | |||||
| right: 0; | |||||
| z-index: 999; | |||||
| .calendar-content{ | |||||
| background: #fff; | |||||
| border-radius: 16px 16px 0 0; | |||||
| padding: 0 20px 20px; | |||||
| } | |||||
| <style lang="scss" scoped> | |||||
| .personal-pet { | |||||
| position: relative; | |||||
| height: 100%; | |||||
| padding-bottom: 90px; | |||||
| .personal-pet-add { | |||||
| background-color: #FFFFFF; | |||||
| padding: 10px 20px 40px; | |||||
| width: 100%; | |||||
| height: 90px; | |||||
| position: fixed; | |||||
| bottom: 0; | |||||
| z-index: 100; | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| .personal-pet-add-btn { | |||||
| width: 100%; | |||||
| border-radius: 6px; | |||||
| font-size: 16px; | |||||
| } | |||||
| } | } | ||||
| .personal-pet-list { | |||||
| .personal-pet-list-add { | |||||
| width: 100%; | |||||
| height: 44px; | |||||
| background-color: #FFFFFF; | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| align-items: center; | |||||
| padding: 0 15px; | |||||
| .personal-pet-list-add-btn { | |||||
| font-size: 14px; | |||||
| color: #AAA; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| } | |||||
| } | |||||
| .personal-pet-list-item_backgroud_m { | |||||
| background: linear-gradient(179deg, #EDF5FE 0.75%, #FFF 34.11%); | |||||
| } | |||||
| .personal-pet-list-item_backgroud_f { | |||||
| background: linear-gradient(179deg, #FFF4F6 0.75%, #FFF 34.11%); | |||||
| } | |||||
| .personal-pet-list-item { | |||||
| margin: 10px 10px 0 10px; | |||||
| border-radius: 5px; | |||||
| padding: 20px 10px 10px; | |||||
| .personal-pet-info { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: flex-start; | |||||
| .personal-pet-info-1 { | |||||
| margin-left: 10px; | |||||
| .personal-pet-info-2 { | |||||
| display: flex; | |||||
| flex-wrap: wrap; | |||||
| .personal-pet-name { | |||||
| color: #333; | |||||
| font-size: 16px; | |||||
| margin-right: 10px; | |||||
| } | |||||
| } | |||||
| .personal-pet-info-3 { | |||||
| display: flex; | |||||
| align-items: baseline; | |||||
| font-size: 14px; | |||||
| margin-top: 5px; | |||||
| color: #7D8196; | |||||
| .personal-pet-info-age { | |||||
| padding: 0 10px; | |||||
| margin: 0 10px; | |||||
| border-left: solid 2px #7D8196; | |||||
| border-right: solid 2px #7D8196; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| .personal-pet-info-disposition { | |||||
| padding: 10px; | |||||
| color: #7D8196; | |||||
| font-size: 14px; | |||||
| background: #f9f9f9; | |||||
| border-radius: 5px; | |||||
| margin-top: 10px; | |||||
| } | |||||
| .personal-pet-info-btns { | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| margin-top: 10px; | |||||
| .personal-pet-info-btn { | |||||
| display: flex; | |||||
| font-size: 14px; | |||||
| color: #7D8196; | |||||
| margin-left: 20px; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| .personal-pet-none { | |||||
| display: flex; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| flex-wrap: wrap; | |||||
| margin-top: 40%; | |||||
| .personal-pet-none-text { | |||||
| color: #666; | |||||
| text-align: center; | |||||
| font-size: 14px; | |||||
| width: 100%; | |||||
| margin-top: 10px; | |||||
| } | |||||
| } | |||||
| .calendar-popup { | |||||
| position: fixed; | |||||
| bottom: 0; | |||||
| left: 0; | |||||
| right: 0; | |||||
| z-index: 999; | |||||
| .calendar-content { | |||||
| background: #fff; | |||||
| border-radius: 16px 16px 0 0; | |||||
| padding: 0 20px 20px; | |||||
| } | |||||
| } | |||||
| .calendar-mask { | .calendar-mask { | ||||
| position: fixed; | |||||
| top: 0; | |||||
| left: 0; | |||||
| right: 0; | |||||
| bottom: 0; | |||||
| background: rgba(0, 0, 0, 0.5); /* 半透明黑色 */ | |||||
| z-index: 998; /* 确保在内容下方 */ | |||||
| pointer-events: none; /* 使遮罩层不阻止点击事件 */ | |||||
| position: fixed; | |||||
| top: 0; | |||||
| left: 0; | |||||
| right: 0; | |||||
| bottom: 0; | |||||
| background: rgba(0, 0, 0, 0.5); | |||||
| /* 半透明黑色 */ | |||||
| z-index: 998; | |||||
| /* 确保在内容下方 */ | |||||
| pointer-events: none; | |||||
| /* 使遮罩层不阻止点击事件 */ | |||||
| } | } | ||||
| .calendar-content { | .calendar-content { | ||||
| position: relative; /* 确保内容在遮罩层之上 */ | |||||
| z-index: 999; /* 确保内容在遮罩层之上 */ | |||||
| position: relative; | |||||
| /* 确保内容在遮罩层之上 */ | |||||
| z-index: 999; | |||||
| /* 确保内容在遮罩层之上 */ | |||||
| } | } | ||||
| } | |||||
| } | |||||
| </style> | </style> | ||||
| @ -0,0 +1,332 @@ | |||||
| <template> | |||||
| <view class="order-detail-container"> | |||||
| <!-- 日期信息 --> | |||||
| <view class="order-date"> | |||||
| <view class="order-date-icon"> | |||||
| <u-icon name="calendar" color="#FFAA48" size="20"></u-icon> | |||||
| </view> | |||||
| <view class="order-date-text">{{ orderDate }}</view> | |||||
| </view> | |||||
| <!-- 个人信息区域 --> | |||||
| <view class="order-section"> | |||||
| <view class="order-section-title">个人信息</view> | |||||
| <view class="order-section-content"> | |||||
| <view class="order-image-item"> | |||||
| <view class="order-image-label">手套照片 (共2张)</view> | |||||
| <view class="order-image-container"> | |||||
| <image class="order-image" src="https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/gloves.jpg" mode="aspectFill"></image> | |||||
| </view> | |||||
| </view> | |||||
| <view class="order-image-item"> | |||||
| <view class="order-image-label">鞋套照片 (共2张)</view> | |||||
| <view class="order-image-container"> | |||||
| <image class="order-image" src="https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/shoes.jpg" mode="aspectFill"></image> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| <!-- 宠物状况记录 --> | |||||
| <view class="order-section"> | |||||
| <view class="order-section-title">宠物状况记录</view> | |||||
| <view class="order-section-content"> | |||||
| <view class="pet-record" v-for="(pet, index) in pets" :key="index"> | |||||
| <view class="pet-name">{{ pet.name }} (共{{ pet.photoCount }}张)</view> | |||||
| <view class="pet-images"> | |||||
| <view class="pet-image-container" v-for="(photo, photoIndex) in pet.photos" :key="photoIndex"> | |||||
| <image class="pet-image" :src="photo" mode="aspectFill"></image> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| <!-- 基础服务记录 --> | |||||
| <view class="order-section"> | |||||
| <view class="order-section-title">基础服务记录</view> | |||||
| <view class="order-section-content"> | |||||
| <view class="service-record" v-for="(service, index) in services" :key="index"> | |||||
| <view class="service-name">{{ service.name }}</view> | |||||
| <view class="service-comparison"> | |||||
| <view class="service-before-after"> | |||||
| <view class="service-image-container"> | |||||
| <image class="service-image" :src="service.beforeImage" mode="aspectFill"></image> | |||||
| <view class="service-image-label">前</view> | |||||
| </view> | |||||
| <view class="service-image-container"> | |||||
| <image class="service-image" :src="service.afterImage" mode="aspectFill"></image> | |||||
| <view class="service-image-label">后</view> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| <!-- 定制服务记录 --> | |||||
| <view class="order-section"> | |||||
| <view class="order-section-title">定制服务记录</view> | |||||
| <view class="order-section-content"> | |||||
| <view class="custom-service"> | |||||
| <view class="custom-service-item"> | |||||
| <view class="custom-service-name">遛狗 (5-30分钟)</view> | |||||
| <view class="custom-service-images"> | |||||
| <image class="custom-service-image" src="https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/dog1.jpg" mode="aspectFill"></image> | |||||
| <image class="custom-service-image" src="https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/dog2.jpg" mode="aspectFill"></image> | |||||
| <image class="custom-service-image" src="https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/dog3.jpg" mode="aspectFill"></image> | |||||
| </view> | |||||
| </view> | |||||
| <view class="custom-service-item"> | |||||
| <view class="custom-service-name">梳毛 (5-30分钟)</view> | |||||
| <view class="custom-service-images"> | |||||
| <image class="custom-service-image" src="https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/cat1.jpg" mode="aspectFill"></image> | |||||
| <image class="custom-service-image" src="https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/cat2.jpg" mode="aspectFill"></image> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| </template> | |||||
| <script> | |||||
| export default { | |||||
| data() { | |||||
| return { | |||||
| orderId: null, | |||||
| orderDate: '2024年12月08日', | |||||
| pets: [ | |||||
| { | |||||
| name: '小汪', | |||||
| photoCount: 2, | |||||
| photos: [ | |||||
| 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/dog1.jpg', | |||||
| 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/dog2.jpg' | |||||
| ] | |||||
| }, | |||||
| { | |||||
| name: 'Billion', | |||||
| photoCount: 2, | |||||
| photos: [ | |||||
| 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/cat1.jpg', | |||||
| 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/cat2.jpg' | |||||
| ] | |||||
| } | |||||
| ], | |||||
| services: [ | |||||
| { | |||||
| name: '猫粮前后对比', | |||||
| beforeImage: 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/food_before.jpg', | |||||
| afterImage: 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/food_after.jpg' | |||||
| }, | |||||
| { | |||||
| name: '水碗前后对比', | |||||
| beforeImage: 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/water_before.jpg', | |||||
| afterImage: 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/water_after.jpg' | |||||
| }, | |||||
| { | |||||
| name: '猫砂盆 厚度前后对比', | |||||
| beforeImage: 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/litter_before.jpg', | |||||
| afterImage: 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/litter_after.jpg' | |||||
| } | |||||
| ] | |||||
| } | |||||
| }, | |||||
| onLoad(options) { | |||||
| if (options.orderId) { | |||||
| this.orderId = options.orderId; | |||||
| // 这里可以根据orderId加载订单详情数据 | |||||
| this.loadOrderDetail(); | |||||
| } | |||||
| }, | |||||
| methods: { | |||||
| loadOrderDetail() { | |||||
| // 这里可以调用API获取订单详情 | |||||
| // 示例代码,实际项目中需要替换为真实API调用 | |||||
| /* | |||||
| getOrderDetail(this.orderId).then(res => { | |||||
| if (res && res.code === 200) { | |||||
| this.orderDate = res.data.orderDate; | |||||
| this.pets = res.data.pets; | |||||
| this.services = res.data.services; | |||||
| } | |||||
| }); | |||||
| */ | |||||
| } | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style lang="scss"> | |||||
| .order-detail-container { | |||||
| padding: 15px; | |||||
| background-color: #f5f5f7; | |||||
| min-height: 100vh; | |||||
| } | |||||
| .order-date { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| padding: 10px 15px; | |||||
| background-color: #fff; | |||||
| border-radius: 8px; | |||||
| margin-bottom: 15px; | |||||
| .order-date-icon { | |||||
| margin-right: 10px; | |||||
| } | |||||
| .order-date-text { | |||||
| color: #333; | |||||
| font-size: 16px; | |||||
| font-weight: 500; | |||||
| } | |||||
| } | |||||
| .order-section { | |||||
| background-color: #fff; | |||||
| border-radius: 8px; | |||||
| margin-bottom: 15px; | |||||
| overflow: hidden; | |||||
| .order-section-title { | |||||
| padding: 12px 15px; | |||||
| border-bottom: 1px solid #f0f0f0; | |||||
| color: #333; | |||||
| font-size: 16px; | |||||
| font-weight: 500; | |||||
| position: relative; | |||||
| &::before { | |||||
| content: ''; | |||||
| position: absolute; | |||||
| left: 0; | |||||
| top: 12px; | |||||
| height: 16px; | |||||
| width: 4px; | |||||
| background-color: #ffaa48; | |||||
| border-radius: 0 2px 2px 0; | |||||
| } | |||||
| } | |||||
| .order-section-content { | |||||
| padding: 15px; | |||||
| } | |||||
| } | |||||
| .order-image-item { | |||||
| margin-bottom: 15px; | |||||
| .order-image-label { | |||||
| color: #666; | |||||
| font-size: 14px; | |||||
| margin-bottom: 8px; | |||||
| } | |||||
| .order-image-container { | |||||
| display: flex; | |||||
| flex-wrap: wrap; | |||||
| gap: 10px; | |||||
| .order-image { | |||||
| width: 100px; | |||||
| height: 100px; | |||||
| border-radius: 4px; | |||||
| object-fit: cover; | |||||
| } | |||||
| } | |||||
| } | |||||
| .pet-record { | |||||
| margin-bottom: 20px; | |||||
| .pet-name { | |||||
| color: #333; | |||||
| font-size: 15px; | |||||
| font-weight: 500; | |||||
| margin-bottom: 10px; | |||||
| } | |||||
| .pet-images { | |||||
| display: flex; | |||||
| flex-wrap: wrap; | |||||
| gap: 10px; | |||||
| .pet-image-container { | |||||
| .pet-image { | |||||
| width: 100px; | |||||
| height: 100px; | |||||
| border-radius: 4px; | |||||
| object-fit: cover; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| .service-record { | |||||
| margin-bottom: 20px; | |||||
| .service-name { | |||||
| color: #333; | |||||
| font-size: 15px; | |||||
| font-weight: 500; | |||||
| margin-bottom: 10px; | |||||
| } | |||||
| .service-comparison { | |||||
| .service-before-after { | |||||
| display: flex; | |||||
| gap: 15px; | |||||
| .service-image-container { | |||||
| position: relative; | |||||
| .service-image { | |||||
| width: 120px; | |||||
| height: 120px; | |||||
| border-radius: 4px; | |||||
| object-fit: cover; | |||||
| } | |||||
| .service-image-label { | |||||
| position: absolute; | |||||
| bottom: 0; | |||||
| left: 0; | |||||
| background-color: rgba(0,0,0,0.5); | |||||
| color: #fff; | |||||
| padding: 2px 8px; | |||||
| font-size: 12px; | |||||
| border-radius: 0 0 0 4px; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| .custom-service { | |||||
| .custom-service-item { | |||||
| margin-bottom: 15px; | |||||
| .custom-service-name { | |||||
| color: #333; | |||||
| font-size: 15px; | |||||
| font-weight: 500; | |||||
| margin-bottom: 10px; | |||||
| } | |||||
| .custom-service-images { | |||||
| display: flex; | |||||
| flex-wrap: wrap; | |||||
| gap: 10px; | |||||
| .custom-service-image { | |||||
| width: 100px; | |||||
| height: 100px; | |||||
| border-radius: 4px; | |||||
| object-fit: cover; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| </style> | |||||
| @ -0,0 +1,367 @@ | |||||
| <template> | |||||
| <view class="task-detail"> | |||||
| <!-- 任务头部信息 --> | |||||
| <view class="task-header"> | |||||
| <view class="task-title">{{taskInfo.title}}</view> | |||||
| <view class="task-deadline">请于{{taskInfo.deadline}}之前上传任务,超时将自动取消</view> | |||||
| </view> | |||||
| <!-- 任务进度 --> | |||||
| <view class="task-progress"> | |||||
| <view class="progress-title">任务进度</view> | |||||
| <uni-steps :options="stepsList" :active="currentStep" active-icon="checkbox-filled" active-color="#ffaa48"></uni-steps> | |||||
| </view> | |||||
| <!-- 任务说明 --> | |||||
| <view class="task-instruction"> | |||||
| <view class="instruction-header"> | |||||
| <image class="instruction-icon" src="https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/point.png"></image> | |||||
| <view class="instruction-title">悬赏任务说明</view> | |||||
| </view> | |||||
| <view class="instruction-content"> | |||||
| <view class="instruction-main"> | |||||
| <text>请以"{{taskInfo.description}}"为主题编辑小红书宣传笔记~</text> | |||||
| </view> | |||||
| <view class="requirement-section"> | |||||
| <view class="requirement-title">封面和配图要求</view> | |||||
| <view class="requirement-content"> | |||||
| <text>封面: 个人宠物图片</text> | |||||
| <text>配图: 个人宠物图片或小程序页面截图(共2-3张)</text> | |||||
| </view> | |||||
| </view> | |||||
| <view class="requirement-section"> | |||||
| <view class="requirement-title">标题示例 (实际发布可以参照以下)</view> | |||||
| <view class="title-examples"> | |||||
| <view class="example-item"> | |||||
| <view class="example-tag">H1</view> | |||||
| <view class="example-text">春节回家猫咪/狗狗怎么办?</view> | |||||
| </view> | |||||
| <view class="example-item"> | |||||
| <view class="example-tag">H2</view> | |||||
| <view class="example-text">今年过年不用担心宠物没人照顾啦~</view> | |||||
| </view> | |||||
| <view class="example-item"> | |||||
| <view class="example-tag">H3</view> | |||||
| <view class="example-text">关于宠物喂养平台的真实体验;</view> | |||||
| </view> | |||||
| <view class="example-item"> | |||||
| <view class="example-tag">H4</view> | |||||
| <view class="example-text">出门旅游,再也不用担心宠物啦!</view> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| <view class="requirement-section"> | |||||
| <view class="requirement-title">其他要求</view> | |||||
| <view class="other-requirements"> | |||||
| <view class="requirement-item"> | |||||
| <view class="requirement-tag">①</view> | |||||
| <view class="requirement-text">文案内容不少于400字;</view> | |||||
| </view> | |||||
| <view class="requirement-item"> | |||||
| <view class="requirement-tag">②</view> | |||||
| <view class="requirement-text">提及关键词上门猫咪/上门狗狗/上门喂养;</view> | |||||
| </view> | |||||
| <view class="requirement-item"> | |||||
| <view class="requirement-tag">③</view> | |||||
| <view class="requirement-text">提及猫狗宠物平台并适当好评;</view> | |||||
| </view> | |||||
| <view class="requirement-item"> | |||||
| <view class="requirement-tag">④</view> | |||||
| <view class="requirement-text">评论区@猫狗宠物官方账号;</view> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| <view class="note-text"> | |||||
| <text>注意是评论区!请务必在正文@官方账号!</text> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| <!-- 底部按钮 --> | |||||
| <view class="footer-buttons"> | |||||
| <u-button shape="circle" plain @click="cancelTask">取消</u-button> | |||||
| <u-button shape="circle" color="#ffaa48" @click="reuploadTask">重新上传</u-button> | |||||
| </view> | |||||
| </view> | |||||
| </template> | |||||
| <script> | |||||
| import { | |||||
| getTaskDetail | |||||
| } from "@/api/system/task.js" | |||||
| export default { | |||||
| data() { | |||||
| return { | |||||
| taskInfo: { | |||||
| id: 0, | |||||
| title: '发布小红书宣传笔记', | |||||
| description: '主题: 猫狗狗食使用感受&体验', | |||||
| deadline: '2025-03-28', | |||||
| taskType: '悬赏任务', | |||||
| reward: '2', | |||||
| status: 'PENDING' | |||||
| }, | |||||
| stepsList: [ | |||||
| { | |||||
| title: '接受任务' | |||||
| }, | |||||
| { | |||||
| title: '上传任务' | |||||
| }, | |||||
| { | |||||
| title: '平台审核' | |||||
| }, | |||||
| { | |||||
| title: '酬劳到账' | |||||
| } | |||||
| ], | |||||
| currentStep: 0 | |||||
| } | |||||
| }, | |||||
| onLoad(options) { | |||||
| if (options.id) { | |||||
| this.loadTaskDetail(options.id); | |||||
| } | |||||
| }, | |||||
| methods: { | |||||
| loadTaskDetail(taskId) { | |||||
| // 实际项目中取消注释下面的代码 | |||||
| /* | |||||
| getTaskDetail(taskId).then(res => { | |||||
| if (res && res.code === 200) { | |||||
| this.taskInfo = res.data; | |||||
| // 根据任务状态设置当前步骤 | |||||
| switch(this.taskInfo.status) { | |||||
| case 'PENDING': | |||||
| this.currentStep = 0; | |||||
| break; | |||||
| case 'ACCEPTED': | |||||
| this.currentStep = 1; | |||||
| break; | |||||
| case 'SUBMITTED': | |||||
| this.currentStep = 2; | |||||
| break; | |||||
| case 'COMPLETED': | |||||
| this.currentStep = 3; | |||||
| break; | |||||
| } | |||||
| } | |||||
| }); | |||||
| */ | |||||
| // 模拟数据 | |||||
| console.log('加载任务详情,ID:', taskId); | |||||
| // 设置当前步骤为1(已接受) | |||||
| this.currentStep = 1; | |||||
| }, | |||||
| cancelTask() { | |||||
| uni.showToast({ | |||||
| title: '已取消任务', | |||||
| icon: 'none' | |||||
| }); | |||||
| setTimeout(() => { | |||||
| uni.navigateBack(); | |||||
| }, 1500); | |||||
| }, | |||||
| reuploadTask() { | |||||
| uni.showToast({ | |||||
| title: '准备重新上传', | |||||
| icon: 'none' | |||||
| }); | |||||
| // 这里可以添加上传逻辑或跳转到上传页面 | |||||
| } | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style lang="scss"> | |||||
| .task-detail { | |||||
| background-color: #f5f5f7; | |||||
| min-height: 100vh; | |||||
| padding-bottom: 120rpx; | |||||
| .task-header { | |||||
| background-color: #FFFFFF; | |||||
| padding: 30rpx; | |||||
| .task-title { | |||||
| font-size: 36rpx; | |||||
| font-weight: bold; | |||||
| color: #333; | |||||
| margin-bottom: 20rpx; | |||||
| } | |||||
| .task-deadline { | |||||
| font-size: 24rpx; | |||||
| color: #999; | |||||
| } | |||||
| } | |||||
| .task-progress { | |||||
| background-color: #FFFFFF; | |||||
| margin-top: 20rpx; | |||||
| padding: 30rpx; | |||||
| .progress-title { | |||||
| font-size: 30rpx; | |||||
| font-weight: bold; | |||||
| color: #333; | |||||
| margin-bottom: 30rpx; | |||||
| } | |||||
| } | |||||
| .task-instruction { | |||||
| background-color: #FFFFFF; | |||||
| margin-top: 20rpx; | |||||
| padding: 30rpx; | |||||
| .instruction-header { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| margin-bottom: 30rpx; | |||||
| .instruction-icon { | |||||
| width: 60rpx; | |||||
| height: 60rpx; | |||||
| margin-right: 20rpx; | |||||
| } | |||||
| .instruction-title { | |||||
| font-size: 32rpx; | |||||
| font-weight: bold; | |||||
| color: #A94F20; | |||||
| } | |||||
| } | |||||
| .instruction-content { | |||||
| .instruction-main { | |||||
| padding: 20rpx 0; | |||||
| border-bottom: 1px solid #EEEEEE; | |||||
| margin-bottom: 20rpx; | |||||
| text { | |||||
| font-size: 28rpx; | |||||
| color: #666; | |||||
| line-height: 1.6; | |||||
| } | |||||
| } | |||||
| .requirement-section { | |||||
| margin-bottom: 30rpx; | |||||
| .requirement-title { | |||||
| font-size: 28rpx; | |||||
| font-weight: bold; | |||||
| color: #333; | |||||
| margin-bottom: 20rpx; | |||||
| } | |||||
| .requirement-content { | |||||
| padding: 20rpx; | |||||
| background-color: #FFF4E5; | |||||
| border-radius: 10rpx; | |||||
| text { | |||||
| display: block; | |||||
| font-size: 26rpx; | |||||
| color: #A94F20; | |||||
| line-height: 1.8; | |||||
| } | |||||
| } | |||||
| .title-examples { | |||||
| background-color: #FFF4E5; | |||||
| padding: 20rpx; | |||||
| border-radius: 10rpx; | |||||
| .example-item { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| margin-bottom: 15rpx; | |||||
| .example-tag { | |||||
| width: 50rpx; | |||||
| height: 50rpx; | |||||
| background-color: #ffaa48; | |||||
| color: #FFFFFF; | |||||
| border-radius: 25rpx; | |||||
| display: flex; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| font-size: 24rpx; | |||||
| margin-right: 20rpx; | |||||
| } | |||||
| .example-text { | |||||
| font-size: 26rpx; | |||||
| color: #A94F20; | |||||
| } | |||||
| } | |||||
| } | |||||
| .other-requirements { | |||||
| background-color: #FFF4E5; | |||||
| padding: 20rpx; | |||||
| border-radius: 10rpx; | |||||
| .requirement-item { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| margin-bottom: 15rpx; | |||||
| .requirement-tag { | |||||
| width: 40rpx; | |||||
| height: 40rpx; | |||||
| color: #A94F20; | |||||
| display: flex; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| font-size: 24rpx; | |||||
| margin-right: 20rpx; | |||||
| } | |||||
| .requirement-text { | |||||
| font-size: 26rpx; | |||||
| color: #A94F20; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| .note-text { | |||||
| text-align: center; | |||||
| margin-top: 20rpx; | |||||
| text { | |||||
| font-size: 24rpx; | |||||
| color: #FF5722; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| .footer-buttons { | |||||
| position: fixed; | |||||
| bottom: 0; | |||||
| left: 0; | |||||
| right: 0; | |||||
| background-color: #FFFFFF; | |||||
| padding: 20rpx 30rpx; | |||||
| display: flex; | |||||
| justify-content: space-around; | |||||
| align-items: center; | |||||
| box-shadow: 0 -2rpx 10rpx rgba(0,0,0,0.05); | |||||
| .u-button { | |||||
| width: 300rpx; | |||||
| height: 80rpx; | |||||
| font-size: 28rpx; | |||||
| } | |||||
| } | |||||
| } | |||||
| </style> | |||||
| @ -0,0 +1,298 @@ | |||||
| <template> | |||||
| <view class="task-center"> | |||||
| <u-subsection :list="tabList" | |||||
| active-color="#ffaa48" | |||||
| bg-color="#fff" | |||||
| inactive-color="#aaaaaa" | |||||
| font-size="16" | |||||
| :current="curNow" | |||||
| @change="sectionChange"></u-subsection> | |||||
| <!-- <view class="container-tabs"> | |||||
| <up-tabs :list="tabList" lineWidth="68rpx" :activeStyle="{ | |||||
| color: '#ffaa48', | |||||
| fontWeight: 'bold', | |||||
| transform: 'scale(1.05)' | |||||
| }" :inactiveStyle="{ | |||||
| color: '#555', | |||||
| transform: 'scale(1)' | |||||
| }" :itemStyle="{height:'88rpx',padding:'0 52rpx'}" lineColor="#ffaa48" @click="sectionChange"></up-tabs> | |||||
| </view> --> | |||||
| <view v-for="(item,index) in pendingTasks" style="padding:28rpx 36rpx 0;" :key="index"> | |||||
| <view class="task-card"> | |||||
| <view class="task-header"> | |||||
| <view class="task-image"> | |||||
| <image src="" mode="heightFix"></image> | |||||
| <image src="" mode="heightFix"></image> | |||||
| </view> | |||||
| <view class="task-type">{{item.taskType}}</view> | |||||
| <view class="task-reward">酬劳 <text> ¥{{item.reward}}</text> </view> | |||||
| </view> | |||||
| <view class="task-content"> | |||||
| <view class="task-icon"> | |||||
| <image :src="item.icon" style="width: 120rpx; height: 120rpx;" mode="aspectFill"></image> | |||||
| </view> | |||||
| <view class="task-info"> | |||||
| <view class="task-title">{{item.title}}</view> | |||||
| <view class="task-desc">{{item.description}}</view> | |||||
| <view class="task-deadline">任务截止日期: {{item.deadline}}</view> | |||||
| </view> | |||||
| </view> | |||||
| <view class="task-footer" v-if="true"> | |||||
| <u-button shape="circle" plain text="查看详情" @click="viewTaskDetail(item)"></u-button> | |||||
| <u-button shape="circle" color="#ffaa48" text="立即上传" @click="uploadTask(item)"></u-button> | |||||
| </view> | |||||
| <view class="task-footer" v-else> | |||||
| <u-button shape="circle" plain text="查看详情" @click="viewTaskDetail(item)"></u-button> | |||||
| <view class="task-status">已接受</view> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| <view v-if="pendingTasks.length === 0" class="empty-tip"> | |||||
| <text>暂无待接受任务</text> | |||||
| </view> | |||||
| </view> | |||||
| </template> | |||||
| <script> | |||||
| import { | |||||
| getTaskList, | |||||
| acceptTask, | |||||
| submitTask, | |||||
| getTaskDetail | |||||
| } from "@/api/system/task.js" | |||||
| export default { | |||||
| data() { | |||||
| return { | |||||
| tabList: [ | |||||
| { | |||||
| name: '待接受', | |||||
| badge: { | |||||
| value: 1, | |||||
| } | |||||
| }, | |||||
| { | |||||
| name: '已接受', | |||||
| badge: { | |||||
| value: 0, | |||||
| } | |||||
| }, | |||||
| ], | |||||
| curNow: 0, | |||||
| pendingTasks: [{ | |||||
| id: 1, | |||||
| taskType: '悬赏任务', | |||||
| reward: '2', | |||||
| icon: 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/point.png', | |||||
| title: '发布小红书宣传笔记', | |||||
| description: '主题: 猫狗狗食使用感受&体验', | |||||
| deadline: '2025-03-28' | |||||
| }, | |||||
| { | |||||
| id: 2, | |||||
| taskType: '悬赏任务', | |||||
| reward: '2', | |||||
| icon: 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/point.png', | |||||
| title: '发布小红书宣传笔记', | |||||
| description: '主题: 猫狗狗食使用感受&体验', | |||||
| deadline: '2025-03-28' | |||||
| }, | |||||
| { | |||||
| id: 3, | |||||
| taskType: '悬赏任务', | |||||
| reward: '2', | |||||
| icon: 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/point.png', | |||||
| title: '发布小红书宣传笔记', | |||||
| description: '主题: 猫狗狗食使用感受&体验', | |||||
| deadline: '2025-03-28' | |||||
| } | |||||
| ], | |||||
| acceptedTasks: [] | |||||
| } | |||||
| }, | |||||
| onLoad() { | |||||
| // 加载任务列表数据 | |||||
| this.getTaskList() | |||||
| }, | |||||
| methods: { | |||||
| sectionChange(index) { | |||||
| this.curNow = index; | |||||
| }, | |||||
| getTaskList() { | |||||
| // 调用API获取任务列表 | |||||
| // 由于后端API可能尚未实现,这里先使用模拟数据 | |||||
| // 实际项目中取消注释下面的代码 | |||||
| /* | |||||
| getTaskList().then(res=>{ | |||||
| if (res && res.code === 200) { | |||||
| let rows = res.rows || [] | |||||
| console.log(rows) | |||||
| this.pendingTasks = rows.filter(item=>item.status=="PENDING") | |||||
| this.acceptedTasks = rows.filter(item=>item.status=="ACCEPTED") | |||||
| } | |||||
| }) | |||||
| */ | |||||
| // 使用模拟数据 | |||||
| console.log('加载任务列表') | |||||
| }, | |||||
| viewTaskDetail(task) { | |||||
| // 查看任务详情,跳转到任务详情页面 | |||||
| uni.navigateTo({ | |||||
| url: `/pages/personalCenter/taskDetail?id=${task.id}` | |||||
| }); | |||||
| }, | |||||
| uploadTask(task) { | |||||
| // 上传任务 | |||||
| uni.showToast({ | |||||
| title: '上传任务: ' + task.title, | |||||
| icon: 'none' | |||||
| }); | |||||
| // 实际项目中取消注释下面的代码 | |||||
| /* | |||||
| submitTask({ | |||||
| taskId: task.id, | |||||
| content: '任务提交内容' | |||||
| }).then(res => { | |||||
| if (res && res.code === 200) { | |||||
| uni.showToast({ | |||||
| title: '任务提交成功', | |||||
| icon: 'success' | |||||
| }); | |||||
| // 刷新任务列表 | |||||
| this.getTaskList(); | |||||
| } | |||||
| }); | |||||
| */ | |||||
| // 模拟接受任务 | |||||
| const index = this.pendingTasks.findIndex(item => item.id === task.id); | |||||
| if (index !== -1) { | |||||
| const acceptedTask = { | |||||
| ...this.pendingTasks[index] | |||||
| }; | |||||
| this.acceptedTasks.push(acceptedTask); | |||||
| this.pendingTasks.splice(index, 1); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style lang="scss"> | |||||
| .task-center { | |||||
| background-color: #f5f5f7; | |||||
| min-height: 100vh; | |||||
| .task-card { | |||||
| background-color: #FFFFFF; | |||||
| border-radius: 16rpx; | |||||
| margin-bottom: 30rpx; | |||||
| overflow: hidden; | |||||
| .task-header { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| margin-bottom: 20rpx; | |||||
| background-color: #FFF4E599; | |||||
| padding: 15rpx; | |||||
| .task-image { | |||||
| margin-right: 30rpx; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| image { | |||||
| height: 50rpx; | |||||
| width: 50rpx; | |||||
| } | |||||
| } | |||||
| .task-type { | |||||
| color: #A94F20; | |||||
| font-size: 26rpx; | |||||
| background-color: #FFF4E5; | |||||
| padding: 10rpx 30rpx; | |||||
| border-radius: 30rpx; | |||||
| } | |||||
| .task-reward { | |||||
| font-size: 26rpx; | |||||
| margin-left: auto; | |||||
| text { | |||||
| color: #FF5722; | |||||
| font-weight: bold; | |||||
| margin-left: 10rpx; | |||||
| font-size: 30rpx; | |||||
| } | |||||
| } | |||||
| } | |||||
| .task-content { | |||||
| display: flex; | |||||
| margin-bottom: 30rpx; | |||||
| padding: 0 30rpx 0 30rpx; | |||||
| .task-icon { | |||||
| margin-right: 30rpx; | |||||
| } | |||||
| .task-info { | |||||
| flex: 1; | |||||
| .task-title { | |||||
| font-size: 32rpx; | |||||
| font-weight: bold; | |||||
| color: #333; | |||||
| margin-bottom: 10rpx; | |||||
| } | |||||
| .task-desc { | |||||
| font-size: 28rpx; | |||||
| color: #666; | |||||
| margin-bottom: 10rpx; | |||||
| } | |||||
| .task-deadline { | |||||
| font-size: 24rpx; | |||||
| color: #999; | |||||
| } | |||||
| } | |||||
| } | |||||
| .task-footer { | |||||
| padding-bottom: 30rpx; | |||||
| display: flex; | |||||
| justify-content: center; | |||||
| align-items: flex-end; | |||||
| gap: 20rpx; | |||||
| .u-button { | |||||
| width: 250rpx; | |||||
| height: 60rpx; | |||||
| font-size: 28rpx; | |||||
| } | |||||
| .task-status { | |||||
| height: 60rpx; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: center; | |||||
| width: 250rpx; | |||||
| color: #ffaa48; | |||||
| font-size: 28rpx; | |||||
| } | |||||
| } | |||||
| } | |||||
| .empty-tip { | |||||
| text-align: center; | |||||
| padding: 60rpx 0; | |||||
| color: #999; | |||||
| font-size: 28rpx; | |||||
| } | |||||
| } | |||||
| </style> | |||||
| @ -0,0 +1,261 @@ | |||||
| <template> | |||||
| <view class="user-info-container container"> | |||||
| <view class="user-avatar-section"> | |||||
| <view class="user-info-title"> | |||||
| 用户头像 | |||||
| </view> | |||||
| <view style="display: flex;justify-content: center;"> | |||||
| <u-upload | |||||
| accept="image" | |||||
| :capture="['album','camera']" | |||||
| :fileList="fileList" | |||||
| @afterRead="afterRead" | |||||
| @delete="deletePic" | |||||
| :max-count="1" | |||||
| name="avatar" | |||||
| width="80" | |||||
| height="80" | |||||
| :custom-style="{flex:0}" | |||||
| > | |||||
| <image :src="avatarUrl" style="width: 80px;height: 80px;border-radius: 50%;"></image> | |||||
| </u-upload> | |||||
| </view> | |||||
| </view> | |||||
| <view class="user-info-section"> | |||||
| <view class="user-info-title"> | |||||
| 基本信息 | |||||
| </view> | |||||
| <view class="user-info-form"> | |||||
| <view class="user-info-item"> | |||||
| <view class="user-info-label">昵称</view> | |||||
| <view class="user-info-input"> | |||||
| <u-input v-model="nickname" placeholder="请输入昵称" :border="false" /> | |||||
| </view> | |||||
| </view> | |||||
| <!-- <view class="user-info-item"> | |||||
| <view class="user-info-label">会员等级</view> | |||||
| <view class="user-info-value"> | |||||
| <text>{{userLevel}}</text> | |||||
| </view> | |||||
| </view> --> | |||||
| </view> | |||||
| </view> | |||||
| <view class="user-info-btns"> | |||||
| <view class="user-info-btn" @click="save"> | |||||
| <u-button color="#FFBF60" :loading="loading"> | |||||
| <view style="color: #fff;"> | |||||
| 保存 | |||||
| </view> | |||||
| </u-button> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| </template> | |||||
| <script> | |||||
| import {updateUserProfile, uploadAvatar} from '@/api/system/user' | |||||
| import {getPersonalInfo} from "@/api/system/personal.js" | |||||
| export default { | |||||
| data() { | |||||
| return { | |||||
| loading: false, | |||||
| fileList: [], | |||||
| avatarUrl: 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/avatar_1.png', | |||||
| nickname: '', | |||||
| userLevel: '' | |||||
| } | |||||
| }, | |||||
| onLoad() { | |||||
| this.getUserInfo() | |||||
| }, | |||||
| methods: { | |||||
| // 获取用户信息 | |||||
| getUserInfo() { | |||||
| getPersonalInfo().then(res => { | |||||
| if (res && (res.id || res.id === 0)) { | |||||
| this.nickname = res.nickname || '' | |||||
| this.userLevel = res.level || '' | |||||
| if (res.avatar) { | |||||
| this.avatarUrl = res.avatar | |||||
| this.fileList = [{url: res.avatar}] | |||||
| } | |||||
| } | |||||
| }) | |||||
| }, | |||||
| // 删除图片 | |||||
| deletePic(event) { | |||||
| this.fileList.splice(event.index, 1) | |||||
| this.avatarUrl = 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/avatar_1.png' | |||||
| }, | |||||
| // 新增图片 | |||||
| async afterRead(event) { | |||||
| // 当设置 multiple 为 true 时, file 为数组格式,否则为对象格式 | |||||
| let lists = [].concat(event.file) | |||||
| let fileListLen = this.fileList.length | |||||
| lists.map((item) => { | |||||
| this.fileList.push({ | |||||
| ...item, | |||||
| status: 'uploading', | |||||
| message: '上传中' | |||||
| }) | |||||
| }) | |||||
| for (let i = 0; i < lists.length; i++) { | |||||
| const result = await this.uploadFilePromise(lists[i].url) | |||||
| let item = this.fileList[fileListLen] | |||||
| this.fileList.splice(fileListLen, 1, Object.assign(item, { | |||||
| status: 'success', | |||||
| message: '', | |||||
| url: result | |||||
| })) | |||||
| this.avatarUrl = result | |||||
| fileListLen++ | |||||
| } | |||||
| }, | |||||
| uploadFilePromise(url) { | |||||
| return new Promise((resolve, reject) => { | |||||
| let a = uni.uploadFile({ | |||||
| url: 'https://store-test.catmdogd.com/test-api/h5/oss/upload', | |||||
| filePath: url, | |||||
| name: 'file', | |||||
| formData: { | |||||
| user: 'test' | |||||
| }, | |||||
| success: (res) => { | |||||
| setTimeout(() => { | |||||
| if(res && res.data){ | |||||
| let resData = JSON.parse(res.data); | |||||
| resolve(resData.url); | |||||
| } | |||||
| reject("上传失败"); | |||||
| }, 1000) | |||||
| } | |||||
| }); | |||||
| }) | |||||
| }, | |||||
| // 保存用户信息 | |||||
| save() { | |||||
| if (!this.nickname) { | |||||
| this.$modal.showToast('请输入昵称!') | |||||
| return | |||||
| } | |||||
| this.loading = true | |||||
| let params = { | |||||
| nickname: this.nickname, | |||||
| avatar: this.avatarUrl | |||||
| } | |||||
| updateUserProfile(params).then(res => { | |||||
| if (res && res.code == 200) { | |||||
| uni.showToast({ | |||||
| title: '保存成功', | |||||
| duration: 3000, | |||||
| icon: "none" | |||||
| }) | |||||
| setTimeout(() => { | |||||
| this.loading = false | |||||
| let len = getCurrentPages().length | |||||
| if (len >= 2) { | |||||
| uni.navigateBack() | |||||
| } else { | |||||
| uni.redirectTo({url: '/pages/personalCenter/index'}) | |||||
| } | |||||
| }, 1000) | |||||
| } else { | |||||
| this.loading = false | |||||
| uni.showToast({ | |||||
| title: '更新用户信息失败', | |||||
| duration: 3000, | |||||
| icon: "none" | |||||
| }) | |||||
| } | |||||
| }).catch(() => { | |||||
| this.loading = false | |||||
| uni.showToast({ | |||||
| title: '更新用户信息失败', | |||||
| duration: 3000, | |||||
| icon: "none" | |||||
| }) | |||||
| }) | |||||
| } | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style lang="scss"> | |||||
| .user-info-container { | |||||
| position: relative; | |||||
| height: 100%; | |||||
| padding-bottom: 90px; | |||||
| .user-avatar-section { | |||||
| width: 100%; | |||||
| background-color: #fff; | |||||
| padding: 15px 20px; | |||||
| margin-bottom: 10px; | |||||
| } | |||||
| .user-info-section { | |||||
| width: 100%; | |||||
| background-color: #fff; | |||||
| padding: 15px 20px; | |||||
| } | |||||
| .user-info-title { | |||||
| font-size: 14px; | |||||
| color: #333; | |||||
| font-weight: bold; | |||||
| padding-bottom: 15px; | |||||
| } | |||||
| .user-info-form { | |||||
| width: 100%; | |||||
| } | |||||
| .user-info-item { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| padding: 12px 0; | |||||
| border-bottom: 1px solid #efefef; | |||||
| &:last-child { | |||||
| border-bottom: none; | |||||
| } | |||||
| } | |||||
| .user-info-label { | |||||
| width: 80px; | |||||
| color: #333; | |||||
| font-size: 14px; | |||||
| } | |||||
| .user-info-input { | |||||
| flex: 1; | |||||
| } | |||||
| .user-info-value { | |||||
| flex: 1; | |||||
| color: #666; | |||||
| font-size: 14px; | |||||
| } | |||||
| .user-info-btns { | |||||
| background-color: #FFFFFF; | |||||
| padding: 10px 20px 40px; | |||||
| width: 100%; | |||||
| height: 90px; | |||||
| position: fixed; | |||||
| bottom: 0; | |||||
| z-index: 100; | |||||
| text-align: center; | |||||
| .user-info-btn { | |||||
| width: 80%; | |||||
| margin: 0 auto; | |||||
| } | |||||
| } | |||||
| } | |||||
| </style> | |||||
| @ -1,98 +1,116 @@ | |||||
| import config from '@/config' | import config from '@/config' | ||||
| import storage from '@/utils/storage' | import storage from '@/utils/storage' | ||||
| import constant from '@/utils/constant' | import constant from '@/utils/constant' | ||||
| import { login, logout, getInfo } from '@/api/login' | |||||
| import { getToken, setToken, removeToken } from '@/utils/auth' | |||||
| import { | |||||
| login, | |||||
| logout, | |||||
| getInfo | |||||
| } from '@/api/login' | |||||
| import { | |||||
| getToken, | |||||
| setToken, | |||||
| removeToken | |||||
| } from '@/utils/auth' | |||||
| const baseUrl = config.baseUrl | const baseUrl = config.baseUrl | ||||
| const user = { | const user = { | ||||
| state: { | |||||
| token: getToken(), | |||||
| name: storage.get(constant.name), | |||||
| avatar: storage.get(constant.avatar), | |||||
| roles: storage.get(constant.roles), | |||||
| permissions: storage.get(constant.permissions) | |||||
| }, | |||||
| state: { | |||||
| token: getToken(), | |||||
| name: storage.get(constant.name), | |||||
| avatar: storage.get(constant.avatar), | |||||
| roles: storage.get(constant.roles), | |||||
| permissions: storage.get(constant.permissions) | |||||
| }, | |||||
| mutations: { | |||||
| SET_TOKEN: (state, token) => { | |||||
| state.token = token | |||||
| }, | |||||
| SET_NAME: (state, name) => { | |||||
| state.name = name | |||||
| storage.set(constant.name, name) | |||||
| }, | |||||
| SET_AVATAR: (state, avatar) => { | |||||
| state.avatar = avatar | |||||
| storage.set(constant.avatar, avatar) | |||||
| }, | |||||
| SET_ROLES: (state, roles) => { | |||||
| state.roles = roles | |||||
| storage.set(constant.roles, roles) | |||||
| }, | |||||
| SET_PERMISSIONS: (state, permissions) => { | |||||
| state.permissions = permissions | |||||
| storage.set(constant.permissions, permissions) | |||||
| } | |||||
| }, | |||||
| mutations: { | |||||
| SET_TOKEN: (state, token) => { | |||||
| state.token = token | |||||
| }, | |||||
| SET_NAME: (state, name) => { | |||||
| state.name = name | |||||
| storage.set(constant.name, name) | |||||
| }, | |||||
| SET_AVATAR: (state, avatar) => { | |||||
| state.avatar = avatar | |||||
| storage.set(constant.avatar, avatar) | |||||
| }, | |||||
| SET_ROLES: (state, roles) => { | |||||
| state.roles = roles | |||||
| storage.set(constant.roles, roles) | |||||
| }, | |||||
| SET_PERMISSIONS: (state, permissions) => { | |||||
| state.permissions = permissions | |||||
| storage.set(constant.permissions, permissions) | |||||
| } | |||||
| }, | |||||
| actions: { | |||||
| // 登录 | |||||
| Login({ commit }, userInfo) { | |||||
| const username = userInfo.username.trim() | |||||
| const password = userInfo.password | |||||
| const code = userInfo.code | |||||
| const uuid = userInfo.uuid | |||||
| return new Promise((resolve, reject) => { | |||||
| login(username, password, code, uuid).then(res => { | |||||
| setToken(res.token) | |||||
| commit('SET_TOKEN', res.token) | |||||
| resolve() | |||||
| }).catch(error => { | |||||
| reject(error) | |||||
| }) | |||||
| }) | |||||
| }, | |||||
| actions: { | |||||
| // 登录 | |||||
| Login({ | |||||
| commit | |||||
| }, userInfo) { | |||||
| const username = userInfo.username.trim() | |||||
| const password = userInfo.password | |||||
| const code = userInfo.code | |||||
| const uuid = userInfo.uuid | |||||
| return new Promise((resolve, reject) => { | |||||
| login(username, password, code, uuid).then(res => { | |||||
| setToken(res.token) | |||||
| commit('SET_TOKEN', res.token) | |||||
| resolve() | |||||
| }).catch(error => { | |||||
| reject(error) | |||||
| }) | |||||
| }) | |||||
| }, | |||||
| // 获取用户信息 | |||||
| GetInfo({ commit, state }) { | |||||
| return new Promise((resolve, reject) => { | |||||
| getInfo().then(res => { | |||||
| const user = res.user | |||||
| const avatar = (user == null || user.avatar == "" || user.avatar == null) ? require("@/static/images/profile.jpg") : baseUrl + user.avatar | |||||
| const username = (user == null || user.userName == "" || user.userName == null) ? "" : user.userName | |||||
| if (res.roles && res.roles.length > 0) { | |||||
| commit('SET_ROLES', res.roles) | |||||
| commit('SET_PERMISSIONS', res.permissions) | |||||
| } else { | |||||
| commit('SET_ROLES', ['ROLE_DEFAULT']) | |||||
| } | |||||
| commit('SET_NAME', username) | |||||
| commit('SET_AVATAR', avatar) | |||||
| resolve(res) | |||||
| }).catch(error => { | |||||
| reject(error) | |||||
| }) | |||||
| }) | |||||
| }, | |||||
| // 获取用户信息 | |||||
| GetInfo({ | |||||
| commit, | |||||
| state | |||||
| }) { | |||||
| return new Promise((resolve, reject) => { | |||||
| getInfo().then(res => { | |||||
| const user = res.user | |||||
| const avatar = (user == null || user.avatar == "" || user.avatar == null) ? | |||||
| require("@/static/images/profile.jpg") : baseUrl + user.avatar | |||||
| const username = (user == null || user.userName == "" || user.userName == | |||||
| null) ? "" : user.userName | |||||
| if (res.roles && res.roles.length > 0) { | |||||
| commit('SET_ROLES', res.roles) | |||||
| commit('SET_PERMISSIONS', res.permissions) | |||||
| } else { | |||||
| commit('SET_ROLES', ['ROLE_DEFAULT']) | |||||
| } | |||||
| commit('SET_NAME', username) | |||||
| commit('SET_AVATAR', avatar) | |||||
| resolve(res) | |||||
| }).catch(error => { | |||||
| reject(error) | |||||
| }) | |||||
| }) | |||||
| }, | |||||
| // 退出系统 | |||||
| LogOut({ commit, state }) { | |||||
| return new Promise((resolve, reject) => { | |||||
| logout(state.token).then(() => { | |||||
| commit('SET_TOKEN', '') | |||||
| commit('SET_ROLES', []) | |||||
| commit('SET_PERMISSIONS', []) | |||||
| removeToken() | |||||
| storage.clean() | |||||
| resolve() | |||||
| }).catch(error => { | |||||
| reject(error) | |||||
| }) | |||||
| }) | |||||
| } | |||||
| } | |||||
| // 退出系统 | |||||
| LogOut({ | |||||
| commit, | |||||
| state | |||||
| }) { | |||||
| return new Promise((resolve, reject) => { | |||||
| logout(state.token).then(() => { | |||||
| commit('SET_TOKEN', '') | |||||
| commit('SET_ROLES', []) | |||||
| commit('SET_PERMISSIONS', []) | |||||
| removeToken() | |||||
| storage.clean() | |||||
| resolve() | |||||
| }).catch(error => { | |||||
| reject(error) | |||||
| }) | |||||
| }) | |||||
| } | |||||
| } | |||||
| } | } | ||||
| export default user | |||||
| export default user | |||||