/// 加班申请主表,对应 OA_OT_APPLY 表。 class OvertimeModel { final int applyId; final String billNo; final DateTime? applyDate; final String origBillNo; final String salesman; final String dept; final String customer; final String billType; final bool isClosed; final String feedback; final String remark; final int status; final String createUser; final DateTime createTime; final DateTime updateTime; // ── 瞬态字段(API 实时查询,非存储) ── final bool isAuditApproved; // ── 子表 ── final List details; const OvertimeModel({ required this.applyId, this.billNo = '', this.applyDate, this.origBillNo = '', this.salesman = '', this.dept = '', this.customer = '', this.billType = '', this.isClosed = false, this.feedback = '', this.remark = '', this.status = 0, this.createUser = '', required this.createTime, required this.updateTime, this.isAuditApproved = false, this.details = const [], }); factory OvertimeModel.fromJson(Map json) { return OvertimeModel( applyId: json['applyId'] as int? ?? 0, billNo: json['billNo'] as String? ?? '', applyDate: json['applyDate'] != null ? DateTime.tryParse(json['applyDate'] as String) : null, origBillNo: json['origBillNo'] as String? ?? '', salesman: json['salesman'] as String? ?? '', dept: json['dept'] as String? ?? '', customer: json['customer'] as String? ?? '', billType: json['billType'] as String? ?? '', isClosed: (json['isClosed'] as int?) == 1, feedback: json['feedback'] as String? ?? '', remark: json['remark'] as String? ?? '', status: json['status'] as int? ?? 0, createUser: json['createUser'] as String? ?? '', createTime: json['createTime'] != null ? DateTime.parse(json['createTime'] as String) : DateTime.now(), updateTime: json['updateTime'] != null ? DateTime.parse(json['updateTime'] as String) : DateTime.now(), isAuditApproved: (json['isAuditApproved'] as int?) == 1, details: (json['details'] as List?) ?.map( (e) => OvertimeDetailModel.fromJson(e as Map), ) .toList() ?? [], ); } Map toJson() => { 'applyId': applyId, 'billNo': billNo, 'applyDate': applyDate?.toIso8601String(), 'origBillNo': origBillNo, 'salesman': salesman, 'dept': dept, 'customer': customer, 'billType': billType, 'isClosed': isClosed ? 1 : 0, 'feedback': feedback, 'remark': remark, 'status': status, 'createUser': createUser, 'createTime': createTime.toIso8601String(), 'updateTime': updateTime.toIso8601String(), 'isAuditApproved': isAuditApproved ? 1 : 0, 'details': details.map((d) => d.toJson()).toList(), }; OvertimeModel copyWith({ int? applyId, String? billNo, DateTime? applyDate, String? origBillNo, String? salesman, String? dept, String? customer, String? billType, bool? isClosed, String? feedback, String? remark, int? status, String? createUser, DateTime? createTime, DateTime? updateTime, bool? isAuditApproved, List? details, }) { return OvertimeModel( applyId: applyId ?? this.applyId, billNo: billNo ?? this.billNo, applyDate: applyDate ?? this.applyDate, origBillNo: origBillNo ?? this.origBillNo, salesman: salesman ?? this.salesman, dept: dept ?? this.dept, customer: customer ?? this.customer, billType: billType ?? this.billType, isClosed: isClosed ?? this.isClosed, feedback: feedback ?? this.feedback, remark: remark ?? this.remark, status: status ?? this.status, createUser: createUser ?? this.createUser, createTime: createTime ?? this.createTime, updateTime: updateTime ?? this.updateTime, isAuditApproved: isAuditApproved ?? this.isAuditApproved, details: details ?? this.details, ); } } /// 加班明细,对应 OA_OT_DETAIL 表。 class OvertimeDetailModel { final int detailId; final int applyId; final int seqNo; final String empCode; final String shiftType; final DateTime? startDate; final DateTime? endDate; final double approvedHours; final String isApproved; final String directOt; final double otQuantity; final String reason; final String handleMethod; final String chargeMethod; final String remark; final String isClosed; final String outBillNo; const OvertimeDetailModel({ required this.detailId, this.applyId = 0, this.seqNo = 0, this.empCode = '', this.shiftType = '', this.startDate, this.endDate, this.approvedHours = 0.0, this.isApproved = 'N', this.directOt = 'N', this.otQuantity = 0.0, this.reason = '', this.handleMethod = '', this.chargeMethod = '', this.remark = '', this.isClosed = 'N', this.outBillNo = '', }); factory OvertimeDetailModel.fromJson(Map json) { return OvertimeDetailModel( detailId: json['detailId'] as int? ?? 0, applyId: json['applyId'] as int? ?? 0, seqNo: json['seqNo'] as int? ?? 0, empCode: json['empCode'] as String? ?? '', shiftType: json['shiftType'] as String? ?? '', startDate: json['startDate'] != null ? DateTime.tryParse(json['startDate'] as String) : null, endDate: json['endDate'] != null ? DateTime.tryParse(json['endDate'] as String) : null, approvedHours: (json['approvedHours'] as num?)?.toDouble() ?? 0.0, isApproved: json['isApproved'] as String? ?? 'N', directOt: json['directOt'] as String? ?? 'N', otQuantity: (json['otQuantity'] as num?)?.toDouble() ?? 0.0, reason: json['reason'] as String? ?? '', handleMethod: json['handleMethod'] as String? ?? '', chargeMethod: json['chargeMethod'] as String? ?? '', remark: json['remark'] as String? ?? '', isClosed: json['isClosed'] as String? ?? 'N', outBillNo: json['outBillNo'] as String? ?? '', ); } Map toJson() => { 'detailId': detailId, 'applyId': applyId, 'seqNo': seqNo, 'empCode': empCode, 'shiftType': shiftType, 'startDate': startDate?.toIso8601String(), 'endDate': endDate?.toIso8601String(), 'approvedHours': approvedHours, 'isApproved': isApproved, 'directOt': directOt, 'otQuantity': otQuantity, 'reason': reason, 'handleMethod': handleMethod, 'chargeMethod': chargeMethod, 'remark': remark, 'isClosed': isClosed, 'outBillNo': outBillNo, }; }