gbmake-payload/src/components/sync/medusa/BatchSyncProducts.tsx

120 lines
3.3 KiB
TypeScript

'use client'
import { useState, useEffect } from 'react'
import { Button, useSelection } from '@payloadcms/ui'
import { useRouter } from 'next/navigation'
/**
* 批量同步选中商品(普通 / 强制覆盖)
* API: POST /api/admin/batch-sync-medusa
*/
export function BatchSyncProducts() {
const { getQueryParams, toggleAll } = useSelection()
const [loading, setLoading] = useState(false)
const [message, setMessage] = useState('')
const [collectionSlug, setCollectionSlug] = useState('products')
const router = useRouter()
useEffect(() => {
if (typeof window !== 'undefined') {
setCollectionSlug(
window.location.pathname.includes('preorder-products')
? 'preorder-products'
: 'products',
)
}
}, [])
const handle = async (forceUpdate: boolean) => {
const queryParams = getQueryParams()
let selectedIds: string[] = []
if (queryParams && typeof queryParams === 'object') {
const where = (queryParams as any).where
if (where?.id?.in) selectedIds = where.id.in
}
if (!selectedIds.length) {
setMessage('⚠️ 请先勾选要同步的商品(使用列表左侧的复选框)')
return
}
if (
forceUpdate &&
!confirm(`确定要强制更新选中的 ${selectedIds.length} 个商品吗?这将覆盖本地修改。`)
)
return
setLoading(true)
setMessage('')
try {
const res = await fetch('/api/admin/batch-sync-medusa', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ids: selectedIds, collection: collectionSlug, forceUpdate }),
})
const data = await res.json()
if (data.success) {
setMessage('✅ ' + (data.message || '批量同步成功!'))
toggleAll?.()
setTimeout(() => router.refresh(), 1500)
} else {
setMessage('❌ ' + (data.error || '批量同步失败'))
}
} catch (err) {
setMessage('❌ ' + (err instanceof Error ? err.message : '未知错误'))
} finally {
setLoading(false)
}
}
return (
<div>
<div style={{ display: 'flex', gap: '0.5rem', flexWrap: 'wrap' }}>
<Button
onClick={() => handle(false)}
disabled={loading}
buttonStyle="secondary"
size="small"
>
🔄 {loading ? '同步中...' : '同步选中商品'}
</Button>
<Button
onClick={() => handle(true)}
disabled={loading}
buttonStyle="secondary"
size="small"
>
{loading ? '更新中...' : '强制更新选中'}
</Button>
</div>
{message && <StatusMsg text={message} />}
</div>
)
}
function StatusMsg({ text }: { text: string }) {
const isError = text.startsWith('❌')
const isWarn = text.startsWith('⚠️')
return (
<div
style={{
marginTop: '0.5rem',
padding: '0.4rem 0.6rem',
borderRadius: '4px',
fontSize: '0.8rem',
background: isError
? 'var(--theme-error-50)'
: isWarn
? 'var(--theme-warning-50)'
: 'var(--theme-success-50)',
color: isError
? 'var(--theme-error-750)'
: isWarn
? 'var(--theme-warning-750)'
: 'var(--theme-success-750)',
}}
>
{text}
</div>
)
}