横向树列表
运行效果
基于树形动态数据集,使用 antdv 原生 Table 组件实现数据在表格中横向展示
案例需求
将平台中树形结构动态数据集数据,使用表格进行横向展示,支持节点单步加载、全部数据加载及数据级联选择
知识点
- 使用平台树形动态数据集进行数据保存及“父 id 、全路径 id 、层级、是否叶子节点”字段平台自动维护
- 使用 antdv 下原生 Table 组件实现树形数据在表中横向展示
开发过程
新增树形动态数据集
- 在应用中“数据”新增动态数据集,其中需新增字段“父id、全路径id、层级、是否叶子节点”,用于后续设置数据为树形结果数据,并对这些字段进行自动维护
- 勾选树形数据,设置父列属性
- 设置“父id、全路径id、层级、是否叶子节点”字段
- 保存数据集配置并新增数据
工具条
{% raw %}
<antdv:ToolBar class="x-toolbar" id="toolBar0">
<antdv:Button id="button2" on:onClick="onButton2Click" text="刷新">
</antdv:Button>
<antdv:Button id="loadAllBtn" on:onClick="onLoadAllBtnClick" text="加载全部数据">
</antdv:Button>
<antdv:Button id="button0" on:onClick="onSaveBtnClick" text="保存选择数据" type="primary" xmlns:antdv="$UI/comp/antdv/components">
</antdv:Button>
<antdv:Div id="div0">
<antdv:Typography.Text content="开启级联选择:" id="typographyText0">
</antdv:Typography.Text>
<antdv:Switch bind:ref="pageData.current.cascade" checkedChildren="是" id="switch0" unCheckedChildren="否">
</antdv:Switch>
</antdv:Div>
</antdv:ToolBar>
{% endraw%}
添加数据集
- 功能菜单数据:用于表格数据展示,取消树形数据设置及设置分页为-1,全部加载,并设置刷新前事件,用于控制数据是全部加载还是parent过滤加载。
{% raw %}
//菜单数据加载前过滤设置,用于控制数据是全部加载还是parent过滤加载
onMainDataBeforeRefresh = (event) => {
let mainData = event.source;
//设置数据全部加载
if (this.loadAll) {
mainData.setFilter("parentFilter", []);
this.loadAll = false;
return;
}
//设置数据单步加载
let parentId = this.comp("pageData").getValue("parentId");
let filter = [];
if (parentId) {
filter.push({ name: "parentId", value: parentId, op: "eq" });
} else {
filter.push({ name: "parentId", value: null, op: "isNull" });
}
mainData.setFilter("parentFilter", filter);
}
{% endraw %}
- 用户功能菜单:用于保存选择的菜单数据(用户根据需要自行新建,当前案例中表仅包含用户 id 及菜单 id)
- 树形功能菜单数据:与功能菜单数据为同一个动态数据集,用于绑定树形选择组件,需要设置加载所有数据
使用原生 antdv Table 进行渲染
.w
//调用js中定义的方法
{tableRender?.()}
.js
//引入
import {Table} from "ant-design-vue";
//渲染表格
let tableRender = () => {
let columns = getColumns();
//渲染字段
return (
<>
<Table
key={new Date().getTime()}
class={"tableBox"}
columns={columns}
dataSource={state.treeData}
rowKey="fid"
pagination={false}
bordered={true}
rowHoverable={false}
/>
</>
);
}
表格数据刷新及图标相关代码
{% raw %}
//选择
let onChange = (event, column, text, record, index) => {
let cascade = pageData.getValue("cascade");
let treeData = [...state.treeData] || [];
treeData.filter(item => cascade ? (item.fullId?.includes(record.fullId)) : (item.fid == record.fid)).forEach(item => item.checked = event.target.checked);
state.treeData = treeData;
}
//展开子节点数据
let onExpand = (record) => {
pageData.setValue("parentId", record.fid);
mainData.refreshData();
}
//编辑菜单数据
let onEdit = async (record, isNew = false) => {
if (isNew) {
await mainData.newData();
mainData.setValue("parentId", record.fid);
} else {
mainData.to(record.fid);
}
$page.comp("menuModal").show();
}
let confirm = (content, ok) => {
Modal.confirm({
title: '提示',
content,
getContainer: () => document.querySelector('#pcx-page-root'),
okText: "确定",
cancelText: "取消",
onOk() {
if (ok) {
ok();
}
}
});
}
//删除功能菜单
let onDelMenu = (record) => {
confirm((record.isLeaf ? "" : "当前数据下还有子菜单数据,") + "确定删除?", async () => {
state.loading = true;
try {
let { data: { result, message: msg } } = await $page.request({ url: `/vue/main/dbrest/menus?fullId=like.${record.fullId}*`, method: "DELETE" });
if (result > 0) {
message.info("删除成功");
//删除当前数据及子数据
let treeData = [...state.treeData] || [];
treeData = treeData.filter(item => !item.fullId?.includes(record.fid));
state.treeData = treeData;
//重新加载父数据
// onExpand({ fid: record.parentId });
$page.loadAll = true;
resetData = true;
mainData.refreshData()
} else {
message.info("删除失败:" + msg);
}
} catch (error) {
message.info("删除失败");
} finally {
state.loading = false;
}
})
}
//获取表格列
let getColumns = () => {
let columns = [];
for (let { key, value, rowSpan } of columnsData) {
let column = {
title: value,
dataIndex: key,
ellipsis: true,
customRender: ({ text, record, index, column }) => onRender(text, record, index, key),
customCell: (record, rowIndex, column) => {
return {
rowSpan: record[`${key}_rowSpan`] || 0
}
}
}
columns.push(column)
}
return columns;
}
//多选框渲染
let onRender = (text, record = {}, index, column) => {
if (!text) return;
let divBox = [];
divBox.push(<Checkbox checked={record.checked || false} onChange={(e) => { return onChange(e, column, text, record, index); }}>{text || '空'}</Checkbox>);
let optDiv = [];
if (!record.isLeaf) {
optDiv.push(<FolderOutlined title="展开" onClick={() => onExpand(record)} />);
}
optDiv.push(<PlusOutlined onClick={() => onEdit(record, true)} />);
optDiv.push(<DeleteOutlined onClick={() => onDelMenu(record)} />);
optDiv.push(<EditOutlined onClick={() => onEdit(record, false)} />);
divBox.push(<Space class={"optDiv"} style={{ color: "#1677FF", display: "none" }}>{optDiv}</Space>);
return <Space>{divBox}</Space>;
};
//渲染表格
let tableRender = () => {
let columns = getColumns();
//渲染字段
return (
<>
<Table
key={new Date().getTime()}
class={"tableBox"}
columns={columns}
dataSource={state.treeData}
rowKey="fid"
pagination={false}
bordered={true}
rowHoverable={false}
/>
</>
);
}
{% endraw %}
工具栏中数据加载及保存等方法
{% raw %}
//数据初始
let onPageInitState = async (event) => {
//默认异步加载
await onButton2Click();
}
//保存用户选择数据
let onSaveBtnClick = async (event) => {
state.loading = true;
try {
//获取选择数据
let menuIds = [];
state.treeData.filter(item => item.checked).forEach(item => menuIds.push(item.fid));
//获取用户已保存的数据
let userInfo = userData.getCurrentRow();
if (!userInfo) {
await userData.newData();
}
userData.setValue("menuIds", menuIds.join());
userData.saveData();
message.info("保存成功")
} catch (error) {
message.error("保存失败");
} finally {
state.loading = false;
}
}
//刷新
let onButton2Click = async (event) => {
resetData = true;
$page.loadAll = false;
await userData.refreshData();
await mainData.refreshData();
}
//加载全部数据
let onLoadAllBtnClick = async (event) => {
resetData = true;
$page.loadAll = true;
await userData.refreshData();
await mainData.refreshData();
}
//保存菜单数据
let onMenuModalOk = async (event) => {
state.loading = true;
try {
//校验数据集必填
mainData.enabledCheck.set(true);//没有接管保存时需要设置
let checkInfo = mainData.check();
if (!checkInfo.valid) {
message.error(checkInfo.msg.join());
return;
}
let currentRow = mainData.getCurrentRow().toJson({ ui: true });
await mainData.saveData();
message.info("保存成功")
//设置当前节点父数据叶子节点为否
let treeData = [...state.treeData] || [];
treeData.forEach(item => {
if (item.fid == currentRow.parentId) {
item.isLeaf = 0;
}
})
state.treeData = treeData
//加载子节点数据
onExpand({ fid: currentRow.parentId });
restData1.refreshData();
} catch (error) {
message.error("保存失败");
} finally {
state.loading = false;
}
}
{% endraw %}
案例位置
桌面-页面-列表表单组件-横向树列表.w
使用html的input(file)
使用html的input做文件选择具体实现如下:
js定义渲染方法返回input
let inputRender = () => {
return <input id="input0" type="file" />
}
在页面源码中需要显示input的地方通过 {inputRender()}
引入,即可使用html的input做文件选择
运行效果如下: