492 lines
21 KiB
React
492 lines
21 KiB
React
|
|
import React, { useState, useRef, useEffect } from 'react'
|
|||
|
|
|
|||
|
|
// Input 组件(复用 Add.jsx 的定义)
|
|||
|
|
const Input = ({ form, handleChange, label, field, type = 'text', options = null }) => {
|
|||
|
|
const onChange = (e) => {
|
|||
|
|
const value = e.target.value
|
|||
|
|
if (type === 'number' && value !== '') {
|
|||
|
|
const num = parseFloat(value)
|
|||
|
|
handleChange(field, isNaN(num) ? '' : num)
|
|||
|
|
} else handleChange(field, value)
|
|||
|
|
}
|
|||
|
|
return (
|
|||
|
|
<div style={{ flex: 1, minWidth: '45%', marginBottom: '12px' }}>
|
|||
|
|
<div style={{ fontSize: '12px', color: '#94a3b8', marginBottom: '4px' }}>{label}</div>
|
|||
|
|
{options ? (
|
|||
|
|
<select value={form[field] || ''} onChange={onChange}
|
|||
|
|
style={{ background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.1)', color: '#fff', padding: '8px', borderRadius: '6px', width: '100%', fontSize: '13px' }}>
|
|||
|
|
<option value="">请选择</option>
|
|||
|
|
{options.map(o => <option key={o.value} value={o.value} style={{color:'#000'}}>{o.label}</option>)}
|
|||
|
|
</select>
|
|||
|
|
) : (
|
|||
|
|
<input type={type} value={form[field] ?? ''} onChange={onChange}
|
|||
|
|
style={{ background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.1)', color: '#fff', padding: '8px', borderRadius: '6px', width: '100%', fontSize: '13px' }} />
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 选项定义
|
|||
|
|
const statusOptions = [
|
|||
|
|
{ value: 'in_collection', label: '收藏中' },
|
|||
|
|
{ value: 'selling', label: '出售中' },
|
|||
|
|
{ value: 'sold', label: '已售' },
|
|||
|
|
{ value: 'grading', label: '送评中' },
|
|||
|
|
{ value: 'repairing', label: '修复中' },
|
|||
|
|
{ value: 'transit', label: '在途中' },
|
|||
|
|
{ value: 'seeking', label: '寻号中' },
|
|||
|
|
{ value: 'other', label: '其他' }
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
const categoryOptions = [
|
|||
|
|
{ value: '自持', label: '自持' },
|
|||
|
|
{ value: '寄存', label: '寄存' },
|
|||
|
|
{ value: '寄售', label: '寄售' },
|
|||
|
|
{ value: '共有', label: '共有' },
|
|||
|
|
{ value: '其他', label: '其他' }
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
const numberCategoryOptions = [{value:'无2347',label:'无2347'},{value:'无347',label:'无347'},{value:'无247',label:'无247'},{value:'无47',label:'无47'},{value:'无4',label:'无4'},{value:'带4',label:'带4'},{value:'其他',label:'其他'}];
|
|||
|
|
const rarityOptions = [
|
|||
|
|
{ value: '通货', label: '通货' },
|
|||
|
|
{ value: '特色', label: '特色' },
|
|||
|
|
{ value: '少见', label: '少见' },
|
|||
|
|
{ value: '稀有', label: '稀有' },
|
|||
|
|
{ value: '珍品', label: '珍品' },
|
|||
|
|
{ value: '孤品', label: '孤品' }
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
const packagingOptions = [
|
|||
|
|
{ value: '标十', label: '标十' },
|
|||
|
|
{ value: '标百', label: '标百' },
|
|||
|
|
{ value: '单张', label: '单张' },
|
|||
|
|
{ value: '裸钞', label: '裸钞' }
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
export default function Edit() {
|
|||
|
|
// 从 URL 获取藏品 ID
|
|||
|
|
const params = new URLSearchParams(window.location.hash.split('?')[1] || '')
|
|||
|
|
const editId = params.get('id')
|
|||
|
|
|
|||
|
|
const [form, setForm] = useState({
|
|||
|
|
name: '', code: '', category: '自持', rarity: '通货', numberCategory: '', prefixSerial: '',
|
|||
|
|
version: '2024 龙', denomination: '', status: 'in_collection', packaging: '单张',
|
|||
|
|
material: '塑料钞', issueQuantity: '1 亿', purpose: '收藏', isGraded: false,
|
|||
|
|
gradingCompany: '', gradingScore: '', threeStar: false, specialMark: '',
|
|||
|
|
serialFeature: '', issuer: '中国人民银行', issueYear: '2024',
|
|||
|
|
costPrice: '', targetPrice: '', goalPrice: '', repairFee: '', gradingFee: '', remark: ''
|
|||
|
|
})
|
|||
|
|
const [loading, setLoading] = useState(true)
|
|||
|
|
const [saving, setSaving] = useState(false)
|
|||
|
|
const [error, setError] = useState('')
|
|||
|
|
const [uploadImages, setUploadImages] = useState([])
|
|||
|
|
const fileInputRef = useRef(null)
|
|||
|
|
|
|||
|
|
// 加载现有藏品数据
|
|||
|
|
useEffect(() => {
|
|||
|
|
if (editId) {
|
|||
|
|
const token = localStorage.getItem('token')
|
|||
|
|
fetch(`/api/collections/${editId}`, {
|
|||
|
|
headers: { 'Authorization': 'Bearer ' + token }
|
|||
|
|
})
|
|||
|
|
.then(res => res.json())
|
|||
|
|
.then(data => {
|
|||
|
|
// 填充表单
|
|||
|
|
setForm({
|
|||
|
|
name: data.name || '',
|
|||
|
|
code: data.code || '',
|
|||
|
|
category: data.category || '自持',
|
|||
|
|
rarity: data.rarity || '通货',
|
|||
|
|
numberCategory: data.numberCategory || '',
|
|||
|
|
prefixSerial: data.prefixSerial || '',
|
|||
|
|
version: data.version || '2024 龙',
|
|||
|
|
denomination: data.denomination || '',
|
|||
|
|
status: data.status || 'in_collection',
|
|||
|
|
packaging: data.packaging || '单张',
|
|||
|
|
isGraded: data.isGraded || false,
|
|||
|
|
gradingCompany: data.gradingCompany || '',
|
|||
|
|
gradingScore: data.gradingScore || '',
|
|||
|
|
threeStar: data.threeStar || false,
|
|||
|
|
specialMark: data.specialMark || '',
|
|||
|
|
serialFeature: data.serialFeature || '',
|
|||
|
|
issuer: data.issuer || '中国人民银行',
|
|||
|
|
issueYear: data.issueYear || '2024',
|
|||
|
|
material: data.material || '塑料钞',
|
|||
|
|
issueQuantity: data.issueQuantity || '1 亿',
|
|||
|
|
costPrice: data.costPrice || '',
|
|||
|
|
targetPrice: data.targetPrice || '',
|
|||
|
|
goalPrice: data.goalPrice || '',
|
|||
|
|
repairFee: data.repairFee || '',
|
|||
|
|
gradingFee: data.gradingFee || '',
|
|||
|
|
purpose: data.purpose || '收藏',
|
|||
|
|
remark: data.remark || ''
|
|||
|
|
})
|
|||
|
|
// 加载图片
|
|||
|
|
if (data.images && Array.isArray(data.images)) {
|
|||
|
|
const images = data.images.map(img => ({
|
|||
|
|
file: null,
|
|||
|
|
preview: img.path?.startsWith('http') ? img.path : `/${img.path || `uploads/collections/${img.filename}`}`,
|
|||
|
|
name: img.original_name || img.filename,
|
|||
|
|
size: 0,
|
|||
|
|
id: img.id
|
|||
|
|
}))
|
|||
|
|
setUploadImages(images)
|
|||
|
|
}
|
|||
|
|
setLoading(false)
|
|||
|
|
})
|
|||
|
|
.catch(err => {
|
|||
|
|
console.error('加载藏品失败:', err)
|
|||
|
|
setError('加载失败:' + err.message)
|
|||
|
|
setLoading(false)
|
|||
|
|
})
|
|||
|
|
} else {
|
|||
|
|
setError('未指定藏品 ID')
|
|||
|
|
setLoading(false)
|
|||
|
|
}
|
|||
|
|
}, [editId])
|
|||
|
|
|
|||
|
|
const handleChange = (key, value) => {
|
|||
|
|
setForm({ ...form, [key]: value })
|
|||
|
|
if (key === 'targetPrice' && value) setForm(prev => ({ ...prev, status: 'sold' }))
|
|||
|
|
// 冠字号变化时自动分类
|
|||
|
|
if (key === 'prefixSerial') {
|
|||
|
|
const serial = value
|
|||
|
|
let cat = ''
|
|||
|
|
const match = serial.match(/J(\d{9})/)
|
|||
|
|
const digits = match ? match[1] : serial.replace(/\D/g, '').slice(0, 9)
|
|||
|
|
if (digits) {
|
|||
|
|
if (!digits.includes('2') && !digits.includes('3') && !digits.includes('4') && !digits.includes('7')) cat = '无2347'
|
|||
|
|
else if (!digits.includes('3') && !digits.includes('4') && !digits.includes('7')) cat = '无347'
|
|||
|
|
else if (digits.includes('4')) cat = '带4'
|
|||
|
|
else if (digits.includes('7')) cat = '无4'
|
|||
|
|
else if (!digits.includes('4') && !digits.includes('7')) cat = '无47'
|
|||
|
|
else if (!digits.includes('2') && !digits.includes('4') && !digits.includes('7')) cat = '无247'
|
|||
|
|
else cat = '其他'
|
|||
|
|
}
|
|||
|
|
setForm(prev => ({ ...prev, numberCategory: cat }))
|
|||
|
|
}
|
|||
|
|
// 版别变化时同步发行年份
|
|||
|
|
if (key === 'version') {
|
|||
|
|
const yearMatch = value.match(/(20\d{2})/)
|
|||
|
|
if (yearMatch) {
|
|||
|
|
setForm(prev => ({ ...prev, issueYear: yearMatch[1] }))
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 图片上传处理
|
|||
|
|
const handleImageUpload = async (e) => {
|
|||
|
|
const files = Array.from(e.target.files)
|
|||
|
|
if (files.length === 0 || !editId) return
|
|||
|
|
|
|||
|
|
const token = localStorage.getItem('token')
|
|||
|
|
const file = files[0] // 只允许上传 1 张
|
|||
|
|
|
|||
|
|
const imgFormData = new FormData()
|
|||
|
|
imgFormData.append('file', file)
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
const res = await fetch(`/api/collections/upload-image?collection_id=${editId}`, {
|
|||
|
|
method: 'POST',
|
|||
|
|
headers: { 'Authorization': 'Bearer ' + token },
|
|||
|
|
body: imgFormData
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
if (res.ok) {
|
|||
|
|
// 重新加载藏品数据
|
|||
|
|
const dataRes = await fetch(`/api/collections/${editId}`, {
|
|||
|
|
headers: { 'Authorization': 'Bearer ' + token }
|
|||
|
|
})
|
|||
|
|
const data = await dataRes.json()
|
|||
|
|
if (data.images && Array.isArray(data.images)) {
|
|||
|
|
const images = data.images.map(img => ({
|
|||
|
|
file: null,
|
|||
|
|
preview: img.path?.startsWith('http') ? img.path : `/${img.path || `uploads/collections/${img.filename}`}`,
|
|||
|
|
name: img.original_name || img.filename,
|
|||
|
|
size: 0,
|
|||
|
|
id: img.id
|
|||
|
|
}))
|
|||
|
|
setUploadImages(images)
|
|||
|
|
}
|
|||
|
|
alert('图片上传成功!')
|
|||
|
|
} else {
|
|||
|
|
alert('图片上传失败')
|
|||
|
|
}
|
|||
|
|
} catch (err) {
|
|||
|
|
console.error('图片上传失败:', err)
|
|||
|
|
alert('图片上传失败:' + err.message)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const handleSave = async () => {
|
|||
|
|
if (!form.name || !form.version) { setError('名称和版别为必填项'); return }
|
|||
|
|
setSaving(true)
|
|||
|
|
setError('')
|
|||
|
|
const token = localStorage.getItem('token')
|
|||
|
|
const formData = convertField(form)
|
|||
|
|
try {
|
|||
|
|
// 1. 更新藏品信息
|
|||
|
|
const res = await fetch(`/api/collections/${editId}`, {
|
|||
|
|
method: 'PUT',
|
|||
|
|
headers: {
|
|||
|
|
'Content-Type': 'application/json',
|
|||
|
|
'Authorization': 'Bearer ' + token
|
|||
|
|
},
|
|||
|
|
body: JSON.stringify(formData)
|
|||
|
|
})
|
|||
|
|
if (!res.ok) {
|
|||
|
|
const data = await res.json()
|
|||
|
|
throw new Error(data.error?.message || data.detail || '更新失败')
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
alert('更新成功!')
|
|||
|
|
window.location.hash = '#/list'
|
|||
|
|
window.refreshList?.()
|
|||
|
|
} catch (e) {
|
|||
|
|
console.error('更新失败:', e)
|
|||
|
|
alert('更新失败:' + e.message)
|
|||
|
|
}
|
|||
|
|
finally { setSaving(false) }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 字段转换函数
|
|||
|
|
const convertField = (obj) => {
|
|||
|
|
const map = {
|
|||
|
|
id: 'f99_90_id', userId: 'f99_91_user_id',
|
|||
|
|
name: 'f01_01_name', code: 'f01_02_code', category: 'f01_03_category',
|
|||
|
|
status: 'f01_04_status', remark: 'f01_05_remark',
|
|||
|
|
prefixSerial: 'f02_10_prefix_serial', version: 'f02_11_version',
|
|||
|
|
packaging: 'f02_12_packaging', rarity: 'f02_13_rarity',
|
|||
|
|
numberCategory: 'f02_14_number_category',
|
|||
|
|
isGraded: 'f03_20_is_graded', gradingCompany: 'f03_21_grading_company',
|
|||
|
|
gradingScore: 'f03_22_grading_score', threeStar: 'f03_23_three_star',
|
|||
|
|
specialMark: 'f04_30_special_mark', serialFeature: 'f04_31_serial_feature',
|
|||
|
|
issuer: 'f04_32_issuer', issueYear: 'f04_33_issue_year',
|
|||
|
|
material: 'f04_34_material', denomination: 'f04_35_denomination',
|
|||
|
|
issueQuantity: 'f04_36_issue_quantity',
|
|||
|
|
costPrice: 'f05_40_cost_price', targetPrice: 'f05_41_target_price',
|
|||
|
|
goalPrice: 'f05_42_goal_price', repairFee: 'f05_43_repair_fee',
|
|||
|
|
gradingFee: 'f05_44_grading_fee', purpose: 'f06_50_purpose'
|
|||
|
|
}
|
|||
|
|
const result = {}
|
|||
|
|
const numberFields = ['costPrice', 'targetPrice', 'goalPrice', 'repairFee', 'gradingFee']
|
|||
|
|
for (const key in obj) {
|
|||
|
|
let value = obj[key]
|
|||
|
|
if (value === '' || value === null) value = null
|
|||
|
|
else if (numberFields.includes(key)) {
|
|||
|
|
value = parseFloat(value)
|
|||
|
|
if (isNaN(value)) value = null
|
|||
|
|
}
|
|||
|
|
result[map[key] || key] = value
|
|||
|
|
}
|
|||
|
|
return result
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (loading) {
|
|||
|
|
return (
|
|||
|
|
<div style={{ background: '#0f172a', minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
|||
|
|
<div style={{ color: '#94a3b8', fontSize: '16px' }}>加载中...</div>
|
|||
|
|
</div>
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div style={{ background: '#0f172a', minHeight: '100vh', paddingBottom: '80px' }}>
|
|||
|
|
{/* 顶部标题 */}
|
|||
|
|
<div style={{ padding: '16px', background: 'rgba(255,255,255,0.02)', borderBottom: '1px solid rgba(255,255,255,0.05)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
|||
|
|
<div>
|
|||
|
|
<div style={{ color: '#fff', fontSize: '18px', fontWeight: 'bold' }}>编辑藏品</div>
|
|||
|
|
<div style={{ color: '#94a3b8', fontSize: '13px', marginTop: '4px' }}>修改藏品信息</div>
|
|||
|
|
</div>
|
|||
|
|
<div onClick={() => window.history.back()} style={{ color: '#60a5fa', fontSize: '24px', cursor: 'pointer', padding: '8px' }}>←</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{error && (
|
|||
|
|
<div style={{ margin: '16px', padding: '12px', background: 'rgba(239, 68, 68, 0.2)', border: '1px solid #ef4444', color: '#ef4444', borderRadius: '8px' }}>
|
|||
|
|
⚠️ {error}
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
|
|||
|
|
<div style={{ padding: '16px' }}>
|
|||
|
|
{/* 藏品图片 */}
|
|||
|
|
<div style={{ background: 'rgba(255,255,255,0.03)', borderRadius: '12px', padding: '16px', marginBottom: '12px' }}>
|
|||
|
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '12px' }}>
|
|||
|
|
<div style={{ color: '#fbbf24', fontSize: '14px', fontWeight: 'bold' }}>藏品图片 ({uploadImages.length}/1)</div>
|
|||
|
|
{uploadImages.length === 0 && (
|
|||
|
|
<button
|
|||
|
|
onClick={() => fileInputRef.current?.click()}
|
|||
|
|
style={{
|
|||
|
|
padding: '6px 12px',
|
|||
|
|
background: 'rgba(34, 197, 94, 0.2)',
|
|||
|
|
color: '#22c55e',
|
|||
|
|
border: '1px solid #22c55e',
|
|||
|
|
borderRadius: '6px',
|
|||
|
|
fontSize: '12px',
|
|||
|
|
cursor: 'pointer'
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
📷 上传图片
|
|||
|
|
</button>
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* 隐藏的文件输入框 */}
|
|||
|
|
<input
|
|||
|
|
ref={fileInputRef}
|
|||
|
|
type="file"
|
|||
|
|
accept="image/*"
|
|||
|
|
onChange={handleImageUpload}
|
|||
|
|
style={{ display: 'none' }}
|
|||
|
|
/>
|
|||
|
|
{uploadImages.length > 0 ? (
|
|||
|
|
<div style={{ display: 'grid', gridTemplateColumns: `repeat(${Math.min(uploadImages.length, 1)}, 1fr)`, gap: '12px' }}>
|
|||
|
|
{uploadImages.map((img, index) => (
|
|||
|
|
<div key={img.id || index} style={{ position: 'relative' }}>
|
|||
|
|
<img
|
|||
|
|
src={img.preview}
|
|||
|
|
alt={img.name || '藏品图片'}
|
|||
|
|
style={{
|
|||
|
|
width: '100%',
|
|||
|
|
aspectRatio: '1.5',
|
|||
|
|
objectFit: 'contain',
|
|||
|
|
borderRadius: '12px',
|
|||
|
|
border: '2px solid #10b981',
|
|||
|
|
boxShadow: '0 4px 12px rgba(0,0,0,0.3)',
|
|||
|
|
background: 'rgba(0,0,0,0.3)'
|
|||
|
|
}}
|
|||
|
|
/>
|
|||
|
|
<div style={{
|
|||
|
|
position: 'absolute',
|
|||
|
|
top: '8px',
|
|||
|
|
left: '8px',
|
|||
|
|
background: 'rgba(0,0,0,0.6)',
|
|||
|
|
color: '#fff',
|
|||
|
|
padding: '4px 8px',
|
|||
|
|
borderRadius: '4px',
|
|||
|
|
fontSize: '12px'
|
|||
|
|
}}>{index + 1}/{uploadImages.length}</div>
|
|||
|
|
</div>
|
|||
|
|
))}
|
|||
|
|
</div>
|
|||
|
|
) : (
|
|||
|
|
<div style={{ textAlign: 'center', color: '#94a3b8', padding: '24px' }}>
|
|||
|
|
📷 暂无图片
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* 基本信息 */}
|
|||
|
|
<div style={{ background: 'rgba(255,255,255,0.03)', borderRadius: '12px', padding: '16px', marginBottom: '12px' }}>
|
|||
|
|
<div style={{ color: '#fbbf24', fontSize: '14px', fontWeight: 'bold', marginBottom: '12px' }}>基本信息</div>
|
|||
|
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '12px' }}>
|
|||
|
|
<Input form={form} handleChange={handleChange} label="名称 *" field="name" />
|
|||
|
|
<Input form={form} handleChange={handleChange} label="编号" field="code" />
|
|||
|
|
<Input form={form} handleChange={handleChange} label="持仓类型" field="category" options={categoryOptions} />
|
|||
|
|
<Input form={form} handleChange={handleChange} label="珍惜度" field="rarity" options={rarityOptions} />
|
|||
|
|
<Input form={form} handleChange={handleChange} label="冠字序号" field="prefixSerial" />
|
|||
|
|
<Input form={form} handleChange={handleChange} label="版别 *" field="version" />
|
|||
|
|
<Input form={form} handleChange={handleChange} label="面值" field="denomination" />
|
|||
|
|
<Input form={form} handleChange={handleChange} label="状态" field="status" options={statusOptions} />
|
|||
|
|
<Input form={form} handleChange={handleChange} label="包装" field="packaging" options={packagingOptions} />
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* 评级信息 */}
|
|||
|
|
<div style={{ background: 'rgba(255,255,255,0.03)', borderRadius: '12px', padding: '16px', marginBottom: '12px' }}>
|
|||
|
|
<div style={{ color: '#fbbf24', fontSize: '14px', fontWeight: 'bold', marginBottom: '12px' }}>评级信息</div>
|
|||
|
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '12px', alignItems: 'center', marginBottom: '12px' }}>
|
|||
|
|
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|||
|
|
<input type="checkbox" id="isGraded" checked={form.isGraded || false} onChange={(e) => handleChange('isGraded', e.target.checked)}
|
|||
|
|
style={{ width: '18px', height: '18px', cursor: 'pointer', accentColor: '#22c55e' }} />
|
|||
|
|
<label htmlFor="isGraded" style={{ color: '#fff', cursor: 'pointer', fontSize: '13px' }}>是否评级</label>
|
|||
|
|
</div>
|
|||
|
|
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|||
|
|
<input type="checkbox" id="threeStar" checked={form.threeStar || false} onChange={(e) => handleChange('threeStar', e.target.checked)}
|
|||
|
|
style={{ width: '18px', height: '18px', cursor: 'pointer', accentColor: '#22c55e' }} />
|
|||
|
|
<label htmlFor="threeStar" style={{ color: '#fff', cursor: 'pointer', fontSize: '13px' }}>三星</label>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '12px' }}>
|
|||
|
|
<Input form={form} handleChange={handleChange} label="评级公司" field="gradingCompany" />
|
|||
|
|
<Input form={form} handleChange={handleChange} label="评级分数" field="gradingScore" />
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* 特殊信息 */}
|
|||
|
|
<div style={{ background: 'rgba(255,255,255,0.03)', borderRadius: '12px', padding: '16px', marginBottom: '12px' }}>
|
|||
|
|
<div style={{ color: '#fbbf24', fontSize: '14px', fontWeight: 'bold', marginBottom: '12px' }}>特殊信息</div>
|
|||
|
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '12px' }}>
|
|||
|
|
<Input form={form} handleChange={handleChange} label="特殊标识" field="specialMark" />
|
|||
|
|
<Input form={form} handleChange={handleChange} label="号码特征" field="serialFeature" />
|
|||
|
|
<Input form={form} handleChange={handleChange} label="号码分类" field="numberCategory" options={numberCategoryOptions} />
|
|||
|
|
<Input form={form} handleChange={handleChange} label="发行方" field="issuer" />
|
|||
|
|
<Input form={form} handleChange={handleChange} label="发行年份" field="issueYear" />
|
|||
|
|
<Input form={form} handleChange={handleChange} label="材质" field="material" />
|
|||
|
|
<Input form={form} handleChange={handleChange} label="发行量" field="issueQuantity" />
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* 价格信息 */}
|
|||
|
|
<div style={{ background: 'rgba(255,255,255,0.03)', borderRadius: '12px', padding: '16px', marginBottom: '12px' }}>
|
|||
|
|
<div style={{ color: '#fbbf24', fontSize: '14px', fontWeight: 'bold', marginBottom: '12px' }}>价格信息</div>
|
|||
|
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '12px' }}>
|
|||
|
|
<Input form={form} handleChange={handleChange} label="成本价" field="costPrice" type="number" />
|
|||
|
|
<Input form={form} handleChange={handleChange} label="目标价" field="targetPrice" type="number" />
|
|||
|
|
<Input form={form} handleChange={handleChange} label="出售价" field="goalPrice" type="number" />
|
|||
|
|
<Input form={form} handleChange={handleChange} label="修复费" field="repairFee" type="number" />
|
|||
|
|
<Input form={form} handleChange={handleChange} label="评级费" field="gradingFee" type="number" />
|
|||
|
|
<Input form={form} handleChange={handleChange} label="用途" field="purpose" />
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* 备注 */}
|
|||
|
|
<div style={{ background: 'rgba(255,255,255,0.03)', borderRadius: '12px', padding: '16px', marginBottom: '12px' }}>
|
|||
|
|
<div style={{ fontSize: '13px', color: '#94a3b8', marginBottom: '6px' }}>备注</div>
|
|||
|
|
<textarea
|
|||
|
|
value={form.remark || ''}
|
|||
|
|
onChange={(e) => handleChange('remark', e.target.value)}
|
|||
|
|
rows={3}
|
|||
|
|
style={{ background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.1)', color: '#fff', padding: '10px', borderRadius: '8px', width: '100%', resize: 'none' }}
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* 按钮 */}
|
|||
|
|
<button
|
|||
|
|
onClick={saving ? null : handleSave}
|
|||
|
|
disabled={saving}
|
|||
|
|
style={{
|
|||
|
|
width: '100%',
|
|||
|
|
padding: '14px',
|
|||
|
|
background: saving ? '#64748b' : '#fbbf24',
|
|||
|
|
color: saving ? '#94a3b8' : '#1e293b',
|
|||
|
|
border: 'none',
|
|||
|
|
borderRadius: '10px',
|
|||
|
|
fontSize: '16px',
|
|||
|
|
fontWeight: '600',
|
|||
|
|
cursor: saving ? 'not-allowed' : 'pointer',
|
|||
|
|
marginBottom: '12px'
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
{saving ? '更新中...' : '✅ 更新藏品'}
|
|||
|
|
</button>
|
|||
|
|
|
|||
|
|
<button
|
|||
|
|
onClick={() => window.location.hash = '#/list'}
|
|||
|
|
style={{
|
|||
|
|
width: '100%',
|
|||
|
|
padding: '14px',
|
|||
|
|
background: 'rgba(255,255,255,0.05)',
|
|||
|
|
color: '#94a3b8',
|
|||
|
|
border: '1px solid rgba(255,255,255,0.1)',
|
|||
|
|
borderRadius: '10px',
|
|||
|
|
fontSize: '14px',
|
|||
|
|
cursor: 'pointer'
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
🔄 返回列表
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
)
|
|||
|
|
}
|