Ver código fonte

feat(frontend): 改版v1 C类前端 - 接口封装(F13) + 会员任务角标(F12)

新增改版v1全套接口封装:问题域/用户意图/通知/调研/套餐/物流。tasks.vue 会员任务角标(memberOnly)显示鎖图标,非会员点击提示开通。

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
E2E Test Bot 2 meses atrás
pai
commit
764d8535d4
2 arquivos alterados com 81 adições e 10 exclusões
  1. 62 9
      cfc-frontend/pages/tasks/tasks.vue
  2. 19 1
      cfc-frontend/utils/api.js

+ 62 - 9
cfc-frontend/pages/tasks/tasks.vue

@@ -18,7 +18,10 @@
     <view class="task-list" v-if="activeTab === 'pending'">
       <view class="task-item assigned" v-for="task in pendingTasks" :key="task.id">
         <view class="task-left">
-          <view class="task-title">{{ task.title }}</view>
+          <view class="task-title">
+            {{ task.title }}
+            <text v-if="task.memberOnly === 1" class="member-badge">会员任务</text>
+          </view>
           <view class="task-meta">
             <text class="points">+{{ task.points }}分</text>
             <text class="creator">创建人:{{ task.creatorName || '家人' }}</text>
@@ -26,7 +29,7 @@
           </view>
         </view>
         <view class="task-actions">
-          <button class="btn-accept" @click="acceptTask(task.id)">接受</button>
+          <button class="btn-accept" @click="acceptTask(task)">接受</button>
           <button class="btn-reject" @click="showRejectModal(task)">拒绝</button>
         </view>
       </view>
@@ -41,6 +44,7 @@
         <view class="task-left">
           <view class="task-title">
             {{ task.title }}
+            <text v-if="task.memberOnly === 1" class="member-badge">会员任务</text>
             <text v-if="task.category === '小游戏类'" class="minigame-badge">🎮</text>
           </view>
           <view class="task-meta">
@@ -49,7 +53,7 @@
           </view>
         </view>
         <view class="task-right" v-if="task.status === 'pending'">
-          <button class="btn-complete" @click="completeTask(task.id)">完成</button>
+          <button class="btn-complete" @click="completeTask(task)">完成</button>
         </view>
         <view class="completed-badge" v-else>已完成</view>
       </view>
@@ -62,7 +66,10 @@
     <view class="task-list" v-if="activeTab === 'created'">
       <view class="task-item" v-for="task in createdTasks" :key="task.id">
         <view class="task-left">
-          <view class="task-title">{{ task.title }}</view>
+          <view class="task-title">
+            {{ task.title }}
+            <text v-if="task.memberOnly === 1" class="member-badge">会员任务</text>
+          </view>
           <view class="task-meta">
             <text class="points">+{{ task.points }}分</text>
             <text class="assignee">{{ task.executorName || '未分配' }}</text>
@@ -148,7 +155,7 @@
 </template>
 
 <script>
