120 lines
3.3 KiB
TypeScript
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>
|
|
)
|
|
}
|