Files
yunhaifinance/temp-clone/frontend/src/pages/budget/BudgetProjectCreate.tsx
T

296 lines
9.3 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { Card, Typography, Button, Form, Input, Select, DatePicker, InputNumber, Radio, Space, message, Divider, Row, Col } from 'antd';
import { SaveOutlined, ArrowLeftOutlined } from '@ant-design/icons';
import { useNavigate } from 'react-router-dom';
import axios from 'axios';
import dayjs from 'dayjs';
import FileUpload from '../../components/FileUpload';
import { useAuthStore } from '../../store/authStore';
const { Title, Paragraph } = Typography;
const { Option } = Select;
const { TextArea } = Input;
interface Customer {
id: number;
name: string;
}
interface User {
id: number;
name: string;
department?: string;
}
const BudgetProjectCreate: React.FC = () => {
const [isMobile, setIsMobile] = useState(false);
const [loading, setLoading] = useState(false);
const [customers, setCustomers] = useState<Customer[]>([]);
const [users, setUsers] = useState<User[]>([]);
const [form] = Form.useForm();
const [attachments, setAttachments] = useState<string[]>([]);
const [surveyPhotos, setSurveyPhotos] = useState<string[]>([]);
const navigate = useNavigate();
const { user: currentUser } = useAuthStore();
const isAdmin = currentUser?.role === 'admin';
// 检查权限,如果不是管理员,重定向到列表页面
useEffect(() => {
if (!isAdmin) {
message.error('您没有权限访问此页面');
navigate('/budget-projects');
}
}, [isAdmin, navigate]);
// const { user: currentUser } = useAuthStore();
// 表单监听值
const intermediaryFeeType = Form.useWatch('intermediary_fee_type', form);
useEffect(() => {
const checkMobile = () => setIsMobile(window.innerWidth <= 768);
checkMobile();
window.addEventListener('resize', checkMobile);
return () => window.removeEventListener('resize', checkMobile);
}, []);
useEffect(() => {
fetchCustomers();
fetchUsers();
}, []);
const fetchCustomers = async () => {
try {
const res = await axios.get('/api/customers');
if (res.data.success) setCustomers(res.data.data);
} catch (error) {
console.error('获取客户列表失败:', error);
}
};
const fetchUsers = async () => {
try {
const res = await axios.get('/api/users');
if (res.data.success) setUsers(res.data.data);
} catch (error) {
console.error('获取用户列表失败:', error);
}
};
const handleSubmit = async () => {
try {
const values = await form.validateFields();
setLoading(true);
const projectData = {
...values,
attachments,
survey_photos: surveyPhotos,
survey_date: values.survey_date?.format('YYYY-MM-DD'),
status: 'negotiating',
};
const res = await axios.post('/api/budget-projects', projectData, {
headers: {
'x-user-role': 'admin' // 创建预算项目需要管理员权限
}
});
if (res.data.success) {
message.success('创建成功');
navigate('/budget-projects');
}
} catch (error: any) {
if (error.response?.data?.error) {
message.error(error.response.data.error);
} else {
message.error('创建失败');
}
} finally {
setLoading(false);
}
};
return (
<div style={{ padding: isMobile ? 8 : 24 }}>
<div style={{ marginBottom: isMobile ? 12 : 24 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 16, marginBottom: 8 }}>
<Button
icon={<ArrowLeftOutlined />}
onClick={() => navigate('/budget-projects')}
>
返回
</Button>
<Title level={isMobile ? 3 : 2} style={{ marginBottom: 0 }}>新建商谈项目</Title>
</div>
<Paragraph type="secondary">创建新的商谈项目,添加项目基本信息</Paragraph>
</div>
<Card>
<Form
form={form}
layout="vertical"
initialValues={{
intermediary_fee_type: 'fixed',
survey_date: dayjs(), // 勘察日期默认为当天
attachments: [],
survey_photos: []
}}
>
{/* 基本信息 */}
<Divider orientation="left">基本信息</Divider>
<Row gutter={16}>
<Col xs={24} md={12}>
<Form.Item
name="name"
label="项目名称"
rules={[{ required: true, message: '请输入项目名称' }]}
>
<Input placeholder="请输入项目名称" size="large" />
</Form.Item>
</Col>
<Col xs={24} md={12}>
<Form.Item
name="customer_id"
label="客户"
rules={[{ required: true, message: '请选择客户' }]}
>
<Select
placeholder="请选择客户"
showSearch
optionFilterProp="children"
size="large"
>
{customers.map((c) => (
<Option key={c.id} value={c.id}>{c.name}</Option>
))}
</Select>
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col xs={24} md={12}>
<Form.Item
name="manager_id"
label="业务经理"
rules={[{ required: true, message: '请选择业务经理' }]}
>
<Select
placeholder="请选择业务经理"
showSearch
optionFilterProp="children"
size="large"
>
{users.map((u) => (
<Option key={u.id} value={u.id}>{u.name} ({u.department || '未知部门'})</Option>
))}
</Select>
</Form.Item>
</Col>
<Col xs={24} md={12}>
<Form.Item name="location" label="项目地点">
<Input placeholder="请输入项目地点" size="large" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col xs={24} md={12}>
<Form.Item name="survey_date" label="勘察日期">
<DatePicker style={{ width: '100%' }} size="large" />
</Form.Item>
</Col>
</Row>
{/* 居间人信息 */}
<Divider orientation="left">居间人信息</Divider>
<Row gutter={16}>
<Col xs={24} md={8}>
<Form.Item name="intermediary" label="居间人">
<Input placeholder="请输入居间人姓名" size="large" />
</Form.Item>
</Col>
<Col xs={24} md={8}>
<Form.Item name="intermediary_fee_type" label="居间费类型">
<Radio.Group>
<Radio value="fixed">固定金额</Radio>
<Radio value="percentage">百分比</Radio>
</Radio.Group>
</Form.Item>
</Col>
<Col xs={24} md={8}>
<Form.Item
name="intermediary_fee_value"
label={intermediaryFeeType === 'percentage' ? '居间费比例(%)' : '居间费金额'}
>
<InputNumber
style={{ width: '100%' }}
size="large"
min={0}
precision={intermediaryFeeType === 'percentage' ? 2 : 0}
placeholder={intermediaryFeeType === 'percentage' ? '输入比例,如:5' : '输入金额'}
/>
</Form.Item>
</Col>
</Row>
{/* 项目详情 */}
<Divider orientation="left">项目详情</Divider>
<Form.Item name="customer_requirements" label="客户要求">
<TextArea rows={4} placeholder="请输入客户的具体要求" />
</Form.Item>
<Form.Item name="project_overview" label="工程概况">
<TextArea rows={4} placeholder="请输入工程概况描述" />
</Form.Item>
{/* 附件上传 */}
<Divider orientation="left">附件</Divider>
<Row gutter={16}>
<Col xs={24} md={12}>
<Form.Item label="附件上传">
<FileUpload
value={attachments}
onChange={setAttachments}
accept=".pdf,.doc,.docx,.jpg,.jpeg,.png,.xlsx,.xls"
/>
</Form.Item>
</Col>
<Col xs={24} md={12}>
<Form.Item label="勘察照片">
<FileUpload
value={surveyPhotos}
onChange={setSurveyPhotos}
accept="image/*"
/>
</Form.Item>
</Col>
</Row>
{/* 提交按钮 */}
<div style={{ marginTop: 24, textAlign: 'right' }}>
<Space>
<Button onClick={() => navigate('/budget-projects')}>取消</Button>
<Button
type="primary"
icon={<SaveOutlined />}
loading={loading}
onClick={handleSubmit}
>
保存
</Button>
</Space>
</div>
</Form>
</Card>
</div>
);
};
export default BudgetProjectCreate;