kra/resource/package/web/pages/index.tsx.tpl

524 lines
13 KiB
Smarty
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{{- $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 }}