客户,供应商
This commit is contained in:
@@ -51,6 +51,26 @@ const companyRoutes = [
|
|||||||
name: '客户管理',
|
name: '客户管理',
|
||||||
icon: 'user',
|
icon: 'user',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'customerInfo/:id?',
|
||||||
|
hidden: true,
|
||||||
|
component: lazy(() => import('@/pages/company/customer/detail')),
|
||||||
|
name: '客户详情',
|
||||||
|
icon: 'user',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'supplier',
|
||||||
|
component: lazy(() => import('@/pages/company/supplier')),
|
||||||
|
name: '供应商管理',
|
||||||
|
icon: 'branches',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'supplierInfo/:id?',
|
||||||
|
hidden: true,
|
||||||
|
component: lazy(() => import('@/pages/company/supplier/detail')),
|
||||||
|
name: '供应商详情',
|
||||||
|
icon: 'branches',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const marketingRoutes = [
|
const marketingRoutes = [
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useState, useCallback } from 'react';
|
|||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
import { resourceService } from '@/services/supabase/resource';
|
import { resourceService } from '@/services/supabase/resource';
|
||||||
|
|
||||||
export const useResources = (initialPagination, initialSorter) => {
|
export const useResources = (initialPagination, initialSorter,type) => {
|
||||||
const [resources, setResources] = useState([]);
|
const [resources, setResources] = useState([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [total, setTotal] = useState(0);
|
const [total, setTotal] = useState(0);
|
||||||
@@ -29,6 +29,7 @@ export const useResources = (initialPagination, initialSorter) => {
|
|||||||
pageSize: newPagination.pageSize,
|
pageSize: newPagination.pageSize,
|
||||||
orderBy: newSorter.field,
|
orderBy: newSorter.field,
|
||||||
ascending: newSorter.order === 'ascend',
|
ascending: newSorter.order === 'ascend',
|
||||||
|
type: type,
|
||||||
...(params?.search !== '' ? { searchQuery: params.search } : {})
|
...(params?.search !== '' ? { searchQuery: params.search } : {})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
210
src/pages/company/customer/detail/index.jsx
Normal file
210
src/pages/company/customer/detail/index.jsx
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { Form, Input, Select, Button, Space, Card, Typography } from 'antd';
|
||||||
|
import { ArrowLeftOutlined, SaveOutlined } from '@ant-design/icons';
|
||||||
|
import { supabase } from '@/config/supabase';
|
||||||
|
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||||
|
|
||||||
|
const { TextArea } = Input;
|
||||||
|
const { Title } = Typography;
|
||||||
|
|
||||||
|
const CustomerForm = () => {
|
||||||
|
const { id } = useParams();
|
||||||
|
const [searchParams] = useSearchParams();
|
||||||
|
const isView = id&&!searchParams.get('edit');
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const fetchCustomerDetail = async () => {
|
||||||
|
try {
|
||||||
|
const { data, error } = await supabase
|
||||||
|
.from('resources')
|
||||||
|
.select('*')
|
||||||
|
.eq('id', id)
|
||||||
|
.single();
|
||||||
|
|
||||||
|
if (error) throw error;
|
||||||
|
|
||||||
|
if (id) {
|
||||||
|
form.setFieldsValue({
|
||||||
|
name: data.attributes.name,
|
||||||
|
contact: data.attributes.contact,
|
||||||
|
phone: data.attributes.phone,
|
||||||
|
address: data.attributes.address,
|
||||||
|
level: data.attributes.level || 'regular',
|
||||||
|
status: data.attributes.status || 'active',
|
||||||
|
remark: data.attributes.remark
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取客户详情失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (id) {
|
||||||
|
fetchCustomerDetail();
|
||||||
|
}
|
||||||
|
}, [id]);
|
||||||
|
|
||||||
|
const onFinish = async (values) => {
|
||||||
|
try {
|
||||||
|
const customerData = {
|
||||||
|
type: 'customer',
|
||||||
|
attributes: {
|
||||||
|
name: values.name,
|
||||||
|
contact: values.contact,
|
||||||
|
phone: values.phone,
|
||||||
|
address: values.address,
|
||||||
|
level: values.level,
|
||||||
|
status: values.status,
|
||||||
|
remark: values.remark
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let result;
|
||||||
|
if (id) {
|
||||||
|
result = await supabase
|
||||||
|
.from('resources')
|
||||||
|
.update(customerData)
|
||||||
|
.eq('id', id)
|
||||||
|
.select();
|
||||||
|
} else {
|
||||||
|
result = await supabase
|
||||||
|
.from('resources')
|
||||||
|
.insert([customerData])
|
||||||
|
.select();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
navigate('/company/customer');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('保存失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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 ? '编辑客户' : '新建客户'}
|
||||||
|
</Title>
|
||||||
|
<span className="text-gray-400 text-sm">
|
||||||
|
{id ? '请修改客户信息' : '请填写客户信息'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<Space size="middle">
|
||||||
|
<Button
|
||||||
|
icon={<ArrowLeftOutlined />}
|
||||||
|
onClick={() => navigate('/company/customer')}
|
||||||
|
>
|
||||||
|
返回
|
||||||
|
</Button>
|
||||||
|
{!isView && (
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
icon={<SaveOutlined />}
|
||||||
|
onClick={() => form.submit()}
|
||||||
|
>
|
||||||
|
保存
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
bodyStyle={{ backgroundColor: '#fff' }}
|
||||||
|
>
|
||||||
|
<Form
|
||||||
|
form={form}
|
||||||
|
onFinish={onFinish}
|
||||||
|
layout="vertical"
|
||||||
|
initialValues={{
|
||||||
|
status: 'active',
|
||||||
|
level: 'regular'
|
||||||
|
}}
|
||||||
|
className="space-y-6"
|
||||||
|
disabled={isView}
|
||||||
|
>
|
||||||
|
<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>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Form.Item
|
||||||
|
label="客户名称"
|
||||||
|
name="name"
|
||||||
|
rules={[{ required: true, message: '请输入客户名称' }]}
|
||||||
|
>
|
||||||
|
<Input placeholder="请输入客户名称" />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label="联系人"
|
||||||
|
name="contact"
|
||||||
|
rules={[{ required: true, message: '请输入联系人姓名' }]}
|
||||||
|
>
|
||||||
|
<Input placeholder="请输入联系人姓名" />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label="联系电话"
|
||||||
|
name="phone"
|
||||||
|
rules={[
|
||||||
|
{ required: true, message: '请输入联系电话' },
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input placeholder="请输入联系电话" />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label="客户等级"
|
||||||
|
name="level"
|
||||||
|
rules={[{ required: true, message: '请选择客户等级' }]}
|
||||||
|
>
|
||||||
|
<Select>
|
||||||
|
<Select.Option value="vip">VIP客户</Select.Option>
|
||||||
|
<Select.Option value="regular">普通客户</Select.Option>
|
||||||
|
<Select.Option value="potential">潜在客户</Select.Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label="地址"
|
||||||
|
name="address"
|
||||||
|
>
|
||||||
|
<Input.TextArea rows={3} placeholder="请输入详细地址" />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label="状态"
|
||||||
|
name="status"
|
||||||
|
rules={[{ required: true, message: '请选择状态' }]}
|
||||||
|
>
|
||||||
|
<Select>
|
||||||
|
<Select.Option value="active">启用</Select.Option>
|
||||||
|
<Select.Option value="inactive">禁用</Select.Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label="备注"
|
||||||
|
name="remark"
|
||||||
|
>
|
||||||
|
<Input.TextArea rows={3} placeholder="请输入备注信息" />
|
||||||
|
</Form.Item>
|
||||||
|
</Card>
|
||||||
|
</Form>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CustomerForm;
|
||||||
@@ -1,41 +1,172 @@
|
|||||||
import React from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Card, Table, Button } from 'antd';
|
import { Card, Table, Button, message, Popconfirm, Tag, Space } from 'antd';
|
||||||
import { PlusOutlined } from '@ant-design/icons';
|
import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||||
|
import { useResources } from '@/hooks/resource/useResource';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
const CustomerPage = () => {
|
const CustomerPage = () => {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [pagination, setPagination] = useState({ current: 1, pageSize: 10 });
|
||||||
|
const [sorter, setSorter] = useState({ field: 'created_at', order: 'descend' });
|
||||||
|
|
||||||
|
const {
|
||||||
|
resources: customers,
|
||||||
|
loading,
|
||||||
|
total,
|
||||||
|
fetchResources: fetchCustomers,
|
||||||
|
deleteResource: deleteCustomer
|
||||||
|
} = useResources(pagination, sorter, 'customer');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchCustomers();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleTableChange = (pagination, filters, sorter) => {
|
||||||
|
setPagination(pagination);
|
||||||
|
setSorter(sorter);
|
||||||
|
fetchCustomers({
|
||||||
|
current: pagination.current,
|
||||||
|
pageSize: pagination.pageSize,
|
||||||
|
field: sorter.field,
|
||||||
|
order: sorter.order,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = async (id) => {
|
||||||
|
try {
|
||||||
|
await deleteCustomer(id);
|
||||||
|
message.success('删除成功');
|
||||||
|
fetchCustomers();
|
||||||
|
} catch (error) {
|
||||||
|
message.error('删除失败:' + error.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: '客户名称',
|
title: '客户名称',
|
||||||
dataIndex: 'name',
|
dataIndex: ['attributes', 'name'],
|
||||||
key: 'name',
|
key: 'name',
|
||||||
|
ellipsis: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '联系人',
|
title: '联系人',
|
||||||
dataIndex: 'contact',
|
dataIndex: ['attributes', 'contact'],
|
||||||
key: 'contact',
|
key: 'contact',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '电话',
|
title: '电话',
|
||||||
dataIndex: 'phone',
|
dataIndex: ['attributes', 'phone'],
|
||||||
key: 'phone',
|
key: 'phone',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '客户等级',
|
||||||
|
dataIndex: ['attributes', 'level'],
|
||||||
|
key: 'level',
|
||||||
|
render: (level) => {
|
||||||
|
const colors = {
|
||||||
|
vip: 'gold',
|
||||||
|
regular: 'blue',
|
||||||
|
potential: 'green'
|
||||||
|
};
|
||||||
|
const labels = {
|
||||||
|
vip: 'VIP客户',
|
||||||
|
regular: '普通客户',
|
||||||
|
potential: '潜在客户'
|
||||||
|
};
|
||||||
|
return <Tag color={colors[level]}>{labels[level]}</Tag>;
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '状态',
|
title: '状态',
|
||||||
dataIndex: 'status',
|
dataIndex: ['attributes', 'status'],
|
||||||
key: 'status',
|
key: 'status',
|
||||||
|
render: (status) => (
|
||||||
|
<Tag color={status === 'active' ? 'green' : 'red'}>
|
||||||
|
{status === 'active' ? '启用' : '禁用'}
|
||||||
|
</Tag>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '创建日期',
|
||||||
|
dataIndex: 'created_at',
|
||||||
|
key: 'created_at',
|
||||||
|
sorter: true,
|
||||||
|
width: 180,
|
||||||
|
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: '操作',
|
||||||
|
key: 'action',
|
||||||
|
width: 150,
|
||||||
|
render: (_, record) => (
|
||||||
|
<Space size={0}>
|
||||||
|
<Button
|
||||||
|
size='small'
|
||||||
|
type="link"
|
||||||
|
icon={<EditOutlined />}
|
||||||
|
onClick={() => navigate(`/company/customerInfo/${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 (
|
return (
|
||||||
<Card
|
<Card
|
||||||
title="客户管理"
|
title={
|
||||||
|
<Space>
|
||||||
|
<span>客户管理</span>
|
||||||
|
<Tag color="blue">{total} 个客户</Tag>
|
||||||
|
</Space>
|
||||||
|
}
|
||||||
|
className='h-full w-full overflow-auto'
|
||||||
extra={
|
extra={
|
||||||
<Button type="primary" icon={<PlusOutlined />}>
|
<Button
|
||||||
|
type="primary"
|
||||||
|
icon={<PlusOutlined />}
|
||||||
|
onClick={() => navigate('/company/customerInfo')}
|
||||||
|
>
|
||||||
新增客户
|
新增客户
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Table columns={columns} dataSource={[]} rowKey="id" />
|
<Table
|
||||||
|
columns={columns}
|
||||||
|
dataSource={customers}
|
||||||
|
rowKey="id"
|
||||||
|
loading={loading}
|
||||||
|
onChange={handleTableChange}
|
||||||
|
pagination={{
|
||||||
|
...pagination,
|
||||||
|
total,
|
||||||
|
showSizeChanger: true,
|
||||||
|
showQuickJumper: true,
|
||||||
|
showTotal: (total) => `共 ${total} 条记录`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ const QuotationForm = () => {
|
|||||||
const [dataSource, setDataSource] = useState([{ id: Date.now() }]);
|
const [dataSource, setDataSource] = useState([{ id: Date.now() }]);
|
||||||
const [totalAmount, setTotalAmount] = useState(0);
|
const [totalAmount, setTotalAmount] = useState(0);
|
||||||
const [currentCurrency, setCurrentCurrency] = useState('CNY');
|
const [currentCurrency, setCurrentCurrency] = useState('CNY');
|
||||||
|
const [customers, setCustomers] = useState([]);
|
||||||
|
|
||||||
const calculateTotal = (items = []) => {
|
const calculateTotal = (items = []) => {
|
||||||
const total = items.reduce((sum, item) => {
|
const total = items.reduce((sum, item) => {
|
||||||
@@ -127,7 +128,7 @@ const QuotationForm = () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
width: '10%',
|
width: 100,
|
||||||
render: (_, record, index) => (
|
render: (_, record, index) => (
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
@@ -157,13 +158,13 @@ const QuotationForm = () => {
|
|||||||
|
|
||||||
if (error) throw error;
|
if (error) throw error;
|
||||||
|
|
||||||
|
|
||||||
if (isEdit) {
|
if (isEdit) {
|
||||||
// 设置表单初始值
|
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
quataName: data.attributes.quataName,
|
quataName: data.attributes.quataName,
|
||||||
companyName: data.attributes.companyName,
|
customer: {
|
||||||
supplierName: data.attributes.supplierName,
|
id: data.attributes.customerId,
|
||||||
|
name: data.attributes.customerName
|
||||||
|
},
|
||||||
description: data.attributes.description,
|
description: data.attributes.description,
|
||||||
currency: data.attributes.currency,
|
currency: data.attributes.currency,
|
||||||
items: data.attributes.items,
|
items: data.attributes.items,
|
||||||
@@ -194,8 +195,8 @@ const QuotationForm = () => {
|
|||||||
type: 'quota',
|
type: 'quota',
|
||||||
attributes: {
|
attributes: {
|
||||||
quataName: values.quataName,
|
quataName: values.quataName,
|
||||||
companyName: values.companyName,
|
customerId: values.customer.id,
|
||||||
supplierName: values.supplierName,
|
customerName: values.customer.name,
|
||||||
description: values.description,
|
description: values.description,
|
||||||
currency: values.currency,
|
currency: values.currency,
|
||||||
items: values.items,
|
items: values.items,
|
||||||
@@ -224,7 +225,25 @@ const QuotationForm = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fetchCustomers = async () => {
|
||||||
|
try {
|
||||||
|
const { data, error } = await supabase
|
||||||
|
.from('resources')
|
||||||
|
.select('*')
|
||||||
|
.eq('type', 'customer')
|
||||||
|
.eq('attributes->>status', 'active'); // 只获取启用状态的客户
|
||||||
|
|
||||||
|
if (error) throw error;
|
||||||
|
|
||||||
|
setCustomers(data || []);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取客户列表失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchCustomers();
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-gradient-to-b from-gray-50 to-white min-h-screen p-6">
|
<div className="bg-gradient-to-b from-gray-50 to-white min-h-screen p-6">
|
||||||
@@ -259,7 +278,7 @@ const QuotationForm = () => {
|
|||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
bodyStyle={{ backgroundColor: '#fff' }}
|
style={{ backgroundColor: '#fff' }}
|
||||||
>
|
>
|
||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
@@ -297,7 +316,7 @@ const QuotationForm = () => {
|
|||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
{/* <Form.Item
|
||||||
name="companyName"
|
name="companyName"
|
||||||
label={<span className="text-gray-700 font-medium">公司名称</span>}
|
label={<span className="text-gray-700 font-medium">公司名称</span>}
|
||||||
rules={[{ required: true, message: '请输入公司名称' }]}
|
rules={[{ required: true, message: '请输入公司名称' }]}
|
||||||
@@ -306,17 +325,46 @@ const QuotationForm = () => {
|
|||||||
placeholder="请输入公司名称"
|
placeholder="请输入公司名称"
|
||||||
className="rounded-md hover:border-blue-400 focus:border-blue-500"
|
className="rounded-md hover:border-blue-400 focus:border-blue-500"
|
||||||
/>
|
/>
|
||||||
|
</Form.Item> */}
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name={['customer', 'name']}
|
||||||
|
label={<span className="text-gray-700 font-medium">客户名称</span>}
|
||||||
|
rules={[{ required: true, message: '请选择客户' }]}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
placeholder="请选择客户"
|
||||||
|
className="rounded-md hover:border-blue-400 focus:border-blue-500"
|
||||||
|
showSearch
|
||||||
|
optionFilterProp="children"
|
||||||
|
filterOption={(input, option) =>
|
||||||
|
(option?.children ?? '').toLowerCase().includes(input.toLowerCase())
|
||||||
|
}
|
||||||
|
onChange={(value, option) => {
|
||||||
|
form.setFieldsValue({
|
||||||
|
customer: {
|
||||||
|
id: option.key,
|
||||||
|
name: value
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{customers.map(customer => (
|
||||||
|
<Select.Option
|
||||||
|
key={customer.id}
|
||||||
|
value={customer.attributes.name}
|
||||||
|
>
|
||||||
|
{customer.attributes.name}
|
||||||
|
</Select.Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="supplierName"
|
name={['customer', 'id']}
|
||||||
label={<span className="text-gray-700 font-medium">供应商名称</span>}
|
hidden
|
||||||
rules={[{ required: true, message: '请输入供应商名称' }]}
|
|
||||||
>
|
>
|
||||||
<Input
|
<Input />
|
||||||
placeholder="请输入供应商名称"
|
|
||||||
className="rounded-md hover:border-blue-400 focus:border-blue-500"
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const QuotationPage = () => {
|
|||||||
total,
|
total,
|
||||||
fetchResources: fetchQuotations,
|
fetchResources: fetchQuotations,
|
||||||
deleteResource: deleteQuotation
|
deleteResource: deleteQuotation
|
||||||
} = useResources(pagination, sorter);
|
} = useResources(pagination, sorter, 'quota');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchQuotations();
|
fetchQuotations();
|
||||||
@@ -52,18 +52,12 @@ const QuotationPage = () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '客户信息',
|
title: '客户信息',
|
||||||
dataIndex: ['attributes', 'companyName'],
|
dataIndex: ['attributes', 'customerName'],
|
||||||
key: 'companyName',
|
key: 'customerName',
|
||||||
render: (companyName) => (
|
render: (customerName,record) => (
|
||||||
<Tag color="blue">{companyName}</Tag>
|
<Tag color="blue" className='cursor-pointer' onClick={() => {
|
||||||
),
|
navigate(`/company/customerInfo/${record.attributes.customerId}`)
|
||||||
},
|
}}>{customerName}</Tag>
|
||||||
{
|
|
||||||
title: '供应商',
|
|
||||||
dataIndex: ['attributes', 'supplierName'],
|
|
||||||
key: 'supplierName',
|
|
||||||
render: (supplierName) => (
|
|
||||||
<Tag color="green">{supplierName}</Tag>
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -82,7 +76,7 @@ const QuotationPage = () => {
|
|||||||
dataIndex: 'created_at',
|
dataIndex: 'created_at',
|
||||||
key: 'created_at',
|
key: 'created_at',
|
||||||
sorter: true,
|
sorter: true,
|
||||||
width: 180,
|
width: 120,
|
||||||
render: (text) => (
|
render: (text) => (
|
||||||
<span>{new Date(text).toLocaleString('zh-CN', {
|
<span>{new Date(text).toLocaleString('zh-CN', {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
@@ -96,11 +90,11 @@ const QuotationPage = () => {
|
|||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
key: 'action',
|
key: 'action',
|
||||||
width:180,
|
width:200,
|
||||||
render: (_, record) => (
|
render: (_, record) => (
|
||||||
<Space size="mini">
|
<Space size={0}>
|
||||||
<Button
|
<Button
|
||||||
size='mini'
|
size='small'
|
||||||
type="link"
|
type="link"
|
||||||
icon={<EyeOutlined />}
|
icon={<EyeOutlined />}
|
||||||
onClick={() => navigate(`/company/quotaInfo/preview/${record.id}`)}
|
onClick={() => navigate(`/company/quotaInfo/preview/${record.id}`)}
|
||||||
@@ -108,7 +102,7 @@ const QuotationPage = () => {
|
|||||||
查看
|
查看
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size='mini'
|
size='small'
|
||||||
type="link"
|
type="link"
|
||||||
icon={<EditOutlined />}
|
icon={<EditOutlined />}
|
||||||
onClick={() => navigate(`/company/quotaInfo/${record.id}?edit=true`)}
|
onClick={() => navigate(`/company/quotaInfo/${record.id}?edit=true`)}
|
||||||
@@ -123,7 +117,7 @@ const QuotationPage = () => {
|
|||||||
cancelText="取消"
|
cancelText="取消"
|
||||||
okButtonProps={{ danger: true }}
|
okButtonProps={{ danger: true }}
|
||||||
>
|
>
|
||||||
<Button size='mini' type="link" danger icon={<DeleteOutlined />}>
|
<Button size='small' type="link" danger icon={<DeleteOutlined />}>
|
||||||
删除
|
删除
|
||||||
</Button>
|
</Button>
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ const QuotationView = () => {
|
|||||||
if (error) throw error;
|
if (error) throw error;
|
||||||
setData(quotation);
|
setData(quotation);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取报价单<EFBFBD><EFBFBD>情失败:', error);
|
console.error('获取报价单失败:', error);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -197,10 +197,7 @@ const QuotationView = () => {
|
|||||||
<div className="bg-gray-50 p-6 rounded-lg mb-8">
|
<div className="bg-gray-50 p-6 rounded-lg mb-8">
|
||||||
<Descriptions column={2} bordered>
|
<Descriptions column={2} bordered>
|
||||||
<Descriptions.Item label="客户公司" span={1}>
|
<Descriptions.Item label="客户公司" span={1}>
|
||||||
{data.attributes.companyName}
|
{data.attributes.customerName}
|
||||||
</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="供应商" span={1}>
|
|
||||||
{data.attributes.supplierName}
|
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
<Descriptions.Item label="报价日期" span={1}>
|
<Descriptions.Item label="报价日期" span={1}>
|
||||||
{new Date(data.created_at).toLocaleDateString('zh-CN')}
|
{new Date(data.created_at).toLocaleDateString('zh-CN')}
|
||||||
|
|||||||
198
src/pages/company/supplier/detail/index.jsx
Normal file
198
src/pages/company/supplier/detail/index.jsx
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { Form, Input, Select, Button, Space, Card, Typography } from 'antd';
|
||||||
|
import { ArrowLeftOutlined, SaveOutlined } from '@ant-design/icons';
|
||||||
|
import { supabase } from '@/config/supabase';
|
||||||
|
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||||
|
|
||||||
|
const { TextArea } = Input;
|
||||||
|
const { Title } = Typography;
|
||||||
|
|
||||||
|
const SupplierForm = () => {
|
||||||
|
const { id } = useParams();
|
||||||
|
const [searchParams] = useSearchParams();
|
||||||
|
const isEdit = searchParams.get('edit') === 'true';
|
||||||
|
const isView = id && !isEdit;
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const fetchSupplierDetail = async () => {
|
||||||
|
try {
|
||||||
|
const { data, error } = await supabase
|
||||||
|
.from('resources')
|
||||||
|
.select('*')
|
||||||
|
.eq('id', id)
|
||||||
|
.single();
|
||||||
|
|
||||||
|
if (error) throw error;
|
||||||
|
|
||||||
|
if (id) {
|
||||||
|
// 设置表单初始值
|
||||||
|
form.setFieldsValue({
|
||||||
|
name: data.attributes.name,
|
||||||
|
contact: data.attributes.contact,
|
||||||
|
phone: data.attributes.phone,
|
||||||
|
address: data.attributes.address,
|
||||||
|
status: data.attributes.status || 'active',
|
||||||
|
remark: data.attributes.remark
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取供应商详情失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (id) {
|
||||||
|
fetchSupplierDetail();
|
||||||
|
}
|
||||||
|
}, [id]);
|
||||||
|
|
||||||
|
const onFinish = async (values) => {
|
||||||
|
try {
|
||||||
|
const supplierData = {
|
||||||
|
type: 'supplier',
|
||||||
|
attributes: {
|
||||||
|
name: values.name,
|
||||||
|
contact: values.contact,
|
||||||
|
phone: values.phone,
|
||||||
|
address: values.address,
|
||||||
|
status: values.status,
|
||||||
|
remark: values.remark
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let result;
|
||||||
|
if (id) {
|
||||||
|
result = await supabase
|
||||||
|
.from('resources')
|
||||||
|
.update(supplierData)
|
||||||
|
.eq('id', id)
|
||||||
|
.select();
|
||||||
|
} else {
|
||||||
|
result = await supabase
|
||||||
|
.from('resources')
|
||||||
|
.insert([supplierData])
|
||||||
|
.select();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
navigate('/company/supplier');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('保存失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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('/company/supplier')}
|
||||||
|
>
|
||||||
|
返回
|
||||||
|
</Button>
|
||||||
|
{!isView && (
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
icon={<SaveOutlined />}
|
||||||
|
onClick={() => form.submit()}
|
||||||
|
>
|
||||||
|
保存
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
bodyStyle={{ backgroundColor: '#fff' }}
|
||||||
|
>
|
||||||
|
<Form
|
||||||
|
form={form}
|
||||||
|
onFinish={onFinish}
|
||||||
|
layout="vertical"
|
||||||
|
initialValues={{
|
||||||
|
status: 'active'
|
||||||
|
}}
|
||||||
|
className="space-y-6"
|
||||||
|
disabled={isView}
|
||||||
|
>
|
||||||
|
{/* 基本信息卡片 */}
|
||||||
|
<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>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Form.Item
|
||||||
|
label="供应商名称"
|
||||||
|
name="name"
|
||||||
|
rules={[{ required: true, message: '请输入供应商名称' }]}
|
||||||
|
>
|
||||||
|
<Input placeholder="请输入供应商名称" />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label="联系人"
|
||||||
|
name="contact"
|
||||||
|
rules={[{ required: true, message: '请输入联系人姓名' }]}
|
||||||
|
>
|
||||||
|
<Input placeholder="请输入联系人姓名" />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label="联系电话"
|
||||||
|
name="phone"
|
||||||
|
rules={[
|
||||||
|
{ required: true, message: '请输入联系电话' },
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input placeholder="请输入联系电话" />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label="地址"
|
||||||
|
name="address"
|
||||||
|
>
|
||||||
|
<Input.TextArea rows={3} placeholder="请输入详细地址" />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label="状态"
|
||||||
|
name="status"
|
||||||
|
rules={[{ required: true, message: '请选择状态' }]}
|
||||||
|
>
|
||||||
|
<Select>
|
||||||
|
<Select.Option value="active">启用</Select.Option>
|
||||||
|
<Select.Option value="inactive">禁用</Select.Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label="备注"
|
||||||
|
name="remark"
|
||||||
|
>
|
||||||
|
<Input.TextArea rows={3} placeholder="请输入备注信息" />
|
||||||
|
</Form.Item>
|
||||||
|
</Card>
|
||||||
|
</Form>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SupplierForm;
|
||||||
@@ -1,41 +1,154 @@
|
|||||||
import React from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Card, Table, Button } from 'antd';
|
import { Card, Table, Button, message, Popconfirm, Tag, Space } from 'antd';
|
||||||
import { PlusOutlined } from '@ant-design/icons';
|
import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||||
|
import { useResources } from '@/hooks/resource/useResource';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
const SupplierPage = () => {
|
const SupplierPage = () => {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [pagination, setPagination] = useState({ current: 1, pageSize: 10 });
|
||||||
|
const [sorter, setSorter] = useState({ field: 'created_at', order: 'descend' });
|
||||||
|
|
||||||
|
const {
|
||||||
|
resources: suppliers,
|
||||||
|
loading,
|
||||||
|
total,
|
||||||
|
fetchResources: fetchSuppliers,
|
||||||
|
deleteResource: deleteSupplier
|
||||||
|
} = useResources(pagination, sorter, 'supplier');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchSuppliers();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleTableChange = (pagination, filters, sorter) => {
|
||||||
|
setPagination(pagination);
|
||||||
|
setSorter(sorter);
|
||||||
|
fetchSuppliers({
|
||||||
|
current: pagination.current,
|
||||||
|
pageSize: pagination.pageSize,
|
||||||
|
field: sorter.field,
|
||||||
|
order: sorter.order,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = async (id) => {
|
||||||
|
try {
|
||||||
|
await deleteSupplier(id);
|
||||||
|
message.success('删除成功');
|
||||||
|
fetchSuppliers();
|
||||||
|
} catch (error) {
|
||||||
|
message.error('删除失败:' + error.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: '供应商名称',
|
title: '供应商名称',
|
||||||
dataIndex: 'name',
|
dataIndex: ['attributes', 'name'],
|
||||||
key: 'name',
|
key: 'name',
|
||||||
|
ellipsis: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '联系人',
|
title: '联系人',
|
||||||
dataIndex: 'contact',
|
dataIndex: ['attributes', 'contact'],
|
||||||
key: 'contact',
|
key: 'contact',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '电话',
|
title: '电话',
|
||||||
dataIndex: 'phone',
|
dataIndex: ['attributes', 'phone'],
|
||||||
key: 'phone',
|
key: 'phone',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '状态',
|
title: '状态',
|
||||||
dataIndex: 'status',
|
dataIndex: ['attributes', 'status'],
|
||||||
key: 'status',
|
key: 'status',
|
||||||
|
render: (status) => (
|
||||||
|
<Tag color={status === 'active' ? 'green' : 'red'}>
|
||||||
|
{status === 'active' ? '启用' : '禁用'}
|
||||||
|
</Tag>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '创建日期',
|
||||||
|
dataIndex: 'created_at',
|
||||||
|
key: 'created_at',
|
||||||
|
sorter: true,
|
||||||
|
width: 180,
|
||||||
|
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: '操作',
|
||||||
|
key: 'action',
|
||||||
|
width: 150,
|
||||||
|
render: (_, record) => (
|
||||||
|
<Space size={0}>
|
||||||
|
<Button
|
||||||
|
size='small'
|
||||||
|
type="link"
|
||||||
|
icon={<EditOutlined />}
|
||||||
|
onClick={() => navigate(`/company/supplierInfo/${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 (
|
return (
|
||||||
<Card
|
<Card
|
||||||
title="供应商管理"
|
title={
|
||||||
|
<Space>
|
||||||
|
<span>供应商管理</span>
|
||||||
|
<Tag color="blue">{total} 个供应商</Tag>
|
||||||
|
</Space>
|
||||||
|
}
|
||||||
|
className='h-full w-full overflow-auto'
|
||||||
extra={
|
extra={
|
||||||
<Button type="primary" icon={<PlusOutlined />}>
|
<Button
|
||||||
|
type="primary"
|
||||||
|
icon={<PlusOutlined />}
|
||||||
|
onClick={() => navigate('/company/supplierInfo')}
|
||||||
|
>
|
||||||
新增供应商
|
新增供应商
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Table columns={columns} dataSource={[]} rowKey="id" />
|
<Table
|
||||||
|
columns={columns}
|
||||||
|
dataSource={suppliers}
|
||||||
|
rowKey="id"
|
||||||
|
loading={loading}
|
||||||
|
onChange={handleTableChange}
|
||||||
|
pagination={{
|
||||||
|
...pagination,
|
||||||
|
total,
|
||||||
|
showSizeChanger: true,
|
||||||
|
showQuickJumper: true,
|
||||||
|
showTotal: (total) => `共 ${total} 条记录`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ export const MembershipTable = ({ memberships, onUpdate, onDelete, onAdd }) => {
|
|||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
key: 'action',
|
key: 'action',
|
||||||
|
width: 180,
|
||||||
render: (_, record) => {
|
render: (_, record) => {
|
||||||
const editable = isEditing(record);
|
const editable = isEditing(record);
|
||||||
return editable ? (
|
return editable ? (
|
||||||
@@ -76,6 +77,7 @@ export const MembershipTable = ({ memberships, onUpdate, onDelete, onAdd }) => {
|
|||||||
icon={<SaveOutlined />}
|
icon={<SaveOutlined />}
|
||||||
onClick={() => save(record.id)}
|
onClick={() => save(record.id)}
|
||||||
type="link"
|
type="link"
|
||||||
|
size='small'
|
||||||
>
|
>
|
||||||
保存
|
保存
|
||||||
</Button>
|
</Button>
|
||||||
@@ -83,6 +85,7 @@ export const MembershipTable = ({ memberships, onUpdate, onDelete, onAdd }) => {
|
|||||||
icon={<CloseOutlined />}
|
icon={<CloseOutlined />}
|
||||||
onClick={cancel}
|
onClick={cancel}
|
||||||
type="link"
|
type="link"
|
||||||
|
size='small'
|
||||||
>
|
>
|
||||||
取消
|
取消
|
||||||
</Button>
|
</Button>
|
||||||
@@ -94,6 +97,7 @@ export const MembershipTable = ({ memberships, onUpdate, onDelete, onAdd }) => {
|
|||||||
icon={<EditOutlined />}
|
icon={<EditOutlined />}
|
||||||
onClick={() => edit(record)}
|
onClick={() => edit(record)}
|
||||||
type="link"
|
type="link"
|
||||||
|
size='small'
|
||||||
>
|
>
|
||||||
编辑
|
编辑
|
||||||
</Button>
|
</Button>
|
||||||
@@ -105,6 +109,7 @@ export const MembershipTable = ({ memberships, onUpdate, onDelete, onAdd }) => {
|
|||||||
<Button
|
<Button
|
||||||
icon={<DeleteOutlined />}
|
icon={<DeleteOutlined />}
|
||||||
type="link"
|
type="link"
|
||||||
|
size='small'
|
||||||
danger
|
danger
|
||||||
>
|
>
|
||||||
删除
|
删除
|
||||||
|
|||||||
@@ -100,19 +100,22 @@ export const TeamTable = ({ tableLoading,pagination,dataSource, onTableChange,on
|
|||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
key: 'action',
|
key: 'action',
|
||||||
|
width: 180,
|
||||||
render: (_, record) => {
|
render: (_, record) => {
|
||||||
const editable = isEditing(record);
|
const editable = isEditing(record);
|
||||||
return editable ? (
|
return editable ? (
|
||||||
<Space>
|
<Space size={0}>
|
||||||
<Button
|
<Button
|
||||||
icon={<SaveOutlined />}
|
icon={<SaveOutlined />}
|
||||||
onClick={() => save(record.id)}
|
onClick={() => save(record.id)}
|
||||||
type="link"
|
type="link"
|
||||||
|
size='small'
|
||||||
loading={loading}
|
loading={loading}
|
||||||
>
|
>
|
||||||
保存
|
保存
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
|
size='small'
|
||||||
icon={<CloseOutlined />}
|
icon={<CloseOutlined />}
|
||||||
onClick={cancel}
|
onClick={cancel}
|
||||||
type="link"
|
type="link"
|
||||||
@@ -123,6 +126,7 @@ export const TeamTable = ({ tableLoading,pagination,dataSource, onTableChange,on
|
|||||||
) : (
|
) : (
|
||||||
<Space>
|
<Space>
|
||||||
<Button
|
<Button
|
||||||
|
size='small'
|
||||||
disabled={editingKey !== ''}
|
disabled={editingKey !== ''}
|
||||||
icon={<EditOutlined />}
|
icon={<EditOutlined />}
|
||||||
onClick={() => edit(record)}
|
onClick={() => edit(record)}
|
||||||
@@ -138,6 +142,7 @@ export const TeamTable = ({ tableLoading,pagination,dataSource, onTableChange,on
|
|||||||
icon={<DeleteOutlined />}
|
icon={<DeleteOutlined />}
|
||||||
type="link"
|
type="link"
|
||||||
danger
|
danger
|
||||||
|
size='small'
|
||||||
loading={loading}
|
loading={loading}
|
||||||
>
|
>
|
||||||
删除
|
删除
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { supabase } from '@/config/supabase';
|
import { supabase } from '@/config/supabase';
|
||||||
|
|
||||||
export const resourceService = {
|
export const resourceService = {
|
||||||
async getResources({ page = 1, pageSize = 10, orderBy = 'created_at', ascending = false, searchQuery = '' }) {
|
async getResources({ page = 1, pageSize = 10, orderBy = 'created_at', ascending = false, searchQuery = '', type = '' }) {
|
||||||
try {
|
try {
|
||||||
let query = supabase
|
let query = supabase
|
||||||
.from('resources')
|
.from('resources')
|
||||||
.select('*', { count: 'exact' })
|
.select('*', { count: 'exact' })
|
||||||
.eq('type','quota')
|
.eq('type', type)
|
||||||
|
|
||||||
if (searchQuery) {
|
if (searchQuery) {
|
||||||
query = query.or(`external_id.ilike.%${searchQuery}%`);
|
query = query.or(`external_id.ilike.%${searchQuery}%`);
|
||||||
|
|||||||
Reference in New Issue
Block a user