plus-ui/gen/index-tree.tsx.vm
2026-06-03 15:24:03 +08:00

473 lines
18 KiB
Plaintext
Raw 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.

#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>
);
}