[Claude Workbench] Initial commit - preserving existing code

This commit is contained in:
Claude Workbench
2025-11-14 17:41:15 +08:00
commit 0f7bc05697
587 changed files with 103215 additions and 0 deletions

View File

@@ -0,0 +1,556 @@
# 积分系统与AI模型管理完整功能总结
## 📋 目录
1. [积分消费查询功能](#1-积分消费查询功能)
2. [AI模型列表查询功能](#2-ai模型列表查询功能)
3. [数据库迁移脚本](#3-数据库迁移脚本)
4. [API接口列表](#4-api接口列表)
5. [前端调用示例](#5-前端调用示例)
---
## 1. 积分消费查询功能
### 功能概述
用户可以查看自己的积分余额、消费明细和统计信息。
### 核心接口
#### 1.1 获取积分余额
```http
GET /user/points/consumption/balance
Authorization: Bearer {token}
```
**响应示例:**
```json
{
"code": 200,
"message": "success",
"data": {
"currentPoints": 1500,
"pointsExpiresAt": "2025-12-31T23:59:59",
"willExpireSoon": false,
"daysUntilExpire": 120
}
}
```
#### 1.2 获取积分消费记录(分页)
```http
GET /user/points/consumption/logs?page=1&size=10&changeType=consume
Authorization: Bearer {token}
```
**参数说明:**
- `page`: 页码默认1
- `size`: 每页数量默认10最大100
- `changeType`: 变动类型(可选)
- `recharge`: 充值
- `consume`: 消费
- `refund`: 退款
- `admin_adjust`: 管理员调整
**响应示例:**
```json
{
"code": 200,
"message": "success",
"data": {
"records": [
{
"id": 1,
"taskNo": "TASK202510221234567890",
"changeType": "consume",
"changeTypeName": "消费",
"changeAmount": -10,
"balanceBefore": 1510,
"balanceAfter": 1500,
"description": "AI图片生成消费",
"createTime": "2025-10-22T10:30:00"
}
],
"total": 100,
"page": 1,
"size": 10,
"totalPages": 10
}
}
```
#### 1.3 获取积分统计
```http
GET /user/points/consumption/stats
Authorization: Bearer {token}
```
**响应示例:**
```json
{
"code": 200,
"message": "success",
"data": {
"currentPoints": 1500,
"totalRechargePoints": 2000,
"totalConsumePoints": 500,
"totalRefundPoints": 0,
"pointsExpiresAt": "2025-12-31T23:59:59"
}
}
```
---
## 2. AI模型列表查询功能
### 功能概述
用户可以查看系统中所有可用的AI模型支持按任务类型、厂商分组查询。
### 任务类型分类
#### 细致分类(数据库 task_type 字段)
- `text_to_image`: 文生图
- `image_to_image`: 图生图
- `text_to_video`: 文生视频
- `image_to_video`: 图生视频
- `llm`: 大语言模型
- `text_to_audio`: 文生音频
- `image_to_text`: 图生文
- `other`: 其他
#### 粗略分类(兼容旧接口)
- `image`: 图片生成(包括 text_to_image 和 image_to_image
- `video`: 视频生成(包括 text_to_video 和 image_to_video
- `audio`: 音频生成
- `text`: 文本生成
### 核心接口
#### 2.1 获取模型列表(支持筛选)
```http
GET /user/ai/models?taskType=text_to_image&provider=openai&enabledOnly=true
```
**参数说明:**
- `taskType`: 任务类型(可选)
- `provider`: 服务提供商可选openai/runninghub
- `enabledOnly`: 是否只返回已启用的模型默认true
**响应示例:**
```json
{
"code": 200,
"message": "success",
"data": [
{
"id": 1,
"modelName": "sora_image",
"displayName": "Sora高质量图片生成",
"description": "Sora高质量图片生成",
"pointsCost": 11,
"providerType": "openai",
"taskType": "text_to_image",
"isEnabled": true,
"extendedConfig": {}
}
]
}
```
#### 2.2 按任务类型分组获取模型
```http
GET /user/ai/models/group-by-type?provider=&enabledOnly=true
```
**响应示例:**
```json
{
"code": 200,
"message": "success",
"data": [
{
"taskType": "text_to_image",
"taskTypeName": "文生图",
"models": [
{
"id": 1,
"modelName": "sora_image",
"displayName": "Sora高质量图片生成",
"pointsCost": 11,
"providerType": "openai",
"taskType": "text_to_image",
"isEnabled": true
}
],
"count": 2
},
{
"taskType": "text_to_video",
"taskTypeName": "文生视频",
"models": [...],
"count": 4
}
]
}
```
#### 2.3 按厂商分组获取模型
```http
GET /user/ai/models/group-by-provider?taskType=&enabledOnly=true
```
**响应示例:**
```json
{
"code": 200,
"message": "success",
"data": [
{
"providerType": "openai",
"providerName": "OpenAI",
"models": [...],
"count": 3
},
{
"providerType": "runninghub",
"providerName": "RunningHub",
"models": [...],
"count": 5
}
]
}
```
#### 2.4 获取模型统计
```http
GET /user/ai/models/stats
```
**响应示例:**
```json
{
"code": 200,
"message": "success",
"data": {
"totalModels": 10,
"enabledModels": 8,
"countByType": {
"text_to_image": 2,
"text_to_video": 4,
"image_to_video": 1,
"llm": 1
},
"countByProvider": {
"openai": 3,
"runninghub": 5
}
}
}
```
---
## 3. 数据库迁移脚本
### V6: 积分充值系统
- 创建 `points_package` 表(积分套餐)
- 扩展 `order` 表支持积分订单
- 更新 `points_consumption_log` 表支持充值类型
### V7: 任务类型细分
-`points_config` 表添加 `task_type` 字段
- 根据现有模型名称更新任务类型
- 添加多种模型类型示例数据
- 添加索引优化查询性能
---
## 4. API接口列表
### 4.1 积分消费查询(需要登录)
| 接口 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 获取积分余额 | GET | `/user/points/consumption/balance` | 当前积分和过期时间 |
| 获取消费记录 | GET | `/user/points/consumption/logs` | 分页查询消费明细 |
| 获取积分统计 | GET | `/user/points/consumption/stats` | 累计充值、消费、退款 |
### 4.2 AI模型查询公开访问
| 接口 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 获取模型列表 | GET | `/user/ai/models` | 支持筛选和过滤 |
| 按类型分组 | GET | `/user/ai/models/group-by-type` | 按任务类型分组 |
| 按厂商分组 | GET | `/user/ai/models/group-by-provider` | 按服务提供商分组 |
| 获取统计信息 | GET | `/user/ai/models/stats` | 模型数量统计 |
---
## 5. 前端调用示例
### 5.1 Vue 3 + TypeScript 示例
```typescript
// api/points.ts
import request from '@/utils/request'
// 获取积分余额
export function getPointsBalance() {
return request({
url: '/user/points/consumption/balance',
method: 'get'
})
}
// 获取积分消费记录
export function getConsumptionLogs(params: {
page?: number
size?: number
changeType?: 'recharge' | 'consume' | 'refund' | 'admin_adjust'
}) {
return request({
url: '/user/points/consumption/logs',
method: 'get',
params
})
}
// 获取积分统计
export function getConsumptionStats() {
return request({
url: '/user/points/consumption/stats',
method: 'get'
})
}
// api/models.ts
import request from '@/utils/request'
// 获取所有模型
export function getAllModels(params: {
taskType?: string
provider?: string
enabledOnly?: boolean
}) {
return request({
url: '/user/ai/models',
method: 'get',
params
})
}
// 按类型分组获取模型
export function getModelsByType(params: {
provider?: string
enabledOnly?: boolean
}) {
return request({
url: '/user/ai/models/group-by-type',
method: 'get',
params
})
}
// 按厂商分组获取模型
export function getModelsByProvider(params: {
taskType?: string
enabledOnly?: boolean
}) {
return request({
url: '/user/ai/models/group-by-provider',
method: 'get',
params
})
}
// 获取模型统计
export function getModelStats() {
return request({
url: '/user/ai/models/stats',
method: 'get'
})
}
```
### 5.2 React 示例
```typescript
// hooks/usePoints.ts
import { useState, useEffect } from 'react'
import { getPointsBalance, getConsumptionLogs } from '@/api/points'
export function usePointsBalance() {
const [balance, setBalance] = useState(null)
const [loading, setLoading] = useState(true)
useEffect(() => {
getPointsBalance().then(res => {
setBalance(res.data)
setLoading(false)
})
}, [])
return { balance, loading }
}
// hooks/useModels.ts
import { useState, useEffect } from 'react'
import { getModelsByType } from '@/api/models'
export function useModelsByType(provider?: string) {
const [models, setModels] = useState([])
const [loading, setLoading] = useState(true)
useEffect(() => {
getModelsByType({ provider, enabledOnly: true }).then(res => {
setModels(res.data)
setLoading(false)
})
}, [provider])
return { models, loading }
}
```
### 5.3 使用场景示例
```vue
<!-- PointsBalance.vue -->
<template>
<div class="points-balance">
<div class="balance-card">
<h3>当前积分</h3>
<p class="points">{{ balance?.currentPoints || 0 }}</p>
<p class="expire-info" v-if="balance?.pointsExpiresAt">
{{ balance.willExpireSoon ? '即将过期' : '有效期至' }}
{{ formatDate(balance.pointsExpiresAt) }}
</p>
</div>
<div class="consumption-logs">
<h3>消费记录</h3>
<div v-for="log in logs.records" :key="log.id" class="log-item">
<span>{{ log.changeTypeName }}</span>
<span>{{ log.description }}</span>
<span :class="log.changeAmount > 0 ? 'increase' : 'decrease'">
{{ log.changeAmount > 0 ? '+' : '' }}{{ log.changeAmount }}
</span>
<span>{{ formatDate(log.createTime) }}</span>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { getPointsBalance, getConsumptionLogs } from '@/api/points'
const balance = ref(null)
const logs = ref({ records: [], total: 0 })
onMounted(async () => {
const [balanceRes, logsRes] = await Promise.all([
getPointsBalance(),
getConsumptionLogs({ page: 1, size: 10 })
])
balance.value = balanceRes.data
logs.value = logsRes.data
})
</script>
```
```vue
<!-- ModelSelector.vue -->
<template>
<div class="model-selector">
<div class="filter">
<select v-model="selectedType">
<option value="">全部类型</option>
<option value="text_to_image">文生图</option>
<option value="text_to_video">文生视频</option>
<option value="image_to_video">图生视频</option>
</select>
<select v-model="selectedProvider">
<option value="">全部厂商</option>
<option value="openai">OpenAI</option>
<option value="runninghub">RunningHub</option>
</select>
</div>
<div class="models-grid">
<div v-for="model in filteredModels" :key="model.id" class="model-card">
<h4>{{ model.displayName }}</h4>
<p>{{ model.description }}</p>
<div class="model-footer">
<span class="cost">{{ model.pointsCost }} 积分</span>
<span class="provider">{{ model.providerType }}</span>
</div>
<button @click="selectModel(model)">选择</button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { getAllModels } from '@/api/models'
const selectedType = ref('')
const selectedProvider = ref('')
const allModels = ref([])
const filteredModels = computed(() => {
return allModels.value.filter(model => {
const typeMatch = !selectedType.value || model.taskType === selectedType.value
const providerMatch = !selectedProvider.value || model.providerType === selectedProvider.value
return typeMatch && providerMatch
})
})
onMounted(async () => {
const res = await getAllModels({ enabledOnly: true })
allModels.value = res.data
})
const selectModel = (model) => {
// 选择模型逻辑
console.log('Selected model:', model)
}
</script>
```
---
## 📌 总结
### 已实现功能
1. ✅ 用户积分余额查询
2. ✅ 用户积分消费记录查询(分页、筛选)
3. ✅ 用户积分统计信息
4. ✅ AI模型列表查询支持筛选
5. ✅ 按任务类型分组查询模型
6. ✅ 按厂商分组查询模型
7. ✅ 模型统计信息
### 技术特点
- 支持细致的任务类型分类(文生图、图生图、图生视频等)
- 向后兼容粗略分类image、video等
- 公开访问的模型列表接口,无需登录
- 需要登录的积分查询接口,保护用户隐私
- 完整的分页支持
- 灵活的筛选和分组功能
### 数据库优化
- 添加 `task_type` 字段用于精确分类
- 添加索引提升查询性能
- 支持逻辑删除
### 安全性
- 积分相关接口需要用户认证
- 模型列表接口公开访问,方便前端展示
- 完整的权限控制配置
---
**文档版本:** v1.0
**最后更新:** 2025-10-22