后端重构

This commit is contained in:
Yvan
2026-01-14 14:34:49 +08:00
parent f5f77b32fe
commit 30842b42e5
274 changed files with 39754 additions and 1005 deletions
+130
View File
@@ -0,0 +1,130 @@
import service from '@/utils/request'
{{- if not .OnlyTemplate}}
// @Tags {{.StructName}}
// @Summary 创建{{.Description}}
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body model.{{.StructName}} true "创建{{.Description}}"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /{{.Abbreviation}}/create{{.StructName}} [post]
export const create{{.StructName}} = (data) => {
return service({
url: '/{{.Abbreviation}}/create{{.StructName}}',
method: 'post',
data
})
}
// @Tags {{.StructName}}
// @Summary 删除{{.Description}}
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body model.{{.StructName}} true "删除{{.Description}}"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /{{.Abbreviation}}/delete{{.StructName}} [delete]
export const delete{{.StructName}} = (params) => {
return service({
url: '/{{.Abbreviation}}/delete{{.StructName}}',
method: 'delete',
params
})
}
// @Tags {{.StructName}}
// @Summary 批量删除{{.Description}}
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body request.IdsReq true "批量删除{{.Description}}"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /{{.Abbreviation}}/delete{{.StructName}} [delete]
export const delete{{.StructName}}ByIds = (params) => {
return service({
url: '/{{.Abbreviation}}/delete{{.StructName}}ByIds',
method: 'delete',
params
})
}
// @Tags {{.StructName}}
// @Summary 更新{{.Description}}
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data body model.{{.StructName}} true "更新{{.Description}}"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /{{.Abbreviation}}/update{{.StructName}} [put]
export const update{{.StructName}} = (data) => {
return service({
url: '/{{.Abbreviation}}/update{{.StructName}}',
method: 'put',
data
})
}
// @Tags {{.StructName}}
// @Summary 用id查询{{.Description}}
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data query model.{{.StructName}} true "用id查询{{.Description}}"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /{{.Abbreviation}}/find{{.StructName}} [get]
export const find{{.StructName}} = (params) => {
return service({
url: '/{{.Abbreviation}}/find{{.StructName}}',
method: 'get',
params
})
}
// @Tags {{.StructName}}
// @Summary 分页获取{{.Description}}列表
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Param data query request.PageInfo true "分页获取{{.Description}}列表"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /{{.Abbreviation}}/get{{.StructName}}List [get]
export const get{{.StructName}}List = (params) => {
return service({
url: '/{{.Abbreviation}}/get{{.StructName}}List',
method: 'get',
params
})
}
{{- if .HasDataSource}}
// @Tags {{.StructName}}
// @Summary 获取数据源
// @Security ApiKeyAuth
// @Accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /{{.Abbreviation}}/find{{.StructName}}DataSource [get]
export const get{{.StructName}}DataSource = () => {
return service({
url: '/{{.Abbreviation}}/get{{.StructName}}DataSource',
method: 'get',
})
}
{{- end}}
{{- end}}
// @Tags {{.StructName}}
// @Summary 不需要鉴权的{{.Description}}接口
// @Accept application/json
// @Produce application/json
// @Param data query {{.Package}}Req.{{.StructName}}Search true "分页获取{{.Description}}列表"
// @Success 200 {object} response.Response{data=object,msg=string} "获取成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}Public [get]
export const get{{.StructName}}Public = () => {
return service({
url: '/{{.Abbreviation}}/get{{.StructName}}Public',
method: 'get',
})
}
+200
View File
@@ -0,0 +1,200 @@
{{- $global := . }}
{{- if .IsAdd }}
// ============ 详情组件新增字段配置 ============
// 详情新增字段
{{- range .Fields}}
{{- if .Desc }}
{{ GenerateReactDescriptionItem . }}
{{- end }}
{{- end }}
{{- else }}
{{- if not .OnlyTemplate}}
/**
* KRA - {{.Description}}详情组件
* Auto-generated by KRA AutoCode
*/
import React, { useEffect, useState } from 'react';
import {
Drawer,
Descriptions,
Spin,
message,
Tag,
{{- if .HasPic }}
Image,
{{- end }}
{{- if .IsTree }}
TreeSelect,
{{- end }}
} from 'antd';
import { find{{.StructName}} } from '@/services/kratos/{{.PackageName}}';
import type { {{.StructName}} } from '@/services/kratos/{{.PackageName}}';
{{- if .DictTypes }}
import { useDictionary } from '@/hooks/useDictionary';
{{- end }}
{{- if .HasDataSource }}
import { get{{.StructName}}DataSource } from '@/services/kratos/{{.PackageName}}';
{{- end }}
import dayjs from 'dayjs';
interface {{.StructName}}DetailProps {
visible: boolean;
record?: {{.StructName}} | null;
onClose: () => void;
{{- if .IsTree }}
treeData?: {{.StructName}}[];
{{- end }}
}
const {{.StructName}}Detail: React.FC<{{.StructName}}DetailProps> = ({
visible,
record,
onClose,
{{- if .IsTree }}
treeData = [],
{{- end }}
}) => {
const [loading, setLoading] = useState(false);
const [currentRecord, setCurrentRecord] = useState<{{.StructName}} | null>(null);
{{- if .HasDataSource }}
const [dataSource, setDataSource] = useState<Record<string, Array<{ label: string; value: any }>>>({});
{{- end }}
{{- if .DictTypes }}
// 字典数据
{{- range $index, $element := .DictTypes}}
const { getLabel: get{{$element | toPascalCase}}Label } = useDictionary('{{$element}}');
{{- end }}
{{- end }}
{{- if .HasDataSource }}
// 获取数据源
const fetchDataSource = async () => {
try {
const res = await get{{.StructName}}DataSource();
if (res.code === 0) {
setDataSource(res.data || {});
}
} catch (error) {
console.error('获取数据源失败:', error);
}
};
{{- end }}
// 获取详情数据
const fetchDetail = async (id: {{ GenerateTSType .PrimaryField.FieldType }}) => {
setLoading(true);
try {
const res = await find{{.StructName}}({ {{.PrimaryField.FieldJson}}: id });
if (res.code === 0 && res.data) {
setCurrentRecord(res.data);
} else {
message.error(res.msg || '获取详情失败');
}
} catch (error) {
message.error('获取详情失败');
} finally {
setLoading(false);
}
};
useEffect(() => {
if (visible && record?.{{.PrimaryField.FieldJson}}) {
{{- if .HasDataSource }}
fetchDataSource();
{{- end }}
fetchDetail(record.{{.PrimaryField.FieldJson}});
}
}, [visible, record]);
// 关闭抽屉
const handleClose = () => {
setCurrentRecord(null);
onClose();
};
return (
<Drawer
title="{{.Description}}详情"
open={visible}
onClose={handleClose}
width={600}
destroyOnClose
>
<Spin spinning={loading}>
{currentRecord && (
<Descriptions column={1} bordered>
{{- if .IsTree }}
<Descriptions.Item label="父节点">
<TreeSelect
value={currentRecord.parentID}
treeData={[{ {{.PrimaryField.FieldJson}}: 0, {{.TreeJson}}: '根节点', children: treeData }]}
fieldNames={{ "{{" }} label: '{{.TreeJson}}', value: '{{.PrimaryField.FieldJson}}', children: 'children' {{ "}}" }}
disabled
style={{ "{{" }} width: '100%' {{ "}}" }}
placeholder="根节点"
/>
</Descriptions.Item>
{{- end }}
{{- range .Fields}}
{{- if .Desc }}
{{ GenerateReactDescriptionItem . }}
{{- end }}
{{- end }}
{{- if .GvaModel }}
<Descriptions.Item label="创建时间">
{currentRecord.CreatedAt ? dayjs(currentRecord.CreatedAt).format('YYYY-MM-DD HH:mm:ss') : '-'}
</Descriptions.Item>
<Descriptions.Item label="更新时间">
{currentRecord.UpdatedAt ? dayjs(currentRecord.UpdatedAt).format('YYYY-MM-DD HH:mm:ss') : '-'}
</Descriptions.Item>
{{- end }}
</Descriptions>
)}
</Spin>
</Drawer>
);
};
export default {{.StructName}}Detail;
{{- else}}
/**
* KRA - {{.Description}}详情组件
* Auto-generated by KRA AutoCode
*/
import React from 'react';
import { Drawer, Descriptions } from 'antd';
interface {{.StructName}}DetailProps {
visible: boolean;
record?: any;
onClose: () => void;
}
const {{.StructName}}Detail: React.FC<{{.StructName}}DetailProps> = ({
visible,
record,
onClose,
}) => {
return (
<Drawer
title="{{.Description}}详情"
open={visible}
onClose={onClose}
width={600}
destroyOnClose
>
{record && (
<Descriptions column={1} bordered>
{/* 详情字段 */}
</Descriptions>
)}
</Drawer>
);
};
export default {{.StructName}}Detail;
{{- end }}
{{- end }}
+254
View File
@@ -0,0 +1,254 @@
{{- $global := . }}
{{- if .IsAdd }}
// ============ 表单组件新增字段配置 ============
// 表单新增字段
{{- range .Fields}}
{{- if .Form}}
{{ GenerateReactFormItem . }}
{{- end }}
{{- end }}
{{- else }}
{{- if not .OnlyTemplate}}
/**
* KRA - {{.Description}}表单组件
* Auto-generated by KRA AutoCode
*/
import React, { useEffect, useState } from 'react';
import {
Modal,
Form,
Input,
message,
{{- if .HasTimer }}
DatePicker,
{{- end }}
{{- if or .DictTypes .HasDataSource }}
Select,
{{- end }}
{{- if .HasBool }}
Switch,
{{- end }}
{{- if .HasNumber }}
InputNumber,
{{- end }}
{{- if .IsTree }}
TreeSelect,
{{- end }}
} from 'antd';
import type { FormInstance } from 'antd/es/form';
import {
create{{.StructName}},
update{{.StructName}},
find{{.StructName}},
{{- if .HasDataSource }}
get{{.StructName}}DataSource,
{{- end }}
} from '@/services/kratos/{{.PackageName}}';
import type { {{.StructName}} } from '@/services/kratos/{{.PackageName}}';
{{- if .DictTypes }}
import { useDictionary } from '@/hooks/useDictionary';
{{- end }}
interface {{.StructName}}FormProps {
visible: boolean;
type: 'create' | 'edit';
record?: {{.StructName}} | null;
onClose: () => void;
onSuccess: () => void;
{{- if .IsTree }}
treeData?: {{.StructName}}[];
{{- end }}
}
const {{.StructName}}Form: React.FC<{{.StructName}}FormProps> = ({
visible,
type,
record,
onClose,
onSuccess,
{{- if .IsTree }}
treeData = [],
{{- end }}
}) => {
const [form] = Form.useForm<FormInstance>();
const [loading, setLoading] = useState(false);
const [detailLoading, setDetailLoading] = useState(false);
{{- if .HasDataSource }}
const [dataSource, setDataSource] = useState<Record<string, Array<{ label: string; value: any }>>>({});
{{- end }}
{{- if .DictTypes }}
// 字典数据
{{- range $index, $element := .DictTypes}}
const { options: {{$element}}Options } = useDictionary('{{$element}}');
{{- end }}
{{- end }}
{{- if .HasDataSource }}
// 获取数据源
const fetchDataSource = async () => {
try {
const res = await get{{.StructName}}DataSource();
if (res.code === 0) {
setDataSource(res.data || {});
}
} catch (error) {
console.error('获取数据源失败:', error);
}
};
{{- end }}
// 获取详情数据
const fetchDetail = async (id: {{ GenerateTSType .PrimaryField.FieldType }}) => {
setDetailLoading(true);
try {
const res = await find{{.StructName}}({ {{.PrimaryField.FieldJson}}: id });
if (res.code === 0 && res.data) {
form.setFieldsValue(res.data);
}
} catch (error) {
message.error('获取详情失败');
} finally {
setDetailLoading(false);
}
};
useEffect(() => {
if (visible) {
{{- if .HasDataSource }}
fetchDataSource();
{{- end }}
if (type === 'edit' && record?.{{.PrimaryField.FieldJson}}) {
fetchDetail(record.{{.PrimaryField.FieldJson}});
} else if (type === 'create') {
form.resetFields();
{{- if .IsTree }}
if (record?.parentID) {
form.setFieldsValue({ parentID: record.parentID });
}
{{- end }}
}
}
}, [visible, type, record]);
// 提交表单
const handleSubmit = async () => {
try {
const values = await form.validateFields();
setLoading(true);
const submitData = type === 'edit'
? { ...record, ...values }
: values;
const res = type === 'create'
? await create{{.StructName}}(submitData)
: await update{{.StructName}}(submitData);
if (res.code === 0) {
message.success(type === 'create' ? '创建成功' : '更新成功');
handleClose();
onSuccess();
} else {
message.error(res.msg || (type === 'create' ? '创建失败' : '更新失败'));
}
} catch (error) {
// 表单验证失败
} finally {
setLoading(false);
}
};
// 关闭弹窗
const handleClose = () => {
form.resetFields();
onClose();
};
return (
<Modal
title={type === 'create' ? '新增{{.Description}}' : '编辑{{.Description}}'}
open={visible}
onOk={handleSubmit}
onCancel={handleClose}
confirmLoading={loading}
destroyOnClose
width={600}
maskClosable={false}
>
<Form
form={form}
layout="vertical"
disabled={detailLoading}
>
{{- if .IsTree }}
<Form.Item name="parentID" label="父节点">
<TreeSelect
placeholder="请选择父节点"
allowClear
treeData={[{ {{.PrimaryField.FieldJson}}: 0, {{.TreeJson}}: '根节点', children: treeData }]}
fieldNames={{ "{{" }} label: '{{.TreeJson}}', value: '{{.PrimaryField.FieldJson}}', children: 'children' {{ "}}" }}
treeDefaultExpandAll
/>
</Form.Item>
{{- end }}
{{- range .Fields}}
{{- if .Form}}
{{ GenerateReactFormItem . }}
{{- end }}
{{- end }}
</Form>
</Modal>
);
};
export default {{.StructName}}Form;
{{- else}}
/**
* KRA - {{.Description}}表单组件
* Auto-generated by KRA AutoCode
*/
import React from 'react';
import { Modal, Form, Input } from 'antd';
interface {{.StructName}}FormProps {
visible: boolean;
type: 'create' | 'edit';
record?: any;
onClose: () => void;
onSuccess: () => void;
}
const {{.StructName}}Form: React.FC<{{.StructName}}FormProps> = ({
visible,
type,
onClose,
onSuccess,
}) => {
const [form] = Form.useForm();
return (
<Modal
title={type === 'create' ? '新增{{.Description}}' : '编辑{{.Description}}'}
open={visible}
onOk={() => {
form.validateFields().then(() => {
onSuccess();
onClose();
});
}}
onCancel={onClose}
destroyOnClose
>
<Form form={form} layout="vertical">
{/* 表单字段 */}
</Form>
</Modal>
);
};
export default {{.StructName}}Form;
{{- end }}
{{- end }}
+523
View File
@@ -0,0 +1,523 @@
{{- $global := . }}
{{- $templateID := printf "%s_%s" .Package .StructName }}
{{- if .IsAdd }}
// ============ 新增字段配置 ============
// 搜索表单新增字段
{{- range .Fields}}
{{- if .FieldSearchType}}
{{ GenerateReactSearchFormItem . }}
{{- end }}
{{- end }}
// 表格列新增配置
{{- range .Fields}}
{{- if .Table}}
{{ GenerateReactTableColumn . }}
{{- end }}
{{- end }}
// 表单新增字段
{{- range .Fields}}
{{- if .Form}}
{{ GenerateReactFormItem . }}
{{- end }}
{{- end }}
// 详情新增字段
{{- range .Fields}}
{{- if .Desc }}
{{ GenerateReactDescriptionItem . }}
{{- end }}
{{- end }}
{{- else }}
{{- if not .OnlyTemplate}}
/**
* KRA - {{.Description}}管理页面
* Auto-generated by KRA AutoCode
*/
import React, { useState, useRef, useEffect } from 'react';
import { PageContainer, ProTable } from '@ant-design/pro-components';
import type { ActionType, ProColumns } from '@ant-design/pro-components';
import {
Button,
Space,
Modal,
message,
Form,
Input,
Tag,
{{- if .HasTimer }}
DatePicker,
{{- end }}
{{- if or .DictTypes .HasDataSource }}
Select,
{{- end }}
Drawer,
Descriptions,
Popconfirm,
{{- if .HasPic }}
Image,
{{- end }}
{{- if .IsTree }}
TreeSelect,
{{- end }}
{{- if .HasRichText }}
Typography,
{{- end }}
} from 'antd';
import type { FormInstance } from 'antd/es/form';
import {
PlusOutlined,
DeleteOutlined,
EditOutlined,
EyeOutlined,
{{- if .IsTree }}
PlusCircleOutlined,
{{- end }}
} from '@ant-design/icons';
import {
create{{.StructName}},
delete{{.StructName}},
delete{{.StructName}}ByIds,
update{{.StructName}},
find{{.StructName}},
get{{.StructName}}List,
{{- if .HasDataSource }}
get{{.StructName}}DataSource,
{{- end }}
} from '@/services/kratos/{{.PackageName}}';
import type { {{.StructName}} } from '@/services/kratos/{{.PackageName}}';
{{- if .DictTypes }}
import { useDictionary } from '@/hooks/useDictionary';
{{- end }}
import dayjs from 'dayjs';
const {{.StructName}}Page: React.FC = () => {
// 表格操作引用
const actionRef = useRef<ActionType>();
const formRef = useRef<FormInstance>(null);
// 状态定义
const [drawerVisible, setDrawerVisible] = useState(false);
const [drawerType, setDrawerType] = useState<'create' | 'edit'>('create');
const [detailVisible, setDetailVisible] = useState(false);
const [currentRecord, setCurrentRecord] = useState<{{.StructName}} | null>(null);
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const [btnLoading, setBtnLoading] = useState(false);
{{- if .HasDataSource }}
const [dataSource, setDataSource] = useState<Record<string, Array<{ label: string; value: any }>>>({});
{{- end }}
{{- if .IsTree }}
const [treeData, setTreeData] = useState<{{.StructName}}[]>([]);
{{- end }}
{{- if .DictTypes }}
// 字典数据
{{- range $index, $element := .DictTypes}}
const { options: {{$element}}Options, getLabel: get{{$element | toPascalCase}}Label } = useDictionary('{{$element}}');
{{- end }}
{{- end }}
{{- if .HasDataSource }}
// 获取数据源
const fetchDataSource = async () => {
try {
const res = await get{{.StructName}}DataSource();
if (res.code === 0) {
setDataSource(res.data || {});
}
} catch (error) {
console.error('获取数据源失败:', error);
}
};
useEffect(() => {
fetchDataSource();
}, []);
{{- end }}
// 新增
const handleAdd = ({{- if .IsTree -}}parentRecord?: {{.StructName}}{{- end -}}) => {
setDrawerType('create');
setCurrentRecord({{- if .IsTree -}}parentRecord ? { parentID: parentRecord.{{.PrimaryField.FieldJson}} } as {{.StructName}} : {{- end -}}null);
setDrawerVisible(true);
};
// 编辑
const handleEdit = async (record: {{.StructName}}) => {
try {
const res = await find{{.StructName}}({ {{.PrimaryField.FieldJson}}: record.{{.PrimaryField.FieldJson}}! });
if (res.code === 0) {
setDrawerType('edit');
setCurrentRecord(res.data);
setDrawerVisible(true);
}
} catch (error) {
message.error('获取详情失败');
}
};
// 查看详情
const handleDetail = async (record: {{.StructName}}) => {
try {
const res = await find{{.StructName}}({ {{.PrimaryField.FieldJson}}: record.{{.PrimaryField.FieldJson}}! });
if (res.code === 0) {
setCurrentRecord(res.data);
setDetailVisible(true);
}
} catch (error) {
message.error('获取详情失败');
}
};
// 删除
const handleDelete = async (record: {{.StructName}}) => {
try {
const res = await delete{{.StructName}}({ {{.PrimaryField.FieldJson}}: record.{{.PrimaryField.FieldJson}}! });
if (res.code === 0) {
message.success('删除成功');
actionRef.current?.reload();
} else {
message.error(res.msg || '删除失败');
}
} catch (error) {
message.error('删除失败');
}
};
// 批量删除
const handleBatchDelete = async () => {
if (selectedRowKeys.length === 0) {
message.warning('请选择要删除的数据');
return;
}
Modal.confirm({
title: '确认删除',
content: `确定要删除选中的 ${selectedRowKeys.length} 条数据吗?`,
onOk: async () => {
try {
const res = await delete{{.StructName}}ByIds({ {{.PrimaryField.FieldJson}}s: selectedRowKeys as {{ GenerateTSType .PrimaryField.FieldType }}[] });
if (res.code === 0) {
message.success('删除成功');
setSelectedRowKeys([]);
actionRef.current?.reload();
} else {
message.error(res.msg || '删除失败');
}
} catch (error) {
message.error('删除失败');
}
},
});
};
// 关闭抽屉
const handleDrawerClose = () => {
setDrawerVisible(false);
setCurrentRecord(null);
formRef.current?.resetFields();
};
// 提交表单
const handleSubmit = async () => {
try {
const values = await formRef.current?.validateFields();
setBtnLoading(true);
const submitData = { ...currentRecord, ...values };
const res = drawerType === 'create'
? await create{{.StructName}}(submitData)
: await update{{.StructName}}(submitData);
if (res.code === 0) {
message.success(drawerType === 'create' ? '创建成功' : '更新成功');
handleDrawerClose();
actionRef.current?.reload();
} else {
message.error(res.msg || (drawerType === 'create' ? '创建失败' : '更新失败'));
}
} catch (error) {
// 表单验证失败
} finally {
setBtnLoading(false);
}
};
// 表格列定义
const columns: ProColumns<{{.StructName}}>[] = [
{{- if .GvaModel }}
{
title: '创建时间',
dataIndex: 'CreatedAt',
valueType: 'dateTime',
width: 180,
sorter: true,
hideInSearch: true,
},
{{- end }}
{{- range .Fields}}
{{- if .Table}}
{{ GenerateReactProTableColumn . }}
{{- end }}
{{- end }}
{
title: '操作',
valueType: 'option',
fixed: 'right',
width: {{- if .IsTree -}}280{{- else -}}200{{- end }},
render: (_, record) => [
{{- if .IsTree }}
<Button
key="addChild"
type="link"
size="small"
icon={<PlusCircleOutlined />}
onClick={() => handleAdd(record)}
>
新增子节点
</Button>,
{{- end }}
<Button
key="detail"
type="link"
size="small"
icon={<EyeOutlined />}
onClick={() => handleDetail(record)}
>
查看
</Button>,
<Button
key="edit"
type="link"
size="small"
icon={<EditOutlined />}
onClick={() => handleEdit(record)}
>
编辑
</Button>,
{{- if .IsTree }}
!record.children?.length && (
{{- end }}
<Popconfirm
key="delete"
title="确定删除吗?"
onConfirm={() => handleDelete(record)}
okText="确定"
cancelText="取消"
>
<Button type="link" size="small" danger icon={<DeleteOutlined />}>
删除
</Button>
</Popconfirm>
{{- if .IsTree }}
)
{{- end }},
],
},
];
return (
<PageContainer>
<ProTable<{{.StructName}}>
actionRef={actionRef}
columns={columns}
rowKey="{{.PrimaryField.FieldJson}}"
scroll={{ "{{" }} x: 'max-content' {{ "}}" }}
rowSelection={{
selectedRowKeys,
onChange: (keys) => setSelectedRowKeys(keys),
}}
request={async (params, sort) => {
// 处理排序
const sortKey = Object.keys(sort || {})[0];
let orderKey = '';
if (sortKey) {
// 排序字段映射
const sortMap: Record<string, string> = {
CreatedAt: 'created_at',
ID: 'id',
{{- range .Fields}}
{{- if .Table}}
{{- if .Sort}}
{{- if .ColumnName}}
{{.FieldJson}}: '{{.ColumnName}}',
{{- end}}
{{- end}}
{{- end}}
{{- end}}
};
orderKey = sortMap[sortKey] || sortKey.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`);
}
try {
const res = await get{{.StructName}}List({
page: params.current || 1,
pageSize: params.pageSize || 10,
{{- range .Fields}}
{{- if .FieldSearchType}}
{{- if eq .FieldSearchType "BETWEEN"}}
start{{.FieldName}}: params.start{{.FieldName}},
end{{.FieldName}}: params.end{{.FieldName}},
{{- else}}
{{.FieldJson}}: params.{{.FieldJson}},
{{- end}}
{{- end }}
{{- end }}
{{- if .GvaModel }}
startCreatedAt: params.startCreatedAt,
endCreatedAt: params.endCreatedAt,
{{- end }}
orderKey: orderKey,
desc: sort?.[sortKey] === 'descend',
});
{{- if .IsTree }}
if (res.code === 0) {
setTreeData(res.data || []);
}
return {
data: res.data || [],
success: res.code === 0,
};
{{- else }}
return {
data: res.data?.list || [],
total: res.data?.total || 0,
success: res.code === 0,
};
{{- end }}
} catch (error) {
return {
data: [],
total: 0,
success: false,
};
}
}}
pagination={{- if .IsTree -}}={false}{{- else -}}={{
defaultPageSize: 10,
showSizeChanger: true,
pageSizeOptions: ['10', '30', '50', '100'],
showTotal: (total) => `共 ${total} 条`,
}}{{- end }}
search={{
labelWidth: 'auto',
collapsed: true,
collapseRender: (collapsed) => (collapsed ? '展开' : '收起'),
defaultCollapsed: true,
span: {{- if .GvaModel -}}6{{- else -}}8{{- end }},
}}
toolBarRender={() => [
<Button
key="add"
type="primary"
icon={<PlusOutlined />}
onClick={() => handleAdd()}
>
新增
</Button>,
<Button
key="delete"
danger
icon={<DeleteOutlined />}
disabled={selectedRowKeys.length === 0}
onClick={handleBatchDelete}
>
批量删除
</Button>,
]}
/>
{/* 新增/编辑抽屉 */}
<Drawer
title={drawerType === 'create' ? '新增{{.Description}}' : '编辑{{.Description}}'}
open={drawerVisible}
onClose={handleDrawerClose}
width={600}
destroyOnClose
extra={
<Space>
<Button onClick={handleDrawerClose}>取消</Button>
<Button type="primary" loading={btnLoading} onClick={handleSubmit}>
确定
</Button>
</Space>
}
>
<Form
ref={formRef}
layout="vertical"
initialValues={currentRecord || {}}
>
{{- if .IsTree }}
<Form.Item name="parentID" label="父节点">
<TreeSelect
placeholder="请选择父节点"
allowClear
treeData={[{ {{.PrimaryField.FieldJson}}: 0, {{.TreeJson}}: '根节点', children: treeData }]}
fieldNames={{ "{{" }} label: '{{.TreeJson}}', value: '{{.PrimaryField.FieldJson}}', children: 'children' {{ "}}" }}
treeDefaultExpandAll
/>
</Form.Item>
{{- end }}
{{- range .Fields}}
{{- if .Form}}
{{ GenerateReactFormItem . }}
{{- end }}
{{- end }}
</Form>
</Drawer>
{/* 详情抽屉 */}
<Drawer
title="{{.Description}}详情"
open={detailVisible}
onClose={() => {
setDetailVisible(false);
setCurrentRecord(null);
}}
width={600}
>
{currentRecord && (
<Descriptions column={1} bordered>
{{- if .IsTree }}
<Descriptions.Item label="父节点">{currentRecord.parentID || '根节点'}</Descriptions.Item>
{{- end }}
{{- range .Fields}}
{{- if .Desc }}
{{ GenerateReactDescriptionItem . }}
{{- end }}
{{- end }}
{{- if .GvaModel }}
<Descriptions.Item label="创建时间">
{currentRecord.CreatedAt ? dayjs(currentRecord.CreatedAt).format('YYYY-MM-DD HH:mm:ss') : '-'}
</Descriptions.Item>
<Descriptions.Item label="更新时间">
{currentRecord.UpdatedAt ? dayjs(currentRecord.UpdatedAt).format('YYYY-MM-DD HH:mm:ss') : '-'}
</Descriptions.Item>
{{- end }}
</Descriptions>
)}
</Drawer>
</PageContainer>
);
};
export default {{.StructName}}Page;
{{- else}}
/**
* KRA - {{.Description}}页面
* Auto-generated by KRA AutoCode
*/
import React from 'react';
import { PageContainer } from '@ant-design/pro-components';
const {{.StructName}}Page: React.FC = () => {
return (
<PageContainer>
<div>{{.Description}}页面</div>
</PageContainer>
);
};
export default {{.StructName}}Page;
{{- end }}
{{- end }}
+131
View File
@@ -0,0 +1,131 @@
import { request } from '@umijs/max';
import type { ApiResponse, PageResult } from '@/types/api';
{{- if not .OnlyTemplate}}
// {{.StructName}} {{.Description}}类型
export interface {{.StructName}} {
{{- if .GvaModel }}
ID?: number;
CreatedAt?: string;
UpdatedAt?: string;
{{- end }}
{{- range .Fields}}
{{.FieldJson}}{{if not .Require}}?{{end}}: {{ GenerateTSType .FieldType }}; // {{.FieldDesc}}
{{- end }}
{{- if .AutoCreateResource }}
createdBy?: number;
updatedBy?: number;
deletedBy?: number;
{{- end }}
{{- if .IsTree }}
children?: {{.StructName}}[];
parentID?: number;
{{- end }}
}
// {{.StructName}}Search {{.Description}}搜索条件
export interface {{.StructName}}Search {
page: number;
pageSize: number;
{{- if .GvaModel }}
createdAtRange?: string[];
{{- end }}
{{- range .Fields}}
{{- if .FieldSearchType}}
{{.FieldJson}}?: {{ GenerateTSType .FieldType }};
{{- end}}
{{- end}}
{{- if .NeedSort}}
sort?: string;
order?: string;
{{- end}}
}
/**
* 创建{{.Description}}
* @param data {{.Description}}数据
*/
export const create{{.StructName}} = (data: {{.StructName}}) => {
return request<ApiResponse<null>>('/{{.Abbreviation}}/create{{.StructName}}', {
method: 'POST',
data,
});
};
/**
* 删除{{.Description}}
* @param params 包含{{.PrimaryField.FieldJson}}的参数
*/
export const delete{{.StructName}} = (params: { {{.PrimaryField.FieldJson}}: {{ GenerateTSType .PrimaryField.FieldType }} }) => {
return request<ApiResponse<null>>('/{{.Abbreviation}}/delete{{.StructName}}', {
method: 'DELETE',
params,
});
};
/**
* 批量删除{{.Description}}
* @param params 包含{{.PrimaryField.FieldJson}}s数组的参数
*/
export const delete{{.StructName}}ByIds = (params: { {{.PrimaryField.FieldJson}}s: {{ GenerateTSType .PrimaryField.FieldType }}[] }) => {
return request<ApiResponse<null>>('/{{.Abbreviation}}/delete{{.StructName}}ByIds', {
method: 'DELETE',
params,
});
};
/**
* 更新{{.Description}}
* @param data {{.Description}}数据
*/
export const update{{.StructName}} = (data: {{.StructName}}) => {
return request<ApiResponse<null>>('/{{.Abbreviation}}/update{{.StructName}}', {
method: 'PUT',
data,
});
};
/**
* 根据ID获取{{.Description}}
* @param params 包含{{.PrimaryField.FieldJson}}的参数
*/
export const find{{.StructName}} = (params: { {{.PrimaryField.FieldJson}}: {{ GenerateTSType .PrimaryField.FieldType }} }) => {
return request<ApiResponse<{{.StructName}}>>('/{{.Abbreviation}}/find{{.StructName}}', {
method: 'GET',
params,
});
};
/**
* 获取{{.Description}}列表
* @param params 搜索条件
*/
export const get{{.StructName}}List = (params: {{.StructName}}Search) => {
return request<ApiResponse<PageResult<{{.StructName}}>>>('/{{.Abbreviation}}/get{{.StructName}}List', {
method: 'GET',
params,
});
};
{{- if .HasDataSource}}
/**
* 获取{{.Description}}数据源
*/
export const get{{.StructName}}DataSource = () => {
return request<ApiResponse<Record<string, Array<{ label: string; value: any }>>>>('/{{.Abbreviation}}/get{{.StructName}}DataSource', {
method: 'GET',
});
};
{{- end}}
{{- end}}
/**
* 获取{{.Description}}公开数据(无需鉴权)
*/
export const get{{.StructName}}Public = () => {
return request<ApiResponse<any>>('/{{.Abbreviation}}/get{{.StructName}}Public', {
method: 'GET',
});
};
+183
View File
@@ -0,0 +1,183 @@
{{- $global := . }}
{{- if not .OnlyTemplate}}
/**
* KRA - {{.Description}}类型定义
* Auto-generated by KRA AutoCode
*/
/**
* {{.StructName}} {{.Description}}实体类型
*/
export interface {{.StructName}} {
{{- if .GvaModel }}
/** 主键ID */
ID?: number;
/** 创建时间 */
CreatedAt?: string;
/** 更新时间 */
UpdatedAt?: string;
/** 删除时间 */
DeletedAt?: string | null;
{{- end }}
{{- range .Fields}}
/** {{.FieldDesc}} */
{{.FieldJson}}{{if not .Require}}?{{end}}: {{ GenerateTSType .FieldType }};
{{- end }}
{{- if .AutoCreateResource }}
/** 创建者ID */
createdBy?: number;
/** 更新者ID */
updatedBy?: number;
/** 删除者ID */
deletedBy?: number;
{{- end }}
{{- if .IsTree }}
/** 子节点 */
children?: {{.StructName}}[];
/** 父节点ID */
parentID?: number;
{{- end }}
}
/**
* {{.StructName}}ListReq {{.Description}}列表请求参数
*/
export interface {{.StructName}}ListReq {
/** 页码 */
page: number;
/** 每页数量 */
pageSize: number;
{{- if .GvaModel }}
/** 创建时间范围 */
createdAtRange?: string[];
/** 创建时间开始 */
startCreatedAt?: string;
/** 创建时间结束 */
endCreatedAt?: string;
{{- end }}
{{- range .Fields}}
{{- if .FieldSearchType}}
{{- if eq .FieldSearchType "BETWEEN"}}
/** {{.FieldDesc}}开始值 */
start{{.FieldName}}?: {{ GenerateTSType .FieldType }};
/** {{.FieldDesc}}结束值 */
end{{.FieldName}}?: {{ GenerateTSType .FieldType }};
{{- else}}
/** {{.FieldDesc}} */
{{.FieldJson}}?: {{ GenerateTSType .FieldType }};
{{- end}}
{{- end}}
{{- end}}
{{- if .NeedSort}}
/** 排序字段 */
orderKey?: string;
/** 是否降序 */
desc?: boolean;
{{- end}}
}
/**
* {{.StructName}}Search {{.Description}}搜索条件
* @description 与 {{.StructName}}ListReq 相同,用于API服务层
*/
export type {{.StructName}}Search = {{.StructName}}ListReq;
/**
* {{.StructName}}ListRes {{.Description}}列表响应
*/
export interface {{.StructName}}ListRes {
/** 数据列表 */
list: {{.StructName}}[];
/** 总数 */
total: number;
/** 当前页码 */
page: number;
/** 每页数量 */
pageSize: number;
}
/**
* {{.StructName}}IdReq {{.Description}}ID请求参数
*/
export interface {{.StructName}}IdReq {
/** {{.PrimaryField.FieldDesc}} */
{{.PrimaryField.FieldJson}}: {{ GenerateTSType .PrimaryField.FieldType }};
}
/**
* {{.StructName}}IdsReq {{.Description}}批量ID请求参数
*/
export interface {{.StructName}}IdsReq {
/** {{.PrimaryField.FieldDesc}}列表 */
{{.PrimaryField.FieldJson}}s: {{ GenerateTSType .PrimaryField.FieldType }}[];
}
{{- if .HasDataSource }}
/**
* {{.StructName}}DataSource {{.Description}}数据源类型
*/
export interface {{.StructName}}DataSource {
{{- range .Fields}}
{{- if .CheckDataSource}}
/** {{.FieldDesc}}数据源 */
{{.FieldJson}}?: Array<{ label: string; value: any }>;
{{- end}}
{{- end}}
}
{{- end }}
{{- if .DictTypes }}
/**
* 字典选项类型
*/
export interface DictOption {
/** 显示标签 */
label: string;
/** 值 */
value: number | string;
/** 状态 */
status?: boolean;
}
/**
* {{.StructName}}相关字典类型
*/
export interface {{.StructName}}DictTypes {
{{- range $index, $element := .DictTypes}}
/** {{$element}}字典选项 */
{{$element}}: DictOption[];
{{- end }}
}
{{- end }}
{{- else}}
/**
* KRA - {{.Description}}类型定义
* Auto-generated by KRA AutoCode (Template Only)
*/
// 仅模板模式,请根据实际需求定义类型
export interface {{.StructName}} {
// TODO: 添加字段定义
}
export interface {{.StructName}}ListReq {
page: number;
pageSize: number;
}
/**
* {{.StructName}}Search {{.Description}}搜索条件
* @description 与 {{.StructName}}ListReq 相同,用于API服务层
*/
export type {{.StructName}}Search = {{.StructName}}ListReq;
export interface {{.StructName}}ListRes {
list: {{.StructName}}[];
total: number;
page: number;
pageSize: number;
}
{{- end }}