feat: 全平台时间显示统一为北京时间 (Asia/Shanghai)
新增 formatTime 工具函数,强制使用 Asia/Shanghai 时区,
替换两个平台所有视图中裸 toLocaleString('zh-CN') 调用。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
这个提交包含在:
父节点
2b7857a820
当前提交
c4373c8cc1
@ -0,0 +1,7 @@
|
||||
const TZ = 'Asia/Shanghai'
|
||||
|
||||
export function formatTime(value: string | number | null | undefined): string {
|
||||
if (value === null || value === undefined || value === '') return '-'
|
||||
const date = new Date(value as string | number)
|
||||
return Number.isNaN(date.getTime()) ? '-' : date.toLocaleString('zh-CN', { timeZone: TZ })
|
||||
}
|
||||
@ -55,6 +55,7 @@
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { opsApi, type AppDetail } from '@/api/ops'
|
||||
import { formatTime } from '@/utils/date'
|
||||
|
||||
const route = useRoute()
|
||||
const detail = ref<AppDetail | null>(null)
|
||||
@ -65,9 +66,7 @@ async function loadDetail() {
|
||||
detail.value = res.data.data
|
||||
}
|
||||
|
||||
function fmt(value: string) {
|
||||
return value ? new Date(value).toLocaleString('zh-CN') : '-'
|
||||
}
|
||||
const fmt = formatTime
|
||||
|
||||
function mask(value: string) {
|
||||
if (!value) return '-'
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
<template #default="{ row }">{{ row.tenantName || row.tenantId }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createdAt" label="创建时间" width="180">
|
||||
<template #default="{ row }">{{ new Date(row.createdAt).toLocaleString('zh-CN') }}</template>
|
||||
<template #default="{ row }">{{ formatTime(row.createdAt) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="160" fixed="right">
|
||||
<template #default="{ row }">
|
||||
@ -95,6 +95,7 @@ import { ref, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import { opsApi, type AppItem, type TenantItem } from '@/api/ops'
|
||||
import { formatTime } from '@/utils/date'
|
||||
|
||||
const apps = ref<AppItem[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
<el-table :data="logs" v-loading="loading" border stripe>
|
||||
<el-table-column prop="createdAt" label="时间" width="180">
|
||||
<template #default="{ row }">{{ new Date(row.createdAt).toLocaleString('zh-CN') }}</template>
|
||||
<template #default="{ row }">{{ formatTime(row.createdAt) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="operator" label="操作者" width="140" />
|
||||
<el-table-column prop="moduleType" label="模块" width="100">
|
||||
@ -35,6 +35,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { opsApi, type OpsLogItem } from '@/api/ops'
|
||||
import { formatTime } from '@/utils/date'
|
||||
|
||||
const logs = ref<OpsLogItem[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
@ -140,6 +140,7 @@
|
||||
import { reactive, ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { opsApi, type PushDeviceInfo, type PushDeviceLog, type PushDiagnostics } from '@/api/ops'
|
||||
import { formatTime } from '@/utils/date'
|
||||
|
||||
const form = reactive({ token: '', appKey: '' })
|
||||
const loading = ref(false)
|
||||
@ -201,7 +202,7 @@ async function sendTestOffline() {
|
||||
appKey: diagnostics.value.appKey,
|
||||
userId: diagnostics.value.userId,
|
||||
title: 'XuqmGroup Push 测试',
|
||||
body: `离线推送测试 ${new Date().toLocaleString('zh-CN')}`,
|
||||
body: `离线推送测试 ${formatTime(Date.now())}`,
|
||||
payload: JSON.stringify({ type: 'PUSH_TEST', ts: Date.now() }),
|
||||
})
|
||||
ElMessage.success(`已发送到 ${res.data.data.targetCount} 个设备`)
|
||||
@ -214,10 +215,7 @@ function deviceName(device: PushDeviceInfo | PushDeviceLog) {
|
||||
return [device.brand, device.model].filter(Boolean).join(' ') || '-'
|
||||
}
|
||||
|
||||
function fmt(value?: string | number) {
|
||||
if (!value) return '-'
|
||||
return new Date(value).toLocaleString('zh-CN')
|
||||
}
|
||||
const fmt = formatTime
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@ -108,6 +108,7 @@ import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { opsApi, type RiskRuleForm, type SensitiveWord } from '@/api/ops'
|
||||
import { formatTime } from '@/utils/date'
|
||||
|
||||
const isMobile = ref(window.innerWidth < 768)
|
||||
const updateViewport = () => { isMobile.value = window.innerWidth < 768 }
|
||||
@ -247,9 +248,7 @@ async function deleteWord(row: SensitiveWord) {
|
||||
}
|
||||
}
|
||||
|
||||
function fmt(value: string) {
|
||||
return value ? new Date(value).toLocaleString('zh-CN') : '-'
|
||||
}
|
||||
const fmt = formatTime
|
||||
|
||||
onMounted(() => {
|
||||
loadRules()
|
||||
|
||||
@ -80,6 +80,7 @@
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { opsApi, type ServiceRequest } from '@/api/ops'
|
||||
import { formatTime } from '@/utils/date'
|
||||
|
||||
const requests = ref<ServiceRequest[]>([])
|
||||
const loading = ref(false)
|
||||
@ -145,9 +146,7 @@ function statusLabel(status: string) {
|
||||
return status === 'APPROVED' ? '已通过' : status === 'REJECTED' ? '已拒绝' : '待审核'
|
||||
}
|
||||
|
||||
function fmt(dt: string) {
|
||||
return new Date(dt).toLocaleString('zh-CN')
|
||||
}
|
||||
const fmt = formatTime
|
||||
|
||||
onMounted(loadRequests)
|
||||
</script>
|
||||
|
||||
@ -65,6 +65,7 @@ import { computed, onMounted, ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { opsApi, type TenantDetail } from '@/api/ops'
|
||||
import { formatTime } from '@/utils/date'
|
||||
|
||||
const route = useRoute()
|
||||
const tenant = ref<TenantDetail | null>(null)
|
||||
@ -87,9 +88,7 @@ async function toggleStatus() {
|
||||
await loadDetail()
|
||||
}
|
||||
|
||||
function fmt(value: string) {
|
||||
return value ? new Date(value).toLocaleString('zh-CN') : '-'
|
||||
}
|
||||
const fmt = formatTime
|
||||
|
||||
onMounted(loadDetail)
|
||||
</script>
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createdAt" label="注册时间" width="180">
|
||||
<template #default="{ row }">{{ new Date(row.createdAt).toLocaleString('zh-CN') }}</template>
|
||||
<template #default="{ row }">{{ formatTime(row.createdAt) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120">
|
||||
<template #default="{ row }">
|
||||
@ -51,6 +51,7 @@
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { opsApi, type TenantItem } from '@/api/ops'
|
||||
import { formatTime } from '@/utils/date'
|
||||
|
||||
const tenants = ref<TenantItem[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
const TZ = 'Asia/Shanghai'
|
||||
|
||||
export function formatTime(value: string | number | null | undefined): string {
|
||||
if (value === null || value === undefined || value === '') return '-'
|
||||
const date = new Date(value as string | number)
|
||||
return Number.isNaN(date.getTime()) ? '-' : date.toLocaleString('zh-CN', { timeZone: TZ })
|
||||
}
|
||||
@ -55,6 +55,7 @@ import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { appApi, type App } from '@/api/app'
|
||||
import { formatTime } from '@/utils/date'
|
||||
|
||||
const apps = ref<App[]>([])
|
||||
const loading = ref(false)
|
||||
@ -100,9 +101,7 @@ async function handleDelete(appKey: string) {
|
||||
loadApps()
|
||||
}
|
||||
|
||||
function formatDate(d: string) {
|
||||
return d ? new Date(d).toLocaleString('zh-CN') : '-'
|
||||
}
|
||||
const formatDate = formatTime
|
||||
|
||||
function updateViewport() {
|
||||
isMobile.value = window.innerWidth < 768
|
||||
|
||||
@ -819,6 +819,7 @@ import { useRoute, useRouter } from 'vue-router'
|
||||
import { appApi, type App } from '@/api/app'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import { formatTime } from '@/utils/date'
|
||||
import {
|
||||
imAdminApi,
|
||||
type GlobalMute,
|
||||
@ -1070,11 +1071,6 @@ const globalMuteEnabled = computed({
|
||||
},
|
||||
})
|
||||
|
||||
function formatTime(value: number | string | null | undefined) {
|
||||
if (value === null || value === undefined || value === '') return '-'
|
||||
const date = new Date(value)
|
||||
return Number.isNaN(date.getTime()) ? '-' : date.toLocaleString('zh-CN')
|
||||
}
|
||||
|
||||
function formatContent(content: string) {
|
||||
if (!content) return '-'
|
||||
|
||||
@ -125,6 +125,7 @@ import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { CopyDocument } from '@element-plus/icons-vue'
|
||||
import { appApi, type App } from '@/api/app'
|
||||
import { imAdminApi, type WebhookConfig, type WebhookConfigForm } from '@/api/im'
|
||||
import { formatTime } from '@/utils/date'
|
||||
|
||||
const route = useRoute()
|
||||
const app = ref<App | null>(null)
|
||||
@ -231,9 +232,6 @@ async function deleteWebhook(row: WebhookConfig) {
|
||||
await loadWebhooks()
|
||||
}
|
||||
|
||||
function formatTime(value: number) {
|
||||
return new Date(value).toLocaleString()
|
||||
}
|
||||
|
||||
function copy(text: string) {
|
||||
navigator.clipboard.writeText(text)
|
||||
|
||||
@ -75,6 +75,7 @@ import { useRoute } from 'vue-router'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { appApi, type App } from '@/api/app'
|
||||
import { imAdminApi, type WebhookAlert } from '@/api/im'
|
||||
import { formatTime } from '@/utils/date'
|
||||
|
||||
const route = useRoute()
|
||||
const app = ref<App | null>(null)
|
||||
@ -118,9 +119,6 @@ async function acknowledge(row: WebhookAlert) {
|
||||
await loadUnacknowledgedCount()
|
||||
}
|
||||
|
||||
function formatTime(value: number) {
|
||||
return new Date(value).toLocaleString()
|
||||
}
|
||||
|
||||
watch([filterAcknowledged], () => {
|
||||
page.value = 1
|
||||
|
||||
@ -63,6 +63,7 @@ import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { appApi, type App } from '@/api/app'
|
||||
import { imAdminApi, type WebhookDelivery } from '@/api/im'
|
||||
import { formatTime } from '@/utils/date'
|
||||
|
||||
const route = useRoute()
|
||||
const app = ref<App | null>(null)
|
||||
@ -103,9 +104,6 @@ async function loadDeliveries() {
|
||||
}
|
||||
}
|
||||
|
||||
function formatTime(value: number) {
|
||||
return new Date(value).toLocaleString()
|
||||
}
|
||||
|
||||
watch([filterEvent, filterSuccess], () => {
|
||||
page.value = 1
|
||||
|
||||
@ -135,6 +135,7 @@ import { useRoute, useRouter } from 'vue-router'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { licenseApi, type AppLicense, type LicenseDevice } from '@/api/license'
|
||||
import { appApi, type App } from '@/api/app'
|
||||
import { formatTime } from '@/utils/date'
|
||||
import {
|
||||
connectServiceActivationRealtime,
|
||||
disconnectServiceActivationRealtime,
|
||||
@ -266,10 +267,7 @@ function switchApp(key: string) {
|
||||
router.push(`/services/license/${key}`)
|
||||
}
|
||||
|
||||
function formatDate(d: string | number) {
|
||||
const date = new Date(d)
|
||||
return Number.isNaN(date.getTime()) ? '-' : date.toLocaleString('zh-CN')
|
||||
}
|
||||
const formatDate = formatTime
|
||||
|
||||
function updateViewport() {
|
||||
isMobile.value = window.innerWidth < 768
|
||||
|
||||
@ -109,6 +109,7 @@ import { onMounted, reactive, ref, watch } from 'vue'
|
||||
import { appApi, type App } from '@/api/app'
|
||||
import { updateAdminApi, type OperationLog as UpdateOperationLog } from '@/api/update'
|
||||
import { operationLogApi, type TenantOperationLog } from '@/api/operationLog'
|
||||
import { formatTime } from '@/utils/date'
|
||||
|
||||
const activeSource = ref<'TENANT' | 'UPDATE'>('TENANT')
|
||||
|
||||
@ -255,12 +256,6 @@ function formatDetail(detailJson?: string) {
|
||||
}
|
||||
}
|
||||
|
||||
function formatTime(value: string | number | null | undefined) {
|
||||
if (value === null || value === undefined || value === '') return '-'
|
||||
const date = new Date(value)
|
||||
if (Number.isNaN(date.getTime())) return String(value)
|
||||
return date.toLocaleString('zh-CN')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@ -173,6 +173,7 @@ import { useRoute, useRouter } from 'vue-router'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { appApi, type App } from '@/api/app'
|
||||
import { pushAdminApi, type DeviceLoginLog, type TestPushResult, type UserPushStatus } from '@/api/push'
|
||||
import { formatTime } from '@/utils/date'
|
||||
import {
|
||||
connectServiceActivationRealtime,
|
||||
disconnectServiceActivationRealtime,
|
||||
@ -303,15 +304,7 @@ async function loadLogs() {
|
||||
}
|
||||
}
|
||||
|
||||
function formatTime(ms: number): string {
|
||||
if (!ms) return '-'
|
||||
return new Date(ms).toLocaleString('zh-CN')
|
||||
}
|
||||
|
||||
function formatDateTime(iso: string): string {
|
||||
if (!iso) return '-'
|
||||
return new Date(iso).toLocaleString('zh-CN')
|
||||
}
|
||||
const formatDateTime = formatTime
|
||||
|
||||
function connectPushRealtime(key: string) {
|
||||
void connectServiceActivationRealtime(key, (event: ServiceActivationRefreshEvent) => {
|
||||
|
||||
@ -216,6 +216,7 @@ import { appApi, type App } from '@/api/app'
|
||||
import { migrateApi } from '@/api/migrate'
|
||||
import { getDeploymentStatus, streamSystemUpdate } from '@/api/system'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { formatTime } from '@/utils/date'
|
||||
|
||||
const auth = useAuthStore()
|
||||
const apps = ref<App[]>([])
|
||||
@ -413,9 +414,7 @@ async function pollForRecovery() {
|
||||
updateError.value = '等待 tenant-service 重启超时,请手动刷新页面'
|
||||
}
|
||||
|
||||
function fmt(value: string) {
|
||||
return value ? new Date(value).toLocaleString('zh-CN') : '-'
|
||||
}
|
||||
const fmt = formatTime
|
||||
|
||||
onMounted(async () => {
|
||||
loadData()
|
||||
|
||||
@ -929,6 +929,7 @@ import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { CircleCheckFilled, Edit, Loading, UploadFilled, WarningFilled } from '@element-plus/icons-vue'
|
||||
import { appApi, type App } from '@/api/app'
|
||||
import { fileApi } from '@/api/file'
|
||||
import { formatTime } from '@/utils/date'
|
||||
import {
|
||||
updateAdminApi,
|
||||
type AppPackageInspectResult,
|
||||
@ -2243,9 +2244,6 @@ async function promptUnpublishRn(id: string) {
|
||||
}
|
||||
}
|
||||
|
||||
function formatTime(t: string) {
|
||||
return t ? new Date(t).toLocaleString('zh-CN') : '-'
|
||||
}
|
||||
|
||||
function statusLabel(row: { publishStatus: string }) {
|
||||
return { DRAFT: '草稿', PUBLISHED: '已发布', DEPRECATED: '已下架' }[row.publishStatus] ?? row.publishStatus
|
||||
|
||||
正在加载...
在新工单中引用
屏蔽一个用户