update 优化 代码生成支持接入各种不同前端 只需要将模板放到vm文件夹下 前端传对应的文件夹名即可

This commit is contained in:
疯狂的狮子Li
2026-06-03 15:27:39 +08:00
parent 626496f4ca
commit 97524974d5
14 changed files with 1266 additions and 45 deletions
@@ -0,0 +1,94 @@
import type { #if(!$table.tree)PageResult, #end R } from '@/api/types';
import request from '@/api/request';
import type { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from './types';
/**
* 查询${functionName}列表
*/
export function list${BusinessName}(query?: ${BusinessName}Query) {
return request<R<#if($table.tree)${BusinessName}VO[]#else PageResult<${BusinessName}VO>#end>>({
url: '/${moduleName}/${businessName}/list',
method: 'get',
params: query
});
}
/**
* 查询${functionName}详细
*/
export function get${BusinessName}(${pkColumn.javaField}: string | number) {
return request<R<${BusinessName}VO>>({
url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
method: 'get'
});
}
/**
* 新增${functionName}
*/
export function add${BusinessName}(data: ${BusinessName}Form) {
return request<R>({
url: '/${moduleName}/${businessName}',
method: 'post',
data
});
}
/**
* 修改${functionName}
*/
export function update${BusinessName}(data: ${BusinessName}Form) {
return request<R>({
url: '/${moduleName}/${businessName}',
method: 'put',
data
});
}
#if($enableStatus)
/**
* 修改${functionName}状态
*/
export function change${BusinessName}Status(
${pkColumn.javaField}: string | number,
${statusField}: #if($statusColumn.javaType == 'Boolean')boolean#elseif($statusColumn.javaType == 'Integer' || $statusColumn.javaType == 'Long')number#else string#end
) {
return request<R>({
url: '/${moduleName}/${businessName}/changeStatus',
method: 'put',
data: {
${pkColumn.javaField},
${statusField}
}
});
}
#end
#if($enableSort)
/**
* 调整${functionName}排序
*/
export function update${BusinessName}Sort(
${pkColumn.javaField}: string | number,
${sortField}: #if($sortColumn.javaType == 'LocalDateTime' || $sortColumn.javaType == 'String')string#else number#end
) {
return request<R>({
url: '/${moduleName}/${businessName}/updateSort',
method: 'put',
data: {
${pkColumn.javaField},
${sortField}
}
});
}
#end
/**
* 删除${functionName}
*/
export function del${BusinessName}(${pkColumn.javaField}: string | number | Array<string | number>) {
return request<R>({
url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
method: 'delete'
});
}
@@ -0,0 +1,472 @@
#set($needDict = $dicts != '')
#set($needImagePreview = false)
#set($needImageUpload = false)
#set($needFileUpload = false)
#set($needEditor = false)
#set($needCheckbox = false)
#set($needSelect = false)
#set($needTextArea = false)
#set($needDigit = false)
#set($needDateField = false)
#set($needSwitchField = false)
#foreach($column in $columns)
#if($column.list && $column.htmlType == "imageUpload")
#set($needImagePreview = true)
#end
#if(($column.insert || $column.edit) && $column.htmlType == "imageUpload")
#set($needImageUpload = true)
#end
#if(($column.insert || $column.edit) && $column.htmlType == "fileUpload")
#set($needFileUpload = true)
#end
#if(($column.insert || $column.edit) && $column.htmlType == "editor")
#set($needEditor = true)
#end
#if(($column.insert || $column.edit) && $column.htmlType == "checkbox")
#set($needCheckbox = true)
#end
#if(($column.insert || $column.edit || $column.query) && ($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "switch"))
#set($needSelect = true)
#end
#if(($column.insert || $column.edit) && $column.htmlType == "textarea")
#set($needTextArea = true)
#end
#if(($column.insert || $column.edit) && $column.htmlType == "inputNumber")
#set($needDigit = true)
#end
#if(($column.insert || $column.edit) && $column.htmlType == "datetime")
#set($needDateField = true)
#end
#if(($column.insert || $column.edit || $column.list) && $column.htmlType == "switch")
#set($needSwitchField = true)
#end
#end
#macro(comment $column)#set($idx=$column.columnComment.indexOf(""))#if($idx != -1)$column.columnComment.substring(0, $idx)#else$column.columnComment#end#end
import { DeleteOutlined#if($enableExport), DownloadOutlined#end, EditOutlined, PlusOutlined, SortAscendingOutlined } from '@ant-design/icons';
import {
ModalForm,
PageContainer,
#if($needCheckbox)
ProFormCheckbox,
#end
#if($needDateField)
ProFormDateTimePicker,
#end
#if($needDigit)
ProFormDigit,
#end
#if($needSelect)
ProFormSelect,
#end
#if($needTextArea)
ProFormTextArea,
#end
ProFormText,
ProFormTreeSelect,
ProTable,
type ActionType,
type ProColumns
} from '@ant-design/pro-components';
import { useBoolean } from 'ahooks';
import { Button, Form, message#if($enableStatus || $needSwitchField), Switch#end#if($enableSort), InputNumber#end } from 'antd';
import { useMemo, useRef, useState } from 'react';
import type { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from '@/api/${moduleName}/${businessName}/types';
import {
add${BusinessName},
#if($enableStatus)
change${BusinessName}Status,
#end
del${BusinessName},
get${BusinessName},
list${BusinessName},
#if($enableSort)
update${BusinessName}Sort,
#end
update${BusinessName}
} from '@/api/${moduleName}/${businessName}';
#if($needDict)
import DictTag from '@/components/common/DictTag';
#end
#if($needFileUpload)
import FileUpload from '@/components/common/FileUpload';
#end
#if($needImagePreview)
import ImagePreview from '@/components/common/ImagePreview';
#end
#if($needImageUpload)
import ImageUpload from '@/components/common/ImageUpload';
#end
#if($needEditor)
import RichTextEditor from '@/components/common/RichTextEditor';
#end
import RowActions from '@/components/common/RowActions';
#if($needDict)
import { useDict } from '@/hooks/useDict';
#end
#if($enableExport)
import { useTableExport } from '@/hooks/useTableExport';
#end
import { useTreeTableExpand } from '@/hooks/useTreeTableExpand';
import { useUserStore } from '@/stores/userStore';
#if($needDict)
import { dictOptions } from '@/utils/dict';
#end
#if($enableStatus)
import { confirmAction } from '@/utils/modal';
#end
import { hasPermi } from '@/utils/permission';
import { filterTree#if($needDateField), formatDateTimeFields#end, handleTree#if($needDateField), toDayjsFields#end } from '@/utils/ruoyi';
const default${BusinessName}Form: ${BusinessName}Form = {
${treeParentCode}: ${treeRootValueTsLiteral},
#foreach($column in $columns)
#if(($column.insert || $column.edit) && !$column.pk && $column.htmlType == "checkbox")
${column.javaField}: [],
#end
#end
};
interface ${BusinessName}SelectNode {
title: string;
value: string | number;
children?: ${BusinessName}SelectNode[];
}
function toTreeSelectData(nodes: ${BusinessName}VO[]): ${BusinessName}SelectNode[] {
return nodes.map(node => ({
title: String(node.${treeName} || ''),
value: node.${treeCode},
children: node.children ? toTreeSelectData(node.children) : undefined
}));
}
#macro(switchActiveValue $column)#if($column.javaType == "Boolean")true#elseif($column.javaType == "Integer" || $column.javaType == "Long")0#else'0'#end#end
#macro(switchInactiveValue $column)#if($column.javaType == "Boolean")false#elseif($column.javaType == "Integer" || $column.javaType == "Long")1#else'1'#end#end
#if($enableStatus)
const ${statusField}ActiveValue = #if($statusColumn.javaType == "Boolean")true#elseif($statusColumn.javaType == "Integer" || $statusColumn.javaType == "Long")0#else'0'#end;
const ${statusField}InactiveValue = #if($statusColumn.javaType == "Boolean")false#elseif($statusColumn.javaType == "Integer" || $statusColumn.javaType == "Long")1#else'1'#end;
#end
export default function ${BusinessName}Page() {
const actionRef = useRef<ActionType | undefined>(undefined);
const [form] = Form.useForm<${BusinessName}Form>();
const userInfo = useUserStore(state => state.userInfo);
#if($needDict)
const dicts = useDict(${dicts});
#end
const [treeOptions, setTreeOptions] = useState<${BusinessName}VO[]>([]);
const [tableRows, setTableRows] = useState<${BusinessName}VO[]>([]);
const { expandAll, expandedRowKeys, onExpandedRowsChange, syncExpandedRows, toggleExpandAll } =
useTreeTableExpand<${BusinessName}VO>(row => row.${treeCode});
const [modalOpen, { setTrue: openModal, setFalse: closeModal }] = useBoolean(false);
const [modalTitle, setModalTitle] = useState('');
#if($enableExport)
const { updateExportParams, exportFile } = useTableExport();
#end
const canAdd = hasPermi(userInfo, ['${permissionPrefix}:add']);
const canEdit = hasPermi(userInfo, ['${permissionPrefix}:edit']);
const canRemove = hasPermi(userInfo, ['${permissionPrefix}:remove']);
#if($enableExport)
const canExport = hasPermi(userInfo, ['${permissionPrefix}:export']);
#end
const treeSelectData = useMemo(
() => [{ title: '顶级节点', value: ${treeRootValueTsLiteral}, children: toTreeSelectData(treeOptions) }],
[treeOptions]
);
const loadTreeOptions = async (excludeId?: string | number) => {
const res = await list${BusinessName}();
const rows = handleTree<${BusinessName}VO>(res.data || [], '${treeCode}', '${treeParentCode}');
setTreeOptions(excludeId ? filterTree(rows, node => node.${treeCode} !== excludeId) : rows);
};
const openAdd = async (row?: ${BusinessName}VO) => {
await loadTreeOptions();
form.resetFields();
form.setFieldsValue({ ...default${BusinessName}Form, ${treeParentCode}: row?.${treeCode} || ${treeRootValueTsLiteral} });
setModalTitle('添加${functionName}');
openModal();
};
const openEdit = async (row: ${BusinessName}VO) => {
await loadTreeOptions(row.${treeCode});
const res = await get${BusinessName}(row.${pkColumn.javaField});
const data = #if($needDateField)toDayjsFields({ ...res.data }, [
#foreach($column in $columns)
#if(($column.insert || $column.edit) && $column.htmlType == "datetime")
'${column.javaField}',
#end
#end
])#else{ ...res.data }#end;
#foreach($column in $columns)
#if(($column.insert || $column.edit) && $column.htmlType == "checkbox")
if (typeof data.${column.javaField} === 'string') {
data.${column.javaField} = data.${column.javaField}.split(',');
}
#end
#end
form.resetFields();
form.setFieldsValue(data);
setModalTitle('修改${functionName}');
openModal();
};
const submitForm = async (values: ${BusinessName}Form) => {
const submitValues = #if($needDateField)formatDateTimeFields({ ...values }, [
#foreach($column in $columns)
#if(($column.insert || $column.edit) && $column.htmlType == "datetime")
'${column.javaField}',
#end
#end
])#else{ ...values }#end;
#foreach($column in $columns)
#if(($column.insert || $column.edit) && $column.htmlType == "checkbox")
if (Array.isArray(submitValues.${column.javaField})) {
submitValues.${column.javaField} = submitValues.${column.javaField}.join(',');
}
#end
#end
submitValues.${pkColumn.javaField} ? await update${BusinessName}(submitValues) : await add${BusinessName}(submitValues);
message.success('操作成功');
form.resetFields();
actionRef.current?.reload();
return true;
};
const remove = async (row: ${BusinessName}VO) => {
await del${BusinessName}(row.${pkColumn.javaField});
message.success('删除成功');
actionRef.current?.reload();
};
#if($enableStatus)
const handleStatusChange = async (row: ${BusinessName}VO, checked: boolean) => {
const previousStatus = row.${statusField};
const status = checked ? ${statusField}ActiveValue : ${statusField}InactiveValue;
const text = checked ? '启用' : '停用';
try {
await confirmAction(`确认要"${text}"吗?`);
await change${BusinessName}Status(row.${pkColumn.javaField}, status);
message.success(`${text}成功`);
actionRef.current?.reload();
} catch {
row.${statusField} = previousStatus;
actionRef.current?.reload();
}
};
#end
#if($enableSort)
const handleSortChange = async (row: ${BusinessName}VO, value?: number | null) => {
await update${BusinessName}Sort(row.${pkColumn.javaField}, value || 0);
message.success('排序更新成功');
actionRef.current?.reload();
};
#end
const columns: ProColumns<${BusinessName}VO>[] = [
#foreach($column in $columns)
#set($javaField=$column.javaField)
#set($dictType=$column.dictType)
#if($column.list && !$column.pk)
#if($enableStatus && $statusField == $javaField)
{
title: '#comment($column)',
dataIndex: '${javaField}',
valueType: 'select',
width: 100,
#if("" != $dictType)
fieldProps: { options: dictOptions(dicts.${dictType}) },
#end
render: (_, row) => (
<Switch
checked={row.${javaField} === ${statusField}ActiveValue}
disabled={!canEdit}
onChange={checked => handleStatusChange(row, checked)}
/>
)
},
#elseif($enableSort && $sortField == $javaField)
{
title: '#comment($column)',
dataIndex: '${javaField}',
search: false,
width: 130,
render: (_, row) => <InputNumber min={0} value={row.${javaField} as number} onChange={value => handleSortChange(row, value)} />
},
#elseif($column.htmlType == "datetime")
{ title: '#comment($column)', dataIndex: '${javaField}', valueType: 'dateTime', search: #if($column.query)true#else false#end, width: 170 },
#elseif($column.htmlType == "imageUpload")
{
title: '#comment($column)',
dataIndex: '${javaField}Url',
search: false,
width: 100,
render: (_, row) => <ImagePreview src={row.${javaField}Url || String(row.${javaField} || '')} width={50} height={50} />
},
#elseif($column.dictColumn)
{
title: '#comment($column)',
dataIndex: '${javaField}',
valueType: 'select',
fieldProps: { options: dictOptions(dicts.${dictType}) },
render: (_, row) => <DictTag options={dicts.${dictType}} value={row.${javaField}} />
},
#elseif($column.htmlType == "switch")
{
title: '#comment($column)',
dataIndex: '${javaField}',
valueType: 'select',
width: 100,
render: (_, row) => <Switch checked={row.${javaField} === #switchActiveValue($column)} disabled />
},
#else
{ title: '#comment($column)', dataIndex: '${javaField}'#if(!$column.query), search: false#end },
#end
#end
#end
{
title: '操作',
valueType: 'option',
width: 130,
fixed: 'right',
render: (_, row) => (
<RowActions
actions={[
canEdit && { key: 'edit', label: '修改', icon: <EditOutlined />, onClick: () => openEdit(row) },
canAdd && { key: 'add', label: '新增', icon: <PlusOutlined />, onClick: () => openAdd(row) },
canRemove && {
key: 'delete',
label: '删除',
icon: <DeleteOutlined />,
danger: true,
confirm: `是否确认删除${functionName}编号为"#[[${row.]]#${pkColumn.javaField}#[[}]]#"的数据项?`,
onClick: () => remove(row)
}
]}
/>
)
}
];
return (
<PageContainer title="${functionName}">
<ProTable<${BusinessName}VO, ${BusinessName}Query>
actionRef={actionRef}
rowKey="${treeCode}"
columns={columns}
scroll={{ x: 1000 }}
pagination={false}
search={{ labelWidth: 90 }}
expandable={{
expandedRowKeys,
onExpandedRowsChange
}}
request={async params => {
const res = await list${BusinessName}(params);
const rows = handleTree<${BusinessName}VO>(res.data || [], '${treeCode}', '${treeParentCode}');
setTableRows(rows);
syncExpandedRows(rows, expandAll);
#if($enableExport)
updateExportParams(params);
#end
return { data: rows, total: rows.length, success: true };
}}
toolbar={{ title: '${functionName}列表' }}
toolBarRender={() => [
canAdd && (
<Button key="add" type="primary" icon={<PlusOutlined />} onClick={() => openAdd()}>
新增
</Button>
),
<Button
key="expand"
icon={<SortAscendingOutlined />}
onClick={() => toggleExpandAll(tableRows)}
>
展开/折叠
</Button>#if($enableExport),
canExport && (
<Button
key="export"
icon={<DownloadOutlined />}
onClick={() => exportFile('/${moduleName}/${businessName}/export', () => `${businessName}_#[[${Date.now()}]]#.xlsx`)}
>
导出
</Button>
)#end
]}
/>
<ModalForm<${BusinessName}Form>
title={modalTitle}
open={modalOpen}
width={560}
form={form}
layout="vertical"
initialValues={default${BusinessName}Form}
modalProps={{ destroyOnHidden: true, onCancel: closeModal }}
onOpenChange={open => !open && closeModal()}
onFinish={submitForm}
>
<ProFormText name="${pkColumn.javaField}" hidden />
#foreach($column in $columns)
#if(($column.insert || $column.edit) && !$column.pk)
#set($field=$column.javaField)
#set($dictType=$column.dictType)
#if($field == $treeParentCode)
<ProFormTreeSelect
name="${field}"
label="#comment($column)"
#if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end
fieldProps={{
allowClear: true,
treeDefaultExpandAll: true,
treeData: treeSelectData,
placeholder: '请选择#comment($column)'
}}
/>
#elseif($column.htmlType == "input")
<ProFormText name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
#elseif($column.htmlType == "textarea")
<ProFormTextArea name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
#elseif($column.htmlType == "inputNumber")
<ProFormDigit name="${field}" label="#comment($column)" min={0} #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
#elseif(($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "switch") && "" != $dictType)
<ProFormSelect name="${field}" label="#comment($column)" options={dictOptions(dicts.${dictType})} #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
#elseif($column.htmlType == "checkbox" && "" != $dictType)
<ProFormCheckbox.Group name="${field}" label="#comment($column)" options={dictOptions(dicts.${dictType})} #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
#elseif($column.htmlType == "switch")
<Form.Item
name="${field}"
label="#comment($column)"
valuePropName="checked"
getValueProps={value => ({ checked: value === #switchActiveValue($column) })}
normalize={checked => (checked ? #switchActiveValue($column) : #switchInactiveValue($column))}
>
<Switch />
</Form.Item>
#elseif($column.htmlType == "datetime")
<ProFormDateTimePicker name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
#elseif($column.htmlType == "imageUpload")
<Form.Item name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end>
<ImageUpload />
</Form.Item>
#elseif($column.htmlType == "fileUpload")
<Form.Item name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end>
<FileUpload />
</Form.Item>
#elseif($column.htmlType == "editor")
<Form.Item name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end>
<RichTextEditor />
</Form.Item>
#else
<ProFormText name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
#end
#end
#end
</ModalForm>
</PageContainer>
);
}
@@ -0,0 +1,460 @@
#set($needDict = $dicts != '')
#set($needDateRange = false)
#set($needImagePreview = false)
#set($needImageUpload = false)
#set($needFileUpload = false)
#set($needEditor = false)
#set($needCheckbox = false)
#set($needSelect = false)
#set($needTextArea = false)
#set($needDigit = false)
#set($needDateField = false)
#set($needSwitchField = false)
#foreach($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($needDateRange = true)
#end
#if($column.list && $column.htmlType == "imageUpload")
#set($needImagePreview = true)
#end
#if(($column.insert || $column.edit) && $column.htmlType == "imageUpload")
#set($needImageUpload = true)
#end
#if(($column.insert || $column.edit) && $column.htmlType == "fileUpload")
#set($needFileUpload = true)
#end
#if(($column.insert || $column.edit) && $column.htmlType == "editor")
#set($needEditor = true)
#end
#if(($column.insert || $column.edit) && $column.htmlType == "checkbox")
#set($needCheckbox = true)
#end
#if(($column.insert || $column.edit || $column.query) && ($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "switch"))
#set($needSelect = true)
#end
#if(($column.insert || $column.edit) && $column.htmlType == "textarea")
#set($needTextArea = true)
#end
#if(($column.insert || $column.edit) && $column.htmlType == "inputNumber")
#set($needDigit = true)
#end
#if(($column.insert || $column.edit) && $column.htmlType == "datetime")
#set($needDateField = true)
#end
#if(($column.insert || $column.edit || $column.list) && $column.htmlType == "switch")
#set($needSwitchField = true)
#end
#end
#macro(comment $column)#set($idx=$column.columnComment.indexOf(""))#if($idx != -1)$column.columnComment.substring(0, $idx)#else$column.columnComment#end#end
import { DeleteOutlined#if($enableExport), DownloadOutlined#end, EditOutlined, PlusOutlined } from '@ant-design/icons';
import {
ModalForm,
PageContainer,
#if($needCheckbox)
ProFormCheckbox,
#end
#if($needDateField)
ProFormDateTimePicker,
#end
#if($needDigit)
ProFormDigit,
#end
#if($needSelect)
ProFormSelect,
#end
#if($needTextArea)
ProFormTextArea,
#end
ProFormText,
ProTable,
type ActionType,
type ProColumns
} from '@ant-design/pro-components';
import { useBoolean } from 'ahooks';
import { Button, Form, message, Popconfirm#if($enableStatus || $needSwitchField), Switch#end#if($enableSort), InputNumber#end } from 'antd';
import { useRef, useState } from 'react';
import type { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from '@/api/${moduleName}/${businessName}/types';
import {
add${BusinessName},
#if($enableStatus)
change${BusinessName}Status,
#end
del${BusinessName},
get${BusinessName},
list${BusinessName},
#if($enableSort)
update${BusinessName}Sort,
#end
update${BusinessName}
} from '@/api/${moduleName}/${businessName}';
#if($needDict)
import DictTag from '@/components/common/DictTag';
#end
#if($needFileUpload)
import FileUpload from '@/components/common/FileUpload';
#end
#if($needImagePreview)
import ImagePreview from '@/components/common/ImagePreview';
#end
#if($needImageUpload)
import ImageUpload from '@/components/common/ImageUpload';
#end
#if($needEditor)
import RichTextEditor from '@/components/common/RichTextEditor';
#end
import RowActions from '@/components/common/RowActions';
#if($needDict)
import { useDict } from '@/hooks/useDict';
#end
#if($needDateRange)
import { useDateRangeQuery } from '@/hooks/useDateRangeQuery';
#end
#if($enableExport)
import { useTableExport } from '@/hooks/useTableExport';
#end
import { useTableSelection } from '@/hooks/useTableSelection';
import { useUserStore } from '@/stores/userStore';
#if($needDict)
import { dictOptions } from '@/utils/dict';
#end
#if($enableStatus)
import { confirmAction } from '@/utils/modal';
#end
import { hasPermi } from '@/utils/permission';
import { #if($needDateField)formatDateTimeFields, toDayjsFields, #end toPageQuery, toTableData } from '@/utils/ruoyi';
const default${BusinessName}Form: ${BusinessName}Form = {
#foreach($column in $columns)
#if(($column.insert || $column.edit) && !$column.pk && $column.htmlType == "checkbox")
${column.javaField}: [],
#end
#end
};
#macro(switchActiveValue $column)#if($column.javaType == "Boolean")true#elseif($column.javaType == "Integer" || $column.javaType == "Long")0#else'0'#end#end
#macro(switchInactiveValue $column)#if($column.javaType == "Boolean")false#elseif($column.javaType == "Integer" || $column.javaType == "Long")1#else'1'#end#end
#if($enableStatus)
const ${statusField}ActiveValue = #if($statusColumn.javaType == "Boolean")true#elseif($statusColumn.javaType == "Integer" || $statusColumn.javaType == "Long")0#else'0'#end;
const ${statusField}InactiveValue = #if($statusColumn.javaType == "Boolean")false#elseif($statusColumn.javaType == "Integer" || $statusColumn.javaType == "Long")1#else'1'#end;
#end
export default function ${BusinessName}Page() {
const actionRef = useRef<ActionType | undefined>(undefined);
const [form] = Form.useForm<${BusinessName}Form>();
const userInfo = useUserStore(state => state.userInfo);
#if($needDict)
const dicts = useDict(${dicts});
#end
const { ids, selectedOne, handleSelectionChange, clearSelection } = useTableSelection<${BusinessName}VO>(
row => row.${pkColumn.javaField}
);
const [modalOpen, { setTrue: openModal, setFalse: closeModal }] = useBoolean(false);
const [modalTitle, setModalTitle] = useState('');
#if($enableExport)
const { updateExportParams, exportFile } = useTableExport();
#end
#foreach($column in $columns)
#if($column.query && $column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
const { applyDateRange: apply${AttrName}DateRange } = useDateRangeQuery('${AttrName}');
#end
#end
const canAdd = hasPermi(userInfo, ['${permissionPrefix}:add']);
const canEdit = hasPermi(userInfo, ['${permissionPrefix}:edit']);
const canRemove = hasPermi(userInfo, ['${permissionPrefix}:remove']);
#if($enableExport)
const canExport = hasPermi(userInfo, ['${permissionPrefix}:export']);
#end
const openAdd = () => {
form.resetFields();
form.setFieldsValue(default${BusinessName}Form);
setModalTitle('添加${functionName}');
openModal();
};
const openEdit = async (row?: ${BusinessName}VO) => {
const target = row || selectedOne;
if (!target?.${pkColumn.javaField}) return;
const res = await get${BusinessName}(target.${pkColumn.javaField});
const data = #if($needDateField)toDayjsFields({ ...res.data }, [
#foreach($column in $columns)
#if(($column.insert || $column.edit) && $column.htmlType == "datetime")
'${column.javaField}',
#end
#end
])#else{ ...res.data }#end;
#foreach($column in $columns)
#if(($column.insert || $column.edit) && $column.htmlType == "checkbox")
if (typeof data.${column.javaField} === 'string') {
data.${column.javaField} = data.${column.javaField}.split(',');
}
#end
#end
form.resetFields();
form.setFieldsValue(data);
setModalTitle('修改${functionName}');
openModal();
};
const submitForm = async (values: ${BusinessName}Form) => {
const submitValues = #if($needDateField)formatDateTimeFields({ ...values }, [
#foreach($column in $columns)
#if(($column.insert || $column.edit) && $column.htmlType == "datetime")
'${column.javaField}',
#end
#end
])#else{ ...values }#end;
#foreach($column in $columns)
#if(($column.insert || $column.edit) && $column.htmlType == "checkbox")
if (Array.isArray(submitValues.${column.javaField})) {
submitValues.${column.javaField} = submitValues.${column.javaField}.join(',');
}
#end
#end
submitValues.${pkColumn.javaField} ? await update${BusinessName}(submitValues) : await add${BusinessName}(submitValues);
message.success('操作成功');
form.resetFields();
actionRef.current?.reload();
return true;
};
const remove = async (row?: ${BusinessName}VO) => {
await del${BusinessName}(row?.${pkColumn.javaField} || ids);
message.success('删除成功');
clearSelection();
actionRef.current?.reloadAndRest?.();
};
#if($enableStatus)
const handleStatusChange = async (row: ${BusinessName}VO, checked: boolean) => {
const previousStatus = row.${statusField};
const status = checked ? ${statusField}ActiveValue : ${statusField}InactiveValue;
const text = checked ? '启用' : '停用';
try {
await confirmAction(`确认要"${text}"吗?`);
await change${BusinessName}Status(row.${pkColumn.javaField}, status);
message.success(`${text}成功`);
actionRef.current?.reload();
} catch {
row.${statusField} = previousStatus;
actionRef.current?.reload();
}
};
#end
#if($enableSort)
const handleSortChange = async (row: ${BusinessName}VO, value?: number | null) => {
await update${BusinessName}Sort(row.${pkColumn.javaField}, value || 0);
message.success('排序更新成功');
actionRef.current?.reload();
};
#end
const columns: ProColumns<${BusinessName}VO>[] = [
#foreach($column in $columns)
#set($javaField=$column.javaField)
#set($dictType=$column.dictType)
#if($column.list)
#if($enableStatus && $statusField == $javaField)
{
title: '#comment($column)',
dataIndex: '${javaField}',
valueType: 'select',
width: 100,
#if("" != $dictType)
fieldProps: { options: dictOptions(dicts.${dictType}) },
#end
render: (_, row) => (
<Switch
checked={row.${javaField} === ${statusField}ActiveValue}
disabled={!canEdit}
onChange={checked => handleStatusChange(row, checked)}
/>
)
},
#elseif($enableSort && $sortField == $javaField)
{
title: '#comment($column)',
dataIndex: '${javaField}',
search: false,
width: 130,
render: (_, row) => <InputNumber min={0} value={row.${javaField} as number} onChange={value => handleSortChange(row, value)} />
},
#elseif($column.htmlType == "datetime")
{ title: '#comment($column)', dataIndex: '${javaField}', valueType: 'dateTime', search: #if($column.query && $column.queryType != "BETWEEN")true#else false#end, width: 170 },
#elseif($column.htmlType == "imageUpload")
{
title: '#comment($column)',
dataIndex: '${javaField}Url',
search: false,
width: 100,
render: (_, row) => <ImagePreview src={row.${javaField}Url || String(row.${javaField} || '')} width={50} height={50} />
},
#elseif($column.dictColumn)
{
title: '#comment($column)',
dataIndex: '${javaField}',
valueType: 'select',
fieldProps: { options: dictOptions(dicts.${dictType}) },
render: (_, row) => <DictTag options={dicts.${dictType}} value={row.${javaField}} />
},
#elseif($column.htmlType == "switch")
{
title: '#comment($column)',
dataIndex: '${javaField}',
valueType: 'select',
width: 100,
render: (_, row) => <Switch checked={row.${javaField} === #switchActiveValue($column)} disabled />
},
#else
{ title: '#comment($column)', dataIndex: '${javaField}'#if(!$column.query), search: false#end },
#end
#end
#if($column.query && $column.htmlType == "datetime" && $column.queryType == "BETWEEN")
{ title: '#comment($column)', dataIndex: '${javaField}Range', valueType: 'dateTimeRange', hideInTable: true },
#end
#end
{
title: '操作',
valueType: 'option',
width: 92,
fixed: 'right',
render: (_, row) => (
<RowActions
actions={[
canEdit && { key: 'edit', label: '修改', icon: <EditOutlined />, onClick: () => openEdit(row) },
canRemove && {
key: 'delete',
label: '删除',
icon: <DeleteOutlined />,
danger: true,
confirm: `是否确认删除${functionName}编号为"#[[${row.]]#${pkColumn.javaField}#[[}]]#"的数据项?`,
onClick: () => remove(row)
}
]}
/>
)
}
];
return (
<PageContainer title="${functionName}">
<ProTable<${BusinessName}VO, ${BusinessName}Query#if($needDateRange) & Record<string, unknown>#end>
actionRef={actionRef}
rowKey="${pkColumn.javaField}"
columns={columns}
scroll={{ x: 1000 }}
search={{ labelWidth: 90 }}
pagination={{ defaultPageSize: 10, showSizeChanger: true }}
rowSelection={{ selectedRowKeys: ids, onChange: handleSelectionChange }}
request={async params => {
#if($needDateRange)
let query = toPageQuery(params);
#foreach($column in $columns)
#if($column.query && $column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
query = apply${AttrName}DateRange(query, params.${column.javaField}Range as [string, string] | undefined);
delete query.${column.javaField}Range;
#end
#end
#else
const query = toPageQuery(params);
#end
#if($enableExport)
updateExportParams(query);
#end
const res = await list${BusinessName}(query);
return toTableData(res);
}}
toolbar={{ title: '${functionName}列表' }}
toolBarRender={() => [
canAdd && (
<Button key="add" type="primary" icon={<PlusOutlined />} onClick={openAdd}>
新增
</Button>
),
canEdit && (
<Button key="edit" disabled={!selectedOne} icon={<EditOutlined />} onClick={() => openEdit()}>
修改
</Button>
),
canRemove && (
<Popconfirm key="delete" title={`是否确认删除${functionName}编号为"#[[${ids}]]#"的数据项?`} onConfirm={() => remove()}>
<Button danger disabled={!ids.length} icon={<DeleteOutlined />}>
删除
</Button>
</Popconfirm>
)#if($enableExport),
canExport && (
<Button
key="export"
icon={<DownloadOutlined />}
onClick={() => exportFile('/${moduleName}/${businessName}/export', () => `${businessName}_#[[${Date.now()}]]#.xlsx`)}
>
导出
</Button>
)#end
]}
/>
<ModalForm<${BusinessName}Form>
title={modalTitle}
open={modalOpen}
width={560}
form={form}
layout="vertical"
initialValues={default${BusinessName}Form}
modalProps={{ destroyOnHidden: true, onCancel: closeModal }}
onOpenChange={open => !open && closeModal()}
onFinish={submitForm}
>
<ProFormText name="${pkColumn.javaField}" hidden />
#foreach($column in $columns)
#if(($column.insert || $column.edit) && !$column.pk)
#set($field=$column.javaField)
#set($dictType=$column.dictType)
#if($column.htmlType == "input")
<ProFormText name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
#elseif($column.htmlType == "textarea")
<ProFormTextArea name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
#elseif($column.htmlType == "inputNumber")
<ProFormDigit name="${field}" label="#comment($column)" min={0} #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
#elseif(($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "switch") && "" != $dictType)
<ProFormSelect name="${field}" label="#comment($column)" options={dictOptions(dicts.${dictType})} #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
#elseif($column.htmlType == "checkbox" && "" != $dictType)
<ProFormCheckbox.Group name="${field}" label="#comment($column)" options={dictOptions(dicts.${dictType})} #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
#elseif($column.htmlType == "switch")
<Form.Item
name="${field}"
label="#comment($column)"
valuePropName="checked"
getValueProps={value => ({ checked: value === #switchActiveValue($column) })}
normalize={checked => (checked ? #switchActiveValue($column) : #switchInactiveValue($column))}
>
<Switch />
</Form.Item>
#elseif($column.htmlType == "datetime")
<ProFormDateTimePicker name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
#elseif($column.htmlType == "imageUpload")
<Form.Item name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end>
<ImageUpload />
</Form.Item>
#elseif($column.htmlType == "fileUpload")
<Form.Item name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end>
<FileUpload />
</Form.Item>
#elseif($column.htmlType == "editor")
<Form.Item name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end>
<RichTextEditor />
</Form.Item>
#else
<ProFormText name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
#end
#end
#end
</ModalForm>
</PageContainer>
);
}
@@ -0,0 +1,56 @@
import type { BaseEntity#if(!$table.tree), PageQuery#end } from '@/api/types';
#macro(tsType $column)#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1)string | number#elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal')number#elseif($column.javaType == 'Boolean')boolean#else string#end#end
export interface ${BusinessName}VO {
#foreach ($column in $columns)
#if($column.list || $column.pk)
/**
* $column.columnComment
*/
$column.javaField: #tsType($column);
#if($column.htmlType == "imageUpload")
/**
* ${column.columnComment}Url
*/
${column.javaField}Url?: string;
#end
#end
#end
#if($table.tree)
/**
* 子对象
*/
children?: ${BusinessName}VO[];
#end
}
export interface ${BusinessName}Form extends BaseEntity {
#foreach ($column in $columns)
#if($column.insert || $column.edit || $column.pk)
/**
* $column.columnComment
*/
#if($column.htmlType == "checkbox")
$column.javaField?: string | string[];
#else
$column.javaField?: #tsType($column);
#end
#end
#end
}
export interface ${BusinessName}Query#if(!$table.tree) extends PageQuery#end {
#foreach ($column in $columns)
#if($column.query)
/**
* $column.columnComment
*/
$column.javaField?: #tsType($column);
#end
#end
/**
* 日期范围参数
*/
params?: Record<string, unknown>;
}