diff --git a/src/components/CompanyInfo/component/ContactsInfoFormModal.tsx b/src/components/CompanyInfo/component/ContactsInfoFormModal.tsx new file mode 100644 index 0000000..67b184e --- /dev/null +++ b/src/components/CompanyInfo/component/ContactsInfoFormModal.tsx @@ -0,0 +1,157 @@ +import React, { useEffect, useState } from 'react'; +import { Modal, Form, Input, message, Row, Col, Descriptions } from 'antd'; +import { getDictList } from '@/servers/api/dicts'; +import { coscoSupplierUserView, coscoSupplierUserAdd, coscoSupplierUserEdit } from '../services'; +import { getRegionTree } from '@/servers/api/register'; +import type { DictItem } from '@/servers/api/dicts'; + +// 地区字段转换 +function convertToCascaderOptions(data: any[]): any[] { + return data.map(item => ({ + label: item.name, + value: item.id, + children: item.children && item.children.length > 0 ? convertToCascaderOptions(item.children) : undefined, + })); +} +interface props { + visible: boolean; + onOk: () => void; + onCancel: () => void; + initialValues?: any; + readOnly?: boolean; +} +interface viewDataData { + id?: string | null; + contactsName?: string; + contactsPhone?: string; + contactsEmail?: string; +} +const InvoiceFormModal: React.FC = ({ + visible, + onOk, + onCancel, + initialValues, + readOnly = false, +}) => { + const userId = sessionStorage.getItem('userId') || ''; + // 新增与修改 + const [form] = Form.useForm(); + //查看 + const [viewData, setViewData] = useState({}); + + useEffect(() => { + if (visible) { + if (initialValues) { + coscoSupplierUserView(initialValues.id).then((res) => { + const { code, data } = res; + if (code === 200) { + const fields = { + ...data, + id: data.id ? data.id : null, + address: [ + Number(data.nation), + Number(data.province), + Number(data.city), + ] + }; + console.log(fields); + + form.setFieldsValue(fields); + setViewData(fields); + } + }); + } else { + form.resetFields(); + } + } + }, [visible, initialValues]); + + // 提交 + const handleFinish = async () => { + try { + const values = await form.validateFields(); + const payload = { + ...values, + supplierId: userId, + }; + + if (!values.id) { + coscoSupplierUserAdd(payload).then((res) => { + if (res.code == 200) { + message.success('新增成功'); + onOk(); + } + }) + } else { + coscoSupplierUserEdit(payload).then((res) => { + if (res.code == 200) { + message.success('修改成功'); + onOk(); + } + }) + } + + } catch (error) { + console.error('表单校验失败:', error); + } + }; + + return ( + + {readOnly ? ( + + {viewData.contactsName} + {viewData.contactsPhone} + {viewData.contactsEmail} + + ) : ( +
+ + + + + + + + + + + + + + + + + + + + + +
+ )} +
+ ); +}; + +export default InvoiceFormModal; diff --git a/src/components/CompanyInfo/component/ContactsInfoTab.tsx b/src/components/CompanyInfo/component/ContactsInfoTab.tsx index 8d9ce03..44d809a 100644 --- a/src/components/CompanyInfo/component/ContactsInfoTab.tsx +++ b/src/components/CompanyInfo/component/ContactsInfoTab.tsx @@ -1,64 +1,113 @@ import React, { useEffect, useState } from 'react'; -import { Table } from 'antd'; +import { Table, Button, message, Switch, Popconfirm } from 'antd'; import type { ColumnsType, TablePaginationConfig } from 'antd/es/table'; -import { coscoSupplierBase } from '../services'; +import { getCoscoSupplierUserPage, editType, coscoSupplierUserDel } from '../services'; import { useIntl } from 'umi'; +import ContactsInfoFormModal from './ContactsInfoFormModal'; -// 联系人信息接口 -interface Contact { +interface getCoscoSupplierUser { id: string; - name: string; - department: string; - position: string; - mobile: string; - phone: string; - email: string; - updateTime: string; + attachmentsType?: string; + fileName?: string; + filePath?: string; + fileSize?: string; + fileType?: string; + fileUrl?: string; + supplierId?: string; + certificateUrl?: string; + delFlag: string; + type: string; } + interface Props { viewType?: boolean; record?: string; } -const ContactsInfoTab: React.FC = (props) => { +const OtherAttachmentsTab: React.FC = (props) => { const userId = sessionStorage.getItem('userId') || ''; const { viewType = false, record = userId } = props; + //语言切换 const intl = useIntl(); - const [data, setData] = useState([]); - const [pagination, setPagination] = useState({ - current: 1, - pageSize: 10, - total: 0, - }); + //列表渲染数据 + const [data, setData] = useState([]); + //列表加载 const [loading, setLoading] = useState(false); + //列表分页 + const [pagination, setPagination] = useState({ current: 1, pageSize: 10, total: 0 }); - const fetchContacts = async (page: number = 1, pageSize: number = 10) => { + //列表方法 + const getList = async (pageNo = 1, pageSize = 10) => { + setLoading(true); + try { + const { code, data } = await getCoscoSupplierUserPage({ pageNo, pageSize, supplierId: record }); + if (code === 200) { + setData(data.records); + setPagination({ current: pageNo, pageSize, total: data.total }); + } + } finally { + setLoading(false); + } + }; - coscoSupplierBase(record).then((res) => { - if(res.code == 200) { - setData([res.data.coscoSupplierBase]) + //增改查 + const [formVisible, setFormVisible] = useState(false); + const [editingRecord, setEditingRecord] = useState(null); + const [isViewMode, setIsViewMode] = useState(false); + const handleFormSubmit = () => { + setFormVisible(false); + getList(); + }; + //新增 + const handleAdd = () => { + setEditingRecord(null); + setIsViewMode(false); + setFormVisible(true); + }; + // 修改 + const handleEdit = (record: getCoscoSupplierUser) => { + setEditingRecord(record); + setIsViewMode(false); + setFormVisible(true); + }; + // 查看 + const handleView = (record: getCoscoSupplierUser) => { + setEditingRecord(record); + setIsViewMode(true); + setFormVisible(true); + }; + //删除 + const handleDel = (record: getCoscoSupplierUser) => { + coscoSupplierUserDel(record.id).then((res) => { + if (res.code == 200) { + message.success('删除成功'); + getList(); } }) }; - + //是否为主联系人 + const handleObsoleteChange = async (checked: boolean, id: string) => { + // 调用你的作废接口 + const res = await editType({ id, supplierId: record }); + if (res.code === 200) { + message.success('操作成功'); + getList(pagination.current, pagination.pageSize); // 刷新列表 + } else { + message.error('操作失败'); + } + } + //初始化 useEffect(() => { - if(record) { - fetchContacts(); + if (record) { + getList(); } }, [record]); - const handleTableChange = (pagination: TablePaginationConfig) => { - fetchContacts(pagination.current!, pagination.pageSize!); - }; - const columns: ColumnsType = [ + const columns: ColumnsType = [ { - title: intl.formatMessage({ id: 'page.workbench.contacts.index' }), - dataIndex: 'index', - key: 'index', - width: 80, - align: 'center', - render: (_: any, __: any, index: number) => - (pagination.current! - 1) * pagination.pageSize! + index + 1, + title: intl.formatMessage({ id: 'page.workbench.attachments.index' }), + render: (_: any, __: any, index: number) => index + 1, + width: 60, }, { title: '联系人', @@ -75,22 +124,79 @@ const ContactsInfoTab: React.FC = (props) => { dataIndex: 'contactsEmail', key: 'contactsEmail', }, - ]; + { + title: '是否为主联系人', + dataIndex: 'type', + align: 'center', + width: 180, + render: (value, record: getCoscoSupplierUser) => { + let checkedType = value === '1' ? true : false; + return ( + handleObsoleteChange(checked, record.id)} + /> + ) + + }, + }, + ...(viewType ? [] : [ + { + title: 'page.workbench.attachments.action', + dataIndex: 'option', + width: 140, + render: (_: any, record: getCoscoSupplierUser) => { + + return ( + <> + handleView(record)}>查看 + + handleEdit(record)}>修改 + + {record.type === '0' && ( + handleDel(record)} + > + 删除 + + )} + + ) + } + } + ]) + ]; return (
+
+ {!viewType && ( + + )} +
({ + ...column, + title: intl.formatMessage({ id: column.title as string }) + }))} + dataSource={data} pagination={pagination} - onChange={handleTableChange} - bordered + loading={loading} + onChange={(pagination) => getList(pagination.current!, pagination.pageSize!)} + /> + setFormVisible(false)} + initialValues={editingRecord || undefined} + readOnly={isViewMode} /> ); }; -export default ContactsInfoTab; \ No newline at end of file +export default OtherAttachmentsTab; \ No newline at end of file diff --git a/src/components/CompanyInfo/services.ts b/src/components/CompanyInfo/services.ts index d964088..5812bad 100644 --- a/src/components/CompanyInfo/services.ts +++ b/src/components/CompanyInfo/services.ts @@ -231,8 +231,49 @@ export const updateSupplierBase = (data: updateSupplierBase) => request.post('/c - - +/** +* 联系人分页列表 +*/ +interface getCoscoSupplierUserPage { + pageNo: number; + pageSize: number; + supplierId?: string; +} +export const getCoscoSupplierUserPage = (data: getCoscoSupplierUserPage) => request.post('/coscoSupplierUser/getPage', { data }); +/** +* 附件详情 +*/ +export const coscoSupplierUserView = (id: string) => request.get(`/coscoSupplierUser/${id}`); +/** +* 附件新增 +*/ +interface coscoSupplierUserAdd { + id?: string; + attachmentsType?: string; + fileName?: string; + filePath?: string; + fileSize?: string; + fileType?: string; + fileUrl?: string; + supplierId?: string; + delFlag?: string; + [property: string]: any; +} +export const coscoSupplierUserAdd = (data: coscoSupplierUserAdd) => request.post('/coscoSupplierUser/add', { data }); +/** + * @param data + * @returns + * 附件修改 + */ +export const coscoSupplierUserEdit = (data: coscoSupplierUserAdd) => request.put('/coscoSupplierUser/edit', { data }); + +interface editType { + supplierId:string; + id:string; +} +export const editType = (data: editType) => request.post('/coscoSupplierUser/editType', { data }); + +export const coscoSupplierUserDel = (id: string) => request.delete(`/coscoSupplierUser/${id}`); diff --git a/src/pages/supplier/category/CategoryLibraryManage/components/CategoryAddModal.tsx b/src/pages/supplier/category/CategoryLibraryManage/components/CategoryAddModal.tsx index d07a829..223f42e 100644 --- a/src/pages/supplier/category/CategoryLibraryManage/components/CategoryAddModal.tsx +++ b/src/pages/supplier/category/CategoryLibraryManage/components/CategoryAddModal.tsx @@ -4,7 +4,7 @@ import { UploadOutlined } from '@ant-design/icons'; import { categoryTree, uploadFile, superiorLockList, getSupplierPage, library, libraryData } from '../services'; import type { UploadFile } from 'antd/es/upload/interface'; import AccessDepartmentSelect from '@/components/AccessDepartmentSelect'; -import { getregionInternational } from '@/servers/api/register'; +import { getregionInternational, getAllAreaList } from '@/servers/api/register'; const { Option } = Select; const approveTypeOptions = [ @@ -136,7 +136,7 @@ const CategoryAddModal: React.FC = ({ visible, onCancel, onSuccess }) => form.resetFields(); } init(visible) - getregionInternational().then(res => { + getAllAreaList().then(res => { if (res.code === 200) { setRegionOptions(res.data); } @@ -282,7 +282,7 @@ const CategoryAddModal: React.FC = ({ visible, onCancel, onSuccess }) => @@ -365,7 +365,7 @@ const CategoryAddModal: React.FC = ({ visible, onCancel, onSuccess }) => ); }} - {/* ✅ 外层 Form.Item 正确闭合 */} + diff --git a/src/pages/supplier/category/SupplierEntryManage/components/SupplierAddModal.tsx b/src/pages/supplier/category/SupplierEntryManage/components/SupplierAddModal.tsx index eec8e54..f294c85 100644 --- a/src/pages/supplier/category/SupplierEntryManage/components/SupplierAddModal.tsx +++ b/src/pages/supplier/category/SupplierEntryManage/components/SupplierAddModal.tsx @@ -1,7 +1,18 @@ import React, { useEffect, useState } from 'react'; -import { Modal, Table, Button, Checkbox, Popconfirm, message, Descriptions, Spin } from 'antd'; -import { getSupplierPage, detail, apply } from "../services"; +import { Modal, Table, Button, Checkbox, Form, Select, message, Descriptions, Tooltip, Upload } from 'antd'; import type { ColumnsType } from 'antd/es/table'; +import type { UploadFile } from 'antd/es/upload/interface'; +import { UploadOutlined } from '@ant-design/icons'; +//接口 +import { getSupplierPage, detail, apply, uploadFile } from "../services"; +//统一列表分页 +import tableProps from '@/utils/tableProps' +import { useSupplierDetailModal } from '@/components/SupplierDetailModalContext/SupplierDetailModalContext'; +const approveTypeOptions = [ + { label: '是', value: 'online' }, + { label: '否', value: 'offline' }, +]; + // 供应商类型 interface Supplier { id: string; @@ -31,6 +42,7 @@ const SupplierAddModal: React.FC<{ onCancel: () => void; onSuccess: () => void; }> = ({ visible, storeId, onCancel, onSuccess }) => { + const [form] = Form.useForm(); // 供应商数据 const [suppliers, setSuppliers] = useState([]); // 已勾选的供应商 id @@ -40,6 +52,9 @@ const SupplierAddModal: React.FC<{ // loading const [loading, setLoading] = useState(false); + const supplierDetailModal = useSupplierDetailModal(); + //供应商符合性审查 + const [fileList, setFileList] = useState[]>([]); // 分页 const [pagination, setPagination] = useState({ current: 1, @@ -54,11 +69,11 @@ const SupplierAddModal: React.FC<{ setLoading(false); if (res.code === 200 && res.data) { const inStoreSupplierIds = Array.isArray(inStoreList) - ? inStoreList.map((s: any) => typeof s === 'string' ? s : s.id) - : []; + ? inStoreList.map((s: any) => typeof s === 'string' ? s : s.id) + : []; setSuppliers((res.data.records || []).map((s: any) => ({ ...s, - inStore: inStoreSupplierIds.includes(s.id), + inStore: inStoreSupplierIds.includes(s.id), }))); setPagination(p => ({ ...p, @@ -74,7 +89,7 @@ const SupplierAddModal: React.FC<{ if (!storeId) return; const res = await detail({ id: storeId }); if (res.code === 200 && res.data) setCategoryInfo(res.data); - fetchSuppliers(pagination.current, pagination.pageSize, res.data.suppliers || []); + fetchSuppliers(pagination.current, pagination.pageSize, res.data.suppliers || []); }; useEffect(() => { @@ -99,33 +114,91 @@ const SupplierAddModal: React.FC<{ }; // “移除”操作 - const handleRemove = (id: string) => { - setSuppliers(suppliers.map(s => - s.id === id ? { ...s, inStore: false } : s - )); - message.success('移除成功'); - }; + // const handleRemove = (id: string) => { + // setSuppliers(suppliers.map(s => + // s.id === id ? { ...s, inStore: false } : s + // )); + // message.success('移除成功'); + // }; // 确认入库 - const handleOk = () => { - if(selectedIds.length === 0) { + const handleOk = async () => { + if (selectedIds.length === 0) { message.warning('请选择入库供应商'); return } - apply({ categoryLibraryId: storeId ,supplierIds: selectedIds }) + const values = await form.validateFields(); + if(values.approveType === 'offline') { + if (values.attachments.length === 0) { + message.warning('请上传附件'); + return + } + } else if(!values.approveType) { + message.warning('请选择签报'); + return + } + // + if(values.attachments && values.attachments.length > 0) { + values.coscoCategoryLibrarAttachments = { + ...values.attachments[0].response, + fileUrl: values.attachments[0].response.url, + attachmentsType: 'accessory' + } + } + + apply({ categoryLibraryId: storeId, supplierIds: selectedIds, ...values }) setSelectedIds([]); onSuccess && onSuccess(); }; + // 自定义上传 + const handleCustomRequest = async (options: any) => { + const { file, onSuccess, onError } = options; + try { + // 1. 调用你自己写的上传接口 + const res = await uploadFile(file); + // 2. 可根据后端返回结构,给 fileList 项增加 url 或其他字段 + const uploadedFile: UploadFile = { + ...file, + status: 'done', + url: res?.data?.url || res?.url, // 按后端返回实际字段 + name: res?.data?.name || file.name, + coscoAccessWorkAttachments: res + }; + setFileList([uploadedFile]); + // 同步到 Form + form.setFieldsValue({ supplierCompliance: [uploadedFile] }); + + onSuccess && onSuccess(res, file); + message.success('上传成功'); + } catch (e) { + onError && onError(e); + message.error('上传失败'); + } + }; + // 列表列 const columns: ColumnsType = [ { title: '序号', dataIndex: 'id', align: 'center', width: 60, render: (t: any, r: any, i: number) => (pagination.current - 1) * pagination.pageSize + i + 1 }, - { title: '供应商名称', dataIndex: 'name', align: 'center', ellipsis: true }, - { title: '境内/境外', dataIndex: 'supplierType', align: 'center', - render: (ext: any, record: any) => ({`${record.supplierCategory === 'dvs'? '境内企业':'境外企业'}`}) }, - { title: '统一社会信用代码', dataIndex: 'socialCreditCode', align: 'center', ellipsis: true }, - { title: '企业类型', dataIndex: 'categoryName', align: 'center' , ellipsis: true }, - + { + title: "供应商名称", dataIndex: "name", align: "left", + width: 200, + ellipsis: true, + render: (dom, record) => { + return ( + + supplierDetailModal?.(record.id)}>{record.name || ''} + + ) + } + }, + { + title: '境内/境外', dataIndex: 'supplierType', align: 'center', + render: (ext: any, record: any) => ({`${record.supplierCategory === 'dvs' ? '境内企业' : '境外企业'}`}) + }, + { title: '统一社会信用代码', dataIndex: 'unifiedCode', align: 'center', ellipsis: true }, + { title: '企业类型', dataIndex: 'categoryName', align: 'center', ellipsis: true }, + { title: '操作', align: 'center', @@ -134,14 +207,6 @@ const SupplierAddModal: React.FC<{ return ( <> 已入库 - {/* handleRemove(record.id)} - okText="确认" - cancelText="取消" - > - - */} ); } @@ -180,23 +245,117 @@ const SupplierAddModal: React.FC<{ style={{ marginBottom: 18, background: '#fff', borderRadius: 4 }} labelStyle={{ width: 110, fontWeight: 500 }} > - - {categoryInfo?.name || '-'} - - - {categoryInfo?.termOfValidity || '-'} - - - {categoryInfo?.deptName || '-'} - - - {categoryInfo?.area || '-'} - - - {categoryInfo?.categoryName || '-'} - + + {categoryInfo?.name || '-'} + + + {categoryInfo?.termOfValidity || '-'} + + + {categoryInfo?.deptName || '-'} + + + {categoryInfo?.area || '-'} + + + {categoryInfo?.categoryName || '-'} + + {/* 供应商表格 */} +
+ 选择签报 +
+
{ + if ('approveType' in changedValues) { + form.validateFields(['attachments']); // 手动校验附件 + } + }} + > + +
handleTableChange({ current: page, pageSize }), - }} - style={{ flex: 1, minHeight: 0 }} - scroll={{ y: 'calc(100vh - 650px)' }} - /> - +
{ + handleTableChange({ current: pagination.current!, pageSize: pagination.pageSize! }) + }} + style={{ flex: 1, minHeight: 0 }} + scroll={{ y: 'calc(100vh - 650px)' }} + /> ); }; diff --git a/src/servers/api/register.ts b/src/servers/api/register.ts index 82ff37d..1a1d8ac 100644 --- a/src/servers/api/register.ts +++ b/src/servers/api/register.ts @@ -34,4 +34,10 @@ export async function getregionInternational(){ return request('/api/cosco/dictRegion/regionInternational', { method: 'GET', }) -} \ No newline at end of file +} +export async function getAllAreaList(){ + return request('/api/cosco/dictProject/getAllList/area', { + method: 'GET', + }) +} + diff --git a/src/servers/api/typings.d.ts b/src/servers/api/typings.d.ts index 7eb7e51..289f6aa 100644 --- a/src/servers/api/typings.d.ts +++ b/src/servers/api/typings.d.ts @@ -17,7 +17,8 @@ declare namespace API { label: string; value: string; id: string; - name: string; + name?: string; + dicName?: string; children?: RegionOption[]; }