Files
ai_game/server/models/user.js

224 lines
6.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const pool = require('../config/db');
const UserModel = {
// 通过openid查找或创建用户
async findOrCreate(openid, userInfo = {}) {
const [existing] = await pool.query(
'SELECT * FROM users WHERE openid = ?',
[openid]
);
if (existing.length > 0) {
return existing[0];
}
// 创建新用户
const [result] = await pool.query(
'INSERT INTO users (openid, nickname, avatar_url, gender) VALUES (?, ?, ?, ?)',
[openid, userInfo.nickname || '', userInfo.avatarUrl || '', userInfo.gender || 0]
);
return {
id: result.insertId,
openid,
nickname: userInfo.nickname || '',
avatar_url: userInfo.avatarUrl || '',
gender: userInfo.gender || 0
};
},
// 更新用户信息
async updateProfile(userId, userInfo) {
await pool.query(
'UPDATE users SET nickname = ?, avatar_url = ?, gender = ? WHERE id = ?',
[userInfo.nickname, userInfo.avatarUrl, userInfo.gender, userId]
);
},
// 获取用户进度
async getProgress(userId, storyId = null) {
let sql = `SELECT up.*, s.title as story_title, s.cover_url
FROM user_progress up
JOIN stories s ON up.story_id = s.id
WHERE up.user_id = ?`;
const params = [userId];
if (storyId) {
sql += ' AND up.story_id = ?';
params.push(storyId);
}
sql += ' ORDER BY up.updated_at DESC';
const [rows] = await pool.query(sql, params);
return storyId ? rows[0] : rows;
},
// 保存用户进度
async saveProgress(userId, storyId, data) {
const { currentNodeKey, isCompleted, endingReached } = data;
await pool.query(
`INSERT INTO user_progress (user_id, story_id, current_node_key, is_completed, ending_reached)
VALUES (?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
current_node_key = VALUES(current_node_key),
is_completed = VALUES(is_completed),
ending_reached = VALUES(ending_reached),
play_count = play_count + 1`,
[userId, storyId, currentNodeKey, isCompleted || false, endingReached || '']
);
// 如果完成了,记录结局
if (isCompleted && endingReached) {
await pool.query(
`INSERT IGNORE INTO user_endings (user_id, story_id, ending_name) VALUES (?, ?, ?)`,
[userId, storyId, endingReached]
);
// 更新用户统计
await pool.query(
'UPDATE users SET total_play_count = total_play_count + 1, total_endings = (SELECT COUNT(*) FROM user_endings WHERE user_id = ?) WHERE id = ?',
[userId, userId]
);
}
},
// 点赞/取消点赞
async toggleLike(userId, storyId, isLiked) {
await pool.query(
`INSERT INTO user_progress (user_id, story_id, is_liked)
VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE is_liked = ?`,
[userId, storyId, isLiked, isLiked]
);
},
// 收藏/取消收藏
async toggleCollect(userId, storyId, isCollected) {
await pool.query(
`INSERT INTO user_progress (user_id, story_id, is_collected)
VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE is_collected = ?`,
[userId, storyId, isCollected, isCollected]
);
},
// 获取收藏列表
async getCollections(userId) {
const [rows] = await pool.query(
`SELECT s.id, s.title, s.cover_url, s.description, s.category, s.play_count, s.like_count
FROM user_progress up
JOIN stories s ON up.story_id = s.id
WHERE up.user_id = ? AND up.is_collected = 1
ORDER BY up.updated_at DESC`,
[userId]
);
return rows;
},
// 获取用户解锁的结局
async getUnlockedEndings(userId, storyId = null) {
let sql = 'SELECT * FROM user_endings WHERE user_id = ?';
const params = [userId];
if (storyId) {
sql += ' AND story_id = ?';
params.push(storyId);
}
const [rows] = await pool.query(sql, params);
return rows;
},
// 获取我的作品
async getMyWorks(userId) {
try {
const [rows] = await pool.query(
`SELECT id, title, description, category, cover_url, play_count, like_count,
comment_count, status, created_at, updated_at,
COALESCE(earnings, 0) as earnings
FROM stories
WHERE author_id = ?
ORDER BY created_at DESC`,
[userId]
);
return rows;
} catch (e) {
// 表可能还没有author_id字段返回空数组
return [];
}
},
// 获取草稿箱
async getDrafts(userId) {
try {
const [rows] = await pool.query(
`SELECT id, title, category, node_count, source, created_at, updated_at
FROM story_drafts
WHERE user_id = ?
ORDER BY updated_at DESC`,
[userId]
);
return rows;
} catch (e) {
// 表可能不存在,返回空数组
return [];
}
},
// 获取最近游玩
async getRecentPlayed(userId, limit = 10) {
const [rows] = await pool.query(
`SELECT s.id, s.title, s.category, s.description, s.cover_url,
up.current_node_key, up.is_completed,
CASE WHEN up.is_completed THEN '已完成' ELSE '进行中' END as progress
FROM user_progress up
JOIN stories s ON up.story_id = s.id
WHERE up.user_id = ?
ORDER BY up.updated_at DESC
LIMIT ?`,
[userId, limit]
);
return rows;
},
// 获取AI创作历史
async getAIHistory(userId, limit = 20) {
try {
const [rows] = await pool.query(
`SELECT id, gen_type, input_prompt, output_content, status, created_at
FROM ai_generations
WHERE user_id = ?
ORDER BY created_at DESC
LIMIT ?`,
[userId, limit]
);
return rows;
} catch (e) {
return [];
}
},
// 获取AI配额
async getAIQuota(userId) {
try {
const [rows] = await pool.query(
`SELECT daily_free_total as daily, daily_free_used as used,
purchased_quota as purchased, gift_quota as gift
FROM user_ai_quota
WHERE user_id = ?`,
[userId]
);
if (rows.length > 0) {
return rows[0];
}
// 没有记录则返回默认值
return { daily: 3, used: 0, purchased: 0, gift: 0 };
} catch (e) {
return { daily: 3, used: 0, purchased: 0, gift: 0 };
}
}
};
module.exports = UserModel;