task
This commit is contained in:
@@ -26,7 +26,8 @@
|
||||
"react-infinite-scroll-component": "^6.1.0",
|
||||
"react-router-dom": "^6.18.0",
|
||||
"recharts": "^2.9.0",
|
||||
"styled-components": "^6.1.0"
|
||||
"styled-components": "^6.1.0",
|
||||
"uuid": "^11.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.15",
|
||||
@@ -42,4 +43,4 @@
|
||||
"tailwindcss": "^3.3.5",
|
||||
"vite": "^4.4.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,122 +1,134 @@
|
||||
import { lazy } from 'react';
|
||||
import { lazy } from "react";
|
||||
|
||||
// Dashboard route
|
||||
const dashboardRoute = {
|
||||
path: 'dashboard',
|
||||
component: lazy(() => import('@/pages/Dashboard')),
|
||||
name: '仪表盘',
|
||||
icon: 'dashboard',
|
||||
path: "dashboard",
|
||||
component: lazy(() => import("@/pages/Dashboard")),
|
||||
name: "仪表盘",
|
||||
icon: "dashboard",
|
||||
};
|
||||
|
||||
// Resource Management routes
|
||||
const resourceRoutes = [
|
||||
{
|
||||
path: 'team',
|
||||
component: lazy(() => import('@/pages/resource/team')),
|
||||
name: '团队管理',
|
||||
icon: 'team',
|
||||
path: "team",
|
||||
component: lazy(() => import("@/pages/resource/team")),
|
||||
name: "团队管理",
|
||||
icon: "team",
|
||||
},
|
||||
{
|
||||
path: 'bucket',
|
||||
component: lazy(() => import('@/pages/resource/bucket')),
|
||||
name: '对象存储',
|
||||
icon: 'shop',
|
||||
path: "bucket",
|
||||
component: lazy(() => import("@/pages/resource/bucket")),
|
||||
name: "对象存储",
|
||||
icon: "shop",
|
||||
},
|
||||
{
|
||||
path: "task",
|
||||
component: lazy(() => import("@/pages/resource/resourceTask")),
|
||||
name: "任务管理",
|
||||
icon: "appstore",
|
||||
},
|
||||
{
|
||||
path: "task/edit/:id?",
|
||||
component: lazy(() => import("@/pages/resource/resourceTask/edit")),
|
||||
hidden: true,
|
||||
name: "新增/编辑任务",
|
||||
},
|
||||
];
|
||||
|
||||
// Company routes
|
||||
const companyRoutes = [
|
||||
{
|
||||
path: 'quotation',
|
||||
component: lazy(() => import('@/pages/company/quotation')),
|
||||
name: '报价单',
|
||||
icon: 'file',
|
||||
}, {
|
||||
path: 'quotaInfo/:id?', // 添加可选的 id 参数
|
||||
path: "quotation",
|
||||
component: lazy(() => import("@/pages/company/quotation")),
|
||||
name: "报价单",
|
||||
icon: "file",
|
||||
},
|
||||
{
|
||||
path: "quotaInfo/:id?", // 添加可选的 id 参数
|
||||
hidden: true,
|
||||
component: lazy(() => import('@/pages/company/quotation/detail')),
|
||||
name: '报价单详情',
|
||||
icon: 'file',
|
||||
component: lazy(() => import("@/pages/company/quotation/detail")),
|
||||
name: "报价单详情",
|
||||
icon: "file",
|
||||
},
|
||||
{
|
||||
path: 'serviceTeamplate',
|
||||
component: lazy(() => import('@/pages/company/service')),
|
||||
name: '服务管理',
|
||||
icon: 'container',
|
||||
path: "serviceTeamplate",
|
||||
component: lazy(() => import("@/pages/company/service")),
|
||||
name: "服务管理",
|
||||
icon: "container",
|
||||
},
|
||||
{
|
||||
path: 'serviceType',
|
||||
path: "serviceType",
|
||||
hidden: true,
|
||||
component: lazy(() => import('@/pages/company/service/serviceType')),
|
||||
name: '类型管理',
|
||||
icon: 'container',
|
||||
component: lazy(() => import("@/pages/company/service/serviceType")),
|
||||
name: "类型管理",
|
||||
icon: "container",
|
||||
},
|
||||
{
|
||||
path: 'serviceTemplateInfo/:id?',
|
||||
path: "serviceTemplateInfo/:id?",
|
||||
hidden: true,
|
||||
component: lazy(() => import('@/pages/company/service/detail')),
|
||||
name: '服务模版详情',
|
||||
icon: 'container',
|
||||
component: lazy(() => import("@/pages/company/service/detail")),
|
||||
name: "服务模版详情",
|
||||
icon: "container",
|
||||
},
|
||||
{
|
||||
path: 'quotaInfo/preview/:id?', // 添加可选的 id 参数
|
||||
path: "quotaInfo/preview/:id?", // 添加可选的 id 参数
|
||||
hidden: true,
|
||||
component: lazy(() => import('@/pages/company/quotation/view')),
|
||||
name: '报价单预览',
|
||||
icon: 'file',
|
||||
component: lazy(() => import("@/pages/company/quotation/view")),
|
||||
name: "报价单预览",
|
||||
icon: "file",
|
||||
},
|
||||
{
|
||||
path: 'customer',
|
||||
component: lazy(() => import('@/pages/company/customer')),
|
||||
name: '客户管理',
|
||||
icon: 'user',
|
||||
path: "customer",
|
||||
component: lazy(() => import("@/pages/company/customer")),
|
||||
name: "客户管理",
|
||||
icon: "user",
|
||||
},
|
||||
{
|
||||
path: 'customerInfo/:id?',
|
||||
path: "customerInfo/:id?",
|
||||
hidden: true,
|
||||
component: lazy(() => import('@/pages/company/customer/detail')),
|
||||
name: '客户详情',
|
||||
icon: 'user',
|
||||
component: lazy(() => import("@/pages/company/customer/detail")),
|
||||
name: "客户详情",
|
||||
icon: "user",
|
||||
},
|
||||
{
|
||||
path: 'supplier',
|
||||
component: lazy(() => import('@/pages/company/supplier')),
|
||||
name: '供应商管理',
|
||||
icon: 'branches',
|
||||
path: "supplier",
|
||||
component: lazy(() => import("@/pages/company/supplier")),
|
||||
name: "供应商管理",
|
||||
icon: "branches",
|
||||
},
|
||||
{
|
||||
path: 'supplierInfo/:id?',
|
||||
path: "supplierInfo/:id?",
|
||||
hidden: true,
|
||||
component: lazy(() => import('@/pages/company/supplier/detail')),
|
||||
name: '供应商详情',
|
||||
icon: 'branches',
|
||||
component: lazy(() => import("@/pages/company/supplier/detail")),
|
||||
name: "供应商详情",
|
||||
icon: "branches",
|
||||
},
|
||||
];
|
||||
|
||||
const marketingRoutes = [
|
||||
];
|
||||
const marketingRoutes = [];
|
||||
|
||||
export const routes = [
|
||||
dashboardRoute,
|
||||
{
|
||||
path: 'resource',
|
||||
component: lazy(() => import('@/pages/resource')),
|
||||
name: '资源管理',
|
||||
icon: 'appstore',
|
||||
path: "resource",
|
||||
component: lazy(() => import("@/pages/resource")),
|
||||
name: "资源管理",
|
||||
icon: "appstore",
|
||||
children: resourceRoutes,
|
||||
},
|
||||
{
|
||||
path: 'company',
|
||||
component: lazy(() => import('@/pages/company')),
|
||||
name: '公司管理',
|
||||
icon: 'bank',
|
||||
path: "company",
|
||||
component: lazy(() => import("@/pages/company")),
|
||||
name: "公司管理",
|
||||
icon: "bank",
|
||||
children: companyRoutes,
|
||||
},
|
||||
{
|
||||
path: 'marketing',
|
||||
component: lazy(() => import('@/pages/marketing')),
|
||||
name: '行销中心',
|
||||
icon: 'shopping',
|
||||
path: "marketing",
|
||||
component: lazy(() => import("@/pages/marketing")),
|
||||
name: "行销中心",
|
||||
icon: "shopping",
|
||||
children: marketingRoutes,
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
@@ -1,58 +1,61 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { message } from 'antd';
|
||||
import { resourceService } from '@/services/supabase/resource';
|
||||
import { useState, useCallback } from "react";
|
||||
import { message } from "antd";
|
||||
import { resourceService } from "@/services/supabase/resource";
|
||||
|
||||
export const useResources = (initialPagination, initialSorter,type) => {
|
||||
export const useResources = (initialPagination, initialSorter, type) => {
|
||||
const [resources, setResources] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [currentPagination, setCurrentPagination] = useState(initialPagination);
|
||||
const [currentSorter, setCurrentSorter] = useState(initialSorter);
|
||||
|
||||
const fetchResources = useCallback(async (params = {}) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const newPagination = {
|
||||
current: params.current || currentPagination.current,
|
||||
pageSize: params.pageSize || currentPagination.pageSize
|
||||
};
|
||||
const newSorter = {
|
||||
field: params.field || currentSorter.field,
|
||||
order: params.order || currentSorter.order
|
||||
};
|
||||
const fetchResources = useCallback(
|
||||
async (params = {}) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const newPagination = {
|
||||
current: params.current || currentPagination.current,
|
||||
pageSize: params.pageSize || currentPagination.pageSize,
|
||||
};
|
||||
const newSorter = {
|
||||
field: params.field || currentSorter.field,
|
||||
order: params.order || currentSorter.order,
|
||||
};
|
||||
|
||||
setCurrentPagination(newPagination);
|
||||
setCurrentSorter(newSorter);
|
||||
setCurrentPagination(newPagination);
|
||||
setCurrentSorter(newSorter);
|
||||
|
||||
const { data, total: newTotal } = await resourceService.getResources({
|
||||
page: newPagination.current,
|
||||
pageSize: newPagination.pageSize,
|
||||
orderBy: newSorter.field,
|
||||
ascending: newSorter.order === 'ascend',
|
||||
type: type,
|
||||
...(params?.search !== '' ? { searchQuery: params.search } : {})
|
||||
});
|
||||
const { data, total: newTotal } = await resourceService.getResources({
|
||||
page: newPagination.current,
|
||||
pageSize: newPagination.pageSize,
|
||||
orderBy: newSorter.field,
|
||||
ascending: newSorter.order === "ascend",
|
||||
type: type,
|
||||
...(params?.search !== "" ? { searchQuery: params.search } : {}),
|
||||
});
|
||||
|
||||
setResources(data || []);
|
||||
setTotal(newTotal || 0);
|
||||
|
||||
return { data, total: newTotal };
|
||||
} catch (error) {
|
||||
console.error('获取列表失败:', error);
|
||||
message.error('获取列表失败');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [currentPagination, currentSorter]);
|
||||
setResources(data || []);
|
||||
setTotal(newTotal || 0);
|
||||
|
||||
return { data, total: newTotal };
|
||||
} catch (error) {
|
||||
console.error("获取列表失败:", error);
|
||||
message.error("获取列表失败");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
},
|
||||
[currentPagination, currentSorter]
|
||||
);
|
||||
|
||||
const createResource = async (values) => {
|
||||
try {
|
||||
const newResource = await resourceService.createResource(values);
|
||||
await fetchResources({ current: 1 });
|
||||
message.success('创建成功');
|
||||
message.success("创建成功");
|
||||
return newResource;
|
||||
} catch (error) {
|
||||
message.error('创建失败');
|
||||
message.error("创建失败");
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
@@ -61,24 +64,25 @@ export const useResources = (initialPagination, initialSorter,type) => {
|
||||
try {
|
||||
const updatedResource = await resourceService.updateResource(id, values);
|
||||
await fetchResources({ current: currentPagination.current });
|
||||
message.success('更新成功');
|
||||
message.success("更新成功");
|
||||
return updatedResource;
|
||||
} catch (error) {
|
||||
message.error('更新失败');
|
||||
message.error("更新失败");
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const deleteResource = async (id) => {
|
||||
try {
|
||||
await resourceService.deleteResource(id);
|
||||
const newCurrent = resources.length === 1 && currentPagination.current > 1
|
||||
? currentPagination.current - 1
|
||||
: currentPagination.current;
|
||||
await resourceService.deleteResource(id, type);
|
||||
const newCurrent =
|
||||
resources.length === 1 && currentPagination.current > 1
|
||||
? currentPagination.current - 1
|
||||
: currentPagination.current;
|
||||
await fetchResources({ current: newCurrent });
|
||||
message.success('删除成功');
|
||||
message.success("删除成功");
|
||||
} catch (error) {
|
||||
message.error('删除失败');
|
||||
message.error("删除失败");
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
@@ -94,4 +98,4 @@ export const useResources = (initialPagination, initialSorter,type) => {
|
||||
updateResource,
|
||||
deleteResource,
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
277
src/pages/resource/resourceTask/edit/index.jsx
Normal file
277
src/pages/resource/resourceTask/edit/index.jsx
Normal file
@@ -0,0 +1,277 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import {
|
||||
Form,
|
||||
Input,
|
||||
Button,
|
||||
Space,
|
||||
Card,
|
||||
Table,
|
||||
Typography,
|
||||
message,
|
||||
} from "antd";
|
||||
import {
|
||||
PlusOutlined,
|
||||
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";
|
||||
|
||||
const { Title } = Typography;
|
||||
|
||||
const ResourceTaskForm = () => {
|
||||
const { id } = useParams();
|
||||
const [searchParams] = useSearchParams();
|
||||
const isEdit = searchParams.get("edit") === "true";
|
||||
const isView = id && !isEdit;
|
||||
const [form] = Form.useForm();
|
||||
const navigate = useNavigate();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [dataSource, setDataSource] = useState([{ id: uuidv4(), name: '' }]);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: "名称",
|
||||
dataIndex: "name",
|
||||
render: (_, record, index) => (
|
||||
<Form.Item
|
||||
name={["items", index, "name"]}
|
||||
rules={[{ required: true, message: "请输入名称" }]}
|
||||
style={{ margin: 0 }}
|
||||
preserve={true}
|
||||
>
|
||||
<Input placeholder="请输入名称" maxLength={100} />
|
||||
</Form.Item>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
width: 100,
|
||||
render: (_, record, index) => (
|
||||
<Button
|
||||
type="link"
|
||||
danger
|
||||
disabled={dataSource.length === 1 || isView}
|
||||
onClick={() => handleRemoveItem(record.id, index)}
|
||||
>
|
||||
删除
|
||||
</Button>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const handleRemoveItem = (itemId, index) => {
|
||||
// 获取当前所有表单项的值
|
||||
const allFormValues = form.getFieldsValue();
|
||||
const currentItems = allFormValues.items || [];
|
||||
|
||||
// 保留要删除项之外的所有项
|
||||
const newItems = currentItems.filter((_, idx) => idx !== index);
|
||||
|
||||
// 更新 dataSource,确保保留其他项的数据
|
||||
const newDataSource = dataSource.filter((_, idx) => idx !== index);
|
||||
|
||||
// 同步更新 form 和 dataSource
|
||||
setDataSource(newDataSource);
|
||||
form.setFieldsValue({ items: newItems });
|
||||
};
|
||||
|
||||
const handleAddItem = () => {
|
||||
const newItem = { id: uuidv4(), name: '' };
|
||||
// 获取当前表单值
|
||||
const currentItems = form.getFieldValue('items') || [];
|
||||
|
||||
// 同步更新表单和 dataSource
|
||||
setDataSource(prev => [...prev, newItem]);
|
||||
form.setFieldsValue({
|
||||
items: [...currentItems, newItem]
|
||||
});
|
||||
};
|
||||
|
||||
const fetchResourceTaskDetail = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const { data, error } = await supabase
|
||||
.from("resources")
|
||||
.select("*")
|
||||
.eq("id", id)
|
||||
.single();
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
if (data?.attributes) {
|
||||
const items = data.attributes.items?.map(item => ({
|
||||
...item,
|
||||
id: item.id || uuidv4(),
|
||||
name: item.name || ''
|
||||
})) || [{ id: uuidv4(), name: '' }];
|
||||
|
||||
// 同步设置表单值和 dataSource
|
||||
form.setFieldsValue({
|
||||
taskName: data.attributes.taskName,
|
||||
items,
|
||||
});
|
||||
setDataSource(items);
|
||||
}
|
||||
} catch (error) {
|
||||
message.error("获取任务详情失败,请稍后重试");
|
||||
console.error("获取任务详情失败:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (id) {
|
||||
fetchResourceTaskDetail();
|
||||
}
|
||||
}, [id]);
|
||||
|
||||
const onFinish = async (values) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
// 验证任务项
|
||||
const hasEmptyItems = values.items.some((item) => !item.name?.trim());
|
||||
if (hasEmptyItems) {
|
||||
message.error("请填写所有任务项的名称");
|
||||
return;
|
||||
}
|
||||
|
||||
const resourceTaskData = {
|
||||
type: "task",
|
||||
attributes: {
|
||||
taskName: values.taskName.trim(),
|
||||
items: values.items.map((item, index) => ({
|
||||
id: dataSource[index].id,
|
||||
name: item.name?.trim(),
|
||||
})),
|
||||
},
|
||||
};
|
||||
|
||||
if (id) {
|
||||
resourceTaskData.id = id;
|
||||
}
|
||||
|
||||
const { error } = await supabase
|
||||
.from("resources")
|
||||
.upsert(resourceTaskData)
|
||||
.select();
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
message.success("保存成功");
|
||||
navigate("/resource/task");
|
||||
} catch (error) {
|
||||
message.error("保存失败,请稍后重试");
|
||||
console.error("保存失败:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-gradient-to-b from-gray-50 to-white min-h-screen p-6">
|
||||
<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("/resource/task")}
|
||||
>
|
||||
返回
|
||||
</Button>
|
||||
{!isView && (
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<SaveOutlined />}
|
||||
onClick={() => form.submit()}
|
||||
loading={loading}
|
||||
>
|
||||
保存
|
||||
</Button>
|
||||
)}
|
||||
</Space>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Form
|
||||
form={form}
|
||||
onFinish={onFinish}
|
||||
layout="vertical"
|
||||
initialValues={{
|
||||
items: [{ id: uuidv4() }],
|
||||
}}
|
||||
disabled={isView || loading}
|
||||
>
|
||||
<Card
|
||||
className="mb-4 shadow-sm rounded-lg"
|
||||
title={
|
||||
<div className="flex items-center">
|
||||
<div className="w-1 h-4 bg-blue-500 rounded-full mr-2" />
|
||||
<span>基本信息</span>
|
||||
</div>
|
||||
}
|
||||
bordered={false}
|
||||
>
|
||||
<Form.Item
|
||||
name="taskName"
|
||||
label="任务名称"
|
||||
rules={[{ required: true, message: "请输入任务名称" }]}
|
||||
>
|
||||
<Input placeholder="请输入任务名称" maxLength={100} />
|
||||
</Form.Item>
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
className="shadow-sm rounded-lg"
|
||||
title={
|
||||
<div className="flex items-center">
|
||||
<div className="w-1 h-4 bg-green-500 rounded-full mr-2" />
|
||||
<span>任务明细</span>
|
||||
</div>
|
||||
}
|
||||
extra={
|
||||
!isView && (
|
||||
<Button
|
||||
type="dashed"
|
||||
icon={<PlusOutlined />}
|
||||
onClick={handleAddItem}
|
||||
disabled={loading}
|
||||
>
|
||||
新增一栏
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
bordered={false}
|
||||
>
|
||||
<Table
|
||||
dataSource={dataSource}
|
||||
columns={columns}
|
||||
pagination={false}
|
||||
rowKey="id"
|
||||
loading={loading}
|
||||
/>
|
||||
</Card>
|
||||
</Form>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ResourceTaskForm;
|
||||
166
src/pages/resource/resourceTask/index.jsx
Normal file
166
src/pages/resource/resourceTask/index.jsx
Normal file
@@ -0,0 +1,166 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import {
|
||||
Card,
|
||||
Table,
|
||||
Button,
|
||||
message,
|
||||
Popconfirm,
|
||||
Tag,
|
||||
Space,
|
||||
Tooltip,
|
||||
} from "antd";
|
||||
import {
|
||||
PlusOutlined,
|
||||
EditOutlined,
|
||||
DeleteOutlined,
|
||||
EyeOutlined,
|
||||
CopyOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { useResources } from "@/hooks/resource/useResource";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
const ResourceTask = () => {
|
||||
const navigate = useNavigate();
|
||||
const [pagination, setPagination] = useState({ current: 1, pageSize: 10 });
|
||||
const [sorter, setSorter] = useState({
|
||||
field: "created_at",
|
||||
order: "descend",
|
||||
});
|
||||
|
||||
const {
|
||||
resources: quotations,
|
||||
loading,
|
||||
total,
|
||||
fetchResources: fetchQuotations,
|
||||
deleteResource: deleteQuotation,
|
||||
} = useResources(pagination, sorter, "task");
|
||||
|
||||
useEffect(() => {
|
||||
fetchQuotations();
|
||||
}, []);
|
||||
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
setPagination(pagination);
|
||||
setSorter(sorter);
|
||||
fetchQuotations({
|
||||
current: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
field: sorter.field,
|
||||
order: sorter.order,
|
||||
});
|
||||
};
|
||||
|
||||
const handleDelete = async (id) => {
|
||||
try {
|
||||
await deleteQuotation(id);
|
||||
message.success("删除成功");
|
||||
fetchQuotations();
|
||||
} catch (error) {
|
||||
message.error("删除失败:" + error.message);
|
||||
}
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: "任务名称",
|
||||
dataIndex: ["attributes", "taskName"],
|
||||
key: "taskName",
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: "创建日期",
|
||||
dataIndex: "created_at",
|
||||
key: "created_at",
|
||||
sorter: true,
|
||||
render: (text) => (
|
||||
<span>
|
||||
{new Date(text).toLocaleString("zh-CN", {
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
})}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
width: 250,
|
||||
key: "action",
|
||||
render: (_, record) => (
|
||||
<Space size={0}>
|
||||
<Button
|
||||
size="small"
|
||||
type="link"
|
||||
icon={<EyeOutlined />}
|
||||
onClick={() => navigate(`/resource/task/edit/${record.id}`)}
|
||||
>
|
||||
查看
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
size="small"
|
||||
type="link"
|
||||
icon={<EditOutlined />}
|
||||
onClick={() =>
|
||||
navigate(`/resource/task/edit/${record.id}?edit=true`)
|
||||
}
|
||||
>
|
||||
编辑
|
||||
</Button>
|
||||
<Popconfirm
|
||||
title="确定要删除这个任务吗?"
|
||||
description="删除后将无法恢复!"
|
||||
onConfirm={() => handleDelete(record.id)}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
okButtonProps={{ danger: true }}
|
||||
>
|
||||
<Button size="small" type="link" danger icon={<DeleteOutlined />}>
|
||||
删除
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Card
|
||||
title={
|
||||
<Space>
|
||||
<span>任务管理</span>
|
||||
<Tag color="blue">{total} 个任务</Tag>
|
||||
</Space>
|
||||
}
|
||||
className="h-full w-full overflow-auto"
|
||||
extra={
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
onClick={() => navigate("/resource/task/edit")}
|
||||
>
|
||||
新增任务
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={quotations}
|
||||
rowKey="id"
|
||||
loading={loading}
|
||||
onChange={handleTableChange}
|
||||
pagination={{
|
||||
...pagination,
|
||||
total,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total) => `共 ${total} 条记录`,
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default ResourceTask;
|
||||
@@ -69,13 +69,13 @@ export const resourceService = {
|
||||
}
|
||||
},
|
||||
|
||||
async deleteResource(id) {
|
||||
async deleteResource(id,type) {
|
||||
try {
|
||||
const { error } = await supabase
|
||||
.from('resources')
|
||||
.delete()
|
||||
.eq('id', id)
|
||||
.eq('type', 'quota')
|
||||
.eq('type', type)
|
||||
.select()
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
7
vercel.json
Normal file
7
vercel.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"rewrites": [
|
||||
{
|
||||
"source": "/(.*)"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -4143,6 +4143,11 @@ util-deprecate@^1.0.2:
|
||||
resolved "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
|
||||
|
||||
uuid@^11.0.3:
|
||||
version "11.0.3"
|
||||
resolved "https://registry.npmmirror.com/uuid/-/uuid-11.0.3.tgz#248451cac9d1a4a4128033e765d137e2b2c49a3d"
|
||||
integrity sha512-d0z310fCWv5dJwnX1Y/MncBAqGMKEzlBb1AOf7z9K8ALnd0utBX/msg/fA0+sbyN1ihbMsLhrBlnl1ak7Wa0rg==
|
||||
|
||||
victory-vendor@^36.6.8:
|
||||
version "36.9.2"
|
||||
resolved "https://registry.npmmirror.com/victory-vendor/-/victory-vendor-36.9.2.tgz#668b02a448fa4ea0f788dbf4228b7e64669ff801"
|
||||
|
||||
Reference in New Issue
Block a user