TenantForm.tsx 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. import React from 'react';
  2. import { useForm } from 'react-hook-form';
  3. import { zodResolver } from '@hookform/resolvers/zod';
  4. import { CreateTenantDto, UpdateTenantDto } from '@d8d/tenant-module-mt/schemas';
  5. import { Button } from '@d8d/shared-ui-components/components/ui/button';
  6. import { Input } from '@d8d/shared-ui-components/components/ui/input';
  7. import { Textarea } from '@d8d/shared-ui-components/components/ui/textarea';
  8. import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@d8d/shared-ui-components/components/ui/form';
  9. import { Switch } from '@d8d/shared-ui-components/components/ui/switch';
  10. import type { InferResponseType } from 'hono/client';
  11. import type { tenantClient } from '../api/tenantClient';
  12. type TenantResponse = InferResponseType<typeof tenantClient.index.$get, 200>['data'][0];
  13. interface TenantFormProps {
  14. tenant?: TenantResponse;
  15. onSubmit: (data: Record<string, unknown>) => Promise<void>;
  16. onCancel: () => void;
  17. isSubmitting?: boolean;
  18. }
  19. export const TenantForm: React.FC<TenantFormProps> = ({
  20. tenant,
  21. onSubmit,
  22. onCancel,
  23. isSubmitting = false
  24. }) => {
  25. const isEditing = !!tenant;
  26. const form = useForm({
  27. resolver: zodResolver(isEditing ? UpdateTenantDto : CreateTenantDto),
  28. defaultValues: {
  29. name: tenant?.name || '',
  30. code: tenant?.code || '',
  31. contactName: tenant?.contactName || '',
  32. phone: tenant?.phone || '',
  33. status: tenant?.status || 1,
  34. config: tenant?.config || null,
  35. rsaPublicKey: tenant?.rsaPublicKey || '',
  36. aesKey: tenant?.aesKey || '',
  37. },
  38. });
  39. const handleSubmit = async (data: Record<string, unknown>) => {
  40. // 过滤空值
  41. const submitData = Object.fromEntries(
  42. Object.entries(data).filter(([, value]) => {
  43. if (value === '' || value === null) return false;
  44. if (typeof value === 'string' && value.trim() === '') return false;
  45. return true;
  46. })
  47. );
  48. await onSubmit(submitData);
  49. };
  50. return (
  51. <Form {...form}>
  52. <form onSubmit={form.handleSubmit(handleSubmit)} className="space-y-4">
  53. <FormField
  54. control={form.control}
  55. name="name"
  56. render={({ field }) => (
  57. <FormItem>
  58. <FormLabel>租户名称</FormLabel>
  59. <FormControl>
  60. <Input placeholder="请输入租户名称" {...field} />
  61. </FormControl>
  62. <FormDescription>
  63. 租户的显示名称
  64. </FormDescription>
  65. <FormMessage />
  66. </FormItem>
  67. )}
  68. />
  69. <FormField
  70. control={form.control}
  71. name="code"
  72. render={({ field }) => (
  73. <FormItem>
  74. <FormLabel className="flex items-center">
  75. 租户代码
  76. <span className="text-red-500 ml-1">*</span>
  77. </FormLabel>
  78. <FormControl>
  79. <Input
  80. placeholder="请输入租户代码"
  81. {...field}
  82. disabled={isEditing}
  83. />
  84. </FormControl>
  85. <FormDescription>
  86. 租户的唯一标识符,创建后不可修改
  87. </FormDescription>
  88. <FormMessage />
  89. </FormItem>
  90. )}
  91. />
  92. <FormField
  93. control={form.control}
  94. name="contactName"
  95. render={({ field }) => (
  96. <FormItem>
  97. <FormLabel>联系人姓名</FormLabel>
  98. <FormControl>
  99. <Input placeholder="请输入联系人姓名" {...field} />
  100. </FormControl>
  101. <FormMessage />
  102. </FormItem>
  103. )}
  104. />
  105. <FormField
  106. control={form.control}
  107. name="phone"
  108. render={({ field }) => (
  109. <FormItem>
  110. <FormLabel>联系电话</FormLabel>
  111. <FormControl>
  112. <Input placeholder="请输入联系电话" {...field} />
  113. </FormControl>
  114. <FormMessage />
  115. </FormItem>
  116. )}
  117. />
  118. <FormField
  119. control={form.control}
  120. name="status"
  121. render={({ field }) => (
  122. <FormItem className="flex flex-row items-center justify-between rounded-lg border p-4">
  123. <div className="space-y-0.5">
  124. <FormLabel className="text-base">租户状态</FormLabel>
  125. <FormDescription>
  126. 禁用后租户将无法使用系统
  127. </FormDescription>
  128. </div>
  129. <FormControl>
  130. <Switch
  131. checked={field.value === 1}
  132. onCheckedChange={(checked) => field.onChange(checked ? 1 : 2)}
  133. />
  134. </FormControl>
  135. </FormItem>
  136. )}
  137. />
  138. <FormField
  139. control={form.control}
  140. name="rsaPublicKey"
  141. render={({ field }) => (
  142. <FormItem>
  143. <FormLabel>RSA公钥</FormLabel>
  144. <FormControl>
  145. <Textarea
  146. placeholder="请输入RSA公钥"
  147. rows={4}
  148. {...field}
  149. />
  150. </FormControl>
  151. <FormDescription>
  152. 用于加密通信的RSA公钥
  153. </FormDescription>
  154. <FormMessage />
  155. </FormItem>
  156. )}
  157. />
  158. <FormField
  159. control={form.control}
  160. name="aesKey"
  161. render={({ field }) => (
  162. <FormItem>
  163. <FormLabel>AES密钥</FormLabel>
  164. <FormControl>
  165. <Input
  166. placeholder="请输入AES密钥"
  167. {...field}
  168. />
  169. </FormControl>
  170. <FormDescription>
  171. 用于数据加密的AES密钥(32位字符)
  172. </FormDescription>
  173. <FormMessage />
  174. </FormItem>
  175. )}
  176. />
  177. <div className="flex justify-end gap-2 pt-4">
  178. <Button type="button" variant="outline" onClick={onCancel}>
  179. 取消
  180. </Button>
  181. <Button type="submit" disabled={isSubmitting}>
  182. {isSubmitting ? '提交中...' : (isEditing ? '更新租户' : '创建租户')}
  183. </Button>
  184. </div>
  185. </form>
  186. </Form>
  187. );
  188. };