|
|
@@ -6,6 +6,7 @@ import { Plus, Search, Edit, Trash2, CalendarIcon } from 'lucide-react';
|
|
|
import { useForm } from 'react-hook-form';
|
|
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
|
import { z } from 'zod';
|
|
|
+import type { InferResponseType, InferRequestType } from 'hono/client';
|
|
|
|
|
|
import { Button } from '@/client/components/ui/button';
|
|
|
import { Input } from '@/client/components/ui/input';
|
|
|
@@ -24,19 +25,10 @@ import { CreateStockXunlianCodesDto, UpdateStockXunlianCodesDto } from '@/server
|
|
|
import { DataTablePagination } from '@/client/admin/components/DataTablePagination';
|
|
|
|
|
|
// 类型定义
|
|
|
-type CreateRequest = z.infer<typeof CreateStockXunlianCodesDto>;
|
|
|
-type UpdateRequest = z.infer<typeof UpdateStockXunlianCodesDto>;
|
|
|
-type StockXunlianCode = {
|
|
|
- id: number;
|
|
|
- code: string;
|
|
|
- stockName: string;
|
|
|
- name: string;
|
|
|
- type: string | null;
|
|
|
- description: string | null;
|
|
|
- tradeDate: string;
|
|
|
- createdAt: string;
|
|
|
- updatedAt: string;
|
|
|
-};
|
|
|
+type CreateRequest = InferRequestType<typeof stockXunlianCodesClient.$post>['json'];
|
|
|
+type UpdateRequest = InferRequestType<typeof stockXunlianCodesClient[':id']['$put']>['json'];
|
|
|
+type StockXunlianCode = InferResponseType<typeof stockXunlianCodesClient.$get, 200>['data'][0];
|
|
|
+type StockXunlianCodeListResponse = InferResponseType<typeof stockXunlianCodesClient.$get, 200>;
|
|
|
|
|
|
// 表单Schema
|
|
|
const createFormSchema = CreateStockXunlianCodesDto;
|
|
|
@@ -66,7 +58,8 @@ export const StockXunlianCodesPage = () => {
|
|
|
name: '',
|
|
|
type: '',
|
|
|
description: '',
|
|
|
- tradeDate: new Date(),
|
|
|
+ trainingStartDate: new Date(),
|
|
|
+ trainingEndDate: new Date(),
|
|
|
},
|
|
|
});
|
|
|
|
|
|
@@ -75,7 +68,7 @@ export const StockXunlianCodesPage = () => {
|
|
|
});
|
|
|
|
|
|
// 数据查询
|
|
|
- const { data, isLoading, refetch } = useQuery({
|
|
|
+ const { data, isLoading, refetch } = useQuery<StockXunlianCodeListResponse>({
|
|
|
queryKey: ['stock-xunlian-codes', searchParams],
|
|
|
queryFn: async () => {
|
|
|
const res = await stockXunlianCodesClient.$get({
|
|
|
@@ -170,7 +163,8 @@ export const StockXunlianCodesPage = () => {
|
|
|
name: entity.name,
|
|
|
type: entity.type || '',
|
|
|
description: entity.description || '',
|
|
|
- tradeDate: new Date(entity.tradeDate),
|
|
|
+ trainingStartDate: new Date(entity.trainingStartDate),
|
|
|
+ trainingEndDate: new Date(entity.trainingEndDate),
|
|
|
});
|
|
|
setIsModalOpen(true);
|
|
|
};
|
|
|
@@ -267,7 +261,8 @@ export const StockXunlianCodesPage = () => {
|
|
|
<TableHead>股票名称</TableHead>
|
|
|
<TableHead>案例名称</TableHead>
|
|
|
<TableHead>案例类型</TableHead>
|
|
|
- <TableHead>交易日期</TableHead>
|
|
|
+ <TableHead>训练开始日期</TableHead>
|
|
|
+ <TableHead>训练结束日期</TableHead>
|
|
|
<TableHead>创建时间</TableHead>
|
|
|
<TableHead className="text-right">操作</TableHead>
|
|
|
</TableRow>
|
|
|
@@ -279,7 +274,8 @@ export const StockXunlianCodesPage = () => {
|
|
|
<TableCell>{item.stockName}</TableCell>
|
|
|
<TableCell>{item.name}</TableCell>
|
|
|
<TableCell>{item.type || '-'}</TableCell>
|
|
|
- <TableCell>{format(new Date(item.tradeDate), 'yyyy-MM-dd')}</TableCell>
|
|
|
+ <TableCell>{format(new Date(item.trainingStartDate), 'yyyy-MM-dd')}</TableCell>
|
|
|
+ <TableCell>{format(new Date(item.trainingEndDate), 'yyyy-MM-dd')}</TableCell>
|
|
|
<TableCell>{format(new Date(item.createdAt), 'yyyy-MM-dd HH:mm')}</TableCell>
|
|
|
<TableCell className="text-right">
|
|
|
<div className="flex justify-end gap-2">
|
|
|
@@ -405,10 +401,10 @@ export const StockXunlianCodesPage = () => {
|
|
|
|
|
|
<FormField
|
|
|
control={createForm.control}
|
|
|
- name="tradeDate"
|
|
|
+ name="trainingStartDate"
|
|
|
render={({ field }) => (
|
|
|
<FormItem className="flex flex-col">
|
|
|
- <FormLabel>交易日期</FormLabel>
|
|
|
+ <FormLabel>训练开始日期</FormLabel>
|
|
|
<Popover>
|
|
|
<PopoverTrigger asChild>
|
|
|
<FormControl>
|
|
|
@@ -422,7 +418,49 @@ export const StockXunlianCodesPage = () => {
|
|
|
{field.value ? (
|
|
|
format(field.value, 'yyyy-MM-dd')
|
|
|
) : (
|
|
|
- <span>选择日期</span>
|
|
|
+ <span>选择开始日期</span>
|
|
|
+ )}
|
|
|
+ <CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
|
|
|
+ </Button>
|
|
|
+ </FormControl>
|
|
|
+ </PopoverTrigger>
|
|
|
+ <PopoverContent className="w-auto p-0" align="start">
|
|
|
+ <Calendar
|
|
|
+ mode="single"
|
|
|
+ selected={field.value}
|
|
|
+ onSelect={field.onChange}
|
|
|
+ disabled={(date) =>
|
|
|
+ date > new Date() || date < new Date('1900-01-01')
|
|
|
+ }
|
|
|
+ initialFocus
|
|
|
+ />
|
|
|
+ </PopoverContent>
|
|
|
+ </Popover>
|
|
|
+ <FormMessage />
|
|
|
+ </FormItem>
|
|
|
+ )}
|
|
|
+ />
|
|
|
+
|
|
|
+ <FormField
|
|
|
+ control={createForm.control}
|
|
|
+ name="trainingEndDate"
|
|
|
+ render={({ field }) => (
|
|
|
+ <FormItem className="flex flex-col">
|
|
|
+ <FormLabel>训练结束日期</FormLabel>
|
|
|
+ <Popover>
|
|
|
+ <PopoverTrigger asChild>
|
|
|
+ <FormControl>
|
|
|
+ <Button
|
|
|
+ variant="outline"
|
|
|
+ className={cn(
|
|
|
+ 'w-full pl-3 text-left font-normal',
|
|
|
+ !field.value && 'text-muted-foreground'
|
|
|
+ )}
|
|
|
+ >
|
|
|
+ {field.value ? (
|
|
|
+ format(field.value, 'yyyy-MM-dd')
|
|
|
+ ) : (
|
|
|
+ <span>选择结束日期</span>
|
|
|
)}
|
|
|
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
|
|
|
</Button>
|
|
|
@@ -530,10 +568,52 @@ export const StockXunlianCodesPage = () => {
|
|
|
|
|
|
<FormField
|
|
|
control={updateForm.control}
|
|
|
- name="tradeDate"
|
|
|
+ name="trainingStartDate"
|
|
|
+ render={({ field }) => (
|
|
|
+ <FormItem className="flex flex-col">
|
|
|
+ <FormLabel>训练开始日期</FormLabel>
|
|
|
+ <Popover>
|
|
|
+ <PopoverTrigger asChild>
|
|
|
+ <FormControl>
|
|
|
+ <Button
|
|
|
+ variant="outline"
|
|
|
+ className={cn(
|
|
|
+ 'w-full pl-3 text-left font-normal',
|
|
|
+ !field.value && 'text-muted-foreground'
|
|
|
+ )}
|
|
|
+ >
|
|
|
+ {field.value ? (
|
|
|
+ format(field.value, 'yyyy-MM-dd')
|
|
|
+ ) : (
|
|
|
+ <span>选择开始日期</span>
|
|
|
+ )}
|
|
|
+ <CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
|
|
|
+ </Button>
|
|
|
+ </FormControl>
|
|
|
+ </PopoverTrigger>
|
|
|
+ <PopoverContent className="w-auto p-0" align="start">
|
|
|
+ <Calendar
|
|
|
+ mode="single"
|
|
|
+ selected={field.value}
|
|
|
+ onSelect={field.onChange}
|
|
|
+ disabled={(date) =>
|
|
|
+ date > new Date() || date < new Date('1900-01-01')
|
|
|
+ }
|
|
|
+ initialFocus
|
|
|
+ />
|
|
|
+ </PopoverContent>
|
|
|
+ </Popover>
|
|
|
+ <FormMessage />
|
|
|
+ </FormItem>
|
|
|
+ )}
|
|
|
+ />
|
|
|
+
|
|
|
+ <FormField
|
|
|
+ control={updateForm.control}
|
|
|
+ name="trainingEndDate"
|
|
|
render={({ field }) => (
|
|
|
<FormItem className="flex flex-col">
|
|
|
- <FormLabel>交易日期</FormLabel>
|
|
|
+ <FormLabel>训练结束日期</FormLabel>
|
|
|
<Popover>
|
|
|
<PopoverTrigger asChild>
|
|
|
<FormControl>
|
|
|
@@ -547,7 +627,7 @@ export const StockXunlianCodesPage = () => {
|
|
|
{field.value ? (
|
|
|
format(field.value, 'yyyy-MM-dd')
|
|
|
) : (
|
|
|
- <span>选择日期</span>
|
|
|
+ <span>选择结束日期</span>
|
|
|
)}
|
|
|
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
|
|
|
</Button>
|