diff --git a/package.json b/package.json index 71e98c1..61a9c8c 100644 --- a/package.json +++ b/package.json @@ -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" } -} \ No newline at end of file +} diff --git a/src/config/routes.js b/src/config/routes.js index 1de2bd4..50e1909 100644 --- a/src/config/routes.js +++ b/src/config/routes.js @@ -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, }, -]; \ No newline at end of file +]; diff --git a/src/hooks/resource/useResource.js b/src/hooks/resource/useResource.js index 46cbaf7..6716d7d 100644 --- a/src/hooks/resource/useResource.js +++ b/src/hooks/resource/useResource.js @@ -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, }; -}; \ No newline at end of file +}; diff --git a/src/pages/resource/resourceTask/edit/index.jsx b/src/pages/resource/resourceTask/edit/index.jsx new file mode 100644 index 0000000..a1189b9 --- /dev/null +++ b/src/pages/resource/resourceTask/edit/index.jsx @@ -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) => ( +