Compare commits

..

7 Commits
lxy ... main

Author SHA1 Message Date
崔艺111 51b67bd439 hg
2 months ago
崔艺111 93146f6311 sd
2 months ago
崔艺111 1560489597 as
2 months ago
崔艺111 49ca78c5ef 3
2 months ago
崔艺111 ef7a21b075 2
2 months ago
崔艺111 86972710f8 1
3 months ago
p56u3ak8w 259bfc7cbc Merge pull request '1' (#1) from lxy into main
3 months ago

@ -1,2 +0,0 @@
# study_helper

@ -1,248 +0,0 @@
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV
})
const db = cloud.database()
exports.main = async (event, context) => {
const { action } = event
try {
switch (action) {
case 'loginWithCode':
return await handleLoginWithCode(event)
case 'registerUser':
return await handleRegisterUser(event)
case 'getUserByOpenid':
return await handleGetUserByOpenid(event);
default:
return {
success: false,
message: '未知操作'
}
}
} catch (error) {
console.error('云函数执行错误:', error)
return {
success: false,
message: '服务器内部错误'
}
}
}
// 使用code登录
async function handleLoginWithCode(event) {
const { code } = event
if (!code) {
return {
success: false,
message: '缺少code参数'
}
}
try {
// 1. 通过code调用微信接口获取openid
const authResult = await getOpenIdByCode(code)
if (!authResult.openid) {
return {
success: false,
message: '获取openid失败'
}
}
const openid = authResult.openid
// 2. 通过openid查询数据库
const userResult = await db.collection('users')
.where({
openid: openid
})
.get()
// 3. 如果查询到用户数据,完成登录流程
if (userResult.data.length > 0) {
const user = userResult.data[0]
return {
success: true,
data: {
userInfo: {
_id: user._id,
openid: user.openid,
nickname: user.nickname,
avatarUrl: user.avatarUrl,
role: user.role,
reviewedPoems: user.reviewedPoems,
learningStats: user. learningStats,
}
}
}
} else {
// 4. 如果查询不到用户返回未注册状态和openid
return {
success: false,
message: '用户未注册',
code: 'USER_NOT_REGISTERED',
openid: openid
}
}
} catch (error) {
console.error('登录处理错误:', error)
return {
success: false,
message: '登录失败'
}
}
}
// 注册用户
async function handleRegisterUser(event) {
const { openid, userInfo } = event
if (!openid || !userInfo) {
return {
success: false,
message: '缺少必要参数'
}
}
try {
// 直接创建新用户
const newUser = {
openid: openid,
nickname: userInfo.nickName || '勤奋的小朋友',
avatarUrl: userInfo.avatarUrl || 'defaultAvatar',
createdAt: db.serverDate(),
updatedAt: db.serverDate(),
role: true,
reviewedPoems:{},
// 复习相关数据直接嵌入在用户文档中
learningStats: {
totalLearned: 0,
totalReviewed: 0,
lastLearnDate: null
}
}
// 先查询用户是否存在
const existingUser = await db.collection('users')
.where({ openid: openid })
.get()
let userId
let finalUser
if (existingUser.data.length > 0) {
// 用户存在,更新信息
await db.collection('users')
.where({ openid: openid })
.update({
data:{
updatedAt: newUser.updatedAt
}
})
userId = existingUser.data[0]._id
const updatedUser = await db.collection('users').doc(userId).get()
finalUser = updatedUser.data
}else{
const addResult = await db.collection('users').add({
data: newUser
})
userId = addResult._id
// 获取新创建的用户信息
const user = await db.collection('users').doc(addResult._id).get()
finalUser = user.data
}
// 返回创建的用户信息
return {
success: true,
data: {
userInfo: {
_id: userId,
openid: finalUser.openid,
nickname: finalUser.nickname,
avatarUrl: finalUser.avatarUrl,
role: finalUser.role,
reviewedPoems: finalUser.reviewedPoems|| {},
learningStats: finalUser.learningStats|| {
totalLearned: 0,
totalReviewed: 0,
lastLearnDate: null
}
}
}
}
} catch (error) {
console.error('注册用户错误:', error)
return {
success: false,
message: '注册失败'
}
}
}
// 通过code获取openid
async function getOpenIdByCode(code) {
// 在云函数中我们可以直接获取到openid不需要再用code换取
// 因为云函数自动包含了用户身份信息
const wxContext = cloud.getWXContext()
return {
openid: wxContext.OPENID,
appid: wxContext.APPID,
unionid: wxContext.UNIONID
}
}
async function handleGetUserByOpenid(event) {
const { openid } = event;
if (!openid) {
return {
success: false,
message: '缺少openid参数'
};
}
try {
const userResult = await db.collection('users')
.where({ openid: openid })
.get();
if (userResult.data.length > 0) {
const user = userResult.data[0];
return {
success: true,
data: {
userInfo: {
_id: user._id,
openid: user.openid,
nickname: user.nickname,
avatarUrl: user.avatarUrl,
role: user.role,
reviewedPoems: user.reviewedPoems || {},
learningStats: user.learningStats || {
totalLearned: 0,
totalReviewed: 0,
lastLearnDate: null
}
}
}
};
} else {
return {
success: false,
message: '用户不存在'
};
}
} catch (error) {
console.error('获取用户信息错误:', error);
return {
success: false,
message: '获取用户信息失败'
};
}
}

@ -1,6 +0,0 @@
{
"permissions": {
"openapi": [
]
}
}

@ -1,16 +0,0 @@
// cloudfunctions/getOpenId/index.js
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV
})
exports.main = async (event, context) => {
const wxContext = cloud.getWXContext()
return {
openid: wxContext.OPENID,
appid: wxContext.APPID,
unionid: wxContext.UNIONID,
}
}

@ -1,14 +0,0 @@
{
"name": "getOpenId",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"wx-server-sdk": "~3.0.1"
}
}

@ -1,6 +0,0 @@
{
"permissions": {
"openapi": [
]
}
}

@ -1,52 +0,0 @@
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV
})
exports.main = async (event, context) => {
const db = cloud.database()
const { id } = event
console.log('获取古诗详情ID:', id)
try {
// 根据ID从poeties集合中获取古诗详情
const result = await db.collection('poeties')
.doc(id)
.get()
console.log('数据库查询结果:', result)
if (result.data) {
return {
success: true,
data: result.data
}
} else {
return {
success: false,
message: '古诗不存在'
}
}
} catch (error) {
console.error('获取古诗详情失败:', error)
// 更详细的错误信息
if (error.errCode === -502005) {
return {
success: false,
message: '古诗不存在或已被删除'
}
} else if (error.errCode === -501000) {
return {
success: false,
message: '数据库连接失败'
}
} else {
return {
success: false,
message: '获取古诗详情失败: ' + error.message
}
}
}
}

@ -1,14 +0,0 @@
{
"name": "getPoemDetail",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"wx-server-sdk": "~3.0.1"
}
}

@ -1,381 +0,0 @@
const cloud = require('wx-server-sdk')
cloud.init({
env: 'cloud1-0g2sr1117862afae'
})
const db = cloud.database()
const poemsCollection = db.collection('poeties')
const _ = db.command
exports.main = async (event, context) => {
const { action, data, poemId, searchQuery, keyword, page = 1, pageSize = 20 } = event
try {
switch (action) {
case 'getAllPoems':
return await handleGetAllPoems(event);
case 'getPoemDetail':
return await getPoemDetail(event);
case 'getInitialPoems':
return await getInitialPoems()
case 'searchPoemsManager':
return await searchPoemsManager(searchQuery)
case 'searchPoems':
return await searchPoems(event)
case 'addPoem':
return await addPoem(data)
case 'updatePoem':
return await updatePoem(poemId, data)
case 'deletePoem':
return await deletePoem(poemId)
default:
return {
success: false,
message: '未知操作类型'
}
}
} catch (error) {
return {
success: false,
message: error.message
}
}
}
async function getPoemDetail(event){
const { id } = event;
console.log('获取古诗详情ID:', id)
try {
// 根据ID从poeties集合中获取古诗详情
const result = await db.collection('poeties')
.doc(id)
.get()
console.log('数据库查询结果:', result)
if (result.data) {
return {
success: true,
data: result.data
}
} else {
return {
success: false,
message: '古诗不存在'
}
}
} catch (error) {
console.error('获取古诗详情失败:', error)
// 更详细的错误信息
if (error.errCode === -502005) {
return {
success: false,
message: '古诗不存在或已被删除'
}
} else if (error.errCode === -501000) {
return {
success: false,
message: '数据库连接失败'
}
} else {
return {
success: false,
message: '获取古诗详情失败: ' + error.message
}
}
}
}
async function handleGetAllPoems(event) {
try {
const result = await db.collection('poeties')
.orderBy('title', 'asc')
.get();
return {
success: true,
data: {
poems: result.data,
total: result.data.length
}
};
} catch (error) {
console.error('获取诗词列表错误:', error);
return {
success: false,
message: '获取诗词失败'
};
}
}
// 获取初始的100条古诗
async function getInitialPoems() {
const result = await poemsCollection.limit(100).get()
return {
success: true,
data: result.data
}
}
// 搜索古诗
async function searchPoemsManager(searchQuery) {
const _ = db.command
const result = await poemsCollection.where(
_.or([
{
title: db.RegExp({
regexp: searchQuery,
options: 'i'
})
},
{
author: db.RegExp({
regexp: searchQuery,
options: 'i'
})
},
{
dynasty: db.RegExp({
regexp: searchQuery,
options: 'i'
})
},
{
content: db.RegExp({
regexp: searchQuery,
options: 'i'
})
},
{
translation: db.RegExp({
regexp: searchQuery,
options: 'i'
})
},
{
background: db.RegExp({
regexp: searchQuery,
options: 'i'
})
}
])
).get()
return {
success: true,
data: result.data
}
}
async function searchPoems(event){
const { keyword, page = 1, pageSize = 20 } = event;
console.log('搜索请求参数:', { keyword, page, pageSize })
try {
// 如果关键词为空,返回所有数据
if (!keyword || keyword.trim() === '') {
const allData = await db.collection('poeties') // 注意集合名称
.orderBy('title', 'asc')
.skip((page - 1) * pageSize)
.limit(pageSize)
.get()
const countResult = await db.collection('poeties').count()
return {
success: true,
data: {
poems: allData.data,
total: countResult.total,
page,
pageSize
}
}
}
const searchKeyword = keyword.trim()
console.log('搜索关键词:', searchKeyword)
// 根据你的数据结构构建搜索条件
const searchCondition = _.or([
{
title: db.RegExp({
regexp: searchKeyword,
options: 'i'
})
},
{
author: db.RegExp({
regexp: searchKeyword,
options: 'i'
})
},
{
content: db.RegExp({
regexp: searchKeyword,
options: 'i'
})
},
{
dynasty: db.RegExp({
regexp: searchKeyword,
options: 'i'
})
},
{
'author_info.name': db.RegExp({
regexp: searchKeyword,
options: 'i'
})
},
{
theme: db.RegExp({
regexp: searchKeyword,
options: 'i'
})
},
{
type: db.RegExp({
regexp: searchKeyword,
options: 'i'
})
}
])
console.log('搜索条件:', searchCondition)
// 执行搜索查询 - 使用正确的集合名称 poeties
const [dataResult, countResult] = await Promise.all([
db.collection('poeties')
.where(searchCondition)
.orderBy('title', 'asc')
.skip((page - 1) * pageSize)
.limit(pageSize)
.get(),
db.collection('poeties')
.where(searchCondition)
.count()
])
console.log('搜索结果:', {
找到数据条数: dataResult.data.length,
总条数: countResult.total
})
// 打印第一条数据检查结构
if (dataResult.data.length > 0) {
console.log('第一条数据样例:', JSON.stringify(dataResult.data[0], null, 2))
}
return {
success: true,
data: {
poems: dataResult.data,
total: countResult.total,
page,
pageSize
}
}
} catch (error) {
console.error('搜索云函数错误:', error)
return {
success: false,
message: '搜索失败: ' + error.message,
error: error.message
}
}
}
// 添加古诗
async function addPoem(poemData) {
if (!poemData.title || !poemData.dynasty || !poemData.author || !poemData.content) {
return {
success: false,
message: '缺少必要字段'
}
}
const newPoem = {
title: poemData.title,
dynasty: poemData.dynasty,
author: poemData.author,
content: poemData.content,
translation: poemData.translation || '',
background: poemData.background || '',
author_info: poemData.author_info || {},
theme: poemData.theme || [],
type: poemData.type || '诗',
createTime: db.serverDate(),
updateTime: db.serverDate()
}
const result = await poemsCollection.add({
data: newPoem
})
return {
success: true,
data: result,
message: '添加成功'
}
}
// 更新古诗
async function updatePoem(poemId, updateData) {
if (!poemId) {
return {
success: false,
message: '古诗ID不能为空'
}
}
if (!updateData.title || !updateData.dynasty || !updateData.author || !updateData.content) {
return {
success: false,
message: '缺少必要字段'
}
}
const updateInfo = {
title: updateData.title,
dynasty: updateData.dynasty,
author: updateData.author,
content: updateData.content,
translation: updateData.translation || '',
background: updateData.background || '',
author_info: updateData.author_info || {},
theme: updateData.theme || [],
type: updateData.type || '诗',
updateTime: db.serverDate()
}
const result = await poemsCollection.doc(poemId).update({
data: updateInfo
})
return {
success: true,
data: result,
message: '更新成功'
}
}
// 删除古诗
async function deletePoem(poemId) {
if (!poemId) {
return {
success: false,
message: '古诗ID不能为空'
}
}
const result = await poemsCollection.doc(poemId).remove()
return {
success: true,
data: result,
message: '删除成功'
}
}

