Преглед изворни кода

ui: simplify teacher home cumulative income display

彭峰 пре 6 дана
родитељ
комит
1a09919c03

+ 1 - 1
docs/features/teacher-earnings-2026-10-15.md

@@ -8,7 +8,7 @@
 - 销课记录和结课结果显示实际课酬,合法零元与工资待核对分开。无统一固定单价、无测试账号工资特例。
 - 复习首次完成按数据库生成的北京时间完成时间计薪。当天 1 元、逾期 0 元、未来拒绝,重试返回原凭据;状态与收入同事务。行锁后取实际服务器时间,避免请求排队跨午夜仍使用请求开始时间。旧 content_update 入口同样受规则约束。
 - 首页仅显示全部今日任务,按每页 100 条完整加载后显示;发送 scope 与明确日期兼容旧接口,并在客户端过滤非今日记录,计数与列表一致。每条“查看计划”进入该任务详情;底部只保留“查看全部学员复习计划”,进入完整日历。没有任务、全部完成与加载失败分别呈现。
-- 首页、我的、销课和复习工资使用后台同一计算规则与净收入视图。老师收入是累计已记账收入,与工资实际发放分开;不再按课次数乘 20/40 元估算。缺失工资依据计入待核对数量。
+- 首页、我的、销课和复习工资使用后台同一计算规则与净收入视图。老师收入是累计已记账收入,与工资实际发放分开;不再按课次数乘 20/40 元估算。缺失工资依据计入待核对数量。首页按最新反馈简化为累计时长与累计收入一行:时长直接显示,总收入默认隐藏,眼睛切换显隐;首页移除收入拆分、发放说明和待核对提示,具体明细仍从原入口查看。
 - 老师浏览日历、销课、工资、课程详情等页面保留现有底部导航。复习页去除内容区重复的“返回复习任务”,沿用左上角返回;练习中未提交离开有提示,提交中禁止离开;完成后有继续今日、返回原列表及首页,原列表日期、学生、页码与滚动位置可恢复。缓存隔离账号、日期、筛选和业务数据版本,跨页/标签写入失效;首页今日列表单独按登录账号、会话与北京时间自然日缓存到 sessionStorage,返回首页、切回前台和同日重载页面均复用,跨日/切换账号/新登录重新加载;手动刷新保留。服务器确认复习成功后更新缓存任务及计数,不重拉列表。
 - 历史错计提供只读核对工具、后台筛选和逐条纠正入口。原凭据不可改写;未结算来源净额冲销,草稿行移除,已审核/已发放原单保留,后续草稿记唯一关联调整。理由、原金额、调整金额和工资单可导出。没有运行历史纠正。
 

+ 1 - 7
projects/xiaoshu-mobile/src/app/features/home/home-page.component.html

@@ -20,14 +20,8 @@
           <div><strong>{{ statsLoading() ? '—' : (stats()['t_tiyan'] || 0) }}</strong><span>体验课</span></div>
           <div><strong>{{ statsLoading() ? '—' : (stats()['t_total'] || 0) }}</strong><span>上课总次数</span></div>
         </div>
-        <div class="coach-footer"><span>累计时长 {{ statsLoading() ? '—' : (stats()['t_shichang'] || 0) }}</span><span class="commission">累计收入<button type="button" (click)="commissionHidden.set(!commissionHidden())" [attr.aria-label]="commissionHidden() ? '显示累计收入' : '隐藏累计收入'"><lucide-icon [img]="commissionHidden() ? icons.EyeOff : icons.Eye" [size]="20" /></button></span></div>
+        <div class="coach-footer"><span>累计时长 {{ statsLoading() ? '—' : (stats()['t_shichang'] || 0) }}</span><span class="commission">累计收入 <span class="commission-amount">{{ commissionHidden() ? '***' : (statsLoading() || stats()['totalIncome'] == null ? '—' : '¥' + (stats()['totalIncome'] | number:'1.2-2')) }}</span><button type="button" (click)="commissionHidden.set(!commissionHidden())" [attr.aria-label]="commissionHidden() ? '显示累计收入' : '隐藏累计收入'"><lucide-icon [img]="commissionHidden() ? icons.EyeOff : icons.Eye" [size]="20" /></button></span></div>
       }
-      <div class="income-breakdown" aria-label="累计收入">
-        <a routerLink="/pages/member/ke_xiao"><span>累计带课工资</span><strong>{{ commissionHidden() ? '***' : (stats()['lessonIncome'] == null ? '—' : '¥' + (stats()['lessonIncome'] | number:'1.2-2')) }}</strong></a>
-        <a routerLink="/pages/member/ke_fuxi"><span>累计复习工资</span><strong>{{ commissionHidden() ? '***' : (stats()['reviewIncome'] == null ? '—' : '¥' + (stats()['reviewIncome'] | number:'1.2-2')) }}</strong></a>
-        <div><span>累计总收入</span><strong>{{ commissionHidden() ? '***' : (stats()['totalIncome'] == null ? '—' : '¥' + (stats()['totalIncome'] | number:'1.2-2')) }}</strong></div>
-      </div>
-      <small>已记账收入,不代表已发放@if (stats()['pendingPayCount']) { · {{ stats()['pendingPayCount'] }} 节工资待核对 }</small>
     </section>
 
     <section class="coach-memory-board" aria-labelledby="coach-memory-title">

