Parcourir la source

Refactor timestamp formatting in dashboard components for consistency

- Removed duplicate timestamp formatting functions from various dashboard pages and replaced them with a centralized formatTimestamp utility from the utils/date module.
- Updated render methods in tables across multiple components to utilize the new formatTimestamp function, ensuring consistent date formatting throughout the application.
0es il y a 3 mois
Parent
commit
4da86f8942

+ 2 - 7
src/app/(dashboard)/config/base-config/page.tsx

@@ -27,6 +27,7 @@ import {
   updateBaseConfig,
 } from "@/services/baseConfig";
 import type { BaseConfigAdminDTO, BaseConfigAdminQuery } from "@/types/api";
+import { formatTimestamp } from "@/utils/date";
 
 const BaseConfigPage: React.FC = () => {
   const { message } = App.useApp();
@@ -184,12 +185,6 @@ const BaseConfigPage: React.FC = () => {
     }
   };
 
-  // Format timestamp
-  const formatTimestamp = (timestamp?: number) => {
-    if (!timestamp) return "-";
-    return new Date(timestamp).toLocaleString("zh-CN");
-  };
-
   // Expandable row render
   const expandedRowRender = (record: BaseConfigAdminDTO) => {
     return (
@@ -228,7 +223,7 @@ const BaseConfigPage: React.FC = () => {
       dataIndex: "createdAt",
       key: "createdAt",
       width: 180,
-      render: formatTimestamp,
+      render: (timestamp: number) => formatTimestamp(timestamp),
     },
     {
       title: "操作",

+ 3 - 8
src/app/(dashboard)/config/country-config/page.tsx

@@ -37,6 +37,7 @@ import type {
   BaseCountryAdminQuery,
   BaseCountryI18n,
 } from "@/types/api";
+import { formatTimestamp } from "@/utils/date";
 
 const CountryConfigPage: React.FC = () => {
   const { message } = App.useApp();
@@ -195,12 +196,6 @@ const CountryConfigPage: React.FC = () => {
     }
   };
 
-  // Format timestamp
-  const formatTimestamp = (timestamp?: number) => {
-    if (!timestamp) return "-";
-    return new Date(timestamp).toLocaleString("zh-CN");
-  };
-
   // i18n list operations
   const handleAddI18n = () => {
     setI18nList((prev) => [...prev, { lang: "", first: "", name: "" }]);
@@ -460,14 +455,14 @@ const CountryConfigPage: React.FC = () => {
       dataIndex: "createdAt",
       key: "createdAt",
       width: 180,
-      render: formatTimestamp,
+      render: (timestamp: number) => formatTimestamp(timestamp),
     },
     {
       title: "更新时间",
       dataIndex: "updatedAt",
       key: "updatedAt",
       width: 180,
-      render: formatTimestamp,
+      render: (timestamp: number) => formatTimestamp(timestamp),
     },
     {
       title: "操作",

+ 3 - 8
src/app/(dashboard)/config/currency-exchange-config/page.tsx

@@ -31,6 +31,7 @@ import type {
   BaseExchangeConfigAdminDTO,
   BaseExchangeConfigAdminQuery,
 } from "@/types/api";
+import { formatTimestamp } from "@/utils/date";
 
 const walletTypeOptions = [
   { label: "金币", value: 0 },
@@ -159,12 +160,6 @@ const CurrencyExchangeConfigPage: React.FC = () => {
     return option ? option.label : "-";
   };
 
-  // Format timestamp
-  const formatTimestamp = (timestamp?: number) => {
-    if (!timestamp) return "-";
-    return new Date(timestamp).toLocaleString("zh-CN");
-  };
-
   // Submit form
   const handleSubmit = async () => {
     try {
@@ -242,14 +237,14 @@ const CurrencyExchangeConfigPage: React.FC = () => {
       dataIndex: "createdAt",
       key: "createdAt",
       width: 180,
-      render: formatTimestamp,
+      render: (timestamp: number) => formatTimestamp(timestamp),
     },
     {
       title: "更新时间",
       dataIndex: "updatedAt",
       key: "updatedAt",
       width: 180,
-      render: formatTimestamp,
+      render: (timestamp: number) => formatTimestamp(timestamp),
     },
     {
       title: "操作",

+ 6 - 6
src/app/(dashboard)/home/page.tsx

@@ -14,7 +14,11 @@ import type {
   DailyTrendAdminDTO,
   IndicatorCardAdminDTO,
 } from "@/types/api";
-import { getLast7DaysRange, getTodayRange } from "@/utils/date";
+import {
+  formatTimestamp,
+  getLast7DaysRange,
+  getTodayRange,
+} from "@/utils/date";
 import DashboardAlerts from "./components/Alerts";
 import DashboardIndicatorCards from "./components/IndicatorCards";
 import DashboardTrends from "./components/Trends";
@@ -49,11 +53,7 @@ const HomePage: React.FC = () => {
       setIndicator(indicatorRes);
       setDailyTrend(dailyTrendRes || []);
       setActivityDistribution(activityRes || []);
-      setLastUpdatedAt(
-        new Date().toLocaleString("zh-CN", {
-          hour12: false,
-        }),
-      );
+      setLastUpdatedAt(formatTimestamp(new Date()));
     } catch (error) {
       console.error("Failed to load dashboard data:", error);
       message.error("加载首页统计数据失败");

+ 1 - 6
src/app/(dashboard)/order/list/page.tsx

@@ -33,6 +33,7 @@ import type {
   SkillOrderAdminDTO,
   SkillOrderAdminQuery,
 } from "@/types/api/order";
+import { formatTimestamp } from "@/utils/date";
 
 // 钱包类型枚举(与货币兑换配置保持一致)
 const walletTypeOptions = [
@@ -179,12 +180,6 @@ const OrderListPage: React.FC = () => {
     return "-";
   };
 
-  // 时间格式化
-  const formatTimestamp = (timestamp?: number) => {
-    if (!timestamp) return "-";
-    return new Date(timestamp).toLocaleString("zh-CN");
-  };
-
   // 查看详情
   const handleViewDetail = async (record: SkillOrderAdminDTO) => {
     setDetailModalVisible(true);

+ 1 - 6
src/app/(dashboard)/order/refund-apply/page.tsx

@@ -37,6 +37,7 @@ import type {
   SkillOrderRefundApplyAdminQuery,
   SkillOrderRefundApplyDetailAdminDTO,
 } from "@/types/api/order";
+import { formatTimestamp } from "@/utils/date";
 
 const RefundApplyPage: React.FC = () => {
   const { message } = App.useApp();
@@ -144,12 +145,6 @@ const RefundApplyPage: React.FC = () => {
     return <Tag>-</Tag>;
   };
 
-  // 时间格式化
-  const formatTimestamp = (timestamp?: number) => {
-    if (!timestamp) return "-";
-    return new Date(timestamp).toLocaleString("zh-CN");
-  };
-
   // 查看详情
   const handleViewDetail = async (record: SkillOrderRefundApplyAdminDTO) => {
     setDetailModalVisible(true);

+ 3 - 3
src/app/(dashboard)/playmate/list/page.tsx

@@ -40,6 +40,7 @@ import type {
   PlaymateUserAdminDto,
   SkillInfoAdminDto,
 } from "@/types/api/playmate";
+import { formatTimestamp } from "@/utils/date";
 
 const PlaymateListPage: React.FC = () => {
   const { message } = App.useApp();
@@ -125,10 +126,9 @@ const PlaymateListPage: React.FC = () => {
     });
   };
 
-  // Format date
+  // Format date(使用 dayjs,默认印尼时区 GMT+7)
   const formatDate = (timestamp: number) => {
-    if (!timestamp) return "-";
-    return new Date(timestamp).toLocaleString("zh-CN");
+    return formatTimestamp(timestamp);
   };
 
   // Open create skill modal

+ 2 - 1
src/app/(dashboard)/system/admin/permission/page.tsx

@@ -42,6 +42,7 @@ import type {
   AdminPermissionEditRequest,
   AdminPermissionPageRequest,
 } from "@/types/api";
+import { formatTimestamp } from "@/utils/date";
 
 const PermissionAdminListPage: React.FC = () => {
   const { message } = App.useApp();
@@ -510,7 +511,7 @@ const PermissionAdminListPage: React.FC = () => {
       width: 180,
       render: (date: string) => {
         if (!date) return "-";
-        return new Date(date).toLocaleString("zh-CN");
+        return formatTimestamp(date);
       },
     },
     {

+ 2 - 1
src/app/(dashboard)/system/admin/role/page.tsx

@@ -41,6 +41,7 @@ import type {
   AdminRoleEditRequest,
   AdminRolePageRequest,
 } from "@/types/api";
+import { formatTimestamp } from "@/utils/date";
 
 const RoleAdminListPage: React.FC = () => {
   const { message } = App.useApp();
@@ -326,7 +327,7 @@ const RoleAdminListPage: React.FC = () => {
       width: 180,
       render: (date: string) => {
         if (!date) return "-";
-        return new Date(date).toLocaleString("zh-CN");
+        return formatTimestamp(date);
       },
     },
     {

+ 2 - 1
src/app/(dashboard)/system/admin/user/page.tsx

@@ -43,6 +43,7 @@ import type {
   AdminUserEditRequest,
   AdminUserPageRequest,
 } from "@/types/api";
+import { formatTimestamp } from "@/utils/date";
 
 const UserAdminListPage: React.FC = () => {
   const { message } = App.useApp();
@@ -315,7 +316,7 @@ const UserAdminListPage: React.FC = () => {
       width: 180,
       render: (date: string) => {
         if (!date) return "-";
-        return new Date(date).toLocaleString("zh-CN");
+        return formatTimestamp(date);
       },
     },
     {

+ 1 - 1
src/app/(dashboard)/system/operation-log/page.tsx

@@ -19,11 +19,11 @@ import {
 } from "antd";
 import type { ColumnsType, TablePaginationConfig } from "antd/es/table";
 import type { SorterResult } from "antd/es/table/interface";
-import dayjs from "dayjs";
 import type React from "react";
 import { useEffect, useState } from "react";
 import { getOperationLogPage } from "@/services/operationLog";
 import type { OperationLog, OperationLogPageRequest } from "@/types/api";
+import dayjs from "@/utils/dayjs";
 
 const { RangePicker } = DatePicker;
 const { Text, Paragraph } = Typography;

+ 3 - 3
src/app/(dashboard)/user/list/page.tsx

@@ -46,6 +46,7 @@ import type {
   UserInfoAdminQuery,
   UserInfoFullAdminDTO,
 } from "@/types/api/user";
+import { formatTimestamp } from "@/utils/date";
 
 const UserListPage: React.FC = () => {
   const { message } = App.useApp();
@@ -146,10 +147,9 @@ const UserListPage: React.FC = () => {
     }
   };
 
-  // Format date
+  // Format date(使用 dayjs,默认印尼时区 GMT+7)
   const formatDate = (timestamp: number) => {
-    if (!timestamp) return "-";
-    return new Date(timestamp).toLocaleString("zh-CN");
+    return formatTimestamp(timestamp);
   };
 
   // View user detail

+ 3 - 8
src/app/(dashboard)/wallet/recharge-config/page.tsx

@@ -35,6 +35,7 @@ import type {
   WalletRechargeConfigAdminDTO,
   WalletRechargeConfigAdminQuery,
 } from "@/types/api";
+import { formatTimestamp } from "@/utils/date";
 
 const platformOptions = [
   { label: "OFFICIAL", value: 0 },
@@ -214,12 +215,6 @@ const RechargeConfigPage: React.FC = () => {
     }
   };
 
-  // Format timestamp
-  const formatTimestamp = (timestamp?: number) => {
-    if (!timestamp) return "-";
-    return new Date(timestamp).toLocaleString("zh-CN");
-  };
-
   // Submit form
   const handleSubmit = async () => {
     try {
@@ -370,14 +365,14 @@ const RechargeConfigPage: React.FC = () => {
       dataIndex: "createdAt",
       key: "createdAt",
       width: 180,
-      render: formatTimestamp,
+      render: (timestamp: number) => formatTimestamp(timestamp),
     },
     {
       title: "更新时间",
       dataIndex: "updatedAt",
       key: "updatedAt",
       width: 180,
-      render: formatTimestamp,
+      render: (timestamp: number) => formatTimestamp(timestamp),
     },
     {
       title: "操作",

+ 3 - 3
src/services/baseCountry.ts

@@ -13,7 +13,7 @@ import type {
  * Get base country page data
  */
 export async function getBaseCountryPage(
-  query: BaseCountryAdminQuery
+  query: BaseCountryAdminQuery,
 ): Promise<PagerBaseCountryAdminDTO> {
   return request("/base/base-country/page", {
     method: "POST",
@@ -25,7 +25,7 @@ export async function getBaseCountryPage(
  * Create base country record
  */
 export async function createBaseCountry(
-  data: BaseCountryAdminDTO
+  data: BaseCountryAdminDTO,
 ): Promise<void> {
   return request("/base/base-country/create", {
     method: "POST",
@@ -37,7 +37,7 @@ export async function createBaseCountry(
  * Update base country record
  */
 export async function updateBaseCountry(
-  data: BaseCountryAdminDTO
+  data: BaseCountryAdminDTO,
 ): Promise<void> {
   return request("/base/base-country/update", {
     method: "POST",

+ 0 - 2
src/services/baseExchangeConfig.ts

@@ -44,5 +44,3 @@ export async function updateBaseExchangeConfig(
     body: JSON.stringify(data),
   });
 }
-
-

+ 6 - 6
src/services/indexStat.ts

@@ -11,7 +11,7 @@ import type {
  * 首页指标卡统计
  */
 export async function fetchIndicatorCard(
-  query: IndexDateRangeAdminQuery
+  query: IndexDateRangeAdminQuery,
 ): Promise<IndicatorCardAdminDTO> {
   return post<IndicatorCardAdminDTO>("/index/stat/indicatorCard", query);
 }
@@ -20,7 +20,7 @@ export async function fetchIndicatorCard(
  * 首页订单日趋图
  */
 export async function fetchOrderDailyTrend(
-  query: IndexDateRangeAdminQuery
+  query: IndexDateRangeAdminQuery,
 ): Promise<DailyTrendAdminDTO[]> {
   return post<DailyTrendAdminDTO[]>("/index/stat/order/dailyTrend", query);
 }
@@ -29,11 +29,11 @@ export async function fetchOrderDailyTrend(
  * 陪玩师活跃度分布(按分类)
  */
 export async function fetchPlaymateActivityDistribution(
-  query: IndexDateRangeAdminQuery
+  query: IndexDateRangeAdminQuery,
 ): Promise<CategoryPercentageAdminDTO[]> {
   return post<CategoryPercentageAdminDTO[]>(
     "/index/stat/playmateActivityDistribution",
-    query
+    query,
   );
 }
 
@@ -41,10 +41,10 @@ export async function fetchPlaymateActivityDistribution(
  * 收入分布(按分类)
  */
 export async function fetchRevenueDistribution(
-  query: IndexDateRangeAdminQuery
+  query: IndexDateRangeAdminQuery,
 ): Promise<RevenueByCategoryAdminDTO[]> {
   return post<RevenueByCategoryAdminDTO[]>(
     "/index/stat/revenueDistribution",
-    query
+    query,
   );
 }

+ 1 - 5
src/services/order.ts

@@ -63,10 +63,7 @@ export async function approveSkillOrderRefundApply(
  * @param query - order manager query parameters
  */
 export async function getSkillOrderManagerPage(query: SkillOrderAdminQuery) {
-  return post<PagerSkillOrderAdminDTO>(
-    "/order/skillOrder/manager/page",
-    query,
-  );
+  return post<PagerSkillOrderAdminDTO>("/order/skillOrder/manager/page", query);
 }
 
 /**
@@ -86,4 +83,3 @@ export async function getSkillOrderManagerDetail(id: string) {
 export async function cancelSkillOrderManager(data: SkillOrderCancelAdminDTO) {
   return post<SkillOrderAdminDTO>("/order/skillOrder/manager/cancel", data);
 }
-

+ 1 - 1
src/services/user.ts

@@ -4,11 +4,11 @@
 
 import { post } from "@/lib/request";
 import type {
+  EditPlaymateInfoAdminQuery,
   PagerUserInfoAdminDTO,
   UserInfoAdminQuery,
   UserInfoDetailAdminQuery,
   UserInfoFullAdminDTO,
-  EditPlaymateInfoAdminQuery,
 } from "@/types/api/user";
 
 /**

+ 4 - 4
src/services/wallet.ts

@@ -13,7 +13,7 @@ import type {
  * Get wallet recharge config page data
  */
 export async function getWalletRechargeConfigPage(
-  query: WalletRechargeConfigAdminQuery
+  query: WalletRechargeConfigAdminQuery,
 ): Promise<PagerWalletRechargeConfigAdminDTO> {
   return request("/wallet/recharge-config/page", {
     method: "POST",
@@ -25,7 +25,7 @@ export async function getWalletRechargeConfigPage(
  * Create wallet recharge config record
  */
 export async function createWalletRechargeConfig(
-  data: WalletRechargeConfigAdminDTO
+  data: WalletRechargeConfigAdminDTO,
 ): Promise<void> {
   return request("/wallet/recharge-config/create", {
     method: "POST",
@@ -37,7 +37,7 @@ export async function createWalletRechargeConfig(
  * Update wallet recharge config record
  */
 export async function updateWalletRechargeConfig(
-  data: WalletRechargeConfigAdminDTO
+  data: WalletRechargeConfigAdminDTO,
 ): Promise<void> {
   return request("/wallet/recharge-config/update", {
     method: "POST",
@@ -49,7 +49,7 @@ export async function updateWalletRechargeConfig(
  * Delete wallet recharge config records
  */
 export async function deleteWalletRechargeConfigs(
-  ids: string[]
+  ids: string[],
 ): Promise<void> {
   return request("/wallet/recharge-config/delete", {
     method: "POST",

+ 1 - 1
src/stores/menuStore.ts

@@ -71,7 +71,7 @@ export const useMenuStore = create<MenuStore>((set, get) => ({
     const filteredMenus = filterMenusByPermissions(
       menuConfig,
       permissions,
-      isSuperAdmin
+      isSuperAdmin,
     );
     set({ menus: filteredMenus });
   },

+ 1 - 1
src/stores/tabStore.ts

@@ -11,7 +11,7 @@ interface TabStore {
   removeTab: (key: string) => TabItem | null; // Returns the next active tab
   removeTabsByPosition: (
     position: "left" | "right" | "others" | "all",
-    currentKey: string
+    currentKey: string,
   ) => void;
   setActiveTab: (key: string) => void;
   getTabByPath: (path: string) => TabItem | null;

+ 0 - 2
src/types/api/baseExchangeConfig.ts

@@ -40,5 +40,3 @@ export interface PagerBaseExchangeConfigAdminDTO {
   pageSize: number;
   items: BaseExchangeConfigAdminDTO[];
 }
-
-

+ 0 - 2
src/types/api/consts.ts

@@ -20,5 +20,3 @@ export type ConstItemsMap = Record<string, ConstItem[]>;
 export interface ConstsAdminDTO {
   items: ConstItemsMap;
 }
-
-

+ 0 - 2
src/types/api/indexStat.ts

@@ -91,5 +91,3 @@ export interface RevenueByCategoryAdminDTO {
    */
   orderCount: number;
 }
-
-

+ 23 - 15
src/utils/date.ts

@@ -1,13 +1,12 @@
-// 日期工具方法,仅处理到天级别
+import dayjs from "./dayjs";
+
+// 日期工具方法,默认使用印尼时区(GMT+7),仅处理到天级别
 
 /**
- * 将 Date 格式化为 yyyy-MM-dd 字符串
+ * 将 Date 格式化为 yyyy-MM-dd 字符串(默认印尼时区 GMT+7)
  */
 export function formatDateToYMD(date: Date): string {
-  const year = date.getFullYear();
-  const month = String(date.getMonth() + 1).padStart(2, "0");
-  const day = String(date.getDate()).padStart(2, "0");
-  return `${year}-${month}-${day}`;
+  return dayjs(date).format("YYYY-MM-DD");
 }
 
 /**
@@ -17,8 +16,8 @@ export function getTodayRange(): {
   beginDateTime: string;
   endDateTime: string;
 } {
-  const today = new Date();
-  const ymd = formatDateToYMD(today);
+  const today = dayjs();
+  const ymd = today.format("YYYY-MM-DD");
   return {
     beginDateTime: ymd,
     endDateTime: ymd,
@@ -32,12 +31,10 @@ export function getLast7DaysRange(): {
   beginDateTime: string;
   endDateTime: string;
 } {
-  const today = new Date();
-  const endDateTime = formatDateToYMD(today);
-
-  const start = new Date(today);
-  start.setDate(start.getDate() - 6);
-  const beginDateTime = formatDateToYMD(start);
+  const end = dayjs();
+  const start = end.subtract(6, "day");
+  const beginDateTime = start.format("YYYY-MM-DD");
+  const endDateTime = end.format("YYYY-MM-DD");
 
   return {
     beginDateTime,
@@ -45,4 +42,15 @@ export function getLast7DaysRange(): {
   };
 }
 
-
+/**
+ * 将时间戳/日期格式化为 yyyy-MM-dd HH:mm:ss(默认印尼时区 GMT+7)
+ */
+export function formatTimestamp(
+  timestamp?: number | string | Date,
+  pattern = "YYYY-MM-DD HH:mm:ss",
+): string {
+  if (timestamp === undefined || timestamp === null || timestamp === 0) {
+    return "-";
+  }
+  return dayjs(timestamp).format(pattern);
+}

+ 12 - 0
src/utils/dayjs.ts

@@ -0,0 +1,12 @@
+import dayjs from "dayjs";
+import timezone from "dayjs/plugin/timezone";
+import utc from "dayjs/plugin/utc";
+
+// Enable UTC and timezone support
+dayjs.extend(utc);
+dayjs.extend(timezone);
+
+// Set default timezone to Indonesia (GMT+7)
+dayjs.tz.setDefault("Asia/Jakarta");
+
+export default dayjs;