2026-03-26 06:55:12 +00:00
|
|
|
import React, { useState, useEffect } from 'react';
|
|
|
|
|
import { Drawer, Form, Input, Button, DatePicker, Select, Space, App } from 'antd';
|
|
|
|
|
import { SaveOutlined } from '@ant-design/icons';
|
|
|
|
|
import dayjs from 'dayjs';
|
|
|
|
|
import apiClient from '../utils/apiClient';
|
|
|
|
|
import { buildApiUrl, API_ENDPOINTS } from '../config/api';
|
|
|
|
|
|
|
|
|
|
const { TextArea } = Input;
|
|
|
|
|
|
2026-03-27 07:43:08 +00:00
|
|
|
const MeetingFormDrawer = ({ open, onClose, onSuccess, meetingId = null }) => {
|
2026-03-26 06:55:12 +00:00
|
|
|
const { message } = App.useApp();
|
|
|
|
|
const [form] = Form.useForm();
|
|
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
|
const [fetching, setFetching] = useState(false);
|
|
|
|
|
const [users, setUsers] = useState([]);
|
|
|
|
|
const [prompts, setPrompts] = useState([]);
|
|
|
|
|
|
|
|
|
|
const isEdit = Boolean(meetingId);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (!open) return;
|
|
|
|
|
fetchOptions();
|
|
|
|
|
if (isEdit) {
|
|
|
|
|
fetchMeeting();
|
|
|
|
|
} else {
|
|
|
|
|
form.resetFields();
|
|
|
|
|
form.setFieldsValue({ meeting_time: dayjs() });
|
|
|
|
|
}
|
|
|
|
|
}, [open, meetingId]);
|
|
|
|
|
|
|
|
|
|
const fetchOptions = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const [uRes, pRes] = await Promise.all([
|
|
|
|
|
apiClient.get(buildApiUrl(API_ENDPOINTS.USERS.LIST)),
|
|
|
|
|
apiClient.get(buildApiUrl(API_ENDPOINTS.PROMPTS.ACTIVE('MEETING_TASK'))),
|
|
|
|
|
]);
|
|
|
|
|
setUsers(uRes.data.users || []);
|
|
|
|
|
setPrompts(pRes.data.prompts || []);
|
|
|
|
|
} catch {}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const fetchMeeting = async () => {
|
|
|
|
|
setFetching(true);
|
|
|
|
|
try {
|
|
|
|
|
const res = await apiClient.get(buildApiUrl(API_ENDPOINTS.MEETINGS.DETAIL(meetingId)));
|
|
|
|
|
const meeting = res.data;
|
|
|
|
|
form.setFieldsValue({
|
|
|
|
|
title: meeting.title,
|
|
|
|
|
meeting_time: dayjs(meeting.meeting_time),
|
2026-03-27 07:43:08 +00:00
|
|
|
attendee_ids: meeting.attendee_ids || meeting.attendees?.map((a) => a.user_id).filter(Boolean) || [],
|
2026-03-26 06:55:12 +00:00
|
|
|
prompt_id: meeting.prompt_id,
|
|
|
|
|
tags: meeting.tags?.map((t) => t.name) || [],
|
|
|
|
|
description: meeting.description,
|
|
|
|
|
});
|
|
|
|
|
} catch {
|
|
|
|
|
message.error('加载会议数据失败');
|
|
|
|
|
} finally {
|
|
|
|
|
setFetching(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleSubmit = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const values = await form.validateFields();
|
|
|
|
|
setLoading(true);
|
|
|
|
|
const payload = {
|
|
|
|
|
...values,
|
|
|
|
|
meeting_time: values.meeting_time.format('YYYY-MM-DD HH:mm:ss'),
|
2026-03-27 07:43:08 +00:00
|
|
|
attendee_ids: values.attendee_ids || [],
|
2026-03-26 06:55:12 +00:00
|
|
|
tags: values.tags?.join(',') || '',
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (isEdit) {
|
|
|
|
|
await apiClient.put(buildApiUrl(API_ENDPOINTS.MEETINGS.UPDATE(meetingId)), payload);
|
|
|
|
|
message.success('会议更新成功');
|
|
|
|
|
} else {
|
|
|
|
|
const res = await apiClient.post(buildApiUrl(API_ENDPOINTS.MEETINGS.CREATE), payload);
|
|
|
|
|
if (res.code === '200') {
|
|
|
|
|
message.success('会议创建成功');
|
|
|
|
|
onSuccess?.(res.data.meeting_id);
|
|
|
|
|
onClose();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
onSuccess?.();
|
|
|
|
|
onClose();
|
|
|
|
|
} catch (error) {
|
|
|
|
|
if (!error?.errorFields) {
|
2026-03-27 07:43:08 +00:00
|
|
|
message.error(error?.response?.data?.message || error?.response?.data?.detail || '操作失败');
|
2026-03-26 06:55:12 +00:00
|
|
|
}
|
|
|
|
|
} finally {
|
|
|
|
|
setLoading(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Drawer
|
|
|
|
|
title={isEdit ? '编辑会议' : '新建会议'}
|
|
|
|
|
placement="right"
|
|
|
|
|
width={560}
|
|
|
|
|
open={open}
|
|
|
|
|
onClose={onClose}
|
|
|
|
|
destroyOnClose
|
|
|
|
|
extra={
|
|
|
|
|
<Space>
|
|
|
|
|
<Button type="primary" icon={<SaveOutlined />} loading={loading} onClick={handleSubmit}>
|
|
|
|
|
{isEdit ? '保存修改' : '创建会议'}
|
|
|
|
|
</Button>
|
|
|
|
|
</Space>
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
<Form form={form} layout="vertical" initialValues={{ meeting_time: dayjs() }}>
|
|
|
|
|
<Form.Item label="会议主题" name="title" rules={[{ required: true, message: '请输入会议主题' }]}>
|
|
|
|
|
<Input placeholder="请输入会议主题..." />
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
<Form.Item label="开始时间" name="meeting_time" rules={[{ required: true }]}>
|
|
|
|
|
<DatePicker showTime style={{ width: '100%' }} />
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
<Form.Item label="使用总结模板" name="prompt_id">
|
|
|
|
|
<Select allowClear placeholder="选择总结模版">
|
|
|
|
|
{prompts.map((p) => (
|
|
|
|
|
<Select.Option key={p.id} value={p.id}>{p.name}</Select.Option>
|
|
|
|
|
))}
|
|
|
|
|
</Select>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
2026-03-27 07:43:08 +00:00
|
|
|
<Form.Item label="参会人员" name="attendee_ids" rules={[{ required: true, message: '请选择参会人员' }]}>
|
2026-03-26 06:55:12 +00:00
|
|
|
<Select mode="multiple" placeholder="选择参会人">
|
|
|
|
|
{users.map((u) => (
|
2026-03-27 07:43:08 +00:00
|
|
|
<Select.Option key={u.user_id} value={u.user_id}>{u.caption}</Select.Option>
|
2026-03-26 06:55:12 +00:00
|
|
|
))}
|
|
|
|
|
</Select>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
<Form.Item label="标签" name="tags">
|
|
|
|
|
<Select mode="tags" placeholder="输入标签按回车" />
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
<Form.Item label="会议备注" name="description">
|
|
|
|
|
<TextArea rows={3} placeholder="添加会议背景或说明..." />
|
|
|
|
|
</Form.Item>
|
|
|
|
|
</Form>
|
|
|
|
|
</Drawer>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default MeetingFormDrawer;
|