@ -1,481 +0,0 @@
// cloudfunctions/reviewManagement/index.js
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV
})
const db = cloud.database()
const _ = db.command
const reviewCollection = db.collection('Review')
exports.main = async (event, context) => {
const {
action,
reviewData,
recordId,
openid,
poemId,
page = 1,
pageSize = 20
} = event
try {
switch (action) {
case 'addReviewRecord':
return await addReviewRecord(reviewData)
case 'getReviewRecord':
return await getReviewRecord(recordId)
case 'getUserReviews':
return await getUserReviews(openid, page, pageSize)
case 'getPoemReviews':
return await getPoemReviews(poemId, page, pageSize)
case 'deleteReviewRecord':
return await deleteReviewRecord(recordId)
case 'getReviewStats':
return await getReviewStats(openid)
case 'checkExistingRecord': // 检查是否存在记录
return await checkExistingRecord(poemId, openid)
case 'updateReviewRecord': // 更新已有记录
return await updateReviewRecord(recordId, reviewData)
default:
return {
success: false,
message: `未知操作: ${action}`
}
}
} catch (error) {
console.error('云函数执行失败:', {
message: error.message,
code: error.code,
stack: error.stack,
error: JSON.stringify(error)
})
// 统一的错误处理逻辑
if (error.code === -502001) {
return {
success: false,
message: '数据库权限不足,请确认云函数配置正确'
}
} else if (error.code === -502007) {
return {
success: false,
message: '数据库请求超时,请稍后重试'
}
} else if (error.code === -502023) {
return {
success: false,
message: '数据库容量已满,请联系管理员'
}
} else if (error.code === -404011) {
return {
success: false,
message: '云函数权限不足,请检查云函数配置'
}
} else if (error.code === -502005) {
return {
success: false,
message: '数据库集合不存在,请确保数据库初始化成功',
errorCode: error.code,
errorDetail: '请尝试重新初始化数据库,或检查集合名称是否正确'
}
} else {
return {
success: false,
message: `服务器错误: ${error.message || error}`,
errorCode: error.code,
errorDetail: process.env.NODE_ENV === 'production' ? '详细信息已记录' : String(error)
}
}
}
}
// 检查是否已存在该用户该诗歌的记录
async function checkExistingRecord(poemId, openid) {
if (!poemId || !openid) {
return {
success: false,
message: '古诗ID和用户ID不能为空'
}
}
try {
console.log('检查是否存在记录poemId:', poemId, 'openid:', openid);
const result = await reviewCollection
.where({
poemId: poemId,
openid: openid
})
.orderBy('reciteDateTime', 'desc')
.limit(1)
.get()
console.log('查询结果:', result);
if (result.data && result.data.length > 0) {
const existingRecord = result.data[0];
console.log('找到已存在记录ID:', existingRecord._id);
return {
success: true,
exists: true,
recordId: existingRecord._id,
recordData: existingRecord
}
} else {
console.log('未找到已存在记录');
return {
success: true,
exists: false,
recordId: null
}
}
} catch (error) {
console.error('检查记录失败:', error);
throw error;
}
}
// 更新已有背诵记录
async function updateReviewRecord(recordId, reviewData) {
if (!recordId) {
return {
success: false,
message: '记录ID不能为空'
}
}
// 验证必要字段
if (!reviewData || !reviewData.poemId || !reviewData.openid) {
return {
success: false,
message: '缺少必要字段'
}
}
// 详细日志记录输入数据
console.log('更新记录 - 接收到的原始reviewData数据结构:', Object.keys(reviewData).join(', '))
console.log('更新记录 - 接收到的reviewData是否包含content字段:', reviewData.hasOwnProperty('content'))
console.log('更新记录 - 接收到的reviewData是否包含score字段:', reviewData.hasOwnProperty('score'))
// 先从传入的数据中删除content和score字段确保不被保存
if (reviewData.hasOwnProperty('content')) {
console.warn('更新记录 - 发现并删除content字段:', reviewData.content)
delete reviewData.content;
}
if (reviewData.hasOwnProperty('score')) {
console.warn('更新记录 - 发现并删除score字段:', reviewData.score)
delete reviewData.score;
}
// 详细日志记录清理后的数据
console.log('更新记录 - 清理后reviewData的数据结构:', Object.keys(reviewData).join(', '))
// 准备更新数据,只包含需要更新的字段
const updateData = {};
updateData.poemName = reviewData.poemName || ''; // 古诗名称
updateData.accuracy = Number(reviewData.accuracy) || 0; // 正确率,确保是数字类型
updateData.duration = Number(reviewData.duration) || 0; // 背诵时长(秒),确保是数字类型
updateData.reciteDateTime = reviewData.reciteDateTime || new Date().toISOString(); // 背诵时间
updateData.updateTime = db.serverDate(); // 更新时间
// 再次明确确认updateData中没有content和score字段
if (updateData.hasOwnProperty('content')) {
console.error('更新记录 - 警告: updateData中仍存在content字段将被强制删除!')
delete updateData.content;
}
if (updateData.hasOwnProperty('score')) {
console.error('更新记录 - 警告: updateData中仍存在score字段将被强制删除!')
delete updateData.score;
}
// 详细日志记录最终更新的数据
console.log('更新记录 - 最终准备更新的数据结构:', Object.keys(updateData).join(', '))
console.log('更新记录 - 最终准备更新的数据:', JSON.stringify(updateData))
try {
// 执行更新操作
const result = await reviewCollection.doc(recordId).update({
data: updateData
})
console.log('背诵记录更新成功ID:', recordId, '更新结果:', result)
// 返回结果
return {
success: true,
_id: recordId,
message: '背诵记录更新成功',
updatedFields: Object.keys(updateData), // 返回实际更新的字段列表,便于调试
stats: result.stats // 返回更新统计信息
}
} catch (error) {
if (error.errCode === -502005) {
return {
success: false,
message: '背诵记录不存在或已被删除'
}
}
throw error
}
}
// 添加背诵记录
async function addReviewRecord(reviewData) {
// 验证必要字段
if (!reviewData || !reviewData.poemId || !reviewData.openid) {
return {
success: false,
message: '缺少必要字段'
}
}
// 详细日志记录输入数据
console.log('接收到的原始reviewData数据结构:', Object.keys(reviewData).join(', '))
console.log('接收到的reviewData是否包含content字段:', reviewData.hasOwnProperty('content'))
console.log('接收到的reviewData是否包含score字段:', reviewData.hasOwnProperty('score'))
// 先从传入的数据中删除content和score字段确保不被保存
if (reviewData.hasOwnProperty('content')) {
console.warn('发现并删除content字段:', reviewData.content)
delete reviewData.content;
}
if (reviewData.hasOwnProperty('score')) {
console.warn('发现并删除score字段:', reviewData.score)
delete reviewData.score;
}
// 详细日志记录清理后的数据
console.log('清理后reviewData的数据结构:', Object.keys(reviewData).join(', '))
// 准备数据,只包含需要的字段 - 使用全新对象创建,不继承任何其他属性
const dataToSave = {};
dataToSave.openid = reviewData.openid; // 用户ID必填
dataToSave.poemId = reviewData.poemId; // 古诗ID必填
dataToSave.poemName = reviewData.poemName || ''; // 古诗名称与古诗ID挨着放
dataToSave.accuracy = Number(reviewData.accuracy) || 0; // 正确率,确保是数字类型
dataToSave.duration = Number(reviewData.duration) || 0; // 背诵时长(秒),确保是数字类型
dataToSave.reciteDateTime = reviewData.reciteDateTime || new Date().toISOString(); // 背诵时间
dataToSave.createTime = db.serverDate(); // 服务器时间
// 再次明确确认dataToSave中没有content和score字段
if (dataToSave.hasOwnProperty('content')) {
console.error('警告: dataToSave中仍存在content字段将被强制删除!')
delete dataToSave.content;
}
if (dataToSave.hasOwnProperty('score')) {
console.error('警告: dataToSave中仍存在score字段将被强制删除!')
delete dataToSave.score;
}
// 详细日志记录最终保存的数据
console.log('最终准备保存的数据结构:', Object.keys(dataToSave).join(', '))
console.log('最终准备保存的背诵记录数据:', JSON.stringify(dataToSave))
// 执行保存操作
const result = await reviewCollection.add({
data: dataToSave
})
console.log('背诵记录保存成功ID:', result._id)
// 返回结果
return {
success: true,
_id: result._id,
message: '背诵记录添加成功',
savedFields: Object.keys(dataToSave) // 返回实际保存的字段列表,便于调试
}
}
// 获取单条背诵记录详情
async function getReviewRecord(recordId) {
if (!recordId) {
return {
success: false,
message: '记录ID不能为空'
}
}
try {
const result = await reviewCollection.doc(recordId).get()
if (result.data) {
return {
success: true,
data: result.data
}
} else {
return {
success: false,
message: '背诵记录不存在'
}
}
} catch (error) {
if (error.errCode === -502005) {
return {
success: false,
message: '背诵记录不存在或已被删除'
}
}
throw error
}
}
// 获取用户的背诵记录列表
async function getUserReviews(openid, page = 1, pageSize = 20) {
if (!openid) {
return {
success: false,
message: '用户ID不能为空'
}
}
try {
// 查询总数
const countResult = await reviewCollection.where({
openid: openid
}).count()
// 查询分页数据
const dataResult = await reviewCollection.where({
openid: openid
})
.orderBy('reciteDateTime', 'desc')
.skip((page - 1) * pageSize)
.limit(pageSize)
.get()
return {
success: true,
data: {
reviews: dataResult.data,
total: countResult.total,
page,
pageSize
}
}
} catch (error) {
console.error('获取用户背诵记录失败:', error)
throw error
}
}
// 获取某首诗的所有背诵记录
async function getPoemReviews(poemId, page = 1, pageSize = 20) {
if (!poemId) {
return {
success: false,
message: '古诗ID不能为空'
}
}
try {
// 查询总数
const countResult = await reviewCollection.where({
poemId: poemId
}).count()
// 查询分页数据
const dataResult = await reviewCollection.where({
poemId: poemId
})
.orderBy('reciteDateTime', 'desc')
.skip((page - 1) * pageSize)
.limit(pageSize)
.get()
return {
success: true,
data: {
reviews: dataResult.data,
total: countResult.total,
page,
pageSize
}
}
} catch (error) {
console.error('获取古诗背诵记录失败:', error)
throw error
}
}
// 删除背诵记录
async function deleteReviewRecord(recordId) {
if (!recordId) {
return {
success: false,
message: '记录ID不能为空'
}
}
try {
const result = await reviewCollection.doc(recordId).remove()
return {
success: true,
message: '背诵记录删除成功',
data: result
}
} catch (error) {
if (error.errCode === -502005) {
return {
success: false,
message: '背诵记录不存在或已被删除'
}
}
throw error
}
}
// 获取用户背诵统计信息
async function getReviewStats(openid) {
if (!openid) {
return {
success: false,
message: '用户ID不能为空'
}
}
try {
// 查询总背诵次数
const totalCount = await reviewCollection.where({
openid: openid
}).count()
// 查询今日背诵次数
const today = new Date()
today.setHours(0, 0, 0, 0)
const todayCount = await reviewCollection.where({
openid: openid,
reciteDateTime: _.gte(today)
}).count()
// 查询平均正确率(如果有这个字段)
const avgResult = await reviewCollection.aggregate()
.match({
openid: openid
})
.group({
_id: null,
avgAccuracy: _.avg('$accuracy'),
avgScore: _.avg('$score'),
avgDuration: _.avg('$duration')
})
.end()
return {
success: true,
data: {
totalReviews: totalCount.total,
todayReviews: todayCount.total,
avgAccuracy: avgResult.list[0]?.avgAccuracy || 0,
avgScore: avgResult.list[0]?.avgScore || 0,
avgDuration: avgResult.list[0]?.avgDuration || 0
}
}
} catch (error) {
console.error('获取背诵统计失败:', error)
throw error
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 471 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 429 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 MiB

@ -1,16 +0,0 @@
{
"files.autoSave": "afterDelay",
"workbench.startupEditor": "readme",
"explorer.compactFolders": false,
"editor.formatOnSave": true,
"files.exclude": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true,
"**/Thumbs.db": true,
"**/*.crswap": true,
".tcb_tmp": true
}
}

@ -1,5 +0,0 @@
# 云函数空白模板
此模板为云函数的空白文档,使用 Nodejs 运行环境部署。
运行后会返回:{"hello":"world"},以及请求参数,环境参数。

@ -1,248 +0,0 @@
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV
})
const db = cloud.database()
exports.main = async (event, context) => {
const { action } = event
try {
switch (action) {
case 'loginWithCode':
return await handleLoginWithCode(event)
case 'registerUser':
return await handleRegisterUser(event)
case 'getUserByOpenid':
return await handleGetUserByOpenid(event);
default:
return {
success: false,
message: '未知操作'
}
}
} catch (error) {
console.error('云函数执行错误:', error)
return {
success: false,
message: '服务器内部错误'
}
}
}
// 使用code登录
async function handleLoginWithCode(event) {
const { code } = event
if (!code) {
return {
success: false,
message: '缺少code参数'
}
}
try {
// 1. 通过code调用微信接口获取openid
const authResult = await getOpenIdByCode(code)
if (!authResult.openid) {
return {
success: false,
message: '获取openid失败'
}
}
const openid = authResult.openid
// 2. 通过openid查询数据库
const userResult = await db.collection('users')
.where({
openid: openid
})
.get()
// 3. 如果查询到用户数据,完成登录流程
if (userResult.data.length > 0) {
const user = userResult.data[0]
return {
success: true,
data: {
userInfo: {
_id: user._id,
openid: user.openid,
nickname: user.nickname,
avatarUrl: user.avatarUrl,
role: user.role,
reviewedPoems: user.reviewedPoems,
learningStats: user. learningStats,
}
}
}
} else {
// 4. 如果查询不到用户返回未注册状态和openid
return {
success: false,
message: '用户未注册',
code: 'USER_NOT_REGISTERED',
openid: openid
}
}
} catch (error) {
console.error('登录处理错误:', error)
return {
success: false,
message: '登录失败'
}
}
}
// 注册用户
async function handleRegisterUser(event) {
const { openid, userInfo } = event
if (!openid || !userInfo) {
return {
success: false,
message: '缺少必要参数'
}
}
try {
// 直接创建新用户
const newUser = {
openid: openid,
nickname: userInfo.nickName || '勤奋的小朋友',
avatarUrl: userInfo.avatarUrl || 'defaultAvatar',
createdAt: db.serverDate(),
updatedAt: db.serverDate(),
role: true,
reviewedPoems:{},
// 复习相关数据直接嵌入在用户文档中
learningStats: {
totalLearned: 0,
totalReviewed: 0,
lastLearnDate: null
}
}
// 先查询用户是否存在
const existingUser = await db.collection('users')
.where({ openid: openid })
.get()
let userId
let finalUser
if (existingUser.data.length > 0) {
// 用户存在,更新信息
await db.collection('users')
.where({ openid: openid })
.update({
data:{
updatedAt: newUser.updatedAt
}
})
userId = existingUser.data[0]._id
const updatedUser = await db.collection('users').doc(userId).get()
finalUser = updatedUser.data
}else{
const addResult = await db.collection('users').add({
data: newUser
})
userId = addResult._id
// 获取新创建的用户信息
const user = await db.collection('users').doc(addResult._id).get()
finalUser = user.data
}
// 返回创建的用户信息
return {
success: true,
data: {
userInfo: {
_id: userId,
openid: finalUser.openid,
nickname: finalUser.nickname,
avatarUrl: finalUser.avatarUrl,
role: finalUser.role,
reviewedPoems: finalUser.reviewedPoems|| {},
learningStats: finalUser.learningStats|| {
totalLearned: 0,
totalReviewed: 0,
lastLearnDate: null
}
}
}
}
} catch (error) {
console.error('注册用户错误:', error)
return {
success: false,
message: '注册失败'
}
}
}
// 通过code获取openid
async function getOpenIdByCode(code) {
// 在云函数中我们可以直接获取到openid不需要再用code换取
// 因为云函数自动包含了用户身份信息
const wxContext = cloud.getWXContext()
return {
openid: wxContext.OPENID,
appid: wxContext.APPID,
unionid: wxContext.UNIONID
}
}
async function handleGetUserByOpenid(event) {
const { openid } = event;
if (!openid) {
return {
success: false,
message: '缺少openid参数'
};
}
try {
const userResult = await db.collection('users')
.where({ openid: openid })
.get();
if (userResult.data.length > 0) {
const user = userResult.data[0];
return {
success: true,
data: {
userInfo: {
_id: user._id,
openid: user.openid,
nickname: user.nickname,
avatarUrl: user.avatarUrl,
role: user.role,
reviewedPoems: user.reviewedPoems || {},
learningStats: user.learningStats || {
totalLearned: 0,
totalReviewed: 0,
lastLearnDate: null
}
}
}
};
} else {
return {
success: false,
message: '用户不存在'
};
}
} catch (error) {
console.error('获取用户信息错误:', error);
return {
success: false,
message: '获取用户信息失败'
};
}
}

@ -1,9 +0,0 @@
{
"name": "auth",
"version": "1.0.0",
"description": "用户认证云函数",
"main": "index.js",
"dependencies": {
"wx-server-sdk": "~2.6.3"
}
}

@ -1,16 +0,0 @@
{
"files.autoSave": "afterDelay",
"workbench.startupEditor": "readme",
"explorer.compactFolders": false,
"editor.formatOnSave": true,
"files.exclude": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true,
"**/Thumbs.db": true,
"**/*.crswap": true,
".tcb_tmp": true
}
}

@ -1,5 +0,0 @@
# 云函数空白模板
此模板为云函数的空白文档,使用 Nodejs 运行环境部署。
运行后会返回:{"hello":"world"},以及请求参数,环境参数。

@ -1,9 +0,0 @@
{
"name": "poemManagement",
"version": "1.0.0",
"description": "古诗管理云函数",
"main": "index.js",
"dependencies": {
"wx-server-sdk": "~2.6.3"
}
}

@ -1,134 +0,0 @@
Page({
data: {
ifEntry: false,
userInfo: null
},
onLoad(options) {
// 页面加载时先检查本地缓存
this.checkLocalLoginStatus();
},
// 检查本地登录状态(快速检查)
checkLocalLoginStatus() {
try {
const cachedUserInfo = wx.getStorageSync('userInfo');
if (cachedUserInfo) {
this.setData({
ifEntry: true,
userInfo: cachedUserInfo
});
console.log('从缓存读取用户信息:', cachedUserInfo);
} else {
this.setData({
ifEntry: false,
userInfo: null
});
}
} catch (error) {
console.error('读取缓存失败:', error);
this.setData({ ifEntry: false });
}
},
//检查登录状态
async checkLoginStatus() {
try {
// 强制清除缓存,确保从服务器获取最新的用户信息
this.clearStorage();
// 先检查本地是否有缓存
const cachedUserInfo = wx.getStorageSync('userInfo');
if (cachedUserInfo) {
console.log('使用缓存用户信息,直接进入主页');
this.setData({
ifEntry: true,
userInfo: cachedUserInfo
});
// 调试日志:查看缓存中的用户角色值
console.log('缓存用户角色值:', cachedUserInfo.role, '类型:', typeof cachedUserInfo.role);
// 有缓存时直接跳转到主页 - 安全比较,处理不同类型的值
if (cachedUserInfo.role === true || cachedUserInfo.role === 'true') {
console.log('缓存中为普通用户跳转到index页面');
wx.reLaunch({
url: `/pages/index/index?openid=${cachedUserInfo.openid}`
});
} else {
console.log('缓存中为管理员跳转到managePoem页面');
wx.reLaunch({
url: `/pages/managePoems/managePoems?openid=${cachedUserInfo.openid}`
});
}
return; // 跳转后可以return避免后续代码执行
}
// 1. 如果没有缓存,调用 wx.login() 获取 code
const loginRes = await wx.login();
const code = loginRes.code;
if (!code) {
console.error('获取code失败');
return;
}
// 2. 调用后端登录接口将code传给后端
const result = await wx.cloud.callFunction({
name: 'auth',
data: {
action: 'loginWithCode',
code: code
}
});
if (result.result.success) {
const userInfo = result.result.data.userInfo;
wx.setStorageSync('userInfo', userInfo);
// 登录成功,直接进入用户页面
this.setData({
ifEntry: true,
userInfo: userInfo
});
// 调试日志:查看用户角色值
console.log('用户角色值:', userInfo.role, '类型:', typeof userInfo.role);
// 跳转到用户首页 - 安全比较,处理不同类型的值
if (userInfo.role === true || userInfo.role === 'true') {
console.log('普通用户跳转到index页面');
wx.reLaunch({
url: `/pages/index/index?openid=${userInfo.openid}`
});
} else {
console.log('管理员跳转到managePoems页面');
wx.reLaunch({
url: `/pages/managePoems/managePoems?openid=${userInfo.openid}`
});
}
} else {
// 登录失败
console.error('登录失败:', result.result.message);
this.setData({
ifEntry: false
});
const openid = result.result.openid || '';
wx.reLaunch({
url: `/pages/login/login?openid=${openid}`
});
}
} catch (error) {
console.error('检查登录状态失败:', error);
this.clearStorage();
}
},
clearStorage() {
wx.removeStorageSync('token');
wx.removeStorageSync('userInfo');
this.setData({ ifEntry: false });
},
// 进入按钮
async request_enter() {
this.checkLoginStatus();
}
});

@ -1,219 +0,0 @@
Page({
data: {
userInfo: {},
openid: '',
poems: [], // 所有诗词列表
reviewedPoems: [], // 需要复习的诗词
otherPoems: [], // 其他诗词
isLoading: false
},
onLoad(options) {
console.log('首页加载完成');
if (options.openid) {
this.setData({
openid: options.openid
});
console.log('获取到openid:', options.openid);
// 根据openid加载用户数据和诗词数据
this.loadUserDataAndPoems();
} else {
console.error('未收到openid参数');
wx.showToast({
title: '参数错误',
icon: 'none'
});
}
},
// 加载用户数据和诗词数据
async loadUserDataAndPoems() {
try {
this.setData({ isLoading: true });
// 并行执行:获取用户信息和诗词列表
const [userResult, poemsResult] = await Promise.all([
this.getUserInfo(this.data.openid),
this.getAllPoems()
]);
if (userResult.success) {
const userInfo = userResult.data.userInfo;
this.setData({
userInfo: userInfo
});
}
if (poemsResult.success) {
const allPoems = poemsResult.data.poems;
// 获取用户的复习记录
const reviewResult = await this.getUserReviewRecords(this.data.openid);
const reviewedPoemIds = reviewResult.success ? reviewResult.data.reviews.map(item => item.poemId) : [];
// 分类诗词:把需要复习的古诗放到末尾
const { reviewedPoems, otherPoems, poems } = this.classifyPoems(allPoems, reviewedPoemIds);
this.setData({
poems: poems,
reviewedPoems: reviewedPoems,
otherPoems: otherPoems
});
console.log('复习诗词数量:', reviewedPoems.length);
console.log('其他诗词数量:', otherPoems.length);
}
} catch (error) {
console.error('加载数据失败:', error);
wx.showToast({
title: '加载失败',
icon: 'none'
});
} finally {
this.setData({ isLoading: false });
}
},
// 从Review表获取用户的复习记录
async getUserReviewRecords(openid) {
try {
const result = await wx.cloud.callFunction({
name: 'reviewManagement',
data: {
action: 'getUserReviews',
openid: openid,
page: 1,
pageSize: 100 // 获取所有复习记录
}
});
return result.result;
} catch (error) {
console.error('获取复习记录失败:', error);
return { success: false, message: '获取复习记录失败' };
}
},
// 获取用户信息
async getUserInfo(openid) {
try {
const result = await wx.cloud.callFunction({
name: 'auth',
data: {
action: 'getUserByOpenid',
openid: openid
}
});
return result.result;
} catch (error) {
console.error('获取用户信息失败:', error);
return { success: false, message: '获取用户信息失败' };
}
},
// 获取所有诗词
async getAllPoems() {
try {
const result = await wx.cloud.callFunction({
name: 'poemManagement',
data: {
action: 'getAllPoems'
}
});
return result.result;
} catch (error) {
console.error('获取诗词列表失败:', error);
return { success: false, message: '获取诗词失败' };
}
},
// 分类诗词:把需要复习的古诗放到末尾
classifyPoems(allPoems, reviewedPoemIds) {
const reviewedPoems = [];
const otherPoems = [];
allPoems.forEach(poem => {
if (reviewedPoemIds.includes(poem._id)) {
// 需要复习的诗词
reviewedPoems.push(poem);
} else {
// 其他诗词
otherPoems.push(poem);
}
});
// 把需要复习的诗词放到其他诗词的末尾
const finalPoems = [...otherPoems, ...reviewedPoems];
return {
reviewedPoems: reviewedPoems,
otherPoems: otherPoems,
poems: finalPoems // 最终的诗词列表,复习的放在末尾
};
},
// 进入学习页面
goToStudy(e) {
const poemId = e.currentTarget.dataset.id;
wx.navigateTo({
url: `/pages/study/study?id=${poemId}`
});
},
// 进入背诵页面
goToRecite(e) {
const poemId = e.currentTarget.dataset.id;
console.log('跳转到背诵页面诗歌ID:', poemId);
const poem = this.data.poems.find(p => p._id === poemId);
if (poemId && poem) {
wx.navigateTo({
url: `/pages/recite/recite?id=${poemId}&title=${encodeURIComponent(poem.title)}&author=${encodeURIComponent(poem.author)}`
});
}
},
review(){
const userInfo = this.data.userInfo;
console.log('跳转到复习页面,用户信息:', userInfo);
wx.navigateTo({
url: `/pages/review/review?userInfo=${encodeURIComponent(JSON.stringify(userInfo))}`
})
},
question(){
wx.navigateTo({
url: '/pages/question/question'
})
},
search(){
wx.navigateTo({
url: '/pages/search/search'
})
},
onShow() {
// 每次显示页面时检查数据
if (this.data.openid && this.data.poems.length === 0 && !this.data.isLoading) {
this.loadUserDataAndPoems();
}
},
onPullDownRefresh() {
if (this.data.openid) {
this.loadUserDataAndPoems().finally(() => {
wx.stopPullDownRefresh();
});
} else {
wx.stopPullDownRefresh();
}
},
onShareAppMessage() {
return {
title: '古诗学习小程序',
path: '/pages/index/index'
};
}
})

@ -1,66 +0,0 @@
// pages/keyWord/keyWord.js
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})

@ -1,2 +0,0 @@
<!--pages/keyWord/keyWord.wxml-->
<text>pages/keyWord/keyWord.wxml</text>

@ -1,168 +0,0 @@
// pages/login/login.js
Page({
/**
* 页面的初始数据
*/
data: {
isLoading: false ,// 默认不显示提示文字
errorLoading: false,
openid:''
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
// 接收从guiding页面传递的openid
if (options.openid) {
this.setData({
openid: options.openid
});
console.log('接收到的openid:', options.openid);
} else {
wx.showToast({
title: '参数错误',
icon: 'none'
});
setTimeout(() => {
wx.navigateBack();
}, 1500);
}
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
},
async request_login() {
try {
this.setData({ isLoading: true });
// 获取用户授权信息
const { userInfo } = await wx.getUserProfile({
desc: '用于古诗学习助手的登录授权'
});
console.log('授权成功', userInfo);
this.setData({ isLoading: false });
// 调用注册接口
await this.registerUser(userInfo);
} catch (err) {
console.log('授权失败', err);
this.setData({
isLoading: false,
errorLoading: true
});
wx.showToast({
title: '授权失败,请重试',
icon: 'none'
});
}
},
// 注册用户方法
async registerUser(userInfo) {
try {
console.log('开始注册用户openid:', this.data.openid);
const result = await wx.cloud.callFunction({
name: 'auth',
data: {
action: 'registerUser',
openid: this.data.openid, // 使用传递的openid
userInfo: userInfo
}
});
console.log('注册结果:', result);
if (result.result.success) {
const userData = result.result.data.userInfo;
// 保存用户信息到本地
wx.setStorageSync('userInfo', userData);
this.setData({ isLoading: false });
wx.showToast({
title: '注册成功',
icon: 'success',
success: () => {
// 注册成功后跳转
setTimeout(() => {
// 根据用户角色决定跳转页面role为false时是管理员跳转到pendingQuestion页面
if (userData.role === false) {
wx.reLaunch({
url: `/pages/managePoems/managePoems?openid=${this.data.openid}`
});
} else {
wx.reLaunch({
url: `/pages/index/index?openid=${this.data.openid}`
});
}
}, 1500);
}
});
} else {
throw new Error(result.result.message || '注册失败');
}
} catch (error) {
console.error('注册失败:', error);
this.setData({ isLoading: false });
wx.showToast({
title: '注册失败: ' + error.message,
icon: 'none'
});
}
}
})

@ -1,10 +0,0 @@
<!--pages/login/login.wxml-->
<view class="container">
<view class="guiding_text">古诗学习助手</view>
<text wx:if="{{isLoading}}" class="loading_text">正在请求微信授权...</text>
<text wx:if="{{errorLoading}}" class="loading_text">微信授权失败,请重新登录</text>
<button catch:tap="request_login">微信授权登录</button>
<text class="login_text2">登录即同意用户协议</text>
</view>

@ -1,365 +0,0 @@
Page({
data: {
poems: [], // 当前显示的古诗列表
searchQuery: '',
showModal: false,
editingPoem: false,
currentPoem: {
_id: '',
title: '',
dynasty: '',
author: '',
content: '',
translation: '',
background: '',
author_info: {},
theme: [],
type: '诗'
},
selectedPoemId: '',
isSearchMode: false // 标记当前是否为搜索模式
},
onLoad(options) {
this.loadInitialPoems();
},
// 加载初始的100条古诗
loadInitialPoems() {
wx.showLoading({
title: '加载中...',
});
wx.cloud.callFunction({
name: 'poemManagement',
data: {
action: 'getInitialPoems'
}
}).then(res => {
if (res.result.success) {
const poems = res.result.data.map(item => ({
_id: item._id,
title: item.title || '',
dynasty: item.dynasty || '',
author: item.author || '',
content: item.content || '',
translation: item.translation || '',
background: item.background || '',
author_info: item.author_info || {},
theme: item.theme || [],
type: item.type || '诗'
}));
this.setData({
poems: poems,
isSearchMode: false
});
} else {
throw new Error(res.result.message || '加载失败');
}
wx.hideLoading();
}).catch(error => {
wx.hideLoading();
wx.showToast({
title: '加载失败',
icon: 'none'
});
});
},
onSearchInput(e) {
this.setData({
searchQuery: e.detail.value
});
},
onSearch() {
const { searchQuery } = this.data;
if (!searchQuery.trim()) {
// 如果搜索框为空,回到初始状态
this.loadInitialPoems();
return;
}
wx.showLoading({
title: '搜索中...',
});
wx.cloud.callFunction({
name: 'poemManagement',
data: {
action: 'searchPoemsManager',
searchQuery: searchQuery
}
}).then(res => {
if (res.result.success) {
const searchedPoems = res.result.data.map(item => ({
_id: item._id,
title: item.title || '',
dynasty: item.dynasty || '',
author: item.author || '',
content: item.content || '',
translation: item.translation || '',
background: item.background || '',
author_info: item.author_info || {},
theme: item.theme || [],
type: item.type || '诗'
}));
this.setData({
poems: searchedPoems,
isSearchMode: true
});
} else {
throw new Error(res.result.message || '搜索失败');
}
wx.hideLoading();
}).catch(error => {
wx.hideLoading();
wx.showToast({
title: '搜索失败',
icon: 'none'
});
});
},
onPoemSelect(e) {
const id = e.currentTarget.dataset.id;
this.setData({
selectedPoemId: id
});
},
onAddPoem() {
this.setData({
showModal: true,
editingPoem: false,
currentPoem: {
_id: '',
title: '',
dynasty: '',
author: '',
content: '',
translation: '',
background: '',
author_info: {},
theme: [],
type: '诗'
}
});
},
onEditPoem(e) {
const id = e.currentTarget.dataset.id;
const poem = this.data.poems.find(p => p._id === id);
if (poem) {
this.setData({
showModal: true,
editingPoem: true,
currentPoem: { ...poem }
});
}
},
onDeletePoem(e) {
const id = e.currentTarget.dataset.id;
const poem = this.data.poems.find(p => p._id === id);
wx.showModal({
title: '确认删除',
content: `确定要删除《${poem.title}》吗?`,
success: (res) => {
if (res.confirm) {
this.deletePoemFromCloud(id);
}
}
});
},
closeModal() {
this.setData({
showModal: false
});
},
onTitleInput(e) {
this.setData({
'currentPoem.title': e.detail.value
});
},
onDynastyInput(e) {
this.setData({
'currentPoem.dynasty': e.detail.value
});
},
onAuthorInput(e) {
this.setData({
'currentPoem.author': e.detail.value
});
},
onContentInput(e) {
this.setData({
'currentPoem.content': e.detail.value
});
},
onTranslationInput(e) {
this.setData({
'currentPoem.translation': e.detail.value
});
},
onBackgroundInput(e) {
this.setData({
'currentPoem.background': e.detail.value
});
},
deletePoemFromCloud(poemId) {
wx.showLoading({
title: '删除中...',
});
wx.cloud.callFunction({
name: 'poemManagement',
data: {
action: 'deletePoem',
poemId: poemId
}
}).then(res => {
if (res.result.success) {
// 从当前显示的列表中移除
const updatedPoems = this.data.poems.filter(p => p._id !== poemId);
this.setData({
poems: updatedPoems
});
wx.hideLoading();
wx.showToast({
title: '删除成功',
icon: 'success'
});
} else {
throw new Error(res.result.message || '删除失败');
}
}).catch(error => {
wx.hideLoading();
wx.showToast({
title: '删除失败',
icon: 'none'
});
});
},
savePoem() {
const { currentPoem, editingPoem } = this.data;
if (!currentPoem.title.trim()) {
wx.showToast({
title: '请输入古诗名称',
icon: 'none'
});
return;
}
if (!currentPoem.dynasty.trim()) {
wx.showToast({
title: '请输入朝代',
icon: 'none'
});
return;
}
if (!currentPoem.author.trim()) {
wx.showToast({
title: '请输入作者姓名',
icon: 'none'
});
return;
}
if (!currentPoem.content.trim()) {
wx.showToast({
title: '请输入古诗内容',
icon: 'none'
});
return;
}
wx.showLoading({
title: '保存中...',
});
const saveData = {
title: currentPoem.title.trim(),
dynasty: currentPoem.dynasty.trim(),
author: currentPoem.author.trim(),
content: currentPoem.content.trim(),
translation: currentPoem.translation ? currentPoem.translation.trim() : '',
background: currentPoem.background ? currentPoem.background.trim() : '',
author_info: currentPoem.author_info || {},
theme: currentPoem.theme || [],
type: currentPoem.type || '诗'
};
const cloudFunctionData = {
action: editingPoem ? 'updatePoem' : 'addPoem',
data: saveData
};
if (editingPoem) {
cloudFunctionData.poemId = currentPoem._id;
}
wx.cloud.callFunction({
name: 'poemManagement',
data: cloudFunctionData
}).then(res => {
if (res.result.success) {
wx.hideLoading();
this.setData({
showModal: false
});
// 重新加载当前视图
if (this.data.isSearchMode) {
// 如果是搜索模式,重新搜索
this.onSearch();
} else {
// 如果是初始模式,重新加载初始数据
this.loadInitialPoems();
}
wx.showToast({
title: editingPoem ? '修改成功' : '添加成功',
icon: 'success'
});
} else {
throw new Error(res.result.message || '保存失败');
}
}).catch(error => {
wx.hideLoading();
wx.showToast({
title: '保存失败',
icon: 'none'
});
});
},
goToPendingQuestion() {
wx.navigateTo({
url: '/pages/pendingQuestion/pendingQuestion'
});
},
goToManagePoems() {
// 已经在当前页面
}
})

@ -1,166 +0,0 @@
// pages/chat/chat.js
Page({
data: {
messages: [],
inputText: '',
loading: false,
scrollTop: 0
},
onLoad: function () {
// 初始化对话历史
this.setData({
messages: [
{
role: 'assistant',
content: '你好!我是古诗答疑助手,有什么可以帮你的吗?'
}
]
});
},
// 输入框内容变化
onInput: function (e) {
this.setData({
inputText: e.detail.value
});
},
// 发送消息
sendMessage: function () {
const message = this.data.inputText.trim();
// 检查是否正在加载或消息为空
if (this.data.loading || !message) {
if (!message) {
wx.showToast({
title: '请输入消息',
icon: 'none',
duration: 1500
});
}
return;
}
// 添加用户消息到对话列表
const userMessage = { role: 'user', content: message };
const newMessages = [...this.data.messages, userMessage];
this.setData({
messages: newMessages,
inputText: '',
loading: true
});
// 调用千帆API
this.callQianfanAPI(message, newMessages);
// 滚动到底部
this.scrollToBottom();
},
// 调用百度千帆API
callQianfanAPI: function (message, history) {
const that = this;
// 构建对话历史
const messages = [
{
role: 'system',
content: '你是一个有帮助的AI助手请用中文回答用户的问题。'
}
];
// 添加历史对话(除了系统消息)
history.forEach(msg => {
if (msg.role !== 'system') {
messages.push({
role: msg.role,
content: msg.content
});
}
});
// 直接调用千帆API
wx.request({
url: 'https://qianfan.baidubce.com/v2/chat/completions',
method: 'POST',
header: {
'Content-Type': 'application/json',
'Authorization': 'Bearer bce-v3/ALTAK-DFIVQomhzBnBkgnV1oKld/fed2a317eb41c155dd323bf779a1b8936085390d'
},
data: {
model: 'deepseek-v3.1-250821',
messages: messages,
stream: false
},
success: function (res) {
console.log('千帆API调用成功', res);
if (res.data && res.data.choices && res.data.choices[0]) {
const aiMessage = {
role: 'assistant',
content: res.data.choices[0].message.content
};
that.setData({
messages: [...that.data.messages, aiMessage],
loading: false
});
} else {
that.showError('API返回格式错误');
}
// 滚动到底部
that.scrollToBottom();
},
fail: function (err) {
console.error('千帆API调用失败', err);
that.showError('网络请求失败,请重试');
}
});
},
// 显示错误信息
showError: function (message) {
wx.showToast({
title: message,
icon: 'none',
duration: 2000
});
this.setData({
loading: false
});
},
// 滚动到底部
scrollToBottom: function () {
setTimeout(() => {
this.setData({
scrollTop: 99999
});
}, 100);
},
// 清空对话
clearChat: function () {
wx.showModal({
title: '提示',
content: '确定要清空对话吗?',
success: (res) => {
if (res.confirm) {
this.setData({
messages: [
{
role: 'assistant',
content: '你好!我是古诗答疑助手,有什么可以帮你的吗?'
}
],
inputText: '',
loading: false
});
}
}
});
}
});

@ -1,935 +0,0 @@
const recorderManager = wx.getRecorderManager()
const options = {
duration: 60000,//指定录音的时长,单位 ms
sampleRate: 16000,//采样率
numberOfChannels: 1,//录音通道数
encodeBitRate: 48000,//编码码率
format: 'pcm',//音频格式,有效值 aac/mp3
}
var filesize,tempFilePath
Page({
/**
* 页面的初始数据
*/
data: {
token:'',
content:'',
poemId: '',
poemTitle: '',
poemAuthor: '',
originalText: '',
accuracyRate: 0,
showResult: false,
startReciteTime: 0, // 开始背诵时间
reciteDuration: '', // 背诵时长
reciteDateTime: '', // 背诵时间
openid: '' ,// 添加 openid
isRecording: false, // 是否正在录音
isProcessing: false, // 是否正在处理语音
recognitionProgress: 0, // 识别进度
lastRecognitionTime: 0, // 上次识别时间(用于防抖)
existingRecordId: null // 新增已存在记录的ID
},
onLoad(options) {
console.log('背诵页面参数:', options);
// 接收从学习页面传递的参数
if (options.poemData) {
try {
console.log('原始poemData参数:', options.poemData);
// 尝试直接解析
let poemData;
try {
poemData = JSON.parse(options.poemData);
console.log('直接解析成功');
} catch (firstError) {
console.log('直接解析失败尝试URL解码:', firstError);
// 尝试一次URL解码
try {
const decodedOnce = decodeURIComponent(options.poemData);
poemData = JSON.parse(decodedOnce);
console.log('一次URL解码成功');
} catch (secondError) {
console.log('一次URL解码失败尝试二次URL解码:', secondError);
// 尝试二次URL解码处理双重编码的情况
try {
const decodedTwice = decodeURIComponent(decodeURIComponent(options.poemData));
poemData = JSON.parse(decodedTwice);
console.log('二次URL解码成功');
} catch (thirdError) {
console.log('所有解析方式都失败,使用备用方案:', thirdError);
// 使用备用方案
this.fallbackToIdOnly(options);
return;
}
}
}
console.log('从学习页面传递的诗歌数据:', poemData);
this.setData({
poemId: poemData._id || options.id,
poemTitle: poemData.title || '',
poemAuthor: poemData.author || '',
originalText: poemData.content || '' // 直接从传递的数据中获取原文
});
// 设置导航栏标题为诗歌名称
this.setNavigationBarTitle(poemData.title || '背诵');
} catch (error) {
console.error('解析诗歌数据失败:', error);
// 如果解析失败,使用备用方案
this.fallbackToIdOnly(options);
}
}
// 接收从index页面传递的参数
else if (options.id && options.title && options.author) {
try {
const poemTitle = this.safeDecodeURIComponent(options.title);
const poemAuthor = this.safeDecodeURIComponent(options.author);
this.setData({
poemId: options.id,
poemTitle: poemTitle,
poemAuthor: poemAuthor
});
// 设置导航栏标题
this.setNavigationBarTitle(poemTitle);
// 获取古诗原文
this.getPoemDetail(options.id);
} catch (error) {
console.error('处理标题和作者参数失败:', error);
this.fallbackToIdOnly(options);
}
}
// 只传递了id的情况
else if (options.id) {
this.setData({
poemId: options.id
});
// 获取古诗原文
this.getPoemDetail(options.id);
} else {
console.error('缺少必要的参数');
wx.showToast({
title: '参数错误',
icon: 'none'
});
setTimeout(() => {
wx.navigateBack();
}, 1500);
}
//获取用户openid
this.getUserOpenId();
//获取storge中的token
let that=this;
wx.getStorage({
key:'expires_in',
success(res){
console.log("缓存中有access_token")
console.log("token失效时间",res.data)
const newT = new Date().getTime();
// 用当前时间和存储的时间判断token是否已过期
if (newT > parseInt(res.data)) {
console.log("token过期重新获取token")
that.getToken();
} else {
console.log("获取本地缓存的token")
that.setData({
token:wx.getStorageSync('access_token')
});
}
},fail(){
console.log("缓存中没有access_token")
that.getToken();
}
});
},
// 安全的URL解码函数
safeDecodeURIComponent(str) {
try {
return decodeURIComponent(str);
} catch (error) {
console.log('URL解码失败返回原字符串:', error);
return str;
}
},
// 备用方案只使用ID
fallbackToIdOnly(options) {
console.log('使用备用方案仅通过ID获取数据');
if (options.id) {
this.setData({
poemId: options.id
});
// 获取古诗详情
this.getPoemDetail(options.id);
} else {
wx.showToast({
title: '无法获取诗歌数据',
icon: 'none'
});
setTimeout(() => {
wx.navigateBack();
}, 1500);
}
},
// 获取用户 openid
async getUserOpenId() {
try {
const res = await wx.cloud.callFunction({
name: 'getOpenId'
})
this.setData({
openid: res.result.openid
})
console.log('获取用户openid:', this.data.openid)
} catch (error) {
console.error('获取openid失败:', error)
}
},
// 检查是否已存在该用户该诗歌的记录
async checkExistingRecord(poemId, openid) {
try {
console.log('检查是否已存在记录poemId:', poemId, 'openid:', openid);
const result = await wx.cloud.callFunction({
name: 'reviewManagement',
data: {
action: 'checkExistingRecord',
poemId: poemId,
openid: openid
}
});
console.log('检查记录结果:', result);
if (result && result.result && result.result.success) {
if (result.result.exists) {
console.log('已存在记录记录ID:', result.result.recordId);
this.setData({
existingRecordId: result.result.recordId
});
return true;
} else {
console.log('不存在记录,将创建新记录');
this.setData({
existingRecordId: null
});
return false;
}
} else {
console.log('检查记录失败,默认创建新记录');
this.setData({
existingRecordId: null
});
return false;
}
} catch (error) {
console.error('检查记录时出错:', error);
this.setData({
existingRecordId: null
});
return false;
}
},
// 修改保存背诵记录方法,支持更新已有记录
async saveReviewRecord(reviewData) {
try {
console.log('开始保存背诵记录');
console.log('传入的reviewData完整内容:', JSON.stringify(reviewData));
console.log('传入的reviewData数据结构:', Object.keys(reviewData || {}).join(', '));
// 验证必要字段
if (!reviewData || !reviewData.poemId || !reviewData.openid) {
console.error('缺少必要字段');
wx.showToast({
title: '数据保存失败:缺少必要字段',
icon: 'none'
});
return false;
}
// 先检查并删除可能存在的content和score字段
if (reviewData.hasOwnProperty('content')) {
console.warn('前端发现content字段将被删除:', reviewData.content);
delete reviewData.content;
}
if (reviewData.hasOwnProperty('score')) {
console.warn('前端发现score字段将被删除:', reviewData.score);
delete reviewData.score;
}
// 详细日志记录清理后的数据结构
console.log('前端清理后reviewData的数据结构:', Object.keys(reviewData).join(', '));
// 创建一个全新的干净对象,不继承任何原型属性,只包含我们需要的字段
const dataToSave = {};
dataToSave.openid = reviewData.openid;
dataToSave.poemId = reviewData.poemId;
dataToSave.poemName = reviewData.poemName || this.data.poemTitle || '';
dataToSave.accuracy = Number(reviewData.accuracy || 0);
dataToSave.duration = Number(reviewData.duration || 0);
dataToSave.reciteDateTime = reviewData.reciteDateTime || new Date().toISOString();
// 再次检查dataToSave中是否存在content和score字段
if (dataToSave.hasOwnProperty('content')) {
console.error('警告: 前端dataToSave中仍存在content字段将被强制删除!');
delete dataToSave.content;
}
if (dataToSave.hasOwnProperty('score')) {
console.error('警告: 前端dataToSave中仍存在score字段将被强制删除!');
delete dataToSave.score;
}
// 详细日志记录最终发送的数据
console.log('前端最终发送到数据库的数据结构:', Object.keys(dataToSave).join(', '));
console.log('前端最终发送到数据库的数据:', JSON.stringify(dataToSave));
// 先检查是否已存在记录
const hasExistingRecord = await this.checkExistingRecord(dataToSave.poemId, dataToSave.openid);
let result;
if (hasExistingRecord && this.data.existingRecordId) {
// 更新已有记录
console.log('更新已有记录记录ID:', this.data.existingRecordId);
result = await wx.cloud.callFunction({
name: 'reviewManagement',
data: {
action: 'updateReviewRecord',
recordId: this.data.existingRecordId,
reviewData: dataToSave
}
});
} else {
// 创建新记录
console.log('创建新记录');
result = await wx.cloud.callFunction({
name: 'reviewManagement',
data: {
action: 'addReviewRecord',
reviewData: dataToSave
}
});
}
// 处理结果
if (result && result.result && result.result.success) {
console.log('背诵记录保存成功:', result.result._id);
console.log('云函数返回的保存字段列表:', result.result.savedFields?.join(', ') || '未知');
// 如果是新增记录保存记录ID
if (!hasExistingRecord && result.result._id) {
this.setData({
existingRecordId: result.result._id
});
}
return true;
} else {
console.error('背诵记录保存失败:', result.result?.message || '未知错误');
return false;
}
} catch (error) {
console.error('保存背诵记录异常:', error);
return false;
}
},
// 计算背诵难度
calculateDifficulty(duration, originalText) {
// 基于原文长度和背诵时间计算难度
const textLength = (originalText || '').length;
const avgSpeed = textLength / Math.max(1, duration);
if (textLength > 200 || avgSpeed < 0.5) {
return 'difficult';
} else if (textLength > 100 || avgSpeed < 1) {
return 'medium';
} else {
return 'easy';
}
},
// 获取古诗详情
async getPoemDetail(poemId) {
try {
console.log('调用云函数获取古诗详情ID:', poemId);
const result = await wx.cloud.callFunction({
name: 'poemManagement',
data: {
action: 'getPoemDetail',
id: poemId
}
});
console.log('云函数返回结果:', result);
if (result.result && result.result.success) {
// 直接使用result.result.data因为云函数返回的结构是{success: true, data: poem对象}
const poem = result.result.data;
this.setData({
originalText: poem.content || ''
});
console.log('获取到古诗原文:', this.data.originalText);
} else {
const errorMessage = result.result?.message || '获取古诗详情失败';
console.error('获取古诗详情失败:', errorMessage);
wx.showToast({
title: errorMessage,
icon: 'none'
});
}
} catch (error) {
console.error('获取古诗详情出错:', error);
wx.showToast({
title: '网络错误,请重试',
icon: 'none'
});
}
},
// 清理文本,去除标点符号和空白字符
cleanText(text) {
if (!text) return '';
// 转换为字符串
text = String(text);
// 去除所有空格(包括全角空格)、换行符、制表符
text = text.replace(/[\s\n\t\u3000]/g, '');
// 去除所有标点符号(包括中文标点)
text = text.replace(/[\p{P}\p{S}]/gu, '');
// 去除所有特殊符号
text = text.replace(/[!"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~]/g, '');
console.log('清理后的文本:', text);
return text;
},
// 计算文本相似度(正确率)
calculateAccuracy(recognizedText, originalText) {
const cleanedRecognized = this.cleanText(recognizedText);
const cleanedOriginal = this.cleanText(originalText);
console.log('清理后的识别文本:', cleanedRecognized);
console.log('清理后的原文:', cleanedOriginal);
console.log('原文长度:', cleanedOriginal.length);
if (!cleanedOriginal || cleanedOriginal.length === 0) {
console.log('原文为空或长度为0');
return 0;
}
if (!cleanedRecognized || cleanedRecognized.length === 0) {
console.log('识别文本为空或长度为0');
return 0;
}
// 使用动态规划计算最长公共子序列长度
const m = cleanedRecognized.length;
const n = cleanedOriginal.length;
const dp = Array(m + 1).fill().map(() => Array(n + 1).fill(0));
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
if (cleanedRecognized[i - 1] === cleanedOriginal[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
const lcsLength = dp[m][n];
console.log('最长公共子序列长度:', lcsLength);
// 计算正确率(以原文长度为基准)
const accuracyRate = Math.round((lcsLength / cleanedOriginal.length) * 100);
console.log('计算得到的正确率:', accuracyRate + '%');
return accuracyRate;
},
// 检查背诵结果
// 修改 checkRecitation 方法,在计算完正确率后保存记录
async checkRecitation() {
console.log('开始检查背诵结果');
console.log('当前识别文本类型:', typeof this.data.content);
console.log('当前识别文本内容:', this.data.content);
console.log('当前古诗原文:', this.data.originalText);
// 确保content是字符串格式
let contentText = this.data.content;
console.log('开始处理识别文本格式...');
if (Array.isArray(contentText)) {
console.log('识别文本是数组格式,长度:', contentText.length);
// 处理可能的嵌套数组情况
if (contentText.length > 0 && Array.isArray(contentText[0])) {
console.log('识别文本是嵌套数组');
contentText = contentText[0].join('');
} else {
contentText = contentText.join('');
}
} else if (contentText !== null && contentText !== undefined) {
console.log('识别文本不是数组,转换为字符串');
contentText = String(contentText);
} else {
console.log('识别文本为空');
contentText = '';
}
console.log('处理后的识别文本:', contentText);
if (!contentText || contentText.trim() === '') {
wx.showToast({
title: '请先进行录音',
icon: 'none'
});
console.log('识别文本为空,无法检查');
return;
}
if (!this.data.originalText || this.data.originalText.trim() === '') {
wx.showToast({
title: '获取古诗原文失败',
icon: 'none'
});
console.log('古诗原文为空,无法检查');
// 尝试重新获取古诗原文
if (this.data.poemId) {
console.log('尝试重新获取古诗原文');
this.getPoemDetail(this.data.poemId);
}
return;
}
// 计算正确率
const accuracyRate = this.calculateAccuracy(contentText, this.data.originalText);
console.log('检查背诵结果完成,正确率:', accuracyRate + '%');
// 计算背诵时长
let reciteDuration = '';
let durationSeconds = 0;
if (this.data.startReciteTime > 0) {
const endTime = new Date().getTime();
const durationMs = endTime - this.data.startReciteTime;
durationSeconds = Math.floor(durationMs / 1000);
// 格式化时长显示 (MM:SS)
const minutes = Math.floor(durationSeconds / 60);
const seconds = durationSeconds % 60;
reciteDuration = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
console.log('背诵时长:', reciteDuration);
} else {
reciteDuration = '--:--';
console.log('未记录开始时间,无法计算背诵时长');
}
// 记录和格式化背诵时间
const now = new Date();
const year = now.getFullYear();
const month = (now.getMonth() + 1).toString().padStart(2, '0');
const day = now.getDate().toString().padStart(2, '0');
const hours = now.getHours().toString().padStart(2, '0');
const minutes = now.getMinutes().toString().padStart(2, '0');
const reciteDateTime = `${year}-${month}-${day} ${hours}:${minutes}`;
console.log('背诵时间:', reciteDateTime);
// 准备保存到数据库的数据包含所有必要字段确保古诗ID和古诗名挨着放
const reviewRecord = {
openid: this.data.openid, // 用户ID
poemId: this.data.poemId, // 古诗ID
poemName: this.data.poemTitle, // 古诗名称与古诗ID挨着放
accuracy: accuracyRate, // 正确率
duration: durationSeconds, // 背诵时长(秒)
reciteDateTime: reciteDateTime // 背诵时间
};
// 先显示结果然后异步保存避免UI阻塞
this.setData({
accuracyRate: accuracyRate,
showResult: true,
reciteDuration: reciteDuration,
reciteDateTime: reciteDateTime
});
// 异步保存到数据库
try {
const saveSuccess = await this.saveReviewRecord(reviewRecord);
if (saveSuccess) {
console.log('背诵记录保存成功');
// saveReviewRecord 内部已经有成功提示
} else {
console.log('背诵记录保存失败,但不影响结果显示');
// 不重复显示错误提示saveReviewRecord 内部已经处理
}
} catch (err) {
console.error('保存背诵记录时发生异常:', err);
// 异常已在 saveReviewRecord 内部处理
}
// 延迟显示根据正确率的提示消息,避免与保存结果提示重叠
setTimeout(() => {
console.log('背诵正确率:', accuracyRate + '%');
console.log('背诵时长:', reciteDuration);
// 根据正确率给出提示
let message = '';
if (accuracyRate >= 90) {
message = '太棒了!背诵得很准确!';
} else if (accuracyRate >= 70) {
message = '不错的背诵!继续加油!';
} else if (accuracyRate >= 50) {
message = '还可以,再练习一下会更好!';
} else {
message = '需要多练习,加油!';
}
wx.showToast({
title: message,
icon: 'none',
duration: 2000
});
}, 1000); // 延迟1秒显示提示消息
},
/**
* 重置背诵状态清除识别结果和正确率
*/
resetRecitation: function() {
console.log('重置背诵状态');
// 重置所有相关数据
this.setData({
content: '',
showResult: false,
accuracyRate: 0,
startReciteTime: 0,
reciteDuration: '',
reciteDateTime: '',
isRecording: false,
isProcessing: false,
recognitionProgress: 0
// 注意:不重置 existingRecordId因为重新背诵时还是同一首诗
});
// 停止所有可能的录音
try {
recorderManager.stop();
} catch (e) {
console.log('停止录音时出错:', e);
}
wx.hideLoading();
wx.hideToast();
console.log('重置完成,准备新的背诵');
},
/**
* 当用户编辑识别结果时触发
*/
onContentInput(e) {
console.log('用户编辑了识别结果', e.detail.value);
this.setData({
content: e.detail.value
});
},
// 获取token
getToken:function(){
let that=this;
let ApiKey='qdHcePu7v0WpIlJnaeGJZZqp';
let SecretKey='nuZCuBziZoO2gjE6NGEMKCdxKs4sbaNq';
const url = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id='+ApiKey+'&client_secret='+SecretKey
wx.request({
url:url,
method: 'POST',
success(res){
console.log("创建access_token成功",res)
//将access_token存储到storage中
wx.setStorage({
key:'access_token',
data:res.data.access_token
});
var date=new Date().getTime();
let time=date+2592000*1000;
console.log('三十天后的时间',time);
wx.setStorage({
key:'expires_in',
data:time
});
that.setData({
token:res.data.access_token
});
},
fail(err) {
console.error('获取token失败:', err);
}
});
},
//开始录音
touchStart: function () {
const that = this;
// 防抖处理,避免快速重复点击
const now = Date.now();
if (now - this.data.lastRecognitionTime < 2000) {
console.log("操作过于频繁,请稍后再试");
return;
}
wx.authorize({
scope: 'scope.record',
success() {
console.log("录音授权成功");
// 记录开始背诵的时间
const startTime = new Date().getTime();
console.log('开始背诵时间:', startTime);
that.setData({
startReciteTime: startTime,
isRecording: true,
isProcessing: false,
recognitionProgress: 0,
lastRecognitionTime: now
});
// 显示录音中状态
wx.showToast({
title: '录音中...',
icon: 'none',
duration: 60000 // 最长60秒
});
recorderManager.start(options);
recorderManager.onStart(() => {
console.log('recorder start');
that.setData({
isRecording: true
});
});
// 开始进度模拟(让用户感知进度)
that.startProgressSimulation();
},
fail() {
console.log("录音授权失败");
wx.showToast({
title: '需要麦克风权限',
icon: 'none'
});
}
});
},
//停止录音
touchEnd: function () {
let that = this;
if (!this.data.isRecording) {
return;
}
this.setData({
isRecording: false,
isProcessing: true,
recognitionProgress: 50 // 切换到处理阶段
});
// 隐藏录音Toast显示处理Toast
wx.hideToast();
wx.showLoading({
title: '识别中...',
mask: true
});
recorderManager.stop();
recorderManager.onStop((res) => {
console.log('录音停止,文件路径:', res.tempFilePath);
tempFilePath = res.tempFilePath;
// 更新进度
that.setData({
recognitionProgress: 70
});
// 获取文件长度并开始识别
wx.getFileSystemManager().getFileInfo({
filePath: tempFilePath,
success: function (res) {
filesize = res.size;
console.log('文件长度:', res.size);
that.setData({
recognitionProgress: 80
});
that.shibie();
},
fail: function (res) {
console.log("读取文件长度错误", res);
that.recognitionFailed("文件读取失败");
}
});
});
},
//语音识别
shibie() {
let that = this;
// 更新进度
this.setData({
recognitionProgress: 90
});
wx.getFileSystemManager().readFile({
filePath: tempFilePath,
encoding: 'base64',
success: function (res) {
console.log("开始语音识别请求");
// 设置请求超时
const requestTask = wx.request({
url: 'http://vop.baidu.com/server_api',
data: {
token: that.data.token,
cuid: "12_56",
format: 'pcm',
rate: 16000,
channel: 1,
speech: res.data,
len: filesize
},
headers: {
'Content-Type': 'application/json'
},
method: "post",
timeout: 10000, // 10秒超时
success: function (res) {
wx.hideLoading();
if (res.data.result == '' || !res.data.result) {
that.recognitionFailed('听不清楚,请重新说一遍!');
return;
}
console.log("识别成功:", res.data);
let recognizedText = res.data.result;
// 快速处理识别结果
recognizedText = that.processRecognitionResult(recognizedText);
that.setData({
content: recognizedText,
isProcessing: false,
recognitionProgress: 100
});
console.log('语音识别完成,识别文本:', recognizedText);
// 短暂显示成功状态
wx.showToast({
title: '识别完成',
icon: 'success',
duration: 1000
});
// 自动检查背诵结果(可选)
setTimeout(() => {
that.checkRecitation();
}, 500);
},
fail: function (res) {
that.recognitionFailed('网络请求失败,请重试');
}
});
// 可以取消请求(如果需要)
// that.requestTask = requestTask;
},
fail: function (res) {
that.recognitionFailed('文件读取失败');
}
});
},
// 快速处理识别结果
processRecognitionResult(recognizedText) {
if (Array.isArray(recognizedText)) {
// 百度API的标准格式是返回字符串数组如["识别结果"]
if (recognizedText.length > 0) {
// 直接取第一个结果,不进行复杂处理
recognizedText = recognizedText[0];
} else {
recognizedText = "";
}
}
// 确保是字符串
if (recognizedText !== null && recognizedText !== undefined) {
recognizedText = String(recognizedText);
} else {
recognizedText = "";
}
// 简单的文本清理(去除明显错误字符)
recognizedText = recognizedText.replace(/[^\u4e00-\u9fa5a-zA-Z0-9\s""''()《》]/g, '');
return recognizedText;
},
// 开始进度模拟
startProgressSimulation() {
let progress = 0;
const interval = setInterval(() => {
if (!this.data.isRecording && !this.data.isProcessing) {
clearInterval(interval);
return;
}
if (this.data.isRecording) {
// 录音阶段缓慢增长到40%
progress = Math.min(40, progress + 1);
}
this.setData({
recognitionProgress: progress
});
if (progress >= 100) {
clearInterval(interval);
}
}, 100);
},
// 识别失败处理
recognitionFailed(message) {
wx.hideLoading();
this.setData({
isRecording: false,
isProcessing: false,
recognitionProgress: 0
});
wx.showModal({
title: '提示',
content: message,
showCancel: false,
success: () => {
// 重置状态
this.resetRecitation();
}
});
}
})

@ -1,69 +0,0 @@
<!--pages/recite/recite.wxml-->
<view class="recite-container">
<!-- 头部标题 -->
<view class="header">
<text class="title">背诵《{{poemTitle}}》</text>
<text class="subtitle">{{poemAuthor}}</text>
</view>
<!-- 语音识别结果 -->
<view class="recognition-section">
<text class="section-title">识别结果:</text>
<textarea class="result-textarea" placeholder='等待说话...' value='{{content}}' bindinput="onContentInput"></textarea>
</view>
<!-- 只在识别中显示进度条 -->
<view class="recognition-progress" wx:if="{{isProcessing}}">
<view class="progress-bar">
<view class="progress-inner" style="{{'width: ' + recognitionProgress + '%;'}}"></view>
</view>
<text class="progress-text">
识别中... {{recognitionProgress}}%
</text>
</view>
<!-- 简化录音按钮 -->
<button
class="record-btn {{isRecording ? 'recording' : ''}} {{isProcessing ? 'processing' : ''}}"
bindtouchstart="touchStart"
bindtouchend="touchEnd"
disabled="{{isProcessing}}"
>
{{isRecording ? '录音中...' : isProcessing ? '处理中...' : '按住录音'}}
</button>
<!-- 检查按钮 -->
<view class="check-section">
<button class="btn-check" type="primary" bindtap="checkRecitation" wx:if="{{content && !showResult}}">检查背诵</button>
</view>
<!-- 正确率显示 -->
<view class="result-section" wx:if="{{showResult}}">
<!-- 进度条样式正确率显示 -->
<view class="accuracy-progress-container">
<view class="accuracy-header">
<text class="accuracy-title">背诵评分</text>
<text class="accuracy-value">{{accuracyRate}}%</text>
</view>
<!-- 背诵时长和时间显示 -->
<view class="info-section">
<!-- 背诵用时 -->
<view class="info-item">
<text class="info-label">背诵用时</text>
<text class="info-value duration-value">{{reciteDuration}}</text>
</view>
<!-- 背诵时间 -->
<view class="info-item">
<text class="info-label">背诵时间</text>
<text class="info-value date-value">{{reciteDateTime}}</text>
</view>
</view>
<!-- 评价文字 -->
<text class="accuracy-comment">{{accuracyRate >= 90 ? '优秀!背诵得非常准确' : accuracyRate >= 70 ? '良好!继续保持' : accuracyRate >= 50 ? '一般,还需要练习' : '需要多加练习'}}</text>
</view>
<button class="btn-reset" type="default" bindtap="resetRecitation">重新背诵</button>
</view>
</view>

@ -1,264 +0,0 @@
/* pages/recite/recite.wxss */
.recite-container {
padding: 20rpx;
background-color: #f8f8f8;
min-height: 100vh;
box-sizing: border-box;
}
/* 头部样式 */
.header {
text-align: center;
margin-bottom: 40rpx;
padding: 30rpx 0;
background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%);
border-radius: 15rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}
.title {
font-size: 48rpx;
font-weight: bold;
color: #333;
display: block;
margin-bottom: 10rpx;
}
.subtitle {
font-size: 32rpx;
color: #666;
}
/* 原文和识别结果区域 */
.original-section,
.recognition-section {
background: #fff;
padding: 30rpx;
margin-bottom: 30rpx;
border-radius: 15rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
}
.section-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
display: block;
margin-bottom: 20rpx;
}
.original-text {
font-size: 34rpx;
line-height: 1.8;
color: #444;
white-space: pre-wrap;
word-break: break-all;
}
.result-textarea {
width: 100%;
min-height: 200rpx;
padding: 20rpx;
font-size: 34rpx;
line-height: 1.6;
color: #333;
background: #f9f9f9;
border: 1rpx solid #ddd;
border-radius: 10rpx;
box-sizing: border-box;
}
/* 正确率显示区域 */
.result-section {
text-align: center;
margin: 40rpx 0;
}
/* 进度条样式正确率显示 */
.accuracy-progress-container {
background: #fff;
padding: 40rpx;
border-radius: 20rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
margin-bottom: 30rpx;
}
.accuracy-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
}
/* 背诵信息显示区域 */
.info-section {
margin-bottom: 30rpx;
padding: 15rpx 0;
border-top: 1rpx solid #f0f0f0;
}
/* 信息项样式 */
.info-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10rpx 0;
}
.info-label {
font-size: 32rpx;
color: #666;
}
.info-value {
font-size: 34rpx;
font-weight: bold;
}
/* 背诵时长样式 */
.duration-value {
color: #007AFF;
letter-spacing: 2rpx;
}
/* 背诵时间样式 */
.date-value {
color: #34C759;
font-family: 'Courier New', monospace;
}
.accuracy-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
}
.accuracy-value {
font-size: 48rpx;
font-weight: bold;
color: #4CAF50;
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
}
/* 进度条容器 */
.progress-container {
margin: 40rpx 0;
padding: 0 30rpx;
}
/* 进度条背景 */
.progress-bg {
flex: 1;
height: 24rpx;
background-color: #f0f0f0;
border-radius: 12rpx;
overflow: hidden;
position: relative;
}
/* 进度条填充 */
.progress-fill {
height: 100%;
border-radius: 12rpx;
transition: width 0.5s ease-in-out, background 0.5s ease;
min-width: 0%;
}
/* 评价文字 */
.accuracy-comment {
font-size: 32rpx;
color: #666;
display: block;
padding: 20rpx 0;
background: #f9f9f9;
border-radius: 10rpx;
margin-top: 10rpx;
}
/* 检查按钮区域 */
.check-section {
text-align: center;
margin: 40rpx 0;
}
.btn-check {
width: 60%;
font-size: 36rpx;
padding: 20rpx 0;
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
border: none;
color: white;
}
/* 重置按钮 */
.btn-reset {
margin-top: 30rpx;
font-size: 32rpx;
width: 50%;
}
/* 控制按钮区域 */
.control-buttons {
display: flex;
justify-content: space-around;
margin-top: 40rpx;
padding-bottom: 40rpx;
}
.btn-record-start,
.btn-record-stop {
width: 280rpx;
font-size: 34rpx;
padding: 20rpx 0;
}
/* 语音识别进度条样式 */
.recognition-progress {
margin: 40rpx;
background: #fff;
padding: 30rpx;
border-radius: 15rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
}
.recognition-progress .progress-bar {
width: 100%;
height: 20rpx;
background: #eee;
border-radius: 10rpx;
overflow: hidden;
margin-bottom: 20rpx;
}
.recognition-progress .progress-inner {
height: 100%;
background: linear-gradient(90deg, #4CAF50, #45a049);
border-radius: 10rpx;
transition: width 0.3s ease;
}
.recognition-progress .progress-text {
font-size: 28rpx;
text-align: center;
margin-top: 20rpx;
color: #333;
display: block;
}
/* 录音按钮状态 */
.record-btn.recording {
background-color: #FF4757;
}
.record-btn.processing {
background-color: #FFA502;
opacity: 0.7;
}
/* 响应式设计 */
@media screen and (min-width: 768px) {
.recite-container {
max-width: 800rpx;
margin: 0 auto;
}
}

@ -1,271 +0,0 @@
// pages/search/search.js
Page({
/**
* 页面的初始数据
*/
data: {
keyword: '',
showResults: false,
searchResults: [],
searchHistory: [],
isLoading: false,
hasMore: true,
page: 1,
pageSize: 10,
total: 0
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.loadSearchHistory();
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
this.loadSearchHistory();
},
// 从本地存储加载搜索历史
loadSearchHistory() {
const history = wx.getStorageSync('searchHistory') || [];
this.setData({
searchHistory: history
});
},
// 输入处理
onInput(e) {
const value = e.detail.value;
this.setData({
keyword: value
});
// 如果输入为空,隐藏结果
if (!value.trim()) {
this.setData({
showResults: false,
searchResults: []
});
}
},
// 清空输入框
clearInput() {
console.log('clearInput called'); // 添加日志调试
this.setData({
keyword: '',
showResults: false,
searchResults: []
}, () => {
console.log('clearInput completed, keyword:', this.data.keyword); // 确认清空完成
});
},
// 执行搜索
async doSearch() {
const { keyword, page } = this.data;
if (!keyword.trim()) {
wx.showToast({
title: '请输入搜索关键词',
icon: 'none'
});
return;
}
// 显示加载状态
if (page === 1) {
this.setData({
isLoading: true
});
}
try {
// 调用云函数搜索
const result = await wx.cloud.callFunction({
name: 'poemManagement',
data: {
action: 'searchPoems',
keyword: keyword.trim(),
page: page,
pageSize: this.data.pageSize
}
});
if (result.result.success) {
const { poems, total } = result.result.data;
const newResults = page === 1 ? poems : [...this.data.searchResults, ...poems];
this.setData({
searchResults: newResults,
showResults: true,
total: total,
hasMore: (page * this.data.pageSize) < total,
isLoading: false
});
// 添加到搜索历史
this.addToHistory(keyword.trim());
// 显示搜索结果提示
if (page === 1 && poems.length > 0) {
wx.showToast({
title: `找到 ${total} 条结果`,
icon: 'success',
duration: 1500
});
}
} else {
wx.showToast({
title: result.result.message || '搜索失败',
icon: 'none'
});
this.setData({ isLoading: false });
// 如果云函数失败,使用模拟数据作为备选
this.useMockData(keyword);
}
} catch (error) {
console.error('搜索错误:', error);
wx.showToast({
title: '搜索失败,请检查网络',
icon: 'none'
});
this.setData({ isLoading: false });
}
},
// 通过历史记录搜索
searchByHistory(e) {
const keyword = e.currentTarget.dataset.keyword;
this.setData({
keyword: keyword,
page: 1,
searchResults: [],
hasMore: true
});
this.doSearch();
},
// 添加到搜索历史
addToHistory(keyword) {
let { searchHistory } = this.data;
// 移除已存在的相同关键词
searchHistory = searchHistory.filter(item => item !== keyword);
// 添加到最前面
searchHistory.unshift(keyword);
// 限制历史记录数量
if (searchHistory.length > 10) {
searchHistory = searchHistory.slice(0, 10);
}
// 保存到本地存储
wx.setStorageSync('searchHistory', searchHistory);
this.setData({
searchHistory: searchHistory
});
},
// 清除搜索历史
clearHistory() {
wx.showModal({
title: '确认清除',
content: '确定要清除所有搜索历史吗?',
success: (res) => {
if (res.confirm) {
wx.removeStorageSync('searchHistory');
this.setData({
searchHistory: []
});
}
}
});
},
// 跳转到学习页面
goToStudy(e) {
const poem = e.currentTarget.dataset.poem;
if (poem && poem._id) {
wx.navigateTo({
url: `/pages/study/study?id=${poem._id}`
});
} else {
const id = e.currentTarget.dataset.id;
if (id) {
wx.navigateTo({
url: `/pages/study/study?id=${id}`
});
} else {
wx.showToast({
title: '诗歌信息错误',
icon: 'none'
});
}
}
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
this.setData({
page: 1,
searchResults: [],
hasMore: true
});
if (this.data.keyword.trim()) {
this.doSearch().then(() => {
wx.stopPullDownRefresh();
});
} else {
wx.stopPullDownRefresh();
}
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
if (this.data.hasMore && !this.data.isLoading) {
this.setData({
page: this.data.page + 1
}, () => {
this.doSearch();
});
}
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})

@ -1,70 +0,0 @@
{
"libVersion": "3.10.2",
"projectname": "miniprogram-2",
"setting": {
"urlCheck": false,
"coverView": true,
"lazyloadPlaceholderEnable": false,
"skylineRenderEnable": false,
"preloadBackgroundData": false,
"autoAudits": false,
"showShadowRootInWxmlPanel": true,
"compileHotReLoad": true,
"useApiHook": true,
"useApiHostProcess": true,
"useStaticServer": false,
"useLanDebug": false,
"showES6CompileOption": false,
"checkInvalidKey": true,
"ignoreDevUnusedFiles": true,
"bigPackageSizeSupport": false
},
"condition": {
"miniprogram": {
"list": [
{
"name": "pages/guiding/guiding",
"pathName": "pages/guiding/guiding",
"query": "",
"scene": null,
"launchMode": "default"
},
{
"name": "pages/search/search",
"pathName": "pages/search/search",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "pages/review/review",
"pathName": "pages/review/review",
"query": "userInfo=%5Bobject%20Object%5D",
"launchMode": "default",
"scene": null
},
{
"name": "pages/index/index",
"pathName": "pages/index/index",
"query": "openid=oXrNu16e8evHW3pAyXuBHPL3lsZo",
"launchMode": "default",
"scene": null
},
{
"name": "pages/recite/recite",
"pathName": "pages/recite/recite",
"query": "id=poet_064&poemData=%257B%2522_id%2522%253A%2522poet_064%2522%252C%2522author%2522%253A%2522%25E6%259B%25B9%25E6%25A4%258D%2522%252C%2522author_info%2522%253A%257B%2522intro%2522%253A%2522%25E6%259B%25B9%25E6%25A4%258D%25EF%25BC%2588192%25E5%25B9%25B4%25E2%2580%2594232%25E5%25B9%25B4%25EF%25BC%2589%25EF%25BC%258C%25E5%25AD%2597%25E5%25AD%2590%25E5%25BB%25BA%25EF%25BC%258C%25E4%25B8%2589%25E5%259B%25BD%25E6%2597%25B6%25E6%259C%259F%25E8%2591%2597%25E5%2590%258D%25E6%2596%2587%25E5%25AD%25A6%25E5%25AE%25B6%25EF%25BC%258C%25E5%25BB%25BA%25E5%25AE%2589%25E6%2596%2587%25E5%25AD%25A6%25E7%259A%2584%25E4%25BB%25A3%25E8%25A1%25A8%25E4%25BA%25BA%25E7%2589%25A9%25E3%2580%2582%25E4%25B8%258E%25E6%259B%25B9%25E6%2593%258D%25E3%2580%2581%25E6%259B%25B9%25E4%25B8%2595%25E5%2590%2588%25E7%25A7%25B0'%25E4%25B8%2589%25E6%259B%25B9'%25E3%2580%2582%2522%252C%2522name%2522%253A%2522%25E6%259B%25B9%25E6%25A4%258D%2522%257D%252C%2522background%2522%253A%2522%25E8%25BF%2599%25E9%25A6%2596%25E8%25AF%2597%25E7%2594%25A8%25E5%2590%258C%25E6%25A0%25B9%25E8%2580%258C%25E7%2594%259F%25E7%259A%2584%25E8%2590%2581%25E5%2592%258C%25E8%25B1%2586%25E6%259D%25A5%25E6%25AF%2594%25E5%2596%25BB%25E5%2590%258C%25E7%2588%25B6%25E5%2585%25B1%25E6%25AF%258D%25E7%259A%2584%25E5%2585%2584%25E5%25BC%259F%25EF%25BC%258C%25E7%2594%25A8%25E8%2590%2581%25E7%2585%258E%25E5%2585%25B6%25E8%25B1%2586%25E6%259D%25A5%25E6%25AF%2594%25E5%2596%25BB%25E5%2590%258C%25E8%2583%259E%25E9%25AA%25A8%25E8%2582%2589%25E7%259A%2584%25E5%2593%25A5%25E5%2593%25A5%25E6%259B%25B9%25E4%25B8%2595%25E6%25AE%258B%25E5%25AE%25B3%25E5%25BC%259F%25E5%25BC%259F%25EF%25BC%258C%25E8%25A1%25A8%25E8%25BE%25BE%25E4%25BA%2586%25E5%25AF%25B9%25E6%259B%25B9%25E4%25B8%2595%25E7%259A%2584%25E5%25BC%25BA%25E7%2583%2588%25E4%25B8%258D%25E6%25BB%25A1%25EF%25BC%258C%25E7%2594%259F%25E5%258A%25A8%25E5%25BD%25A2%25E8%25B1%25A1%25E3%2580%2581%25E6%25B7%25B1%25E5%2585%25A5%25E6%25B5%2585%25E5%2587%25BA%25E5%259C%25B0%25E5%258F%258D%25E6%2598%25A0%25E4%25BA%2586%25E5%25B0%2581%25E5%25BB%25BA%25E7%25BB%259F%25E6%25B2%25BB%25E9%259B%2586%25E5%259B%25A2%25E5%2586%2585%25E9%2583%25A8%25E7%259A%2584%25E6%25AE%258B%25E9%2585%25B7%25E6%2596%2597%25E4%25BA%2589%25E5%2592%258C%25E8%25AF%2597%25E4%25BA%25BA%25E8%2587%25AA%25E8%25BA%25AB%25E5%25A4%2584%25E5%25A2%2583%25E8%2589%25B0%25E9%259A%25BE%25EF%25BC%258C%25E6%25B2%2589%25E9%2583%2581%25E6%2584%25A4%25E6%25BF%2580%25E7%259A%2584%25E6%2580%259D%25E6%2583%25B3%25E6%2584%259F%25E6%2583%2585%25E3%2580%2582%2522%252C%2522content%2522%253A%2522%25E7%2585%25AE%25E8%25B1%2586%25E7%2587%2583%25E8%25B1%2586%25E8%2590%2581%25EF%25BC%258C%25E8%25B1%2586%25E5%259C%25A8%25E9%2587%259C%25E4%25B8%25AD%25E6%25B3%25A3%25E3%2580%2582%255Cn%25E6%259C%25AC%25E6%2598%25AF%25E5%2590%258C%25E6%25A0%25B9%25E7%2594%259F%25EF%25BC%258C%25E7%259B%25B8%25E7%2585%258E%25E4%25BD%2595%25E5%25A4%25AA%25E6%2580%25A5%25EF%25BC%259F%2522%252C%2522dynasty%2522%253A%2522%25E4%25B8%2589%25E5%259B%25BD%2522%252C%2522theme%2522%253A%255B%2522%25E5%2585%2584%25E5%25BC%259F%2522%252C%2522%25E6%2594%25BF%25E6%25B2%25BB%2522%255D%252C%2522title%2522%253A%2522%25E4%25B8%2583%25E6%25AD%25A5%25E8%25AF%2597%2522%252C%2522translation%2522%253A%2522%25E9%2594%2585%25E9%2587%258C%25E7%2585%25AE%25E7%259D%2580%25E8%25B1%2586%25E5%25AD%2590%25EF%25BC%258C%25E8%25B1%2586%25E7%25A7%25B8%25E5%259C%25A8%25E9%2594%2585%25E5%25BA%2595%25E4%25B8%258B%25E7%2587%2583%25E7%2583%25A7%25EF%25BC%258C%25E8%25B1%2586%25E5%25AD%2590%25E5%259C%25A8%25E9%2594%2585%25E9%2587%258C%25E9%259D%25A2%25E5%2593%25AD%25E6%25B3%25A3%25E3%2580%2582%25E8%25B1%2586%25E5%25AD%2590%25E5%2592%258C%25E8%25B1%2586%25E7%25A7%25B8%25E6%259C%25AC%25E6%259D%25A5%25E6%2598%25AF%25E5%2590%258C%25E4%25B8%2580%25E6%259D%25A1%25E6%25A0%25B9%25E4%25B8%258A%25E7%2594%259F%25E9%2595%25BF%25E5%2587%25BA%25E6%259D%25A5%25E7%259A%2584%25EF%25BC%258C%25E8%25B1%2586%25E7%25A7%25B8%25E6%2580%258E%25E8%2583%25BD%25E8%25BF%2599%25E6%25A0%25B7%25E6%2580%25A5%25E8%25BF%25AB%25E5%259C%25B0%25E7%2585%258E%25E7%2586%25AC%25E8%25B1%2586%25E5%25AD%2590%25E5%2591%25A2%25EF%25BC%259F%2522%252C%2522type%2522%253A%2522%25E8%25AF%2597%2522%257D",
"launchMode": "default",
"scene": null
},
{
"name": "pages/study/study",
"pathName": "pages/study/study",
"query": "id=poet_064",
"launchMode": "default",
"scene": null
}
]
}
}
}

@ -0,0 +1,2 @@
古诗学习助手,用到微信小程序云开发环境# study_helper

@ -1,5 +1,4 @@
{
"pages": [
"pages/guiding/guiding",
"pages/login/login",
@ -8,20 +7,18 @@
"pages/search/search",
"pages/recite/recite",
"pages/review/review",
"pages/keyWord/keyWord",
"pages/question/question",
"pages/managePoems/managePoems"
],
"window": {
"navigationBarTitleText": "古诗学习助手",
"navigationBarTextStyle":"black",
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#FFFBF3",
"enablePullDownRefresh": true,
"backgroundColor": "#FFFFFF",
"backgroundTextStyle":"dark"
"backgroundTextStyle": "dark"
},
"style": "v2",
"sitemapLocation": "sitemap.json",
"lazyCodeLoading": "requiredComponents"
}

@ -0,0 +1,513 @@
/**
* 云函数主入口
* 处理用户认证相关的各种操作
*/
const cloud = require('wx-server-sdk')
/**
* 初始化云开发环境
*/
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV
})
/**
* 数据库实例
*/
const db = cloud.database()
/**
* 云函数主函数
* @param {Object} event - 事件参数
* @param {string} event.action - 操作类型
* @param {Object} context - 上下文对象
* @returns {Object} 执行结果
*/
exports.main = async (event, context) => {
const { action } = event
try {
switch (action) {
case 'loginWithCode':
return await handleLoginWithCode(event)
case 'registerUser':
return await handleRegisterUser(event)
case 'getUserByOpenid':
return await handleGetUserByOpenid(event)
case 'getOpenId':
return await getOpenIdByCode(event)
case 'checkFavorite': // 检查收藏状态
return await handleCheckFavorite(event)
case 'addFavorite': // 添加收藏
return await handleAddFavorite(event)
case 'removeFavorite': // 移除收藏
return await handleRemoveFavorite(event)
default:
return {
success: false,
message: '未知操作'
}
}
} catch (error) {
console.error('云函数执行错误:', error)
return {
success: false,
message: '服务器内部错误'
}
}
}
/**
* 使用微信登录code进行登录
* @param {Object} event - 事件参数
* @param {string} event.code - 微信登录code
* @returns {Object} 登录结果
*/
async function handleLoginWithCode(event) {
const { code } = event
if (!code) {
return {
success: false,
message: '缺少code参数'
}
}
try {
// 通过code获取用户openid
const authResult = await getOpenIdByCode(code)
if (!authResult.openid) {
return {
success: false,
message: '获取openid失败'
}
}
const openid = authResult.openid
// 查询数据库中是否存在该用户
const userResult = await db.collection('users')
.where({
openid: openid
})
.get()
// 如果用户存在,返回用户信息
if (userResult.data.length > 0) {
const user = userResult.data[0]
return {
success: true,
data: {
userInfo: {
_id: user._id,
openid: user.openid,
nickname: user.nickname,
avatarUrl: user.avatarUrl,
role: user.role,
favorites: finalUser.favorites || []
}
}
}
} else {
// 用户不存在,返回未注册状态
return {
success: false,
message: '用户未注册',
code: 'USER_NOT_REGISTERED',
openid: openid
}
}
} catch (error) {
console.error('登录处理错误:', error)
return {
success: false,
message: '登录失败'
}
}
}
/**
* 注册新用户
* @param {Object} event - 事件参数
* @param {string} event.openid - 用户openid
* @param {Object} event.userInfo - 用户信息
* @returns {Object} 注册结果
*/
async function handleRegisterUser(event) {
const { openid, userInfo } = event
if (!openid || !userInfo) {
return {
success: false,
message: '缺少必要参数'
}
}
try {
// 创建新用户数据对象
const newUser = {
openid: openid,
nickname: userInfo.nickName || '勤奋的小朋友',
avatarUrl: userInfo.avatarUrl || 'defaultAvatar',
createdAt: db.serverDate(),
updatedAt: db.serverDate(),
role: true,
favorites: userInfo.favorites || []
}
// 检查用户是否已存在
const existingUser = await db.collection('users')
.where({ openid: openid })
.get()
let userId
let finalUser
if (existingUser.data.length > 0) {
// 用户存在,更新信息
await db.collection('users')
.where({ openid: openid })
.update({
data:{
updatedAt: newUser.updatedAt
}
})
userId = existingUser.data[0]._id
const updatedUser = await db.collection('users').doc(userId).get()
finalUser = updatedUser.data
} else {
// 用户不存在,创建新用户
const addResult = await db.collection('users').add({
data: newUser
})
userId = addResult._id
// 获取新创建的用户信息
const user = await db.collection('users').doc(addResult._id).get()
finalUser = user.data
}
// 返回用户信息
return {
success: true,
data: {
userInfo: {
_id: userId,
openid: finalUser.openid,
nickname: finalUser.nickname,
avatarUrl: finalUser.avatarUrl,
role: finalUser.role,
favorites: finalUser.favorites || []
}
}
}
} catch (error) {
console.error('注册用户错误:', error)
return {
success: false,
message: '注册失败'
}
}
}
/**
* 通过微信登录code获取用户openid
* @param {string} code - 微信登录code
* @returns {Object} 用户身份信息
*/
async function getOpenIdByCode(code) {
// 在云函数环境中直接获取用户身份信息
const wxContext = cloud.getWXContext()
return {
openid: wxContext.OPENID,
appid: wxContext.APPID,
unionid: wxContext.UNIONID
}
}
/**
* 根据openid获取用户信息
* @param {Object} event - 事件参数
* @param {string} event.openid - 用户openid
* @returns {Object} 用户信息查询结果
*/
async function handleGetUserByOpenid(event) {
const { openid } = event;
if (!openid) {
return {
success: false,
message: '缺少openid参数'
};
}
try {
// 查询用户信息
const userResult = await db.collection('users')
.where({ openid: openid })
.get();
if (userResult.data.length > 0) {
const user = userResult.data[0];
return {
success: true,
data: {
userInfo: {
_id: user._id,
openid: user.openid,
nickname: user.nickname,
avatarUrl: user.avatarUrl,
role: user.role,
reviewedPoems: user.reviewedPoems || {},
learningStats: user.learningStats || {
totalLearned: 0,
totalReviewed: 0,
lastLearnDate: null
}
}
}
};
} else {
return {
success: false,
message: '用户不存在'
};
}
} catch (error) {
console.error('获取用户信息错误:', error);
return {
success: false,
message: '获取用户信息失败'
};
}
}
/**
* 检查诗歌是否被用户收藏
* @param {Object} event - 事件参数
* @param {string} event.poemId - 诗歌ID
* @returns {Object} 收藏状态检查结果
*/
async function handleCheckFavorite(event) {
const { poemId } = event;
if (!poemId) {
return {
success: false,
message: '缺少诗歌ID参数'
};
}
try {
// 获取用户openid
const wxContext = cloud.getWXContext();
const openid = wxContext.OPENID;
if (!openid) {
return {
success: false,
message: '未获取到用户信息'
};
}
// 查询用户信息
const userResult = await db.collection('users')
.where({ openid: openid })
.get();
if (userResult.data.length === 0) {
return {
success: false,
message: '用户不存在'
};
}
const user = userResult.data[0];
const favorites = user.favorites || [];
// 检查诗歌是否在收藏列表中
const isFavorite = favorites.some(favorite => favorite.poemId === poemId);
return {
success: true,
isFavorite: isFavorite
};
} catch (error) {
console.error('检查收藏状态错误:', error);
return {
success: false,
message: '检查收藏状态失败'
};
}
}
/**
* 添加诗歌到用户收藏
* @param {Object} event - 事件参数
* @param {string} event.poemId - 诗歌ID
* @param {Object} event.poemData - 诗歌数据
* @returns {Object} 添加收藏结果
*/
async function handleAddFavorite(event) {
const { poemId, poemData } = event;
if (!poemId) {
return {
success: false,
message: '缺少诗歌ID参数'
};
}
try {
// 获取用户openid
const wxContext = cloud.getWXContext();
const openid = wxContext.OPENID;
if (!openid) {
return {
success: false,
message: '未获取到用户信息'
};
}
// 查询用户信息
const userResult = await db.collection('users')
.where({ openid: openid })
.get();
if (userResult.data.length === 0) {
return {
success: false,
message: '用户不存在'
};
}
const user = userResult.data[0];
const favorites = user.favorites || [];
// 检查是否已经收藏
const alreadyFavorite = favorites.some(favorite => favorite.poemId === poemId);
if (alreadyFavorite) {
return {
success: false,
message: '已经收藏过该诗歌'
};
}
// 构建收藏项
const favoriteItem = {
poemId: poemId,
title: poemData?.title || '未知标题',
author: poemData?.author || '未知作者',
dynasty: poemData?.dynasty || '',
favoriteTime: db.serverDate()
};
// 添加到收藏列表
favorites.push(favoriteItem);
// 更新用户收藏列表
await db.collection('users')
.where({ openid: openid })
.update({
data: {
favorites: favorites,
updatedAt: db.serverDate()
}
});
return {
success: true,
message: '收藏成功'
};
} catch (error) {
console.error('添加收藏错误:', error);
return {
success: false,
message: '收藏失败'
};
}
}
/**
* 从用户收藏中移除诗歌
* @param {Object} event - 事件参数
* @param {string} event.poemId - 诗歌ID
* @returns {Object} 移除收藏结果
*/
async function handleRemoveFavorite(event) {
const { poemId } = event;
if (!poemId) {
return {
success: false,
message: '缺少诗歌ID参数'
};
}
try {
// 获取用户openid
const wxContext = cloud.getWXContext();
const openid = wxContext.OPENID;
if (!openid) {
return {
success: false,
message: '未获取到用户信息'
};
}
// 查询用户信息
const userResult = await db.collection('users')
.where({ openid: openid })
.get();
if (userResult.data.length === 0) {
return {
success: false,
message: '用户不存在'
};
}
const user = userResult.data[0];
const favorites = user.favorites || [];
// 过滤掉要移除的诗歌
const updatedFavorites = favorites.filter(favorite => favorite.poemId !== poemId);
// 如果收藏列表没有变化,说明原本就没有收藏
if (updatedFavorites.length === favorites.length) {
return {
success: false,
message: '该诗歌不在收藏列表中'
};
}
// 更新用户收藏列表
await db.collection('users')
.where({ openid: openid })
.update({
data: {
favorites: updatedFavorites,
updatedAt: db.serverDate()
}
});
return {
success: true,
message: '取消收藏成功'
};
} catch (error) {
console.error('移除收藏错误:', error);
return {
success: false,
message: '取消收藏失败'
};
}
}

