Files
seclusion/plop/templates/web/edit-dialog.hbs
charilezhou 3119460f13 feat(plop): 优化生成器支持 Prisma 关联关系
- 支持一对多/多对一关系定义并生成到 Prisma schema
- 简化流程:查询关联配置根据关系自动预填
- 修复 Handlebars 模板 HTML 转义导致的乱码问题
- 修复 controller 模板缺少 Prisma 导入的问题
- 新增页面模板 (page.hbs) 生成前端页面
- 添加 FindAllParams/PaginationQueryDto 索引签名修复类型兼容

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 17:30:18 +08:00

152 lines
4.1 KiB
Handlebars

'use client';
import { zodResolver } from '@hookform/resolvers/zod';
import type { {{pascalCase name}}Response } from '@seclusion/shared';
import { useEffect } from 'react';
import { useForm } from 'react-hook-form';
import { toast } from 'sonner';
import { z } from 'zod';
import { Button } from '@/components/ui/button';
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
{{#if hasTextarea}}
import { Textarea } from '@/components/ui/textarea';
{{/if}}
{{#if hasSelect}}
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
{{/if}}
{{#if hasSwitch}}
import { Switch } from '@/components/ui/switch';
{{/if}}
import { useUpdate{{pascalCase name}} } from '@/hooks/use{{pascalCase pluralName}}';
const edit{{pascalCase name}}Schema = z.object({
{{#each updateFields}}
{{name}}: {{{zodValidation this}}}.optional(),
{{/each}}
});
type Edit{{pascalCase name}}FormValues = z.infer<typeof edit{{pascalCase name}}Schema>;
interface {{pascalCase name}}EditDialogProps {
{{camelCase name}}: {{pascalCase name}}Response | null;
open: boolean;
onOpenChange: (open: boolean) => void;
}
export function {{pascalCase name}}EditDialog({
{{camelCase name}},
open,
onOpenChange,
}: {{pascalCase name}}EditDialogProps) {
const update{{pascalCase name}} = useUpdate{{pascalCase name}}();
const form = useForm<Edit{{pascalCase name}}FormValues>({
resolver: zodResolver(edit{{pascalCase name}}Schema),
defaultValues: {
{{#each updateFields}}
{{name}}: {{{defaultValue this}}},
{{/each}}
},
});
// 当数据变化时重置表单
useEffect(() => {
if ({{camelCase name}}) {
form.reset({
{{#each updateFields}}
{{name}}: {{camelCase ../name}}.{{name}}{{#if nullable}} ?? {{{defaultValue this}}}{{/if}},
{{/each}}
});
}
}, [{{camelCase name}}, form]);
const onSubmit = async (values: Edit{{pascalCase name}}FormValues) => {
if (!{{camelCase name}}) return;
try {
await update{{pascalCase name}}.mutateAsync({
id: {{camelCase name}}.id,
data: values,
});
toast.success('{{chineseName}}已更新');
onOpenChange(false);
} catch (error) {
toast.error(error instanceof Error ? error.message : '更新失败');
}
};
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>编辑{{chineseName}}</DialogTitle>
<DialogDescription>修改{{chineseName}}信息</DialogDescription>
</DialogHeader>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
{{#each updateFields}}
<FormField
control={form.control}
name="{{name}}"
render={({ field }) => (
<FormItem>
<FormLabel>{{label}}</FormLabel>
<FormControl>
{{{formControl this}}}
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{{/each}}
<div className="text-sm text-muted-foreground space-y-1">
<p>
<span className="font-medium">ID:</span>{' '}
<span className="font-mono">{{{camelCase name}}?.id}</span>
</p>
</div>
<DialogFooter>
<Button
type="button"
variant="outline"
onClick={() => onOpenChange(false)}
>
取消
</Button>
<Button type="submit" disabled={update{{pascalCase name}}.isPending}>
{update{{pascalCase name}}.isPending ? '保存中...' : '保存'}
</Button>
</DialogFooter>
</form>
</Form>
</DialogContent>
</Dialog>
);
}