feat: support batch register resources
This commit is contained in:
143
src/components/BatchRegister.tsx
Normal file
143
src/components/BatchRegister.tsx
Normal file
@@ -0,0 +1,143 @@
|
||||
import React from 'react'
|
||||
import { Layout, Collapse, Form, Input, Button, Space, message, Spin } from 'antd'
|
||||
import type { FormInstance } from 'antd'
|
||||
import PeopleForm from './PeopleForm.tsx'
|
||||
import { createPeoplesBatch, type People } from '../apis'
|
||||
|
||||
const { Panel } = Collapse as any
|
||||
const { Content } = Layout
|
||||
|
||||
type FormItem = { id: string }
|
||||
|
||||
const BatchRegister: React.FC = () => {
|
||||
const [commonForm] = Form.useForm()
|
||||
const [items, setItems] = React.useState<FormItem[]>([{ id: `${Date.now()}-${Math.random()}` }])
|
||||
const instancesRef = React.useRef<Record<string, FormInstance>>({})
|
||||
const [loading, setLoading] = React.useState(false)
|
||||
|
||||
const addItem = () => {
|
||||
if (loading) return
|
||||
setItems((arr) => [...arr, { id: `${Date.now()}-${Math.random()}` }])
|
||||
}
|
||||
|
||||
const removeItem = (id: string) => {
|
||||
if (loading) return
|
||||
setItems((arr) => arr.filter((x) => x.id !== id))
|
||||
delete instancesRef.current[id]
|
||||
}
|
||||
|
||||
const buildPeople = (values: any, common: any): People => {
|
||||
return {
|
||||
name: values.name,
|
||||
contact: values.contact || common.contact || undefined,
|
||||
gender: values.gender,
|
||||
age: values.age,
|
||||
height: values.height || undefined,
|
||||
marital_status: values.marital_status || undefined,
|
||||
introduction: values.introduction || {},
|
||||
match_requirement: values.match_requirement || undefined,
|
||||
cover: values.cover || undefined,
|
||||
}
|
||||
}
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (loading) return
|
||||
try {
|
||||
setLoading(true)
|
||||
const common = await commonForm.validateFields().catch(() => ({}))
|
||||
const ids = items.map((x) => x.id)
|
||||
const forms = ids.map((id) => instancesRef.current[id]).filter(Boolean)
|
||||
if (forms.length !== ids.length) {
|
||||
setLoading(false)
|
||||
message.error('表单未就绪')
|
||||
return
|
||||
}
|
||||
const allValues: any[] = []
|
||||
for (const f of forms) {
|
||||
try {
|
||||
const v = await f.validateFields()
|
||||
allValues.push(v)
|
||||
} catch (err: any) {
|
||||
setLoading(false)
|
||||
message.error('请完善全部表单后再提交')
|
||||
return
|
||||
}
|
||||
}
|
||||
const payload: People[] = allValues.map((v) => buildPeople(v, common))
|
||||
const res = await createPeoplesBatch(payload)
|
||||
const failedIdx: number[] = []
|
||||
res.forEach((r, i) => {
|
||||
if (!r || r.error_code !== 0) failedIdx.push(i)
|
||||
})
|
||||
const success = res.length - failedIdx.length
|
||||
if (success > 0) message.success(`成功提交 ${success} 条`)
|
||||
if (failedIdx.length > 0) {
|
||||
message.error(`有 ${failedIdx.length} 条提交失败,请检查后重试`)
|
||||
setItems((prev) => prev.filter((_, i) => failedIdx.includes(i)))
|
||||
} else {
|
||||
setItems([{ id: `${Date.now()}-${Math.random()}` }])
|
||||
commonForm.resetFields()
|
||||
}
|
||||
} catch (e: any) {
|
||||
message.error('提交失败')
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Content className="main-content">
|
||||
<div className="content-body">
|
||||
<Collapse defaultActiveKey={["common"]}>
|
||||
<Panel header="公共属性" key="common">
|
||||
<Form form={commonForm} layout="vertical" size="large">
|
||||
<Form.Item name="contact" label="联系人">
|
||||
<Input placeholder="请输入联系人(可留空)" />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Panel>
|
||||
</Collapse>
|
||||
|
||||
<div style={{ height: 16 }} />
|
||||
|
||||
<Collapse defaultActiveKey={items.map((x) => x.id)}>
|
||||
{items.map((item, idx) => (
|
||||
<Panel
|
||||
header={`注册表单 #${idx + 1}`}
|
||||
key={item.id}
|
||||
extra={
|
||||
<Button danger size="small" onClick={() => removeItem(item.id)} disabled={loading}>
|
||||
删除
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<PeopleForm
|
||||
hideSubmitButton
|
||||
onFormReady={(f) => (instancesRef.current[item.id] = f)}
|
||||
/>
|
||||
</Panel>
|
||||
))}
|
||||
</Collapse>
|
||||
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 16 }}>
|
||||
<Space>
|
||||
<Button onClick={addItem} disabled={loading}>添加表单</Button>
|
||||
</Space>
|
||||
<Button type="primary" onClick={handleSubmit} loading={loading}>
|
||||
{loading ? '提交中...' : '提交'}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{loading && (
|
||||
<div style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.08)' }}>
|
||||
<div style={{ position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%, -50%)' }}>
|
||||
<Spin size="large" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Content>
|
||||
)
|
||||
}
|
||||
|
||||
export default BatchRegister
|
||||
Reference in New Issue
Block a user