|
|
@@ -52,6 +52,6 @@ export class OperationsPayrollComponent implements OnInit{
|
|
|
async excludeLine(objectId:string):Promise<void>{const batch=this.detail(),reason=this.adjustmentReason().trim();if(!batch||batch.status!=='draft')return;if(!reason){this.error.set('请先在调整原因中填写排除该异常记录的原因');return;}this.saving.set(true);this.error.set('');try{await this.operations.mutate('ops/payroll/exclude-line',objectId,reason,{},'');await this.open(batch);this.message.set('异常记录已排除并保留审计原因');}catch(error){this.error.set(error instanceof Error?error.message:'异常记录排除失败');}finally{this.saving.set(false);}}
|
|
|
async review():Promise<void>{const batch=this.detail();if(!batch)return;this.saving.set(true);this.error.set('');try{await this.operations.mutate('ops/payroll/review',batch.objectId,'实时刷新完成,复核工资明细并永久锁定',{},batch.updatedAt);await this.load();await this.open(batch);this.message.set('工资单已审核锁定');}catch(error){this.error.set(error instanceof Error?error.message:'工资审核失败');}finally{this.saving.set(false);}}
|
|
|
async markPaid():Promise<void>{const batch=this.detail();if(!batch||!this.paymentMethod().trim()||!this.paymentReference().trim()){this.error.set('请填写发放方式和凭证编号');return;}this.saving.set(true);this.error.set('');try{await this.operations.mutate('ops/payroll/mark-paid',batch.objectId,'确认工资已线下发放',{paymentMethod:this.paymentMethod(),paymentReference:this.paymentReference()},batch.updatedAt);await this.load();await this.open(batch);this.message.set('工资发放信息已登记');}catch(error){this.error.set(error instanceof Error?error.message:'发放登记失败');}finally{this.saving.set(false);}}
|
|
|
- async exportExcel():Promise<void>{this.saving.set(true);this.error.set('');try{const batch=this.detail(),data=await this.operations.payrollExport(this.month(),batch?.objectId||'',this.storeId(),this.search());const summary=data.coachItems.map((row)=>({'陪练老师':this.coachLabel(row.coachName,row.coachId),'门店':row.storeName,'30分钟课':row.type30Count,'60分钟课':row.type60Count,'体验课':row.trialCount,'课型4':row.type4Count,'总课次':row.lessonCount,'工时':row.totalHours,'基础工资':row.baseAmount,'有效复习次数':row.reviewCount||0,'复习奖励':row.reviewAmount||0,'调整':row.adjustmentAmount,'应发金额':row.payableAmount}));const details=data.lines.map((line)=>this.exportLine(line)),exceptions=data.exceptions.map((line)=>({...this.exportLine(line),'异常原因':line.exception}));const book=utils.book_new();utils.book_append_sheet(book,utils.json_to_sheet(summary),'老师汇总');utils.book_append_sheet(book,utils.json_to_sheet(details),'计薪明细');utils.book_append_sheet(book,utils.json_to_sheet(exceptions),'异常记录');writeFile(book,data.fileName);}catch(error){this.error.set(error instanceof Error?error.message:'工资 Excel 导出失败');}finally{this.saving.set(false);}}
|
|
|
- private exportLine(line:PayrollLine):Record<string,unknown>{return{'明细类型':line.kind==='review_reward'?'复习奖励':line.kind==='adjustment'?'人工调整':'课酬','奖励凭据':line.reviewRewardId||'','复习任务':line.reviewTaskId||'','计划复习日期':line.plannedDate||'','来源记录ID':line.legacyGeneralId,'上课日期':line.lessonAt,'结算月份':line.settlementMonth,'原上课月份':line.originalMonth,'陪练老师':this.coachLabel(line.coachName,line.coachId),'门店':line.storeName,'学员':line.studentName,'课程':line.courseName,'课程分类':line.courseCategoryName||line.classTypeLabel,'授课方式':line.deliveryLabel||'未记录','时长':line.durationMinutes?`${line.durationMinutes}分钟`:line.classTypeLabel,'工时':line.durationHours,'单价':line.rateAmount,'金额':line.amount,'说明':line.description};}
|
|
|
+ async exportExcel():Promise<void>{this.saving.set(true);this.error.set('');try{const batch=this.detail(),data=await this.operations.payrollExport(this.month(),batch?.objectId||'',this.storeId(),this.search());const summary=data.coachItems.map((row)=>({'陪练老师':this.coachLabel(row.coachName,row.coachId),'门店':row.storeName,'30分钟课':row.type30Count,'60分钟课':row.type60Count,'体验课':row.trialCount,'课型4':row.type4Count,'总课次':row.lessonCount,'工时':row.totalHours,'基础工资':row.baseAmount,'有效复习次数':row.reviewCount||0,'抗遗忘工资':row.reviewAmount||0,'调整':row.adjustmentAmount,'应发金额':row.payableAmount}));const details=data.lines.map((line)=>this.exportLine(line)),exceptions=data.exceptions.map((line)=>({...this.exportLine(line),'异常原因':line.exception}));const book=utils.book_new();utils.book_append_sheet(book,utils.json_to_sheet(summary),'老师汇总');utils.book_append_sheet(book,utils.json_to_sheet(details),'计薪明细');utils.book_append_sheet(book,utils.json_to_sheet(exceptions),'异常记录');writeFile(book,data.fileName);}catch(error){this.error.set(error instanceof Error?error.message:'工资 Excel 导出失败');}finally{this.saving.set(false);}}
|
|
|
+ private exportLine(line:PayrollLine):Record<string,unknown>{return{'明细类型':line.kind==='review_reward'?'抗遗忘工资':line.kind==='adjustment'?'人工调整':'课酬','计薪凭据':line.reviewRewardId||'','复习任务':line.reviewTaskId||'','计划复习日期':line.plannedDate||'','来源记录ID':line.legacyGeneralId,'上课日期':line.lessonAt,'结算月份':line.settlementMonth,'原上课月份':line.originalMonth,'陪练老师':this.coachLabel(line.coachName,line.coachId),'门店':line.storeName,'学员':line.studentName,'课程':line.courseName,'课程分类':line.kind==='review_reward'?'抗遗忘工资':line.courseCategoryName||line.classTypeLabel,'授课方式':line.deliveryLabel||'未记录','时长':line.kind==='review_reward'?'—':line.durationMinutes?`${line.durationMinutes}分钟`:line.classTypeLabel,'工时':line.durationHours,'单价':line.rateAmount,'金额':line.amount,'说明':line.description};}
|
|
|
}
|