- 新增任务中心页面,支持任务列表展示、任务接受、任务提交等功能 - 新增订单详情页面,展示订单详细信息及服务记录 - 新增个人信息页面,支持用户头像、昵称等信息修改 - 新增配置信息初始化功能,优化全局配置管理 - 新增新用户优惠券弹窗,提升用户体验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> | |||
| <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 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 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> | |||
| </template> | |||
| <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> | |||
| <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 { | |||
| 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 { | |||
| position: relative; /* 确保内容在遮罩层之上 */ | |||
| z-index: 999; /* 确保内容在遮罩层之上 */ | |||
| position: relative; | |||
| /* 确保内容在遮罩层之上 */ | |||
| z-index: 999; | |||
| /* 确保内容在遮罩层之上 */ | |||
| } | |||
| } | |||
| } | |||
| </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 storage from '@/utils/storage' | |||
| 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 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 | |||