feat(测试用例): 功能用例关联需求调整&优化table选择

This commit is contained in:
xinxin.wu 2024-09-04 17:04:35 +08:00 committed by 刘瑞斌
parent 8c9f79f14a
commit 53649fbc5e
7 changed files with 146 additions and 103 deletions

View File

@ -233,7 +233,7 @@
</template> </template>
<template #expand-icon="{ expanded, record }"> <template #expand-icon="{ expanded, record }">
<!-- @desc: 这里为了树级别展开折叠如果子级别children不存在不展示展开折叠所以原本组件的隐藏掉改成自定义便于控制展示隐藏 --> <!-- @desc: 这里为了树级别展开折叠如果子级别children不存在不展示展开折叠所以原本组件的隐藏掉改成自定义便于控制展示隐藏 -->
<slot v-if="record.children" name="expand-icon" v-bind="{ expanded, record }"> <slot v-if="record.children && record.children.length" name="expand-icon" v-bind="{ expanded, record }">
<div <div
:class="`${ :class="`${
expanded ? 'expanded-border bg-[rgb(var(--primary-1))]' : 'not-expanded-border bg-[var(--color-text-n8)]' expanded ? 'expanded-border bg-[rgb(var(--primary-1))]' : 'not-expanded-border bg-[var(--color-text-n8)]'
@ -844,7 +844,11 @@
} }
function getChecked(record: TableData) { function getChecked(record: TableData) {
if (!record.children || (attrs.rowSelectionDisabledConfig as MsTableRowSelectionDisabledConfig)?.disabledChildren) { if (
!record.children ||
(attrs.rowSelectionDisabledConfig as MsTableRowSelectionDisabledConfig)?.disabledChildren ||
!(attrs.rowSelectionDisabledConfig as MsTableRowSelectionDisabledConfig)?.checkStrictly
) {
return props.selectedKeys.has(record[rowKey || 'id']); return props.selectedKeys.has(record[rowKey || 'id']);
} }
@ -853,6 +857,11 @@
} }
function getIndeterminate(record: TableData) { function getIndeterminate(record: TableData) {
//
const { rowSelectionDisabledConfig } = attrs;
if (!(rowSelectionDisabledConfig as MsTableRowSelectionDisabledConfig)?.checkStrictly) {
return false;
}
if (!record.children || (attrs.rowSelectionDisabledConfig as MsTableRowSelectionDisabledConfig)?.disabledChildren) { if (!record.children || (attrs.rowSelectionDisabledConfig as MsTableRowSelectionDisabledConfig)?.disabledChildren) {
return false; return false;
} }
@ -1017,8 +1026,6 @@
background: none !important; background: none !important;
} }
:deep(.arco-table .arco-table-expand-btn) { :deep(.arco-table .arco-table-expand-btn) {
width: 16px;
height: 16px;
border-color: transparent; border-color: transparent;
} }
:deep(.arco-table-tr-expand .arco-table-td) { :deep(.arco-table-tr-expand .arco-table-td) {

View File

@ -35,8 +35,9 @@ export interface MsTableColumnFilterConfig {
} }
export interface MsTableRowSelectionDisabledConfig { export interface MsTableRowSelectionDisabledConfig {
disabledChildren?: boolean; disabledChildren?: boolean; // 是否禁用子节点选择
parentKey?: string; parentKey?: string; // 父节点Key
checkStrictly?: boolean; // 父子节点选择是否关联,关联存在半选状态,不关联不存在,选择父即父,选择子即子
} }
export interface MsTableColumnData extends TableColumnData { export interface MsTableColumnData extends TableColumnData {

View File

@ -181,12 +181,46 @@ export default function useTableProps<T>(
} }
propsRes.value.selectedKeys = selectedKeys; propsRes.value.selectedKeys = selectedKeys;
}; };
// 处理全选状态下切换分页也要处理下边的子节点
const processRecordItem = (item: MsTableDataItem<T>): MsTableDataItem<T> => {
const { rowKey, selectorStatus, excludeKeys } = propsRes.value;
if (item.updateTime) {
item.updateTime = dayjs(item.updateTime).format('YYYY-MM-DD HH:mm:ss');
}
if (item.createTime) {
item.createTime = dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss');
}
if (dataTransform) {
item = dataTransform(item);
}
if (selectorStatus === SelectAllEnum.ALL && !excludeKeys.has(item[rowKey])) {
setTableSelected(item[rowKey]);
const selectChildren = (children: MsTableDataItem<T>[]) => {
children.forEach((child) => {
if (!excludeKeys.has(child[rowKey])) {
setTableSelected(child[rowKey]);
}
if (child.children && child.children.length) {
selectChildren(child.children);
}
});
};
if (item.children && item.children.length) {
selectChildren(item.children);
}
}
return item;
};
// 加载分页列表数据 // 加载分页列表数据
const loadList = async () => { const loadList = async () => {
if (propsRes.value.showPagination) { if (propsRes.value.showPagination) {
const { current, pageSize } = propsRes.value.msPagination as Pagination; const { current, pageSize } = propsRes.value.msPagination as Pagination;
const { rowKey, selectorStatus, excludeKeys } = propsRes.value;
let currentPageSize = pageSize; let currentPageSize = pageSize;
if (propsRes.value.tableKey) { if (propsRes.value.tableKey) {
// 如果表格设置了tableKey缓存分页大小 // 如果表格设置了tableKey缓存分页大小
@ -210,21 +244,7 @@ export default function useTableProps<T>(
const data = await loadListFunc(tableQueryParams.value); const data = await loadListFunc(tableQueryParams.value);
const tmpArr = data.list || data.data.list; const tmpArr = data.list || data.data.list;
propsRes.value.data = tmpArr.map((item: MsTableDataItem<T>) => { propsRes.value.data = tmpArr.map((item: MsTableDataItem<T>) => {
if (item.updateTime) { return processRecordItem(item);
item.updateTime = dayjs(item.updateTime).format('YYYY-MM-DD HH:mm:ss');
}
if (item.createTime) {
item.createTime = dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss');
}
if (dataTransform) {
item = dataTransform(item);
}
if (selectorStatus === SelectAllEnum.ALL) {
if (!excludeKeys.has(item[rowKey])) {
setTableSelected(item[rowKey]);
}
}
return item;
}); });
if (data.total === 0) { if (data.total === 0) {
setTableErrorStatus('empty'); setTableErrorStatus('empty');
@ -351,6 +371,57 @@ export default function useTableProps<T>(
}); });
}; };
// 处理父节点半选
const handleParentSelection = (record: MsTableDataItem<T>) => {
const { rowKey, selectedKeys, excludeKeys, rowSelectionDisabledConfig } = propsRes.value;
const key = record[rowKey || 'id'];
const parentKey = record[rowSelectionDisabledConfig?.parentKey || 'parent'];
if (!record[rowSelectionDisabledConfig?.parentKey || 'parent']) return;
const allChildrenSelected =
record.children && record.children.length
? record.children.every((child) => selectedKeys.has(child[key]))
: false;
const someChildrenSelected =
record.children && record.children.length ? record.children.some((child) => selectedKeys.has(child[key])) : false;
if (allChildrenSelected) {
selectedKeys.add(parentKey);
excludeKeys.delete(parentKey);
} else if (someChildrenSelected) {
selectedKeys.add(parentKey);
excludeKeys.delete(parentKey);
} else {
selectedKeys.delete(parentKey);
excludeKeys.add(parentKey);
}
handleParentSelection(record[rowSelectionDisabledConfig?.parentKey || 'parent']);
};
// 选择/取消当前节点下边的子节点
const handleSelectChildren = (record: MsTableDataItem<T>, select: boolean) => {
const { rowKey, selectedKeys, excludeKeys, rowSelectionDisabledConfig } = propsRes.value;
const key = record[rowKey || 'id'];
const parentKey = record[rowSelectionDisabledConfig?.parentKey || 'parent'];
if (select) {
selectedKeys.add(key);
excludeKeys.delete(key);
} else {
selectedKeys.delete(key);
excludeKeys.add(key);
}
if (record.children && record.children.length) {
record.children.forEach((childRecord) => handleSelectChildren(childRecord, select));
}
// 处理父节点的选中状态
if (!select && parentKey && rowSelectionDisabledConfig?.checkStrictly) {
handleParentSelection(record);
}
};
// 获取表格请求参数 // 获取表格请求参数
const getTableQueryParams = () => { const getTableQueryParams = () => {
return tableQueryParams.value; return tableQueryParams.value;
@ -490,85 +561,31 @@ export default function useTableProps<T>(
propsRes.value.selectorStatus = v; propsRes.value.selectorStatus = v;
} }
}, },
// TODO: 待优化逻辑
// 表格行的选中/取消事件 // 表格行的选中/取消事件
rowSelectChange: (record: MsTableDataItem<T>) => { rowSelectChange: (record: MsTableDataItem<T>) => {
const { rowKey } = propsRes.value; const { rowKey, rowSelectionDisabledConfig } = propsRes.value;
const key = record[rowKey || 'id']; const key = record[rowKey || 'id'];
const { selectedKeys, excludeKeys, data } = propsRes.value; const { selectedKeys, excludeKeys } = propsRes.value;
if (props?.rowSelectionDisabledConfig?.disabledChildren) { if (selectedKeys.has(key)) {
if (selectedKeys.has(key)) { // 当前已选中,取消选中
// 当前已选中,取消选中 selectedKeys.delete(key);
selectedKeys.delete(key); excludeKeys.add(key);
excludeKeys.add(key); if (rowSelectionDisabledConfig?.checkStrictly) {
} else { // 取消当前节点的所有子节点
// 当前未选中,选中 handleSelectChildren(record, false);
selectedKeys.add(key);
if (excludeKeys.has(key)) {
excludeKeys.delete(key);
}
} }
return; } else {
} // 当前未选中,选中
// 是否包含子级 selectedKeys.add(key);
const isHasChildrenData = data.some((item) => item.children); if (excludeKeys.has(key)) {
let isSelectChildren; excludeKeys.delete(key);
let currentALlParentChildrenIds: string[] = [];
// @desc: 如果存在子级获取当前同一级别所有的ids用来判断是否子级全部选择将父节点id也添加进来
if (isHasChildrenData) {
const parentItemChildren: any = data.find((item) => item[rowKey] === record.parent)?.children || [];
currentALlParentChildrenIds = getCurrentRecordChildrenIds(parentItemChildren, rowKey || 'id');
}
// 非子级
if (!record.children) {
if (selectedKeys.has(key)) {
// 当前已选中,取消选中
selectedKeys.delete(key);
excludeKeys.add(key);
// @desc: 只要取消一个子级则取消他的父节点选择
if (record.parent) {
selectedKeys.delete(record.parent);
excludeKeys.add(record.parent);
}
} else {
// 当前未选中,选中
selectedKeys.add(key);
if (excludeKeys.has(key)) {
excludeKeys.delete(key);
}
// @desc: 判断当前子级是否已经全选,全选则将上层父级也选择
isSelectChildren = currentALlParentChildrenIds.every((id) => selectedKeys.has(id));
if (isSelectChildren && record.parent) {
selectedKeys.add(record.parent);
excludeKeys.delete(record.parent);
}
} }
if (rowSelectionDisabledConfig?.checkStrictly) {
// 选择当前节点的所有子节点
handleSelectChildren(record, true);
}
}
// 包含子级
} else if (record.children) {
const childrenIds = getCurrentRecordChildrenIds(record.children, rowKey || 'id');
const isSelectAllChildren = childrenIds.every((id) => selectedKeys.has(id));
const includeCurrentIds = [key, ...childrenIds];
// 当前父节点已选中,取消选择父节点和父节点下所有子节点
if (isSelectAllChildren) {
includeCurrentIds.forEach((id) => {
selectedKeys.delete(id);
});
includeCurrentIds.forEach((id) => {
excludeKeys.add(id);
});
// 未选中则全选父节点和下边所有子节点
} else {
selectedKeys.add(key);
collectIds(record.children, rowKey);
childrenIds.forEach((id) => {
excludeKeys.delete(id);
});
if (excludeKeys.has(key)) {
excludeKeys.delete(key);
}
}
}
if (selectedKeys.size === 0 && propsRes.value.selectorStatus === SelectAllEnum.CURRENT) { if (selectedKeys.size === 0 && propsRes.value.selectorStatus === SelectAllEnum.CURRENT) {
propsRes.value.selectorStatus = SelectAllEnum.NONE; propsRes.value.selectorStatus = SelectAllEnum.NONE;
} else if (selectedKeys.size > 0 && propsRes.value.selectorStatus === SelectAllEnum.NONE) { } else if (selectedKeys.size > 0 && propsRes.value.selectorStatus === SelectAllEnum.NONE) {

View File

@ -2,8 +2,11 @@
<ms-base-table ref="tableRef" v-bind="propsRes" v-on="propsEvent"> <ms-base-table ref="tableRef" v-bind="propsRes" v-on="propsEvent">
<template #demandName="{ record }"> <template #demandName="{ record }">
<span :class="[props.highlightName ? 'text-[rgb(var(--primary-5))]' : '']" @click="emit('open', record)"> <span :class="[props.highlightName ? 'text-[rgb(var(--primary-5))]' : '']" @click="emit('open', record)">
{{ characterLimit(record.demandName) }} </span {{ characterLimit(record.demandName) }}
><span class="one-line-text text-[rgb(var(--primary-5))]">({{ (record.children || []).length || 0 }})</span> </span>
<span v-if="(record.children || []).length" class="one-line-text text-[rgb(var(--primary-5))]">
({{ (record.children || []).length || 0 }})
</span>
</template> </template>
<template #operation="{ record }"> <template #operation="{ record }">
<MsButton <MsButton

View File

@ -90,8 +90,8 @@
<template #demandName="{ record }"> <template #demandName="{ record }">
<span class="ml-1 text-[rgb(var(--primary-5))]"> <span class="ml-1 text-[rgb(var(--primary-5))]">
{{ record.demandName }} {{ record.demandName }}
<span>({{ (record.children || []).length || 0 }})</span></span <span v-if="(record.children || []).length"> ({{ (record.children || []).length || 0 }}) </span>
> </span>
</template> </template>
<template v-for="item in customFields" :key="item.slotName" #[item.dataIndex]="{ record }"> <template v-for="item in customFields" :key="item.slotName" #[item.dataIndex]="{ record }">
<span> {{ getSlotName(record, item) }} </span> <span> {{ getSlotName(record, item) }} </span>
@ -211,6 +211,9 @@
selectable: true, selectable: true,
showSelectorAll: false, showSelectorAll: false,
showSetting: false, showSetting: false,
rowSelectionDisabledConfig: {
checkStrictly: false,
},
}); });
const drawerLoading = ref<boolean>(false); const drawerLoading = ref<boolean>(false);
@ -419,4 +422,13 @@
}); });
</script> </script>
<style scoped></style> <style scoped lang="less">
:deep(.arco-table-cell-align-left) > span:first-child {
padding-left: 0 !important;
}
:deep(.arco-table-cell-align-left) {
.arco-table-cell-inline-icon + .arco-table-td-content {
padding-right: 19px !important;
}
}
</style>

View File

@ -32,8 +32,8 @@
<template #demandName="{ record }"> <template #demandName="{ record }">
<span class="ml-1 text-[rgb(var(--primary-5))]"> <span class="ml-1 text-[rgb(var(--primary-5))]">
{{ record.demandName }} {{ record.demandName }}
<span>({{ (record.children || []).length || 0 }})</span></span <span v-if="(record.children || []).length">({{ (record.children || []).length || 0 }})</span>
> </span>
</template> </template>
<template v-for="item in customFields" :key="item.slotName" #[item.dataIndex]="{ record }"> <template v-for="item in customFields" :key="item.slotName" #[item.dataIndex]="{ record }">
<span> {{ getSlotName(record, item) }} </span> <span> {{ getSlotName(record, item) }} </span>

View File

@ -23,7 +23,6 @@
v-on="propsEvent" v-on="propsEvent"
@batch-action="handleTableBatch" @batch-action="handleTableBatch"
> >
<!-- TOTO 等待联调 后台接口需要调整 -->
<template #resourceNum="{ record }"> <template #resourceNum="{ record }">
<div class="flex items-center"> <div class="flex items-center">
<PlanExpandRow <PlanExpandRow
@ -353,6 +352,10 @@
selectable: hasOperationPermission.value, selectable: hasOperationPermission.value,
heightUsed: 330, heightUsed: 330,
showSelectAll: true, showSelectAll: true,
rowSelectionDisabledConfig: {
parentKey: 'parent',
checkStrictly: true,
},
} }
); );