fix: 补 .gitattributes(CRLF for .bat) + README 端口 19540 + 提交 console 锁文件

This commit is contained in:
AskaEth committed 2026-09-09 20:57:58 +08:00
1 parent c121111f51
commit b80c64a115
39 files changed
+4217 -345

No files matched your search

+61 -1
View File
@@ -5,8 +5,19 @@
* 直接断言会把服务端字段改名这类问题推迟到运行期某个深处才炸。
*/
/**
* FormData / Blob(含 File)/ URLSearchParams 不是普通对象:
* 展开或 JSON 序列化都会丢掉内容,必须原样交给 fetch(报名表导入就是被展平才丢文件)。
*/
export function isRawBody(value: unknown): value is FormData | Blob | URLSearchParams {
if (typeof FormData !== 'undefined' && value instanceof FormData) return true
if (typeof Blob !== 'undefined' && value instanceof Blob) return true
if (typeof URLSearchParams !== 'undefined' && value instanceof URLSearchParams) return true
return false
}
export function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null && !Array.isArray(value)
return typeof value === 'object' && value !== null && !Array.isArray(value) && !isRawBody(value)
}
export function readString(source: unknown, key: string): string | null {
@@ -14,3 +25,52 @@ export function readString(source: unknown, key: string): string | null {
const value = source[key]
return typeof value === 'string' ? value : null
}
export function asRecord(value: unknown): Record<string, unknown> {
return isRecord(value) ? value : {}
}
/** 依次取第一个可用值:容忍服务端把数字写成字符串(settings 表存的是文本)。 */
export function firstString(...values: unknown[]): string | null {
for (const value of values) {
if (typeof value === 'string') return value
}
return null
}
export function firstNumber(def: number, ...values: unknown[]): number {
const found = firstNumberOrNull(...values)
return found === null ? def : found
}
export function firstNumberOrNull(...values: unknown[]): number | null {
for (const value of values) {
if (typeof value === 'number' && Number.isFinite(value)) return value
if (typeof value === 'string' && value.trim() !== '') {
const parsed = Number(value)
if (Number.isFinite(parsed)) return parsed
}
}
return null
}
export function firstBool(def: boolean, ...values: unknown[]): boolean {
for (const value of values) {
if (typeof value === 'boolean') return value
if (typeof value === 'number') return value !== 0
if (typeof value === 'string') {
const normalized = value.trim().toLowerCase()
if (normalized === 'true' || normalized === '1' || normalized === 'yes' || normalized === 'on') {
return true
}
if (normalized === 'false' || normalized === '0' || normalized === 'no' || normalized === 'off') {
return false
}
}
}
return def
}
export function emptyToNull(value: string | null): string | null {
return value === null || value.trim() === '' ? null : value
}