feat(pool): 引入 pro_first 调度预设、Pool 候选持久化跳过与诊断信息优化

- 新增 pro_first 调度预设(Pro 优先),更新 plus_first 仅针对 Plus 计划,移除 free_team_first
- Pool 内部候选(pool_key_index 不为空)跳过 DB 持久化(available/skipped/unused 均适用)
- LRU 排序新增 catalog_lru_score 回退:runtime 无记录时使用 last_used_at_unix_secs
- 执行路径 miss 诊断消息细化为中文,按 reason 分类输出可读说明
- build_local_request_candidate_status_record 补充 extra_data 和 created_at_unix_ms 字段
- OpenAI CLI 计划构建流程补充候选评估进度跟踪与 terminal reason 设置
- 前端 PoolSchedulingDialog 增加 pro_first 预设展示,修复 LRU 默认预设检测逻辑
This commit is contained in:
fawney19
2026-04-24 13:29:05 +08:00
parent f29649e3a8
commit f3c9835759
27 changed files with 950 additions and 153 deletions

View File

@@ -1,5 +1,9 @@
import { describe, expect, it } from 'vitest'
import { parseDateLike } from '../date'
import { dateTimeLocalToRfc3339, formatDateTimeLocalInput, parseDateLike } from '../date'
function padDatePart(value: number): string {
return String(value).padStart(2, '0')
}
describe('parseDateLike', () => {
it('parses date-only strings as local calendar dates', () => {
@@ -17,3 +21,27 @@ describe('parseDateLike', () => {
expect(date.toISOString()).toBe('2026-04-12T15:30:00.000Z')
})
})
describe('datetime-local conversion', () => {
it('formats RFC3339 instants for datetime-local inputs using local clock fields', () => {
const date = new Date('2026-04-12T15:30:00Z')
const expected = [
date.getFullYear(),
padDatePart(date.getMonth() + 1),
padDatePart(date.getDate()),
].join('-') + `T${padDatePart(date.getHours())}:${padDatePart(date.getMinutes())}`
expect(formatDateTimeLocalInput('2026-04-12T15:30:00Z')).toBe(expected)
})
it('converts datetime-local values to RFC3339 instants', () => {
expect(dateTimeLocalToRfc3339('2026-04-12T15:30')).toBe(
new Date(2026, 3, 12, 15, 30).toISOString(),
)
})
it('omits blank datetime-local values', () => {
expect(dateTimeLocalToRfc3339('')).toBeUndefined()
expect(formatDateTimeLocalInput(undefined)).toBe('')
})
})

View File

@@ -1,5 +1,9 @@
const DATE_ONLY_PATTERN = /^(\d{4})-(\d{2})-(\d{2})$/
function padDatePart(value: number): string {
return String(value).padStart(2, '0')
}
/**
* 将 `YYYY-MM-DD` 解析为本地时区日期,避免浏览器按 UTC 解析后串天。
* 其他带时间/时区的信息仍交给原生 Date 处理。
@@ -13,3 +17,26 @@ export function parseDateLike(dateString: string): Date {
const [, year, month, day] = matched
return new Date(Number(year), Number(month) - 1, Number(day))
}
export function formatDateTimeLocalInput(dateString: string | null | undefined): string {
if (!dateString) return ''
const date = new Date(dateString)
if (Number.isNaN(date.getTime())) return ''
const year = date.getFullYear()
const month = padDatePart(date.getMonth() + 1)
const day = padDatePart(date.getDate())
const hours = padDatePart(date.getHours())
const minutes = padDatePart(date.getMinutes())
return `${year}-${month}-${day}T${hours}:${minutes}`
}
export function dateTimeLocalToRfc3339(value: string | null | undefined): string | undefined {
const trimmed = value?.trim()
if (!trimmed) return undefined
const parsed = new Date(trimmed)
return Number.isNaN(parsed.getTime()) ? undefined : parsed.toISOString()
}