122 lines
3.5 KiB
TypeScript
122 lines
3.5 KiB
TypeScript
'use client'
|
||
import { useState } from 'react'
|
||
import { useDocumentInfo } from '@payloadcms/ui'
|
||
|
||
/**
|
||
* 产品编辑页 — 淘宝信息同步按钮(仅填充空字段 / 强制覆盖)
|
||
* API: POST /api/admin/taobao/sync-product
|
||
*
|
||
* 使用 useDocumentInfo,只能在 Product / PreorderProduct 编辑页使用。
|
||
*/
|
||
export function TaobaoProductSync() {
|
||
const { id, collectionSlug } = useDocumentInfo()
|
||
const [loadingNormal, setLoadingNormal] = useState(false)
|
||
const [loadingForce, setLoadingForce] = useState(false)
|
||
const [message, setMessage] = useState<string | null>(null)
|
||
|
||
if (!id) return null
|
||
const isValid = collectionSlug === 'products' || collectionSlug === 'preorder-products'
|
||
if (!isValid) return null
|
||
|
||
const busy = loadingNormal || loadingForce
|
||
|
||
const run = async (force: boolean) => {
|
||
const setLoading = force ? setLoadingForce : setLoadingNormal
|
||
setLoading(true)
|
||
setMessage(null)
|
||
try {
|
||
const res = await fetch('/api/admin/taobao/sync-product', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ productId: id, collection: collectionSlug, force }),
|
||
})
|
||
const data = await res.json()
|
||
if (!data.success) throw new Error(data.error || '请求失败')
|
||
setMessage(`✅ ${data.message || '完成'}`)
|
||
setTimeout(() => window.location.reload(), 1200)
|
||
} catch (err: any) {
|
||
setMessage(`❌ ${err?.message ?? '未知错误'}`)
|
||
} finally {
|
||
setLoading(false)
|
||
}
|
||
}
|
||
|
||
return (
|
||
<div>
|
||
<div
|
||
style={{
|
||
fontSize: '0.8rem',
|
||
fontWeight: 600,
|
||
color: 'var(--theme-elevation-600)',
|
||
marginBottom: '0.5rem',
|
||
}}
|
||
>
|
||
淘宝自动解析
|
||
</div>
|
||
|
||
<div style={{ display: 'flex', gap: '0.5rem', flexWrap: 'wrap' }}>
|
||
<button
|
||
type="button"
|
||
disabled={busy}
|
||
onClick={() => run(false)}
|
||
style={btnStyle(busy, '#3b82f6')}
|
||
>
|
||
{loadingNormal ? '解析中…' : '🔄 更新淘宝信息'}
|
||
</button>
|
||
<button
|
||
type="button"
|
||
disabled={busy}
|
||
onClick={() => run(true)}
|
||
style={btnStyle(busy, '#f97316')}
|
||
>
|
||
{loadingForce ? '解析中…' : '⚡ 强制更新淘宝信息'}
|
||
</button>
|
||
</div>
|
||
|
||
<div
|
||
style={{
|
||
marginTop: '0.5rem',
|
||
fontSize: '0.73rem',
|
||
color: 'var(--theme-elevation-450)',
|
||
lineHeight: 1.5,
|
||
}}
|
||
>
|
||
<strong>🔄 更新</strong>:仅填充空白字段(标题、封面、价格) 
|
||
<strong>⚡ 强制更新</strong>:覆盖已有字段
|
||
</div>
|
||
|
||
{message && <StatusMsg text={message} />}
|
||
</div>
|
||
)
|
||
}
|
||
|
||
const btnStyle = (busy: boolean, color: string): React.CSSProperties => ({
|
||
padding: '0.4rem 0.9rem',
|
||
background: busy ? '#9ca3af' : color,
|
||
color: '#fff',
|
||
border: 'none',
|
||
borderRadius: '4px',
|
||
cursor: busy ? 'not-allowed' : 'pointer',
|
||
fontSize: '0.8rem',
|
||
fontWeight: 500,
|
||
whiteSpace: 'nowrap',
|
||
})
|
||
|
||
function StatusMsg({ text }: { text: string }) {
|
||
const isError = text.startsWith('❌')
|
||
return (
|
||
<div
|
||
style={{
|
||
marginTop: '0.5rem',
|
||
padding: '0.4rem 0.75rem',
|
||
borderRadius: '4px',
|
||
fontSize: '0.8rem',
|
||
background: isError ? 'var(--theme-error-50)' : 'var(--theme-success-50)',
|
||
color: isError ? 'var(--theme-error-750)' : 'var(--theme-success-750)',
|
||
}}
|
||
>
|
||
{text}
|
||
</div>
|
||
)
|
||
}
|