使用dayjs格式化时间
显示格式为"YYYY-MM-DD HH:mm:ss" 保持表格其他功能和样式不变 确保时间显示清晰易读
This commit is contained in:
@@ -1,2 +1,3 @@
|
||||
2025.05.13 0.1.0
|
||||
首页添加了迁移管理入口按钮, 无需登录即可访问
|
||||
首页添加了迁移管理入口按钮, 无需登录即可访问
|
||||
打开迁移管理页面时,将迁移历史读取出来
|
||||
@@ -1,10 +1,12 @@
|
||||
import React, { useState } from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { Button, Space, Alert, Spin, Typography } from 'antd';
|
||||
import { Button, Space, Alert, Spin, Typography, Table } from 'antd';
|
||||
import axios from 'axios';
|
||||
import dayjs from 'dayjs';
|
||||
import {
|
||||
QueryClient,
|
||||
QueryClientProvider,
|
||||
useQuery,
|
||||
} from '@tanstack/react-query';
|
||||
|
||||
const { Title } = Typography;
|
||||
@@ -18,10 +20,26 @@ interface MigrationResponse {
|
||||
failedResult?: any;
|
||||
}
|
||||
|
||||
interface MigrationHistory {
|
||||
id: string;
|
||||
name: string;
|
||||
status: string;
|
||||
timestamp: string;
|
||||
batch: string;
|
||||
}
|
||||
|
||||
const MigrationsApp: React.FC = () => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [migrationResult, setMigrationResult] = useState<MigrationResponse | null>(null);
|
||||
|
||||
const { data: historyData, isLoading: isHistoryLoading, error: historyError } = useQuery({
|
||||
queryKey: ['migrations-history'],
|
||||
queryFn: async () => {
|
||||
const response = await axios.get('/api/migrations/history');
|
||||
return response.data.history;
|
||||
}
|
||||
});
|
||||
|
||||
const runMigrations = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
@@ -40,13 +58,43 @@ const MigrationsApp: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '迁移名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
sorter: (a: MigrationHistory, b: MigrationHistory) => a.name.localeCompare(b.name),
|
||||
},
|
||||
{
|
||||
title: '批次',
|
||||
dataIndex: 'batch',
|
||||
key: 'batch',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
render: (status: string) => (
|
||||
<span style={{ color: status === 'completed' ? 'green' : 'red' }}>
|
||||
{status === 'completed' ? '已完成' : '失败'}
|
||||
</span>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '时间',
|
||||
dataIndex: 'timestamp',
|
||||
key: 'timestamp',
|
||||
render: (timestamp: string) => dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="p-4">
|
||||
<Title level={3}>数据库迁移管理</Title>
|
||||
|
||||
<Space direction="vertical" size="middle" style={{ width: '100%' }}>
|
||||
<Button
|
||||
type="primary"
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={runMigrations}
|
||||
loading={loading}
|
||||
disabled={loading}
|
||||
@@ -58,13 +106,13 @@ const MigrationsApp: React.FC = () => {
|
||||
|
||||
{migrationResult && (
|
||||
migrationResult.success ? (
|
||||
<Alert
|
||||
message="迁移成功"
|
||||
type="success"
|
||||
showIcon
|
||||
<Alert
|
||||
message="迁移成功"
|
||||
type="success"
|
||||
showIcon
|
||||
/>
|
||||
) : (
|
||||
<Alert
|
||||
<Alert
|
||||
message="迁移失败"
|
||||
description={
|
||||
<>
|
||||
@@ -76,11 +124,39 @@ const MigrationsApp: React.FC = () => {
|
||||
)}
|
||||
</>
|
||||
}
|
||||
type="error"
|
||||
showIcon
|
||||
type="error"
|
||||
showIcon
|
||||
/>
|
||||
)
|
||||
)}
|
||||
|
||||
<Title level={4}>迁移历史记录</Title>
|
||||
|
||||
{isHistoryLoading ? (
|
||||
<Spin tip="加载历史记录中..." />
|
||||
) : historyError ? (
|
||||
<Alert
|
||||
message="加载历史记录失败"
|
||||
description={historyError.message}
|
||||
type="error"
|
||||
showIcon
|
||||
/>
|
||||
) : (
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={historyData}
|
||||
rowKey="id"
|
||||
pagination={{
|
||||
pageSize: 10,
|
||||
showSizeChanger: true,
|
||||
pageSizeOptions: ['10', '20', '50', '100'],
|
||||
showTotal: (total) => `共 ${total} 条记录`,
|
||||
}}
|
||||
bordered
|
||||
className="migration-history-table"
|
||||
style={{ marginTop: 16 }}
|
||||
/>
|
||||
)}
|
||||
</Space>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -7,20 +7,15 @@ import debug from "debug";
|
||||
const log = {
|
||||
api: debug("api:migrations"),
|
||||
};
|
||||
// 初始化数据库
|
||||
const initDatabase = async (apiClient: APIClient) => {
|
||||
log.api('正在执行数据库迁移...')
|
||||
const migrationsResult = await apiClient.database.executeLiveMigrations(migrations)
|
||||
// log.app('数据库迁移完成 %O',migrationsResult)
|
||||
log.api('数据库迁移完成')
|
||||
return migrationsResult
|
||||
}
|
||||
|
||||
export function createMigrationsRoutes(withAuth: WithAuth) {
|
||||
const migrationsRoutes = new Hono<{ Variables: Variables }>()
|
||||
|
||||
migrationsRoutes.get('/', async (c) => {
|
||||
const apiClient = c.get('apiClient')
|
||||
const migrationsResult = await initDatabase(apiClient)
|
||||
log.api('正在执行数据库迁移...')
|
||||
const migrationsResult = await apiClient.database.executeLiveMigrations(migrations)
|
||||
// log.app('数据库迁移完成 %O',migrationsResult)
|
||||
|
||||
const failedResult = migrationsResult?.find((migration) => migration.status === 'failed')
|
||||
if (failedResult) {
|
||||
@@ -31,5 +26,23 @@ export function createMigrationsRoutes(withAuth: WithAuth) {
|
||||
return c.json({ success: true })
|
||||
})
|
||||
|
||||
|
||||
migrationsRoutes.get('/history', async (c) => {
|
||||
const apiClient = c.get('apiClient')
|
||||
log.api('正在执行数据库迁移...')
|
||||
const MIRGRATIONS_TABLE = 'knex_migrations'
|
||||
const hasTable = await apiClient.database.schema.hasTable(MIRGRATIONS_TABLE);
|
||||
|
||||
let history = []
|
||||
|
||||
if(hasTable)
|
||||
history = await apiClient.database.table(MIRGRATIONS_TABLE).orderBy('id', 'desc')
|
||||
|
||||
return c.json({
|
||||
success: true,
|
||||
history
|
||||
})
|
||||
})
|
||||
|
||||
return migrationsRoutes
|
||||
}
|
||||
Reference in New Issue
Block a user