- 新增新用户专享页面,包含优惠券领取功能 - 优化任务模块接口和页面逻辑 - 重构登录页面样式和交互流程 - 新增图片资源及上传功能 - 优化Vuex状态管理,新增配置映射 - 完善任务上传和详情页面的状态展示master
| @ -1,120 +1,151 @@ | |||
| <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 class="new-user-coupon" v-if="showPopup"> | |||
| <view class="mask" @click="closePopup"></view> | |||
| <view class="coupon-container"> | |||
| <view class="coupon-content"> | |||
| <view style="position: relative;"> | |||
| <image class="coupon-image" | |||
| style="height: 800rpx;" | |||
| src="http://wxa.mp.video.tencent-cloud.com/271/20304/stodownload?m=e32f5f803d62036cc76c2de769355081&filekey=30340201010420301e0202010f040253480410e32f5f803d62036cc76c2de76935508102020d9e040d00000004627466730000000132&hy=SH&storeid=2689416ee0007c1f4000000000000010f00004f50534805aab171568b33d14&bizid=1023" | |||
| mode="aspectFill"></image> | |||
| <image | |||
| style="width: 280rpx;height: 70rpx; | |||
| position: absolute; | |||
| left: 50%; | |||
| top: 20rpx; | |||
| transform: translate(-50%, 0%);" | |||
| mode="aspectFill" | |||
| src="https://image.hhlm1688.com/2025/08/07767f2fc0a686433bb9e3f90bc6e60990Group%201000001612@3x.png"/> | |||
| <image class="coupon-image" | |||
| style="position: absolute;left: 50%;top: 50%; | |||
| width: 80%; | |||
| transform: translate(-50%, -50%);" | |||
| :src="NewUserCoupon.couponPoster || image" | |||
| mode="widthFix"></image> | |||
| </view> | |||
| <view class="coupon-btn" @click="getCoupon">立即领取</view> | |||
| </view> | |||
| <view class="close-btn" @click="closePopup"> | |||
| <text class="close-icon">×</text> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| import { getToken } from '@/utils/auth' | |||
| import { mapState } from 'vuex' | |||
| export default { | |||
| name: 'NewUserCoupon', | |||
| data() { | |||
| return { | |||
| showPopup: true | |||
| } | |||
| }, | |||
| methods: { | |||
| closePopup() { | |||
| this.showPopup = false | |||
| this.$emit('close') | |||
| name: 'NewUserCoupon', | |||
| data() { | |||
| return { | |||
| showPopup: true, | |||
| image : 'https://img.teyizhao.com/2025-08-07/a7535f42-6726-4630-9552-6940331ddb8b.png', | |||
| } | |||
| }, | |||
| getCoupon() { | |||
| // 检查用户是否已登录 | |||
| if (!getToken()) { | |||
| // 未登录,跳转到登录页面 | |||
| uni.navigateTo({ | |||
| url: '/pages_order/auth/login' | |||
| }) | |||
| } else { | |||
| // 已登录,触发领券事件 | |||
| this.$emit('getCoupon') | |||
| this.closePopup() | |||
| } | |||
| computed : { | |||
| ...mapState(['NewUserCoupon']), | |||
| }, | |||
| methods: { | |||
| closePopup() { | |||
| this.showPopup = false | |||
| this.$emit('close') | |||
| }, | |||
| getCoupon() { | |||
| // 检查用户是否已登录 | |||
| if (!getToken() || !this.userInfo.phone) { | |||
| // 未登录,跳转到登录页面 | |||
| uni.navigateTo({ | |||
| url: '/pages_order/auth/login?url=/pages_order/newUser/index' | |||
| }) | |||
| } else { | |||
| // 已登录,跳转到新用户优惠券页面 | |||
| this.closePopup() | |||
| uni.navigateTo({ | |||
| url: '/pages_order/newUser/index' | |||
| }) | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| </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; | |||
| position: fixed; | |||
| 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%; | |||
| z-index: 999; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| .close-icon { | |||
| color: #666; | |||
| font-size: 40rpx; | |||
| font-weight: bold; | |||
| .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 { | |||
| position: relative; | |||
| margin-top: -100rpx; | |||
| 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 { | |||
| position: relative; | |||
| 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> | |||
| @ -0,0 +1,208 @@ | |||
| <template> | |||
| <uni-popup ref="popup" type="bottom" background-color="#fff" border-radius="20rpx 20rpx 0 0"> | |||
| <view class="popup-content"> | |||
| <!-- 标题 --> | |||
| <view class="popup-title"> | |||
| <text>选择下单方式</text> | |||
| <view class="close-btn" @click="close"> | |||
| <uni-icons type="closeempty" size="20" color="#999"></uni-icons> | |||
| </view> | |||
| </view> | |||
| <!-- 选项列表 --> | |||
| <view class="option-list"> | |||
| <!-- 系统下单 --> | |||
| <view class="option-item" @click="selectOption('system')"> | |||
| <view class="option-left"> | |||
| <image class="option-icon" | |||
| src="https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/petServiceOrder/SystemOrderCircle.png" /> | |||
| <view class="option-info"> | |||
| <text class="option-title">系统下单</text> | |||
| <text class="option-desc">系统自动为您匹配合适的伴宠师</text> | |||
| </view> | |||
| </view> | |||
| <uni-icons type="arrowright" size="16" color="#ccc"></uni-icons> | |||
| </view> | |||
| <!-- 指定伴宠师 --> | |||
| <view class="option-item" @click="selectOption('companion')"> | |||
| <view class="option-left"> | |||
| <image class="option-icon" | |||
| src="https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/petServiceOrder/OrderIcon.png" /> | |||
| <view class="option-info"> | |||
| <text class="option-title">指定伴宠师</text> | |||
| <text class="option-desc">选择您信任的伴宠师为您服务</text> | |||
| </view> | |||
| </view> | |||
| <uni-icons type="arrowright" size="16" color="#ccc"></uni-icons> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| </uni-popup> | |||
| </template> | |||
| <script> | |||
| export default { | |||
| name: 'OrderTypeSelectPopup', | |||
| methods: { | |||
| // 打开弹窗 | |||
| open() { | |||
| this.$refs.popup.open('bottom') | |||
| }, | |||
| // 关闭弹窗 | |||
| close() { | |||
| this.$refs.popup.close() | |||
| }, | |||
| // 选择下单方式 | |||
| selectOption(type) { | |||
| this.close() | |||
| setTimeout(() => { | |||
| if (type === 'system') { | |||
| // 系统下单 - 跳转到新订单页面 | |||
| uni.navigateTo({ | |||
| url: '/pages/newOrder/serviceNew' | |||
| }) | |||
| } else if (type === 'companion') { | |||
| // 指定伴宠师 - 先选择定位 | |||
| this.selectLocation() | |||
| } | |||
| }, 300) | |||
| }, | |||
| // 选择定位 | |||
| selectLocation() { | |||
| wx.chooseLocation({ | |||
| type: 'gcj02', | |||
| success: (res) => { | |||
| console.log('选择的位置:', res); | |||
| // 构建位置信息对象 | |||
| const allInfo = { | |||
| isCheckLocation: true, | |||
| locationName: res.address, | |||
| locationLongitude: res.longitude, | |||
| locationLatitude: res.latitude, | |||
| locationAddress: res.address, | |||
| selectedDate: [], | |||
| isCheckTime: false, | |||
| selectedDateShowText: '', | |||
| }; | |||
| this.$store.commit('setPosition', { | |||
| address: res.address, | |||
| longitude: res.longitude, | |||
| latitude: res.latitude, | |||
| date : [], | |||
| }) | |||
| // 跳转到伴宠师列表页面,传递位置信息 | |||
| uni.navigateTo({ | |||
| url: `/pages_order/companionPetList/companionPetList?info=` + encodeURIComponent(JSON.stringify(allInfo)) | |||
| }) | |||
| }, | |||
| fail: (err) => { | |||
| console.error('选择位置失败:', err); | |||
| uni.showToast({ | |||
| title: '选择位置失败,请重试', | |||
| icon: 'none', | |||
| duration: 2000 | |||
| }) | |||
| } | |||
| }); | |||
| } | |||
| } | |||
| } | |||
| </script> | |||
| <style lang="scss" scoped> | |||
| .popup-content { | |||
| padding: 40rpx 30rpx 60rpx; | |||
| background: #fff; | |||
| border-radius: 20rpx 20rpx 0 0; | |||
| } | |||
| .popup-title { | |||
| display: flex; | |||
| justify-content: space-between; | |||
| align-items: center; | |||
| margin-bottom: 40rpx; | |||
| text { | |||
| font-size: 32rpx; | |||
| font-weight: bold; | |||
| color: #333; | |||
| } | |||
| .close-btn { | |||
| width: 60rpx; | |||
| height: 60rpx; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| border-radius: 50%; | |||
| background: #f5f5f5; | |||
| &:active { | |||
| background: #e5e5e5; | |||
| } | |||
| } | |||
| } | |||
| .option-list { | |||
| .option-item { | |||
| display: flex; | |||
| justify-content: space-between; | |||
| align-items: center; | |||
| padding: 30rpx 20rpx; | |||
| margin-bottom: 20rpx; | |||
| background: #f8f9fa; | |||
| border-radius: 16rpx; | |||
| border: 2rpx solid transparent; | |||
| transition: all 0.3s ease; | |||
| &:active { | |||
| background: #e9ecef; | |||
| border-color: #FFB13F; | |||
| transform: scale(0.98); | |||
| } | |||
| &:last-child { | |||
| margin-bottom: 0; | |||
| } | |||
| .option-left { | |||
| display: flex; | |||
| align-items: center; | |||
| flex: 1; | |||
| .option-icon { | |||
| width: 60rpx; | |||
| height: 60rpx; | |||
| margin-right: 20rpx; | |||
| border-radius: 8rpx; | |||
| } | |||
| .option-info { | |||
| display: flex; | |||
| flex-direction: column; | |||
| .option-title { | |||
| font-size: 30rpx; | |||
| font-weight: 600; | |||
| color: #333; | |||
| margin-bottom: 8rpx; | |||
| } | |||
| .option-desc { | |||
| font-size: 24rpx; | |||
| color: #666; | |||
| line-height: 1.4; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| </style> | |||
| @ -0,0 +1,170 @@ | |||
| <template> | |||
| <view class="new-user-page"> | |||
| <!-- 背景图片 --> | |||
| <image class="bg-image" | |||
| src="http://wxa.mp.video.tencent-cloud.com/271/20304/stodownload?m=e32f5f803d62036cc76c2de769355081&filekey=30340201010420301e0202010f040253480410e32f5f803d62036cc76c2de76935508102020d9e040d00000004627466730000000132&hy=SH&storeid=2689416ee0007c1f4000000000000010f00004f50534805aab171568b33d14&bizid=1023" | |||
| mode="aspectFill" /> | |||
| <!-- 顶部标题图片 --> | |||
| <image class="title-image" src="https://image.hhlm1688.com/2025/08/07767f2fc0a686433bb9e3f90bc6e60990Group%201000001612@3x.png" | |||
| mode="widthFix" /> | |||
| <!-- 优惠券内容图片 --> | |||
| <image class="coupon-content-image" | |||
| :src="NewUserCoupon.couponPoster || image" mode="widthFix" /> | |||
| <!-- 立即领取/立即使用按钮 --> | |||
| <view class="receive-btn" @click="handleButtonClick"> | |||
| {{ isReceived ? '立即使用' : '立即领取' }} | |||
| </view> | |||
| <!-- 下单方式选择弹窗 --> | |||
| <order-type-select-popup ref="orderTypeSelectPopup" /> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| import { getToken } from '@/utils/auth' | |||
| import OrderTypeSelectPopup from '@/pages_order/components/OrderTypeSelectPopup.vue' | |||
| import { mapState } from 'vuex' | |||
| import { receiveCoupon } from "@/api/system/user" | |||
| export default { | |||
| name: 'NewUserCouponPage', | |||
| components: { | |||
| OrderTypeSelectPopup | |||
| }, | |||
| data() { | |||
| return { | |||
| isReceived: false, // 优惠券是否已领取 | |||
| image : 'https://img.teyizhao.com/2025-08-07/a7535f42-6726-4630-9552-6940331ddb8b.png', | |||
| } | |||
| }, | |||
| computed : { | |||
| ...mapState(['NewUserCoupon']), | |||
| }, | |||
| methods: { | |||
| // 处理按钮点击 | |||
| handleButtonClick() { | |||
| if (this.isReceived) { | |||
| // 已领取,点击立即使用,打开选择下单方式弹窗 | |||
| this.openOrderTypePopup() | |||
| } else { | |||
| // 未领取,点击立即领取 | |||
| this.receiveCoupon() | |||
| } | |||
| }, | |||
| // 领取优惠券 | |||
| receiveCoupon() { | |||
| let data = { | |||
| stockId: this.NewUserCoupon.id, | |||
| } | |||
| receiveCoupon(data).then(res => { | |||
| if (res.code == 200) { | |||
| uni.showToast({ | |||
| title: '领取成功!', | |||
| icon: 'success', | |||
| duration: 2000 | |||
| }) | |||
| // 更新状态为已领取 | |||
| this.isReceived = true | |||
| } | |||
| }).catch(err => { | |||
| uni.showToast({ | |||
| title: '领取优惠券失败', | |||
| icon: 'none' | |||
| }) | |||
| }) | |||
| }, | |||
| // 打开下单方式选择弹窗 | |||
| openOrderTypePopup() { | |||
| this.$refs.orderTypeSelectPopup.open() | |||
| }, | |||
| // 暂不领取 | |||
| skipReceive() { | |||
| uni.navigateBack() | |||
| } | |||
| } | |||
| } | |||
| </script> | |||
| <style lang="scss" scoped> | |||
| .new-user-page { | |||
| position: relative; | |||
| width: 100vw; | |||
| height: 100vh; | |||
| display: flex; | |||
| flex-direction: column; | |||
| align-items: center; | |||
| justify-content: center; | |||
| overflow: hidden; | |||
| } | |||
| .bg-image { | |||
| position: absolute; | |||
| top: 0; | |||
| left: 0; | |||
| width: 100%; | |||
| height: 100%; | |||
| z-index: 1; | |||
| } | |||
| .title-image { | |||
| position: relative; | |||
| z-index: 2; | |||
| width: 280rpx; | |||
| margin-bottom: 40rpx; | |||
| margin-top: -200rpx; | |||
| } | |||
| .coupon-content-image { | |||
| position: relative; | |||
| z-index: 2; | |||
| width: 600rpx; | |||
| margin-bottom: 80rpx; | |||
| } | |||
| .receive-btn { | |||
| position: relative; | |||
| z-index: 2; | |||
| width: 600rpx; | |||
| height: 80rpx; | |||
| background: linear-gradient(135deg, #FFB13F 0%, #FF8C00 100%); | |||
| color: #FFFFFF; | |||
| font-size: 32rpx; | |||
| font-weight: bold; | |||
| border-radius: 40rpx; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| box-shadow: 0 8rpx 20rpx rgba(255, 177, 63, 0.4); | |||
| margin-bottom: 40rpx; | |||
| &:active { | |||
| transform: scale(0.95); | |||
| transition: transform 0.1s; | |||
| } | |||
| } | |||
| .skip-btn { | |||
| position: relative; | |||
| z-index: 2; | |||
| width: 200rpx; | |||
| height: 60rpx; | |||
| background: rgba(255, 255, 255, 0.8); | |||
| color: #666; | |||
| font-size: 28rpx; | |||
| border-radius: 30rpx; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| &:active { | |||
| background: rgba(255, 255, 255, 0.6); | |||
| transition: background 0.1s; | |||
| } | |||
| } | |||
| </style> | |||
| @ -1,430 +1,422 @@ | |||
| <template> | |||
| <view class="task-detail"> | |||
| <!-- 任务头部信息 --> | |||
| <view class="task-header"> | |||
| <view class="header-content"> | |||
| <view class="header-top-row"> | |||
| <view class="task-title">{{ getStatusText() }}</view> | |||
| <view class="task-type">{{taskInfo.taskName || ''}}</view> | |||
| <view class="task-reward">酬劳 <text> ¥{{taskInfo.taskMoney}}</text> </view> | |||
| </view> | |||
| <view class="task-deadline">请于 | |||
| <text style="color: #FF5722;">{{taskInfo.taskEndTime ? formatDate(taskInfo.taskEndTime) : ''}}</text> | |||
| 之前上传任务,超时将自动取消</view> | |||
| </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"> | |||
| <view class="task-detail"> | |||
| <!-- 任务头部信息 --> | |||
| <view class="task-header"> | |||
| <view class="header-content"> | |||
| <view class="header-top-row"> | |||
| <view class="task-status-tag" | |||
| :class="{ 'status-pending': taskInfo.status === 0, 'status-reviewing': taskInfo.status === 1, 'status-rejected': taskInfo.status === 3, 'status-approved': taskInfo.status === 2 }"> | |||
| <text v-if="taskInfo.status === 0">待上传</text> | |||
| <text v-else-if="taskInfo.status === 1">待审核</text> | |||
| <text v-else-if="taskInfo.status === 2">审核通过</text> | |||
| <text v-else-if="taskInfo.status === 3">已驳回</text> | |||
| </view> | |||
| <view class="task-type">悬赏任务</view> | |||
| <view class="task-reward" v-if="taskInfo.type == 0">酬劳 <text>{{ taskInfo.taskCouponTitle }}</text> | |||
| </view> | |||
| <view class="task-reward" v-if="taskInfo.type == 1">酬劳 <text> ¥{{ taskInfo.taskMoney }}</text></view> | |||
| </view> | |||
| <view class="task-deadline">请于 | |||
| <text style="color: #FF5722;">{{ taskInfo.endTime ? formatDate(taskInfo.endTime) : '' }}</text> | |||
| 之前上传任务,超时将自动取消 | |||
| </view> | |||
| </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="taskInfo.taskIcon || 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/point.png'"> | |||
| </image> | |||
| <view class="instruction-title">{{taskInfo.taskName || '任务说明'}}</view> | |||
| </view> --> | |||
| <view class="instruction-content"> | |||
| <!-- <view class="instruction-main"> | |||
| <!-- <view class="instruction-content"> --> | |||
| <!-- <view class="instruction-main"> | |||
| <text>{{taskInfo.theme || '暂无任务说明'}}</text> | |||
| </view> --> | |||
| <!-- 审核未通过时显示驳回原因 --> | |||
| <!-- <view class="requirement-section" v-if="taskInfo.examineState === 2"> | |||
| <!-- 审核未通过时显示驳回原因 --> | |||
| <!-- <view class="requirement-section" v-if="taskInfo.examineState === 2"> | |||
| <view class="requirement-title">驳回原因</view> | |||
| <view class="other-requirements"> | |||
| <view class="requirement-item"> | |||
| <view class="requirement-tag">!</view> | |||
| <view class="requirement-text">{{taskInfo.examineText || '未提供驳回原因'}}</view> | |||
| <view class="requirement-text">{{taskInfo.rejectTxt || '未提供驳回原因'}}</view> | |||
| </view> | |||
| </view> | |||
| </view> --> | |||
| <!-- 任务图片 --> | |||
| <view class="task-images" v-if="taskInfo.image"> | |||
| <image :src="taskInfo.image" mode="widthFix" style="width: 100%;"></image> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <!-- 底部按钮 --> | |||
| <view class="footer-buttons"> | |||
| <u-button shape="circle" plain @click="cancelTask">取消</u-button> | |||
| <u-button shape="circle" color="#ffaa48" v-if="taskInfo.status == 0" | |||
| @click="acceptTaskHandler">接受任务</u-button> | |||
| <u-button shape="circle" color="#ffaa48" v-else-if="taskInfo.taskState == 1 || taskInfo.examineState == 2" | |||
| @click="uploadTask">{{taskInfo.examineState === 2 ? '重新上传' : '立即上传'}}</u-button> | |||
| </view> | |||
| </view> | |||
| <!-- 任务图片 --> | |||
| <view class="task-images" v-if="taskInfo.image"> | |||
| <image :src="taskInfo.image" mode="widthFix" style="width: 100%;border-radius: 20rpx;"></image> | |||
| </view> | |||
| <!-- </view> --> | |||
| </view> | |||
| <!-- 底部按钮 --> | |||
| <view class="footer-buttons"> | |||
| <u-button shape="circle" plain @click="cancelTask">取消</u-button> | |||
| <u-button shape="circle" color="#ffaa48" v-if="taskInfo.status == 0" @click="uploadTask">立即上传</u-button> | |||
| <u-button shape="circle" disabled v-else-if="taskInfo.status == 1" text="审核中"></u-button> | |||
| <u-button shape="circle" color="#ffaa48" v-else-if="taskInfo.status == 3" | |||
| @click="uploadTask">重新上传</u-button> | |||
| <u-button v-if="taskInfo.status === 3" shape="circle" type="error" text="驳回原因" | |||
| @click="showRejectReason"></u-button> | |||
| <view v-if="taskInfo.status == 2" class="task-status task-status-approved">已通过</view> | |||
| </view> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| import { | |||
| getTaskDetail | |||
| } from "@/api/order/task.js" | |||
| import { | |||
| getTaskList, | |||
| acceptTask | |||
| } from "@/api/order/task.js" | |||
| export default { | |||
| data() { | |||
| return { | |||
| taskInfo: { | |||
| id: 0, | |||
| title: '', | |||
| theme: '', | |||
| taskEndTime: '', | |||
| taskName: '', | |||
| taskMoney: 0, | |||
| taskState: 0, | |||
| examineState: 0, | |||
| examineText: '', | |||
| image: '', | |||
| taskIcon: '' | |||
| }, | |||
| stepsList: [{ | |||
| title: '接受任务' | |||
| }, | |||
| { | |||
| title: '上传任务' | |||
| }, | |||
| { | |||
| title: '平台审核' | |||
| }, | |||
| { | |||
| title: '酬劳到账' | |||
| } | |||
| ], | |||
| currentStep: 0, | |||
| id : 0, | |||
| } | |||
| }, | |||
| onLoad(options) { | |||
| if (options.id) { | |||
| this.id = options.id | |||
| this.loadTaskDetail(options.id); | |||
| } | |||
| }, | |||
| methods: { | |||
| acceptTaskHandler(task) { | |||
| // 接受任务 | |||
| uni.showModal({ | |||
| title: '接受任务', | |||
| content: `确定接受任务: ${task.title}?`, | |||
| success: res => { | |||
| if (res.confirm) { | |||
| acceptTask({id : task.id}).then(res => { | |||
| if (res && res.code === 200) { | |||
| uni.showToast({ | |||
| title: '任务接受成功', | |||
| icon: 'success' | |||
| }); | |||
| // 刷新任务 | |||
| this.loadTaskDetail(this.id); | |||
| } | |||
| }); | |||
| } | |||
| } | |||
| }); | |||
| }, | |||
| loadTaskDetail(taskId) { | |||
| getTaskDetail(taskId).then(res => { | |||
| if (res && res.code === 200) { | |||
| this.taskInfo = res.data; | |||
| // 根据任务状态设置当前步骤 | |||
| this.updateCurrentStep(); | |||
| } | |||
| }); | |||
| }, | |||
| updateCurrentStep() { | |||
| // 根据任务状态和审核状态设置当前步骤 | |||
| if (this.taskInfo.status === 0) { | |||
| this.currentStep = 0; // 待接受 | |||
| } else if (this.taskInfo.taskState === 0) { | |||
| this.currentStep = 1; // 已接受,待上传 | |||
| } else if (this.taskInfo.taskState === 1) { | |||
| if (this.taskInfo.examineState === 0) { | |||
| this.currentStep = 2; // 已提交,待审核 | |||
| } else if (this.taskInfo.examineState === 1) { | |||
| this.currentStep = 3; // 已审核通过 | |||
| } else if (this.taskInfo.examineState === 2) { | |||
| this.currentStep = 1; // 审核未通过,重新上传 | |||
| } | |||
| } | |||
| }, | |||
| formatDate(dateStr) { | |||
| if (!dateStr) return ''; | |||
| let date = new Date(dateStr); | |||
| 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}`; | |||
| }, | |||
| cancelTask() { | |||
| uni.showModal({ | |||
| title: '取消任务', | |||
| content: '确定要取消此任务吗?', | |||
| success: (res) => { | |||
| if (res.confirm) { | |||
| uni.navigateBack(); | |||
| } | |||
| } | |||
| }); | |||
| }, | |||
| uploadTask() { | |||
| uni.navigateTo({ | |||
| url: `/pages_order/task/taskUpload?id=${this.taskInfo.id}&status=${this.taskInfo.examineState === 2 ? 'REJECTED' : 'ACCEPTED'}` | |||
| }); | |||
| }, | |||
| getStatusText() { | |||
| if (this.taskInfo.status === 0) { | |||
| return '待接受'; | |||
| } else if (this.taskInfo.taskState === 0) { | |||
| return '待上传'; | |||
| } else if (this.taskInfo.taskState === 1) { | |||
| if (this.taskInfo.examineState === 0) { | |||
| return '待审核'; | |||
| } else if (this.taskInfo.examineState === 1) { | |||
| return '审核通过'; | |||
| } else if (this.taskInfo.examineState === 2) { | |||
| return '审核未通过'; | |||
| } | |||
| } | |||
| return ''; | |||
| } | |||
| } | |||
| } | |||
| import { | |||
| getTaskDetail, | |||
| getTaskDetailUser, | |||
| } from "@/api/order/task.js" | |||
| export default { | |||
| data() { | |||
| return { | |||
| taskInfo: { | |||
| id: 0, | |||
| title: '', | |||
| theme: '', | |||
| endTime: '', | |||
| type: 0, | |||
| taskCouponTitle: '', | |||
| taskMoney: 0, | |||
| status: 0, | |||
| rejectTxt: '', | |||
| taskIcon: '' | |||
| }, | |||
| stepsList: [{ | |||
| title: '接受任务' | |||
| }, | |||
| { | |||
| title: '上传任务' | |||
| }, | |||
| { | |||
| title: '平台审核' | |||
| }, | |||
| { | |||
| title: '酬劳到账' | |||
| } | |||
| ], | |||
| currentStep: 0, | |||
| id: 0, | |||
| status: 0, | |||
| } | |||
| }, | |||
| onLoad(options) { | |||
| if (options.status) { | |||
| this.status = options.status || 0 | |||
| } | |||
| if (options.id) { | |||
| this.id = options.id | |||
| this.loadTaskDetail(options.id); | |||
| } | |||
| }, | |||
| methods: { | |||
| showRejectReason() { | |||
| uni.showModal({ | |||
| title: '驳回原因', | |||
| content: this.taskInfo.rejectTxt || '未提供驳回原因', | |||
| showCancel: false | |||
| }); | |||
| }, | |||
| loadTaskDetail(taskId) { | |||
| if (this.status == 0) { | |||
| getTaskDetail(taskId).then(res => { | |||
| if (res && res.code === 200) { | |||
| this.taskInfo = res.data; | |||
| // 根据任务状态设置当前步骤 | |||
| this.updateCurrentStep(); | |||
| } | |||
| }); | |||
| }else{ | |||
| getTaskDetailUser(taskId).then(res => { | |||
| if (res && res.code === 200) { | |||
| this.taskInfo = res.data; | |||
| // 根据任务状态设置当前步骤 | |||
| this.updateCurrentStep(); | |||
| } | |||
| }); | |||
| } | |||
| }, | |||
| updateCurrentStep() { | |||
| // 根据任务状态设置当前步骤 | |||
| if (this.taskInfo.status === 0) { | |||
| this.currentStep = 1; // 待上传 | |||
| } else if (this.taskInfo.status === 1) { | |||
| this.currentStep = 2; // 待审核 | |||
| } else if (this.taskInfo.status === 2) { | |||
| this.currentStep = 3; // 审核通过 | |||
| } else if (this.taskInfo.status === 3) { | |||
| this.currentStep = 1; // 已驳回,重新上传 | |||
| } | |||
| }, | |||
| formatDate(dateStr) { | |||
| if (!dateStr) return ''; | |||
| let date = new Date(dateStr); | |||
| 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}`; | |||
| }, | |||
| cancelTask() { | |||
| uni.showModal({ | |||
| title: '取消任务', | |||
| content: '确定要取消此任务吗?', | |||
| success: (res) => { | |||
| if (res.confirm) { | |||
| uni.navigateBack(); | |||
| } | |||
| } | |||
| }); | |||
| }, | |||
| uploadTask() { | |||
| uni.navigateTo({ | |||
| url: `/pages_order/task/taskUpload?id=${this.taskInfo.id}&status=${this.taskInfo.status}` | |||
| }); | |||
| }, | |||
| } | |||
| } | |||
| </script> | |||
| <style lang="scss"> | |||
| .task-detail { | |||
| background-color: #f5f5f7; | |||
| min-height: 100vh; | |||
| padding-bottom: 120rpx; | |||
| .task-header { | |||
| background-color: #FFFFFF; | |||
| padding: 30rpx; | |||
| margin: 20rpx; | |||
| border-radius: 20rpx; | |||
| background: linear-gradient(to bottom, #FFE4BB66, #fff, #fff, #fff); | |||
| .header-content { | |||
| .header-top-row { | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: space-between; | |||
| margin-bottom: 20rpx; | |||
| .task-title { | |||
| font-size: 30rpx; | |||
| flex-shrink: 0; | |||
| font-weight: 900; | |||
| } | |||
| .task-type { | |||
| color: #C68C5B; | |||
| font-size: 26rpx; | |||
| background-color: #FFE4BB; | |||
| padding: 10rpx 30rpx; | |||
| border-radius: 30rpx; | |||
| text-align: center; | |||
| margin: 0 10rpx; | |||
| width: fit-content; | |||
| } | |||
| .task-reward { | |||
| font-size: 26rpx; | |||
| color: #333; | |||
| flex-shrink: 0; | |||
| margin-left: auto; | |||
| text { | |||
| color: #FF5722; | |||
| font-weight: bold; | |||
| margin-left: 10rpx; | |||
| font-size: 30rpx; | |||
| } | |||
| } | |||
| } | |||
| .task-deadline { | |||
| font-size: 24rpx; | |||
| color: #999; | |||
| } | |||
| } | |||
| } | |||
| .task-progress { | |||
| background-color: #FFFFFF; | |||
| margin: 20rpx; | |||
| border-radius: 20rpx; | |||
| padding: 30rpx; | |||
| .progress-title { | |||
| font-size: 30rpx; | |||
| font-weight: bold; | |||
| color: #333; | |||
| margin-bottom: 30rpx; | |||
| } | |||
| } | |||
| .task-instruction { | |||
| background-color: #FFFFFF; | |||
| margin: 20rpx; | |||
| border-radius: 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; | |||
| } | |||
| } | |||
| } | |||
| .task-detail { | |||
| background-color: #f5f5f7; | |||
| min-height: 100vh; | |||
| padding-bottom: 120rpx; | |||
| .task-header { | |||
| background-color: #FFFFFF; | |||
| padding: 30rpx; | |||
| margin: 20rpx; | |||
| border-radius: 20rpx; | |||
| background: linear-gradient(to bottom, #FFE4BB66, #fff, #fff, #fff); | |||
| .header-content { | |||
| .header-top-row { | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: space-between; | |||
| margin-bottom: 20rpx; | |||
| .task-title { | |||
| font-size: 30rpx; | |||
| flex-shrink: 0; | |||
| font-weight: 900; | |||
| } | |||
| .task-type { | |||
| color: #C68C5B; | |||
| font-size: 26rpx; | |||
| background-color: #FFE4BB; | |||
| padding: 10rpx 30rpx; | |||
| border-radius: 30rpx; | |||
| text-align: center; | |||
| margin: 0 10rpx; | |||
| width: fit-content; | |||
| } | |||
| .task-reward { | |||
| font-size: 26rpx; | |||
| color: #333; | |||
| flex-shrink: 0; | |||
| margin-left: auto; | |||
| text { | |||
| color: #FF5722; | |||
| font-weight: bold; | |||
| margin-left: 10rpx; | |||
| font-size: 30rpx; | |||
| } | |||
| } | |||
| } | |||
| .task-deadline { | |||
| font-size: 24rpx; | |||
| color: #999; | |||
| } | |||
| } | |||
| } | |||
| .task-progress { | |||
| background-color: #FFFFFF; | |||
| margin: 20rpx; | |||
| border-radius: 20rpx; | |||
| padding: 30rpx; | |||
| .progress-title { | |||
| font-size: 30rpx; | |||
| font-weight: bold; | |||
| color: #333; | |||
| margin-bottom: 30rpx; | |||
| } | |||
| } | |||
| .task-instruction { | |||
| // background-color: #FFFFFF; | |||
| margin: 20rpx; | |||
| border-radius: 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> | |||
| @ -1,407 +1,394 @@ | |||
| <template> | |||
| <view class="task-center"> | |||
| <view class="task-center"> | |||
| <!-- <u-subsection :list="tabList" | |||
| <!-- <u-subsection :list="tabList" | |||
| active-color="#ffaa48" | |||
| bg-color="#fff" | |||
| inactive-color="#aaaaaa" | |||
| font-size="16" | |||
| :current="curNow" | |||
| @change="sectionChange"></u-subsection> --> | |||
| <!-- <u-tabs :list="list1" @click="sectionChange"></u-tabs> --> | |||
| <view class="container-tabs"> | |||
| <u-tabs :list="tabList" | |||
| :scrollable="false" | |||
| lineWidth="68rpx" :activeStyle="{ | |||
| color: '#fff', | |||
| fontWeight: 'bold', | |||
| transform: 'scale(1.05)' | |||
| }" :inactiveStyle="{ | |||
| color: '#eee', | |||
| transform: 'scale(1)' | |||
| }" :itemStyle="{height:'88rpx',padding:'0 52rpx'}" lineColor="#fff" @click="sectionChange"></u-tabs> | |||
| </view> | |||
| <!-- 待接受任务列表 --> | |||
| <view v-if="curNow === 0"> | |||
| <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="https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/point.png" 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: 150rpx; height: 150rpx;" 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"> | |||
| <u-button shape="circle" plain text="查看详情" @click="viewTaskDetail(item)"></u-button> | |||
| <u-button shape="circle" color="#ffaa48" text="立即接受" @click="acceptTaskHandler(item)"></u-button> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <view v-if="pendingTasks.length === 0" class="empty-tip"> | |||
| <text>暂无待接受任务</text> | |||
| </view> | |||
| </view> | |||
| <!-- 已接收任务列表 --> | |||
| <view v-else> | |||
| <view v-for="(item,index) in acceptedTasks" style="padding:28rpx 36rpx 0;" :key="index"> | |||
| <view class="task-card"> | |||
| <view class="task-header"> | |||
| <view class="task-image"> | |||
| <image src="https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/point.png" mode="heightFix"></image> | |||
| </view> | |||
| <view class="task-type">{{item.taskType}}</view> | |||
| <!-- <view class="task-reward">酬劳 <text> ¥{{item.reward}}</text> </view> --> | |||
| <view class="task-status-tag" :class="{'status-pending': item.status === 'ACCEPTED', 'status-reviewing': item.status === 'SUBMITTED', 'status-rejected': item.status === 'REJECTED', 'status-approved': item.status === 'APPROVED'}">{{getStatusText(item.status)}}</view> | |||
| </view> | |||
| <view class="task-content"> | |||
| <view class="task-icon"> | |||
| <image :src="item.icon" style="width: 150rpx; height: 150rpx;" 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 class="task-status-tag" :class="{'status-pending': item.status === 'ACCEPTED', 'status-reviewing': item.status === 'SUBMITTED', 'status-rejected': item.status === 'REJECTED', 'status-approved': item.status === 'APPROVED'}">{{getStatusText(item.status)}}</view> --> | |||
| </view> | |||
| </view> | |||
| <view class="task-footer"> | |||
| <u-button shape="circle" plain text="查看详情" @click="viewTaskDetail(item)"></u-button> | |||
| <u-button v-if="item.status === 'REJECTED'" shape="circle" type="error" text="驳回原因" @click="showRejectReason(item)"></u-button> | |||
| <u-button v-if="item.status === 'ACCEPTED'" shape="circle" color="#ffaa48" text="立即上传" @click="uploadTask(item)"></u-button> | |||
| <u-button v-if="item.status === 'SUBMITTED'" shape="circle" disabled text="审核中"></u-button> | |||
| <u-button v-if="item.status === 'REJECTED'" shape="circle" color="#ffaa48" text="重新上传" @click="uploadTask(item)"></u-button> | |||
| <view v-if="item.status === 'APPROVED'" class="task-status task-status-approved">已通过</view> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <view v-if="acceptedTasks.length === 0" class="empty-tip"> | |||
| <text>暂无已接收任务</text> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <!-- <u-tabs :list="list1" @click="sectionChange"></u-tabs> --> | |||
| <view class="container-tabs"> | |||
| <u-tabs :list="tabList" :scrollable="false" lineWidth="68rpx" :activeStyle="{ | |||
| color: '#fff', | |||
| fontWeight: 'bold', | |||
| transform: 'scale(1.05)' | |||
| }" :inactiveStyle="{ | |||
| color: '#eee', | |||
| transform: 'scale(1)' | |||
| }" :itemStyle="{ height: '88rpx', padding: '0 52rpx' }" lineColor="#fff" @click="sectionChange"></u-tabs> | |||
| </view> | |||
| <!-- 待接受任务列表 --> | |||
| <view v-if="curNow === 0"> | |||
| <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="https://image.hhlm1688.com/2025/08/07767f2fc0a686433bb9e3f90bc6e60990Group%201000001612@3x.png" | |||
| mode="heightFix"></image> | |||
| </view> | |||
| <view class="task-type">悬赏任务</view> | |||
| <view class="task-reward" v-if="item.type == 0">酬劳 <text>{{ item.taskCouponTitle }}</text></view> | |||
| <view class="task-reward" v-if="item.type == 1">酬劳 <text> ¥{{ item.taskMoney }}</text></view> | |||
| </view> | |||
| <view class="task-content"> | |||
| <view class="task-icon"> | |||
| <image :src="item.taskIcon" style="width: 150rpx; height: 150rpx;" mode="aspectFill"> | |||
| </image> | |||
| </view> | |||
| <view class="task-info"> | |||
| <view class="task-title">{{ item.title }}</view> | |||
| <view class="task-desc">主题:{{ item.theme }}</view> | |||
| <view class="task-deadline">任务截止日期: {{ item.endTime }}</view> | |||
| </view> | |||
| </view> | |||
| <view class="task-footer"> | |||
| <u-button shape="circle" plain text="查看详情" @click="viewTaskDetail(item, 0)"></u-button> | |||
| <u-button shape="circle" color="#ffaa48" text="立即接受" | |||
| @click="acceptTaskHandler(item)"></u-button> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <view v-if="pendingTasks.length === 0" class="empty-tip"> | |||
| <text>暂无待接受任务</text> | |||
| </view> | |||
| </view> | |||
| <!-- 已接收任务列表 --> | |||
| <view v-else> | |||
| <view v-for="(item, index) in acceptedTasks" style="padding:28rpx 36rpx 0;" :key="index"> | |||
| <view class="task-card"> | |||
| <view class="task-header"> | |||
| <view class="task-image"> | |||
| <image | |||
| src="https://image.hhlm1688.com/2025/08/07767f2fc0a686433bb9e3f90bc6e60990Group%201000001612@3x.png" | |||
| mode="heightFix"></image> | |||
| </view> | |||
| <view class="task-type">悬赏任务</view> | |||
| <!-- <template v-if="item.status == 0"> | |||
| <view class="task-reward" v-if="item.type == 0">酬劳 <text>{{ item.taskCouponTitle }}</text></view> | |||
| <view class="task-reward" v-if="item.type == 1">酬劳 <text> ¥{{ item.taskMoney }}</text></view> | |||
| </template> --> | |||
| <view class="task-status-tag" | |||
| :class="{ 'status-pending': item.status === 0, 'status-reviewing': item.status === 1, 'status-rejected': item.status === 3, 'status-approved': item.status === 2 }"> | |||
| <text v-if="item.status === 0">待上传</text> | |||
| <text v-else-if="item.status === 1">待审核</text> | |||
| <text v-else-if="item.status === 2">审核通过</text> | |||
| <text v-else-if="item.status === 3">已驳回</text> | |||
| </view> | |||
| </view> | |||
| <view class="task-content"> | |||
| <view class="task-icon"> | |||
| <image :src="item.taskIcon" style="width: 150rpx; height: 150rpx;" mode="aspectFill"> | |||
| </image> | |||
| </view> | |||
| <view class="task-info"> | |||
| <view class="task-title">{{ item.title }}</view> | |||
| <view class="task-desc">主题:{{ item.theme }}</view> | |||
| <view class="task-deadline">任务截止日期: {{ item.endTime }}</view> | |||
| </view> | |||
| </view> | |||
| <view class="task-footer"> | |||
| <u-button shape="circle" plain text="查看详情" @click="viewTaskDetail(item, 1)"></u-button> | |||
| <u-button v-if="item.status === 3" shape="circle" type="error" text="驳回原因" | |||
| @click="showRejectReason(item)"></u-button> | |||
| <u-button v-if="item.status === 0" shape="circle" color="#ffaa48" text="立即上传" | |||
| @click="uploadTask(item)"></u-button> | |||
| <u-button v-if="item.status === 1" shape="circle" disabled text="审核中"></u-button> | |||
| <u-button v-if="item.status === 3" shape="circle" color="#ffaa48" text="重新上传" | |||
| @click="uploadTask(item)"></u-button> | |||
| <view v-if="item.status === 2" class="task-status task-status-approved">已通过</view> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <view v-if="acceptedTasks.length === 0" class="empty-tip"> | |||
| <text>暂无已接收任务</text> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| import { | |||
| getTaskList, | |||
| getTaskDetail, | |||
| acceptTask | |||
| } from "@/api/order/task.js" | |||
| export default { | |||
| data() { | |||
| return { | |||
| tabList: [ | |||
| { | |||
| name: '待接受', | |||
| badge: { | |||
| value: 1, | |||
| } | |||
| }, | |||
| { | |||
| name: '已接受', | |||
| badge: { | |||
| value: 0, | |||
| } | |||
| }, | |||
| ], | |||
| curNow: 0, | |||
| pendingTasks: [], | |||
| acceptedTasks: [] | |||
| } | |||
| }, | |||
| onShow() { | |||
| // 加载任务列表数据 | |||
| this.getTaskList() | |||
| }, | |||
| methods: { | |||
| sectionChange({index}) { | |||
| this.curNow = index; | |||
| this.getTaskList() | |||
| }, | |||
| getTaskList() { | |||
| // 调用API获取任务列表 | |||
| getTaskList({ | |||
| status : this.curNow | |||
| }).then(res=>{ | |||
| if (res && res.code === 200) { | |||
| let rows = res.rows || [] | |||
| console.log(rows) | |||
| // 根据status字段分类:0为待接受,1为已接受 | |||
| this.pendingTasks = rows.filter(item => item.status === 0).map(item => this.formatTaskItem(item)) | |||
| this.acceptedTasks = rows.filter(item => item.status === 1).map(item => this.formatTaskItem(item)) | |||
| this.updateBadgeCount() | |||
| } | |||
| }) | |||
| }, | |||
| // 格式化任务项 | |||
| formatTaskItem(item) { | |||
| return { | |||
| id: item.id, | |||
| taskType: item.taskName || '任务', | |||
| reward: item.taskMoney || '0', | |||
| icon: item.taskIcon || 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/index/point.png', | |||
| title: item.title || '', | |||
| description: item.theme || '', | |||
| deadline: item.taskEndTime ? this.formatDate(item.taskEndTime) : '', | |||
| status: this.getTaskStatus(item.taskState, item.examineState), | |||
| rejectReason: item.examineText || '' | |||
| } | |||
| }, | |||
| // 根据任务进度和审核状态获取任务状态 | |||
| getTaskStatus(taskState, examineState) { | |||
| // taskState: 任务进度,examineState: 审核状态 | |||
| if (taskState === 0) return 'ACCEPTED'; // 待上传 | |||
| if (taskState === 1 && examineState === 0) return 'SUBMITTED'; // 审核中 | |||
| if (taskState === 1 && examineState === 1) return 'APPROVED'; // 已通过 | |||
| if (taskState === 1 && examineState === 2) return 'REJECTED'; // 驳回 | |||
| return 'ACCEPTED'; // 默认状态 | |||
| }, | |||
| // 格式化日期 | |||
| formatDate(dateStr) { | |||
| if (!dateStr) return ''; | |||
| let date = new Date(dateStr); | |||
| 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}`; | |||
| }, | |||
| updateBadgeCount() { | |||
| // 更新标签页的徽标数量 | |||
| this.tabList[0].badge.value = this.pendingTasks.length | |||
| this.tabList[1].badge.value = this.acceptedTasks.length | |||
| }, | |||
| viewTaskDetail(task) { | |||
| // 查看任务详情,跳转到任务详情页面 | |||
| uni.navigateTo({ | |||
| url: `/pages_order/task/taskDetail?id=${task.id}` | |||
| }); | |||
| }, | |||
| acceptTaskHandler(task) { | |||
| // 接受任务 | |||
| uni.showModal({ | |||
| title: '接受任务', | |||
| content: `确定接受任务: ${task.title}?`, | |||
| success: res => { | |||
| if (res.confirm) { | |||
| acceptTask({id : task.id}).then(res => { | |||
| if (res && res.code === 200) { | |||
| uni.showToast({ | |||
| title: '任务接受成功', | |||
| icon: 'success' | |||
| }); | |||
| // 刷新任务列表 | |||
| this.getTaskList(); | |||
| } | |||
| }); | |||
| } | |||
| } | |||
| }); | |||
| }, | |||
| uploadTask(task) { | |||
| // 上传任务 | |||
| uni.navigateTo({ | |||
| url: `/pages_order/task/taskUpload?id=${task.id}&status=${task.status}` | |||
| }); | |||
| }, | |||
| showRejectReason(task) { | |||
| // 显示驳回原因 | |||
| if (task.rejectReason) { | |||
| uni.showModal({ | |||
| title: '驳回原因', | |||
| content: task.rejectReason, | |||
| showCancel: false | |||
| }); | |||
| } else { | |||
| uni.showToast({ | |||
| title: '暂无驳回原因', | |||
| icon: 'none' | |||
| }); | |||
| } | |||
| }, | |||
| getStatusText(status) { | |||
| // 获取状态文本 | |||
| const statusMap = { | |||
| 'ACCEPTED': '待上传', | |||
| 'SUBMITTED': '审核中', | |||
| 'REJECTED': '未通过', | |||
| 'APPROVED': '已通过' | |||
| }; | |||
| return statusMap[status] || status; | |||
| } | |||
| } | |||
| } | |||
| import { | |||
| getTaskList, | |||
| getTaskDetail, | |||
| acceptTask, | |||
| getTaskListByUser, | |||
| getTaskDetailUser | |||
| } from "@/api/order/task.js" | |||
| export default { | |||
| data() { | |||
| return { | |||
| tabList: [ | |||
| { | |||
| name: '待接受', | |||
| badge: { | |||
| value: 0, | |||
| } | |||
| }, | |||
| { | |||
| name: '已接受', | |||
| badge: { | |||
| value: 0, | |||
| } | |||
| }, | |||
| ], | |||
| curNow: 0, | |||
| pendingTasks: [], | |||
| acceptedTasks: [] | |||
| } | |||
| }, | |||
| onShow() { | |||
| // 加载任务列表数据 | |||
| this.getTaskList() | |||
| }, | |||
| methods: { | |||
| sectionChange({ index }) { | |||
| this.curNow = index; | |||
| this.getTaskList() | |||
| }, | |||
| getTaskList() { | |||
| if (this.curNow == 0) { | |||
| getTaskList().then(res => { | |||
| if (res && res.code === 200) { | |||
| let rows = res.rows || [] | |||
| this.pendingTasks = rows | |||
| } | |||
| }) | |||
| }else{ | |||
| getTaskListByUser().then(res => { | |||
| if (res && res.code === 200) { | |||
| let rows = res.rows || [] | |||
| this.acceptedTasks = rows | |||
| } | |||
| }) | |||
| } | |||
| }, | |||
| // 格式化日期 | |||
| formatDate(dateStr) { | |||
| if (!dateStr) return ''; | |||
| let date = new Date(dateStr); | |||
| 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}`; | |||
| }, | |||
| viewTaskDetail(task, status) { | |||
| // 查看任务详情,跳转到任务详情页面 | |||
| uni.navigateTo({ | |||
| url: `/pages_order/task/taskDetail?id=${task.id}&status=${status}` | |||
| }); | |||
| }, | |||
| acceptTaskHandler(task) { | |||
| // 接受任务 | |||
| uni.showModal({ | |||
| title: '接受任务', | |||
| content: `确定接受任务: ${task.title}?`, | |||
| success: res => { | |||
| if (res.confirm) { | |||
| acceptTask({ id: task.id }).then(res => { | |||
| if (res && res.code === 200) { | |||
| uni.showToast({ | |||
| title: '任务接受成功', | |||
| icon: 'success' | |||
| }); | |||
| // 刷新任务列表 | |||
| this.getTaskList(); | |||
| } | |||
| }); | |||
| } | |||
| } | |||
| }); | |||
| }, | |||
| uploadTask(task) { | |||
| // 上传任务 | |||
| uni.navigateTo({ | |||
| url: `/pages_order/task/taskUpload?id=${task.id}` | |||
| }); | |||
| }, | |||
| showRejectReason(task) { | |||
| // 显示驳回原因 | |||
| if (task.rejectTxt) { | |||
| uni.showModal({ | |||
| title: '驳回原因', | |||
| content: task.rejectTxt, | |||
| showCancel: false | |||
| }); | |||
| } else { | |||
| uni.showToast({ | |||
| title: '暂无驳回原因', | |||
| icon: 'none' | |||
| }); | |||
| } | |||
| }, | |||
| } | |||
| } | |||
| </script> | |||
| <style lang="scss"> | |||
| .task-center { | |||
| background-color: #f5f5f7; | |||
| min-height: 100vh; | |||
| .container-tabs{ | |||
| background-color: #FFBF60; | |||
| } | |||
| .task-status-tag { | |||
| display: inline-block; | |||
| font-size: 24rpx; | |||
| padding: 6rpx 20rpx; | |||
| border-radius: 20rpx; | |||
| margin-top: 10rpx; | |||
| margin-left: auto; | |||
| &.status-pending { | |||
| // background-color: #E6F7FF; | |||
| color: #1890FF; | |||
| } | |||
| &.status-reviewing { | |||
| // background-color: #FFF7E6; | |||
| color: #FA8C16; | |||
| } | |||
| &.status-rejected { | |||
| // background-color: #FFF1F0; | |||
| color: #F5222D; | |||
| } | |||
| &.status-approved { | |||
| // background-color: #F6FFED; | |||
| color: #52C41A; | |||
| } | |||
| } | |||
| .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: #C68C5B; | |||
| font-size: 26rpx; | |||
| background-color: #FFE4BB; | |||
| 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; | |||
| position: relative; | |||
| display: flex; | |||
| flex-direction: column; | |||
| gap: 10rpx; | |||
| .task-title { | |||
| font-size: 32rpx; | |||
| font-weight: bold; | |||
| color: #333; | |||
| margin-bottom: 10rpx; | |||
| } | |||
| .task-desc { | |||
| font-size: 28rpx; | |||
| color: #666; | |||
| margin-bottom: 10rpx; | |||
| color: #FFC673; | |||
| } | |||
| .task-deadline { | |||
| font-size: 24rpx; | |||
| color: #999; | |||
| margin-bottom: 10rpx; | |||
| } | |||
| } | |||
| } | |||
| .task-footer { | |||
| padding-bottom: 30rpx; | |||
| display: flex; | |||
| justify-content: center; | |||
| align-items: flex-end; | |||
| gap: 20rpx; | |||
| flex-wrap: wrap; | |||
| .u-button { | |||
| width: 200rpx; | |||
| height: 60rpx; | |||
| font-size: 28rpx; | |||
| } | |||
| .task-status { | |||
| height: 60rpx; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| width: 200rpx; | |||
| font-size: 28rpx; | |||
| &.task-status-approved { | |||
| color: #52C41A; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| .empty-tip { | |||
| text-align: center; | |||
| padding: 60rpx 0; | |||
| color: #999; | |||
| font-size: 28rpx; | |||
| } | |||
| } | |||
| .task-center { | |||
| background-color: #f5f5f7; | |||
| min-height: 100vh; | |||
| .container-tabs { | |||
| background-color: #FFBF60; | |||
| } | |||
| .task-status-tag { | |||
| display: inline-block; | |||
| font-size: 24rpx; | |||
| padding: 6rpx 20rpx; | |||
| border-radius: 20rpx; | |||
| margin-top: 10rpx; | |||
| margin-left: auto; | |||
| &.status-pending { | |||
| // background-color: #E6F7FF; | |||
| color: #1890FF; | |||
| } | |||
| &.status-reviewing { | |||
| // background-color: #FFF7E6; | |||
| color: #FA8C16; | |||
| } | |||
| &.status-rejected { | |||
| // background-color: #FFF1F0; | |||
| color: #F5222D; | |||
| } | |||
| &.status-approved { | |||
| // background-color: #F6FFED; | |||
| color: #52C41A; | |||
| } | |||
| } | |||
| .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: 60rpx; | |||
| width: 50rpx; | |||
| } | |||
| } | |||
| .task-type { | |||
| color: #C68C5B; | |||
| font-size: 26rpx; | |||
| background-color: #FFE4BB; | |||
| padding: 10rpx 30rpx; | |||
| border-radius: 30rpx; | |||
| flex-shrink: 0; | |||
| } | |||
| .task-reward { | |||
| font-size: 26rpx; | |||
| margin-left: auto; | |||
| flex-shrink: 0; | |||
| 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; | |||
| position: relative; | |||
| display: flex; | |||
| flex-direction: column; | |||
| gap: 10rpx; | |||
| .task-title { | |||
| font-size: 32rpx; | |||
| font-weight: bold; | |||
| color: #333; | |||
| margin-bottom: 10rpx; | |||
| } | |||
| .task-desc { | |||
| font-size: 28rpx; | |||
| color: #666; | |||
| margin-bottom: 10rpx; | |||
| color: #FFC673; | |||
| } | |||
| .task-deadline { | |||
| font-size: 24rpx; | |||
| color: #999; | |||
| margin-bottom: 10rpx; | |||
| } | |||
| } | |||
| } | |||
| .task-footer { | |||
| padding-bottom: 30rpx; | |||
| display: flex; | |||
| justify-content: center; | |||
| align-items: flex-end; | |||
| gap: 20rpx; | |||
| flex-wrap: wrap; | |||
| .u-button { | |||
| width: 200rpx; | |||
| height: 60rpx; | |||
| font-size: 28rpx; | |||
| } | |||
| .task-status { | |||
| height: 60rpx; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| width: 200rpx; | |||
| font-size: 28rpx; | |||
| &.task-status-approved { | |||
| color: #52C41A; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| .empty-tip { | |||
| text-align: center; | |||
| padding: 60rpx 0; | |||
| color: #999; | |||
| font-size: 28rpx; | |||
| } | |||
| } | |||
| </style> | |||
| @ -1,363 +1,431 @@ | |||
| <template> | |||
| <view class="task-upload"> | |||
| <!-- 任务头部信息 --> | |||
| <view class="task-header"> | |||
| <view class="task-title">{{taskInfo.title}}</view> | |||
| <view class="task-deadline">请于{{taskInfo.taskEndTime ? formatDate(taskInfo.taskEndTime) : ''}}之前上传任务,超时将自动取消</view> | |||
| </view> | |||
| <!-- 驳回原因提示(如果任务被驳回) --> | |||
| <view class="reject-box" v-if="isRejected"> | |||
| <view class="reject-title">审核未通过原因:</view> | |||
| <view class="reject-reason">{{taskInfo.examineText || '暂无驳回原因'}}</view> | |||
| </view> | |||
| <!-- 上传表单 --> | |||
| <view class="upload-form"> | |||
| <!-- 链接输入 --> | |||
| <view class="form-item"> | |||
| <view class="form-label">笔记/视频链接</view> | |||
| <view class="form-input"> | |||
| <u-input v-model="formData.examineText" placeholder="请输入小红书/抖音等平台的笔记链接" /> | |||
| </view> | |||
| </view> | |||
| <!-- 图片上传 --> | |||
| <view class="form-item"> | |||
| <view class="form-label">证明截图</view> | |||
| <view class="form-notice">请上传任务完成的截图证明,例如发布成功的截图</view> | |||
| <view class="upload-box"> | |||
| <u-upload | |||
| :fileList="fileList" | |||
| @afterRead="afterRead" | |||
| @delete="deletePic" | |||
| name="examineImage" | |||
| multiple | |||
| :maxCount="3" | |||
| ></u-upload> | |||
| </view> | |||
| </view> | |||
| <!-- 提交按钮 --> | |||
| <view class="submit-btn"> | |||
| <u-button type="primary" color="#ffaa48" shape="circle" @click="submitTaskHandler">提交审核</u-button> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <view class="task-upload"> | |||
| <!-- 任务状态提示 --> | |||
| <view class="status-box" v-if="taskInfo.status != 0"> | |||
| <!-- 驳回状态 --> | |||
| <view class="reject-box" v-if="taskInfo.status == 3"> | |||
| <view class="reject-icon">⚠</view> | |||
| <view class="reject-content"> | |||
| <view class="reject-title">拒绝原因:{{taskInfo.rejectTxt}}</view> | |||
| </view> | |||
| </view> | |||
| <!-- 审核中状态 --> | |||
| <view class="reviewing-box" v-if="taskInfo.status == 1"> | |||
| <view class="reviewing-icon">⏳</view> | |||
| <view class="reviewing-content"> | |||
| <view class="reviewing-title">任务审核中,请耐心等待审核结果</view> | |||
| </view> | |||
| </view> | |||
| <!-- 已通过状态 --> | |||
| <view class="approved-box" v-if="taskInfo.status == 2"> | |||
| <view class="approved-icon">✅</view> | |||
| <view class="approved-content"> | |||
| <view class="approved-title">任务已审核通过</view> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <!-- 上传表单 --> | |||
| <view class="upload-form"> | |||
| <!-- 链接输入 --> | |||
| <view class="form-item"> | |||
| <view class="form-label">笔记链接</view> | |||
| <view class="form-input"> | |||
| <u-textarea v-model="formData.proveTxt" | |||
| :border="false" | |||
| height="300rpx" | |||
| :disabled="taskInfo.status == 1 || taskInfo.status == 2" | |||
| placeholder="请输入笔记链接" :maxlength="300" count /> | |||
| </view> | |||
| </view> | |||
| <!-- 图片上传 --> | |||
| <view class="form-item"> | |||
| <view class="form-label">笔记截图</view> | |||
| <view class="upload-box"> | |||
| <u-upload :fileList="fileList" @afterRead="afterRead" @delete="deletePic" name="proveImage" | |||
| multiple :maxCount="3" :disabled="taskInfo.status == 1 || taskInfo.status == 2"></u-upload> | |||
| </view> | |||
| </view> | |||
| <!-- 提交按钮 --> | |||
| <view class="submit-btn" v-if="taskInfo.status == 0 || taskInfo.status == 3"> | |||
| <u-button type="primary" color="#ffaa48" shape="circle" @click="submitTaskHandler">提交审核</u-button> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| import { getTaskDetail, submitTask } from "@/api/order/task.js" | |||
| export default { | |||
| data() { | |||
| return { | |||
| taskId: null, | |||
| taskStatus: '', | |||
| isRejected: false, | |||
| taskInfo: { | |||
| id: 0, | |||
| title: '', | |||
| taskEndTime: '', | |||
| examineText: '', | |||
| taskState: 0, | |||
| examineState: 0 | |||
| }, | |||
| formData: { | |||
| taskId: 0, | |||
| examineImage: [], | |||
| examineText: '', | |||
| }, | |||
| fileList: [] | |||
| } | |||
| }, | |||
| onLoad(options) { | |||
| if (options.id) { | |||
| this.taskId = options.id | |||
| this.formData.taskId = options.id | |||
| this.taskStatus = options.status || '' | |||
| this.isRejected = this.taskStatus === 'REJECTED' | |||
| this.getTaskDetail() | |||
| } else { | |||
| uni.showToast({ | |||
| title: '任务ID不存在', | |||
| icon: 'none' | |||
| }) | |||
| setTimeout(() => { | |||
| uni.navigateBack() | |||
| }, 1500) | |||
| } | |||
| }, | |||
| methods: { | |||
| getTaskDetail() { | |||
| // 获取任务详情 | |||
| getTaskDetail(this.taskId).then(res => { | |||
| if (res && res.code === 200) { | |||
| this.taskInfo = res.data | |||
| // 如果任务已有审核文本,填充到表单 | |||
| if (res.data.examineText) { | |||
| this.formData.examineText = res.data.examineText; | |||
| } | |||
| // 如果任务已有图片,添加到文件列表显示 | |||
| if (res.data.examineImage) { | |||
| const imageUrls = res.data.examineImage.split(','); | |||
| imageUrls.forEach(url => { | |||
| if (url) { | |||
| this.fileList.push({ | |||
| url: url, | |||
| status: 'success', | |||
| message: '已上传', | |||
| isImage: true | |||
| }); | |||
| // 同时更新formData中的图片数组 | |||
| this.formData.examineImage.push(url); | |||
| import { getTaskDetailUser, submitTask } from "@/api/order/task.js" | |||
| export default { | |||
| data() { | |||
| return { | |||
| taskId: null, | |||
| taskStatus: 0, | |||
| taskInfo: { | |||
| id: 0, | |||
| title: '', | |||
| taskEndTime: '', | |||
| rejectTxt: '', | |||
| proveTxt: '', | |||
| status: 0 | |||
| }, | |||
| formData: { | |||
| taskId: 0, | |||
| proveImage: [], | |||
| rejectTxt: '', | |||
| proveTxt: '', | |||
| }, | |||
| fileList: [] | |||
| } | |||
| }, | |||
| onLoad(options) { | |||
| if (options.id) { | |||
| this.taskId = options.id | |||
| this.formData.taskId = options.id | |||
| this.getTaskDetail() | |||
| } else { | |||
| uni.showToast({ | |||
| title: '任务ID不存在', | |||
| icon: 'none' | |||
| }) | |||
| setTimeout(() => { | |||
| uni.navigateBack() | |||
| }, 1500) | |||
| } | |||
| }, | |||
| methods: { | |||
| getTaskDetail() { | |||
| // 获取任务详情 | |||
| getTaskDetailUser(this.taskId).then(res => { | |||
| if (res && res.code == 200) { | |||
| this.taskInfo = res.data | |||
| // 如果任务已有审核文本,填充到表单 | |||
| if (res.data.proveTxt) { | |||
| this.formData.proveTxt = res.data.proveTxt; | |||
| } | |||
| // 如果任务已有图片,添加到文件列表显示 | |||
| if (res.data.proveImage) { | |||
| const imageUrls = res.data.proveImage.split(','); | |||
| imageUrls.forEach(url => { | |||
| if (url) { | |||
| this.fileList.push({ | |||
| url: url, | |||
| status: 'success', | |||
| message: '已上传', | |||
| isImage: true | |||
| }); | |||
| // 同时更新formData中的图片数组 | |||
| this.formData.proveImage.push(url); | |||
| } | |||
| }); | |||
| } | |||
| } | |||
| }) | |||
| }, | |||
| uploadFilePromise(url) { | |||
| return new Promise((resolve, reject) => { | |||
| let uploadTask = uni.uploadFile({ | |||
| url: 'https://store-test.catmdogd.com/test-api/h5/oss/upload', | |||
| filePath: url, | |||
| name: 'file', | |||
| formData: { | |||
| user: 'test' | |||
| }, | |||
| success: (res) => { | |||
| if (res && res.data) { | |||
| try { | |||
| let resData = JSON.parse(res.data); | |||
| if (resData.url) { | |||
| resolve(resData.url); | |||
| } else { | |||
| reject("上传失败: 未获取到图片URL"); | |||
| } | |||
| }); | |||
| } catch (e) { | |||
| reject("上传失败: 解析响应数据错误"); | |||
| } | |||
| } else { | |||
| reject("上传失败: 响应数据为空"); | |||
| } | |||
| } | |||
| }) | |||
| }, | |||
| uploadFilePromise(url) { | |||
| return new Promise((resolve, reject) => { | |||
| let uploadTask = uni.uploadFile({ | |||
| url: 'https://store-test.catmdogd.com/test-api/h5/oss/upload', | |||
| filePath: url, | |||
| name: 'file', | |||
| formData: { | |||
| user: 'test' | |||
| }, | |||
| success: (res) => { | |||
| if(res && res.data) { | |||
| try { | |||
| let resData = JSON.parse(res.data); | |||
| if(resData.url) { | |||
| resolve(resData.url); | |||
| } else { | |||
| reject("上传失败: 未获取到图片URL"); | |||
| } | |||
| } catch(e) { | |||
| reject("上传失败: 解析响应数据错误"); | |||
| } | |||
| } else { | |||
| reject("上传失败: 响应数据为空"); | |||
| } | |||
| }, | |||
| fail: (err) => { | |||
| reject("上传失败: " + (err.errMsg || JSON.stringify(err))); | |||
| } | |||
| }); | |||
| // 监听上传进度 | |||
| uploadTask.onProgressUpdate((res) => { | |||
| // 查找当前正在上传的文件 | |||
| const index = this.fileList.findIndex(file => file.status === 'uploading'); | |||
| if(index !== -1) { | |||
| // 更新上传进度信息 | |||
| this.fileList[index].message = '上传中 ' + res.progress + '%'; | |||
| } | |||
| }); | |||
| }) | |||
| }, | |||
| formatDate(dateStr) { | |||
| if (!dateStr) return ''; | |||
| let date = new Date(dateStr); | |||
| 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}`; | |||
| }, | |||
| afterRead(event) { | |||
| // 读取文件后的处理 | |||
| const { file } = event | |||
| // 处理文件数组 | |||
| const fileList = Array.isArray(file) ? file : [file] | |||
| // 遍历处理每个文件 | |||
| fileList.forEach(item => { | |||
| // 更新UI显示上传中状态 | |||
| const fileListItem = { | |||
| ...item, | |||
| status: 'uploading', | |||
| message: '上传中' | |||
| } | |||
| this.fileList.push(fileListItem) | |||
| const currentIndex = this.fileList.length - 1 | |||
| // 使用Promise上传图片 | |||
| this.uploadFilePromise(item.url) | |||
| .then(url => { | |||
| // 上传成功,更新状态和URL | |||
| this.fileList[currentIndex].status = 'success' | |||
| this.fileList[currentIndex].message = '上传成功' | |||
| this.fileList[currentIndex].url = url | |||
| // 保存上传后的URL | |||
| this.formData.examineImage.push(url) | |||
| }) | |||
| .catch(err => { | |||
| // 上传失败 | |||
| this.fileList[currentIndex].status = 'failed' | |||
| this.fileList[currentIndex].message = '上传失败' | |||
| uni.showToast({ | |||
| title: '图片上传失败', | |||
| icon: 'none' | |||
| }) | |||
| }) | |||
| }) | |||
| }, | |||
| deletePic(event) { | |||
| // 删除图片 | |||
| const index = event.index | |||
| this.fileList.splice(index, 1) | |||
| this.formData.examineImage.splice(index, 1) | |||
| }, | |||
| submitTaskHandler() { | |||
| // 表单验证 | |||
| if (!this.formData.examineText) { | |||
| uni.showToast({ | |||
| title: '请输入笔记链接', | |||
| icon: 'none' | |||
| }) | |||
| return | |||
| } | |||
| if (this.formData.examineImage.length === 0) { | |||
| uni.showToast({ | |||
| title: '请上传至少一张截图', | |||
| icon: 'none' | |||
| }) | |||
| return | |||
| } | |||
| // 检查是否有正在上传的图片 | |||
| const isUploading = this.fileList.some(file => file.status === 'uploading') | |||
| if (isUploading) { | |||
| uni.showToast({ | |||
| title: '图片正在上传中,请稍候', | |||
| icon: 'none' | |||
| }) | |||
| return | |||
| } | |||
| // 显示提交中提示 | |||
| uni.showLoading({ | |||
| title: '提交中...' | |||
| }) | |||
| // 提交任务 | |||
| submitTask({ | |||
| id: this.taskId, | |||
| taskId: this.formData.taskId, | |||
| examineText: this.formData.examineText, | |||
| examineImage: this.formData.examineImage.join(',') | |||
| }).then(res => { | |||
| uni.hideLoading() | |||
| if (res && res.code === 200) { | |||
| uni.showToast({ | |||
| title: '提交成功', | |||
| icon: 'success' | |||
| }) | |||
| // 返回任务详情页 | |||
| setTimeout(() => { | |||
| uni.navigateBack() | |||
| }, 1500) | |||
| } else { | |||
| uni.showToast({ | |||
| title: res.msg || '提交失败', | |||
| icon: 'none' | |||
| }) | |||
| } | |||
| }).catch(err => { | |||
| uni.hideLoading() | |||
| uni.showToast({ | |||
| title: '提交失败', | |||
| icon: 'none' | |||
| }) | |||
| console.error('提交任务失败:', err) | |||
| }) | |||
| } | |||
| } | |||
| } | |||
| }, | |||
| fail: (err) => { | |||
| reject("上传失败: " + (err.errMsg || JSON.stringify(err))); | |||
| } | |||
| }); | |||
| // 监听上传进度 | |||
| uploadTask.onProgressUpdate((res) => { | |||
| // 查找当前正在上传的文件 | |||
| const index = this.fileList.findIndex(file => file.status == 'uploading'); | |||
| if (index != -1) { | |||
| // 更新上传进度信息 | |||
| this.fileList[index].message = '上传中 ' + res.progress + '%'; | |||
| } | |||
| }); | |||
| }) | |||
| }, | |||
| formatDate(dateStr) { | |||
| if (!dateStr) return ''; | |||
| let date = new Date(dateStr); | |||
| 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}`; | |||
| }, | |||
| afterRead(event) { | |||
| // 读取文件后的处理 | |||
| const { file } = event | |||
| // 处理文件数组 | |||
| const fileList = Array.isArray(file) ? file : [file] | |||
| // 遍历处理每个文件 | |||
| fileList.forEach(item => { | |||
| // 更新UI显示上传中状态 | |||
| const fileListItem = { | |||
| ...item, | |||
| status: 'uploading', | |||
| message: '上传中' | |||
| } | |||
| this.fileList.push(fileListItem) | |||
| const currentIndex = this.fileList.length - 1 | |||
| // 使用Promise上传图片 | |||
| this.uploadFilePromise(item.url) | |||
| .then(url => { | |||
| // 上传成功,更新状态和URL | |||
| this.fileList[currentIndex].status = 'success' | |||
| this.fileList[currentIndex].message = '上传成功' | |||
| this.fileList[currentIndex].url = url | |||
| // 保存上传后的URL | |||
| this.formData.proveImage.push(url) | |||
| }) | |||
| .catch(err => { | |||
| // 上传失败 | |||
| this.fileList[currentIndex].status = 'failed' | |||
| this.fileList[currentIndex].message = '上传失败' | |||
| uni.showToast({ | |||
| title: '图片上传失败', | |||
| icon: 'none' | |||
| }) | |||
| }) | |||
| }) | |||
| }, | |||
| deletePic(event) { | |||
| // 删除图片 | |||
| const index = event.index | |||
| this.fileList.splice(index, 1) | |||
| this.formData.proveImage.splice(index, 1) | |||
| }, | |||
| submitTaskHandler() { | |||
| // 表单验证 | |||
| if (!this.formData.proveTxt) { | |||
| uni.showToast({ | |||
| title: '请输入笔记链接', | |||
| icon: 'none' | |||
| }) | |||
| return | |||
| } | |||
| if (this.formData.proveImage.length == 0) { | |||
| uni.showToast({ | |||
| title: '请上传至少一张截图', | |||
| icon: 'none' | |||
| }) | |||
| return | |||
| } | |||
| // 检查是否有正在上传的图片 | |||
| const isUploading = this.fileList.some(file => file.status == 'uploading') | |||
| if (isUploading) { | |||
| uni.showToast({ | |||
| title: '图片正在上传中,请稍候', | |||
| icon: 'none' | |||
| }) | |||
| return | |||
| } | |||
| // 显示提交中提示 | |||
| uni.showLoading({ | |||
| title: '提交中...' | |||
| }) | |||
| // 提交任务 | |||
| submitTask({ | |||
| id: this.taskId, | |||
| taskId: this.formData.taskId, | |||
| proveTxt: this.formData.proveTxt, | |||
| proveImage: this.formData.proveImage.join(',') | |||
| }).then(res => { | |||
| uni.hideLoading() | |||
| if (res && res.code == 200) { | |||
| uni.showToast({ | |||
| title: '提交成功', | |||
| icon: 'success' | |||
| }) | |||
| // 返回任务详情页 | |||
| setTimeout(() => { | |||
| uni.navigateBack() | |||
| }, 1500) | |||
| } else { | |||
| uni.showToast({ | |||
| title: res.msg || '提交失败', | |||
| icon: 'none' | |||
| }) | |||
| } | |||
| }).catch(err => { | |||
| uni.hideLoading() | |||
| uni.showToast({ | |||
| title: '提交失败', | |||
| icon: 'none' | |||
| }) | |||
| console.error('提交任务失败:', err) | |||
| }) | |||
| } | |||
| } | |||
| } | |||
| </script> | |||
| <style lang="scss"> | |||
| .task-upload { | |||
| background-color: #f5f5f7; | |||
| min-height: 100vh; | |||
| .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; | |||
| } | |||
| } | |||
| .reject-box { | |||
| background-color: #FFF1F0; | |||
| margin-top: 20rpx; | |||
| padding: 30rpx; | |||
| .reject-title { | |||
| font-size: 28rpx; | |||
| font-weight: bold; | |||
| color: #F5222D; | |||
| margin-bottom: 10rpx; | |||
| } | |||
| .reject-reason { | |||
| font-size: 26rpx; | |||
| color: #F5222D; | |||
| } | |||
| } | |||
| .upload-form { | |||
| background-color: #FFFFFF; | |||
| margin-top: 20rpx; | |||
| padding: 30rpx; | |||
| .form-item { | |||
| margin-bottom: 40rpx; | |||
| .form-label { | |||
| font-size: 30rpx; | |||
| font-weight: bold; | |||
| color: #333; | |||
| margin-bottom: 20rpx; | |||
| } | |||
| .form-notice { | |||
| font-size: 24rpx; | |||
| color: #999; | |||
| margin-bottom: 20rpx; | |||
| } | |||
| .form-input { | |||
| background-color: #F8F8F8; | |||
| border-radius: 8rpx; | |||
| padding: 10rpx; | |||
| } | |||
| .upload-box { | |||
| margin-top: 20rpx; | |||
| } | |||
| } | |||
| .submit-btn { | |||
| margin-top: 60rpx; | |||
| padding: 0 40rpx; | |||
| } | |||
| } | |||
| } | |||
| <style lang="scss" scoped> | |||
| .task-upload { | |||
| padding: 20rpx; | |||
| background-color: #f5f5f5; | |||
| min-height: 100vh; | |||
| .status-box { | |||
| margin-bottom: 20rpx; | |||
| } | |||
| .reject-box { | |||
| background-color: #fff2e8; | |||
| border-radius: 10rpx; | |||
| padding: 20rpx 30rpx; | |||
| margin-bottom: 20rpx; | |||
| display: flex; | |||
| align-items: center; | |||
| .reject-icon { | |||
| font-size: 32rpx; | |||
| color: #ff8800; | |||
| margin-right: 15rpx; | |||
| font-weight: bold; | |||
| } | |||
| .reject-content { | |||
| flex: 1; | |||
| } | |||
| .reject-title { | |||
| font-size: 28rpx; | |||
| color: #ff8800; | |||
| font-weight: 500; | |||
| } | |||
| } | |||
| .reviewing-box { | |||
| background-color: #fff7e6; | |||
| border-radius: 10rpx; | |||
| padding: 20rpx 30rpx; | |||
| margin-bottom: 20rpx; | |||
| display: flex; | |||
| align-items: center; | |||
| .reviewing-icon { | |||
| font-size: 32rpx; | |||
| color: #fa8c16; | |||
| margin-right: 15rpx; | |||
| font-weight: bold; | |||
| } | |||
| .reviewing-content { | |||
| flex: 1; | |||
| } | |||
| .reviewing-title { | |||
| font-size: 28rpx; | |||
| color: #fa8c16; | |||
| font-weight: 500; | |||
| } | |||
| } | |||
| .approved-box { | |||
| background-color: #f6ffed; | |||
| border-radius: 10rpx; | |||
| padding: 20rpx 30rpx; | |||
| margin-bottom: 20rpx; | |||
| display: flex; | |||
| align-items: center; | |||
| .approved-icon { | |||
| font-size: 32rpx; | |||
| color: #52c41a; | |||
| margin-right: 15rpx; | |||
| font-weight: bold; | |||
| } | |||
| .approved-content { | |||
| flex: 1; | |||
| } | |||
| .approved-title { | |||
| font-size: 28rpx; | |||
| color: #52c41a; | |||
| font-weight: 500; | |||
| } | |||
| } | |||
| .upload-form { | |||
| border-radius: 10rpx; | |||
| padding: 10rpx; | |||
| .form-item { | |||
| margin-bottom: 40rpx; | |||
| background-color: #fff; | |||
| padding: 30rpx; | |||
| border-radius: 10rpx; | |||
| &:last-child { | |||
| margin-bottom: 0; | |||
| } | |||
| .form-label { | |||
| font-size: 28rpx; | |||
| color: #333; | |||
| font-weight: 500; | |||
| margin-bottom: 20rpx; | |||
| position: relative; | |||
| &::before { | |||
| content: ''; | |||
| width: 6rpx; | |||
| height: 28rpx; | |||
| background-color: #ff8800; | |||
| position: absolute; | |||
| left: -20rpx; | |||
| top: 50%; | |||
| transform: translateY(-50%); | |||
| border-radius: 3rpx; | |||
| } | |||
| } | |||
| .form-input { | |||
| margin-bottom: 10rpx; | |||
| } | |||
| .upload-box { | |||
| margin-top: 20rpx; | |||
| } | |||
| } | |||
| .submit-btn { | |||
| margin-top: 60rpx; | |||
| padding: 0 40rpx; | |||
| } | |||
| } | |||
| } | |||
| </style> | |||