+ 1 - 1
projects/xiaoshu-mobile/src/app/features/home/home-page.component.scss

@@ -166,4 +166,4 @@
 @media (min-width: 620px) { .home-main { padding-inline: 22px; } .memory-content { grid-template-columns: 280px minmax(0, 1fr); } .day-ring { width: 190px; height: 190px; } .memory-dot { transform: rotate(var(--angle)) translateY(-84px); } .today-panel { padding: 8px 30px 0; } .product-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
 @media (prefers-reduced-motion: reduce) { .state-spinner { animation-duration: 1.6s; } }
 
-.income-breakdown{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin:16px 0 8px}.income-breakdown a,.income-breakdown>div{display:flex;flex-direction:column;gap:6px;min-height:48px;color:inherit;text-decoration:none}.income-breakdown span{font-size:12px}.income-breakdown strong{font-size:18px;overflow-wrap:anywhere}.commission button{min-width:44px;min-height:44px}.today-complete{padding:12px;color:var(--brand-strong)}
+.commission button{min-width:44px;min-height:44px}.today-complete{padding:12px;color:var(--brand-strong)}

+ 13 - 2
scripts/check-teacher-earnings-browser.mjs

@@ -35,8 +35,19 @@ try{
  });
  const page=await context.newPage();page.on('pageerror',e=>errors.push(e.message));page.on('dialog',d=>d.accept());
  await page.goto(origin+'/pages/home/index');await page.locator('.coach-memory-list article').waitFor();
- assert.match(await page.locator('.income-breakdown').innerText(),/\*\*\*/);await page.getByRole('button',{name:'显示累计收入'}).click();await page.waitForFunction(()=>document.querySelector('.income-breakdown')?.textContent.includes('¥122.00'));assert.match(await page.locator('.income-breakdown').innerText(),/¥120\.00[\s\S]*¥2\.00[\s\S]*¥122\.00/);
- assert.ok(calls.some(p=>p.action==='app_review_page'&&p.scope==='today'&&p.pageSize===100&&p.date===day&&p.includeMetadata===false));checks.push('首页当天范围、三项累计收入同显同隐');
+ assert.match(await page.locator('.commission').innerText(), /累计收入[\s\S]*\*\*\*/);
+ assert.match(await page.locator('.coach-footer').innerText(), /累计时长 2\.5/);
+ assert.equal(await page.locator('.income-breakdown').count(),0);
+ assert.doesNotMatch(await page.locator('.coach-hero').innerText(), /累计带课工资|累计复习工资|已记账收入|不代表已发放|工资待核对/);
+ await page.getByRole('button',{name:'显示累计收入'}).click();
+ await page.waitForFunction(()=>document.querySelector('.commission')?.textContent.includes('¥122.00'));
+ assert.match(await page.locator('.commission').innerText(), /¥122\.00/);
+ await page.getByRole('button',{name:'隐藏累计收入'}).click();
+ await page.waitForFunction(()=>document.querySelector('.commission')?.textContent.includes('***'));
+ assert.doesNotMatch(await page.locator('.commission').innerText(), /¥122/);
+ await page.getByRole('button',{name:'显示累计收入'}).click();
+ await page.waitForFunction(()=>document.querySelector('.commission')?.textContent.includes('¥122.00'));
+ assert.ok(calls.some(p=>p.action==='app_review_page'&&p.scope==='today'&&p.pageSize===100&&p.date===day&&p.includeMetadata===false));checks.push('首页当天范围、仅保留时长和总收入、默认隐藏且眼睛可切换');
  await page.screenshot({path:out+'/home-390.png',fullPage:true});
  await page.getByRole('button',{name:'查看计划',exact:true}).click();await page.locator('.record-list').waitFor();assert.equal(await page.getByRole('button',{name:'返回复习任务',exact:true}).count(),0);await page.screenshot({path:out+'/review-390.png',fullPage:true});await page.getByRole('button',{name:'返回',exact:true}).click();await page.locator('.coach-memory-list article').waitFor();assert.equal(calls.filter(p=>p.action==='app_review_page'&&p.scope==='today').length,1);await page.getByRole('button',{name:'查看计划',exact:true}).click();await page.locator('.record-list').waitFor();checks.push('复习页仅保留顶部返回,返回首页不重新加载任务');await page.getByRole('button',{name:'结束本次复习',exact:true}).click();await page.locator('.review-complete').waitFor();assert.match(await page.locator('.review-complete').innerText(),/本次收入 ¥1\.00/);await page.screenshot({path:out+'/review-complete-390.png',fullPage:true});
  await page.getByRole('link',{name:'返回首页',exact:true}).click();await page.getByText('今天的复习任务已全部完成').waitFor();checks.push('完成结果显示服务器金额、返回首页更新缓存计数且不重新请求');