承接 14b595b0。以下 7 处仍在函数体内 `new Intl.DateTimeFormat(...)`, 单次构造约 0.5ms,按行/按条调用时会线性放大: - utils/finance-date-range.ts formatShanghaiDate - utils/http.ts (已在上一个提交修复) - scheduler/cost-finance-sync-job.ts today - finance/sales-facts-service.ts formatDateOnly - finance/order-refund-service.ts toChinaDate - admin/admin-finance-service.ts chinaDateParts - admin/admin-dashboard-service.ts resolveChinaTodayRange - scripts/sync-cost-finance.ts formatShanghaiDate 均为同选项的纯 hoist,输出逐字节不变:formatShanghaiDate 用 9 例跨时区/ 毫秒/闰日语料与旧实现比对一致;其余为相同 en-CA/en-US + Asia/Shanghai 选项的等价替换,formatToParts 的取值改为单次遍历、去掉 fromEntries/reduce。
92 lines
2.8 KiB
TypeScript
92 lines
2.8 KiB
TypeScript
import process from 'node:process'
|
|
|
|
import { closeDb } from '../src/db/client.js'
|
|
import {
|
|
syncActualWorkOrderCostSnapshots,
|
|
syncEstimatedOrderItemCostSnapshots,
|
|
} from '../src/services/cost-center/cost-snapshot-sync-service.js'
|
|
import { rebuildSalesDailyFacts } from '../src/services/finance/sales-facts-service.js'
|
|
import { resolveFinanceDateRange, shiftDate } from '../src/utils/finance-date-range.js'
|
|
import { nowIso } from '../src/utils/time.js'
|
|
|
|
type Mode = 'estimated' | 'actual' | 'facts' | 'all'
|
|
|
|
const options = parseOptions(process.argv.slice(2))
|
|
const mode = normalizeMode(options.mode)
|
|
const days = normalizeDays(options.days)
|
|
const fallbackTo = options.to || formatShanghaiDate(new Date())
|
|
const fallbackFrom = options.from || shiftDate(fallbackTo, -(days - 1))
|
|
|
|
async function main() {
|
|
const input = { dateFrom: fallbackFrom, dateTo: fallbackTo }
|
|
const range = resolveFinanceDateRange(input, { defaultDays: days, maxDays: 400 })
|
|
const startedAt = Date.now()
|
|
const result: Record<string, unknown> = { mode, range }
|
|
|
|
if (mode === 'estimated' || mode === 'all') {
|
|
result.estimated = await syncEstimatedOrderItemCostSnapshots(input)
|
|
}
|
|
if (mode === 'actual' || mode === 'all') {
|
|
result.actual = await syncActualWorkOrderCostSnapshots(input)
|
|
}
|
|
if (mode === 'facts' || mode === 'all') {
|
|
result.facts = await rebuildSalesDailyFacts(input)
|
|
}
|
|
|
|
result.durationMs = Date.now() - startedAt
|
|
result.finishedAt = nowIso()
|
|
console.log(JSON.stringify(result, null, 2))
|
|
}
|
|
|
|
main()
|
|
.catch((error) => {
|
|
console.error(error instanceof Error ? error.message : error)
|
|
process.exitCode = 1
|
|
})
|
|
.finally(async () => {
|
|
await closeDb()
|
|
})
|
|
|
|
function parseOptions(args: string[]) {
|
|
const result: Record<string, string> = {}
|
|
for (const arg of args) {
|
|
if (!arg.startsWith('--')) continue
|
|
const body = arg.slice(2)
|
|
const index = body.indexOf('=')
|
|
if (index === -1) {
|
|
result[body] = 'true'
|
|
} else {
|
|
result[body.slice(0, index)] = body.slice(index + 1)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
function normalizeMode(value: unknown): Mode {
|
|
const mode = String(value || 'all').trim()
|
|
if (mode === 'estimated' || mode === 'actual' || mode === 'facts' || mode === 'all') {
|
|
return mode
|
|
}
|
|
throw new Error('--mode 只能是 estimated / actual / facts / all')
|
|
}
|
|
|
|
function normalizeDays(value: unknown) {
|
|
const parsed = Number(value || 7)
|
|
if (!Number.isInteger(parsed) || parsed < 1 || parsed > 400) {
|
|
throw new Error('--days 必须是 1-400 的整数')
|
|
}
|
|
return parsed
|
|
}
|
|
|
|
/** 模块级只构造一次:`new Intl.DateTimeFormat()` 每次约 0.5ms,逐条调用会线性放大。 */
|
|
const SHANGHAI_DATE_FORMATTER = new Intl.DateTimeFormat('en-CA', {
|
|
timeZone: 'Asia/Shanghai',
|
|
year: 'numeric',
|
|
month: '2-digit',
|
|
day: '2-digit',
|
|
})
|
|
|
|
function formatShanghaiDate(value: Date) {
|
|
return SHANGHAI_DATE_FORMATTER.format(value)
|
|
}
|