merge: 合并远程更新并保留签名与报表接入
This commit is contained in:
@@ -24,7 +24,8 @@ const useMockData = mockFlags.workbenchHome
|
||||
|
||||
interface MockCampusOverview {
|
||||
summary: WorkbenchOverviewResponse['summary']
|
||||
trend: WorkbenchTrendPoint[]
|
||||
/** 趋势的日均人次基数(按「院区 + 日期」播种出每天的具体值,见 createTrend) */
|
||||
trendBase: number
|
||||
todos: WorkbenchTodoTask[]
|
||||
ranking: Array<Omit<WorkbenchDocumentRanking, 'signedCount'> & { baseCount: number }>
|
||||
}
|
||||
@@ -39,15 +40,7 @@ const mockCampusOverviews: Record<WorkbenchCampus, MockCampusOverview> = {
|
||||
availableTemplates: 128,
|
||||
coveredDepartments: 9,
|
||||
},
|
||||
trend: [
|
||||
{ label: '8/21', value: 24 },
|
||||
{ label: '8/22', value: 31 },
|
||||
{ label: '8/23', value: 28 },
|
||||
{ label: '8/24', value: 35 },
|
||||
{ label: '8/25', value: 32 },
|
||||
{ label: '8/26', value: 39 },
|
||||
{ label: '8/27', value: 36 },
|
||||
],
|
||||
trendBase: 32,
|
||||
todos: [
|
||||
{
|
||||
id: 'T0818003',
|
||||
@@ -128,15 +121,7 @@ const mockCampusOverviews: Record<WorkbenchCampus, MockCampusOverview> = {
|
||||
availableTemplates: 76,
|
||||
coveredDepartments: 6,
|
||||
},
|
||||
trend: [
|
||||
{ label: '8/21', value: 15 },
|
||||
{ label: '8/22', value: 18 },
|
||||
{ label: '8/23', value: 17 },
|
||||
{ label: '8/24', value: 23 },
|
||||
{ label: '8/25', value: 20 },
|
||||
{ label: '8/26', value: 25 },
|
||||
{ label: '8/27', value: 22 },
|
||||
],
|
||||
trendBase: 20,
|
||||
todos: [
|
||||
{
|
||||
id: 'T0818001',
|
||||
@@ -216,15 +201,7 @@ const mockCampusOverviews: Record<WorkbenchCampus, MockCampusOverview> = {
|
||||
availableTemplates: 54,
|
||||
coveredDepartments: 5,
|
||||
},
|
||||
trend: [
|
||||
{ label: '8/21', value: 11 },
|
||||
{ label: '8/22', value: 14 },
|
||||
{ label: '8/23', value: 13 },
|
||||
{ label: '8/24', value: 16 },
|
||||
{ label: '8/25', value: 15 },
|
||||
{ label: '8/26', value: 19 },
|
||||
{ label: '8/27', value: 17 },
|
||||
],
|
||||
trendBase: 15,
|
||||
todos: [
|
||||
{
|
||||
id: 'T0818021',
|
||||
@@ -301,6 +278,62 @@ function getPeriodFactor(period: HomeRankingPeriod) {
|
||||
return period === 7 ? 1 : period === 14 ? 2 : 3.5
|
||||
}
|
||||
|
||||
/** 「院区 + 日期」→ 固定种子:同一天同一院区的数值不随刷新、切换时段或翻页而变 */
|
||||
function hashSeed(text: string) {
|
||||
let hash = 2166136261
|
||||
|
||||
for (let index = 0; index < text.length; index += 1) {
|
||||
hash ^= text.charCodeAt(index)
|
||||
hash = Math.imul(hash, 16777619)
|
||||
}
|
||||
|
||||
return hash >>> 0
|
||||
}
|
||||
|
||||
/** mulberry32:小、快、同种子可复现(与 api/workbench/report-analytics.ts 同一套做法) */
|
||||
function createRandom(seed: number) {
|
||||
let state = seed >>> 0
|
||||
|
||||
return () => {
|
||||
state = (state + 0x6d2b79f5) >>> 0
|
||||
let t = state
|
||||
t = Math.imul(t ^ (t >>> 15), t | 1)
|
||||
t ^= t + Math.imul(t ^ (t >>> 7), t | 61)
|
||||
|
||||
return ((t ^ (t >>> 14)) >>> 0) / 4294967296
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 演示趋势:近 period 天(含今天)的已签署人次。
|
||||
*
|
||||
* 为什么不用写死的日期数组:写死 8/21–8/27 之后,演示日一过「近 7 天」窗口就全是过期日期
|
||||
* (仓库的演示数据铁律:**日期相对** + **确定性**,不要 Math.random)。
|
||||
* 末点取今日已签署,与指标卡同源 —— 原型里趋势最后一点就是今天已签署的任务数。
|
||||
*/
|
||||
function createTrend(
|
||||
campus: WorkbenchCampus,
|
||||
summary: WorkbenchOverviewResponse['summary'],
|
||||
period: HomeRankingPeriod,
|
||||
): WorkbenchTrendPoint[] {
|
||||
const points: WorkbenchTrendPoint[] = []
|
||||
const base = (mockCampusOverviews[campus] ?? mockCampusOverviews['本部院区']).trendBase
|
||||
|
||||
for (let offset = period - 1; offset >= 0; offset -= 1) {
|
||||
const day = new Date()
|
||||
day.setDate(day.getDate() - offset)
|
||||
const label = `${day.getMonth() + 1}/${day.getDate()}`
|
||||
const value =
|
||||
offset === 0
|
||||
? summary.todaySigned
|
||||
: Math.max(base + Math.round(createRandom(hashSeed(`${campus}-${label}`))() * 12 - 5), 0)
|
||||
|
||||
points.push({ label, value })
|
||||
}
|
||||
|
||||
return points
|
||||
}
|
||||
|
||||
function createRanking(
|
||||
rows: MockCampusOverview['ranking'],
|
||||
period: HomeRankingPeriod,
|
||||
@@ -317,7 +350,15 @@ function createRanking(
|
||||
.sort((left, right) => right.signedCount - left.signedCount)
|
||||
}
|
||||
|
||||
const TODO_LIMIT = 8
|
||||
/**
|
||||
* 首页「我的待办」最多几条。
|
||||
*
|
||||
* 原型 `renderDash()` 是 `tasks.slice(0, 5)`(最多 5 条)。
|
||||
* 仓库收成 **3 条**(2026-09-30 定):趋势卡与待办卡同行,待办越多行高越高,
|
||||
* 图是按宽度定高的、贴底后会在标题与图之间留大片空白 —— 3 条时两张卡高度基本齐平。
|
||||
* 该上限同时作为 `todoLimit` 传给后端,避免取回一批再丢掉。
|
||||
*/
|
||||
const TODO_LIMIT = 3
|
||||
const RANKING_LIMIT = 10
|
||||
let campusIds: Map<string, string> | null = null
|
||||
let campusIdsRequest: Promise<Map<string, string>> | null = null
|
||||
@@ -423,11 +464,12 @@ export async function getWorkbenchOverview(
|
||||
): Promise<WorkbenchOverviewResponse> {
|
||||
if (useMockData) {
|
||||
const overview = mockCampusOverviews[query.campus] ?? mockCampusOverviews['本部院区']
|
||||
const summary = { ...overview.summary }
|
||||
|
||||
return {
|
||||
summary: { ...overview.summary },
|
||||
trend: overview.trend.map((point) => ({ ...point })),
|
||||
todos: overview.todos.map((task) => ({ ...task })),
|
||||
summary,
|
||||
trend: createTrend(query.campus, summary, query.rankingPeriod),
|
||||
todos: overview.todos.slice(0, TODO_LIMIT).map((task) => ({ ...task })),
|
||||
documentRanking: createRanking(overview.ranking, query.rankingPeriod),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user