Commit 6d0e800a authored by hcyhuchaoyue's avatar hcyhuchaoyue

feat:ag grid 表格树

parent 6bfb907f
This diff is collapsed.
......@@ -96,7 +96,7 @@ export default {
copy: '复制',
ctrlC: 'Ctrl+C',
copyWithHeaders: '带标题的复制',
copyWithGroupHeaders: '带组标题的复制',
copyWithGroupHeaders: '带标题组的复制',
paste: '粘贴',
ctrlV: 'Ctrl+V',
export: '导出',
......
......@@ -97,7 +97,7 @@ a:hover {
// 标题列调整大小句柄颜色
--ag-header-column-resize-handle-color: var(--my-ag-grid-active) !important;
--ag-selected-row-background-color: var(--my-ag-grid-primary-1) !important;
--ag-selected-row-background-color: var(--my-ag-grid-primary-2) !important;
--ag-range-selection-background-color: var(--my-ag-grid-primary-2) !important;
--ag-row-hover-color: var(--my-ag-grid-primary-1) !important;
--ag-column-hover-color: var(--my-ag-grid-primary-1) !important;
......
......@@ -63,6 +63,6 @@ $header-heigyht: 50px;
--my-ag-grid-primary-1: rgba(165, 189, 22, 0.1);
--my-ag-grid-primary-2: rgba(165, 189, 22, 0.2);
--my-ag-grid-active: rgb(127, 143, 37);
--my-ag-grid-active: rgb(97, 112, 17);
--my-ag-grid-text: #fff7f7;
}
......@@ -18,6 +18,7 @@ import AgGridStudy from './element/AgGridStudy2.vue';
import AgGridMaster from './element/AgGridMaster.vue';
import AgGridDetailGrids from './element/AgGridDetailGrids.vue';
import AgGridTreeData from './element/AgGridTreeData.vue';
import AgGridTreeFileBrowser from './element/AgGridTreeFileBrowser.vue';
const listData = [
{
......@@ -56,10 +57,14 @@ const listData = [
title: 'Ag Grid 表格树',
name: 'ag-grid-tree-data',
},
{
title: 'Ag Grid 表格树 文件浏览器例子',
name: 'ag-grid-tree-file-browser',
},
];
const isShow = ref(true);
const elementName = ref('ag-grid-tree-data');
const elementTitle = ref('Ag Grid 表格树');
const elementName = ref('ag-grid-tree-file-browser');
const elementTitle = ref('Ag Grid 表格树 文件浏览器例子');
function onclick(data: any) {
elementTitle.value = data.title;
......@@ -101,6 +106,9 @@ function goBack() {
<ag-grid-master v-if="elementName === 'ag-grid-master'" />
<ag-grid-detail-grids v-if="elementName === 'ag-grid-detail-grids'" />
<ag-grid-tree-data v-if="elementName === 'ag-grid-tree-data'" />
<ag-grid-tree-file-browser
v-if="elementName === 'ag-grid-tree-file-browser'"
/>
</div>
</div>
<div v-else>
......
......@@ -71,3 +71,83 @@ export const getData = function () {
// },
// ];
};
export const getData2 = function () {
const rowData = [
{
id: 1,
filePath: ['Documents'],
},
{
id: 2,
filePath: ['Documents', 'txt'],
},
{
id: 3,
filePath: ['Documents', 'txt', 'notes.txt'],
dateModified: 'May 21 2017 01:50:00 PM',
size: 14.7,
},
{
id: 4,
filePath: ['Documents', 'pdf'],
},
{
id: 5,
filePath: ['Documents', 'pdf', 'book.pdf'],
dateModified: 'May 20 2017 01:50:00 PM',
size: 2.1,
},
{
id: 6,
filePath: ['Documents', 'pdf', 'cv.pdf'],
dateModified: 'May 20 2016 11:50:00 PM',
size: 2.4,
},
{
id: 7,
filePath: ['Documents', 'xls'],
},
{
id: 8,
filePath: ['Documents', 'xls', 'accounts.xls'],
dateModified: 'Aug 12 2016 10:50:00 AM',
size: 4.3,
},
{
id: 9,
filePath: ['Documents', 'stuff'],
},
{
id: 10,
filePath: ['Documents', 'stuff', 'xyz.txt'],
dateModified: 'Jan 17 2016 08:03:00 PM',
size: 1.1,
},
{
id: 11,
filePath: ['Music', 'mp3', 'pop'],
dateModified: 'Sep 11 2016 08:03:00 PM',
size: 14.3,
},
{
id: 12,
filePath: ['temp.txt'],
dateModified: 'Aug 12 2016 10:50:00 PM',
size: 101,
},
{
id: 13,
filePath: ['Music', 'mp3', 'pop', 'theme.mp3'],
dateModified: 'Aug 12 2016 10:50:00 PM',
size: 101,
},
{
id: 14,
filePath: ['Music', 'mp3', 'jazz'],
dateModified: 'Aug 12 2016 10:50:00 PM',
size: 101,
},
];
return rowData;
};
<!--
* Ag Grid 表格树 文件浏览器例子
* https://www.ag-grid.com/vue-data-grid/tree-data/#file-browser-example
-->
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue';
import { date } from 'quasar';
import { AgGridVue } from 'ag-grid-vue3';
import { useMessage } from 'src/common/hooks';
import AG_GRID_LOCALE from 'src/config/ag-grid-locale';
import { getData2 } from '../config';
const defaultColDef = {
flex: 1,
filter: true,
sortable: true,
resizable: true,
};
const { warn } = useMessage();
const gridApi = ref<any>(null);
const gridColumnApi = ref<any>(null);
const state = reactive({
columnDefs: [
{
field: 'dateModified',
headerName: '修改时间',
minWidth: 250,
comparator: (d1: any, d2: any) => {
return new Date(d1).getTime() < new Date(d2).getTime() ? -1 : 1;
},
valueFormatter: (params: any) => {
const timeStamp = new Date(params.value);
return date.formatDate(timeStamp, 'YYYY-MM-DD HH:mm:ss');
},
},
{
field: 'size',
headerName: '大小',
aggFunc: 'sum',
valueFormatter: (params: any) => {
return params.value
? Math.round(params.value * 10) / 10 + ' MB'
: '0 MB';
},
},
],
rowData: [] as any,
});
const autoGroupColumnDef = reactive({
headerName: '文件',
minWidth: 330,
cellRendererParams: {
checkbox: true,
suppressCount: true,
innerRenderer: getFileCellRenderer(),
},
});
onMounted(() => {
setTimeout(() => {
state.rowData = getData2();
console.log('rowData', state.rowData);
}, 1000);
});
function onGridReady(params: any) {
gridApi.value = params.api;
gridColumnApi.value = params.columnApi;
}
function getDataPath(data: any) {
return data.filePath;
}
function getRowId(params: any) {
return params.data.id;
}
function addNewGroup() {
const newGroupData = [
{
id: getNextId(),
filePath: ['Music', 'wav', 'hit_' + new Date().getTime() + '.wav'],
dateModified: new Date(),
size: 58.9,
},
];
gridApi.value.applyTransaction({ add: newGroupData });
}
function moveSelectedNodeToTarget(targetRowId: any) {
console.log('moveSelectedNodeToTarget', targetRowId);
let selectedNode = gridApi.value.getSelectedNodes()[0]; // single selection
if (!selectedNode) {
warn('没有选择节点!');
return;
}
let targetNode = gridApi.value.getRowNode(targetRowId);
if (!targetNode) {
warn('目标文件不存在!');
return;
}
let invalidMove =
selectedNode.key === targetNode.key ||
isSelectionParentOfTarget(selectedNode, targetNode);
if (invalidMove) {
warn('无效选择 - 不能是父级或与目标相同!');
return;
}
let rowsToUpdate = getRowsToUpdate(selectedNode, targetNode.data.filePath);
gridApi.value.applyTransaction({ update: rowsToUpdate });
}
function removeSelected() {
let selectedNode = gridApi.value.getSelectedNodes()[0]; // single selection
if (!selectedNode) {
warn('没有选择节点!');
return;
}
gridApi.value.applyTransaction({ remove: getRowsToRemove(selectedNode) });
}
function getFileCellRenderer() {
class FileCellRenderer {
init(params: any) {
let tempDiv = document.createElement('div');
let value = params.value;
let icon = getFileIcon(params.value);
tempDiv.innerHTML = icon
? '<span><i class="' +
icon +
'" style="font-size: 16px"></i>' +
'&nbsp;' +
'<span class="filename"></span>' +
value +
'</span>'
: value;
const that: any = this;
that.eGui = tempDiv.firstChild;
}
getGui() {
const that: any = this;
return that.eGui;
}
refresh() {
return false;
}
}
return FileCellRenderer;
}
function getFileIcon(name: any) {
return endsWith(name, '.mp3') || endsWith(name, '.wav')
? 'far fa-file-audio'
: endsWith(name, '.xls')
? 'far fa-file-excel'
: endsWith(name, '.txt')
? 'far fa-file'
: endsWith(name, '.pdf')
? 'far fa-file-pdf'
: 'far fa-folder';
}
function endsWith(str: any, match: any) {
let len;
if (str == null || !str.length || match == null || !match.length) {
return false;
}
len = str.length;
return str.substring(len - match.length, len) === match;
}
function getNextId() {
const _window: any = window;
if (!_window.nextId) {
_window.nextId = 15;
} else {
_window.nextId++;
}
return _window.nextId;
}
function isSelectionParentOfTarget(selectedNode: any, targetNode: any) {
let children = selectedNode.childrenAfterGroup || [];
for (let i = 0; i < children.length; i++) {
if (targetNode && children[i].key === targetNode.key) return true;
isSelectionParentOfTarget(children[i], targetNode);
}
return false;
}
function getRowsToUpdate(node: any, parentPath: any) {
let res: any = [];
let newPath = parentPath.concat([node.key]);
if (node.data) {
// groups without data, i.e. 'filler groups' don't need path updated
// 没有数据的组,即“填充组”不需要更新路径
node.data.filePath = newPath;
}
let children = node.childrenAfterGroup || [];
for (let i = 0; i < children.length; i++) {
let updatedChildRowData = getRowsToUpdate(children[i], newPath);
res = res.concat(updatedChildRowData);
}
// ignore nodes that have no data, i.e. 'filler groups'
// 忽略没有数据的节点,即“填充组”
return node.data ? res.concat([node.data]) : res;
}
function getRowsToRemove(node: any) {
let res: any = [];
const children = node.childrenAfterGroup || [];
for (let i = 0; i < children.length; i++) {
res = res.concat(getRowsToRemove(children[i]));
}
// ignore nodes that have no data, i.e. 'filler groups'
// 忽略没有数据的节点,即“填充组”
return node.data ? res.concat([node.data]) : res;
}
</script>
<template>
<div class="box">
<div class="btns">
<q-btn
color="primary"
label="在Music下添加一个新组"
no-caps
@click="addNewGroup"
/>
<q-btn
color="primary"
label="移动到stuff文件夹中"
no-caps
@click="moveSelectedNodeToTarget('9')"
/>
<q-btn
color="primary"
label="删除所选组和它的子组"
no-caps
@click="removeSelected"
/>
</div>
<!--
rowSelection="multiple":多选,按住control键多选;【control+shift+鼠标点击】可选中多行
animateRows=true:启用行动画
:masterDetail="true" 启用展开的细节网格行
:isRowMaster="isRowMaster" 确定哪一个行该展开
-->
<div class="ag-table">
<ag-grid-vue
style="height: 500px"
class="ag-theme-alpine"
:localeText="AG_GRID_LOCALE"
:columnDefs="state.columnDefs"
:rowData="state.rowData"
:defaultColDef="defaultColDef"
:animateRows="true"
:pagination="true"
:paginationPageSize="5"
@grid-ready="onGridReady"
:treeData="true"
:getDataPath="getDataPath"
:getRowId="getRowId"
:autoGroupColumnDef="autoGroupColumnDef"
:groupDefaultExpanded="-1"
>
</ag-grid-vue>
</div>
</div>
</template>
<style lang="scss" scoped>
.btns {
padding: 10px;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
column-gap: 10px;
}
.ag-table {
padding: 0 10px 10px 10px;
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment