feat: add reconciliation and quality reporting
This commit is contained in:
@@ -71,8 +71,10 @@ function ClientDrainageModal({ item, onClose, onSaved, signature }: { item?: Cli
|
||||
const [error, setError] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
if (!signature.applicationId) return;
|
||||
clientApi.listApplicationReportFields(signature.applicationId).then(setFields).catch((failure: Error) => setError(failure.message || '引流报备字段加载失败'));
|
||||
const request = signature.applicationId
|
||||
? clientApi.listApplicationReportFields(signature.applicationId, 'drainage')
|
||||
: clientApi.listCommonApplicationReportFields('drainage');
|
||||
request.then(setFields).catch((failure: Error) => setError(failure.message || '引流报备字段加载失败'));
|
||||
}, [signature.applicationId]);
|
||||
|
||||
async function upload(field: ApplicationReportField, file?: File) {
|
||||
@@ -101,7 +103,7 @@ function ClientDrainageModal({ item, onClose, onSaved, signature }: { item?: Cli
|
||||
<Input label="引流信息" onChange={(event) => setSiteName(event.target.value)} required value={siteName} />
|
||||
<Input label="引流地址" onChange={(event) => setUrl(event.target.value)} placeholder="https://" required value={url} />
|
||||
<Textarea label="备注" onChange={(event) => setRemark(event.target.value)} rows={3} value={remark} />
|
||||
<section className="surface" style={{ padding: 16 }}><h3>应用通道引流信息报备资料</h3><div className="signature-form-grid" style={{ marginTop: 12 }}>
|
||||
<section className="surface" style={{ padding: 16 }}><h3>引流信息报备资料(通用 + 通道)</h3><div className="signature-form-grid" style={{ marginTop: 12 }}>
|
||||
{fields.map((field) => field.fieldType === 'string' ? <Input key={field.id} label={`${field.required ? '* ' : ''}${field.name}`} onChange={(event) => setValues((current) => ({ ...current, [field.code]: event.target.value }))} value={String(values[field.code] ?? '')} /> : <label className="signature-upload" key={field.id}><Upload size={28} /><strong>{reportFileRef(values[field.code])?.fileName ?? `${field.required ? '* ' : ''}上传${field.name}`}</strong><small>{uploadingCode === field.code ? '上传中...' : field.fieldType === 'image' ? '请选择图片文件' : '请选择文件'}</small><FileActions file={reportFileRef(values[field.code])} /><input accept={field.fieldType === 'image' ? 'image/*' : undefined} onChange={(event) => void upload(field, event.target.files?.[0])} style={{ display: 'none' }} type="file" /></label>)}
|
||||
</div></section>
|
||||
{error ? <p className="form-error">{error}</p> : null}
|
||||
@@ -119,7 +121,9 @@ export function ClientSignaturesPage() {
|
||||
const [applicationId, setApplicationId] = useState('');
|
||||
const [name, setName] = useState('');
|
||||
const [purpose, setPurpose] = useState('');
|
||||
const [file, setFile] = useState<File | null>(null);
|
||||
const [signatureFields, setSignatureFields] = useState<ApplicationReportField[]>([]);
|
||||
const [signatureValues, setSignatureValues] = useState<Record<string, unknown>>({});
|
||||
const [signatureUploadingCode, setSignatureUploadingCode] = useState('');
|
||||
const [page, setPage] = useState(1);
|
||||
const [drainageModal, setDrainageModal] = useState<{ signature: ClientSmsSignature; item?: ClientDrainageInfo }>();
|
||||
|
||||
@@ -139,6 +143,14 @@ export function ClientSignaturesPage() {
|
||||
loadData();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!modalOpen) return;
|
||||
const request = applicationId
|
||||
? clientApi.listApplicationReportFields(applicationId, 'signature')
|
||||
: clientApi.listCommonApplicationReportFields('signature');
|
||||
request.then(setSignatureFields).catch((reason: Error) => setError(reason.message || '签名报备字段加载失败'));
|
||||
}, [applicationId, modalOpen]);
|
||||
|
||||
const filteredSignatures = useMemo(() => signatures.filter((item) => (
|
||||
!keyword || [item.name, item.purpose, item.applicationId].join(' ').includes(keyword)
|
||||
)), [keyword, signatures]);
|
||||
@@ -153,30 +165,33 @@ export function ClientSignaturesPage() {
|
||||
|
||||
async function createSignature() {
|
||||
try {
|
||||
const signature = await clientApi.createSignature({ applicationId: applicationId || undefined, name, purpose });
|
||||
if (file) {
|
||||
const fileObject = await clientApi.uploadFileObject(file, {
|
||||
purpose: 'signature_material',
|
||||
prefix: `signature-materials/${signature.id}`,
|
||||
});
|
||||
await clientApi.createSignatureMaterial(signature.id, {
|
||||
fileObjectId: fileObject.id,
|
||||
materialType: file.type.startsWith('image/') ? 'image' : 'file',
|
||||
title: file.name,
|
||||
});
|
||||
}
|
||||
const signature = await clientApi.createSignature({ applicationId: applicationId || undefined, name, purpose, drainageInfo: { signatureReportValues: signatureValues } });
|
||||
await clientApi.submitSignature(signature.id);
|
||||
setModalOpen(false);
|
||||
setApplicationId('');
|
||||
setName('');
|
||||
setPurpose('');
|
||||
setFile(null);
|
||||
setSignatureFields([]);
|
||||
setSignatureValues({});
|
||||
loadData();
|
||||
} catch (reason) {
|
||||
setError(reason instanceof Error ? reason.message : '签名提交失败');
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadSignatureField(field: ApplicationReportField, file?: File) {
|
||||
if (!file) return;
|
||||
setSignatureUploadingCode(field.code);
|
||||
try {
|
||||
const uploaded = await clientApi.uploadFileObject(file, { purpose: 'signature_report_material', prefix: 'signature-materials' });
|
||||
setSignatureValues((current) => ({ ...current, [field.code]: { fileObjectId: uploaded.id, fileName: uploaded.fileName, contentType: uploaded.contentType } }));
|
||||
} catch (reason) {
|
||||
setError(reason instanceof Error ? reason.message : '签名报备资料上传失败');
|
||||
} finally {
|
||||
setSignatureUploadingCode('');
|
||||
}
|
||||
}
|
||||
|
||||
function disableSignature(id: string) {
|
||||
clientApi.changeSignatureStatus(id, 'disabled')
|
||||
.then(loadData)
|
||||
@@ -260,7 +275,7 @@ export function ClientSignaturesPage() {
|
||||
footer={(
|
||||
<>
|
||||
<Button onClick={() => setModalOpen(false)} variant="ghost">取消</Button>
|
||||
<Button disabled={!name} onClick={createSignature}>提交审核</Button>
|
||||
<Button disabled={!name || signatureFields.some((field) => field.required && !signatureValues[field.code]) || Boolean(signatureUploadingCode)} onClick={createSignature}>提交审核</Button>
|
||||
</>
|
||||
)}
|
||||
onClose={() => setModalOpen(false)}
|
||||
@@ -277,16 +292,11 @@ export function ClientSignaturesPage() {
|
||||
/>
|
||||
<Input label="短信签名" onChange={(event) => setName(event.target.value)} placeholder="请输入短信签名,如【某某科技】" value={name} />
|
||||
<Input label="用途" onChange={(event) => setPurpose(event.target.value)} placeholder="请输入签名用途" value={purpose} />
|
||||
<label className="signature-upload">
|
||||
<Upload size={36} />
|
||||
<strong>{file ? file.name : '上传资质图片或文件'}</strong>
|
||||
<small>支持图片、PDF、Word 等真实材料文件</small>
|
||||
<input
|
||||
onChange={(event) => setFile(event.target.files?.[0] ?? null)}
|
||||
style={{ display: 'none' }}
|
||||
type="file"
|
||||
/>
|
||||
</label>
|
||||
<section className="surface" style={{ padding: 16 }}><h3>签名报备资料</h3><div className="signature-form-grid" style={{ marginTop: 12 }}>
|
||||
{signatureFields.map((field) => field.fieldType === 'string'
|
||||
? <Input key={field.id} label={`${field.required ? '* ' : ''}${field.name}`} onChange={(event) => setSignatureValues((current) => ({ ...current, [field.code]: event.target.value }))} value={String(signatureValues[field.code] ?? '')} />
|
||||
: <label className="signature-upload" key={field.id}><Upload size={28} /><strong>{reportFileRef(signatureValues[field.code])?.fileName ?? `${field.required ? '* ' : ''}上传${field.name}`}</strong><small>{signatureUploadingCode === field.code ? '上传中...' : field.fieldType === 'image' ? '请选择图片文件' : '请选择文件'}</small><FileActions file={reportFileRef(signatureValues[field.code])} /><input accept={field.fieldType === 'image' ? 'image/*' : undefined} onChange={(event) => void uploadSignatureField(field, event.target.files?.[0])} style={{ display: 'none' }} type="file" /></label>)}
|
||||
</div></section>
|
||||
</div>
|
||||
</Modal>
|
||||
{drainageModal ? <ClientDrainageModal item={drainageModal.item} onClose={() => setDrainageModal(undefined)} onSaved={() => { setDrainageModal(undefined); loadData(); }} signature={drainageModal.signature} /> : null}
|
||||
|
||||
Reference in New Issue
Block a user