|
@@ -1,12 +1,21 @@
|
|
|
-import React from 'react';
|
|
|
|
|
|
|
+import React, { useState } from 'react';
|
|
|
import { useQuery } from '@tanstack/react-query';
|
|
import { useQuery } from '@tanstack/react-query';
|
|
|
import {
|
|
import {
|
|
|
- Select,
|
|
|
|
|
- SelectContent,
|
|
|
|
|
- SelectItem,
|
|
|
|
|
- SelectTrigger,
|
|
|
|
|
- SelectValue,
|
|
|
|
|
-} from '@d8d/shared-ui-components/components/ui/select';
|
|
|
|
|
|
|
+ Popover,
|
|
|
|
|
+ PopoverContent,
|
|
|
|
|
+ PopoverTrigger,
|
|
|
|
|
+} from '@d8d/shared-ui-components/components/ui/popover';
|
|
|
|
|
+import {
|
|
|
|
|
+ Command,
|
|
|
|
|
+ CommandEmpty,
|
|
|
|
|
+ CommandGroup,
|
|
|
|
|
+ CommandInput,
|
|
|
|
|
+ CommandItem,
|
|
|
|
|
+ CommandList,
|
|
|
|
|
+} from '@d8d/shared-ui-components/components/ui/command';
|
|
|
|
|
+import { Button } from '@d8d/shared-ui-components/components/ui/button';
|
|
|
|
|
+import { Check, ChevronsUpDown, Building2 } from 'lucide-react';
|
|
|
|
|
+import { cn } from '@d8d/shared-ui-components/utils/cn';
|
|
|
import { companyClientManager } from '../api/companyClient';
|
|
import { companyClientManager } from '../api/companyClient';
|
|
|
|
|
|
|
|
interface CompanySelectorProps {
|
|
interface CompanySelectorProps {
|
|
@@ -28,79 +37,144 @@ export const CompanySelector: React.FC<CompanySelectorProps> = ({
|
|
|
'data-testid': testId,
|
|
'data-testid': testId,
|
|
|
platformId,
|
|
platformId,
|
|
|
}) => {
|
|
}) => {
|
|
|
|
|
+ const [open, setOpen] = useState(false);
|
|
|
|
|
+ const [searchKeyword, setSearchKeyword] = useState('');
|
|
|
|
|
+
|
|
|
|
|
+ // 搜索公司
|
|
|
const {
|
|
const {
|
|
|
- data: companies,
|
|
|
|
|
- isLoading,
|
|
|
|
|
- isError,
|
|
|
|
|
|
|
+ data: searchResults,
|
|
|
|
|
+ isLoading: isSearching,
|
|
|
} = useQuery({
|
|
} = useQuery({
|
|
|
- queryKey: ['companies', platformId],
|
|
|
|
|
|
|
+ queryKey: ['searchCompanies', searchKeyword, platformId],
|
|
|
queryFn: async () => {
|
|
queryFn: async () => {
|
|
|
const client = companyClientManager.get();
|
|
const client = companyClientManager.get();
|
|
|
|
|
|
|
|
- let res;
|
|
|
|
|
- if (platformId) {
|
|
|
|
|
- // 按平台过滤公司
|
|
|
|
|
- res = await client.getCompaniesByPlatform[':platformId'].$get({
|
|
|
|
|
- param: { platformId }
|
|
|
|
|
- });
|
|
|
|
|
- } else {
|
|
|
|
|
- // 获取所有公司(分页,取前100条)
|
|
|
|
|
- res = await client.getAllCompanies.$get({
|
|
|
|
|
|
|
+ if (searchKeyword.trim()) {
|
|
|
|
|
+ // 有搜索词时使用搜索接口
|
|
|
|
|
+ const res = await client.searchCompanies.$get({
|
|
|
query: {
|
|
query: {
|
|
|
|
|
+ name: searchKeyword.trim(),
|
|
|
skip: 0,
|
|
skip: 0,
|
|
|
- take: 100
|
|
|
|
|
|
|
+ take: 50
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
|
|
+
|
|
|
|
|
+ if (res.status !== 200) throw new Error('搜索公司失败');
|
|
|
|
|
+ return await res.json();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 无搜索词时获取所有公司(前50条)
|
|
|
|
|
+ if (platformId) {
|
|
|
|
|
+ const res = await client.getCompaniesByPlatform[':platformId'].$get({
|
|
|
|
|
+ param: { platformId }
|
|
|
|
|
+ });
|
|
|
|
|
+ if (res.status !== 200) throw new Error('获取公司列表失败');
|
|
|
|
|
+ const companies = await res.json();
|
|
|
|
|
+ // 转换为统一格式
|
|
|
|
|
+ return {
|
|
|
|
|
+ data: companies,
|
|
|
|
|
+ total: companies.length
|
|
|
|
|
+ };
|
|
|
|
|
+ } else {
|
|
|
|
|
+ const res = await client.getAllCompanies.$get({
|
|
|
|
|
+ query: {
|
|
|
|
|
+ skip: 0,
|
|
|
|
|
+ take: 50
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ if (res.status !== 200) throw new Error('获取公司列表失败');
|
|
|
|
|
+ return await res.json();
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
+ },
|
|
|
|
|
+ enabled: open, // 只在下拉打开时查询
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
- if (res.status !== 200) throw new Error('获取公司列表失败');
|
|
|
|
|
|
|
+ // 获取当前选中的公司名称
|
|
|
|
|
+ const {
|
|
|
|
|
+ data: selectedCompany,
|
|
|
|
|
+ } = useQuery({
|
|
|
|
|
+ queryKey: ['company', value],
|
|
|
|
|
+ queryFn: async () => {
|
|
|
|
|
+ if (!value) return null;
|
|
|
|
|
+ const client = companyClientManager.get();
|
|
|
|
|
+ const res = await client.getCompany[':id'].$get({
|
|
|
|
|
+ param: { id: value }
|
|
|
|
|
+ });
|
|
|
|
|
+ if (res.status !== 200) throw new Error('获取公司详情失败');
|
|
|
return await res.json();
|
|
return await res.json();
|
|
|
},
|
|
},
|
|
|
|
|
+ enabled: !!value,
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- if (isError) {
|
|
|
|
|
- return (
|
|
|
|
|
- <div className="text-sm text-destructive">
|
|
|
|
|
- 加载公司列表失败
|
|
|
|
|
- </div>
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 处理响应数据格式
|
|
|
|
|
- let companyList: Array<{ id: number; companyName: string; platformId?: number }> = [];
|
|
|
|
|
-
|
|
|
|
|
- if (companies) {
|
|
|
|
|
- if (platformId) {
|
|
|
|
|
- // getCompaniesByPlatform 返回的是数组
|
|
|
|
|
- companyList = companies as Array<{ id: number; companyName: string; platformId?: number }>;
|
|
|
|
|
- } else {
|
|
|
|
|
- // getAllCompanies 返回的是 { data: [], total: number }
|
|
|
|
|
- companyList = (companies as { data: Array<{ id: number; companyName: string; platformId?: number }> }).data || [];
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ const companyList = searchResults?.data || [];
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
|
- <Select
|
|
|
|
|
- value={value?.toString() || ''}
|
|
|
|
|
- onValueChange={(val) => {
|
|
|
|
|
- if (val) {
|
|
|
|
|
- onChange?.(parseInt(val));
|
|
|
|
|
- }
|
|
|
|
|
- }}
|
|
|
|
|
- disabled={disabled || isLoading || companyList.length === 0}
|
|
|
|
|
- >
|
|
|
|
|
- <SelectTrigger className={className} data-testid={testId}>
|
|
|
|
|
- <SelectValue placeholder={isLoading ? '加载中...' : placeholder} />
|
|
|
|
|
- </SelectTrigger>
|
|
|
|
|
- <SelectContent>
|
|
|
|
|
- {companyList.map((company) => (
|
|
|
|
|
- <SelectItem key={company.id} value={company.id.toString()}>
|
|
|
|
|
- {company.companyName}
|
|
|
|
|
- </SelectItem>
|
|
|
|
|
- ))}
|
|
|
|
|
- </SelectContent>
|
|
|
|
|
- </Select>
|
|
|
|
|
|
|
+ <Popover open={open} onOpenChange={setOpen}>
|
|
|
|
|
+ <PopoverTrigger asChild>
|
|
|
|
|
+ <Button
|
|
|
|
|
+ variant="outline"
|
|
|
|
|
+ role="combobox"
|
|
|
|
|
+ aria-expanded={open}
|
|
|
|
|
+ disabled={disabled}
|
|
|
|
|
+ data-testid={testId}
|
|
|
|
|
+ className={cn(
|
|
|
|
|
+ "w-full justify-between font-normal",
|
|
|
|
|
+ !value && "text-muted-foreground",
|
|
|
|
|
+ className
|
|
|
|
|
+ )}
|
|
|
|
|
+ >
|
|
|
|
|
+ <span className="flex items-center gap-2 truncate">
|
|
|
|
|
+ <Building2 className="h-4 w-4 shrink-0 opacity-50" />
|
|
|
|
|
+ {selectedCompany?.companyName || placeholder}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
|
|
|
|
+ </Button>
|
|
|
|
|
+ </PopoverTrigger>
|
|
|
|
|
+ <PopoverContent className="w-[--radix-popover-trigger-width] p-0" align="start">
|
|
|
|
|
+ <Command shouldFilter={false}>
|
|
|
|
|
+ <CommandInput
|
|
|
|
|
+ placeholder="搜索公司名称..."
|
|
|
|
|
+ value={searchKeyword}
|
|
|
|
|
+ onValueChange={setSearchKeyword}
|
|
|
|
|
+ />
|
|
|
|
|
+ <CommandList>
|
|
|
|
|
+ {isSearching ? (
|
|
|
|
|
+ <div className="py-6 text-center text-sm text-muted-foreground">
|
|
|
|
|
+ 搜索中...
|
|
|
|
|
+ </div>
|
|
|
|
|
+ ) : companyList.length === 0 ? (
|
|
|
|
|
+ <CommandEmpty>
|
|
|
|
|
+ {searchKeyword ? "未找到匹配的公司" : "暂无公司数据"}
|
|
|
|
|
+ </CommandEmpty>
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ <CommandGroup>
|
|
|
|
|
+ {companyList.map((company) => (
|
|
|
|
|
+ <CommandItem
|
|
|
|
|
+ key={company.id}
|
|
|
|
|
+ value={company.id.toString()}
|
|
|
|
|
+ onSelect={(currentValue) => {
|
|
|
|
|
+ const selectedId = parseInt(currentValue);
|
|
|
|
|
+ onChange?.(selectedId);
|
|
|
|
|
+ setOpen(false);
|
|
|
|
|
+ setSearchKeyword('');
|
|
|
|
|
+ }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Check
|
|
|
|
|
+ className={cn(
|
|
|
|
|
+ "mr-2 h-4 w-4",
|
|
|
|
|
+ value === company.id ? "opacity-100" : "opacity-0"
|
|
|
|
|
+ )}
|
|
|
|
|
+ />
|
|
|
|
|
+ {company.companyName}
|
|
|
|
|
+ </CommandItem>
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </CommandGroup>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </CommandList>
|
|
|
|
|
+ </Command>
|
|
|
|
|
+ </PopoverContent>
|
|
|
|
|
+ </Popover>
|
|
|
);
|
|
);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-export default CompanySelector;
|
|
|
|
|
|
|
+export default CompanySelector;
|