This commit is contained in:
孙景学
2025-07-21 14:04:20 +08:00
parent 58dd501cb2
commit e9ebd6ac1c
13 changed files with 320 additions and 265 deletions

View File

@ -2,7 +2,7 @@ import { history } from 'umi';
export function onRouteChange({ location }: any) { export function onRouteChange({ location }: any) {
const token = sessionStorage.getItem('token'); const token = sessionStorage.getItem('token');
const whiteList = ['/login', '/forgot', '/403', '/404']; const whiteList = ['/login', '/forgot', '/register/supplier', '/register/expert', '/403', '/404'];
if (!token && !whiteList.includes(location.pathname)) { if (!token && !whiteList.includes(location.pathname)) {
history.replace('/login'); history.replace('/login');
} }

View File

@ -4,7 +4,7 @@ import { treeData } from './services'; // 你的接口
export interface AccessDepartmentSelectProps { export interface AccessDepartmentSelectProps {
value?: string | number; value?: string | number;
onChange?: (value: string | number) => void; onChange?: (value: string | number, label: any, extra: any) => void;
placeholder?: string; placeholder?: string;
disabled?: boolean; disabled?: boolean;
orgCategory?: string; orgCategory?: string;

View File

@ -100,7 +100,7 @@ const SupplierRegister: React.FC<supplierWithInputProps> = (props) => {
fileType: values.attachments.file.response.fileType, fileType: values.attachments.file.response.fileType,
fileSize: values.attachments.file.response.fileSize, fileSize: values.attachments.file.response.fileSize,
filePath: values.attachments.file.response.filePath, filePath: values.attachments.file.response.filePath,
fileUrl: values.attachments.file.response.filePath, fileUrl: values.attachments.file.response.url,
}, },
]; ];
} }

View File

