|
|
@@ -0,0 +1,88 @@
|
|
|
+import React, { useState } from 'react';
|
|
|
+import { useQuery } from '@tanstack/react-query';
|
|
|
+import { Select, Spin } from 'antd';
|
|
|
+import type { SelectProps } from 'antd';
|
|
|
+import { InferResponseType } from 'hono/client';
|
|
|
+import { hetongClient } from '@/client/api';
|
|
|
+
|
|
|
+// 定义合同数据类型
|
|
|
+type ContractItem = InferResponseType<typeof hetongClient[':id']['$get'], 200>;
|
|
|
+type ContractListResponse = InferResponseType<typeof hetongClient.$get, 200>;
|
|
|
+
|
|
|
+// 定义组件属性接口
|
|
|
+interface ContractSelectProps {
|
|
|
+ value?: number;
|
|
|
+ onChange?: (value?: number) => void;
|
|
|
+ placeholder?: string;
|
|
|
+ disabled?: boolean;
|
|
|
+}
|
|
|
+
|
|
|
+const ContractSelect: React.FC<ContractSelectProps> = ({
|
|
|
+ value,
|
|
|
+ onChange,
|
|
|
+ placeholder = '请选择合同',
|
|
|
+ disabled = false
|
|
|
+}) => {
|
|
|
+ const [searchValue, setSearchValue] = useState('');
|
|
|
+
|
|
|
+ // 使用React Query获取合同列表数据
|
|
|
+ const { data: contractsData, isLoading, error } = useQuery<ContractListResponse>({
|
|
|
+ queryKey: ['contracts', searchValue],
|
|
|
+ queryFn: async () => {
|
|
|
+ const res = await hetongClient.$get({
|
|
|
+ query: {
|
|
|
+ page: 1,
|
|
|
+ pageSize: 1000,
|
|
|
+ keyword: searchValue
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ if (!res.ok) {
|
|
|
+ throw new Error('获取合同列表失败');
|
|
|
+ }
|
|
|
+
|
|
|
+ return res.json();
|
|
|
+ },
|
|
|
+ });
|
|
|
+
|
|
|
+ // 处理搜索输入变化
|
|
|
+ const handleSearch = (value: string) => {
|
|
|
+ setSearchValue(value);
|
|
|
+ };
|
|
|
+
|
|
|
+ // 格式化合同数据为Select组件所需的选项格式
|
|
|
+ const options = contractsData?.data?.map(contract => ({
|
|
|
+ label: `${contract.contractNumber} - ${contract.client?.name || '未知客户'}`,
|
|
|
+ value: contract.id,
|
|
|
+ })) || [];
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div style={{ position: 'relative' }}>
|
|
|
+ <Select
|
|
|
+ value={value}
|
|
|
+ onChange={onChange}
|
|
|
+ placeholder={placeholder}
|
|
|
+ disabled={disabled || isLoading}
|
|
|
+ showSearch
|
|
|
+ filterOption={false}
|
|
|
+ onSearch={handleSearch}
|
|
|
+ style={{ width: '100%' }}
|
|
|
+ options={options}
|
|
|
+ notFoundContent={isLoading ? <Spin size="small" /> : '未找到匹配合同'}
|
|
|
+ />
|
|
|
+ {isLoading && (
|
|
|
+ <div style={{
|
|
|
+ position: 'absolute',
|
|
|
+ top: '50%',
|
|
|
+ right: '16px',
|
|
|
+ transform: 'translateY(-50%)',
|
|
|
+ pointerEvents: 'none'
|
|
|
+ }}>
|
|
|
+ <Spin size="small" />
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+export default ContractSelect;
|