Przeglądaj źródła

chore(cf): 废弃 parent/market 任务模板市场页面及对应接口

- 删除 pages/parent/market/{index,detail}.vue(无 TabBar 入口,死代码)
- 删除 pages.json 中 market/index 和 market/detail 注册
- 删除 api.js 中死代码:getPublicPackages、purchasePackage、getPackageByShareCode
- MarketController packages/* 和 share/* 接口标记 410 废弃
  (套餐购买已统一合并到组合商品 bundle 链路,走 /api/product/order/*)
  保留 MarketController plans/* 接口(计划管理仍在使用)
iwt 1 miesiąc temu
rodzic
commit
d36c0469b8

+ 29 - 31
cfc-backend/src/main/java/com/etotem/cfc/controller/MarketController.java

@@ -19,7 +19,14 @@ import org.springframework.web.bind.annotation.*;
 import java.util.List;
 import java.util.Map;
 
-@Tag(name = "任务模板市场", description = "家长浏览、购买、应用任务模板等接口")
+/**
+ * 任务模板市场控制器(已废弃部分接口)
+ *
+ * /packages/* 和 /share/* 接口已废弃(对应已删除的前端 parent/market 页面,
+ * 套餐购买已合并到组合商品 productType=bundle 链路,走 /api/product/order/*)。
+ * /plans/* 接口保留(计划管理仍在使用)。
+ */
+@Tag(name = "任务模板市场", description = "任务模板市场接口(部分已废弃)")
 @RestController
 @RequestMapping("/api/market")
 public class MarketController {
@@ -34,65 +41,56 @@ public class MarketController {
     private MembershipService membershipService;
 
     /**
-     * 获取公开任务模板列表 (市场)
+     * 获取公开任务模板列表(已废弃)
      */
-    @Operation(summary = "获取公开任务模板列表")
+    @Deprecated
+    @Operation(summary = "获取公开任务模板列表(已废弃)")
     @PostMapping("/packages")
     public Result<List<TaskTemplatePackage>> getPublicPackages(@RequestBody(required = false) Map<String, Object> params) {
-        String category = params != null && params.get("category") != null ? params.get("category").toString() : null;
-        List<TaskTemplatePackage> packages = packageService.getPublicPackages(category);
-        return Result.success(packages);
+        return Result.error(410, "该接口已废弃,套餐购买请走组合商品下单");
     }
 
     /**
-     * 获取任务模板详情
+     * 获取任务模板详情(已废弃)
      */
-    @Operation(summary = "获取任务模板详情")
+    @Deprecated
+    @Operation(summary = "获取任务模板详情(已废弃)")
     @PostMapping("/packages/{id}")
     public Result<TaskTemplatePackage> getPackageDetail(@PathVariable Long id) {
-        TaskTemplatePackage pkg = packageService.getPackageById(id);
-        return Result.success(pkg);
+        return Result.error(410, "该接口已废弃,套餐购买请走组合商品下单");
     }
 
     /**
-     * 获取任务模板的任务项列表
+     * 获取任务模板的任务项列表(已废弃)
      */
-    @Operation(summary = "获取任务模板任务项列表")
+    @Deprecated
+    @Operation(summary = "获取任务模板任务项列表(已废弃)")
     @PostMapping("/packages/{id}/items")
     public Result<List<TaskTemplateItem>> getPackageItems(@PathVariable Long id) {
-        List<TaskTemplateItem> items = packageService.getPackageItems(id);
-        return Result.success(items);
+        return Result.error(410, "该接口已废弃,套餐购买请走组合商品下单");
     }
 
     /**
-     * 通过分享码获取任务模板
+     * 通过分享码获取任务模板(已废弃)
      */
-    @Operation(summary = "通过分享码获取任务模板")
+    @Deprecated
+    @Operation(summary = "通过分享码获取任务模板(已废弃)")
     @PostMapping("/share/{code}")
     public Result<TaskTemplatePackage> getPackageByShareCode(@PathVariable String code) {
-        TaskTemplatePackage pkg = packageService.getPackageByShareCode(code);
-        if (pkg == null) {
-            return Result.error("分享码无效");
-        }
-        return Result.success(pkg);
+        return Result.error(410, "该接口已废弃,套餐购买请走组合商品下单");
     }
 
     /**
-     * 购买并应用任务模板
+     * 购买并应用任务模板(已废弃)
      */
-    @Operation(summary = "购买并应用任务模板")
+    @Deprecated
+    @Operation(summary = "购买并应用任务模板(已废弃)")
     @PostMapping("/packages/{id}/purchase")
-    public Result<Map<String, Object>> purchasePackage(
+    public Result<TaskPlanInstance> purchasePackage(
             @PathVariable Long id,
             @RequestBody ApplyPackageDTO dto,
             @RequestAttribute("userId") Long userId) {
-        Long familyId = membershipService.getUserFamilyId(userId);
-        if (familyId == null) {
-            return Result.noFamily("请先创建或加入家庭");
-        }
-        dto.setPackageId(id);
-        Map<String, Object> applied = planService.applyAndActivate(dto, familyId, userId);
-        return Result.success(applied);
+        return Result.error(410, "该接口已废弃,套餐购买请走组合商品下单");
     }
 
     /**

+ 0 - 12
cfc-frontend/pages.json

@@ -166,18 +166,6 @@
     {
       "root": "pages/parent",
       "pages": [
-        {
-          "path": "market/index",
-          "style": {
-            "navigationBarTitleText": "任务模板市场"
-          }
-        },
-        {
-          "path": "market/detail",
-          "style": {
-            "navigationBarTitleText": "任务模板详情"
-          }
-        },
         {
           "path": "plans/index",
           "style": {

+ 0 - 166
cfc-frontend/pages/parent/market/detail.vue

@@ -1,166 +0,0 @@
-<template>
-  <view class="container">
-    <!-- 任务模板信息 -->
-    <view class="package-header">
-      <image class="cover" :src="getImageUrl(pkg.coverImage) || '/static/default-cover.png'" mode="aspectFill" />
-      <view class="header-content">
-        <text class="name">{{ pkg.name }}</text>
-        <view class="meta">
-          <text>{{ pkg.cycleDays }}天</text>
-          <text>{{ pkg.category }}</text>
-        </view>
-        <text class="price">{{ formatPriceWithSymbol(pkg.price) }}</text>
-      </view>
-    </view>
-
-    <!-- 描述 -->
-    <view class="section">
-      <text class="section-title">任务模板介绍</text>
-      <text class="description">{{ pkg.description || '暂无介绍' }}</text>
-    </view>
-
-    <!-- 任务项选择 -->
-    <view class="section">
-      <text class="section-title">选择任务项</text>
-      <view class="item-list">
-        <view 
-          class="item-card" 
-          v-for="item in items" 
-          :key="item.id"
-          :class="{ disabled: item.isRequired }"
-          @click="toggleItem(item)"
-        >
-          <view class="item-check">
-            <checkbox :checked="selectedItems.includes(item.id)" :disabled="item.isRequired" />
-          </view>
-          <view class="item-content">
-            <text class="item-name">{{ item.taskName }}</text>
-            <text class="item-desc">{{ item.description }}</text>
-            <view class="item-meta">
-              <text>积分: {{ item.points }}</text>
-              <text>频率: {{ item.frequency }}</text>
-              <text v-if="item.isRequired" class="required-tag">必选</text>
-            </view>
-          </view>
-        </view>
-      </view>
-    </view>
-
-    <!-- 底部操作 -->
-    <view class="footer">
-      <button class="btn-apply" @click="applyPackage">立即应用</button>
-    </view>
-  </view>
-</template>
-
-<script>
-import { getPackage, getPackageItems, purchasePackage } from '@/utils/api.js'
-import config from '@/config.js'
-
-export default {
-  data() {
-    return {
-      pkgId: null,
-      pkg: {},
-      items: [],
-      selectedItems: []
-    }
-  },
-  onLoad(options) {
-    this.pkgId = options.id
-    this.loadPackage()
-    this.loadItems()
-  },
-  methods: {
-    async loadPackage() {
-      try {
-        const res = await getPackage(this.pkgId)
-        this.pkg = res.data || {}
-      } catch (e) {
-        console.error(e)
-      }
-    },
-    async loadItems() {
-      try {
-        const res = await getPackageItems(this.pkgId)
-        this.items = res.data || []
-        // 自动选中必选项
-        this.items.forEach(item => {
-          if (item.isRequired) {
-            this.selectedItems.push(item.id)
-          }
-        })
-      } catch (e) {
-        console.error(e)
-      }
-    },
-    toggleItem(item) {
-      if (item.isRequired) return
-      const idx = this.selectedItems.indexOf(item.id)
-      if (idx > -1) {
-        this.selectedItems.splice(idx, 1)
-      } else {
-        this.selectedItems.push(item.id)
-      }
-    },
-    async applyPackage() {
-      // 获取孩子列表,选择一个孩子
-      uni.showActionSheet({
-        itemList: ['选择孩子'],
-        success: async () => {
-          // 这里应该先获取孩子列表,让用户选择
-          // 简化处理,直接使用当前家庭的孩子
-          try {
-            const res = await purchasePackage(this.pkgId, {
-              selectedItemIds: this.selectedItems,
-              memberId: 1 // TODO: 实际应该让用户选择
-            })
-            uni.showToast({ title: '应用成功' })
-            setTimeout(() => {
-              var pages = getCurrentPages()
-              if (pages.length > 1) {
-                uni.navigateBack()
-              } else {
-                uni.switchTab({ url: '/pages/index-home/index' })
-              }
-            }, 1500)
-          } catch (e) {
-            uni.showToast({ title: '应用失败', icon: 'none' })
-          }
-        }
-        })
-    },
-    getImageUrl: function(path) {
-      return config.API_BASE_URL + path
-    }
-  }
-}
-</script>
-
-<style scoped>
-.container { min-height: 100vh; background: #f5f5f5; padding-bottom: 120rpx; }
-
-.package-header { position: relative; }
-.cover { width: 100%; height: 400rpx; }
-.header-content { position: absolute; bottom: 0; left: 0; right: 0; padding: 30rpx; background: linear-gradient(transparent, rgba(0,0,0,0.7)); color: #fff; }
-.name { font-size: 36rpx; font-weight: bold; display: block; margin-bottom: 10rpx; }
-.meta { display: flex; gap: 20rpx; font-size: 24rpx; opacity: 0.8; margin-bottom: 10rpx; }
-.price { font-size: 40rpx; font-weight: bold; }
-
-.section { background: #fff; padding: 30rpx; margin-bottom: 10rpx; }
-.section-title { font-size: 30rpx; font-weight: bold; display: block; margin-bottom: 20rpx; }
-.description { font-size: 28rpx; color: #666; line-height: 1.6; }
-
-.item-list { display: flex; flex-direction: column; gap: 16rpx; }
-.item-card { display: flex; padding: 20rpx; background: #f9f9f9; border-radius: 12rpx; }
-.item-card.disabled { opacity: 0.7; }
-.item-check { margin-right: 16rpx; }
-.item-content { flex: 1; }
-.item-name { font-size: 28rpx; font-weight: bold; display: block; margin-bottom: 8rpx; }
-.item-desc { font-size: 24rpx; color: #999; display: block; margin-bottom: 8rpx; }
-.item-meta { display: flex; gap: 16rpx; font-size: 22rpx; color: #666; }
-.required-tag { color: #ff9800; }
-
-.footer { position: fixed; bottom: 0; left: 0; right: 0; background: #fff; padding: 20rpx 30rpx; box-shadow: 0 -2rpx 10rpx rgba(0,0,0,0.05); }
-.btn-apply { background: #4CAF50; color: #fff; border-radius: 40rpx; }
-</style>

+ 0 - 123
cfc-frontend/pages/parent/market/index.vue

@@ -1,123 +0,0 @@
-<template>
-  <view class="container">
-    <!-- 搜索/分类 -->
-    <view class="filter-bar">
-      <view class="search-box">
-        <input class="search-input" v-model="keyword" placeholder="搜索任务模板" @confirm="search" />
-      </view>
-      <view class="categories">
-        <text 
-          class="cat-item" 
-          :class="{ active: !currentCategory }"
-          @click="selectCategory('')"
-        >全部</text>
-        <text 
-          class="cat-item" 
-          v-for="cat in categories" 
-          :key="cat"
-          :class="{ active: currentCategory === cat }"
-          @click="selectCategory(cat)"
-        >{{ cat }}</text>
-      </view>
-    </view>
-
-    <!-- 任务模板列表 -->
-    <view class="package-list">
-      <view 
-        class="package-card" 
-        v-for="pkg in packages" 
-        :key="pkg.id"
-        @click="goToDetail(pkg.id)"
-      >
-        <image class="package-cover" :src="getImageUrl(pkg.coverImage) || '/static/default-cover.png'" mode="aspectFill" />
-        <view class="package-content">
-          <text class="package-name">{{ pkg.name }}</text>
-          <text class="package-desc">{{ pkg.description }}</text>
-          <view class="package-meta">
-            <text class="meta-item">{{ pkg.cycleDays }}天</text>
-            <text class="meta-item">{{ pkg.category }}</text>
-            <text class="price">{{ formatPriceWithSymbol(pkg.price) }}</text>
-          </view>
-        </view>
-      </view>
-    </view>
-
-    <!-- 空状态 -->
-    <view class="empty" v-if="packages.length === 0">
-      <text>暂无任务模板</text>
-    </view>
-  </view>
-</template>
-
-<script>
-import { getPublicPackages } from '@/utils/api.js'
-import config from '@/config.js'
-
-export default {
-  data() {
-    return {
-      packages: [],
-      keyword: '',
-      currentCategory: '',
-      categories: ['学习', '习惯', '健康', '情绪', '其他']
-    }
-  },
-  onShow() {
-    this.loadPackages()
-  },
-  methods: {
-    async loadPackages() {
-      try {
-        const res = await getPublicPackages(this.currentCategory)
-        this.packages = res.data || []
-      } catch (e) {
-        console.error(e)
-      }
-    },
-    selectCategory(cat) {
-      this.currentCategory = cat
-      this.loadPackages()
-    },
-    search() {
-      // 简单筛选
-      if (this.keyword) {
-        this.packages = this.packages.filter(p => p.name.includes(this.keyword))
-      } else {
-        this.loadPackages()
-      }
-    },
-    goToDetail(id) {
-      uni.navigateTo({
-        url: `/pages/parent/market/detail?id=${id}`
-      })
-    },
-    getImageUrl: function(path) {
-      return config.API_BASE_URL + path
-    }
-  }
-}
-</script>
-
-<style scoped>
-.container { min-height: 100vh; background: #f5f5f5; }
-
-.filter-bar { background: #fff; padding: 20rpx; margin-bottom: 10rpx; }
-.search-box { margin-bottom: 20rpx; }
-.search-input { padding: 16rpx 20rpx; background: #f5f5f5; border-radius: 30rpx; font-size: 28rpx; }
-
-.categories { display: flex; gap: 20rpx; overflow-x: auto; }
-.cat-item { font-size: 26rpx; color: #666; padding: 10rpx 20rpx; white-space: nowrap; }
-.cat-item.active { color: #4CAF50; font-weight: bold; }
-
-.package-list { padding: 20rpx; display: flex; flex-direction: column; gap: 20rpx; }
-.package-card { background: #fff; border-radius: 16rpx; overflow: hidden; box-shadow: 0 2rpx 10rpx rgba(0,0,0,0.05); }
-.package-cover { width: 100%; height: 300rpx; }
-.package-content { padding: 20rpx; }
-.package-name { font-size: 32rpx; font-weight: bold; color: #333; display: block; margin-bottom: 10rpx; }
-.package-desc { font-size: 26rpx; color: #999; display: block; margin-bottom: 16rpx; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
-.package-meta { display: flex; align-items: center; gap: 20rpx; }
-.meta-item { font-size: 24rpx; color: #666; }
-.price { font-size: 32rpx; color: #f44336; font-weight: bold; margin-left: auto; }
-
-.empty { display: flex; justify-content: center; padding: 100rpx; color: #999; }
-</style>

+ 0 - 14
cfc-frontend/utils/api.js

@@ -801,20 +801,6 @@ export const getPackageItems = (packageId) => {
   return request(`/api/packages/${packageId}/items`, 'POST')
 }
 
-// 获取公开任务模板列表
-export const getPublicPackages = (category) => {
-  return request('/api/market/packages', 'POST', { category })
-}
-
-// 通过分享码获取任务模板
-export const getPackageByShareCode = (code) => {
-  return request(`/api/market/share/${code}`, 'POST')
-}
-
-// 购买并应用任务模板
-export const purchasePackage = (packageId, data) => {
-  return request(`/api/market/packages/${packageId}/purchase`, 'POST', data)
-}
 
 // 获取我的任务计划
 export const getMyPlans = () => {