gbmake-payload/src/components/sync/admin/ResetData.tsx

117 lines
4.2 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 { useState } from 'react'
import { Button } from '@payloadcms/ui'
/**
* 数据重置按钮(全量 / 仅 Medusa
* API: POST /api/admin/reset-data
*/
export function ResetData() {
const [loading, setLoading] = useState<'full' | 'medusa-only' | null>(null)
const [message, setMessage] = useState('')
const [details, setDetails] = useState<any>(null)
const handle = async (mode: 'full' | 'medusa-only') => {
const confirmMsg =
mode === 'medusa-only'
? '⚠️ 重置 Medusa 数据\n\n此操作将\n1. 清理所有 Medusa 数据\n2. 重新导入 Medusa seed 数据\n\nPayload CMS 数据不受影响。\n\n⚠ 此操作不可撤销!确认继续吗?'
: '⚠️ 危险操作:重置所有数据\n\n此操作将\n1. 清理所有 Payload CMS 数据(保留用户)\n2. 清理所有 Medusa 数据\n3. 重新导入 Medusa seed 数据\n\n⚠ 此操作不可撤销!确认要继续吗?'
if (!confirm(confirmMsg)) return
setLoading(mode)
setMessage('🔄 开始数据重置流程...')
setDetails(null)
try {
const res = await fetch('/api/admin/reset-data', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ mode }),
})
const result = await res.json()
if (!result.success) {
const stepError = result.steps?.find((s: any) => !s.success && !s.skipped && s.error)?.error
throw new Error(result.error || stepError || 'Reset failed')
}
setDetails(result)
setMessage(
mode === 'medusa-only'
? '✅ Medusa 数据重置完成!\n\n下一步\n1. 同步 Medusa 商品到 Payload CMS'
: '✅ 数据重置完成!\n\n下一步\n1. 同步 Medusa 商品到 Payload CMS\n2. 设置 ProductRecommendations\n3. 配置 PreorderProducts 的预购设置',
)
} catch (err) {
setMessage('❌ 重置失败: ' + (err instanceof Error ? err.message : 'Unknown error'))
} finally {
setLoading(null)
}
}
const busy = loading !== null
return (
<div>
<div style={{ display: 'flex', gap: '0.75rem', flexWrap: 'wrap' }}>
<Button onClick={() => handle('full')} buttonStyle="error" disabled={busy} size="small">
{loading === 'full' ? '🔄 重置中...' : '🗑️ 重置所有数据'}
</Button>
<Button
onClick={() => handle('medusa-only')}
buttonStyle="secondary"
disabled={busy}
size="small"
>
{loading === 'medusa-only' ? '🔄 重置中...' : '🔄 仅重置 Medusa'}
</Button>
</div>
{message && (
<div
style={{
marginTop: '0.75rem',
padding: '0.75rem',
borderRadius: '4px',
whiteSpace: 'pre-wrap',
fontSize: '0.85rem',
backgroundColor: message.includes('✅')
? '#d4edda'
: message.includes('❌')
? '#f8d7da'
: '#d1ecf1',
border: `1px solid ${message.includes('✅') ? '#c3e6cb' : message.includes('❌') ? '#f5c6cb' : '#bee5eb'}`,
}}
>
{message}
</div>
)}
{details?.steps && (
<div
style={{
marginTop: '0.75rem',
padding: '0.75rem',
background: '#f8f9fa',
border: '1px solid #dee2e6',
borderRadius: '4px',
fontSize: '0.82rem',
}}
>
<h4 style={{ margin: '0 0 0.5rem' }}></h4>
{details.steps.map((step: any, i: number) => (
<div key={i} style={{ marginBottom: '0.4rem' }}>
<strong>
[{step.step}/3] {step.name}:{' '}
</strong>
<span style={{ color: step.skipped ? '#888' : step.success ? 'green' : 'red' }}>
{step.skipped ? '⏭️ 跳过' : step.success ? '✅ 成功' : '❌ 失败'}
</span>
{step.deleted !== undefined && (
<span style={{ marginLeft: '0.4rem' }}>( {step.deleted} )</span>
)}
</div>
))}
</div>
)}
</div>
)
}