@ -1,33 +1,33 @@
const cloud = require('wx-server-sdk')
// 初始化云开发环境
cloud.init({
env: 'cloud1-0g2sr1117862afae'
})
const db = cloud.database()
const poemsCollection = db.collection('poeties')
const poemsCollection = db.collection('poeties') // 古诗集合
const _ = db.command
// 云函数主入口
exports.main = async (event, context) => {
const { action, data, poemId, searchQuery, keyword, page = 1, pageSize = 20 } = event
try {
switch (action) {
case 'getAllPoems':
return await handleGetAllPoems(event);
return await handleGetAllPoems(event); // 获取所有古诗
case 'getPoemDetail':
return await getPoemDetail(event);
case 'getInitialPoems':
return await getInitialPoems()
return await getPoemDetail(event); // 获取古诗详情
case 'searchPoemsManager':
return await searchPoemsManager(searchQuery)
return await searchPoemsManager(searchQuery) // 管理端搜索古诗
case 'searchPoems':
return await searchPoems(event)
return await searchPoems(event) // 搜索古诗
case 'addPoem':
return await addPoem(data)
return await addPoem(data) // 添加古诗
case 'updatePoem':
return await updatePoem(poemId, data)
return await updatePoem(poemId, data) // 更新古诗
case 'deletePoem':
return await deletePoem(poemId)
return await deletePoem(poemId) // 删除古诗
default:
return {
success: false,
@ -42,8 +42,9 @@ exports.main = async (event, context) => {
}
}
// 获取古诗详情
async function getPoemDetail(event){
const { id } = event;
const { id } = event; // 古诗ID
console.log('获取古诗详情ID:', id)
try {
@ -68,7 +69,7 @@ async function getPoemDetail(event){
} catch (error) {
console.error('获取古诗详情失败:', error)
// 更详细的错误信息
// 错误处理
if (error.errCode === -502005) {
return {
success: false,
@ -88,17 +89,38 @@ async function getPoemDetail(event){
}
}
// 获取所有古诗
async function handleGetAllPoems(event) {
try {
const result = await db.collection('poeties')
.orderBy('title', 'asc')
.get();
const db = cloud.database();
const { page = 1, pageSize = 20, fields } = event;
// 构建查询条件
let query = db.collection('poeties').orderBy('title', 'asc');
// 字段筛选
if (fields && Array.isArray(fields)) {
const projection = {};
fields.forEach(field => {
projection[field] = true;
});
query = query.field(projection);
}
// 分页查询
const [dataResult, countResult] = await Promise.all([
query.skip((page - 1) * pageSize).limit(pageSize).get(),
db.collection('poeties').count()
]);
return {
success: true,
data: {
poems: result.data,
total: result.data.length
poems: dataResult.data,
total: countResult.total,
page: parseInt(page),
pageSize: parseInt(pageSize),
totalPages: Math.ceil(countResult.total / pageSize)
}
};
} catch (error) {
@ -109,24 +131,17 @@ async function handleGetAllPoems(event) {
};
}
}
// 获取初始的100条古诗
async function getInitialPoems() {
const result = await poemsCollection.limit(100).get()
return {
success: true,
data: result.data
}
}
// 搜索古诗
// 管理端搜索古诗
async function searchPoemsManager(searchQuery) {
const _ = db.command
const result = await poemsCollection.where(
_.or([
{
title: db.RegExp({
regexp: searchQuery,
options: 'i'
regexp: searchQuery, // 搜索关键词
options: 'i' // 不区分大小写
})
},
{
@ -168,20 +183,21 @@ async function searchPoemsManager(searchQuery) {
}
}
// 搜索古诗
async function searchPoems(event){
const { keyword, page = 1, pageSize = 20 } = event;
const { keyword, page = 1, pageSize = 20 } = event; // 搜索关键词,页码,页大小
console.log('搜索请求参数:', { keyword, page, pageSize })
try {
// 如果关键词为空,返回所有数据
if (!keyword || keyword.trim() === '') {
const allData = await db.collection('poeties') // 注意集合名称
const allData = await db.collection('poeties')
.orderBy('title', 'asc')
.skip((page - 1) * pageSize)
.limit(pageSize)
.skip((page - 1) * pageSize) // 跳过记录数
.limit(pageSize) // 限制返回数量
.get()
const countResult = await db.collection('poeties').count()
const countResult = await db.collection('poeties').count() // 获取总数
return {
success: true,
@ -197,7 +213,7 @@ async function searchPoems(event){
const searchKeyword = keyword.trim()
console.log('搜索关键词:', searchKeyword)
// 根据你的数据结构构建搜索条件
// 构建搜索条件
const searchCondition = _.or([
{
title: db.RegExp({
@ -245,15 +261,15 @@ async function searchPoems(event){
console.log('搜索条件:', searchCondition)
// 执行搜索查询 - 使用正确的集合名称 poeties
// 执行搜索查询
const [dataResult, countResult] = await Promise.all([
db.collection('poeties')
db.collection('poeties')
.where(searchCondition)
.orderBy('title', 'asc')
.skip((page - 1) * pageSize)
.limit(pageSize)
.get(),
db.collection('poeties')
db.collection('poeties')
.where(searchCondition)
.count()
])
@ -290,6 +306,7 @@ async function searchPoems(event){
// 添加古诗
async function addPoem(poemData) {
// 验证必要字段
if (!poemData.title || !poemData.dynasty || !poemData.author || !poemData.content) {
return {
success: false,
@ -297,18 +314,19 @@ async function addPoem(poemData) {
}
}
// 构建古诗数据对象
const newPoem = {
title: poemData.title,
dynasty: poemData.dynasty,
author: poemData.author,
content: poemData.content,
translation: poemData.translation || '',
background: poemData.background || '',
author_info: poemData.author_info || {},
theme: poemData.theme || [],
type: poemData.type || '诗',
createTime: db.serverDate(),
updateTime: db.serverDate()
title: poemData.title, // 标题
dynasty: poemData.dynasty, // 朝代
author: poemData.author, // 作者
content: poemData.content, // 内容
translation: poemData.translation || '', // 翻译
background: poemData.background || '', // 背景
author_info: poemData.author_info || {}, // 作者信息
theme: poemData.theme || [], // 主题
type: poemData.type || '诗', // 类型
createTime: db.serverDate(), // 创建时间
updateTime: db.serverDate() // 更新时间
}
const result = await poemsCollection.add({
@ -324,6 +342,7 @@ async function addPoem(poemData) {
// 更新古诗
async function updatePoem(poemId, updateData) {
// 验证古诗ID
if (!poemId) {
return {
success: false,
@ -331,6 +350,7 @@ async function updatePoem(poemId, updateData) {
}
}
// 验证必要字段
if (!updateData.title || !updateData.dynasty || !updateData.author || !updateData.content) {
return {
success: false,
@ -338,6 +358,7 @@ async function updatePoem(poemId, updateData) {
}
}
// 构建更新数据对象
const updateInfo = {
title: updateData.title,
dynasty: updateData.dynasty,
@ -364,6 +385,7 @@ async function updatePoem(poemId, updateData) {
// 删除古诗
async function deletePoem(poemId) {
// 验证古诗ID
if (!poemId) {
return {
success: false,

@ -0,0 +1,269 @@
// cloudfunctions/reviewManagement/index.js
const cloud = require('wx-server-sdk')
// 初始化云开发环境
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV
})
const db = cloud.database()
const _ = db.command
const reviewCollection = db.collection('Review') // 背诵记录集合
// 云函数主入口
exports.main = async (event, context) => {
const {
action, // 操作类型
reviewData, // 背诵记录数据
recordId, // 记录ID
openid, // 用户openid
poemId, // 诗歌ID
page = 1, // 页码
pageSize = 20 // 每页数量
} = event
try {
switch (action) {
case 'addReviewRecord':
return await addReviewRecord(reviewData) // 添加背诵记录
case 'getUserReviews':
return await getUserReviews(openid, page, pageSize) // 获取用户背诵记录
case 'checkExistingRecord':
return await checkExistingRecord(poemId, openid) // 检查是否存在记录
case 'updateReviewRecord':
return await updateReviewRecord(recordId, reviewData) // 更新已有记录
default:
return {
success: false,
message: `未知操作: ${action}`
}
}
} catch (error) {
console.error('云函数执行失败:', {
message: error.message,
code: error.code,
stack: error.stack,
error: JSON.stringify(error)
})
// 错误处理
if (error.code === -502001) {
return {
success: false,
message: '数据库权限不足'
}
} else if (error.code === -502007) {
return {
success: false,
message: '数据库请求超时'
}
} else if (error.code === -502023) {
return {
success: false,
message: '数据库容量已满'
}
} else if (error.code === -404011) {
return {
success: false,
message: '云函数权限不足'
}
} else if (error.code === -502005) {
return {
success: false,
message: '数据库集合不存在'
}
} else {
return {
success: false,
message: `服务器错误: ${error.message || error}`
}
}
}
}
// 检查用户是否已存在该诗歌的背诵记录
async function checkExistingRecord(poemId, openid) {
if (!poemId || !openid) {
return {
success: false,
message: '古诗ID和用户ID不能为空'
}
}
try {
console.log('检查是否存在记录poemId:', poemId, 'openid:', openid);
// 查询最新的一条记录
const result = await reviewCollection
.where({
poemId: poemId,
openid: openid
})
.orderBy('reciteDateTime', 'desc')
.limit(1)
.get()
console.log('查询结果:', result);
if (result.data && result.data.length > 0) {
const existingRecord = result.data[0];
console.log('找到已存在记录ID:', existingRecord._id);
return {
success: true,
exists: true,
recordId: existingRecord._id,
recordData: existingRecord
}
} else {
console.log('未找到已存在记录');
return {
success: true,
exists: false,
recordId: null
}
}
} catch (error) {
console.error('检查记录失败:', error);
throw error;
}
}
// 更新已有的背诵记录
async function updateReviewRecord(recordId, reviewData) {
if (!recordId) {
return {
success: false,
message: '记录ID不能为空'
}
}
// 验证必要字段
if (!reviewData || !reviewData.poemId || !reviewData.openid) {
return {
success: false,
message: '缺少必要字段'
}
}
// 清理不需要的字段
if (reviewData.hasOwnProperty('content')) {
delete reviewData.content;
}
if (reviewData.hasOwnProperty('score')) {
delete reviewData.score;
}
// 准备更新数据
const updateData = {};
updateData.poemName = reviewData.poemName || ''; // 古诗名称
updateData.accuracy = Number(reviewData.accuracy) || 0; // 正确率
updateData.duration = Number(reviewData.duration) || 0; // 背诵时长(秒)
updateData.reciteDateTime = reviewData.reciteDateTime || new Date().toISOString(); // 背诵时间
updateData.updateTime = db.serverDate(); // 更新时间
try {
// 执行更新操作
const result = await reviewCollection.doc(recordId).update({
data: updateData
})
console.log('背诵记录更新成功ID:', recordId, '更新结果:', result)
return {
success: true,
_id: recordId,
message: '背诵记录更新成功',
updatedFields: Object.keys(updateData)
}
} catch (error) {
if (error.errCode === -502005) {
return {
success: false,
message: '背诵记录不存在或已被删除'
}
}
throw error
}
}
// 添加新的背诵记录
async function addReviewRecord(reviewData) {
// 验证必要字段
if (!reviewData || !reviewData.poemId || !reviewData.openid) {
return {
success: false,
message: '缺少必要字段'
}
}
// 清理不需要的字段
if (reviewData.hasOwnProperty('content')) {
delete reviewData.content;
}
if (reviewData.hasOwnProperty('score')) {
delete reviewData.score;
}
// 准备保存的数据
const dataToSave = {};
dataToSave.openid = reviewData.openid; // 用户ID
dataToSave.poemId = reviewData.poemId; // 古诗ID
dataToSave.poemName = reviewData.poemName || ''; // 古诗名称
dataToSave.accuracy = Number(reviewData.accuracy) || 0; // 正确率
dataToSave.duration = Number(reviewData.duration) || 0; // 背诵时长(秒)
dataToSave.reciteDateTime = reviewData.reciteDateTime || new Date().toISOString(); // 背诵时间
dataToSave.createTime = db.serverDate(); // 创建时间
// 执行保存操作
const result = await reviewCollection.add({
data: dataToSave
})
console.log('背诵记录保存成功ID:', result._id)
return {
success: true,
_id: result._id,
message: '背诵记录添加成功',
savedFields: Object.keys(dataToSave)
}
}
// 获取用户的背诵记录列表
async function getUserReviews(openid, page = 1, pageSize = 20) {
if (!openid) {
return {
success: false,
message: '用户ID不能为空'
}
}
try {
// 查询记录总数
const countResult = await reviewCollection.where({
openid: openid
}).count()
// 查询分页数据
const dataResult = await reviewCollection.where({
openid: openid
})
.orderBy('reciteDateTime', 'desc') // 按背诵时间倒序排列
.skip((page - 1) * pageSize) // 跳过记录数
.limit(pageSize) // 限制返回数量
.get()
return {
success: true,
data: {
reviews: dataResult.data, // 背诵记录列表
total: countResult.total, // 总记录数
page, // 当前页码
pageSize // 每页数量
}
}
} catch (error) {
console.error('获取用户背诵记录失败:', error)
throw error
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save