-import { getMyPendingTasks, acceptTask as acceptTaskApi, rejectTask as rejectTaskApi, getTodayTasks, completeTask as completeTaskApi, createTask as createTaskApi, getVisibleFamilyMembers } from '../../utils/api.js'
+import { getMyPendingTasks, acceptTask as acceptTaskApi, rejectTask as rejectTaskApi, getTodayTasks, completeTask as completeTaskApi, createTask as createTaskApi, getVisibleFamilyMembers, getMyMembership } from '../../utils/api.js'
 import { parseDate } from '../../utils/format.js'
 
 export default {
@@ -160,6 +167,7 @@ export default {
       todayTasks: [],
       createdTasks: [],
       isParent: false,
+      isMember: false,
       currentMemberId: null,
       currentUserId: null,
       familyMembers: [],
@@ -182,9 +190,16 @@ export default {
     this.isParent = role === 'parent'
     this.currentUserId = uni.getStorageSync('userId')
     this.currentMemberId = uni.getStorageSync('currentChildId') || this.currentUserId
+    this.checkMembership()
     this.loadInitialData()
   },
   methods: {
+    checkMembership() {
+      getMyMembership().then(res => {
+        const m = res.data || {}
+        this.isMember = !!(m.levelCode && m.levelCode !== 'FREE')
+      }).catch(() => {})
+    },
     switchTab(tab) {
       this.activeTab = tab
       if (tab === 'pending') this.loadPendingTasks()
@@ -229,18 +244,44 @@ export default {
         console.error('加载创建的任务失败', e)
       }
     },
-    async completeTask(taskId) {
+    async completeTask(task) {
+      if (task.memberOnly === 1 && !this.isMember) {
+        uni.showModal({
+          title: '会员任务',
+          content: '该任务是会员专属任务,开通会员后即可完成',
+          confirmText: '去开通',
+          success: (res) => {
+            if (res.confirm) {
+              uni.navigateTo({ url: '/pages/membership/index' })
+            }
+          }
+        })
+        return
+      }
       try {
-        const res = await completeTaskApi(taskId, this.currentMemberId, '')
+        const res = await completeTaskApi(task.id, this.currentMemberId, '')
         uni.showToast({ title: `获得 ${res.data.pointsEarned} 积分`, icon: 'success' })
         this.loadTodayTasks()
       } catch (e) {
         console.error('完成任务失败', e)
       }
     },
-    acceptTask(taskId) {
+    acceptTask(task) {
+      if (task.memberOnly === 1 && !this.isMember) {
+        uni.showModal({
+          title: '会员任务',
+          content: '该任务是会员专属任务,开通会员后即可接受',
+          confirmText: '去开通',
+          success: (res) => {
+            if (res.confirm) {
+              uni.navigateTo({ url: '/pages/membership/index' })
+            }
+          }
+        })
+        return
+      }
       uni.showLoading({ title: '接受中...' })
-      acceptTaskApi(taskId, this.currentMemberId).then(res => {
+      acceptTaskApi(task.id, this.currentMemberId).then(res => {
         uni.hideLoading()
         if (res.data) {
           uni.showToast({ title: '已接受任务', icon: 'success' })
@@ -520,6 +561,18 @@ export default {
   margin-left: 10rpx;
 }
 
+.member-badge {
+  display: inline-block;
+  font-size: 20rpx;
+  color: #B45309;
+  background: #FEF3C7;
+  border: 1rpx solid #F59E0B;
+  border-radius: 8rpx;
+  padding: 2rpx 12rpx;
+  margin-left: 12rpx;
+  vertical-align: middle;
+}
+
 .empty {
   text-align: center;
   color: #999;

+ 19 - 1
cfc-frontend/utils/api.js

@@ -2679,4 +2679,22 @@ export const aiQHistory = (data) => request('/api/ai-questionnaire/history', 'PO
 export const aiQProfileDetail = (data) => request('/api/ai-questionnaire/profile/detail', 'POST', data)
 export const getProfileRecommend = (data) => request('/api/recommend/profile', 'POST', data)
 
-
+// ===== 改版v1 需求驱动·逐步解锁(C类闭环 C类接口) =====
+// 问题域
+export const getProblemDomainList = () => request('/api/problem-domain/list', 'POST', {})
+// 用户意图
+export const getUserIntent = () => request('/api/user-intent/get', 'POST', {})
+export const chooseUserIntent = (data) => request('/api/user-intent/choose', 'POST', data)
+export const updateUserIntentStage = (journeyStage) => request('/api/user-intent/update-stage', 'POST', { journeyStage })
+// 站内通知
+export const getNotificationList = () => request('/api/notification/list', 'POST', {})
+export const readNotification = (data) => request('/api/notification/read', 'POST', data)
+// 专项调研
+export const submitProblemSurvey = (data) => request('/api/problem-survey/submit', 'POST', data)
+// 套餐详情
+export const getProblemPackageDetail = (packageId) => request('/api/problem-package/detail', 'POST', { packageId })
+// 物流
+export const updateLogistics = (data) => request('/api/logistics/update', 'POST', data)
+export const getMyLogistics = () => request('/api/logistics/my', 'POST', {})
+// 内容标签过滤
+export const getContentByTags = (data) => request('/api/content/by-tags', 'POST', data)