This commit is contained in:
‘Liammcl’
2024-12-29 09:55:17 +08:00
parent 56f4522139
commit 8a7762142c
7 changed files with 144 additions and 47 deletions

View File

@@ -44,9 +44,9 @@ const QuotationPage = () => {
const [selectedTemplateId, setSelectedTemplateId] = useState(null);
const [templates, setTemplates] = useState([]);
const [loading, setLoading] = useState(false);
const [selectedCategory, setSelectedCategory] = useState("all");
const [categories, setCategories] = useState([]);
const [customers,setCustomers]=useState([])
const [loadingCustomers, setLoadingCustomers] = useState(false);
const [selectedCustomer, setSelectedCustomer] = useState(null);
const {
resources: quotations,
loading: loadingQuotations,
@@ -56,9 +56,18 @@ const QuotationPage = () => {
} = useResources(pagination, sorter, "quota");
useEffect(() => {
fetchQuotations();
}, []);
fetchQuotations({
current: pagination.current,
pageSize: pagination.pageSize,
field: sorter.field,
order: sorter.order,
search: selectedCustomer ? JSON.stringify({ customerId: selectedCustomer }) : "" // 添加搜索参数
});
}, [selectedCustomer, pagination.current, pagination.pageSize, sorter]); // 添加更多依赖项
useEffect(()=>{
fetchCustomers();
},[])
const handleTableChange = (pagination, filters, sorter) => {
setPagination(pagination);
setSorter(sorter);
@@ -106,11 +115,7 @@ const QuotationPage = () => {
}
}, [isModalVisible]);
useEffect(() => {
if (templates.length > 0) {
setCategories(getAllCategories(templates));
}
}, [templates]);
const handleTemplateSelect = (templateId) => {
setSelectedTemplateId(templateId);
@@ -126,23 +131,6 @@ const QuotationPage = () => {
setSelectedTemplateId(null);
};
const getAllCategories = (templates) => {
const categorySet = new Set();
templates.forEach((template) => {
template.attributes.category?.forEach((cat) => {
categorySet.add(JSON.stringify(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)
);
};
const columns = [
{
title: "报价单名称",
@@ -333,6 +321,24 @@ const QuotationPage = () => {
setLoading(false);
}
};
const fetchCustomers = async () => {
setLoadingCustomers(true);
try {
const { data, error } = await supabase
.from('resources')
.select('*')
.eq('type', 'customer')
.order('created_at', { ascending: false });
if (error) throw error;
setCustomers(data || []);
} catch (error) {
console.error('获取客户列表失败:', error);
message.error('获取客户列表失败');
} finally {
setLoadingCustomers(false);
}
};
return (
<>
<Card
@@ -344,7 +350,21 @@ const QuotationPage = () => {
}
className="h-full w-full overflow-auto"
extra={
<div className="flex justify-between my-4">
<Space>
<Select
allowClear
loading={loadingCustomers}
placeholder="按客户筛选"
style={{ width: 200 }}
options={customers.map(c => ({
label: c.attributes.name,
value: c.id
}))}
onChange={(value) => {
setSelectedCustomer(value);
setPagination({ current: 1, pageSize: pagination.pageSize });
}}
/>
<Button
type="primary"
icon={<PlusOutlined />}
@@ -352,7 +372,7 @@ const QuotationPage = () => {
>
新增报价单
</Button>
</div>
</Space>
}
>
<Table

View File

@@ -177,7 +177,7 @@ const TaskTemplate = ({ id, isView, onCancel,isEdit }) => {
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>相关任务</span>
</span>
}
bordered={false}

View File

@@ -10,6 +10,7 @@ import {
Spin,
Modal,
Empty,
Select,
Typography,
} from "antd";
import {
@@ -37,7 +38,8 @@ const TaskPage = () => {
const [selectedTemplateId, setSelectedTemplateId] = useState(null);
const [templates, setTemplates] = useState([]);
const [loading, setLoading] = useState(false);
const [customers,setCustomers]=useState([])
const [loadingCustomers, setLoadingCustomers] = useState(false);
const {
resources: tasks,
loading: loadingTasks,
@@ -45,11 +47,30 @@ const TaskPage = () => {
fetchResources: fetchTasks,
deleteResource: deleteTask,
} = useResources(pagination, sorter, "task");
const [selectedCustomer, setSelectedCustomer] = useState(null);
useEffect(() => {
fetchTasks();
fetchCustomers()
}, []);
const fetchCustomers = async () => {
setLoadingCustomers(true);
try {
const { data, error } = await supabase
.from('resources')
.select('*')
.eq('type', 'customer')
.order('created_at', { ascending: false });
if (error) throw error;
setCustomers(data || []);
} catch (error) {
console.error('获取客户列表失败:', error);
message.error('获取客户列表失败');
} finally {
setLoadingCustomers(false);
}
};
const columns = [
{
title: "任务名称",
@@ -58,6 +79,24 @@ const TaskPage = () => {
ellipsis: true,
className: "dark:text-gray-200",
},
{
title: "相关人员",
dataIndex: ["attributes", "customers"],
key: "customers",
render: (customers, record) => (
<Space>
{customers?.map((customer) => (
<Tag
key={customer.id}
color="blue"
className="cursor-pointer"
>
{customer.name}
</Tag>
))}
</Space>
),
},
{
title: "开始时间",
dataIndex: ["attributes", "timeRange"],
@@ -258,6 +297,7 @@ const TaskPage = () => {
pageSize: pagination.pageSize,
field: sorter.field,
order: sorter.order,
search: selectedCustomer ? JSON.stringify({ customerId: selectedCustomer }) : undefined
});
};
@@ -307,6 +347,29 @@ const TaskPage = () => {
}
className="h-full w-full overflow-auto dark:bg-gray-800 dark:border-gray-700"
extra={
<Space>
<Select
allowClear
loading={loadingCustomers}
placeholder="按客户筛选"
variant="filled"
style={{ width: 200 }}
options={customers.map(c => ({
label: c.attributes.name,
value: c.id
}))}
onChange={(value) => {
setSelectedCustomer(value);
setPagination({ current: 1, pageSize: pagination.pageSize });
fetchTasks({
current: 1,
pageSize: pagination.pageSize,
field: sorter.field,
order: sorter.order,
search: value ? JSON.stringify({ customerId: value }) : undefined
});
}}
/>
<Button
type="primary"
icon={<PlusOutlined />}
@@ -315,6 +378,7 @@ const TaskPage = () => {
>
新增任务
</Button>
</Space>
}
>
<Table

View File

@@ -629,11 +629,11 @@ const StorageManager = () => {
</div>
<div className="space-y-3">
<Search
<Input
variant="filled"
placeholder="搜索文件名..."
allowClear
onChange={(e) => setSearchText(e.target.value)}
className="w-full"
size="large"
/>
<div className=" p-3 rounded-lg shadow-sm">

View File

@@ -25,6 +25,8 @@ export const MembershipTable = ({ memberships, onUpdate, onDelete, onAdd }) => {
try {
const row = await form.validateFields();
setEditingKey('');
console.log(row,'row');
onUpdate(key, row);
} catch (error) {
console.error('Save failed:', error);
@@ -93,6 +95,11 @@ export const MembershipTable = ({ memberships, onUpdate, onDelete, onAdd }) => {
</Space>
) : (
<Space>
{!record.is_creator && (
<>
<Button
disabled={editingKey !== '' || record.isCreator}
icon={<EditOutlined />}
@@ -102,7 +109,6 @@ export const MembershipTable = ({ memberships, onUpdate, onDelete, onAdd }) => {
>
编辑
</Button>
{!record.isCreator && (
<Popconfirm
title="确定要删除该成员吗?"
onConfirm={() => onDelete(record.id)}
@@ -116,6 +122,7 @@ export const MembershipTable = ({ memberships, onUpdate, onDelete, onAdd }) => {
删除
</Button>
</Popconfirm>
</>
)}
</Space>
);

View File

@@ -162,7 +162,6 @@ const TeamManagement = () => {
try {
await updateTeam(id, values);
await loadTeams();
message.success('更新团队成功');
} catch (error) {
message.error('更新团队失败');
}

View File

@@ -9,13 +9,19 @@ export const resourceService = {
.eq('type', type)
if (searchQuery) {
query = query.or(`external_id.ilike.%${searchQuery}%`);
const searchParams = JSON.parse(searchQuery);
if (searchParams.customerId) {
query = query.filter('attributes->customers', 'cs',
JSON.stringify([{id: searchParams.customerId}])
);
}
}
if (orderBy) {
query = query.order(orderBy, { ascending });
}
const from = (page - 1) * pageSize;
query = query.range(from, from + pageSize - 1);
const to = from + pageSize - 1;
query = query.range(from, to);
const { data, count, error } = await query;
if (error) throw error;
@@ -25,6 +31,7 @@ export const resourceService = {
total: count || 0,
};
} catch (error) {
console.error("获取资源列表失败:", error);
throw error;
}
},