From 3923217e0e0d71c6e47e8eeba8d33eaf7a7501e3 Mon Sep 17 00:00:00 2001 From: Ethanfly Date: Tue, 10 Feb 2026 10:25:19 +0800 Subject: [PATCH] feat: Implement date formatting across controllers for improved readability - Added a new utility function `formatDateTime` to standardize date formatting across various controllers. - Updated multiple controllers (admin, article, ladder, match, points, store, user) to utilize the new formatting function for timestamps, enhancing the clarity of date and time displays in API responses. - Ensured consistent date representation in user and match details, improving overall user experience. --- server/src/controllers/adminController.js | 10 +++--- server/src/controllers/articleController.js | 6 ++-- .../src/controllers/ladderAdminController.js | 6 ++-- server/src/controllers/ladderController.js | 5 +-- .../src/controllers/matchAdminController.js | 12 +++---- server/src/controllers/matchController.js | 35 +++++++------------ .../src/controllers/pointsAdminController.js | 11 +++--- server/src/controllers/pointsController.js | 12 +++---- server/src/controllers/storeController.js | 4 +-- server/src/controllers/userController.js | 3 +- server/src/utils/helper.js | 18 ++++++++++ 11 files changed, 66 insertions(+), 56 deletions(-) diff --git a/server/src/controllers/adminController.js b/server/src/controllers/adminController.js index c842011d..eb6d5cf2 100644 --- a/server/src/controllers/adminController.js +++ b/server/src/controllers/adminController.js @@ -1,7 +1,7 @@ const jwt = require('jsonwebtoken'); const bcrypt = require('bcryptjs'); const { User, Store, SystemUser, LadderUser, Match, PointOrder, StoreStaff } = require('../models'); -const { success, error, getPagination, pageResult } = require('../utils/helper'); +const { success, error, getPagination, pageResult, formatDateTime } = require('../utils/helper'); const { Op } = require('sequelize'); class AdminController { @@ -145,7 +145,7 @@ class AdminController { memberCode: user.member_code, totalPoints: user.total_points, status: user.status, - createdAt: user.created_at, + createdAt: formatDateTime(user.created_at), // 前端根据该字段隐藏“添加为天梯用户”按钮 hasLadderUser: ladderUserIdSet.has(user.id) })), count, page, pageSize)); @@ -232,7 +232,7 @@ class AdminController { memberCode: user.member_code, totalPoints: user.total_points, status: user.status, - createdAt: user.created_at, + createdAt: formatDateTime(user.created_at), ladderUsers: user.ladderUsers.map(lu => ({ id: lu.id, storeId: lu.store_id, @@ -382,8 +382,8 @@ class AdminController { storeId: user.store_id, storeName: user.store?.name, status: user.status, - lastLoginAt: user.last_login_at, - createdAt: user.created_at + lastLoginAt: formatDateTime(user.last_login_at), + createdAt: formatDateTime(user.created_at) })), count, page, pageSize)); } catch (err) { console.error('获取系统用户列表失败:', err); diff --git a/server/src/controllers/articleController.js b/server/src/controllers/articleController.js index de60f90d..76f10f62 100644 --- a/server/src/controllers/articleController.js +++ b/server/src/controllers/articleController.js @@ -1,5 +1,5 @@ const { Article } = require('../models'); -const { success, error } = require('../utils/helper'); +const { success, error, formatDateTime } = require('../utils/helper'); const { Op } = require('sequelize'); class ArticleController { @@ -31,7 +31,7 @@ class ArticleController { category: a.category, coverImage: a.cover_image, summary: a.summary, - createdAt: a.created_at, + createdAt: formatDateTime(a.created_at), isTop: a.is_top === 1, })); @@ -66,7 +66,7 @@ class ArticleController { coverImage: article.cover_image, summary: article.summary, contentHtml: article.content_html, - createdAt: article.created_at, + createdAt: formatDateTime(article.created_at), }), ); } catch (err) { diff --git a/server/src/controllers/ladderAdminController.js b/server/src/controllers/ladderAdminController.js index 0a846d99..90f5726b 100644 --- a/server/src/controllers/ladderAdminController.js +++ b/server/src/controllers/ladderAdminController.js @@ -1,6 +1,6 @@ const { User, LadderUser, Store } = require('../models'); const { LADDER_LEVEL_NAMES } = require('../config/constants'); -const { success, error, getPagination, pageResult, generateMemberCode } = require('../utils/helper'); +const { success, error, getPagination, pageResult, formatDateTime, generateMemberCode } = require('../utils/helper'); const { Op } = require('sequelize'); class LadderAdminController { @@ -63,8 +63,8 @@ class LadderAdminController { matchCount: lu.match_count, winCount: lu.win_count, monthlyMatchCount: lu.monthly_match_count, - lastMatchTime: lu.last_match_time, - createdAt: lu.created_at + lastMatchTime: formatDateTime(lu.last_match_time), + createdAt: formatDateTime(lu.created_at) })), count, page, pageSize)); } catch (err) { console.error('获取天梯用户列表失败:', err); diff --git a/server/src/controllers/ladderController.js b/server/src/controllers/ladderController.js index 2201586c..3d86d7ce 100644 --- a/server/src/controllers/ladderController.js +++ b/server/src/controllers/ladderController.js @@ -9,6 +9,7 @@ const { error, getPagination, pageResult, + formatDateTime, } = require("../utils/helper"); const { Op } = require("sequelize"); const sequelize = require("../config/database"); @@ -247,7 +248,7 @@ class LadderController { rank: higherCount + 1, storeId: ladderUser.store_id, storeName: ladderUser.store?.name, - lastMatchTime: ladderUser.last_match_time, + lastMatchTime: formatDateTime(ladderUser.last_match_time), }), ); } catch (err) { @@ -319,7 +320,7 @@ class LadderController { rank: higherCount + 1, storeId: ladderUser.store_id, storeName: ladderUser.store && ladderUser.store.name, - lastMatchTime: ladderUser.last_match_time, + lastMatchTime: formatDateTime(ladderUser.last_match_time), }), ); } catch (err) { diff --git a/server/src/controllers/matchAdminController.js b/server/src/controllers/matchAdminController.js index 064beba9..ccb1d08a 100644 --- a/server/src/controllers/matchAdminController.js +++ b/server/src/controllers/matchAdminController.js @@ -1,6 +1,6 @@ const { Match, MatchGame, MatchPlayer, MatchRound, LadderUser, User, Store, sequelize } = require('../models'); const { MATCH_TYPES, MATCH_STATUS, RANKING_STAGE, CONFIRM_STATUS } = require('../config/constants'); -const { generateMatchCode, success, error, getPagination, pageResult } = require('../utils/helper'); +const { generateMatchCode, success, error, getPagination, pageResult, formatDateTime } = require('../utils/helper'); const PowerCalculator = require('../services/powerCalculator'); const { broadcastToUsers, sendMatchNotification } = require('../websocket'); const { Op } = require('sequelize'); @@ -53,9 +53,9 @@ class MatchAdminController { refereeName: match.referee?.nickname, status: match.status, stage: match.stage, - startTime: match.start_time, - endTime: match.end_time, - createdAt: match.created_at + startTime: formatDateTime(match.start_time), + endTime: formatDateTime(match.end_time), + createdAt: formatDateTime(match.created_at) })), count, page, pageSize)); } catch (err) { console.error('获取比赛列表失败:', err); @@ -244,8 +244,8 @@ class MatchAdminController { storeName: match.store?.name, refereeId: match.referee_id, refereeName: match.referee?.nickname, - startTime: match.start_time, - endTime: match.end_time, + startTime: formatDateTime(match.start_time), + endTime: formatDateTime(match.end_time), players: sortedPlayers.map(p => ({ id: p.id, ladderUserId: p.ladder_user_id, diff --git a/server/src/controllers/matchController.js b/server/src/controllers/matchController.js index 5268f744..3a3d587c 100644 --- a/server/src/controllers/matchController.js +++ b/server/src/controllers/matchController.js @@ -1,6 +1,6 @@ const { Match, MatchGame, MatchPlayer, MatchRound, LadderUser, User, Store, sequelize } = require('../models'); const { MATCH_TYPES, MATCH_STATUS, CONFIRM_STATUS, RANKING_STAGE, MATCH_WEIGHTS, POWER_CALC } = require('../config/constants'); -const { generateMatchCode, success, error, getPagination, pageResult, normalizeAvatarForClient } = require('../utils/helper'); +const { generateMatchCode, success, error, getPagination, pageResult, formatDateTime, normalizeAvatarForClient } = require('../utils/helper'); const PowerCalculator = require('../services/powerCalculator'); const { sendChallengeNotification, sendScoreConfirmNotification, sendMatchNotification, broadcastToUsers, sendToUser } = require('../websocket'); const matchAdminController = require('./matchAdminController'); @@ -1036,7 +1036,7 @@ class MatchController { stageName: stageNames[match.stage] || '未知', weight: match.weight, storeName: match.store?.name, - startTime: match.start_time, + startTime: formatDateTime(match.start_time), refereeId: match.referee_id, isReferee: isReferee, players: (match.players || []).map(p => ({ @@ -1392,7 +1392,7 @@ class MatchController { powerChange: game.winner_id === myLadderId ? game.winner_power_change : game.loser_power_change, - confirmedAt: game.confirmed_at + confirmedAt: formatDateTime(game.confirmed_at) }; })); @@ -1446,17 +1446,6 @@ class MatchController { }); const opponentMap = new Map(opponents.map((o) => [String(o.id), o])); - const formatMatchTime = (date) => { - if (!date) return ''; - const d = new Date(date); - const Y = d.getFullYear(); - const M = String(d.getMonth() + 1).padStart(2, '0'); - const D = String(d.getDate()).padStart(2, '0'); - const h = String(d.getHours()).padStart(2, '0'); - const m = String(d.getMinutes()).padStart(2, '0'); - return `${Y}-${M}-${D} ${h}:${m}`; - }; - const list = rows.map((game) => { const isPlayer1 = game.player1_id === player.id; const opponentId = isPlayer1 ? game.player2_id : game.player1_id; @@ -1466,7 +1455,7 @@ class MatchController { const opponentScore = isPlayer1 ? game.player2_score : game.player1_score; const isWin = game.winner_id === player.id; const typeName = game.match && game.match.type === MATCH_TYPES.CHALLENGE ? '挑战赛' : '排位赛'; - const timeText = formatMatchTime(game.confirmed_at); + const timeText = formatDateTime(game.confirmed_at); return { id: game.id, @@ -1682,8 +1671,8 @@ class MatchController { opponent, currentGame, playerCount, - startTime: match.start_time, - createdAt: match.created_at, + startTime: formatDateTime(match.start_time), + createdAt: formatDateTime(match.created_at), isReferee: match.referee_id === user.id }; })); @@ -1745,9 +1734,9 @@ class MatchController { match.type === MATCH_TYPES.RANKING ? ["报名中", "循环赛", "淘汰赛", "已结束"][match.stage] : null, - startTime: match.start_time, - endTime: match.end_time, - createdAt: match.created_at, + startTime: formatDateTime(match.start_time), + endTime: formatDateTime(match.end_time), + createdAt: formatDateTime(match.created_at), storeId: match.store?.id, storeName: match.store?.name, })); @@ -1801,7 +1790,7 @@ class MatchController { opponentName: opponent?.real_name, myScore: game.player1_id === ladderUser.id ? game.player1_score : game.player2_score, opponentScore: game.player1_id === ladderUser.id ? game.player2_score : game.player1_score, - createdAt: game.created_at + createdAt: formatDateTime(game.created_at) }; })); @@ -1983,8 +1972,8 @@ class MatchController { status: match.status, stage: match.stage, storeName: match.store?.name, - startTime: match.start_time, - endTime: match.end_time, + startTime: formatDateTime(match.start_time), + endTime: formatDateTime(match.end_time), challenger: challengerInfo, defender: defenderInfo, myRole: myRole || null, diff --git a/server/src/controllers/pointsAdminController.js b/server/src/controllers/pointsAdminController.js index 93bc6a50..4dee6e24 100644 --- a/server/src/controllers/pointsAdminController.js +++ b/server/src/controllers/pointsAdminController.js @@ -12,6 +12,7 @@ const { error, getPagination, pageResult, + formatDateTime, } = require("../utils/helper"); const PowerCalculator = require("../services/powerCalculator"); const { Op } = require("sequelize"); @@ -311,7 +312,7 @@ class PointsAdminController { status: product.status, storeId: product.store_id, storeName: product.store?.name, - createdAt: product.created_at, + createdAt: formatDateTime(product.created_at), })), count, page, @@ -458,8 +459,8 @@ class PointsAdminController { status: order.status, storeId: order.store_id, storeName: order.store?.name, - createdAt: order.created_at, - verifiedAt: order.verified_at, + createdAt: formatDateTime(order.created_at), + verifiedAt: formatDateTime(order.verified_at), })), count, page, @@ -501,7 +502,7 @@ class PointsAdminController { orderId: order.id, orderNo: order.order_no, status: order.status, - verifiedAt: order.verified_at, + verifiedAt: formatDateTime(order.verified_at), }, }); } @@ -556,7 +557,7 @@ class PointsAdminController { orderId: order.id, orderNo: order.order_no, status: order.status, - verifiedAt: order.verified_at, + verifiedAt: formatDateTime(order.verified_at), }, }); } diff --git a/server/src/controllers/pointsController.js b/server/src/controllers/pointsController.js index 38da3432..ac5ef48e 100644 --- a/server/src/controllers/pointsController.js +++ b/server/src/controllers/pointsController.js @@ -1,6 +1,6 @@ const { User, PointRecord, PointProduct, PointOrder, Store } = require('../models'); const { ORDER_STATUS } = require('../config/constants'); -const { generateOrderNo, generateExchangeCode, success, error, getPagination, pageResult } = require('../utils/helper'); +const { generateOrderNo, generateExchangeCode, success, error, getPagination, pageResult, formatDateTime } = require('../utils/helper'); const { Op } = require('sequelize'); const sequelize = require('../config/database'); const QRCode = require('qrcode'); @@ -42,7 +42,7 @@ class PointsController { consumeAmount: record.consume_amount, storeName: record.store?.name, remark: record.remark, - createdAt: record.created_at + createdAt: formatDateTime(record.created_at) })), count, page, pageSize)); } catch (err) { console.error('获取积分记录失败:', err); @@ -225,8 +225,8 @@ class PointsController { status: order.status, storeName: order.store?.name, storeAddress: order.store?.address, - createdAt: order.created_at, - verifiedAt: order.verified_at + createdAt: formatDateTime(order.created_at), + verifiedAt: formatDateTime(order.verified_at) })), count, page, pageSize)); } catch (err) { console.error('获取订单列表失败:', err); @@ -267,8 +267,8 @@ class PointsController { storeContact: order.store?.contact, storeLatitude: order.store?.latitude, storeLongitude: order.store?.longitude, - createdAt: order.created_at, - verifiedAt: order.verified_at + createdAt: formatDateTime(order.created_at), + verifiedAt: formatDateTime(order.verified_at) })); } catch (err) { console.error('获取订单详情失败:', err); diff --git a/server/src/controllers/storeController.js b/server/src/controllers/storeController.js index 0d83fd1b..2057a013 100644 --- a/server/src/controllers/storeController.js +++ b/server/src/controllers/storeController.js @@ -1,5 +1,5 @@ const { Store, LadderUser } = require('../models'); -const { success, error, getPagination, pageResult, calculateDistance } = require('../utils/helper'); +const { success, error, getPagination, pageResult, formatDateTime, calculateDistance } = require('../utils/helper'); const { Op } = require('sequelize'); class StoreController { @@ -194,7 +194,7 @@ class StoreController { realName: lu.real_name, level: lu.level, powerScore: lu.power_score, - lastMatchTime: lu.last_match_time + lastMatchTime: formatDateTime(lu.last_match_time) })))); } catch (err) { console.error('获取天梯门店失败:', err); diff --git a/server/src/controllers/userController.js b/server/src/controllers/userController.js index 4c1ba8c9..a7b1857e 100644 --- a/server/src/controllers/userController.js +++ b/server/src/controllers/userController.js @@ -8,6 +8,7 @@ const { success, error, calculateDistance, + formatDateTime, getFullUrl, normalizeAvatarUrl, normalizeAvatarForClient, @@ -548,7 +549,7 @@ class UserController { matchCount: lu.match_count, winCount: lu.win_count, monthlyMatchCount: lu.monthly_match_count, - lastMatchTime: lu.last_match_time, + lastMatchTime: formatDateTime(lu.last_match_time), })), ), ); diff --git a/server/src/utils/helper.js b/server/src/utils/helper.js index de6314d7..24b4aded 100644 --- a/server/src/utils/helper.js +++ b/server/src/utils/helper.js @@ -204,6 +204,23 @@ function getFullUrl(path, req) { return `${protocol}://${host}${path}`; } +/** + * 统一接口返回的时间格式:YYYY-MM-DD HH:mm(服务器本地时区) + * @param {Date|string|null|undefined} date - 日期对象或 ISO 字符串 + * @returns {string} 格式化后的时间字符串,无效时返回空字符串 + */ +function formatDateTime(date) { + if (date == null) return ''; + const d = new Date(date); + if (Number.isNaN(d.getTime())) return ''; + const Y = d.getFullYear(); + const M = String(d.getMonth() + 1).padStart(2, '0'); + const D = String(d.getDate()).padStart(2, '0'); + const h = String(d.getHours()).padStart(2, '0'); + const m = String(d.getMinutes()).padStart(2, '0'); + return `${Y}-${M}-${D} ${h}:${m}`; +} + /** * 规范化返回给客户端的头像URL * 如果头像是服务端的默认头像URL,返回null让前端使用本地默认头像 @@ -233,6 +250,7 @@ module.exports = { success, error, pageResult, + formatDateTime, getFullUrl, normalizeAvatarUrl, normalizeAvatarForClient