audit fixes: align all frontend timestamps to Beijing time + debounce MarketPage search (vv2026.07.20.1)
CI / gate (push) Has been cancelled
CI / gate (push) Has been cancelled
This commit is contained in:
1 parent
d55a496ff4
commit
612ce37518
9 files changed
+46
-28
No files matched your search
@@ -1121,7 +1121,7 @@ const Achievement: React.FC = () => {
|
||||
|
||||
<td style={{ color: 'rgba(0,0,0,0.4)' }}>
|
||||
|
||||
{entry.last_completed ? new Date(entry.last_completed).toLocaleDateString('zh-CN') : '-'}
|
||||
{entry.last_completed ? formatBjDate(entry.last_completed) : '-'}
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { adminAPI, marketAPI } from '@/api';
|
||||
import type { AdBanner, MarketApp } from '@/types';
|
||||
import { formatBjDate } from '@/utils/datetime';
|
||||
import './Ads.css';
|
||||
|
||||
const SVGIcon: React.FC<{ children: React.ReactNode; size?: number }> = ({ children, size = 16 }) => (
|
||||
@@ -281,7 +282,7 @@ const Ads: React.FC = () => {
|
||||
</span>
|
||||
</td>
|
||||
<td style={{ fontSize: 'var(--text-xs)', color: 'var(--color-text-tertiary)' }}>
|
||||
{new Date(banner.createdAt).toLocaleDateString()}
|
||||
{formatBjDate(banner.createdAt)}
|
||||
</td>
|
||||
<td>
|
||||
<div style={{ display: 'flex', gap: 'var(--space-xs)' }}>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { adminAPI } from '@/api';
|
||||
import './Apps.css';
|
||||
import { formatBjTime } from '@/utils/datetime';
|
||||
import { formatBjTime, formatBjDate } from '@/utils/datetime';
|
||||
|
||||
interface AIApp {
|
||||
id: string;
|
||||
@@ -224,11 +224,7 @@ export default function AdminApps() {
|
||||
};
|
||||
|
||||
const formatDate = (dt: string | null) => {
|
||||
if (!dt) return '-';
|
||||
try {
|
||||
const d = new Date(dt);
|
||||
return d.toLocaleDateString('zh-CN') + ' ' + d.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' });
|
||||
} catch { return dt; }
|
||||
return formatBjTime(dt);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -738,7 +734,7 @@ function AppDetailDrawer({ app, analytics, onClose, onAction }: {
|
||||
<div key={v.id} className="version-item">
|
||||
<span className="version-num">v{v.version}</span>
|
||||
<span className="version-log">{v.changelog}</span>
|
||||
<span className="version-date">{v.created_at ? new Date(v.created_at).toLocaleDateString('zh-CN') : '-'}</span>
|
||||
<span className="version-date">{v.created_at ? formatBjDate(v.created_at) : '-'}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// @ts-nocheck
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { imUserAPI } from '@/api';
|
||||
import { formatBjDate } from '@/utils/datetime';
|
||||
|
||||
const PRIMARY = '#5B5FED';
|
||||
|
||||
@@ -106,7 +107,7 @@ const AppServices: React.FC = () => {
|
||||
</div>
|
||||
<p style={{ fontSize: '13px', color: '#6B7280', lineHeight: 1.7, flex: 1, margin: '0 0 14px 0' }}>{app.description || '暂无描述'}</p>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<span style={{ fontSize: '12px', color: '#9CA3AF' }}>{app.published_at ? '上架于 ' + new Date(app.published_at).toLocaleDateString('zh-CN') : ''}</span>
|
||||
<span style={{ fontSize: '12px', color: '#9CA3AF' }}>{app.published_at ? '上架于 ' + formatBjDate(app.published_at) : ''}</span>
|
||||
<button onClick={() => showToast('已加入「我的应用」,可在 AI 聊天中调用')} style={{ padding: '7px 16px', background: PRIMARY, border: 'none', borderRadius: '8px', color: '#fff', fontSize: '13px', fontWeight: 500, cursor: 'pointer' }}>使用</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import type { Asset, AssetCategory, AssetCategoryDef, AssetFileType } from '@/types';
|
||||
import { assetsAPI } from '@/api';
|
||||
import { formatBjTime } from '@/utils/datetime';
|
||||
import './AssetsPage.css';
|
||||
|
||||
const fileTypeLabels: Record<string, { label: string; bg: string; color: string }> = {
|
||||
@@ -46,7 +47,7 @@ function formatSize(bytes?: number): string {
|
||||
}
|
||||
|
||||
function formatDate(dateStr: string): string {
|
||||
return new Date(dateStr).toLocaleDateString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' });
|
||||
return formatBjTime(dateStr);
|
||||
}
|
||||
|
||||
// 将文件扩展名或API返回的file_type映射到前端fileType标签
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState, useRef, useEffect, useMemo, useCallback } from 'react';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { chatAPI, knowledgeAPI, marketAPI, evolutionAPI } from '@/api';
|
||||
import { formatChatTime } from '@/utils/datetime';
|
||||
import type { Conversation, Message } from '@/types';
|
||||
import './ChatPage.css';
|
||||
|
||||
@@ -396,21 +397,7 @@ function escapeHtml(text: string): string {
|
||||
|
||||
// ===== Time Formatting =====
|
||||
function formatTime(iso: string): string {
|
||||
const date = new Date(iso);
|
||||
const now = new Date();
|
||||
const diff = now.getTime() - date.getTime();
|
||||
const oneDay = 24 * 60 * 60 * 1000;
|
||||
|
||||
if (diff < oneDay) {
|
||||
return date.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' });
|
||||
} else if (diff < 7 * oneDay) {
|
||||
const days = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
||||
return days[date.getDay()];
|
||||
} else if (date.getFullYear() === now.getFullYear()) {
|
||||
return `${date.getMonth() + 1}/${date.getDate()}`;
|
||||
} else {
|
||||
return `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`;
|
||||
}
|
||||
return formatChatTime(iso);
|
||||
}
|
||||
|
||||
// ===== Helpers: normalize API responses =====
|
||||
|
||||
@@ -1596,6 +1596,7 @@ const MarketPage: React.FC = () => {
|
||||
const [localApps, setLocalApps] = useState<MarketApp[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const searchTimerRef = useRef<number | null>(null);
|
||||
const [capabilityFilter, setCapabilityFilter] = useState<string | null>(null);
|
||||
const [installToast, setInstallToast] = useState<string | null>(null);
|
||||
|
||||
@@ -1893,7 +1894,7 @@ const MarketPage: React.FC = () => {
|
||||
className="form-input"
|
||||
placeholder="搜索应用名称或描述..."
|
||||
value={searchQuery}
|
||||
onChange={e => { setSearchQuery(e.target.value); loadApps(e.target.value); }}
|
||||
onChange={e => { const v = e.target.value; setSearchQuery(v); if (searchTimerRef.current) clearTimeout(searchTimerRef.current); searchTimerRef.current = window.setTimeout(() => loadApps(v), 350); }}
|
||||
style={{ paddingLeft: 32, flex: 1, maxWidth: 400 }}
|
||||
/>
|
||||
{searchQuery && (
|
||||
|
||||
Reference in new issue
Block a user