Ver Fonte

fix(story-008.004): 修复RPC类型推导和表单类型问题

- 修复RPC类型推导语法:使用正确的`['$put']`和`['$delete']`语法
- 使用RPC推导的类型替代schema类型:`CreateSalaryRequest`、`UpdateSalaryRequest`、`SalaryResponse`
- 修复表单类型不匹配问题
- 根据集成测试确认更新API的ID通过param传递,不在json中

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
yourname há 1 mês atrás
pai
commit
aa9be2d23a

+ 9 - 12
allin-packages/salary-management-ui/src/api/types.ts

@@ -1,9 +1,11 @@
 import type { InferResponseType, InferRequestType } from 'hono/client';
 import { salaryClient } from './salaryClient';
-import type { SalaryLevel, QuerySalaryDto, GetSalaryByProvinceCityDto } from '@d8d/allin-salary-module/schemas';
 
 // 薪资搜索参数类型
-export type SalarySearchParams = QuerySalaryDto & {
+export type SalarySearchParams = {
+  provinceId?: number;
+  cityId?: number;
+  districtId?: number;
   page: number;
   limit: number;
 };
@@ -14,21 +16,16 @@ export type PaginatedResponse<T> = {
   total: number;
 };
 
-// 使用Hono类型推导
+// 使用Hono类型推导 - 请求类型
 export type CreateSalaryRequest = InferRequestType<typeof salaryClient.create.$post>['json'];
-export type UpdateSalaryRequest = InferRequestType<typeof salaryClient.update[':id']['$put']>['json'] & {
-  id: number;
-};
+export type UpdateSalaryRequest = InferRequestType<typeof salaryClient.update[':id']['$put']>['json'];
 export type DeleteSalaryRequest = InferRequestType<typeof salaryClient.delete[':id']['$delete']>['param'];
 
+// 使用Hono类型推导 - 响应类型
 export type SalaryResponse = InferResponseType<typeof salaryClient.list.$get, 200>['data'][0];
 export type SalaryListResponse = InferResponseType<typeof salaryClient.list.$get, 200>;
 export type SalaryDetailResponse = InferResponseType<typeof salaryClient.detail[':id']['$get'], 200>;
 export type SalaryByProvinceCityResponse = InferResponseType<typeof salaryClient.byProvinceCity.$get, 200>;
 
-// 导出后端模块的类型
-export type {
-  SalaryLevel,
-  QuerySalaryDto,
-  GetSalaryByProvinceCityDto
-};
+// 查询参数类型
+export type QuerySalaryParams = InferRequestType<typeof salaryClient.list.$get>['query'];

+ 21 - 15
allin-packages/salary-management-ui/src/components/SalaryManagement.tsx

@@ -16,7 +16,13 @@ import { DataTablePagination } from '@d8d/shared-ui-components/components/admin/
 import { AreaSelect } from '@d8d/area-management-ui/components';
 import { salaryClientManager } from '../api/salaryClient';
 import { CreateSalarySchema, UpdateSalarySchema } from '@d8d/allin-salary-module/schemas';
-import type { CreateSalaryDto, UpdateSalaryDto, SalaryLevel, QuerySalaryDto } from '@d8d/allin-salary-module/schemas';
+import type {
+  CreateSalaryRequest,
+  UpdateSalaryRequest,
+  SalaryResponse,
+  SalaryListResponse,
+  QuerySalaryParams
+} from '../api/types';
 
 interface SalarySearchParams {
   page: number;
@@ -33,8 +39,8 @@ const SalaryManagement: React.FC = () => {
   const [salaryToDelete, setSalaryToDelete] = useState<number | null>(null);
   const [areaValue, setAreaValue] = useState<{ provinceId?: number; cityId?: number; districtId?: number }>({});
 
-  // 表单实例
-  const createForm = useForm<CreateSalaryDto>({
+  // 表单实例 - 使用RPC推导的类型
+  const createForm = useForm<CreateSalaryRequest>({
     resolver: zodResolver(CreateSalarySchema),
     defaultValues: {
       basicSalary: 0,
@@ -44,7 +50,7 @@ const SalaryManagement: React.FC = () => {
     }
   });
 
-  const updateForm = useForm<UpdateSalaryDto>({
+  const updateForm = useForm<UpdateSalaryRequest>({
     resolver: zodResolver(UpdateSalarySchema),
     defaultValues: {}
   });
@@ -58,7 +64,7 @@ const SalaryManagement: React.FC = () => {
   const { data, isLoading, refetch } = useQuery({
     queryKey: ['salaries', searchParams],
     queryFn: async () => {
-      const query: QuerySalaryDto = {
+      const query: QuerySalaryParams = {
         skip: (searchParams.page - 1) * searchParams.limit,
         take: searchParams.limit
       };
@@ -66,7 +72,7 @@ const SalaryManagement: React.FC = () => {
       if (searchParams.provinceId) query.provinceId = searchParams.provinceId;
       if (searchParams.cityId) query.cityId = searchParams.cityId;
 
-      const res = await salaryClientManager.get().$get({ query });
+      const res = await salaryClientManager.get().list.$get({ query });
       if (res.status !== 200) throw new Error('获取薪资列表失败');
       return await res.json();
     }
@@ -74,7 +80,7 @@ const SalaryManagement: React.FC = () => {
 
   // 创建薪资
   const createMutation = useMutation({
-    mutationFn: async (data: CreateSalaryDto) => {
+    mutationFn: async (data: CreateSalaryRequest) => {
       const res = await salaryClientManager.get().create.$post({ json: data });
       if (res.status !== 200) throw new Error('创建薪资失败');
       return await res.json();
@@ -93,8 +99,8 @@ const SalaryManagement: React.FC = () => {
 
   // 更新薪资
   const updateMutation = useMutation({
-    mutationFn: async (data: UpdateSalaryDto) => {
-      const res = await salaryClientManager.get().update[':id'].$put({
+    mutationFn: async (data: UpdateSalaryRequest) => {
+      const res = await salaryClientManager.get().update[':id']['$put']({
         param: { id: data.id! },
         json: data
       });
@@ -114,7 +120,7 @@ const SalaryManagement: React.FC = () => {
   // 删除薪资
   const deleteMutation = useMutation({
     mutationFn: async (id: number) => {
-      const res = await salaryClientManager.get().delete[':id'].$delete({ param: { id } });
+      const res = await salaryClientManager.get().delete[':id']['$delete']({ param: { id } });
       if (res.status !== 200) throw new Error('删除薪资失败');
       return await res.json();
     },
@@ -157,7 +163,7 @@ const SalaryManagement: React.FC = () => {
   };
 
   // 显示编辑模态框
-  const showEditModal = (salary: SalaryLevel) => {
+  const showEditModal = (salary: SalaryResponse) => {
     setIsCreateForm(false);
     updateForm.reset({
       id: salary.id,
@@ -184,7 +190,7 @@ const SalaryManagement: React.FC = () => {
   };
 
   // 处理创建表单提交
-  const handleCreateSubmit = (data: CreateSalaryDto) => {
+  const handleCreateSubmit = (data: CreateSalaryRequest) => {
     const submitData = {
       ...data,
       provinceId: areaValue.provinceId!,
@@ -195,7 +201,7 @@ const SalaryManagement: React.FC = () => {
   };
 
   // 处理更新表单提交
-  const handleUpdateSubmit = (data: UpdateSalaryDto) => {
+  const handleUpdateSubmit = (data: UpdateSalaryRequest) => {
     updateMutation.mutate(data);
   };
 
@@ -210,7 +216,7 @@ const SalaryManagement: React.FC = () => {
   };
 
   // 处理数值变化,实时计算总薪资
-  const handleValueChange = (field: keyof CreateSalaryDto, value: number) => {
+  const handleValueChange = (field: keyof CreateSalaryRequest, value: number) => {
     if (isCreateForm) {
       const formValues = createForm.getValues();
       const total = calculateTotalSalary(
@@ -281,7 +287,7 @@ const SalaryManagement: React.FC = () => {
                 </TableRow>
               </TableHeader>
               <TableBody>
-                {data?.data?.map((salary: SalaryLevel) => (
+                {data?.data?.map((salary: SalaryResponse) => (
                   <TableRow key={salary.id}>
                     <TableCell>{salary.id}</TableCell>
                     <TableCell>{salary.province?.name || salary.provinceId}</TableCell>

+ 4 - 4
allin-packages/salary-management-ui/src/components/SalarySelector.tsx

@@ -8,20 +8,20 @@ import { Alert, AlertDescription } from '@d8d/shared-ui-components/components/ui
 import { Calculator, AlertCircle } from 'lucide-react';
 import { AreaSelect } from '@d8d/area-management-ui/components';
 import { salaryClientManager } from '../api/salaryClient';
-import type { SalaryLevel } from '@d8d/allin-salary-module/schemas';
+import type { SalaryByProvinceCityResponse } from '../api/types';
 
 export interface SalarySelectorProps {
   value?: {
     provinceId?: number;
     cityId?: number;
     salary?: number;
-    salaryDetail?: SalaryLevel;
+    salaryDetail?: SalaryByProvinceCityResponse;
   };
   onChange?: (value: {
     provinceId?: number;
     cityId?: number;
     salary?: number;
-    salaryDetail?: SalaryLevel;
+    salaryDetail?: SalaryByProvinceCityResponse;
   }) => void;
   disabled?: boolean;
   allowManualAdjust?: boolean;
@@ -75,7 +75,7 @@ const SalarySelector: React.FC<SalarySelectorProps> = ({
   });
 
   // 计算总薪资
-  const calculateTotalSalary = (salary: SalaryLevel | null | undefined): number => {
+  const calculateTotalSalary = (salary: SalaryByProvinceCityResponse): number => {
     if (!salary) return 0;
     return salary.basicSalary + (salary.allowance || 0) - (salary.insurance || 0) - (salary.housingFund || 0);
   };