diff --git a/src/assets/logo-collapsed.png b/src/assets/logo-collapsed.png new file mode 100644 index 0000000..23b251f Binary files /dev/null and b/src/assets/logo-collapsed.png differ diff --git a/src/assets/logo.png b/src/assets/logo.png new file mode 100644 index 0000000..911ec37 Binary files /dev/null and b/src/assets/logo.png differ diff --git a/src/components/Layout/Logo.jsx b/src/components/Layout/Logo.jsx index 510b329..0762fc9 100644 --- a/src/components/Layout/Logo.jsx +++ b/src/components/Layout/Logo.jsx @@ -1,18 +1,24 @@ -import React from 'react'; -import { RocketOutlined } from '@ant-design/icons'; -import { Typography } from 'antd'; +import React from "react"; -const { Text } = Typography; +import logo from "@/assets/logo.png"; +import logoCollapsed from "@/assets/logo-collapsed.png"; export const Logo = ({ collapsed, isDarkMode }) => (
- - {!collapsed && ( - - Uppeta - + {collapsed ? ( +
+ logo +
+ ) : ( +
+ logo +
)}
-); \ No newline at end of file +); diff --git a/src/components/Layout/MainLayout.jsx b/src/components/Layout/MainLayout.jsx index 993f7b6..7626508 100644 --- a/src/components/Layout/MainLayout.jsx +++ b/src/components/Layout/MainLayout.jsx @@ -15,7 +15,7 @@ const MainLayout = () => { -
+
setTaxRate(value)} + disabled={isView} /> diff --git a/src/pages/company/customer/index.jsx b/src/pages/company/customer/index.jsx index 630c006..2df9258 100644 --- a/src/pages/company/customer/index.jsx +++ b/src/pages/company/customer/index.jsx @@ -143,13 +143,15 @@ const CustomerPage = () => { } className='h-full w-full overflow-auto' extra={ - +
+ +
} > { const navigate = useNavigate(); const [pagination, setPagination] = useState({ current: 1, pageSize: 10 }); - const [sorter, setSorter] = useState({ field: 'created_at', order: 'descend' }); + const [sorter, setSorter] = useState({ + field: "created_at", + order: "descend", + }); const [isModalVisible, setIsModalVisible] = useState(false); const [selectedTemplateId, setSelectedTemplateId] = useState(null); const [templates, setTemplates] = useState([]); const [loading, setLoading] = useState(false); - const [selectedCategory, setSelectedCategory] = useState('all'); + const [selectedCategory, setSelectedCategory] = useState("all"); const [categories, setCategories] = useState([]); const { @@ -22,8 +52,8 @@ const QuotationPage = () => { loading: loadingQuotations, total, fetchResources: fetchQuotations, - deleteResource: deleteQuotation - } = useResources(pagination, sorter, 'quota'); + deleteResource: deleteQuotation, + } = useResources(pagination, sorter, "quota"); useEffect(() => { fetchQuotations(); @@ -43,10 +73,10 @@ const QuotationPage = () => { const handleDelete = async (id) => { try { await deleteQuotation(id); - message.success('删除成功'); + message.success("删除成功"); fetchQuotations(); } catch (error) { - message.error('删除失败:' + error.message); + message.error("删除失败:" + error.message); } }; @@ -89,7 +119,7 @@ const QuotationPage = () => { if (selectedTemplateId) { navigate(`/company/quotaInfo?templateId=${selectedTemplateId}`); } else { - navigate('/company/quotaInfo'); + navigate("/company/quotaInfo"); } setIsModalVisible(false); setSelectedTemplateId(null); @@ -97,41 +127,41 @@ const QuotationPage = () => { const getAllCategories = (templates) => { const categorySet = new Set(); - templates.forEach(template => { - template.attributes.category?.forEach(cat => { + templates.forEach((template) => { + template.attributes.category?.forEach((cat) => { categorySet.add(JSON.stringify(cat)); }); }); - return Array.from(categorySet).map(cat => JSON.parse(cat)); + return Array.from(categorySet).map((cat) => JSON.parse(cat)); }; const getFilteredTemplates = () => { - if (selectedCategory === 'all') return templates; - return templates.filter(template => - template.attributes.category?.some(cat => cat.id === selectedCategory) + if (selectedCategory === "all") return templates; + return templates.filter((template) => + template.attributes.category?.some((cat) => cat.id === selectedCategory) ); }; const columns = [ { - title: '报价单名称', - dataIndex: ['attributes', 'quataName'], - key: 'quataName', + title: "报价单名称", + dataIndex: ["attributes", "quataName"], + key: "quataName", ellipsis: true, }, { - title: '客户信息', - dataIndex: ['attributes', 'customers'], - key: 'customers', + title: "客户信息", + dataIndex: ["attributes", "customers"], + key: "customers", render: (customers, record) => ( - {customers?.map(customer => ( + {customers?.map((customer) => ( { - navigate(`/company/customerInfo/${customer.id}`) + navigate(`/company/customerInfo/${customer.id}`); }} > {customer.name} @@ -141,61 +171,70 @@ const QuotationPage = () => { ), }, { - title: '报价总额', - dataIndex: ['attributes'], - key: 'totalAmount', - align: 'right', + title: "报价总额", + dataIndex: ["attributes"], + key: "totalAmount", + align: "right", render: (attributes) => { // 获取货币符号 - const currencySymbol = EXCHANGE_RATE[attributes?.currency]?.symbol || defaultSymbol; + const currencySymbol = + EXCHANGE_RATE[attributes?.currency]?.symbol || defaultSymbol; return (
- - 税前:{formatExchangeRate(attributes?.currency, attributes.beforeTaxAmount)} + + 税前: + {formatExchangeRate( + attributes?.currency, + attributes.beforeTaxAmount + )}
-
); }, }, { - title: '创建日期', - dataIndex: 'created_at', - key: 'created_at', + title: "创建日期", + dataIndex: "created_at", + key: "created_at", sorter: true, render: (text) => ( - {new Date(text).toLocaleString('zh-CN', { - year: 'numeric', - month: '2-digit', - day: '2-digit', - hour: '2-digit', - minute: '2-digit' - })} + + {new Date(text).toLocaleString("zh-CN", { + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + })} + ), }, { - title: '操作', - key: 'action', - fixed: 'right', + title: "操作", + key: "action", + fixed: "right", render: (_, record) => ( @@ -226,7 +267,7 @@ const QuotationPage = () => { cancelText="取消" okButtonProps={{ danger: true }} > - @@ -239,19 +280,21 @@ const QuotationPage = () => { const groups = new Map(); // 添加未分类组 - groups.set('uncategorized', { - name: '未分类', - templates: templates.filter(t => !t.attributes.category || t.attributes.category.length === 0) + groups.set("uncategorized", { + name: "未分类", + templates: templates.filter( + (t) => !t.attributes.category || t.attributes.category.length === 0 + ), }); // 按分类分组 - templates.forEach(template => { + templates.forEach((template) => { if (template.attributes.category) { - template.attributes.category.forEach(cat => { + template.attributes.category.forEach((cat) => { if (!groups.has(cat.id)) { groups.set(cat.id, { name: cat.name, - templates: [] + templates: [], }); } groups.get(cat.id).templates.push(template); @@ -259,35 +302,35 @@ const QuotationPage = () => { } }); - return Array.from(groups.values()).filter(group => group.templates.length > 0); + return Array.from(groups.values()).filter( + (group) => group.templates.length > 0 + ); }; const copyItem = async (record) => { try { setLoading(true); // 深拷贝原有数据的 attributes const newAttributes = JSON.parse(JSON.stringify(record.attributes)); - + // 修改报价单名称,添加"副本"标识 newAttributes.quataName = `${newAttributes.quataName} (副本)`; - + // 创建新的报价单记录 - const { data, error } = await supabase - .from('resources') - .insert([ - { - type: 'quota', - attributes: newAttributes - } - ]); + const { data, error } = await supabase.from("resources").insert([ + { + type: "quota", + attributes: newAttributes, + }, + ]); if (error) throw error; - - message.success('复制成功'); + + message.success("复制成功"); // 刷新列表 fetchQuotations(); } catch (error) { - console.error('复制报价单失败:', error); - message.error('复制失败:' + error.message); + console.error("复制报价单失败:", error); + message.error("复制失败:" + error.message); } finally { setLoading(false); } @@ -301,19 +344,21 @@ const QuotationPage = () => { {total} 个报价单 } - className='h-full w-full overflow-auto' + className="h-full w-full overflow-auto" extra={ - +
+ +
} >
{
- {group.templates.map(template => ( + {group.templates.map((template) => (
handleTemplateSelect(template.id)} @@ -381,8 +426,8 @@ const QuotationPage = () => { relative p-4 rounded-xl cursor-pointer transition-all duration-200 ${ selectedTemplateId === template.id - ? 'ring-2 ring-blue-500 bg-blue-50/40 dark:bg-blue-900/40' - : 'hover:bg-gray-50 dark:hover:bg-gray-700/50 border border-gray-200 dark:border-gray-700 shadow-sm hover:shadow-md' + ? "ring-2 ring-blue-500 bg-blue-50/40 dark:bg-blue-900/40" + : "hover:bg-gray-50 dark:hover:bg-gray-700/50 border border-gray-200 dark:border-gray-700 shadow-sm hover:shadow-md" } dark:bg-gray-800 `} @@ -393,7 +438,7 @@ const QuotationPage = () => { {template.attributes.templateName}

- {template.attributes.description || '暂无描述'} + {template.attributes.description || "暂无描述"}

@@ -422,7 +467,11 @@ const QuotationPage = () => { {selectedTemplateId === template.id && (
- +
@@ -440,4 +489,4 @@ const QuotationPage = () => { ); }; -export default QuotationPage; \ No newline at end of file +export default QuotationPage; diff --git a/src/pages/company/supplier/index.jsx b/src/pages/company/supplier/index.jsx index 45c5faa..fd82331 100644 --- a/src/pages/company/supplier/index.jsx +++ b/src/pages/company/supplier/index.jsx @@ -1,21 +1,24 @@ -import React, { useEffect, useState } from 'react'; -import { Card, Table, Button, message, Popconfirm, Tag, Space } from 'antd'; -import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons'; -import { useResources } from '@/hooks/resource/useResource'; -import { useNavigate } from 'react-router-dom'; +import React, { useEffect, useState } from "react"; +import { Card, Table, Button, message, Popconfirm, Tag, Space } from "antd"; +import { PlusOutlined, EditOutlined, DeleteOutlined } from "@ant-design/icons"; +import { useResources } from "@/hooks/resource/useResource"; +import { useNavigate } from "react-router-dom"; const SupplierPage = () => { const navigate = useNavigate(); const [pagination, setPagination] = useState({ current: 1, pageSize: 10 }); - const [sorter, setSorter] = useState({ field: 'created_at', order: 'descend' }); + const [sorter, setSorter] = useState({ + field: "created_at", + order: "descend", + }); const { resources: suppliers, loading, total, fetchResources: fetchSuppliers, - deleteResource: deleteSupplier - } = useResources(pagination, sorter, 'supplier'); + deleteResource: deleteSupplier, + } = useResources(pagination, sorter, "supplier"); useEffect(() => { fetchSuppliers(); @@ -35,66 +38,70 @@ const SupplierPage = () => { const handleDelete = async (id) => { try { await deleteSupplier(id); - message.success('删除成功'); + message.success("删除成功"); fetchSuppliers(); } catch (error) { - message.error('删除失败:' + error.message); + message.error("删除失败:" + error.message); } }; const columns = [ { - title: '供应商名称', - dataIndex: ['attributes', 'name'], - key: 'name', + title: "供应商名称", + dataIndex: ["attributes", "name"], + key: "name", ellipsis: true, }, { - title: '联系人', - dataIndex: ['attributes', 'contact'], - key: 'contact', + title: "联系人", + dataIndex: ["attributes", "contact"], + key: "contact", }, { - title: '电话', - dataIndex: ['attributes', 'phone'], - key: 'phone', + title: "电话", + dataIndex: ["attributes", "phone"], + key: "phone", }, { - title: '状态', - dataIndex: ['attributes', 'status'], - key: 'status', + title: "状态", + dataIndex: ["attributes", "status"], + key: "status", render: (status) => ( - - {status === 'active' ? '启用' : '禁用'} + + {status === "active" ? "启用" : "禁用"} ), }, { - title: '创建日期', - dataIndex: 'created_at', - key: 'created_at', + title: "创建日期", + dataIndex: "created_at", + key: "created_at", sorter: true, render: (text) => ( - {new Date(text).toLocaleString('zh-CN', { - year: 'numeric', - month: '2-digit', - day: '2-digit', - hour: '2-digit', - minute: '2-digit' - })} + + {new Date(text).toLocaleString("zh-CN", { + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + })} + ), }, { - title: '操作', - key: 'action', - fixed: 'right', + title: "操作", + key: "action", + fixed: "right", render: (_, record) => ( @@ -106,7 +113,7 @@ const SupplierPage = () => { cancelText="取消" okButtonProps={{ danger: true }} > - @@ -123,15 +130,17 @@ const SupplierPage = () => { {total} 个供应商 } - className='h-full w-full overflow-auto' + className="h-full w-full overflow-auto" extra={ - +
+ +
} >
{ ); }; -export default SupplierPage; \ No newline at end of file +export default SupplierPage; diff --git a/src/pages/company/task/index.jsx b/src/pages/company/task/index.jsx index 272aceb..2ea31ed 100644 --- a/src/pages/company/task/index.jsx +++ b/src/pages/company/task/index.jsx @@ -30,9 +30,11 @@ const TaskPage = () => { }> - 新增任务 - +
+ +
} >
diff --git a/src/pages/marketing/communication/tasks/index.jsx b/src/pages/marketing/communication/tasks/index.jsx index 56b1744..18bfb0d 100644 --- a/src/pages/marketing/communication/tasks/index.jsx +++ b/src/pages/marketing/communication/tasks/index.jsx @@ -35,9 +35,11 @@ const CommunicationTasks = () => { }> - 新增任务 - +
+ +
} >
diff --git a/src/pages/resource/resourceTask/index.jsx b/src/pages/resource/resourceTask/index.jsx index 86bd9ab..870fb98 100644 --- a/src/pages/resource/resourceTask/index.jsx +++ b/src/pages/resource/resourceTask/index.jsx @@ -86,7 +86,7 @@ const ResourceTask = () => { }, { title: "操作", - fixed: 'right', + fixed: "right", key: "action", render: (_, record) => ( @@ -136,13 +136,15 @@ const ResourceTask = () => { } className="h-full w-full overflow-auto" extra={ - +
+ +
} >