gbmake-payload/src/components/views/AdminPanel.tsx

269 lines
8.1 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client'
import React, { useState } from 'react'
import { Button } from '@payloadcms/ui'
/**
* 管理员控制面板
* 用于执行管理操作:清理数据、系统维护等
*/
export default function AdminPanel() {
const [clearLoading, setClearLoading] = useState(false)
const [clearMessage, setClearMessage] = useState('')
const [showClearConfirm, setShowClearConfirm] = useState(false)
const [fixLoading, setFixLoading] = useState(false)
const [fixMessage, setFixMessage] = useState('')
const handleClearData = () => {
setShowClearConfirm(true)
setClearMessage('')
}
const handleConfirmClear = async () => {
setClearLoading(true)
setClearMessage('')
setShowClearConfirm(false)
try {
const response = await fetch('/api/clear-data?confirm=true', {
method: 'GET',
})
const data = await response.json()
if (data.success) {
setClearMessage(data.message || '数据清理成功!')
} else {
setClearMessage(`清理失败: ${data.error}`)
}
} catch (error) {
setClearMessage(`清理出错: ${error instanceof Error ? error.message : '未知错误'}`)
} finally {
setClearLoading(false)
}
}
const handleCancelClear = () => {
setShowClearConfirm(false)
setClearMessage('')
}
const handleFixDatabase = async () => {
if (!confirm('确定要修复数据库字段类型吗?这会修改 products 表的 thumbnail 字段。')) {
return
}
setFixLoading(true)
setFixMessage('')
try {
const response = await fetch('/api/fix-database', {
method: 'GET',
})
const data = await response.json()
if (data.success) {
setFixMessage(data.message || '数据库修复成功!')
} else {
setFixMessage(`修复失败: ${data.error}`)
}
} catch (error) {
setFixMessage(`修复出错: ${error instanceof Error ? error.message : '未知错误'}`)
} finally {
setFixLoading(false)
}
}
return (
<div style={{ padding: '2rem', maxWidth: '1200px', margin: '0 auto' }}>
<h1 style={{ marginBottom: '2rem', fontSize: '2rem', fontWeight: 'bold' }}>
🛠
</h1>
{/* 数据管理区域 */}
<div
style={{
backgroundColor: 'var(--theme-elevation-50)',
borderRadius: '8px',
padding: '1.5rem',
marginBottom: '1.5rem',
border: '1px solid var(--theme-elevation-100)',
}}
>
<h2 style={{ marginBottom: '1rem', fontSize: '1.25rem', fontWeight: '600' }}>
📦
</h2>
<div
style={{
backgroundColor: 'var(--theme-elevation-0)',
borderRadius: '6px',
padding: '1.5rem',
border: '1px solid var(--theme-elevation-150)',
}}
>
<h3 style={{ marginBottom: '0.5rem', fontSize: '1rem', fontWeight: '600' }}>
🗑
</h3>
<p
style={{
marginBottom: '1rem',
fontSize: '0.875rem',
color: 'var(--theme-elevation-600)',
}}
>
</p>
{showClearConfirm ? (
<div>
<div
style={{
marginBottom: '1rem',
padding: '1rem',
backgroundColor: 'var(--theme-error-50)',
borderRadius: '6px',
border: '1px solid var(--theme-error-500)',
}}
>
<p
style={{
margin: '0 0 0.5rem 0',
fontWeight: 'bold',
color: 'var(--theme-error-700)',
}}
>
</p>
<p style={{ margin: '0', fontSize: '0.875rem', color: 'var(--theme-error-600)' }}>
</p>
</div>
<div style={{ display: 'flex', gap: '0.75rem' }}>
<Button onClick={handleConfirmClear} disabled={clearLoading} buttonStyle="error">
{clearLoading ? '清理中...' : '确认清理'}
</Button>
<Button onClick={handleCancelClear} disabled={clearLoading} buttonStyle="secondary">
</Button>
</div>
</div>
) : (
<Button onClick={handleClearData} disabled={clearLoading} buttonStyle="error">
</Button>
)}
{clearMessage && (
<div
style={{
marginTop: '1rem',
padding: '1rem',
backgroundColor:
clearMessage.includes('失败') || clearMessage.includes('出错')
? 'var(--theme-error-50)'
: 'var(--theme-success-50)',
borderRadius: '6px',
fontSize: '0.875rem',
border: `1px solid ${
clearMessage.includes('失败') || clearMessage.includes('出错')
? 'var(--theme-error-500)'
: 'var(--theme-success-500)'
}`,
}}
>
{clearMessage}
</div>
)}
</div>
{/* 修复数据库区域 */}
<div
style={{
backgroundColor: 'var(--theme-elevation-0)',
borderRadius: '6px',
padding: '1.5rem',
marginTop: '1rem',
border: '1px solid var(--theme-elevation-150)',
}}
>
<h3 style={{ marginBottom: '0.5rem', fontSize: '1rem', fontWeight: '600' }}>
🔧
</h3>
<p
style={{
marginBottom: '1rem',
fontSize: '0.875rem',
color: 'var(--theme-elevation-600)',
}}
>
products.thumbnail integer varchar
</p>
<Button onClick={handleFixDatabase} disabled={fixLoading} buttonStyle="primary">
{fixLoading ? '修复中...' : '修复字段类型'}
</Button>
{fixMessage && (
<div
style={{
marginTop: '1rem',
padding: '1rem',
backgroundColor:
fixMessage.includes('失败') || fixMessage.includes('出错')
? 'var(--theme-error-50)'
: 'var(--theme-success-50)',
borderRadius: '6px',
fontSize: '0.875rem',
border: `1px solid ${
fixMessage.includes('失败') || fixMessage.includes('出错')
? 'var(--theme-error-500)'
: 'var(--theme-success-500)'
}`,
}}
>
{fixMessage}
</div>
)}
</div>
</div>
{/* 系统信息区域 */}
<div
style={{
backgroundColor: 'var(--theme-elevation-50)',
borderRadius: '8px',
padding: '1.5rem',
border: '1px solid var(--theme-elevation-100)',
}}
>
<h2 style={{ marginBottom: '1rem', fontSize: '1.25rem', fontWeight: '600' }}>
</h2>
<div
style={{
backgroundColor: 'var(--theme-elevation-0)',
borderRadius: '6px',
padding: '1rem',
border: '1px solid var(--theme-elevation-150)',
}}
>
<div style={{ marginBottom: '0.5rem' }}>
<strong>Payload CMS:</strong> v3.75.0
</div>
<div style={{ marginBottom: '0.5rem' }}>
<strong>:</strong> PostgreSQL
</div>
<div style={{ marginBottom: '0.5rem' }}>
<strong>:</strong> Cloudflare R2 (S3 API)
</div>
</div>
</div>
</div>
)
}