菜单,合同前端提交
This commit is contained in:
359
src/pages/Contract/ContractList.tsx
Normal file
359
src/pages/Contract/ContractList.tsx
Normal file
@ -0,0 +1,359 @@
|
||||
import React, {useState, useRef, useCallback} from 'react';
|
||||
import { history } from 'umi';
|
||||
import {Input, Button, Modal, Form, Select, message, DatePicker} from 'antd';
|
||||
import { SearchOutlined , UndoOutlined} from '@ant-design/icons';
|
||||
import ProTable, {ActionType, ProColumns} from '@ant-design/pro-table';
|
||||
import {saveDateTimeFormatter} from "@/utils/DateUtils";
|
||||
import { fetchContracts, deleteContract,updateContract, getContract } from "@/pages/Contract/ContractService";
|
||||
import moment from "moment";
|
||||
const { Option } = Select;
|
||||
|
||||
interface Contract {
|
||||
contractType: string;
|
||||
contractCode: string;
|
||||
contractName: string;
|
||||
supplierName: string;
|
||||
contractAmount: number;
|
||||
supplierCreditCode: string;
|
||||
status: string;
|
||||
createTime: string;
|
||||
}
|
||||
|
||||
const contractTypeList = [
|
||||
{
|
||||
label: '我已执行合同,录入阳光购系统',
|
||||
value: '0'
|
||||
},
|
||||
{
|
||||
label: '我要与供应商进行在线合同磋商',
|
||||
value: '1'
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
const ContractList: React.FC = () => {
|
||||
const [form] = Form.useForm();
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
const [searchParams, setSearchParams] = useState({
|
||||
contractCode: '',
|
||||
contractName: '',
|
||||
supplierName: '',
|
||||
projectName: '',
|
||||
biddingName: '',
|
||||
createDate: undefined
|
||||
});
|
||||
const actionRef = useRef<ActionType>();
|
||||
const handleEdit = useCallback((selectedRecord: any, opt: string) => {
|
||||
getContract(selectedRecord.id).then((res) => {
|
||||
history.push({
|
||||
pathname: '/stepOne',
|
||||
state: {
|
||||
contractInfo: res.data,
|
||||
opt: opt
|
||||
}
|
||||
});
|
||||
});
|
||||
},[]);
|
||||
|
||||
// 选择合同类型
|
||||
const handleChoose = () => {
|
||||
// 重置表单到初始值
|
||||
form.resetFields();
|
||||
setIsModalVisible(true);
|
||||
};
|
||||
|
||||
const createContract = async () => {
|
||||
// 验证表单并获取值
|
||||
const values = await form.validateFields();
|
||||
//路由跳转
|
||||
history.push({
|
||||
pathname: '/stepOne',
|
||||
state: {
|
||||
contractType: values.contractType
|
||||
}
|
||||
});
|
||||
// 关闭模态框
|
||||
setIsModalVisible(false);
|
||||
};
|
||||
|
||||
// 处理搜索
|
||||
const handleSearch = useCallback(() => {
|
||||
if (searchParams.createDate) {
|
||||
searchParams.createDate = saveDateTimeFormatter(moment(searchParams.createDate))
|
||||
setSearchParams({
|
||||
...searchParams
|
||||
})
|
||||
}
|
||||
actionRef.current?.reload()
|
||||
}, []);
|
||||
|
||||
const goPerformance = useCallback((selectedRecord: any) => {
|
||||
getContract(selectedRecord.id).then((res) => {
|
||||
if(res?.code === 200){
|
||||
history.push({
|
||||
pathname: '/performance',
|
||||
state: {
|
||||
contractInfo: res.data,
|
||||
opt: 'edit'
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},[])
|
||||
|
||||
const handleUpdate = useCallback((optRecord: any) => {
|
||||
updateContract(optRecord).then((r: any) => {
|
||||
if (r?.code == 200) {
|
||||
message.success('操作成功');
|
||||
} else {
|
||||
message.error('操作失败');
|
||||
}
|
||||
}).finally(() => actionRef.current?.reload());
|
||||
},[])
|
||||
|
||||
const handleOperation = useCallback((optRecord: any, status: string) => {
|
||||
optRecord.status = status;
|
||||
const operation = status == '2' ? '中止' : status == '3' ? '终止' : '';
|
||||
Modal.confirm({
|
||||
title: '确认' + operation + '该合同?',
|
||||
onOk: async () => {
|
||||
await handleUpdate(optRecord);
|
||||
}
|
||||
})
|
||||
},[])
|
||||
|
||||
const handleDelete = useCallback((id: string) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除该合同?',
|
||||
onOk: async () => {
|
||||
await deleteContract(id).then((r: any) => {
|
||||
if (r?.code == 200) {
|
||||
message.success('删除成功');
|
||||
} else {
|
||||
message.error('删除失败');
|
||||
}
|
||||
})
|
||||
.finally(() => actionRef.current?.reload());
|
||||
},
|
||||
});
|
||||
},[])
|
||||
|
||||
// 处理重置
|
||||
const handleReset = () => {
|
||||
setSearchParams({
|
||||
contractCode: '',
|
||||
contractName: '',
|
||||
supplierName: '',
|
||||
projectName: '',
|
||||
biddingName: '',
|
||||
createDate: undefined
|
||||
});
|
||||
actionRef.current?.reload();
|
||||
};
|
||||
|
||||
// 定义ProTable的列配置
|
||||
const columns: ProColumns<Contract>[] = [
|
||||
{
|
||||
title: '合同/协议编号',
|
||||
dataIndex: 'contractCode',
|
||||
key: 'contractCode',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '合同/协议名称',
|
||||
dataIndex: 'contractName',
|
||||
key: 'contractName',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: '供应商名称',
|
||||
dataIndex: 'supplierName',
|
||||
key: 'supplierName',
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: '合同金额',
|
||||
dataIndex: 'amount',
|
||||
key: 'amount',
|
||||
width: 120,
|
||||
render: (text: any) => `${text}`,
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createDate',
|
||||
key: 'createDate',
|
||||
width: 160,
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
width: 120,
|
||||
render: (_: any, rec: Contract) => {
|
||||
const status = rec.status;//合同状态
|
||||
if (status === '0') {
|
||||
return (<>合同草稿已创建</>)
|
||||
}else if (status === '1') {
|
||||
return (<>合同执行中</>)
|
||||
}else if (status === '2') {
|
||||
return (<>合同中止</>)
|
||||
}else if (status === '3') {
|
||||
return (<>合同终止</>)
|
||||
}else if (status === '4') {
|
||||
return (<>合同结束</>)
|
||||
} else {
|
||||
return (<></>)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'operation',
|
||||
width: 250,
|
||||
valueType: 'option',
|
||||
render: (text: any, optRecord: any) => (
|
||||
<>
|
||||
{optRecord.status === '0' && (<Button type="link" danger onClick={() => handleDelete(optRecord.id)}>删除</Button>)}
|
||||
{(optRecord.status === '0'|| optRecord.status === '2' )&& (<Button type="link" danger onClick={() => handleEdit(optRecord, 'edit')}>编辑</Button>)}
|
||||
{optRecord.status === '1' && (<Button type="link" danger onClick={() => goPerformance(optRecord)}>履约信息补充</Button>)}
|
||||
{optRecord.status === '1' && (<Button type="link" danger onClick={() => handleOperation(optRecord, '2')}>中止</Button>)}
|
||||
{optRecord.status === '1' && (<Button type="link" danger onClick={() => handleOperation(optRecord, '3')}>终止</Button>)}
|
||||
{(<Button type="link" onClick={() => handleEdit(optRecord, 'detail')}>查看</Button>)}
|
||||
</>
|
||||
)
|
||||
},
|
||||
];
|
||||
|
||||
// 定义ProTable的请求函数
|
||||
const request = async (params: any, sorter: any) => {
|
||||
try {
|
||||
// 构建请求参数,合并搜索参数
|
||||
const requestParams = {
|
||||
...params,
|
||||
...searchParams,
|
||||
basePageRequest: {
|
||||
pageNo: params.current || 1,
|
||||
pageSize: params.pageSize || 10
|
||||
},
|
||||
};
|
||||
const result = await fetchContracts(requestParams);
|
||||
// 转换数据格式以适应ProTable的要求
|
||||
return {
|
||||
data: result.data.records,
|
||||
total: result.data.total,
|
||||
success: true,
|
||||
};
|
||||
} catch (error) {
|
||||
message.error('获取合同列表失败');
|
||||
return {
|
||||
data: [],
|
||||
total: 0,
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: '3px' }}>
|
||||
<Modal
|
||||
centered
|
||||
title={'请选择类型'}
|
||||
visible={isModalVisible}
|
||||
onCancel={() => setIsModalVisible(false)}
|
||||
onOk={createContract}
|
||||
okText="确定"
|
||||
>
|
||||
<Form
|
||||
form={form}
|
||||
initialValues={{
|
||||
contractType: '0'
|
||||
}}
|
||||
>
|
||||
<Form.Item
|
||||
name="contractType"
|
||||
label="合同类型"
|
||||
rules={[{ required: true, message: '请选择合同类型' }]}
|
||||
>
|
||||
<Select placeholder="请选择">
|
||||
{contractTypeList.map(({ label, value }) => (
|
||||
<Option key={value} value={value}>
|
||||
{label}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
{/* 标题部分 */}
|
||||
<div style={{ borderLeft: '4px solid #0066cc', paddingLeft: 8, marginBottom: 16 }}>
|
||||
<span style={{ fontSize: 16, fontWeight: 'bold' }}>合同管理</span>
|
||||
</div>
|
||||
|
||||
{/* 第一行搜索框 */}
|
||||
<div style={{ marginBottom: 16, display: 'flex', alignItems: 'center' }}>
|
||||
<Input
|
||||
placeholder="搜索合同编号"
|
||||
value={searchParams.contractCode}
|
||||
onChange={(e) => setSearchParams({...searchParams, contractCode: e.target.value})}
|
||||
style={{ width: 200, marginRight: 16 }}
|
||||
/>
|
||||
<Input
|
||||
placeholder="搜索合同名称关键词"
|
||||
value={searchParams.contractName}
|
||||
onChange={(e) => setSearchParams({...searchParams, contractName: e.target.value})}
|
||||
style={{ width: 200, marginRight: 16 }}
|
||||
/>
|
||||
<Input
|
||||
placeholder="搜索供应商关键词"
|
||||
value={searchParams.supplierName}
|
||||
onChange={(e) => setSearchParams({...searchParams, supplierName: e.target.value})}
|
||||
style={{ width: 200, marginRight: 16 }}
|
||||
/>
|
||||
<div style={{ marginLeft: 'auto' }}>
|
||||
<Button type="primary" onClick={handleSearch} icon={<SearchOutlined />}>查询</Button>
|
||||
<Button type="text" onClick={handleReset} icon={<UndoOutlined/> } style={{ marginLeft: 8, border: '1px solid #d9d9d9', borderRadius: 2 }}>重置</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 第二行搜索框 */}
|
||||
<div style={{ marginBottom: 16, display: 'flex', alignItems: 'center' }}>
|
||||
<Input
|
||||
placeholder="搜索项目名称关键词"
|
||||
value={searchParams.projectName}
|
||||
onChange={(e) => setSearchParams({...searchParams, projectName: e.target.value})}
|
||||
style={{ width: 200, marginRight: 16 }}
|
||||
/>
|
||||
<Input
|
||||
placeholder="搜索标段名称关键词"
|
||||
value={searchParams.biddingName}
|
||||
onChange={(e) => setSearchParams({...searchParams, biddingName: e.target.value})}
|
||||
style={{ width: 200, marginRight: 16 }}
|
||||
/>
|
||||
<DatePicker placeholder="请选择创建时间" inputReadOnly={true} onChange={ (date, dateString) => {
|
||||
// @ts-ignore
|
||||
setSearchParams({...searchParams, createDate: date})}
|
||||
} style={{ width: 200, marginRight: 16 }}/>
|
||||
<Button type="primary" style={{ marginLeft: 'auto', width: 170 }} onClick={handleChoose}>新建合同</Button>
|
||||
</div>
|
||||
|
||||
{/* 使用ProTable替代Table */}
|
||||
<ProTable<Contract>
|
||||
actionRef={actionRef}//action触发后更新表格
|
||||
columns={columns}
|
||||
request={request}
|
||||
rowKey="contractCode"
|
||||
pagination={{
|
||||
pageSize: 10,
|
||||
showSizeChanger: true,
|
||||
pageSizeOptions: ['10', '20', '50', '100'],
|
||||
}}
|
||||
// 移除操作按钮
|
||||
options={false}
|
||||
search={false}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContractList;
|
146
src/pages/Contract/ContractService.ts
Normal file
146
src/pages/Contract/ContractService.ts
Normal file
@ -0,0 +1,146 @@
|
||||
import request from "@/utils/request";
|
||||
|
||||
// 字典项类型定义
|
||||
export interface CoscoContract {
|
||||
// 基本信息
|
||||
id: string;
|
||||
contractType: number;
|
||||
projectName: string;
|
||||
biddingName: string;
|
||||
biddingCode: string;
|
||||
|
||||
// 采购单位信息
|
||||
purchaserName: string;
|
||||
purchaserCode: string;
|
||||
industryCode: string;
|
||||
|
||||
// 供应商信息
|
||||
supplierId: string;
|
||||
supplierName: string;
|
||||
supplierCode: string;
|
||||
signerName: string;
|
||||
signerContact: string;
|
||||
|
||||
// 合同基本信息
|
||||
frameworkAgreementId: string;
|
||||
contractCode: string;
|
||||
contractName: string;
|
||||
categoryCode: string;
|
||||
signedDatetime: string; // 日期时间通常在前端使用字符串表示
|
||||
valuationType: number;
|
||||
amount: number; // BigDecimal 转为 number
|
||||
payType: number;
|
||||
startDatetime: string;
|
||||
endDatetime: string;
|
||||
|
||||
// 履约信息
|
||||
performancePlace: string;
|
||||
guaranteeType: number;
|
||||
note: string;
|
||||
contactAccessory: string;
|
||||
}
|
||||
|
||||
// 获取字典列表
|
||||
// export const fetchDictionaries = async (): Promise<DictionaryItem[]> => {
|
||||
// const response = await axios.get('/api/sys-manager-ebtp-project/v1/dictProject/getDictList?parentCode=procurement_type&toParentCode=entrust');
|
||||
// return response.data.data;
|
||||
// };
|
||||
|
||||
const prefix = '/api/biz-service-ebtp-project/';
|
||||
|
||||
export async function fetchContracts(params: any) {
|
||||
return request(prefix + 'v1/contract/getPage', {
|
||||
data: params,
|
||||
method: 'POST'
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateContract(params: any) {
|
||||
return request(prefix + 'v1/contract/update', {
|
||||
data: params,
|
||||
method: 'POST'
|
||||
});
|
||||
}
|
||||
|
||||
export async function createContract(params: any) {
|
||||
return request(prefix + 'v1/contract', {
|
||||
data: params,
|
||||
method: 'POST'
|
||||
});
|
||||
}
|
||||
|
||||
export async function getContract(param: any) {
|
||||
return request(prefix + 'v1/contract/' + param, {
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
export async function listNegotiate(params: any) {
|
||||
return request(prefix + 'v1/negotiate/list', {
|
||||
data: params,
|
||||
method: 'POST'
|
||||
});
|
||||
}
|
||||
|
||||
export async function deleteContract(param: any) {
|
||||
return request(prefix + 'v1/contract/delete/' + param, {
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
export async function createPerformance(params: any) {
|
||||
return request(prefix + 'v1/performance', {
|
||||
data: params,
|
||||
method: 'POST'
|
||||
});
|
||||
}
|
||||
|
||||
export async function updatePerformance(params: any) {
|
||||
return request(prefix + 'v1/performance/update', {
|
||||
data: params,
|
||||
method: 'POST'
|
||||
});
|
||||
}
|
||||
|
||||
export async function createAmountItem(params: any) {
|
||||
return request(prefix + 'v1/amount/item', {
|
||||
data: params,
|
||||
method: 'POST'
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateAmountItem(params: any) {
|
||||
return request(prefix + 'v1/amount/item/update', {
|
||||
data: params,
|
||||
method: 'POST'
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export async function createNegotiate(params: any) {
|
||||
return request(prefix + 'v1/negotiate', {
|
||||
data: params,
|
||||
method: 'POST'
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateNegotiate(params: any) {
|
||||
return request(prefix + 'v1/negotiate/update', {
|
||||
data: params,
|
||||
method: 'POST'
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export async function deleteAmountItem(param: any) {
|
||||
return request(prefix + 'v1/amount/item/delete/' + param, {
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
export async function getPerformanceById(params: any) {
|
||||
return request(prefix + 'v1/performance', {
|
||||
params: params,
|
||||
method: 'POST'
|
||||
});
|
||||
}
|
250
src/pages/Contract/Negotiate.tsx
Normal file
250
src/pages/Contract/Negotiate.tsx
Normal file
@ -0,0 +1,250 @@
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import {Table, Button, Upload, message, Form} from 'antd';
|
||||
import {PlusOutlined, DeleteOutlined, SendOutlined, CheckOutlined} from '@ant-design/icons';
|
||||
import moment, {Moment} from "moment";
|
||||
import {createNegotiate, listNegotiate} from "@/pages/Contract/ContractService";
|
||||
import {useLocation} from "umi";
|
||||
import {saveDateTimeFormatter} from "@/utils/DateUtils";
|
||||
import TextArea from "antd/es/input/TextArea";
|
||||
import {history} from "@@/core/history";
|
||||
|
||||
const createDate = moment()
|
||||
|
||||
const tableData: any[] | (() => any[]) = [
|
||||
// {
|
||||
// key: '1',
|
||||
// id: '',
|
||||
// contractFileId: '',
|
||||
// contractFileName: '2024年度汽车保养服务合同.doc',
|
||||
// createBy: '集团',
|
||||
// createDate: createDate,
|
||||
// note: '我方已上传,请确认',
|
||||
// },
|
||||
// {
|
||||
// key: '2',
|
||||
// id: '',
|
||||
// contractFileId: '',
|
||||
// contractFileName: '2024年度汽车保养服务合同-20241123.doc',
|
||||
// createBy: '北京风向文化有限公司',
|
||||
// createDate: createDate,
|
||||
// note: '已对合同内容进行修改,请确认。',
|
||||
// },
|
||||
];
|
||||
const Negotiate: React.FC = () => {
|
||||
const location = useLocation();
|
||||
const contractInfo = location.state?.contractInfo;
|
||||
const opt = location.state?.opt;
|
||||
let readOnly = false;
|
||||
if (opt === 'detail') {
|
||||
readOnly = true;
|
||||
}
|
||||
// 模拟表格数据
|
||||
const [tableDataState, setTableDataState] = useState(tableData);
|
||||
|
||||
// 处理TextArea内容变化
|
||||
const handleNoteChange = (e: React.ChangeEvent<HTMLTextAreaElement>, key: string) => {
|
||||
const newTableData = tableDataState.map(item => {
|
||||
if (item.key === key) {
|
||||
return {...item, note: e.target.value};
|
||||
}
|
||||
return item;
|
||||
});
|
||||
setTableDataState(newTableData);
|
||||
};
|
||||
|
||||
const handleDelete = (key: string) => {
|
||||
const newTableData = tableDataState.filter((row) => row.key !== key);
|
||||
newTableData.forEach((item, index) => {
|
||||
item.key = index.toString();
|
||||
})
|
||||
setTableDataState(newTableData);
|
||||
};
|
||||
|
||||
// rowSelection object indicates the need for row selection
|
||||
const rowSelection = {
|
||||
onChange: (selectedRowKeys: React.Key[], selectedRows: any[]) => {
|
||||
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
await listNegotiate({
|
||||
contractId: contractInfo.id
|
||||
}).then((res) => {
|
||||
if (res?.code === 200) {
|
||||
setTableDataState(res.data);
|
||||
if (res.data && res.data.length != 0) {
|
||||
for (const i in res.data) {
|
||||
const record = res.data[i];
|
||||
record.readOnly = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}); // 传递搜索参数
|
||||
|
||||
} catch (error) {
|
||||
message.error('获取磋商信息列表失败');
|
||||
} finally {
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchData().then(res => {} );
|
||||
}, []);
|
||||
|
||||
const saveNegotiateItem = (record: any) => {
|
||||
delete record.key;
|
||||
record.contractId = contractInfo.id;
|
||||
record.createDate = saveDateTimeFormatter(moment(record.createDate))
|
||||
createNegotiate(record).then((res) => {
|
||||
if (res?.code === 200) {
|
||||
message.success("发送成功")
|
||||
} else {
|
||||
message.error("发送失败")
|
||||
}
|
||||
})
|
||||
}
|
||||
// @ts-ignore
|
||||
const columns: Table.ColumnType<any>[] = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'key',
|
||||
key: 'key',
|
||||
render: (_: any, record: any, index: number) => index + 1,
|
||||
},
|
||||
{
|
||||
title: '合同文件名称',
|
||||
dataIndex: 'contractFileName',
|
||||
key: 'contractFileName',
|
||||
render: (text: string) => (
|
||||
<span style={{color: 'red'}}>
|
||||
{text ? <a href="#">{text}</a> : (
|
||||
<Upload
|
||||
name="file"
|
||||
// listType="simple"
|
||||
onChange={(info) => {
|
||||
console.log('Uploaded file info:', info);
|
||||
message.success('文件上传成功');
|
||||
}}
|
||||
>
|
||||
<Button type="primary">点击上传</Button>
|
||||
</Upload>
|
||||
)}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '上传方',
|
||||
dataIndex: 'createBy',
|
||||
key: 'createBy',
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createDate',
|
||||
key: 'createDate',
|
||||
render: (value: Moment, record: any) => value ? moment(value).format('yyyy-MM-DD') : null
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
dataIndex: 'note',
|
||||
key: 'note',
|
||||
render: (text: string, record: any) =>
|
||||
(
|
||||
<TextArea
|
||||
placeholder="请输入备注"
|
||||
value={text}
|
||||
readOnly={readOnly}
|
||||
onChange={(e) => handleNoteChange(e, record.key)}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'operation',
|
||||
render: (_: any, record: any) => (
|
||||
<div>
|
||||
<Button
|
||||
type="link"
|
||||
danger
|
||||
disabled={readOnly}
|
||||
icon={<DeleteOutlined/>}
|
||||
onClick={() => handleDelete(record.key)}
|
||||
>
|
||||
删除
|
||||
</Button>
|
||||
<Button type="link" icon={<CheckOutlined/>} onClick={() => saveNegotiateItem(record)}
|
||||
hidden={readOnly || record.id}>
|
||||
保存
|
||||
</Button>
|
||||
<Button type="link" icon={<SendOutlined/>} disabled={readOnly}>
|
||||
发送
|
||||
</Button>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const addRow = () => {
|
||||
const newRow = {
|
||||
id: '',
|
||||
key: (tableDataState.length + 1).toString(),
|
||||
contractFileName: '',
|
||||
contractFileId: '',
|
||||
createBy: '', // 设置默认上传方
|
||||
createDate: createDate,
|
||||
note: ''
|
||||
};
|
||||
const newTableData = [...tableDataState, newRow];
|
||||
setTableDataState(newTableData);
|
||||
};
|
||||
|
||||
const handleNegotiationEnd = () => {
|
||||
console.log('磋商结束操作触发');
|
||||
message.success('磋商结束');
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{marginLeft: 20}}>
|
||||
{/* 补充标题部分 */}
|
||||
<div style={{borderLeft: '4px solid #0066cc', paddingLeft: 8, marginBottom: 16}}>
|
||||
<span style={{fontSize: 16, fontWeight: 'bold'}}>合同磋商</span>
|
||||
</div>
|
||||
<Table
|
||||
rowSelection={{
|
||||
type: 'checkbox',
|
||||
...rowSelection,
|
||||
}}
|
||||
columns={columns}
|
||||
dataSource={tableDataState}/>
|
||||
|
||||
{/* 增加行按钮 */}
|
||||
<Button type="primary" onClick={addRow} icon={<PlusOutlined/>} hidden={readOnly}>
|
||||
增加行
|
||||
</Button>
|
||||
|
||||
{/* 居中的磋商结束按钮 */}
|
||||
<div style={{textAlign: 'center', marginTop: 24}}>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={handleNegotiationEnd}
|
||||
style={{width: 160}}
|
||||
hidden={readOnly}
|
||||
>
|
||||
磋商结束
|
||||
</Button>
|
||||
<Form.Item label="">
|
||||
<Button type="primary" hidden={!readOnly} onClick={() => {
|
||||
history.push({
|
||||
pathname: '/contract'
|
||||
})
|
||||
}}>
|
||||
返回
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Negotiate;
|
592
src/pages/Contract/Performance.tsx
Normal file
592
src/pages/Contract/Performance.tsx
Normal file
@ -0,0 +1,592 @@
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import {Form, Select, Input, Table, Button, message, DatePicker} from 'antd';
|
||||
import {useLocation} from "umi";
|
||||
|
||||
const {Option} = Select;
|
||||
import {
|
||||
createPerformance,
|
||||
updateContract,
|
||||
createAmountItem,
|
||||
updatePerformance, updateAmountItem
|
||||
} from "./ContractService";
|
||||
import {history} from "@@/core/history";
|
||||
import {saveDateTimeFormatter} from "@/utils/DateUtils";
|
||||
import moment, {Moment} from "moment";
|
||||
|
||||
const createDate = moment()
|
||||
|
||||
// 模拟合同履约状态选项
|
||||
const performanceStatusOptions = [
|
||||
{label: '正常履约', value: '0'},
|
||||
{label: '中止履约', value: '1'},
|
||||
{label: '终止履约', value: '2'}
|
||||
];
|
||||
|
||||
const yesOrNo = [
|
||||
{label: '是', value: '0'},
|
||||
{label: '否', value: '1'}
|
||||
]
|
||||
|
||||
// 模拟合同履约阶段选项
|
||||
const performanceStageOptions = [
|
||||
{label: '交付前', value: '0'},
|
||||
{label: '交付中', value: '1'},
|
||||
{label: '交付完毕', value: '2'},
|
||||
{label: '质量保证期间', value: '3'},
|
||||
{label: '履约结束', value: '4'},
|
||||
{label: '其他', value: '5'}
|
||||
];
|
||||
|
||||
//合同履约阶段说明
|
||||
const performanceStageDescOptions = [
|
||||
{label: '因供应商交付质量(态度、时间逾期、拒签合约、项目造假、资质不达标、存在造假或其他负面原因)导致的合同提前终止;', value: '0'},
|
||||
{label: '因触发合同条款,双方友好协商提前终止合同;', value: '1'},
|
||||
{label: '采购方主动取消,提前终止合同;', value: '2'},
|
||||
{label: '供应商主动取消或提前(因价格、工作量)终止合同;', value: '3'},
|
||||
{label: '因录入问题或系统操作问题导致的合同作废(取消);', value: '4'},
|
||||
{label: '因不可抗力因素(战争、疫情、灾害、新增监管要求)导致的合同提前终止;', value: '5'},
|
||||
{label: '其他(需列名具体原因)', value: '6'}
|
||||
];
|
||||
|
||||
// 模拟金额单位选项
|
||||
const amountUnitOptions = [
|
||||
{label: '元', value: '0'},
|
||||
{label: '万元', value: '1'},
|
||||
];
|
||||
|
||||
const initTableData = [
|
||||
{
|
||||
key: '1',
|
||||
id: '',
|
||||
contractPerformanceId: '',
|
||||
invoiceAmountItem: 0,
|
||||
invoiceUnit: '0',
|
||||
payAmountItem: 0,
|
||||
payUnit: '0',
|
||||
createDate: createDate
|
||||
}
|
||||
];
|
||||
// @ts-ignore
|
||||
const Performance: React.FC = () => {
|
||||
const [form] = Form.useForm();
|
||||
const location = useLocation();
|
||||
const contractInfo = location.state?.contractInfo;
|
||||
const opt = location.state?.opt;
|
||||
const totalReadOnly = true;
|
||||
let readOnly = false;
|
||||
if(opt ==='detail'){
|
||||
readOnly = true;
|
||||
}else if(opt === 'edit') {
|
||||
readOnly = false;
|
||||
}
|
||||
|
||||
const [tableData, setTableData] = useState(initTableData);
|
||||
// @ts-ignore
|
||||
const [invoiceAmount, setInvoiceAmount] = useState(0);
|
||||
// @ts-ignore
|
||||
const [payAmount, setPayAmount] = useState(0);
|
||||
let status0 = true;
|
||||
let status1 = true;
|
||||
let changeType0 = true;
|
||||
let phaseDescriptionText0 = true;
|
||||
// const [status0, setStatus0] = useState(true);
|
||||
// const [status1, setStatus1] = useState(true);
|
||||
// const [changeType0,setChangeType0] = useState(true);
|
||||
// 计算总发票金额
|
||||
const calculateTotalInvoiceAmount = (data: any) => {
|
||||
return data.reduce((sum: number, row: { invoiceAmountItem: any; }) => sum + Number(row.invoiceAmountItem || 0), 0);
|
||||
};
|
||||
|
||||
// 计算总支付金额
|
||||
const calculateTotalPaymentAmount = (data: any) => {
|
||||
return data.reduce((sum: number, row: { payAmountItem: any; }) => sum + Number(row.payAmountItem || 0), 0);
|
||||
};
|
||||
useEffect(() => {
|
||||
const newInvoiceAmount = calculateTotalInvoiceAmount(tableData);
|
||||
const newPayAmount = calculateTotalPaymentAmount(tableData);
|
||||
|
||||
// 更新状态
|
||||
setInvoiceAmount(newInvoiceAmount);
|
||||
setPayAmount(newPayAmount);
|
||||
|
||||
// 同步到表单
|
||||
form.setFieldsValue({
|
||||
invoiceAmount: newInvoiceAmount,
|
||||
payAmount: newPayAmount
|
||||
});
|
||||
}, [tableData, form]);
|
||||
|
||||
// 初始化数据
|
||||
useEffect(() => {
|
||||
if(opt && contractInfo.performance){
|
||||
// 设置表单初始值
|
||||
form.setFieldsValue({
|
||||
...contractInfo.performance,
|
||||
changeDate: moment(contractInfo.performance.changeDate)
|
||||
});
|
||||
|
||||
// 处理表格数据
|
||||
if(contractInfo.performance.list){
|
||||
const newTableData = contractInfo.performance.list.map((amountItem: any, index: number) => ({
|
||||
...amountItem,
|
||||
key: index + '',
|
||||
invoiceUnit: '0',
|
||||
payUnit: '0'
|
||||
}));
|
||||
|
||||
setTableData(newTableData);
|
||||
}
|
||||
}
|
||||
}, [opt, contractInfo, form]);
|
||||
|
||||
// 1111
|
||||
const handleInvoiceAmountItemChange = (key: string, value: any) => {
|
||||
if(isNaN(value)){
|
||||
message.error("请输入正确的数字").then()
|
||||
}else{
|
||||
// 更新表格中对应行的发票金额
|
||||
const newTableData = tableData.map((row: any) =>
|
||||
row.key === key ? {...row, invoiceAmountItem: value} : row
|
||||
);
|
||||
setTableData(newTableData);
|
||||
}
|
||||
};
|
||||
|
||||
// 222
|
||||
const handlePayAmountItemChange = (key: string, value: any) => {
|
||||
if(isNaN(value)){
|
||||
message.error("请输入正确的数字").then()
|
||||
}else{
|
||||
// 更新表格中对应行的支付金额
|
||||
const newTableData = tableData.map((row: any) =>
|
||||
row.key === key ? {...row, payAmountItem: value} : row
|
||||
);
|
||||
setTableData(newTableData);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteRow = (key: string) => {
|
||||
const newTableData = tableData.filter((row: any) => row.key !== key);
|
||||
newTableData.forEach((item,index) => {
|
||||
item.key = index.toString();
|
||||
})
|
||||
setTableData(newTableData);
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
const columns: Table.ColumnType<any>[] = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'key',
|
||||
key: 'key',
|
||||
render: (_: any, record: any, index: number) => index + 1,
|
||||
},
|
||||
{
|
||||
title: '发票金额(CNY)',
|
||||
dataIndex: 'invoiceAmountItem',
|
||||
key: 'invoiceAmountItem',
|
||||
render: (text: any, record: any) => (
|
||||
<Input
|
||||
readOnly={readOnly}
|
||||
placeholder="请输入金额"
|
||||
value={text}
|
||||
onChange={(e) => handleInvoiceAmountItemChange(record.key, e.target.value)}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
dataIndex: 'invoiceUnit',
|
||||
key: 'invoiceUnit',
|
||||
render: (text: any, record: any) => (
|
||||
<Select
|
||||
defaultValue={'0'}
|
||||
disabled
|
||||
value={text}
|
||||
>
|
||||
{amountUnitOptions.map(({label, value}) => (
|
||||
<Option key={value} value={value}>
|
||||
{label}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '支付金额(CNY)',
|
||||
dataIndex: 'payAmountItem',
|
||||
key: 'payAmountItem',
|
||||
render: (text: any, record: any) => (
|
||||
<Input
|
||||
readOnly={readOnly}
|
||||
placeholder="请输入金额"
|
||||
value={text}
|
||||
onChange={(e) => handlePayAmountItemChange(record.key, e.target.value)}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
dataIndex: 'payUnit',
|
||||
key: 'payUnit',
|
||||
render: (text: any, record: any) => (
|
||||
<Select
|
||||
defaultValue={'0'}
|
||||
disabled
|
||||
value={text}
|
||||
>
|
||||
{amountUnitOptions.map(({label, value}) => (
|
||||
<Option key={value} value={value}>
|
||||
{label}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '录入时间',
|
||||
dataIndex: 'createDate',
|
||||
key: 'createDate',
|
||||
render: (value: Moment, record: any) => value?moment(value).format('yyyy-MM-DD'):null
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'operation',
|
||||
render: (_: any, record: any) => (
|
||||
<Button type="link" danger onClick={() => handleDeleteRow(record.key)} disabled={readOnly}>
|
||||
删除
|
||||
</Button>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const addRow = () => {
|
||||
const newRow = {
|
||||
key: (tableData.length + 1).toString(),
|
||||
id: '',
|
||||
contractPerformanceId: '',
|
||||
invoiceAmountItem: 0,
|
||||
invoiceUnit: '0',
|
||||
payAmountItem: 0,
|
||||
payUnit: '0',
|
||||
createDate: createDate
|
||||
};
|
||||
const newTableData = [...tableData, newRow];
|
||||
setTableData(newTableData);
|
||||
};
|
||||
|
||||
const buildAmountItem: any = (id: string) => {
|
||||
const amountItemList: any[] = [];
|
||||
tableData.forEach((data) => {
|
||||
delete data.key;
|
||||
if (data.invoiceAmountItem != 0 || data.payAmountItem != 0) {
|
||||
data.contractPerformanceId = id;
|
||||
data.createDate = saveDateTimeFormatter(moment(data.createDate));
|
||||
amountItemList.push(data);
|
||||
}
|
||||
})
|
||||
return amountItemList;
|
||||
}
|
||||
|
||||
const statusChange = (value: any) => {
|
||||
status0 = (value==='2'?false:true)
|
||||
status1 = (value==='1'?false:true)
|
||||
phaseDescriptionText0 = (true);
|
||||
}
|
||||
|
||||
const onFinish = (values: any) => {
|
||||
if(opt === 'edit'){
|
||||
values.contractId = contractInfo.id;
|
||||
values.contractCode = contractInfo.contractCod;
|
||||
values.contractName = contractInfo.contractName;
|
||||
const newValues = {
|
||||
...values,
|
||||
actualAmount: values.actualAmount?Number(values.actualAmount):0,
|
||||
changeDate: saveDateTimeFormatter(values.changeDate)
|
||||
}
|
||||
updatePerformance(newValues).then((res) => {
|
||||
const performanceId = res.data.id;
|
||||
if(performanceId){
|
||||
updateAmountItem(buildAmountItem(performanceId)).then((amountRes: any) => {
|
||||
if (amountRes.code === 200) {
|
||||
message.success('保存成功').then(r =>
|
||||
history.push({
|
||||
pathname: '/contract',
|
||||
state: {
|
||||
contractInfo: res.data
|
||||
}
|
||||
})
|
||||
);
|
||||
} else {
|
||||
message.error('保存失败').then();
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}else {
|
||||
//履约信息与合同信息 关联
|
||||
values.contractId = contractInfo.id;
|
||||
values.contractCode = contractInfo.contractCod;
|
||||
values.contractName = contractInfo.contractName;
|
||||
values.actualAmount = values.actualAmount?Number(values.actualAmount):0
|
||||
values.changeDate = saveDateTimeFormatter(values.changeDate)
|
||||
try {
|
||||
//修改合同信息状态为 进行中
|
||||
contractInfo.status = 1;
|
||||
updateContract(contractInfo);//更新合同状态
|
||||
createPerformance(values).then((res: any) => {
|
||||
const performanceId = res.data.id;
|
||||
if (performanceId) {
|
||||
createAmountItem(buildAmountItem(performanceId)).then((amountRes) => {
|
||||
if (amountRes.code === 200) {
|
||||
message.success('保存成功').then(r =>
|
||||
history.push({
|
||||
pathname: '/contract',
|
||||
state: {
|
||||
contractInfo: res.data
|
||||
}
|
||||
})
|
||||
);
|
||||
} else {
|
||||
message.error('保存失败').then();
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
message.error(error.message || '保存失败').then();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onFinishFailed = (errorInfo: any) => {
|
||||
message.error('表单提交失败,请检查输入');
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* 标题部分 */}
|
||||
<div style={{
|
||||
borderLeft: '4px solid #0066cc',
|
||||
paddingLeft: 16,
|
||||
marginBottom: 16,
|
||||
position: 'relative',
|
||||
left: 10
|
||||
}}>
|
||||
<span style={{fontSize: 16, fontWeight: 'bold'}}>合同履约信息</span>
|
||||
</div>
|
||||
<Form
|
||||
form={form}
|
||||
labelCol={{span:6}}
|
||||
wrapperCol={{span:18}}
|
||||
initialValues={{}}
|
||||
onFinish={onFinish}
|
||||
onFinishFailed={onFinishFailed}
|
||||
style={{marginLeft: 20}}
|
||||
>
|
||||
<div style={{display: 'flex', flexWrap: 'wrap'}}>
|
||||
<Form.Item name="id" hidden={true}></Form.Item>
|
||||
{/* 合同履约状态 */}
|
||||
<Form.Item
|
||||
name="status"
|
||||
label="合同履约状态"
|
||||
rules={[{required: true, message: '请选择合同履约状态'}]}
|
||||
style={{width: '50%', marginRight: 16}}
|
||||
>
|
||||
<Select placeholder="请选择" disabled={readOnly} onChange={statusChange}>
|
||||
{performanceStatusOptions.map(({label, value}) => (
|
||||
<Option key={value} value={value}>
|
||||
{label}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
</div>
|
||||
<div style={{display: 'flex', flexWrap: 'wrap'}}>
|
||||
{/* 合同履约阶段 */}
|
||||
<Form.Item
|
||||
name="phase"
|
||||
label="合同履约阶段"
|
||||
hidden={!status0 || !status1}
|
||||
rules={[{required: status0, message: '请选择合同履约阶段'}]}
|
||||
style={{width: '50%'}}
|
||||
>
|
||||
<Select placeholder="请选择" disabled={readOnly} onChange={ (value) => {
|
||||
phaseDescriptionText0 = (value==='5'? false: true)
|
||||
}}>
|
||||
{performanceStageOptions.map(({label, value}) => (
|
||||
<Option key={value} value={value}>
|
||||
{label}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="phaseDescription"
|
||||
label="合同履约阶段说明"
|
||||
hidden={status0}
|
||||
rules={[{required: !status0, message: '请选择合同履约阶段'}]}
|
||||
style={{width: '50%'}}
|
||||
>
|
||||
<Select placeholder="请选择" disabled={readOnly} onChange={(value) => {
|
||||
phaseDescriptionText0 = (value==='6'? false: true)
|
||||
}}>
|
||||
{performanceStageDescOptions.map(({label, value}) => (
|
||||
<Option key={value} value={value}>
|
||||
{label}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
hidden={phaseDescriptionText0}
|
||||
name="phaseDescriptionText"
|
||||
label="合同履约阶段说明"
|
||||
style={{width: '45%'}}
|
||||
rules={[{ message: '请填写合同履约阶段说明'}]}
|
||||
>
|
||||
<Input
|
||||
placeholder="请输入合同履约阶段说明"
|
||||
readOnly={readOnly}
|
||||
/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
<div style={{display: 'flex', flexWrap: 'wrap'}}>
|
||||
{/* 合同金额变更 */}
|
||||
<Form.Item
|
||||
name="changeType"
|
||||
label="合同金额变更"
|
||||
rules={[{required: true, message: '请选择合同金额变更情况'}]}
|
||||
style={{width: '50%', marginRight: 16}}
|
||||
>
|
||||
<Select placeholder="请选择" disabled={readOnly} onChange={ (value) => {
|
||||
changeType0 = (value === '0'?false: true);
|
||||
}}>
|
||||
{yesOrNo.map(({label, value}) => (
|
||||
<Option key={value} value={value}>
|
||||
{label}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
</div>
|
||||
<div style={{display: 'flex', flexWrap: 'wrap'}}>
|
||||
{/* 合同实际金额 */}
|
||||
<Form.Item
|
||||
name="amount"
|
||||
label="合同金额(CNY): / 元"
|
||||
hidden={changeType0}
|
||||
style={{width: '50%'}}
|
||||
rules={[{ pattern: /^[0-9]+(\.[0-9]{1,2})?$/, message: '请输入正确的金额格式,最多保留两位小数' },
|
||||
{ validator: (_, value) => value > 0 ? Promise.resolve() : Promise.reject('金额必须大于0') }]}
|
||||
>
|
||||
<Input
|
||||
placeholder="请输入合同金额"
|
||||
// value={actualAmount}
|
||||
// onChange={handleActualAmountChange}
|
||||
readOnly={readOnly}
|
||||
/>
|
||||
</Form.Item>
|
||||
{/* 合同是否有扣款 */}
|
||||
<Form.Item
|
||||
name="changeDate"
|
||||
hidden={changeType0}
|
||||
label="合同变更日期"
|
||||
style={{width: '45%'}}
|
||||
>
|
||||
<DatePicker placeholder="请选择时间" inputReadOnly={true} format={"yyyy-MM-DD"} disabled={readOnly} style={{width:'100%'}} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
<div style={{display: 'flex', flexWrap: 'wrap'}}>
|
||||
{/* 合同实际金额 */}
|
||||
<Form.Item
|
||||
name="actualAmount"
|
||||
label="合同实际金额 / 元"
|
||||
style={{width: '50%'}}
|
||||
rules={[{ required: true ,pattern: /^[0-9]+(\.[0-9]{1,2})?$/, message: '请输入正确的金额格式,最多保留两位小数' },
|
||||
{ validator: (_, value) => value > 0 ? Promise.resolve() : Promise.reject('金额必须大于0') }]}
|
||||
>
|
||||
<Input
|
||||
placeholder="请输入合同实际金额"
|
||||
// value={actualAmount}
|
||||
// onChange={handleActualAmountChange}
|
||||
readOnly={readOnly}
|
||||
/>
|
||||
</Form.Item>
|
||||
{/* 合同是否有扣款 */}
|
||||
<Form.Item
|
||||
name="deductionsStatus"
|
||||
label="合同是否有扣款"
|
||||
rules={[{required: true, message: '请选择合同是否有扣款'}]}
|
||||
style={{width: '45%'}}
|
||||
>
|
||||
<Select placeholder="请选择" disabled={readOnly}>
|
||||
{yesOrNo.map(({label, value}) => (
|
||||
<Option key={value} value={value}>
|
||||
{label}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
</div>
|
||||
<div style={{display: 'flex', flexWrap: 'wrap'}}>
|
||||
<label style={{marginLeft: '55%',marginBottom:'10px',marginTop:'5px'}}>因卖方存在安全、环保、质量、进度、服务、廉洁等问题造成的扣款。</label>
|
||||
</div>
|
||||
<div style={{display: 'flex', flexWrap: 'wrap'}}>
|
||||
{/* 累计发票金额(CNY) */}
|
||||
<Form.Item
|
||||
name="invoiceAmount"
|
||||
label="累计发票金额(CNY) / 元"
|
||||
rules={[{required: true, message: '请输入累计发票金额'}]}
|
||||
style={{width: '50%'}}
|
||||
>
|
||||
<Input
|
||||
value={invoiceAmount}
|
||||
readOnly={totalReadOnly}
|
||||
placeholder="请输入金额"
|
||||
/>
|
||||
</Form.Item>
|
||||
{/* 累计支付金额(CNY) */}
|
||||
<Form.Item
|
||||
name="payAmount"
|
||||
label="累计支付金额(CNY) / 元"
|
||||
rules={[{required: true, message: '请输入累计支付金额'}]}
|
||||
style={{width: '45%'}}
|
||||
>
|
||||
<Input
|
||||
value={payAmount}
|
||||
readOnly={totalReadOnly}
|
||||
placeholder="请输入金额"
|
||||
/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
{/* 表格部分 */}
|
||||
<div style={{marginLeft: '50%', transform: 'translateX(-50%)', width: '100%'}}>
|
||||
<Table columns={columns} dataSource={tableData}/>
|
||||
<Button type="primary" onClick={addRow} hidden={readOnly || !status0}>
|
||||
+增加行
|
||||
</Button>
|
||||
</div>
|
||||
{/* 按钮部分 */}
|
||||
<div style={{display: 'flex', justifyContent: 'center', marginTop: 24}}>
|
||||
<Form.Item label="">
|
||||
<Button type="primary" htmlType="submit" hidden={readOnly}>
|
||||
保存并提交
|
||||
</Button>
|
||||
</Form.Item>
|
||||
<Form.Item label="">
|
||||
<Button type="primary" hidden={!readOnly} onClick={ ()=> {
|
||||
history.push({
|
||||
pathname: '/contract'
|
||||
})
|
||||
}}>
|
||||
返回
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Performance;
|
340
src/pages/Contract/StepOne.tsx
Normal file
340
src/pages/Contract/StepOne.tsx
Normal file
@ -0,0 +1,340 @@
|
||||
import React, {useState} from 'react';
|
||||
import { Form, Input, Select, Button, Spin, message } from 'antd';
|
||||
const { Option } = Select;
|
||||
import { useLocation } from 'umi';
|
||||
import {createContract, updateContract} from "./ContractService";
|
||||
import {history} from "@@/core/history";
|
||||
|
||||
|
||||
// 模拟行业选项
|
||||
const industryOptions = [
|
||||
{ label: '制造业', value:'0' },
|
||||
{ label: '服务业', value:'service' },
|
||||
{ label: '零售业', value:'retail' },
|
||||
];
|
||||
|
||||
const StepOne: React.FC = () => {
|
||||
const [form] = Form.useForm();
|
||||
let readOnly = false;
|
||||
const location = useLocation();
|
||||
const contractType = location.state?.contractType;
|
||||
const contractInfo = location.state?.contractInfo;
|
||||
const opt = location.state?.opt;
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
if(opt){
|
||||
form.setFieldsValue({
|
||||
...contractInfo
|
||||
});
|
||||
if(opt === 'detail'){
|
||||
readOnly = true;
|
||||
}else if (opt ==='edit'){
|
||||
readOnly = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 表单提交处理函数
|
||||
const onFinish = (values: any) => {
|
||||
values.contractType = contractType;
|
||||
if(opt === 'detail'){
|
||||
history.push({
|
||||
pathname: '/stepTwo',
|
||||
state: {
|
||||
contractInfo: contractInfo,
|
||||
opt: opt
|
||||
}
|
||||
});
|
||||
}else{
|
||||
try {
|
||||
if (values.id) {
|
||||
setLoading(true)
|
||||
updateContract(values).then((res: any) => {
|
||||
if(res.code === 200){
|
||||
// message.success("当前数据更新成功").then(() => {
|
||||
history.push({
|
||||
pathname: '/stepTwo',
|
||||
state: {
|
||||
contractInfo: res.data,
|
||||
opt: opt
|
||||
}
|
||||
});
|
||||
// }).then( () => {
|
||||
setLoading(false)
|
||||
// })
|
||||
}else {
|
||||
message.error('更新失败');
|
||||
}
|
||||
})
|
||||
} else {
|
||||
createContract(values).then( (res: any) => {
|
||||
if(res.code === 200){
|
||||
history.push({
|
||||
pathname: '/stepTwo',
|
||||
state: {
|
||||
contractInfo: res.data
|
||||
}
|
||||
});
|
||||
}else {
|
||||
message.error('更新失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
message.error(error.message || '操作失败');
|
||||
}
|
||||
}
|
||||
};
|
||||
// @ts-ignore
|
||||
const validateCreditCode = (value: string) => {
|
||||
// 基本格式校验
|
||||
if (!value || value.length !== 18) {
|
||||
return '统一社会信用代码必须为18位';
|
||||
}
|
||||
|
||||
// 正则校验(允许数字和大写字母,不包括I、O、Z、S、V)
|
||||
const pattern = /^[0-9A-HJ-NPQRTUWXY]{18}$/;
|
||||
if (!pattern.test(value)) {
|
||||
return '统一社会信用代码格式不正确';
|
||||
}
|
||||
|
||||
// 校验码计算
|
||||
const weightFactor = [1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28];
|
||||
const codePoint = {
|
||||
'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9,
|
||||
'A': 10, 'B': 11, 'C': 12, 'D': 13, 'E': 14, 'F': 15, 'G': 16, 'H': 17, 'J': 18,
|
||||
'K': 19, 'L': 20, 'M': 21, 'N': 22, 'P': 23, 'Q': 24, 'R': 25, 'T': 26, 'U': 27,
|
||||
'W': 28, 'X': 29, 'Y': 30
|
||||
};
|
||||
const checkCodeDict = {
|
||||
0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7', 8: '8', 9: '9',
|
||||
10: 'A', 11: 'B', 12: 'C', 13: 'D', 14: 'E', 15: 'F', 16: 'G', 17: 'H', 18: 'J',
|
||||
19: 'K', 20: 'L', 21: 'M', 22: 'N', 23: 'P', 24: 'Q', 25: 'R', 26: 'T', 27: 'U',
|
||||
28: 'W', 29: 'X', 30: 'Y'
|
||||
};
|
||||
|
||||
let sum = 0;
|
||||
for (let i = 0; i < 17; i++) {
|
||||
sum += codePoint[value[i]] * weightFactor[i];
|
||||
}
|
||||
|
||||
const mod = sum % 31;
|
||||
const checkCode = checkCodeDict[mod];
|
||||
|
||||
if (checkCode !== value[17]) {
|
||||
return '统一社会信用代码校验位不正确';
|
||||
}
|
||||
|
||||
return null; // 校验通过
|
||||
};
|
||||
|
||||
|
||||
// 表单提交失败处理函数
|
||||
const onFinishFailed = (errorInfo: any) => {
|
||||
// console.log('Form submission failed:', errorInfo);
|
||||
message.error('表单提交失败,请检查输入');
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: '10px' }}>
|
||||
{/* 添加全局遮罩 */}
|
||||
{loading && (
|
||||
<Spin
|
||||
tip="加载中..."
|
||||
style={{
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
zIndex: 9999,
|
||||
background: 'rgba(255, 255, 255, 0.8)',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<Form
|
||||
form={form}
|
||||
labelCol={{span:4}}
|
||||
wrapperCol={{span:20}}
|
||||
|
||||
initialValues={{
|
||||
status: 0
|
||||
}}
|
||||
onFinish={onFinish}
|
||||
onFinishFailed={onFinishFailed}
|
||||
>
|
||||
{/* 项目基本信息部分 */}
|
||||
<div style={{ borderLeft: '4px solid #0066cc', paddingLeft: 8, marginBottom: 16 }}>
|
||||
<span style={{ fontSize: 16, fontWeight: 'bold' }}>基本信息</span>
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||
<Form.Item hidden={true} name="id"></Form.Item>
|
||||
<Form.Item
|
||||
name="status"
|
||||
label="合同状态"
|
||||
hidden={true}
|
||||
>
|
||||
<Input value={0}/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="projectName"
|
||||
label="项目名称"
|
||||
rules={[{ required: true, message: '请输入项目名称' }]}
|
||||
style={{ width: '50%', marginRight: 16 }}
|
||||
>
|
||||
<Input placeholder="请输入项目名称" readOnly={readOnly}/>
|
||||
</Form.Item>
|
||||
<Form.Item name="projectSelect" label="" style={{ width: '80%' }}>
|
||||
<Button type="primary" hidden={readOnly}>选择项目</Button>
|
||||
</Form.Item>
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||
<Form.Item
|
||||
name="biddingName"
|
||||
label="标段名称"
|
||||
rules={[{ required: true, message: '请输入标段名称' }]}
|
||||
style={{ width: '50%', marginRight: 16 }}
|
||||
>
|
||||
<Input placeholder="请输入标段名称" readOnly={readOnly}/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="biddingCode"
|
||||
label="标段编号"
|
||||
rules={[{ required: true, message: '请输入标段编号' }]}
|
||||
style={{ width: '45%' }}
|
||||
>
|
||||
<Input placeholder="请输入标段编号" readOnly={readOnly} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
<Form.Item name="sectionSelect" label="" style={{ width: '20%' }}>
|
||||
<Button type="primary" hidden={readOnly}>选择标段</Button>
|
||||
</Form.Item>
|
||||
|
||||
{/* 我方签约主体信息部分 */}
|
||||
<div style={{ borderLeft: '4px solid #0066cc', paddingLeft: 8, marginBottom: 16, marginTop: 16 }}>
|
||||
<span style={{ fontSize: 16, fontWeight: 'bold' }}>我方签约主体信息</span>
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||
<Form.Item
|
||||
name="purchaserName"
|
||||
label="采购单位"
|
||||
rules={[{ required: true, message: '请输入采购单位' }]}
|
||||
style={{ width: '50%', marginRight: 16 }}
|
||||
>
|
||||
<Input placeholder="请输入采购单位" readOnly={readOnly} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="purchaserCode"
|
||||
label="统一社会信用代码"
|
||||
rules={[{ required: true, message: '请输入统一社会信用代码' },
|
||||
// ({ getFieldValue }) => ({
|
||||
// validator(rule, value) {
|
||||
// const errorMessage = validateCreditCode(value);
|
||||
// if (errorMessage) {
|
||||
// return Promise.reject(errorMessage);
|
||||
// }
|
||||
// return Promise.resolve();
|
||||
// },
|
||||
// })
|
||||
]}
|
||||
style={{ width: '50%', marginRight: 16 }}
|
||||
>
|
||||
<Input placeholder="请输入统一社会信用代码" readOnly={readOnly} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="industryCode"
|
||||
label="所属主要行业"
|
||||
rules={[{ required: true, message: '请选择所属主要行业' }]}
|
||||
style={{ width: '45%' }}
|
||||
>
|
||||
<Select placeholder="请选择" disabled={readOnly}>
|
||||
{industryOptions.map(({ label, value }) => (
|
||||
<Option key={value} value={value}>
|
||||
{label}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
{/* 对方签约主体信息部分 */}
|
||||
<div style={{ borderLeft: '4px solid #0066cc', paddingLeft: 8, marginBottom: 16, marginTop: 16 }}>
|
||||
<span style={{ fontSize: 16, fontWeight: 'bold' }}>对方签约主体信息</span>
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||
<Form.Item
|
||||
name="supplierName"
|
||||
label="供应商公司名称"
|
||||
rules={[{ required: true, message: '请输入供应商公司名称' }]}
|
||||
style={{ width: '50%', marginRight: 16 }}
|
||||
>
|
||||
<Input placeholder="请输入供应商公司名称" readOnly={readOnly} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="supplierCode"
|
||||
label="统一社会信用代码"
|
||||
rules={[
|
||||
{ required: true, message: '请输入统一社会信用代码' },
|
||||
// ({ getFieldValue }) => ({
|
||||
// validator(rule, value) {
|
||||
// const errorMessage = validateCreditCode(value);
|
||||
// if (errorMessage) {
|
||||
// return Promise.reject(errorMessage);
|
||||
// }
|
||||
// return Promise.resolve();
|
||||
// },
|
||||
// })
|
||||
]}
|
||||
style={{ width: '45%' }}
|
||||
>
|
||||
<Input placeholder="请输入统一社会信用代码" readOnly={readOnly} />
|
||||
</Form.Item>
|
||||
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||
<Form.Item name="supplierSelect" label="" style={{ width: '20%' }}>
|
||||
<Button type="primary" hidden={readOnly}>选择供应商</Button>
|
||||
</Form.Item>
|
||||
{/*<Form.Item*/}
|
||||
{/* name="supplierName"*/}
|
||||
{/* label="供应商公司名称"*/}
|
||||
{/* rules={[{ required: true, message: '请输入供应商公司名称' }]}*/}
|
||||
{/* style={{ width: '50%', marginRight: 16 }}*/}
|
||||
{/*>*/}
|
||||
{/* <Input placeholder="请输入供应商公司名称" readOnly={readOnly} />*/}
|
||||
{/*</Form.Item>*/}
|
||||
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||
<Form.Item
|
||||
name="signerName"
|
||||
label="供应商签约人"
|
||||
style={{ width: '50%', marginRight: 16 }}
|
||||
rules={[{ min: 2, message: '姓名长度不能少于2个字符' },
|
||||
{ max: 20, message: '姓名长度不能超过20个字符' },
|
||||
{ pattern: /^[\u4e00-\u9fa5a-zA-Z\s·]{2,20}$/, message: '请输入正确的姓名' }]}
|
||||
>
|
||||
<Input placeholder="" readOnly={readOnly}/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="signerContact"
|
||||
label="供应商联系方式"
|
||||
style={{ width: '50%' }}
|
||||
rules={ [{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码' }]}
|
||||
>
|
||||
<Input placeholder="" readOnly={readOnly} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
{/* 居中显示的下一步按钮 */}
|
||||
<div style={{ display: 'flex', justifyContent: 'center', marginTop: 24 }}>
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit" style={{ width: 200 }} onClick={ () => {}}>
|
||||
下一步,合同信息
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default StepOne;
|
458
src/pages/Contract/StepTwo.tsx
Normal file
458
src/pages/Contract/StepTwo.tsx
Normal file
@ -0,0 +1,458 @@
|
||||
import React, {useState} from 'react';
|
||||
import {Form, Input, Select, DatePicker, Button, message, Spin, Upload} from 'antd';
|
||||
import {useLocation} from "umi";
|
||||
import {updateContract} from "@/pages/Contract/ContractService";
|
||||
import {history} from "@@/core/history";
|
||||
import { saveDateTimeFormatter } from '@/utils/DateUtils';
|
||||
import moment from "moment";
|
||||
const { Option } = Select;
|
||||
|
||||
// 合同金额单位 元/万元
|
||||
// const amountUnits = [
|
||||
// { label: '元', value: '0' },
|
||||
// { label: '万元', value:'1' }
|
||||
// ];
|
||||
|
||||
// 合同主要标的类型选项
|
||||
const categoryCodeOptions = [
|
||||
{ label: '土地、建筑物及构筑物', value: '0' },
|
||||
{ label: '通用设备', value:'1' },
|
||||
{ label: '专用设备', value: '2' },
|
||||
{ label: '文物和陈列品', value: '3' },
|
||||
];
|
||||
|
||||
// 合同计价方式选项
|
||||
const pricingMethodOptions = [
|
||||
{ label: '总价合同', value: '0' },
|
||||
{ label: '单价合同', value: '1' },
|
||||
{ label: '成本加酬金合同', value: '2' },
|
||||
{ label: '其他形式合同', value: '3' }
|
||||
];
|
||||
|
||||
// 付款方式选项
|
||||
const paymentMethodOptions = [
|
||||
{ label: '一次性付款', value: '0' },
|
||||
{ label: '分期付款', value: '1' },
|
||||
{ label: '其他', value: '2' },
|
||||
];
|
||||
|
||||
// 模拟履约担保选项
|
||||
const guaranteeOptions = [
|
||||
{ label: '无', value: '0'},
|
||||
{ label: '履约担保金', value: '1' },
|
||||
{ label: '银行履约保函', value: '2' },
|
||||
{ label: '履约担保书', value: '3' }
|
||||
];
|
||||
|
||||
const StepTwo: React.FC = () => {
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
// const [payType0,setPayType0] = useState(true);
|
||||
let payType0 = true;
|
||||
let valuationType0 = true;
|
||||
// const [valuationType0,setValuationType0] = useState(true);
|
||||
const [form] = Form.useForm();
|
||||
const location = useLocation();
|
||||
const contractInfo = location.state?.contractInfo;
|
||||
const opt = location.state?.opt;
|
||||
const isShow = contractInfo? contractInfo.contractType=='0'? false: true: true;
|
||||
let readOnly = false;
|
||||
if(opt){
|
||||
form.setFieldsValue({
|
||||
...contractInfo,
|
||||
endDatetime: contractInfo.endDatetime ? moment(contractInfo.endDatetime) : null,
|
||||
startDatetime: contractInfo.startDatetime ? moment(contractInfo.startDatetime) : null,
|
||||
signedDatetime: contractInfo.signedDatetime ? moment(contractInfo.signedDatetime) : null,
|
||||
performancePlace: contractInfo.performancePlace ? contractInfo.performancePlace.split(",") : [],
|
||||
mainType: contractInfo.mainType ? contractInfo.mainType.split(","): []
|
||||
})
|
||||
if(opt === 'detail'){
|
||||
readOnly = true
|
||||
}else if(opt ==='edit'){
|
||||
readOnly = false
|
||||
}
|
||||
}
|
||||
payType0 = (form.getFieldValue("payType") === '2' ? false: true);
|
||||
valuationType0 = (form.getFieldValue("valuationType") === '3' ? false: true);
|
||||
|
||||
function assignMatchingProperties<T>(original: T, updates: Partial<T>): T {
|
||||
const result: T = { ...original };
|
||||
|
||||
for (const key in updates) {
|
||||
if (Object.prototype.hasOwnProperty.call(updates, key)) {
|
||||
const typedKey = key as keyof T;
|
||||
if (typedKey in original && updates[typedKey] !== undefined) {
|
||||
result[typedKey] = updates[typedKey] as T[keyof T];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 表单提交处理函数
|
||||
const onFinish = (values: any) => {
|
||||
let newContract = null;
|
||||
if(opt){
|
||||
newContract = values;
|
||||
}else{
|
||||
const updatedContract = assignMatchingProperties(contractInfo, values);
|
||||
newContract = updatedContract;
|
||||
}
|
||||
newContract.performancePlace = newContract.performancePlace.join(',');
|
||||
newContract.mainType = newContract.mainType.join(',');
|
||||
newContract.signedDatetime = saveDateTimeFormatter(newContract.signedDatetime);
|
||||
newContract.startDatetime = saveDateTimeFormatter(newContract.startDatetime);
|
||||
newContract.endDatetime = saveDateTimeFormatter(newContract.endDatetime);
|
||||
setLoading(true)
|
||||
updateContract(newContract).then( (res: any) => {
|
||||
if(res?.code === 200){
|
||||
setLoading(false)
|
||||
message.success('保存成功');
|
||||
}else {
|
||||
message.error('保存失败');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 表单提交失败处理函数
|
||||
const onFinishFailed = (errorInfo: any) => {
|
||||
message.error('表单提交失败,请检查输入');
|
||||
};
|
||||
|
||||
const goNegotiatePage = async () => {
|
||||
if(opt === 'detail'){
|
||||
history.push({
|
||||
pathname: '/negotiate',
|
||||
state: {
|
||||
contractInfo: contractInfo,
|
||||
opt: opt
|
||||
}
|
||||
});
|
||||
}else{
|
||||
const values = await form.validateFields();
|
||||
const updatedContract = assignMatchingProperties(contractInfo, values);
|
||||
updatedContract.performancePlace = updatedContract.performancePlace.join(',')
|
||||
updatedContract.mainType = updatedContract.mainType.join(',');
|
||||
updatedContract.signedDatetime = saveDateTimeFormatter(updatedContract.signedDatetime);
|
||||
updatedContract.startDatetime = saveDateTimeFormatter(updatedContract.startDatetime);
|
||||
updatedContract.endDatetime = saveDateTimeFormatter(updatedContract.endDatetime);
|
||||
setLoading(true);
|
||||
updateContract(updatedContract).then( (res: any) => {
|
||||
if(res.code === 200){
|
||||
// message.success("当前数据更新成功").then(() => {
|
||||
history.push({
|
||||
pathname: '/negotiate',
|
||||
state: {
|
||||
contractInfo: updatedContract,
|
||||
opt: opt
|
||||
}
|
||||
});
|
||||
// }).then( () => {
|
||||
setLoading(false);
|
||||
// })
|
||||
}else {
|
||||
message.error('保存失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const goPerformancePage = async () => {
|
||||
if(opt ==='detail'){
|
||||
history.push({
|
||||
pathname: '/performance',
|
||||
state: {
|
||||
contractInfo: contractInfo,
|
||||
opt: "detail"
|
||||
}
|
||||
});
|
||||
}else{
|
||||
const values = await form.validateFields();
|
||||
const updatedContract = assignMatchingProperties(contractInfo, values);
|
||||
updatedContract.performancePlace = updatedContract.performancePlace.join(',')
|
||||
updatedContract.mainType = updatedContract.mainType.join(',');
|
||||
updatedContract.signedDatetime = saveDateTimeFormatter(updatedContract.signedDatetime);
|
||||
updatedContract.startDatetime = saveDateTimeFormatter(updatedContract.startDatetime);
|
||||
updatedContract.endDatetime = saveDateTimeFormatter(updatedContract.endDatetime);
|
||||
setLoading(true);
|
||||
updateContract(updatedContract).then( (res: any) => {
|
||||
if(res.code === 200){
|
||||
message.success("当前数据更新成功").then(() => {
|
||||
history.push({
|
||||
pathname: '/performance',
|
||||
state: {
|
||||
contractInfo: updatedContract,
|
||||
opt: opt
|
||||
}
|
||||
});
|
||||
}).then( () => {
|
||||
setLoading(false);
|
||||
})
|
||||
}else {
|
||||
message.error('保存失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const payTypeOnChange = (value: any) => {
|
||||
payType0 = (value === '2' ? false: true);
|
||||
};
|
||||
const onValuationTypeChange = (value: any) => {
|
||||
valuationType0 = (value === '3' ? false: true);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* 标题部分 */}
|
||||
<div style={{
|
||||
borderLeft: '4px solid #0066cc',
|
||||
paddingLeft: 16,
|
||||
marginBottom: 16,
|
||||
position: 'relative',
|
||||
left: 10
|
||||
}}>
|
||||
<span style={{ fontSize: 16, fontWeight: 'bold' }}>合同基本信息</span>
|
||||
</div>
|
||||
{/* 添加全局遮罩 */}
|
||||
{loading && (
|
||||
<Spin
|
||||
tip="加载中..."
|
||||
style={{
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
zIndex: 9999,
|
||||
background: 'rgba(255, 255, 255, 0.8)',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<Form
|
||||
form={form}
|
||||
labelCol={{span:5}}
|
||||
wrapperCol={{span:19}}
|
||||
initialValues={{}}
|
||||
onFinish={onFinish}
|
||||
onFinishFailed={onFinishFailed}
|
||||
style={{ marginLeft: 20 }}
|
||||
>
|
||||
<Form.Item name="id" hidden={true}></Form.Item>
|
||||
{/* 框架协议编号,独占一行 */}
|
||||
<Form.Item
|
||||
name="frameworkAgreementId"
|
||||
label="框架协议编号"
|
||||
style={{ width: '45%', marginRight: 16 }}
|
||||
>
|
||||
<Input placeholder="当合同为执行框架协议或执行统谈分签协议时,须填写对应的框架协议或统谈分签协议的编号。" readOnly={readOnly}/>
|
||||
</Form.Item>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||
{/* 合同编号和合同名称 */}
|
||||
<Form.Item
|
||||
name="contractCode"
|
||||
label="合同编号"
|
||||
rules={[{ required: true, message: '请输入合同编号' }]}
|
||||
style={{ width: '45%', marginRight: 16 }}
|
||||
>
|
||||
<Input readOnly={readOnly}/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="contractName"
|
||||
label="合同名称"
|
||||
rules={[{ required: true, message: '请输入合同名称' }]}
|
||||
style={{ width: '45%' }}
|
||||
>
|
||||
<Input readOnly={readOnly}/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||
{/* 合同主要标的类型和公司签订日期 */}
|
||||
<Form.Item
|
||||
name="mainType"
|
||||
label="合同主要标的类型"
|
||||
rules={[{ required: true, message: '请选择合同主要标的类型' }]}
|
||||
style={{ width: '45%', marginRight: 16 }}
|
||||
>
|
||||
<Select placeholder="请选择" disabled={readOnly} mode="multiple">
|
||||
{categoryCodeOptions.map(({ label, value }) => (
|
||||
<Option key={value} value={value}>
|
||||
{label}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="signedDatetime"
|
||||
label="公司签订日期"
|
||||
rules={[{ required: true, message: '请选择公司签订日期' }]}
|
||||
style={{ width: '45%' }}
|
||||
>
|
||||
<DatePicker placeholder="请选择时间" inputReadOnly={true} format={"yyyy-MM-DD"} disabled={readOnly} style={{width:'100%'}} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||
{/* 合同计价方式,独占一行 */}
|
||||
<Form.Item
|
||||
name="valuationType"
|
||||
label="合同计价方式"
|
||||
rules={[{ required: true, message: '请选择合同计价方式' }]}
|
||||
style={{ width: '45%', marginRight: 16 }}
|
||||
>
|
||||
<Select placeholder="请选择" disabled={readOnly} onChange={onValuationTypeChange}>
|
||||
{pricingMethodOptions.map(({ label, value }) => (
|
||||
<Option key={value} value={value}>
|
||||
{label}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="vnote"
|
||||
label="备注"
|
||||
style={{ width: '45%' }}
|
||||
hidden={valuationType0}
|
||||
rules={[{ required: !valuationType0, message: '请填写备注' }]}
|
||||
>
|
||||
<Input placeholder="请输入备注" readOnly={readOnly}/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||
{/* 合同金额(CNY)和下拉选项 */}
|
||||
<Form.Item
|
||||
name="amount"
|
||||
label="合同金额(CNY) / 元"
|
||||
// labelCol={{span:6}}
|
||||
// wrapperCol={{span:18}}
|
||||
style={{ width: '45%'}}
|
||||
rules={[{ pattern: /^[0-9]+(\.[0-9]{1,2})?$/, message: '请输入正确的金额格式,最多保留两位小数' },
|
||||
{ validator: (_, value) => value > 0 ? Promise.resolve() : Promise.reject('金额必须大于0') }]}
|
||||
>
|
||||
<Input placeholder="" readOnly={readOnly}/>
|
||||
</Form.Item>
|
||||
{/*<Form.Item name="amountUnit" rules={[{ required: true, message: '请选合同金额单位' }]} initialValue={'0'} style={{ width: '5%',marginLeft:'20px'}}>*/}
|
||||
{/* <Select placeholder="请选择" disabled={readOnly}>*/}
|
||||
{/* {amountUnits.map(({ label, value }) => (*/}
|
||||
{/* <Option key={value} value={value}>*/}
|
||||
{/* {label}*/}
|
||||
{/* </Option>*/}
|
||||
{/* ))}*/}
|
||||
{/* </Select>*/}
|
||||
{/*</Form.Item>*/}
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||
{/* 付款方式和备注输入框 */}
|
||||
<Form.Item
|
||||
name="payType"
|
||||
label="付款方式"
|
||||
rules={[{ required: true, message: '请选择付款方式' }]}
|
||||
style={{ width: '45%', marginRight: 16 }}
|
||||
>
|
||||
<Select placeholder="请选择" onChange={ (value) => payTypeOnChange(value)} disabled={readOnly}>
|
||||
{paymentMethodOptions.map(({ label, value }) => (
|
||||
<Option key={value} value={value}>
|
||||
{label}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="note"
|
||||
label="备注"
|
||||
style={{ width: '45%' }}
|
||||
hidden={payType0}
|
||||
rules={[{ required: !payType0, message: '请填写备注' }]}
|
||||
>
|
||||
<Input placeholder="请输入备注" readOnly={readOnly}/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||
{/* 合同约定开始日期和合同约定结束日期 */}
|
||||
<Form.Item
|
||||
name="startDatetime"
|
||||
label="合同约定开始日期"
|
||||
rules={[{ required: true, message: '请选择合同约定开始日期' }]}
|
||||
style={{ width: '45%', marginRight: 16 }}
|
||||
>
|
||||
<DatePicker placeholder="请选择时间" format={"yyyy-MM-DD"} inputReadOnly={true} style={{width:'100%'}} onChange={ (date, dateString) =>{
|
||||
|
||||
}} disabled={readOnly}/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="endDatetime"
|
||||
label="合同约定结束日期"
|
||||
rules={[{ required: true, message: '请选择合同约定结束日期' }]}
|
||||
style={{ width: '45%' }}
|
||||
>
|
||||
<DatePicker placeholder="请选择时间" inputReadOnly={true} format={"yyyy-MM-DD"} disabled={readOnly} style={{width:'100%'}}/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||
{/* 履约地点和履约担保 */}
|
||||
<Form.Item
|
||||
name="performancePlace"
|
||||
label="履约地点"
|
||||
rules={[{ required: true, message: '请选择履约地点' }]}
|
||||
style={{ width: '45%', marginRight: 16 }}
|
||||
>
|
||||
<Select mode="multiple" placeholder="请选择" disabled={readOnly}>
|
||||
<Option value="beijing">北京市</Option>
|
||||
<Option value="shanghai">上海市</Option>
|
||||
<Option value="shenzhen">深圳市</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="guaranteeType"
|
||||
label="履约担保"
|
||||
rules={[{ required: true, message: '请选择履约担保' }]}
|
||||
style={{ width: '45%' }}
|
||||
>
|
||||
<Select placeholder="请选择" disabled={readOnly}>
|
||||
{guaranteeOptions.map(({ label, value }) => (
|
||||
<Option key={value} value={value}>
|
||||
{label}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
</div>
|
||||
<div hidden={isShow} style={{
|
||||
borderLeft: '4px solid #0066cc',
|
||||
paddingLeft: 16,
|
||||
marginBottom: 16,
|
||||
position: 'relative'
|
||||
}}>
|
||||
<span style={{ fontSize: 16, fontWeight: 'bold' }}>上传合同</span>
|
||||
</div>
|
||||
<div hidden={isShow} style={{ display: 'flex',marginLeft:30}}>
|
||||
<Upload
|
||||
name="file"
|
||||
// listType="simple"
|
||||
onChange={(info) => {
|
||||
console.log('Uploaded file info:', info);
|
||||
message.success('文件上传成功');
|
||||
}}
|
||||
>
|
||||
<label style={{left: 40, marginRight: 20}}>上传签章后合同: </label><Button type="primary">上传文件</Button>
|
||||
<p></p>
|
||||
<label style={{color: 'red'}}>支持格式:.rar .zip .doc .docx .pdf ,单个文件不能超过100MB</label>
|
||||
</Upload>
|
||||
</div>
|
||||
{/* 按钮部分 */}
|
||||
<div style={{ display: 'flex', justifyContent: 'center', marginTop: 24 }}>
|
||||
<Button type="primary" htmlType="submit" hidden={readOnly}>
|
||||
保存并提交
|
||||
</Button>
|
||||
<Button type="primary" style={{ marginLeft: 24 }} onClick={goNegotiatePage} hidden={!isShow}>
|
||||
下一步,合同磋商
|
||||
</Button>
|
||||
<Button type="primary" style={{ marginLeft: 24 }} onClick={goPerformancePage} hidden={isShow}>
|
||||
下一步,合同履约
|
||||
</Button>
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default StepTwo;
|
426
src/pages/Menu/MenuManagementPage.tsx
Normal file
426
src/pages/Menu/MenuManagementPage.tsx
Normal file
@ -0,0 +1,426 @@
|
||||
import React, {useState, useEffect} from 'react';
|
||||
import {Button, Form, Input, Select, Table, Modal, message, Popconfirm} from 'antd';
|
||||
import { DeleteOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
fetchMenuList,
|
||||
updateMenu,
|
||||
deleteMenu,
|
||||
createMenu
|
||||
} from "@/pages/Menu/MenuService";
|
||||
|
||||
const {Option} = Select;
|
||||
|
||||
// 模拟菜单数据结构
|
||||
type MenuItem = {
|
||||
id: number;
|
||||
menuId: number;
|
||||
key: number;
|
||||
menuName: string;
|
||||
parentId: number;
|
||||
orderNum: number;
|
||||
path: string;
|
||||
component: string;
|
||||
isFrame: number;
|
||||
isCache: number;
|
||||
menuType: 'M' | 'C' | 'F';
|
||||
visible: string;
|
||||
status: string;
|
||||
perms: string;
|
||||
icon: string;
|
||||
createBy: string;
|
||||
createTime: string;
|
||||
updateBy: string;
|
||||
updateTime: string;
|
||||
remark: string;
|
||||
children?: MenuItem[]; // 用于处理树结构
|
||||
};
|
||||
|
||||
// 模拟后端返回数据
|
||||
// @ts-ignore
|
||||
const mockMenuData: MenuItem[] = [];
|
||||
|
||||
const MenuManagement: React.FC = () => {
|
||||
const [form] = Form.useForm();
|
||||
const [folder, setFolder] = useState(false);
|
||||
const [btn, setBtn] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [menuList, setMenuList] = useState<MenuItem[]>([]);
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [editingItem, setEditingItem] = useState<MenuItem | null>(null);
|
||||
// const [status, setStatus] = useState('');
|
||||
const [searchMenuName, setSearchMenuName] = useState('');
|
||||
const [searchStatus, setSearchStatus] = useState('');
|
||||
const [expandedRowKeys, setExpandedRowKeys] = useState<string[]>([]);
|
||||
|
||||
const onExpand = (expanded: any, record: any) => {
|
||||
if (expanded) {
|
||||
setExpandedRowKeys([record.id]);
|
||||
} else {
|
||||
setExpandedRowKeys([]);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchMenu = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const result = await fetchMenuList({}); // 传递搜索参数
|
||||
setMenuList(result.data);
|
||||
} catch (error) {
|
||||
message.error('获取字典列表失败');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchMenu();
|
||||
}, [searchMenuName, searchStatus]);
|
||||
|
||||
// 处理编辑
|
||||
const handleEdit = (item: MenuItem) => {
|
||||
debugger;
|
||||
setEditingItem(item);
|
||||
form.setFieldsValue({
|
||||
id: item.menuId,
|
||||
parentId: item.parentId,
|
||||
// parentName: item.parentName,
|
||||
menuName: item.menuName,
|
||||
orderNum: item.orderNum,
|
||||
path: item.path,
|
||||
component: item.component,
|
||||
isFrame: item.isFrame,
|
||||
isCache: item.isCache,
|
||||
menuType: item.menuType,
|
||||
visible: item.visible,
|
||||
status: item.status,
|
||||
perms: item.perms,
|
||||
icon: item.icon,
|
||||
remark: item.remark,
|
||||
});
|
||||
setVisible(true);
|
||||
};
|
||||
|
||||
const handleDelete = async (menuItem: MenuItem) => {
|
||||
const id = menuItem.menuId;
|
||||
try {
|
||||
await deleteMenu(id); // 使用 `await` 等待删除接口完成
|
||||
message.success('删除成功');
|
||||
await fetchMenu(); // 调用已有的 `fetchMenu` 刷新数据
|
||||
} catch (error) {
|
||||
message.error('删除失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 处理新增子菜单
|
||||
const handleAddSub = (parentItem: MenuItem) => {
|
||||
setEditingItem({
|
||||
...parentItem,
|
||||
menuId: -1, // 临时标识新增项
|
||||
});
|
||||
form.setFieldsValue({
|
||||
id: null,
|
||||
menuName: '',
|
||||
orderNum: 0,
|
||||
path: '',
|
||||
component: '',
|
||||
isFrame: 1,
|
||||
isCache: 0,
|
||||
menuType: 'C',
|
||||
visible: '0',
|
||||
status: '0',
|
||||
perms: '',
|
||||
icon: '',
|
||||
remark: '',
|
||||
parentId: parentItem.menuId
|
||||
});
|
||||
setVisible(true);
|
||||
};
|
||||
// 表格列配置
|
||||
// @ts-ignore
|
||||
const columns: Table.ColumnType<MenuItem>[] = [
|
||||
{
|
||||
title: '菜单名称',
|
||||
dataIndex: 'menuName',
|
||||
key: 'menuName',
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'orderNum',
|
||||
key: 'orderNum',
|
||||
},
|
||||
{
|
||||
title: '权限标识',
|
||||
dataIndex: 'perms',
|
||||
key: 'perms',
|
||||
},
|
||||
{
|
||||
title: '组件路径',
|
||||
dataIndex: 'component',
|
||||
key: 'component',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
render: (text: string) => (text === '0' ? '正常' : '停用'),
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
key: 'createTime',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
render: (_: any, record: any) => (
|
||||
<div>
|
||||
<Button type="link" onClick={() => handleEdit(record)}>修改</Button>
|
||||
<Button type="link" onClick={() => handleAddSub(record)}>新增</Button>
|
||||
<Popconfirm
|
||||
title="确定要删除吗?"
|
||||
onConfirm={() => handleDelete(record)}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Button icon={<DeleteOutlined />} danger>
|
||||
删除
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
// 显示模态框
|
||||
const handleAdd = () => {
|
||||
setEditingItem(null);
|
||||
form.resetFields();
|
||||
setVisible(true);
|
||||
};
|
||||
|
||||
// 模态框确定按钮处理
|
||||
const handleOk = async () => {
|
||||
const values = await form.validateFields();
|
||||
debugger;
|
||||
if (editingItem) {
|
||||
if (editingItem.menuId === -1) {
|
||||
// 新增操作
|
||||
const newItem: MenuItem = {
|
||||
...values
|
||||
};
|
||||
await createMenu(newItem);
|
||||
message.success('创建成功');
|
||||
fetchMenu();
|
||||
} else {
|
||||
// 编辑操作
|
||||
const newItem: MenuItem = {
|
||||
...values
|
||||
};
|
||||
await updateMenu(newItem);
|
||||
message.success('修改成功');
|
||||
fetchMenu();
|
||||
}
|
||||
} else {
|
||||
await createMenu(values);
|
||||
message.success('创建成功');
|
||||
fetchMenu();
|
||||
}
|
||||
setVisible(false);
|
||||
};
|
||||
|
||||
// 模态框取消按钮处理
|
||||
const handleCancel = () => {
|
||||
setVisible(false);
|
||||
form.resetFields();
|
||||
};
|
||||
|
||||
// 搜索功能处理
|
||||
const handleSearch = () => {
|
||||
const filteredData = menuList.filter(item => {
|
||||
const nameMatch = item.menuName.includes(searchMenuName);
|
||||
const statusMatch = searchStatus === '' || item.status === searchStatus;
|
||||
return nameMatch && statusMatch;
|
||||
});
|
||||
setMenuList(filteredData);
|
||||
};
|
||||
|
||||
// 重置搜索功能处理
|
||||
const handleReset = () => {
|
||||
setSearchMenuName('');
|
||||
setSearchStatus('');
|
||||
setMenuList(mockMenuData);
|
||||
};
|
||||
|
||||
const handleMenuTypeChange = (value: string) => {
|
||||
if (value == 'M') {
|
||||
setFolder(true)
|
||||
setBtn(false)
|
||||
} else if (value == 'F') {
|
||||
setBtn(true)
|
||||
setFolder(false)
|
||||
} else {
|
||||
setFolder(false)
|
||||
setBtn(false)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// @ts-ignore
|
||||
return (
|
||||
<div style={{padding: '16px'}}>
|
||||
<Form form={form} layout="inline" style={{marginBottom: '16px'}}>
|
||||
<Form.Item
|
||||
name="menuName"
|
||||
label="菜单名称"
|
||||
>
|
||||
<Input
|
||||
placeholder="请输入菜单名称"
|
||||
onChange={(e) => setSearchMenuName(e.target.value)}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="status"
|
||||
label="状态"
|
||||
>
|
||||
<Select
|
||||
placeholder="菜单状态"
|
||||
onChange={(value: any) => setSearchStatus(value)}
|
||||
>
|
||||
<Option value="">全部</Option>
|
||||
<Option value="0">正常</Option>
|
||||
<Option value="1">停用</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Button type="primary" onClick={handleSearch}>搜索</Button>
|
||||
<Button type="link" onClick={handleReset}>重置</Button>
|
||||
</Form>
|
||||
<Button
|
||||
type="primary"
|
||||
style={{marginBottom: '8px'}}
|
||||
onClick={handleAdd}
|
||||
>新增</Button>
|
||||
<Table
|
||||
loading={loading}
|
||||
rowKey={record => record.id}
|
||||
dataSource={menuList}
|
||||
columns={columns}
|
||||
expandable={{
|
||||
expandedRowKeys,
|
||||
onExpand,
|
||||
}}>
|
||||
</Table>
|
||||
<Modal
|
||||
title={editingItem && editingItem.id === -1 ? '新增菜单' : '修改菜单'}
|
||||
visible={visible}
|
||||
onOk={handleOk}
|
||||
onCancel={handleCancel}
|
||||
>
|
||||
<Form form={form}>
|
||||
<Form.Item
|
||||
name="id"
|
||||
hidden={true}
|
||||
>
|
||||
</Form.Item>
|
||||
<Form.Item name="parentId" hidden={true}></Form.Item>
|
||||
<Form.Item
|
||||
name="menuType"
|
||||
label="菜单类型"
|
||||
rules={[{required: true, message: '请选择菜单类型'}]}
|
||||
>
|
||||
<Select placeholder="请选择" onChange={handleMenuTypeChange}>
|
||||
<Option value="M">目录</Option>
|
||||
<Option value="C">菜单</Option>
|
||||
<Option value="F">按钮</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="menuName"
|
||||
label="菜单名称"
|
||||
rules={[{required: true, message: '请输入菜单名称'}]}
|
||||
>
|
||||
<Input placeholder="请输入菜单名称"/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="orderNum"
|
||||
label="排序"
|
||||
rules={[{required: true, message: '请输入排序'}]}
|
||||
>
|
||||
<Input placeholder="请输入排序"/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="isFrame"
|
||||
label="是否为外链"
|
||||
hidden={btn}
|
||||
rules={[{type: 'number', message: '请输入正确的数值'}]}
|
||||
>
|
||||
<Select placeholder="请选择" defaultValue={1}>
|
||||
<Option value={0}>是</Option>
|
||||
<Option value={1}>否</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="path"
|
||||
label="路由地址"
|
||||
hidden={btn}
|
||||
>
|
||||
<Input placeholder="请输入路由地址"/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="query"
|
||||
label="路由参数"
|
||||
hidden={folder || btn}
|
||||
>
|
||||
<Input placeholder="请输入路由参数"/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="component"
|
||||
label="组件路径"
|
||||
hidden={folder || btn}
|
||||
>
|
||||
<Input placeholder="请输入组件路径"/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="perms"
|
||||
label="权限标识"
|
||||
hidden={folder && !btn}
|
||||
>
|
||||
<Input placeholder="请输入权限标识"/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="isCache"
|
||||
label="是否缓存"
|
||||
hidden={folder || btn}
|
||||
rules={[{type: 'number', message: '请输入正确的数值'}]}
|
||||
>
|
||||
<Select placeholder="请选择" defaultValue={0}>
|
||||
<Option value={0}>缓存</Option>
|
||||
<Option value={1}>不缓存</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="visible"
|
||||
label="显示状态(显示/隐藏)"
|
||||
hidden={btn}
|
||||
rules={[{required: true, message: '请选择显示状态'}]}
|
||||
>
|
||||
<Select placeholder="请选择" defaultValue="0">
|
||||
<Option value="0">显示</Option>
|
||||
<Option value="1">隐藏</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="status"
|
||||
label="菜单状态(正常/停用)"
|
||||
>
|
||||
<Select placeholder="请选择" defaultValue="0">
|
||||
<Option value="0">正常</Option>
|
||||
<Option value="1">停用</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MenuManagement;
|
31
src/pages/Menu/MenuService.ts
Normal file
31
src/pages/Menu/MenuService.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import request from "@/utils/request";
|
||||
|
||||
|
||||
const prefix = '/api/sys-manager-ebtp-project/';
|
||||
|
||||
export async function fetchMenuList(params: any) {
|
||||
return request(prefix + 'v1/menu/treeselect', {
|
||||
params: params,
|
||||
method: 'GET'
|
||||
});
|
||||
}
|
||||
|
||||
export async function createMenu(params: any) {
|
||||
return request(prefix + 'v1/menu', {
|
||||
data: params,
|
||||
method: 'POST'
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateMenu(params: any) {
|
||||
return request(prefix + 'v1/menu', {
|
||||
data: params,
|
||||
method: 'PUT'
|
||||
});
|
||||
}
|
||||
|
||||
export async function deleteMenu(param: any) {
|
||||
return request(prefix + 'v1/menu/delete/' + param, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user