|
|
@@ -2742,7 +2742,7 @@ function durationHours(type) { return durationMinutes(type)/60; }
|
|
|
function appointmentDate(value,date,time) { const raw=text(value); if(raw) { const normalized=raw.includes('T')?raw:raw.replace(' ','T')+(raw.includes('+')||raw.endsWith('Z')?'':'+08:00'); const parsed=new Date(normalized); if(!Number.isNaN(parsed.getTime())) return parsed; } const fallback=new Date(text(date)+'T'+(text(time)||'00:00')+':00+08:00'); return fallback; }
|
|
|
function appointmentProjection(row) { const start=appointmentDate(row.yysj,row.bxrq,row.sdsd),type=number(row.dslx),end=new Date(start.getTime()+durationMinutes(type)*60000),student=legacyOf({legacyUserData:row.studentLegacy}),coach=legacyOf({legacyUserData:row.coachLegacy}),cancelled=number(row.commonStatus)===-2,coachId=number(row.pl||row.fxpl),coachObjectId=text(row.coachObjectId),startsAt=Number.isNaN(start.getTime())?'':start.toISOString(),endsAt=Number.isNaN(end.getTime())?'':end.toISOString(); return { targetId:text(row.targetId),generalId:number(row.generalId),studentObjectId:text(row.studentObjectId),studentId:number(row.szyh),studentName:text(row.studentRealName||row.studentNickname||student.HoneyName||row.studentUsername)||'用户 '+number(row.szyh),coachObjectId,coachId,coachName:text(row.coachRealName||row.coachNickname||coach.HoneyName||row.coachUsername||row.plxm)||(coachId?'历史陪练 '+coachId:'未分配'),courseId:number(row.kcid),courseName:text(row.courseTitle)||'课程 '+number(row.kcid),classType:type,classTypeLabel:classType(type),deliveryMethod:text(row.jffs)||'未设置',startsAt,endsAt,statusCode:number(row.dszt),statusLabel:cancelled?'已取消':statusLabel(row.dszt),cancelled,cancellationReason:text(row.cancellationReason),coachAccountMissing:Boolean(coachId&&!coachObjectId),availabilityWarning:row.availabilityConfigured===false,updatedAt:dateIso(row.commonUpdatedAt||row.updatedAt) }; }
|
|
|
async function allAppointmentRows(context,input) { const companyId=companyIdOf(context,input); const raw=await Psql.query('SELECT c."objectId" AS "targetId",c."generalId",c."status" AS "commonStatus",c."updatedAt" AS "commonUpdatedAt",a.*,s."objectId" AS "studentObjectId",s."realName" AS "studentRealName",s."nickname" AS "studentNickname",s."username" AS "studentUsername",s."legacyUserData" AS "studentLegacy",p."objectId" AS "coachObjectId",p."realName" AS "coachRealName",p."nickname" AS "coachNickname",p."username" AS "coachUsername",p."legacyUserData" AS "coachLegacy",n."nodeName" AS "courseTitle" FROM "CommonModel" c JOIN "CourseAppointment" a ON a."company"=c."company" AND CAST(a."id" AS text)=CAST(c."itemId" AS text) LEFT JOIN "_User" s ON s."company"=c."company" AND COALESCE(CAST(s."legacyUserId" AS text),s."legacyUserData"->>\'UserID\')=CAST(a."szyh" AS text) LEFT JOIN "_User" p ON p."company"=c."company" AND COALESCE(CAST(p."legacyUserId" AS text),p."legacyUserData"->>\'UserID\')=COALESCE(NULLIF(CAST(a."pl" AS text),\'\'),CAST(a."fxpl" AS text)) LEFT JOIN "Node" n ON n."company"=c."company" AND CAST(n."nodeId" AS text)=CAST(a."kcid" AS text) WHERE ($1::text IS NULL OR c."company"=$1) AND CAST(c."modelId" AS text)=\'54\' ORDER BY c."updatedAt" DESC LIMIT 10000',[companyId]); return raw.map(appointmentProjection); }
|
|
|
-async function newClassObjects(className,context,input,limit=1000) { try { const query=new Parse.Query(className); const company=companyPointer(context,input); if(company) query.equalTo('company',company); query.limit(limit); query.descending('createdAt'); return await query.find({useMasterKey:true}); } catch(error) { if(error.code===100||error.code===103||/class/i.test(text(error.message))) return []; throw error; } }
|
|
|
+async function newClassObjects(className,context,input,limit=1000) { try { const fields=await fieldsOf(className).catch(()=>({})); if(!Object.keys(fields).length)return[]; const query=new Parse.Query(className); const company=companyPointer(context,input); if(company&&fields.company) query.equalTo('company',company); query.limit(limit); query.descending(fields.createdAt?'createdAt':'objectId'); return await query.find({useMasterKey:true}); } catch(error) { if(error.code===100||error.code===103||/class|schema|column .* does not exist/i.test(text(error.message))) return []; throw error; } }
|
|
|
async function availabilityRows(context,input,coachId=0) { const rows=await newClassObjects('CoachAvailability',context,input,1000); return rows.filter((row)=>!coachId||number(row.get('coachId'))===coachId).map((row)=>({objectId:row.id,coachId:number(row.get('coachId')),ruleType:text(row.get('ruleType'))||'weekly',weekday:number(row.get('weekday')),date:text(row.get('date')),startTime:text(row.get('startTime')),endTime:text(row.get('endTime')),available:row.get('available')!==false,reason:text(row.get('reason')),updatedAt:dateIso(row.updatedAt)})); }
|
|
|
function defaultPayRates() { return [{objectId:'default-1',classType:1,classTypeLabel:classType(1),amount:20,durationHours:.5,effectiveFrom:'1970-01-01',active:true,isDefault:true},{objectId:'default-2',classType:2,classTypeLabel:classType(2),amount:40,durationHours:1,effectiveFrom:'1970-01-01',active:true,isDefault:true},{objectId:'default-3',classType:3,classTypeLabel:classType(3),amount:40,durationHours:1,effectiveFrom:'1970-01-01',active:true,isDefault:true}]; }
|
|
|
async function payRateRows(context,input) { const stored=(await newClassObjects('CoachPayRate',context,input,1000)).map((row)=>({objectId:row.id,classType:number(row.get('classType')),classTypeLabel:classType(row.get('classType')),amount:number(row.get('amount')),durationHours:number(row.get('durationHours'),durationHours(row.get('classType'))),effectiveFrom:text(row.get('effectiveFrom')),active:row.get('active')!==false,isDefault:false,updatedAt:dateIso(row.updatedAt)})); return defaultPayRates().concat(stored).sort((a,b)=>String(b.effectiveFrom).localeCompare(String(a.effectiveFrom))); }
|