| 1234567891011121314151617181920212223242526272829303132 |
- async function upsertStudyRecord(input,current) {
- assertLessonTenant(current);
- const uid=await authorizeRequestedUser(current,input.uid),gid=String(input.orderId||input.id||'');
- const order=await orderDetailRow(gid,current);
- if(!order||number(order.szyh)!==uid||ownLegacyId(current)!==number(order.pl))fail(403,'仅预约老师可以保存课堂学习');
- const addon=parseObject(input.addon,'学习记录'),words=await validateStudyWords(addon.xxqs||[]);
- // The transaction checks lesson state after command replay, so a confirmed
- // request can be retried after concurrent completion without a second write.
- const binding=await lessonStudyBinding(addon,current,uid,{...order,dszt:10},words);
- const mode=String(input.saveMode||'legacy'),batchId=String(input.batchId||('legacy:'+binding.objectId));
- const key=mobileCommandKey(input)||('legacy:'+randomObjectId());
- try{return (await Psql.one('SELECT xs_lesson_study_save($1,$2,$3,$4,$5,$6::jsonb) result',[DEFAULT_COMPANY_ID,gid,current.id,ownLegacyId(current),key,JSON.stringify({mode,batchId,bindingId:binding.objectId,expectedVersion:input.expectedVersion??0,words})])).result;}
- catch(e){fail(409,String(e.message||e));}
- }
- async function appLessonStudy(input,current) {
- assertLessonTenant(current);
- const gid=String(input.orderId||''),order=await orderDetailRow(gid,current);
- if(!order)fail(404,'预约不存在');
- const batches=await Psql.query('SELECT b.*,cb.kcid AS "courseId",n."nodeName" AS "courseName" FROM "LessonStudyBatch" b LEFT JOIN "CourseBinding" cb ON cb.company=b.company AND cb."objectId"=b."bindingId" LEFT JOIN "Node" n ON n.company=cb.company AND n."nodeId"::text=cb.kcid WHERE b.company=$1 AND b."orderId"=$2 AND b.status<>\'discarded\' ORDER BY b."updatedAt",b."batchId"',[DEFAULT_COMPANY_ID,gid]);
- const record=await Psql.oneOrNone('SELECT d.*,c."generalId" AS "GeneralID" FROM "DailyStudyRecord" d JOIN "CommonModel" c ON c.company=d.company AND c."modelId"=56 AND c."itemId"=d.id WHERE d.company=$1 AND d.dsid::text=$2 AND d."recordScope"=\'lesson\'',[DEFAULT_COMPANY_ID,gid]);
- const nodes=await Psql.query('SELECT "nodeId","nodeName" FROM "Node" WHERE company=$1 AND "nodeId"::text=ANY($2::text[])',[DEFAULT_COMPANY_ID,[...new Set(batches.flatMap(b=>parseArray(b.words).map(w=>String(w.nodeId||''))))]]);
- const names=new Map(nodes.map(n=>[String(n.nodeId),n.nodeName]));
- return {orderId:gid,record:record?{...record,words:parseArray(record.xxqs)}:null,batches:batches.map(b=>({...b,words:parseArray(b.words).map(w=>({...w,nodeName:names.get(String(w.nodeId))||''}))})),pending:batches.filter(b=>b.status==='draft').length};
- }
- async function appReadingSource(input,current) {
- const detail=await recordDetailData({id:input.sourceStudyId,studentId:input.studentId},current);
- if(!detail?.record)fail(404,'学习记录不存在');
- const record=detail.record,order=record.dsid?await orderDetailRow(record.dsid,current):null;
- if(record.recordScope==='lesson'&&number(order?.dszt)<30)fail(409,'请先完成课程,再使用完整课堂词表生成阅读');
- const words=detail.words||[];
- return {sourceStudyId:String(record.GeneralID||record.generalId),sourceVersion:String(record.studyVersion||record.updatedAt||''),wordIds:words.map(w=>String(w.GeneralID)),wordList:words.map(w=>w.Title),studentId:number(record.userId??record.UserID)};
- }
|