fix(frontend): complete i18n coverage and responsive layouts

This commit is contained in:
elky
2026-09-07 08:54:19 +08:00
parent 14f96c9fa0
commit b599fb7354
78 changed files with 4809 additions and 1485 deletions
@@ -1019,6 +1019,7 @@
</template>
<script setup lang="ts">
import { getI18nLocale } from '@/i18n'
import { computed, defineComponent, h, onMounted, onUnmounted, ref, watch, type Component } from 'vue'
import { RouterLink } from 'vue-router'
import type { ChartData, ChartOptions } from 'chart.js'
@@ -1300,7 +1301,7 @@ function formatShortDate(value?: string | null): string {
if (!value) return '-'
const date = new Date(value)
if (Number.isNaN(date.getTime())) return '-'
return date.toLocaleString('zh-CN', {
return date.toLocaleString(getI18nLocale(), {
month: '2-digit',
day: '2-digit',
hour: '2-digit',
+2 -1
View File
@@ -802,6 +802,7 @@
</template>
<script setup lang="ts">
import { getI18nLocale } from '@/i18n'
import { ref, computed, onMounted, onBeforeUnmount, watch } from 'vue'
import { useToast } from '@/composables/useToast'
import { useConfirm } from '@/composables/useConfirm'
@@ -1349,7 +1350,7 @@ function isExpiringSoon(apiKey: AdminApiKey): boolean {
}
function formatDate(dateString: string): string {
return new Date(dateString).toLocaleString('zh-CN', {
return new Date(dateString).toLocaleString(getI18nLocale(), {
year: 'numeric',
month: '2-digit',
day: '2-digit',
+3 -3
View File
@@ -862,7 +862,7 @@ import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
import { asyncTasksApi, type AsyncTaskItem, type AsyncTaskDetail, type AsyncTaskStatsResponse, type AsyncTaskStatus } from '@/api/async-tasks'
import { useToast } from '@/composables/useToast'
import { useClipboard } from '@/composables/useClipboard'
import { useI18n } from '@/i18n'
import { getI18nLocale, useI18n } from '@/i18n'
import Card from '@/components/ui/card.vue'
import Button from '@/components/ui/button.vue'
import Input from '@/components/ui/input.vue'
@@ -1176,7 +1176,7 @@ function canCancel(status: string): boolean {
function formatDate(dateStr: string | null): string {
if (!dateStr) return '-'
const date = new Date(dateStr)
return date.toLocaleString('zh-CN', {
return date.toLocaleString(getI18nLocale(), {
month: '2-digit',
day: '2-digit',
hour: '2-digit',
@@ -1188,7 +1188,7 @@ function formatDate(dateStr: string | null): string {
function formatDateFull(dateStr: string | null): string {
if (!dateStr) return '-'
const date = new Date(dateStr)
return date.toLocaleString('zh-CN', {
return date.toLocaleString(getI18nLocale(), {
year: 'numeric',
month: '2-digit',
day: '2-digit',
+2 -1
View File
@@ -409,6 +409,7 @@
</template>
<script setup lang="ts">
import { getI18nLocale } from '@/i18n'
import { ref, onMounted, onBeforeUnmount, computed } from 'vue'
import {
Card,
@@ -728,7 +729,7 @@ function getStatusCodeVariant(statusCode: number): 'default' | 'success' | 'dest
function formatDateTime(dateStr: string): string {
const date = new Date(dateStr)
return date.toLocaleString('zh-CN', {
return date.toLocaleString(getI18nLocale(), {
year: 'numeric',
month: '2-digit',
day: '2-digit',
@@ -415,7 +415,7 @@
<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue'
import { useToast } from '@/composables/useToast'
import { useI18n } from '@/i18n'
import { getI18nLocale, useI18n } from '@/i18n'
import Card from '@/components/ui/card.vue'
import Badge from '@/components/ui/badge.vue'
import Button from '@/components/ui/button.vue'
@@ -658,7 +658,7 @@ function handleFileSelect(e: Event) {
function formatDate(dateStr: string) {
if (!dateStr) return '-'
const date = new Date(dateStr)
return date.toLocaleString('zh-CN', {
return date.toLocaleString(getI18nLocale(), {
month: '2-digit',
day: '2-digit',
hour: '2-digit',
@@ -55,7 +55,7 @@
/>
</div>
<div class="flex-1 min-w-0 pt-1">
<h4 class="font-semibold text-base truncate">
<h4 class="break-words font-semibold text-base">
{{ tool.name }}
</h4>
</div>
@@ -150,7 +150,7 @@
/>
</div>
<div class="flex-1 min-w-0 pt-1 pr-8">
<h4 class="font-semibold text-base truncate">
<h4 class="break-words font-semibold text-base">
{{ module.display_name }}
</h4>
</div>
@@ -177,7 +177,7 @@
</div>
<!-- 操作区域 -->
<div class="mt-5 pt-4 border-t border-border/50 flex items-center justify-between">
<div class="mt-5 pt-4 border-t border-border/50 flex flex-wrap items-center justify-between gap-3">
<div class="flex items-center gap-3">
<Switch
:model-value="module.enabled"
@@ -204,11 +204,11 @@
v-if="module.admin_route"
variant="outline"
size="sm"
class="gap-1.5"
class="shrink-0 gap-1.5"
@click="router.push(module.admin_route)"
>
<Settings class="w-3.5 h-3.5" />
配置
{{ t('common.configure') }}
</Button>
</div>
</div>
@@ -240,6 +240,7 @@
</template>
<script setup lang="ts">
import { useI18n } from '@/i18n'
import { ref, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import {
@@ -266,6 +267,7 @@ import { modulesApi, type ModuleStatus } from '@/api/modules'
const router = useRouter()
const { success, error } = useToast()
const { t } = useI18n()
const moduleStore = useModuleStore()
const loading = ref(false)
@@ -419,6 +419,7 @@
</template>
<script setup lang="ts">
import { getI18nLocale } from '@/i18n'
import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue'
import { CircleHelp, PlugZap, Plus, Save, Trash2 } from 'lucide-vue-next'
import { epayGatewayApi, type EpayChannelConfig, type PaymentGatewayProvider } from '@/api/billing'
@@ -544,7 +545,7 @@ const visibleFields = computed(() => activeProviderMeta.value.fields)
const updatedAtText = computed(() => {
if (!updatedAt.value) return ''
return new Date(updatedAt.value * 1000).toLocaleString('zh-CN')
return new Date(updatedAt.value * 1000).toLocaleString(getI18nLocale())
})
const defaultCallbackBaseUrl = computed(() => {
@@ -826,6 +826,7 @@
</template>
<script setup lang="ts">
import { useI18n } from '@/i18n'
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import {
Activity,
@@ -890,6 +891,7 @@ type ProviderPerformanceParams = NonNullable<Parameters<typeof adminApi.getProvi
const timeRange = ref<DateRangeParams>(getDateRangeFromPeriod('last7days'))
const { error: showError } = useToast()
const { legacyT } = useI18n()
const percentiles = ref<PercentileItem[]>([])
const percentileLoading = ref(false)
@@ -1228,7 +1230,7 @@ const errorTrendChartData = computed(() => ({
labels: errorTrend.value.map(item => item.date),
datasets: [
{
label: '错误数',
label: legacyT('错误数'),
data: errorTrend.value.map(item => item.total),
borderColor: 'rgb(239, 68, 68)',
tension: 0.25,
@@ -261,6 +261,7 @@
</template>
<script setup lang="ts">
import { getI18nLocale } from '@/i18n'
import { computed, onMounted, ref } from 'vue'
import { RefreshCw } from 'lucide-vue-next'
import {
@@ -326,7 +327,7 @@ function formatUsd(value: number): string {
function formatUnix(value?: number | null): string {
if (!value) return '-'
return new Date(value * 1000).toLocaleString('zh-CN')
return new Date(value * 1000).toLocaleString(getI18nLocale())
}
function getRewardTypeLabel(value: string): string {
+2 -1
View File
@@ -808,6 +808,7 @@
</template>
<script setup lang="ts">
import { getI18nLocale } from '@/i18n'
import { computed, onMounted, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import {
@@ -1734,7 +1735,7 @@ async function confirmDeleteDraft(): Promise<void> {
function formatUnixSeconds(value?: number | null): string {
if (!value) return '-'
return new Date(value * 1000).toLocaleString('zh-CN')
return new Date(value * 1000).toLocaleString(getI18nLocale())
}
onMounted(() => {
@@ -1383,7 +1383,7 @@ import {
import type { PaymentOrder } from '@/api/wallet'
import { parseApiError } from '@/utils/errorParser'
import { useToast } from '@/composables/useToast'
import { useI18n } from '@/i18n'
import { getI18nLocale, useI18n } from '@/i18n'
import { log } from '@/utils/logger'
import {
callbackStatusBadge,
@@ -2222,7 +2222,7 @@ function ownerDisplayName(name: string | null | undefined, ownerType: 'user' | '
function formatDateTime(value: string | null | undefined) {
if (!value) return '-'
return new Date(value).toLocaleString('zh-CN', {
return new Date(value).toLocaleString(getI18nLocale(), {
year: 'numeric',
month: '2-digit',
day: '2-digit',
@@ -52,9 +52,7 @@
class="mt-1"
/>
<p class="mt-1 text-xs text-muted-foreground">
Bark App 中推送地址
<span class="font-mono">https://api.day.app/xxxx</span>
的 <span class="font-mono">xxxx</span> 部分
{{ $t('modules.bark.deviceKeyHint') }}
</p>
</div>
@@ -308,8 +308,8 @@
</div>
<div class="mt-4 border border-border rounded-lg overflow-hidden">
<div class="flex items-center justify-between px-4 py-3 border-b border-border">
<div>
<div class="flex flex-wrap items-start justify-between gap-3 px-4 py-3 border-b border-border">
<div class="min-w-0 flex-1 basis-48">
<h4 class="text-sm font-medium">
最近清理记录
</h4>
@@ -320,6 +320,7 @@
<Button
variant="outline"
size="sm"
class="shrink-0"
:disabled="cleanupRunsLoading"
@click="loadCleanupRuns"
>
@@ -33,21 +33,23 @@
variant="outline"
size="sm"
class="w-full"
:title="item.exportLabel"
:disabled="item.exportLoading"
@click="$emit('export', item.key)"
>
<Download class="w-3.5 h-3.5 mr-1.5" />
{{ item.exportLoading ? '导出中...' : item.exportLabel }}
{{ item.exportLoading ? '导出中...' : '导出' }}
</Button>
<Button
variant="outline"
size="sm"
class="w-full"
:title="item.importLabel"
:disabled="item.importLoading"
@click="triggerDataFileSelect(item.key)"
>
<Upload class="w-3.5 h-3.5 mr-1.5" />
{{ item.importLoading ? '导入中...' : item.importLabel }}
{{ item.importLoading ? '导入中...' : '导入' }}
</Button>
</div>
</div>