296 lines
9.3 KiB
TypeScript
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;
|