Files
manage/src/pages/company/task/detail/index.jsx
liamzi 73f8033183 fix
2024-12-31 14:25:51 +08:00

421 lines
12 KiB
JavaScript

import React, { useState, useEffect, useMemo } from "react";
import {
Form,
Input,
Select,
Button,
Space,
Card,
Typography,
message,
DatePicker,
} from "antd";
import {
ArrowLeftOutlined,
SaveOutlined,
} from "@ant-design/icons";
import { supabase } from "@/config/supabase";
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
import { v4 as uuidv4 } from "uuid";
import TaskList from '@/components/TaskList';
import dayjs from 'dayjs';
import {supabaseService} from '@/hooks/supabaseService'
const { Title } = Typography;
const TYPE = "task";
export default function TaskForm() {
const { id } = useParams();
const [searchParams] = useSearchParams();
const isEdit = searchParams.get("edit") === "true";
const templateId = searchParams.get("templateId");
const isView = id && !isEdit;
const [form] = Form.useForm();
const navigate = useNavigate();
const [loading, setLoading] = useState(false);
const [customers, setCustomers] = useState([]);
const [formValues, setFormValues] = useState({});
const [units, setUnits] = useState([]);
const [loadingUnits,setLoadingUnits]=useState(false)
const fetchUnits = async () => {
setLoadingUnits(true);
try {
const { data: units } = await supabaseService.select("resources", {
filter: {
type: { eq: "units" },
"attributes->>template_type": { in: `(${TYPE})` },
},
order: {
column: "created_at",
ascending: false,
},
});
setUnits(units || []);
} catch (error) {
message.error("获取单位列表失败");
console.error(error);
} finally {
setLoadingUnits(false);
}
};
useEffect(() => {
fetchUnits();
}, []);
const initialValues = {
sections: [
{
key: uuidv4(),
sectionName: "任务类型 1",
items: [
{
key: uuidv4(),
name: "",
description: "",
timeRange: null,
unit: "未开始",
},
],
},
],
status: "未开始",
timeRange: null,
};
// 处理表单值变化
const handleValuesChange = (changedValues, allValues) => {
setFormValues(allValues);
};
// 获取任务详情
const fetchTaskDetail = async () => {
try {
setLoading(true);
const { data, error } = await supabase
.from("resources")
.select("*")
.eq("id", id)
.single();
if (error) throw error;
if (data?.attributes) {
const formData = {
taskName: data.attributes.taskName,
customers: data.attributes.customers.map((customer) => customer.id) || [],
description: data.attributes.description,
sections: data.attributes.sections.map((section) => ({
key: uuidv4(),
sectionName: section.sectionName,
items: section.items.map((item) => ({
key: uuidv4(),
name: item.name,
description: item.description || "",
timeRange: item.timeRange,
unit: item.unit || "未开始",
})),
})),
status: data.attributes.status || "未开始",
timeRange: data.attributes.timeRange
? [dayjs(data.attributes.timeRange[0]), dayjs(data.attributes.timeRange[1])]
: null,
};
form.setFieldsValue(formData);
setFormValues(formData);
}
} catch (error) {
console.error("获取任务详情失败:", error);
message.error("获取任务详情失败");
} finally {
setLoading(false);
}
};
// 获取模板数据
const fetchTemplateData = async () => {
try {
setLoading(true);
const { data: template, error } = await supabase
.from("resources")
.select("*")
.eq("type", "serviceTemplate")
.eq("id", templateId)
.single();
if (error) throw error;
if (template?.attributes) {
const taskData = {
taskName: template.attributes.templateName,
description: template.attributes.description,
sections: template.attributes.sections.map((section) => ({
key: uuidv4(),
sectionName: section.sectionName,
items: section.items.map((item) => ({
key: uuidv4(),
name: item.name,
description: item.description,
timeRange: null,
unit: "未开始",
})),
})),
};
form.setFieldsValue(taskData);
setFormValues(taskData);
}
} catch (error) {
console.error("获取模板数据失败:", error);
message.error("获取模板数据失败");
} finally {
setLoading(false);
}
};
// 获取客户列表
const fetchCustomers = async () => {
try {
const { data, error } = await supabase
.from("resources")
.select("*")
.eq("type", "customer");
if (error) throw error;
setCustomers(data || []);
} catch (error) {
console.error("获取客户列表失败:", error);
}
};
// 保存任务
const onFinish = async (values) => {
try {
setLoading(true);
const taskData = {
type: "task",
attributes: {
taskName: values.taskName,
customers: customers
.filter(customer => values.customers.includes(customer.id))
.map(customer => ({
id: customer.id,
name: customer.attributes.name
})),
description: values.description,
sections: values.sections.map((section) => ({
sectionName: section.sectionName,
items: section.items.map((item) => ({
name: item.name,
description: item.description,
timeRange: item.timeRange,
unit: item.unit,
})),
})),
status: values.status,
timeRange: values.timeRange
? [
values.timeRange[0].format('YYYY-MM-DD'),
values.timeRange[1].format('YYYY-MM-DD')
]
: null,
},
};
let result;
if (id) {
result = await supabase
.from("resources")
.update(taskData)
.eq("id", id)
.select();
} else {
result = await supabase
.from("resources")
.insert([taskData])
.select();
}
if (result.error) throw result.error;
message.success("保存成功");
navigate("/company/task");
} catch (error) {
console.error("保存失败:", error);
message.error("保存失败");
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchCustomers();
}, []);
useEffect(() => {
if (id) {
fetchTaskDetail();
} else if (templateId) {
fetchTemplateData();
} else {
form.setFieldsValue(initialValues);
setFormValues(initialValues);
}
}, [id, templateId]);
return (
<div className="bg-gradient-to-b from-gray-50 to-white dark:from-gray-800 dark:to-gray-900/90 min-h-screen p-2">
<Card
className="shadow-lg rounded-lg border-0"
title={
<div className="flex justify-between items-center py-2">
<div className="flex items-center space-x-3">
<Title level={4} className="mb-0 text-gray-800">
{id ? (isEdit ? "编辑任务" : "查看任务") : "新建任务"}
</Title>
<span className="text-gray-400 text-sm">
{id
? isEdit
? "请修改任务信息"
: "任务详情"
: "请填写任务信息"}
</span>
</div>
<Space size="middle">
<Button
icon={<ArrowLeftOutlined />}
onClick={() => navigate("/company/task")}
>
返回
</Button>
{!isView && (
<Button
type="primary"
icon={<SaveOutlined />}
onClick={() => form.submit()}
loading={loading}
>
保存
</Button>
)}
</Space>
</div>
}
>
<Form
form={form}
onFinish={onFinish}
onValuesChange={handleValuesChange}
layout="vertical"
disabled={isView}
initialValues={initialValues}
>
<Card
className="shadow-sm rounded-lg"
type="inner"
title={
<span className="flex items-center space-x-2 text-gray-700">
<span className="w-1 h-4 bg-blue-500 rounded-full" />
<span>基本信息</span>
</span>
}
bordered={false}
>
<div className="grid grid-cols-2 gap-8">
<Form.Item
name="taskName"
label={<span className="text-gray-700 font-medium">任务名称</span>}
rules={[{ required: true, message: "请输入任务名称" }]}
>
<Input
placeholder="请输入任务名称"
className=" hover:border-blue-400 focus:border-blue-500"
/>
</Form.Item>
<Form.Item
name="customers"
label={<span className="text-gray-700 font-medium">客户名称</span>}
rules={[{ required: true, message: "请选择至少一个客户" }]}
>
<Select
mode="multiple"
placeholder="请选择客户"
className=" hover:border-blue-400 focus:border-blue-500"
showSearch
optionFilterProp="children"
filterOption={(input, option) =>
(option?.label ?? "").toLowerCase().includes(input.toLowerCase())
}
options={customers.map((customer) => ({
value: customer.id,
label: customer.attributes.name,
}))}
/>
</Form.Item>
<Form.Item
name="status"
label={<span className="text-gray-700 font-medium">任务状态</span>}
rules={[{ required: true, message: "请选择任务状态" }]}
>
<Select
allowClear
loading={loadingUnits}
placeholder="请选择任务状态"
className=" hover:border-blue-400 focus:border-blue-500"
options={units.map((unit) => ({
label: unit.attributes.name,
value: unit.attributes.name,
}))}
/>
</Form.Item>
<Form.Item
name="timeRange"
label={<span className="text-gray-700 font-medium">时间范围</span>}
rules={[{ required: true, message: "请选择时间范围" }]}
>
<DatePicker.RangePicker
className="w-full hover:border-blue-400 focus:border-blue-500"
format="YYYY-MM-DD"
onChange={(dates) => {
if (dates) {
form.setFieldValue('timeRange', [
dayjs(dates[0]),
dayjs(dates[1])
]);
} else {
form.setFieldValue('timeRange', null);
}
}}
/>
</Form.Item>
</div>
</Card>
<Card
className="shadow-sm rounded-lg mt-6"
type="inner"
title={
<span className="flex items-center space-x-2 text-gray-700">
<span className="w-1 h-4 bg-blue-500 rounded-full" />
<span>任务流程</span>
</span>
}
bordered={false}
>
<TaskList
type={TYPE}
form={form}
isView={isView}
formValues={formValues}
onValuesChange={handleValuesChange}
/>
</Card>
</Form>
</Card>
</div>
);
}