master
lion 2 months ago
parent b091301ab1
commit 5ff81cb011

@ -69,7 +69,8 @@ export async function createCompetition(payload: CompetitionPayload): Promise<Co
}
export async function updateCompetition(id: number, payload: CompetitionPayload): Promise<CompetitionRow> {
const { data } = await adminHttp.put<unknown>(`/competitions/${id}`, payload)
// 正式环境部分网关会挂起 PUT,改用 PATCH
const { data } = await adminHttp.patch<unknown>(`/competitions/${id}`, payload)
const body = (data as { data?: CompetitionRow })?.data ?? (data as CompetitionRow)
if (!body || typeof body !== 'object') throw new Error('更新响应无效')
return body as CompetitionRow

@ -0,0 +1,63 @@
/** 业务时间统一按北京时间(Asia/Shanghai,无夏令时)处理。 */
const SHANGHAI = 'Asia/Shanghai'
function pad(n: number): string {
return String(n).padStart(2, '0')
}
/**
* API ISO / 任意可解析时间 → 日期时间选择器模型(北京时间 `YYYY-MM-DD HH:mm:ss`)。
*/
export function toShanghaiPickerValue(iso: string | null | undefined): string | null {
if (!iso) return null
const d = new Date(iso)
if (Number.isNaN(d.getTime())) return null
const parts = new Intl.DateTimeFormat('en-GB', {
timeZone: SHANGHAI,
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hourCycle: 'h23',
}).formatToParts(d)
const get = (type: Intl.DateTimeFormatPartTypes): string =>
parts.find((p) => p.type === type)?.value ?? '00'
const hour = get('hour') === '24' ? '00' : get('hour')
return `${get('year')}-${get('month')}-${get('day')} ${hour}:${get('minute')}:${get('second')}`
}
/**
* 选择器值(按北京时间理解)→ API ISO8601(带偏移,避免被当成 UTC)。
*/
export function fromShanghaiPickerValue(s: string | null | undefined): string | null {
const t = (s ?? '').trim()
if (!t) return null
const m = t.match(/^(\d{4})-(\d{2})-(\d{2})[ T](\d{2}):(\d{2})(?::(\d{2}))?/)
if (!m) return null
const [, y, mo, d, h, mi, sec = '00'] = m
return `${y}-${mo}-${d}T${h}:${mi}:${sec}+08:00`
}
/** 列表/详情展示用北京时间。 */
export function formatShanghaiDateTime(iso: string | null | undefined, empty = '—'): string {
const v = toShanghaiPickerValue(iso)
if (!v) return empty
return v.replace(/:\d{2}$/, '') // YYYY-MM-DD HH:mm
}
export function formatShanghaiDateTimeFull(iso: string | null | undefined, empty = '—'): string {
return toShanghaiPickerValue(iso) ?? empty
}
/** 调试/校验用 */
export function shanghaiOffsetLabel(): string {
return `${SHANGHAI} (UTC+8)`
}
export { pad }

@ -10,6 +10,7 @@ import type {
} from '../../api/admin/types'
import { useAdminCompetitionStore } from '../../stores/adminCompetition'
import { competitionStatusLabel } from '../../utils/competitionAdminLabels'
import { formatShanghaiDateTime } from '../../utils/datetimeShanghai'
type SetupKey = keyof AdminDashboardSetup
@ -147,8 +148,7 @@ async function loadDashboard() {
function formatDateTime(value: string | null | undefined): string {
if (!value) return '未配置'
const d = new Date(value)
return Number.isNaN(d.getTime()) ? value : d.toLocaleString()
return formatShanghaiDateTime(value, '未配置')
}
function statusTagType(status: string): 'success' | 'info' | 'warning' | 'danger' | 'primary' {

@ -15,6 +15,7 @@ import {
} from '../../../api/admin/competitions'
import * as formSchemaApi from '../../../api/admin/formSchemas'
import { setSignupFieldRegistry } from '../../../utils/signupApplicationFields'
import { fromShanghaiPickerValue, toShanghaiPickerValue } from '../../../utils/datetimeShanghai'
import {
createSignupChannel,
getSignupChannel,
@ -337,22 +338,14 @@ function resolveCompetitionId(): number | null {
return sid && sid > 0 ? sid : null
}
/** API ISO → Element Plus 日期时间选择器(value-format `YYYY-MM-DD HH:mm:ss`,本地时区) */
/** API ISO → Element Plus 日期时间选择器(北京时间 `YYYY-MM-DD HH:mm:ss`) */
function toElDateTimeModel(iso: string | null | undefined): string | null {
if (!iso) return null
const d = new Date(iso)
if (Number.isNaN(d.getTime())) return null
const pad = (n: number) => String(n).padStart(2, '0')
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`
return toShanghaiPickerValue(iso)
}
/** 选择器北京时间 → API(显式 +08:00,避免被当成 UTC 再偏移) */
function fromDatetimePickerValue(s: string | null | undefined): string | null {
const t = (s ?? '').trim()
if (!t) return null
const forParse = t.includes('T') ? t : t.replace(/^(\d{4}-\d{2}-\d{2})\s+/, '$1T')
const d = new Date(forParse)
if (Number.isNaN(d.getTime())) return null
return d.toISOString()
return fromShanghaiPickerValue(s)
}
async function refreshSignupSchemas() {

@ -4,6 +4,7 @@ import { ElMessage } from 'element-plus'
import { listCompetitions } from '../../../api/admin/competitions'
import type { CompetitionRow } from '../../../api/admin/types'
import { competitionStatusLabel } from '../../../utils/competitionAdminLabels'
import { formatShanghaiDateTime } from '../../../utils/datetimeShanghai'
import { useAdminCompetitionStore } from '../../../stores/adminCompetition'
const rows = ref<CompetitionRow[]>([])
@ -37,9 +38,7 @@ function goPage(p: number) {
}
function formatDt(iso: string | null) {
if (!iso) return '—'
const d = new Date(iso)
return Number.isNaN(d.getTime()) ? iso : d.toLocaleString()
return formatShanghaiDateTime(iso)
}
onMounted(() => {

Loading…
Cancel
Save