feat: 集成 KieAI 服务,移除 models-integration 子项目

- 添加 Gemini 2.5 Flash 对话接口(流式+非流式)
- 添加 NanoBanana 图像生成/编辑接口
- 添加 Sora2 视频生成接口(文生视频、图生视频、去水印)
- 移除 models-integration 子项目(功能已迁移至主后端)
- 新增测试文档和 Playwright E2E 配置
- 更新前端页面和 API 接口
- 更新后端配置和日志处理
This commit is contained in:
2026-03-03 15:33:50 +08:00
parent 1ddb051977
commit 4be53dcd1b
586 changed files with 21142 additions and 25130 deletions

View File

@@ -36,9 +36,13 @@
</view>
</view>
<!-- 立即打卡按钮 -->
<view class="checkin-btn" @click="handleCheckin">
<text>立即打卡</text>
<!-- 立即打卡按钮今日已打卡则显示灰色不可点 -->
<view
class="checkin-btn"
:class="{ 'checkin-btn-disabled': todaySigned }"
@click="handleCheckin"
>
<text>{{ todaySigned ? '今日已打卡' : '立即打卡' }}</text>
</view>
</view>
@@ -108,6 +112,7 @@
export default {
data() {
return {
todaySigned: false,
currentPoints: 522,
streakDays: [
{ day: 1, completed: false, special: false },
@@ -170,6 +175,11 @@ export default {
}
},
onLoad() {
const { checkLogin, toLogin } = require('@/libs/login.js');
if (!checkLogin()) {
toLogin();
return;
}
this.loadCheckinData();
},
onShow() {
@@ -180,31 +190,32 @@ export default {
async loadCheckinData() {
try {
const { getUserPoints, getCheckinStreak, getCheckinTasks } = await import('@/api/tool.js');
// 并行加载数据
const [pointsRes, streakRes, tasksRes] = await Promise.all([
const { getSignGet } = await import('@/api/user.js');
const [pointsRes, streakRes, tasksRes, signRes] = await Promise.all([
getUserPoints().catch(() => ({ data: { points: 0 } })),
getCheckinStreak().catch(() => ({ data: { streakDays: 7, currentStreak: 0 } })),
getCheckinTasks().catch(() => ({ data: { tasks: [] } }))
getCheckinTasks().catch(() => ({ data: { tasks: [] } })),
getSignGet().catch(() => ({ data: { today: false } }))
]);
// 更新积分
if (pointsRes.data) {
this.currentPoints = pointsRes.data.points || 0;
if (signRes && signRes.data && signRes.data.today) {
this.todaySigned = true;
}
// 更新连续打卡天数
if (pointsRes.data) {
this.currentPoints = pointsRes.data.totalPoints ?? pointsRes.data.points ?? 0;
}
if (streakRes.data) {
const streak = streakRes.data.currentStreak || 0;
// 生成连续打卡天数数组
this.streakDays = Array.from({ length: 7 }, (_, i) => ({
day: i + 1,
completed: i < streak,
special: i === 6 // 第7天特殊标记
special: i === 6
}));
}
// 更新任务列表
if (tasksRes.data && tasksRes.data.tasks && tasksRes.data.tasks.length > 0) {
this.taskList = tasksRes.data.tasks.map(task => ({
id: task.id || task.taskId,
@@ -224,16 +235,39 @@ export default {
url: '/pages/tool/points-rules'
})
},
handleCheckin() {
async handleCheckin() {
if (this.todaySigned) {
uni.showToast({ title: '今日已打卡', icon: 'none' });
return;
}
try {
const { setSignIntegral, getUserInfo } = await import('@/api/user.js');
const { getUserPoints } = await import('@/api/tool.js');
// 子问题 A不在 API 成功前修改 currentPoints避免积分提前跳变
await setSignIntegral();
this.todaySigned = true;
// 子问题 B打卡成功后用服务端最新积分刷新优先 GET /api/front/user/info禁止前端本地 +30
const userRes = await getUserInfo();
if (userRes && userRes.data && (userRes.data.integral != null || userRes.data.points != null)) {
this.currentPoints = userRes.data.integral ?? userRes.data.points ?? 0;
} else {
const pointsRes = await getUserPoints();
if (pointsRes && pointsRes.data) {
const serverPoints = pointsRes.data.totalPoints ?? pointsRes.data.points ?? pointsRes.data.availablePoints ?? 0;
this.currentPoints = serverPoints;
}
}
} catch (e) {
const msg = (typeof e === 'string' ? e : (e && (e.message || e.msg))) || '打卡失败';
if (msg.includes('今日已签到') || msg.includes('不可重复')) {
this.todaySigned = true;
}
uni.showToast({ title: msg, icon: 'none' });
return;
}
uni.navigateTo({
url: '/pages/tool/checkin-publish'
})
// 更新打卡状态
const todayIndex = this.getTodayIndex()
if (todayIndex >= 0 && todayIndex < this.streakDays.length) {
// this.streakDays[todayIndex].completed = true
this.currentPoints += 30 // 每日打卡获得30积分
}
});
},
getTodayIndex() {
// 根据连续打卡数据计算当前是第几天
@@ -388,7 +422,7 @@ export default {
padding: 20rpx;
text-align: center;
box-shadow: 0 16rpx 48rpx rgba(255, 107, 53, 0.35);
text {
font-size: 32rpx;
color: #ffffff;
@@ -396,6 +430,12 @@ export default {
}
}
.checkin-btn-disabled {
background: linear-gradient(135deg, #c4c4c4 0%, #e0e0e0 100%);
box-shadow: none;
opacity: 0.9;
}
/* 通用区块样式 */
.section {
margin: 48rpx 32rpx 0;