Просмотр исходного кода

Compact payroll source status and verification action

彭峰 3 дней назад
Родитель
Сommit
ce0b87fa77

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
projects/xiaoshu-admin/src/app/pages/operations-payroll.component.html


+ 4 - 3
projects/xiaoshu-admin/src/app/pages/operations-payroll.component.scss

@@ -291,9 +291,10 @@
   box-shadow: 0 0 0 4px rgba(217, 45, 32, .1);
 }
 
-.sync-status{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:12px;padding:12px 16px;border:1px solid #b9dfd2;border-radius:12px;background:#edf9f5;color:#176c55;font-size:13px}
-.sync-status span{color:#486a5e}.sync-status small{flex-basis:100%;color:#58776c}
-.sync-status.delayed{border-color:#efc7bd;background:#fff4f0;color:#ad3b2f}.sync-status.delayed span,.sync-status.delayed small{color:#8a5149}
+.payroll-source-row{display:flex;align-items:center;flex-wrap:wrap;gap:8px 14px;margin-top:12px;padding:8px 12px;border:1px solid #b9dfd2;border-radius:12px;background:#f5fbf8;color:#176c55}
+.payroll-source-row.delayed{border-color:#efd4c8;background:#fff8f5;color:#994536}
+.sync-status{display:flex;align-items:center;flex:1 1 640px;min-width:0;gap:6px 14px;flex-wrap:wrap;margin:0;font-size:12px;line-height:1.35}
+.sync-status strong{white-space:nowrap}.sync-status span,.sync-status small{color:inherit;opacity:.82}
 
 .payroll-metrics {
   display: grid;

+ 2 - 2
projects/xiaoshu-admin/src/app/pages/payroll-cutoff.component.ts

@@ -4,7 +4,7 @@ import { FormsModule } from '@angular/forms';
 import { OperationsService } from '../operations.service';
 interface Difference {id:string;dataset:string;legacyKey:string;student:string;course:string;date:string;fields:string[];current:unknown;fingerprint:string;cosmetic:boolean;resolved:boolean;}
 interface Cutoff {month:string;version:string;runId:string;cutoffAt:string;complete:boolean;pending:number;conflicts:Difference[];approved:boolean;monthClosed:boolean;datasets:{model:number;source:number;matched:number}[];}
-@Component({selector:'app-payroll-cutoff',standalone:true,imports:[CommonModule,FormsModule],template:`
+@Component({selector:'app-payroll-cutoff',standalone:true,imports:[CommonModule,FormsModule],host:{'[class.expanded]':'data() !== null || error().length > 0'},template:`
 <section class="cutoff" [class.is-collapsed]="!data()&&!error()"><button type="button" (click)="load()" [disabled]="busy()">{{busy()?'核验中…':'核验 '+month()+' 结算来源'}}</button>
 @if(error()){<p role="alert">{{error()}}</p>}
 @if(data();as d){<h3>{{d.month}} · 工资来源核验</h3><p>旧接口同步截止:{{d.cutoffAt|date:'yyyy-MM-dd HH:mm':'+0800'}}。{{d.monthClosed?'已覆盖整月':'当前仅可生成截止时间内的草稿,整月同步后才能审核'}}</p>
@@ -14,7 +14,7 @@ interface Cutoff {month:string;version:string;runId:string;cutoffAt:string;compl
 <label>核验依据<textarea [(ngModel)]="reason" rows="2" placeholder="说明核对依据,至少 2 个字"></textarea></label>
 <div class="differences">@for(row of d.conflicts;track row.id){<details><summary>{{row.student||row.legacyKey}} · {{row.course}} · {{row.cosmetic?'不影响计薪':row.resolved?'已确认':'待核对'}}</summary><p>{{sourceName(row.dataset)}}编号 {{row.legacyKey}} · {{row.date||'日期待核对'}}</p><p>以下为新系统当前记录,请与旧系统同编号记录核对后填写依据。</p><dl>@for(field of row.fields;track field){<dt>{{fieldName(field)}}</dt><dd>{{fieldValue(row,field)}}</dd>}@empty{<dt>差异说明</dt><dd>来源没有提供具体字段,请完整核对该记录。</dd>}</dl>@if(!row.resolved&&canConfirm()){<button type="button" [disabled]="busy()||reason.trim().length<2" (click)="confirm(row)">确认此记录保留新系统</button>}</details>}</div>
 @if(canConfirm()){<button type="button" [disabled]="busy()||!d.complete||d.pending>0||reason.trim().length<2" (click)="confirm()">确认该月份截止来源</button>}@if(d.approved){<p role="status">来源已确认;数据变化后确认将自动失效。</p>}
-}</section>`,styles:[`.cutoff{padding:20px;border:1px solid #d8e5e1;border-radius:16px;background:#fff;margin:16px 0;color:#28443a}.cutoff.is-collapsed{display:flex;justify-content:flex-end;margin:12px 0 0;padding:0;border:0;background:transparent}button{min-height:44px;padding:8px 16px;border:1px solid #197664;background:#eff8f5;border-radius:8px;color:#155c4e;cursor:pointer}button:disabled{opacity:.5;cursor:default}label{display:grid;gap:8px;margin:12px 0}textarea{padding:10px;border:1px solid #b8ccc4;border-radius:8px}dl{display:grid;grid-template-columns:minmax(100px,1fr) 2fr;gap:8px;margin:12px 0}dt{color:#567168}dd{margin:0;overflow-wrap:anywhere}details{padding:10px 0;border-bottom:1px solid #edf2f0}.differences{max-height:480px;overflow:auto;margin:12px 0}.source{display:inline-block;margin-right:20px}`]})
+}</section>`,styles:[`:host{display:block;flex:0 0 auto;margin-left:auto}:host(.expanded){flex:1 0 100%;margin-left:0}.cutoff{padding:20px;border:1px solid #d8e5e1;border-radius:16px;background:#fff;margin:16px 0;color:#28443a}.cutoff.is-collapsed{display:flex;justify-content:flex-end;margin:0;padding:0;border:0;background:transparent}.cutoff.is-collapsed button{min-height:32px;padding:5px 11px;border-color:#c6d8d1;background:#fff;color:#4c675c;font-size:12px}button{min-height:44px;padding:8px 16px;border:1px solid #197664;background:#eff8f5;border-radius:8px;color:#155c4e;cursor:pointer}button:disabled{opacity:.5;cursor:default}label{display:grid;gap:8px;margin:12px 0}textarea{padding:10px;border:1px solid #b8ccc4;border-radius:8px}dl{display:grid;grid-template-columns:minmax(100px,1fr) 2fr;gap:8px;margin:12px 0}dt{color:#567168}dd{margin:0;overflow-wrap:anywhere}details{padding:10px 0;border-bottom:1px solid #edf2f0}.differences{max-height:480px;overflow:auto;margin:12px 0}.source{display:inline-block;margin-right:20px}`]})
 export class PayrollCutoffComponent {
  readonly month=input.required<string>();readonly canConfirm=input(false);readonly changed=output<void>();readonly busy=signal(false);readonly error=signal('');readonly data=signal<Cutoff|null>(null);reason='';private readonly ops=inject(OperationsService);
  sourceName(value:string):string{return ({'54':'预约','59':'完课','60':'复习'} as Record<string,string>)[value]||'来源记录';}

Некоторые файлы не были показаны из-за большого количества измененных файлов