@ -16,6 +16,7 @@ import {
Radio, Radio,
Cascader, Cascader,
Empty, Empty,
Descriptions
} from 'antd'; } from 'antd';
import { UploadOutlined, PlusOutlined, DeleteOutlined } from '@ant-design/icons'; import { UploadOutlined, PlusOutlined, DeleteOutlined } from '@ant-design/icons';
import { message } from 'antd'; import { message } from 'antd';
@ -257,9 +258,8 @@ export const QualificationSection: React.FC<CommonFormSectionsProps> = ({ form }
<FileUpload <FileUpload
listType="text" listType="text"
maxCount={1} maxCount={1}
allowedTypes={['pdf', 'jpg', 'jpeg', 'png']} allowedTypes={['pdf', 'doc', 'docx', 'jpg', 'jpeg', 'png']}
maxSize={10} maxSize={10}
tip="pdf,jpg,jpeg,png类型的文件,大小不超过10MB"
/> />
</Form.Item> </Form.Item>
), ),
@ -379,9 +379,8 @@ export const InvoiceSection: React.FC<CommonFormSectionsProps> = ({ form }) => {
<FileUpload <FileUpload
listType="text" listType="text"
maxCount={1} maxCount={1}
allowedTypes={['pdf', 'jpg', 'jpeg', 'png']} allowedTypes={['pdf', 'doc', 'docx', 'jpg', 'jpeg', 'png']}
maxSize={10} maxSize={10}
tip="pdf,jpg,jpeg,png类型的文件,大小不超过10MB"
/> />
</Form.Item> </Form.Item>
</Col> </Col>
@ -474,40 +473,40 @@ export const BankAccountSection: React.FC<CommonFormSectionsProps> = ({ form, su
const domesticColumns: ColumnType[] = const domesticColumns: ColumnType[] =
supplierType === 'dvs' supplierType === 'dvs'
? [ ? [
{ {
title: '银联号', title: '银联号',
dataIndex: 'interbankNumber', dataIndex: 'interbankNumber',
render: (text, record) => ( render: (text, record) => (
<Form.Item <Form.Item
name={[record.name, 'interbankNumber']} name={[record.name, 'interbankNumber']}
noStyle noStyle
rules={[{ required: true, message: '请输入银联号' }]} rules={[{ required: true, message: '请输入银联号' }]}
> >
<Input placeholder="请输入银联号" /> <Input placeholder="请输入银联号" />
</Form.Item> </Form.Item>
), ),
}, },
] ]
: []; : [];
// 境外企业特有列 // 境外企业特有列
const foreignColumns: ColumnType[] = const foreignColumns: ColumnType[] =
supplierType === 'ovs' supplierType === 'ovs'
? [ ? [
{ {
title: 'SWIFT CODE', title: 'SWIFT CODE',
dataIndex: 'swiftCode', dataIndex: 'swiftCode',
render: (text, record) => ( render: (text, record) => (
<Form.Item <Form.Item
name={[record.name, 'swiftCode']} name={[record.name, 'swiftCode']}
noStyle noStyle
rules={[{ required: true, message: '请输入SWIFT CODE' }]} rules={[{ required: true, message: '请输入SWIFT CODE' }]}
> >
<Input placeholder="请输入SWIFT CODE" /> <Input placeholder="请输入SWIFT CODE" />
</Form.Item> </Form.Item>
), ),
}, },
] ]
: []; : [];
// 通用列 // 通用列
@ -818,19 +817,24 @@ export const AttachmentSection: React.FC<CommonFormSectionsProps> = ({ form }) =
return ( return (
<> <>
<div className="form-section-title">贿</div> <div className="form-section-title">贿</div>
<Row gutter={24}> <Descriptions
<Col span={12}> column={1}
<div className="upload-label"> bordered
size="middle"
<Button labelStyle={{ width: 240 }}
type="link" style={{ background: '#fff' }}
href="/templates/anti-bribery-template.docx" >
download="供应商反商业贿赂承诺书模板.docx" <Descriptions.Item label="请下载模版,按模版填写">
> <Button
type="link"
</Button> href="/templates/anti-bribery-template.docx"
</div> download="供应商反商业贿赂承诺书模板.docx"
>
</Button>
</Descriptions.Item>
<Descriptions.Item label="请加盖公司公章后上传">
<Form.List name="coscoSupplierSurveyAttachments"> <Form.List name="coscoSupplierSurveyAttachments">
{(fields, { add, remove }) => { {(fields, { add, remove }) => {
// 确保至少有一项用于反商业贿赂承诺书 // 确保至少有一项用于反商业贿赂承诺书
@ -863,6 +867,7 @@ export const AttachmentSection: React.FC<CommonFormSectionsProps> = ({ form }) =
<Form.Item <Form.Item
name={[field.name, 'fileUrl']} name={[field.name, 'fileUrl']}
rules={[{ required: true, message: '请上传已盖章的反商业贿赂承诺书' }]} rules={[{ required: true, message: '请上传已盖章的反商业贿赂承诺书' }]}
style={{marginBottom: 0}}
getValueFromEvent={(value) => { getValueFromEvent={(value) => {
if (value && value.length > 0) { if (value && value.length > 0) {
const file = value[0]; const file = value[0];
@ -891,7 +896,6 @@ export const AttachmentSection: React.FC<CommonFormSectionsProps> = ({ form }) =
maxCount={1} maxCount={1}
allowedTypes={['pdf', 'doc', 'docx', 'jpg', 'jpeg', 'png']} allowedTypes={['pdf', 'doc', 'docx', 'jpg', 'jpeg', 'png']}
maxSize={10} maxSize={10}
tip="pdf,doc,docx,jpg,jpeg,png类型的文件,大小不超过10MB"
/> />
</Form.Item> </Form.Item>
</div> </div>
@ -900,16 +904,23 @@ export const AttachmentSection: React.FC<CommonFormSectionsProps> = ({ form }) =
); );
}} }}
</Form.List> </Form.List>
</Col>
</Row> </Descriptions.Item>
</Descriptions>
<div className="form-section-title"></div> <div className="form-section-title"></div>
<Row gutter={24}> <Descriptions
<Col span={24}> column={1}
<Form.List name="coscoSupplierSurveyAttachments"> bordered
size="middle"
labelStyle={{ width: 240 }}
style={{ background: '#fff' }}
>
<Descriptions.Item label="其他附件(非必须上传)">
<Form.List name="coscoSupplierSurveyAttachments">
{(fields, { add, remove }) => ( {(fields, { add, remove }) => (
<> <>
<div className="upload-label"></div>
{fields.map((field, index) => ( {fields.map((field, index) => (
<div <div
key={field.key} key={field.key}
@ -920,22 +931,22 @@ export const AttachmentSection: React.FC<CommonFormSectionsProps> = ({ form }) =
> >
{index > 0 && ( {index > 0 && (
<> <>
<Form.Item <Form.Item
name={[field.name, 'attachmentsType']} name={[field.name, 'attachmentsType']}
initialValue="accessory" initialValue="accessory"
hidden hidden
> >
<Input /> <Input />
</Form.Item> </Form.Item>
<Form.Item name={[field.name, 'fileName']} hidden> <Form.Item name={[field.name, 'fileName']} hidden>
<Input /> <Input />
</Form.Item> </Form.Item>
<Form.Item name={[field.name, 'fileType']} hidden> <Form.Item name={[field.name, 'fileType']} hidden>
<Input /> <Input />
</Form.Item> </Form.Item>
<Form.Item name={[field.name, 'fileSize']} hidden> <Form.Item name={[field.name, 'fileSize']} hidden>
<Input /> <Input />
</Form.Item> </Form.Item>
</> </>
)} )}
@ -987,8 +998,8 @@ export const AttachmentSection: React.FC<CommonFormSectionsProps> = ({ form }) =
</> </>
)} )}
</Form.List> </Form.List>
</Col> </Descriptions.Item>
</Row> </Descriptions>
</> </>
); );
}; };

View File

@ -337,7 +337,7 @@ const ForeignForm: React.FC<ForeignFormProps> = ({
{/* 使用通用表单组件 */} {/* 使用通用表单组件 */}
<QualificationSection form={form} /> <QualificationSection form={form} />
<InvoiceSection form={form} /> {/* <InvoiceSection form={form} /> */}
<BankAccountSection form={form} supplierType={'ovs'} /> <BankAccountSection form={form} supplierType={'ovs'} />
<SurveySection form={form} surveyQuestions={surveyQuestions} /> <SurveySection form={form} surveyQuestions={surveyQuestions} />
<AttachmentSection form={form} /> <AttachmentSection form={form} />

View File

@ -10,7 +10,7 @@ import { categoryTree, add } from '../services';
const CreateModal: React.FC<{ visible: boolean; onCancel: () => void; }> = ({ visible, onCancel }) => { const CreateModal: React.FC<{ visible: boolean; onCancel: () => void; }> = ({ visible, onCancel }) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
//名称输入 //名称输入
const [accessWorkNameEdited, setAccessWorkNameEdited] = useState(false); const [accessWorkNameEdited, setAccessWorkNameEdited] = useState(false);
//品类选择 //品类选择
@ -20,6 +20,8 @@ const CreateModal: React.FC<{ visible: boolean; onCancel: () => void; }> = ({ vi
const [supplierModalVisible, setSupplierModalVisible] = useState(false); const [supplierModalVisible, setSupplierModalVisible] = useState(false);
//品类选择渲染数据 //品类选择渲染数据
const [categoriesTreeData, setCategoriesTreeData] = useState([]); const [categoriesTreeData, setCategoriesTreeData] = useState([]);
//提交防抖
const [submitting, setSubmitting] = useState(false);
//品类选择数据中字段转换 //品类选择数据中字段转换
const convertTreeData = (data: any) => { const convertTreeData = (data: any) => {
return data.map((item: any) => ({ return data.map((item: any) => ({
@ -54,69 +56,69 @@ const CreateModal: React.FC<{ visible: boolean; onCancel: () => void; }> = ({ vi
? checkedKeysValue ? checkedKeysValue
: checkedKeysValue.checked; : checkedKeysValue.checked;
// 只取叶子节点 key // 只取叶子节点 key
const leafKeys = findLeafKeys(convertTreeData(categoriesTreeData)); const leafKeys = findLeafKeys(convertTreeData(categoriesTreeData));
const onlyLeafChecked = keys.filter(key => leafKeys.includes(String(key))); const onlyLeafChecked = keys.filter(key => leafKeys.includes(String(key)));
console.log(onlyLeafChecked,'onlyLeafChecked', leafKeys ,keys); console.log(onlyLeafChecked, 'onlyLeafChecked', leafKeys, keys);
setCheckedKeys(keys); // UI 显示用,还是全量 setCheckedKeys(keys); // UI 显示用,还是全量
form.setFieldsValue({ categoryIds: onlyLeafChecked }); // 只存叶子到表单 form.setFieldsValue({ categoryIds: onlyLeafChecked }); // 只存叶子到表单
// ============================== // ==============================
// 增加自动拼标题的逻辑 // 增加自动拼标题的逻辑
// ============================== // ==============================
if (!accessWorkNameEdited) { if (!accessWorkNameEdited) {
// 1. 获取供应商名 // 1. 获取供应商名
const supplier = (form.getFieldValue('supplier') || [])[0]; const supplier = (form.getFieldValue('supplier') || [])[0];
let supplierName = ''; let supplierName = '';
if (supplier) { if (supplier) {
supplierName = supplier.supplierType === 'ovs' ? supplier.nameEn : supplier.name; supplierName = supplier.supplierType === 'ovs' ? supplier.nameEn : supplier.name;
}
// 2. 获取已选品类名称
const findNamesByIds = (treeData: any[], ids: any[]) => {
let names: string[] = [];
const dfs = (list: any[]) => {
list.forEach(item => {
if (ids.includes(item.id)) {
names.push(item.categoryName);
}
if (item.children) dfs(item.children);
});
} }
dfs(treeData); // 2. 获取已选品类名称
return names; const findNamesByIds = (treeData: any[], ids: any[]) => {
}; let names: string[] = [];
const categoryNames = findNamesByIds(categoriesTreeData, onlyLeafChecked); const dfs = (list: any[]) => {
list.forEach(item => {
if (ids.includes(item.id)) {
names.push(item.categoryName);
}
if (item.children) dfs(item.children);
});
}
dfs(treeData);
return names;
};
const categoryNames = findNamesByIds(categoriesTreeData, onlyLeafChecked);
let autoTitle = supplierName; let autoTitle = supplierName;
if (supplierName && categoryNames.length) { if (supplierName && categoryNames.length) {
if (categoryNames.length === 1) { if (categoryNames.length === 1) {
autoTitle = `${supplierName}-${categoryNames[0]}-品类准入工作`; autoTitle = `${supplierName}-${categoryNames[0]}-品类准入工作`;
} else { } else {
autoTitle = `${supplierName}-${categoryNames[0]}等-品类准入工作`; autoTitle = `${supplierName}-${categoryNames[0]}等-品类准入工作`;
} }
} else if (!supplierName && categoryNames.length) { } else if (!supplierName && categoryNames.length) {
if (categoryNames.length === 1) { if (categoryNames.length === 1) {
autoTitle = categoryNames[0]; autoTitle = categoryNames[0];
} else { } else {
autoTitle = `${categoryNames[0]}等-品类准入工作`; autoTitle = `${categoryNames[0]}等-品类准入工作`;
} }
} }
form.setFieldsValue({ accessWorkName: autoTitle }); form.setFieldsValue({ accessWorkName: autoTitle });
} }
}; };
// 提交 // 提交
const onFinish = async (values: any) => { const onFinish = async (values: any) => {
const finalPayload: { const finalPayload: {
coscoAccessWork: { coscoAccessWork: {
accessWorkName: string; accessWorkName: string;
deptId: string; deptId: string;
}; };
categoryIds: string[]; categoryIds: string[];
supplierIds: string[]; supplierIds: string[];
} = { } = {
coscoAccessWork: { coscoAccessWork: {
accessWorkName: '', accessWorkName: '',
@ -132,25 +134,33 @@ form.setFieldsValue({ accessWorkName: autoTitle });
//品类选择 //品类选择
finalPayload.categoryIds = values.categoryIds; finalPayload.categoryIds = values.categoryIds;
//选择供应商 //选择供应商
if(values.supplier.length != 0) { if (values.supplier.length != 0) {
values.supplier.forEach((item: { id: string }) => { values.supplier.forEach((item: { id: string }) => {
finalPayload.supplierIds.push(item.id) finalPayload.supplierIds.push(item.id)
}) })
} }
console.log( finalPayload, values); console.log(finalPayload, values);
const res = await add(finalPayload); if (submitting) return; // 防重复提交
if (res?.success) { setSubmitting(true);
message.success('创建成功');
form.resetFields(); try {
setCheckedKeys([]); const res = await add(finalPayload);
onCancel(); if (res?.success) {
} else { message.success('创建成功');
message.error('创建失败'); form.resetFields();
setCheckedKeys([]);
onCancel();
} else {
message.error('创建失败');
}
}
finally {
setSubmitting(false); // 无论成功失败都解锁
} }
}; };
//初始化 //初始化
useEffect(() => { useEffect(() => {
if(visible) { if (visible) {
categoryTree().then((res) => { categoryTree().then((res) => {
const { code, data } = res; const { code, data } = res;
if (code == 200) { if (code == 200) {
@ -183,21 +193,21 @@ form.setFieldsValue({ accessWorkName: autoTitle });
name="accessWorkName" name="accessWorkName"
rules={[{ required: true, message: '请输入标题名称' }]} rules={[{ required: true, message: '请输入标题名称' }]}
> >
<Input placeholder="请输入标题名称" allowClear <Input placeholder="请输入标题名称" allowClear
onChange={e => { onChange={e => {
if (e.target.value) { if (e.target.value) {
setAccessWorkNameEdited(true); setAccessWorkNameEdited(true);
} else { } else {
setAccessWorkNameEdited(false); setAccessWorkNameEdited(false);
} }
}}/> }} />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="准入部门" label="准入部门"
name="deptId" name="deptId"
rules={[{ required: true, message: '请选择准入部门' }]} rules={[{ required: true, message: '请选择准入部门' }]}
> >
<AccessDepartmentSelect style={{width: '100%'}} orgCategory='' /> <AccessDepartmentSelect style={{ width: '100%' }} orgCategory='' />
</Form.Item> </Form.Item>
@ -209,7 +219,7 @@ form.setFieldsValue({ accessWorkName: autoTitle });
<Button onClick={() => setSupplierModalVisible(true)}> <Button onClick={() => setSupplierModalVisible(true)}>
</Button> </Button>
<span style={{marginLeft: 10}}>{`${form.getFieldValue('supplier')? form.getFieldValue('supplier')[0].supplierType === 'ovs' ? form.getFieldValue('supplier')[0].nameEn : form.getFieldValue('supplier')[0].name : ''}`}</span> <span style={{ marginLeft: 10 }}>{`${form.getFieldValue('supplier') ? form.getFieldValue('supplier')[0].supplierType === 'ovs' ? form.getFieldValue('supplier')[0].nameEn : form.getFieldValue('supplier')[0].name : ''}`}</span>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
@ -235,7 +245,7 @@ form.setFieldsValue({ accessWorkName: autoTitle });
</Form.Item> </Form.Item>
<Form.Item wrapperCol={{ offset: 6 }}> <Form.Item wrapperCol={{ offset: 6 }}>
<Button type="primary" htmlType="submit" style={{ marginRight: 8 }}> <Button type="primary" htmlType="submit" style={{ marginRight: 8 }} disabled={submitting}>
</Button> </Button>
<Button <Button
@ -257,13 +267,13 @@ form.setFieldsValue({ accessWorkName: autoTitle });
form.setFieldsValue({ supplier: selected }); form.setFieldsValue({ supplier: selected });
setCheckedKeys([]); setCheckedKeys([]);
setSupplierModalVisible(false); setSupplierModalVisible(false);
// 取所有已选供应商的 categoryName 并分割 // 取所有已选供应商的 categoryName 并分割
const allCategories = selected const allCategories = selected
.map(item => item.categoryIds) // 取出字符串 .map(item => item.categoryIds) // 取出字符串
.filter(Boolean) // 防止空 .filter(Boolean) // 防止空
.flatMap(str => str.split(',')) // 逗号切分 .flatMap(str => str.split(',')) // 逗号切分
.map(c => c.trim()) // 去空格 .map(c => c.trim()) // 去空格
.filter(Boolean); .filter(Boolean);
setDisabledCategories(Array.from(new Set(allCategories))); // 去重 setDisabledCategories(Array.from(new Set(allCategories))); // 去重
//名称 //名称
@ -277,7 +287,7 @@ form.setFieldsValue({ accessWorkName: autoTitle });
} }
} }
}} }}
/> />
</Modal> </Modal>
); );
}; };

View File

@ -46,6 +46,8 @@ const CreateModal: React.FC<{ visible: boolean; onCancel: () => void; }> = ({ vi
const [supplierModalVisible, setSupplierModalVisible] = useState(false); const [supplierModalVisible, setSupplierModalVisible] = useState(false);
const [reviewerModalVisible, setReviewerModalVisible] = useState(false); const [reviewerModalVisible, setReviewerModalVisible] = useState(false);
const [divisionModalVisible, setDivisionModalVisible] = useState(false); const [divisionModalVisible, setDivisionModalVisible] = useState(false);
//提交防抖
const [submitting, setSubmitting] = useState(false);
//品类选择渲染数据 //品类选择渲染数据
const [categoriesTreeData, setCategoriesTreeData] = useState([]); const [categoriesTreeData, setCategoriesTreeData] = useState([]);
//品类选择数据中字段转换 //品类选择数据中字段转换
@ -132,92 +134,106 @@ const CreateModal: React.FC<{ visible: boolean; onCancel: () => void; }> = ({ vi
message.error('上传失败'); message.error('上传失败');
} }
}; };
//获取 cuCompanyNumber
const onChangeDepartmentSelect = (value: any, label: any, extra: any) => {
form.setFieldsValue({ orgId: extra?.triggerNode?.props.cuCompanyNumber });
}
// 提交 // 提交
const onFinish = async (values: any) => { const onFinish = async (values: any) => {
const finalPayload: { if (submitting) return; // 防重复提交
coscoAccessWork: { setSubmitting(true);
startTime: string;
endTime: string;
accessType: string;
accessWorkName: string;
deptId: string;
accessDesc: string;
};
categoryIds: string[];
supplierIds: string[];
coscoAccessUserls: { userId: string; deptId: string; isLeader: number }[];
coscoAccessItems: { itemName: string; reviewBy: string[] }[];
coscoAccessWorkAttachments: any;
attachmentsType: any;
} = {
coscoAccessWork: {
startTime: '',
endTime: '',
accessType: '',
accessWorkName: '',
deptId: '',
accessDesc: '',
},
categoryIds: [],
supplierIds: [],
coscoAccessUserls: [],
coscoAccessItems: [],
coscoAccessWorkAttachments: {},
attachmentsType: {},
};
//标题名称 try {
finalPayload.coscoAccessWork.accessWorkName = values.accessWorkName; const finalPayload: {
//准入方式 coscoAccessWork: {
finalPayload.coscoAccessWork.accessType = values.accessType; startTime: string;
//准入部门 endTime: string;
finalPayload.coscoAccessWork.deptId = values.deptId; accessType: string;
// 准入说明 accessWorkName: string;
finalPayload.coscoAccessWork.accessDesc = values.accessDesc; deptId: string;
//品类选择 orgId: string;
finalPayload.categoryIds = values.categoryIds; accessDesc: string;
//选择供应商
values.supplier.forEach((item: { id: string }) => {
finalPayload.supplierIds.push(item.id)
})
if (values.accessType === 'online') {
// 评审时间
if (values.rangePicker && values.rangePicker.length === 2) {
const [start, end] = values.rangePicker;
finalPayload.coscoAccessWork.startTime = start.format('YYYY-MM-DD HH:mm');
finalPayload.coscoAccessWork.endTime = end.format('YYYY-MM-DD HH:mm');
}
//选择评审人员
finalPayload.coscoAccessUserls = values.reviewers.selected.map((item: { userId: string, deptId: string, isLeader: number }) => {
return { userId: item.userId, deptId: item.deptId, isLeader: item.isLeader }
});
//评审分工
values.division.forEach((item: any) => {
const dataJson = {
itemName: item.itemName,
reviewBy: [] as string[],
}; };
Object.entries(item.reviewerChecks || {}).forEach(([key, value]) => { categoryIds: string[];
dataJson.reviewBy.push(key); supplierIds: string[];
coscoAccessUserls: { userId: string; deptId: string; isLeader: number }[];
coscoAccessItems: { itemName: string; reviewBy: string[] }[];
coscoAccessWorkAttachments: any;
attachmentsType: any;
} = {
coscoAccessWork: {
startTime: '',
endTime: '',
accessType: '',
accessWorkName: '',
deptId: '',
orgId: '',
accessDesc: '',
},
categoryIds: [],
supplierIds: [],
coscoAccessUserls: [],
coscoAccessItems: [],
coscoAccessWorkAttachments: {},
attachmentsType: {},
};
//标题名称
finalPayload.coscoAccessWork.accessWorkName = values.accessWorkName;
//准入方式
finalPayload.coscoAccessWork.accessType = values.accessType;
//准入部门
finalPayload.coscoAccessWork.deptId = values.deptId;
//准入单位
finalPayload.coscoAccessWork.orgId = values.orgId;
// 准入说明
finalPayload.coscoAccessWork.accessDesc = values.accessDesc;
//品类选择
finalPayload.categoryIds = values.categoryIds;
//选择供应商
values.supplier.forEach((item: { id: string }) => {
finalPayload.supplierIds.push(item.id)
})
if (values.accessType === 'online') {
// 评审时间
if (values.rangePicker && values.rangePicker.length === 2) {
const [start, end] = values.rangePicker;
finalPayload.coscoAccessWork.startTime = start.format('YYYY-MM-DD HH:mm');
finalPayload.coscoAccessWork.endTime = end.format('YYYY-MM-DD HH:mm');
}
//选择评审人员
finalPayload.coscoAccessUserls = values.reviewers.selected.map((item: { userId: string, deptId: string, isLeader: number }) => {
return { userId: item.userId, deptId: item.deptId, isLeader: item.isLeader }
}); });
finalPayload.coscoAccessItems.push(dataJson); //评审分工
}); values.division.forEach((item: any) => {
} else { const dataJson = {
// 供应商符合性审查 itemName: item.itemName,
finalPayload.coscoAccessWorkAttachments = values.supplierCompliance[0].response; reviewBy: [] as string[],
finalPayload.coscoAccessWorkAttachments.fileUrl = values.supplierCompliance[0].response.url; };
} Object.entries(item.reviewerChecks || {}).forEach(([key, value]) => {
dataJson.reviewBy.push(key);
const res = await add(finalPayload); });
if (res?.success) { finalPayload.coscoAccessItems.push(dataJson);
message.success('创建成功'); });
form.resetFields(); } else {
setCheckedKeys([]); // 供应商符合性审查
setSelectedReviewers({ selected: [], leader: null, }); finalPayload.coscoAccessWorkAttachments = values.supplierCompliance[0].response;
setAdmissionMethod('online'); finalPayload.coscoAccessWorkAttachments.fileUrl = values.supplierCompliance[0].response.url;
onCancel(); }
} else { const res = await add(finalPayload);
message.error('创建失败'); if (res?.success) {
message.success('创建成功');
form.resetFields();
setCheckedKeys([]);
setSelectedReviewers({ selected: [], leader: null, });
setAdmissionMethod('online');
onCancel();
} else {
message.error('创建失败');
}
} finally {
setSubmitting(false); // 无论成功失败都解锁
} }
}; };
//初始化 //初始化
@ -273,7 +289,10 @@ const CreateModal: React.FC<{ visible: boolean; onCancel: () => void; }> = ({ vi
name="deptId" name="deptId"
rules={[{ required: true, message: '请选择准入部门' }]} rules={[{ required: true, message: '请选择准入部门' }]}
> >
<AccessDepartmentSelect style={{width: '100%'}} orgCategory='' /> <AccessDepartmentSelect style={{width: '100%'}} orgCategory='' onChange={onChangeDepartmentSelect} />
</Form.Item>
<Form.Item name="orgId" noStyle>
<Input type="hidden" />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
@ -474,7 +493,7 @@ const CreateModal: React.FC<{ visible: boolean; onCancel: () => void; }> = ({ vi
)} )}
<Form.Item wrapperCol={{ offset: 6 }}> <Form.Item wrapperCol={{ offset: 6 }}>
<Button type="primary" htmlType="submit" style={{ marginRight: 8 }}> <Button type="primary" htmlType="submit" style={{ marginRight: 8 }} disabled={submitting}>
{admissionMethod === 'online' ? '确认' : admissionMethod === 'offline' ? '提交审批' : '提交'} {admissionMethod === 'online' ? '确认' : admissionMethod === 'offline' ? '提交审批' : '提交'}
</Button> </Button>

View File

@ -51,7 +51,8 @@ const SupplierAddModal: React.FC<{
const [categoryInfo, setCategoryInfo] = useState<CategoryInfo>({}); const [categoryInfo, setCategoryInfo] = useState<CategoryInfo>({});
// loading // loading
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
//提交防抖
const [submitting, setSubmitting] = useState(false);
const supplierDetailModal = useSupplierDetailModal(); const supplierDetailModal = useSupplierDetailModal();
//供应商符合性审查 //供应商符合性审查
const [fileList, setFileList] = useState<UploadFile<any>[]>([]); const [fileList, setFileList] = useState<UploadFile<any>[]>([]);
@ -145,15 +146,19 @@ const SupplierAddModal: React.FC<{
attachmentsType: 'accessory' attachmentsType: 'accessory'
} }
} }
if (submitting) return; // 防重复提交
apply({ categoryLibraryId: storeId, supplierIds: selectedIds, ...values }).then((res) => { setSubmitting(true);
if(res.code == 200) { try {
message.success('操作成功'); apply({ categoryLibraryId: storeId, supplierIds: selectedIds, ...values }).then((res) => {
setSelectedIds([]); if(res.code == 200) {
onSuccess && onSuccess(); message.success('操作成功');
} setSelectedIds([]);
}) onSuccess && onSuccess();
}
})
} finally {
setSubmitting(false); // 无论成功失败都解锁
}
}; };
// 自定义上传 // 自定义上传
@ -233,7 +238,7 @@ const SupplierAddModal: React.FC<{
visible={visible} visible={visible}
onCancel={onCancel} onCancel={onCancel}
footer={[ footer={[
<Button key="ok" type="primary" onClick={handleOk}></Button>, <Button key="ok" type="primary" onClick={handleOk} disabled={submitting}></Button>,
<Button key="cancel" onClick={onCancel}></Button>, <Button key="cancel" onClick={onCancel}></Button>,
]} ]}
width={820} width={820}

View File

@ -60,6 +60,8 @@ const CategoryAddModal: React.FC<Props> = ({ visible, onCancel, onSuccess }) =>
const [expandedKeys, setExpandedKeys] = useState<string[]>([]); const [expandedKeys, setExpandedKeys] = useState<string[]>([]);
//供应商符合性审查 //供应商符合性审查
const [fileList, setFileList] = useState<UploadFile<any>[]>([]); const [fileList, setFileList] = useState<UploadFile<any>[]>([]);
//提交防抖
const [submitting, setSubmitting] = useState(false);
const [deptOptions, setDeptOptions] = useState<DeptOption[]>([]); const [deptOptions, setDeptOptions] = useState<DeptOption[]>([]);
// 自定义上传 // 自定义上传
@ -142,6 +144,8 @@ const CategoryAddModal: React.FC<Props> = ({ visible, onCancel, onSuccess }) =>
// 提交校验 // 提交校验
const handleOk = async () => { const handleOk = async () => {
if (submitting) return; // 防重复提交
setSubmitting(true);
try { try {
const values = await form.validateFields(); const values = await form.validateFields();
const submitData = { const submitData = {
@ -172,7 +176,9 @@ const CategoryAddModal: React.FC<Props> = ({ visible, onCancel, onSuccess }) =>
onSuccess && onSuccess(); onSuccess && onSuccess();
} }
}) })
} catch { } } finally {
setSubmitting(false); // 无论成功失败都解锁
}
}; };
return ( return (
<Modal <Modal
@ -339,7 +345,7 @@ const CategoryAddModal: React.FC<Props> = ({ visible, onCancel, onSuccess }) =>
<Form.Item wrapperCol={{ span: 24 }} style={{ textAlign: 'center', marginTop: 30 }}> <Form.Item wrapperCol={{ span: 24 }} style={{ textAlign: 'center', marginTop: 30 }}>
<Button type="primary" style={{ width: 160 }} onClick={handleOk}> <Button type="primary" style={{ width: 160 }} onClick={handleOk} disabled={submitting}>
</Button> </Button>
<Button style={{ width: 120, marginLeft: 32 }} onClick={onCancel}> <Button style={{ width: 120, marginLeft: 32 }} onClick={onCancel}>

View File

@ -197,6 +197,7 @@ const SupplierRegisterAgent: React.FC = () => {
visible={exitModalVisible} visible={exitModalVisible}
exitId={exitId} exitId={exitId}
onOk={() => { onOk={() => {
fetchData(1, pagination.pageSize);
setExitModalVisible(false) setExitModalVisible(false)
}} }}
/> />

View File

@ -38,7 +38,8 @@ const CreateBlacklistModal: React.FC<CreateBlacklistModalProps> = ({
const [suppliers, setSuppliers] = useState<Supplier[]>([]); const [suppliers, setSuppliers] = useState<Supplier[]>([]);
const [timelimitOption, setTimelimitOption] = useState<any[]>([]); const [timelimitOption, setTimelimitOption] = useState<any[]>([]);
const supplierDetailModal = useSupplierDetailModal(); const supplierDetailModal = useSupplierDetailModal();
//提交防抖
const [submitting, setSubmitting] = useState(false);
const removeSupplier = (id: string) => { const removeSupplier = (id: string) => {
setSuppliers(suppliers.filter((s) => s.id !== id)); setSuppliers(suppliers.filter((s) => s.id !== id));
}; };
@ -49,6 +50,8 @@ const CreateBlacklistModal: React.FC<CreateBlacklistModalProps> = ({
}; };
const handleSubmit = async () => { const handleSubmit = async () => {
if (submitting) return; // 防重复提交
setSubmitting(true);
try { try {
const values = await form.validateFields(); const values = await form.validateFields();
if (suppliers.length === 0) { if (suppliers.length === 0) {
@ -75,6 +78,8 @@ const CreateBlacklistModal: React.FC<CreateBlacklistModalProps> = ({
} }
} catch (err) { } catch (err) {
// 校验失败 // 校验失败
} finally {
setSubmitting(false); // 无论成功失败都解锁
} }
}; };
useEffect(() => { useEffect(() => {
@ -114,7 +119,7 @@ const CreateBlacklistModal: React.FC<CreateBlacklistModalProps> = ({
return ( return (
<> <>
<Modal <Modal
title="供应商退出" title="供应商黑名单"
visible={visible} visible={visible}
onCancel={onCancel} onCancel={onCancel}
width={900} width={900}
@ -143,19 +148,7 @@ const CreateBlacklistModal: React.FC<CreateBlacklistModalProps> = ({
wrapperCol={{ flex: 1 }} // 输入框区域自适应剩余空间 wrapperCol={{ flex: 1 }} // 输入框区域自适应剩余空间
layout="horizontal" layout="horizontal"
> >
{/* <Form.Item
label="黑名单类型"
name="backlistType"
rules={[{ required: true, message: '请选择黑名单类型' }]}
>
<Select placeholder="请选择黑名单类型">
{DEPT_OPTIONS.map((opt) => (
<Option key={opt.value} value={opt.value}>{opt.label}</Option>
))}
</Select>
</Form.Item> */}
<Form.Item <Form.Item
label="时限类型" label="时限类型"
name="timelimitType" name="timelimitType"
@ -181,7 +174,7 @@ const CreateBlacklistModal: React.FC<CreateBlacklistModalProps> = ({
</div> </div>
<div style={{ marginTop: 28, textAlign: "center" }}> <div style={{ marginTop: 28, textAlign: "center" }}>
<Button type="primary" style={{ marginRight: 24 }} onClick={handleSubmit}></Button> <Button type="primary" style={{ marginRight: 24 }} onClick={handleSubmit} disabled={submitting}></Button>
<Button onClick={onCancel}></Button> <Button onClick={onCancel}></Button>
</div> </div>
</Modal> </Modal>

View File

@ -35,7 +35,8 @@ const CreateBlacklistModal: React.FC<CreateBlacklistModalProps> = ({
const [selectVisible, setSelectVisible] = useState(false); const [selectVisible, setSelectVisible] = useState(false);
const [suppliers, setSuppliers] = useState<Supplier[]>([]); const [suppliers, setSuppliers] = useState<Supplier[]>([]);
const [form] = Form.useForm(); const [form] = Form.useForm();
//提交防抖
const [submitting, setSubmitting] = useState(false);
const removeSupplier = (id: number) => { const removeSupplier = (id: number) => {
setSuppliers(suppliers.filter((s) => s.id !== id)); setSuppliers(suppliers.filter((s) => s.id !== id));
}; };
@ -46,6 +47,8 @@ const CreateBlacklistModal: React.FC<CreateBlacklistModalProps> = ({
}; };
const handleSubmit = async () => { const handleSubmit = async () => {
if (submitting) return; // 防重复提交
setSubmitting(true);
try { try {
const values = await form.validateFields(); const values = await form.validateFields();
if (suppliers.length === 0) { if (suppliers.length === 0) {
@ -76,6 +79,8 @@ const CreateBlacklistModal: React.FC<CreateBlacklistModalProps> = ({
} }
} catch (err) { } catch (err) {
// 校验失败 // 校验失败
} finally {
setSubmitting(false); // 无论成功失败都解锁
} }
}; };
useEffect(() => { useEffect(() => {
@ -162,7 +167,7 @@ const CreateBlacklistModal: React.FC<CreateBlacklistModalProps> = ({
</div> </div>
<div style={{ marginTop: 28, textAlign: "center" }}> <div style={{ marginTop: 28, textAlign: "center" }}>
<Button type="primary" style={{ marginRight: 24 }} onClick={handleSubmit}></Button> <Button type="primary" style={{ marginRight: 24 }} onClick={handleSubmit} disabled={submitting}></Button>
<Button onClick={onCancel}></Button> <Button onClick={onCancel}></Button>
</div> </div>
</Modal> </Modal>

View File

@ -39,7 +39,8 @@ const CreateBlacklistModal: React.FC<CreateBlacklistModalProps> = ({
const [userDeptId, setUserDeptId] = useState(''); const [userDeptId, setUserDeptId] = useState('');
const currentUserStr = sessionStorage.getItem('currentUser'); const currentUserStr = sessionStorage.getItem('currentUser');
const currentUser = currentUserStr ? JSON.parse(currentUserStr) : null; const currentUser = currentUserStr ? JSON.parse(currentUserStr) : null;
//提交防抖
const [submitting, setSubmitting] = useState(false);
//移除已选供应商 //移除已选供应商
const removeSupplier = (id: number) => { const removeSupplier = (id: number) => {
setSuppliers(suppliers.filter((s) => s.id !== id)); setSuppliers(suppliers.filter((s) => s.id !== id));
@ -51,6 +52,8 @@ const CreateBlacklistModal: React.FC<CreateBlacklistModalProps> = ({
}; };
//提交 //提交
const handleSubmit = async () => { const handleSubmit = async () => {
if (submitting) return; // 防重复提交
setSubmitting(true);
try { try {
const values = await form.validateFields(); const values = await form.validateFields();
if (suppliers.length === 0) { if (suppliers.length === 0) {
@ -80,6 +83,8 @@ const CreateBlacklistModal: React.FC<CreateBlacklistModalProps> = ({
message.error("提交失败"); message.error("提交失败");
} }
} catch (err) { } catch (err) {
} finally {
setSubmitting(false); // 无论成功失败都解锁
} }
}; };
useEffect(() => { useEffect(() => {
@ -165,7 +170,7 @@ const CreateBlacklistModal: React.FC<CreateBlacklistModalProps> = ({
</div> </div>
<div style={{ marginTop: 28, textAlign: "center" }}> <div style={{ marginTop: 28, textAlign: "center" }}>
<Button type="primary" style={{ marginRight: 24 }} onClick={handleSubmit}></Button> <Button type="primary" style={{ marginRight: 24 }} onClick={handleSubmit} disabled={submitting}></Button>
<Button onClick={onCancel}></Button> <Button onClick={onCancel}></Button>
</div> </div>
</Modal> </Modal>