Explorar o código

# fix: 封装统一时间格式化工具并替换各视图重复实现

yangyi hai 2 meses
pai
achega
91d32dfcd1

+ 5 - 3
package-lock.json

@@ -9,6 +9,7 @@
       "version": "0.0.0",
       "dependencies": {
         "axios": "^1.15.2",
+        "dayjs": "^1.11.21",
         "element-plus": "^2.13.6",
         "orval": "7.0",
         "pinia": "^3.0.4",
@@ -2636,9 +2637,10 @@
       }
     },
     "node_modules/dayjs": {
-      "version": "1.11.20",
-      "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.20.tgz",
-      "integrity": "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ=="
+      "version": "1.11.21",
+      "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz",
+      "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==",
+      "license": "MIT"
     },
     "node_modules/de-indent": {
       "version": "1.0.2",

+ 1 - 0
package.json

@@ -11,6 +11,7 @@
   },
   "dependencies": {
     "axios": "^1.15.2",
+    "dayjs": "^1.11.21",
     "element-plus": "^2.13.6",
     "orval": "7.0",
     "pinia": "^3.0.4",

+ 8 - 0
src/util/format-time.ts

@@ -0,0 +1,8 @@
+import dayjs from 'dayjs'
+
+export function formatTime(value?: string | number | Date | null, fallback = '-'): string {
+  if (value === undefined || value === null || value === '') return fallback
+  const d = dayjs(value)
+  if (!d.isValid()) return fallback
+  return d.format('YYYY-MM-DD HH:mm')
+}

+ 4 - 3
src/view/admin/ContestManageView.vue

@@ -15,6 +15,7 @@ import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'elem
 import { Delete, Edit, Plus, RefreshRight, Search, UserFilled, View } from '@element-plus/icons-vue'
 import { computed, onMounted, reactive, ref } from 'vue'
 import { useLoginUserStore } from '@/store'
+import { formatTime } from '@/util/format-time'
 
 const api = getContestController()
 const problemApi = getProblemController()
@@ -51,8 +52,6 @@ const statusTag = (status?: ContestVo['status']) => {
 const statusLabel = (status?: ContestVo['status']) =>
   statusOptions.find((s) => s.value === status)?.label || status || '-'
 
-const formatTime = (t?: string) => (t ? t.replace('T', ' ').slice(0, 16) : '-')
-
 // ---------- 搜索 ----------
 const searchForm = reactive({
   title: '',
@@ -620,7 +619,9 @@ onMounted(fetchData)
         <el-table-column prop="id" label="ID" width="80" align="center" />
         <el-table-column prop="userId" label="用户ID" width="100" align="center" />
         <el-table-column prop="username" label="用户名" min-width="160" />
-        <el-table-column prop="createdAt" label="报名时间" width="180" align="center" />
+        <el-table-column label="报名时间" width="180" align="center">
+          <template #default="{ row }">{{ formatTime(row.createdAt) }}</template>
+        </el-table-column>
       </el-table>
       <el-empty v-if="!regLoading && !regTable.length" description="暂无报名" :image-size="60" />
     </el-dialog>

+ 4 - 1
src/view/admin/ProblemManageView.vue

@@ -16,6 +16,7 @@ import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'elem
 import { Delete, Edit, Plus, RefreshRight, Search, View } from '@element-plus/icons-vue'
 import { computed, onMounted, reactive, ref } from 'vue'
 import { useLoginUserStore } from '@/store'
+import { formatTime } from '@/util/format-time'
 
 const api = getProblemController()
 const loginUserStore = useLoginUserStore()
@@ -507,7 +508,9 @@ onMounted(() => {
         <el-table-column label="通过/提交" width="110" align="center">
           <template #default="{ row }">{{ row.acceptedCount ?? 0 }} / {{ row.tryCount ?? 0 }}</template>
         </el-table-column>
-        <el-table-column prop="createdAt" label="创建时间" width="170" align="center" />
+        <el-table-column label="创建时间" width="170" align="center">
+          <template #default="{ row }">{{ formatTime(row.createdAt) }}</template>
+        </el-table-column>
         <el-table-column label="操作" width="200" align="center" fixed="right">
           <template #default="{ row }">
             <el-button type="primary" link @click="openDetail(row)">

+ 1 - 2
src/view/contest/ContestDetailView.vue

@@ -6,6 +6,7 @@ import { ArrowLeft, Key, Trophy } from '@element-plus/icons-vue'
 import { computed, onMounted, ref } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
 import { useLoginUserStore } from '@/store'
+import { formatTime } from '@/util/format-time'
 
 const route = useRoute()
 const router = useRouter()
@@ -50,8 +51,6 @@ const difficultyLabel = (d?: string) => {
   return '-'
 }
 
-const formatTime = (t?: string) => (t ? t.replace('T', ' ').slice(0, 16) : '-')
-
 const isLogin = computed(() => loginUserStore.loginUser.isLogin)
 const isPasswordType = computed(() => detail.value.type === 'password')
 

+ 1 - 5
src/view/contest/ContestListView.vue

@@ -5,6 +5,7 @@ import { ElMessage } from 'element-plus'
 import { RefreshRight, Search } from '@element-plus/icons-vue'
 import { onMounted, reactive, ref } from 'vue'
 import { useRouter } from 'vue-router'
+import { formatTime } from '@/util/format-time'
 
 const router = useRouter()
 const api = getContestController()
@@ -52,11 +53,6 @@ const statusTag = (status: ContestVo['status']) => {
 const statusLabel = (status: ContestVo['status']) =>
   statusOptions.find((s) => s.value === status)?.label || status || '-'
 
-const formatTime = (t?: string) => {
-  if (!t) return '-'
-  return t.replace('T', ' ').slice(0, 16)
-}
-
 const fetchData = async () => {
   loading.value = true
   try {

+ 2 - 1
src/view/contest/ContestRankingView.vue

@@ -6,6 +6,7 @@ import { ArrowLeft, Trophy } from '@element-plus/icons-vue'
 import { onMounted, ref } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
 import { useLoginUserStore } from '@/store'
+import { formatTime } from '@/util/format-time'
 
 const route = useRoute()
 const router = useRouter()
@@ -82,7 +83,7 @@ onMounted(() => {
           <template #default="{ row }">{{ row.maxAcMinutes ?? '-' }}</template>
         </el-table-column>
         <el-table-column prop="regTime" label="报名时间" width="180" align="center">
-          <template #default="{ row }">{{ row.regTime ? row.regTime.replace('T', ' ').slice(0, 16) : '-' }}</template>
+          <template #default="{ row }">{{ formatTime(row.regTime) }}</template>
         </el-table-column>
       </el-table>
       <el-empty v-else description="暂无排名数据(提交模块尚未实现,属正常现象)" :image-size="80" />