feat: table标签列快捷编辑内容空/宽度编辑优化

This commit is contained in:
xinxin.wu 2024-09-11 10:38:55 +08:00 committed by 刘瑞斌
parent 85d098646e
commit 359bfa96f4
9 changed files with 157 additions and 98 deletions

View File

@ -29,8 +29,7 @@
{{ t(item.locale) }}
</div>
<div v-if="Array.isArray(item.value)" class="pr-[24px]">
<MsTagGroup v-if="item.value.length > 0" :tag-list="item.value" size="small" is-string-tag />
<div v-else>-</div>
<MsTagGroup :tag-list="item.value" size="small" is-string-tag />
</div>
<slot v-else :name="item.key" :value="item.value">
<a-tooltip :content="item.value" :disabled="isEmpty(item.value)" :position="item.tooltipPosition">

View File

@ -67,12 +67,12 @@
<a-table-column
v-for="(item, idx) in currentColumns"
:key="idx"
:width="item.isTag || item.isStringTag ? columnLastWidthMap[item.dataIndex as string] : item.width"
:width="item.isTag || item.isStringTag ? getColumnTagLastWidthMap(item) : item.width"
:align="item.align"
:fixed="item.fixed"
:sortable="item.sortable"
:filterable="item.filterable"
:cell-class="item.cellClass"
:cell-class="item.isTag || item.isStringTag ? `ms-tag-cell-class ${item.cellClass || ''}` : item.cellClass"
:header-cell-class="`${item.filterConfig && hasSelectedFilter(item) ? 'header-cell-filter' : ''} ${
item.headerCellClass
}`"
@ -143,20 +143,13 @@
</template>
<template v-else-if="item.isTag || item.isStringTag">
<slot :name="item.slotName" v-bind="{ record, rowIndex, column, columnConfig: item }">
<template
v-if="!record[item.dataIndex as string] || (Array.isArray(record[item.dataIndex as string]) && record[item.dataIndex as string].length === 0)"
>
-
</template>
<template v-else>
<MsTagGroup
:is-string-tag="item.isStringTag"
:tag-list="record[item.dataIndex as string]"
type="primary"
theme="outline"
:tag-position="item.tagPosition"
/>
</template>
<MsTagGroup
:is-string-tag="item.isStringTag"
:tag-list="record[item.dataIndex as string]"
type="primary"
theme="outline"
:tag-position="item.tagPosition"
/>
</slot>
</template>
<template v-else-if="item.slotName === SpecialColumnEnum.OPERATION">
@ -523,12 +516,25 @@
const columnLastWidthMap = ref<Record<string, any>>({});
function getColumnTagLastWidthMap(column: MsTableColumnData) {
const editTgaMinColumnWidth = 200;
// 200
if (column?.allowEditTag) {
if (columnLastWidthMap.value[column.dataIndex as string] < editTgaMinColumnWidth) {
return editTgaMinColumnWidth;
}
return columnLastWidthMap.value[column.dataIndex as string];
}
return columnLastWidthMap.value[column.dataIndex as string];
}
//
const getTagWidth = (tag: Record<string, any>, lastText: string) => {
const maxTagWidth = 144; //
const spanPadding = 8; //
const spanBorder = 2; //
const marginRight = 4; //
const fillWidth = 8; //
const el = document.createElement('div');
el.style.visibility = 'hidden';
@ -542,7 +548,7 @@
//
document.body.removeChild(el);
width = width > maxTagWidth ? maxTagWidth + marginRight : width + marginRight;
width = width > maxTagWidth ? maxTagWidth + marginRight + fillWidth : width + marginRight + fillWidth;
return width;
};
@ -1163,6 +1169,13 @@
color: var(--color-text-3);
}
}
:deep(.arco-table-td.ms-tag-cell-class) {
.arco-table-td-content {
> div {
width: 100%;
}
}
}
</style>
<style lang="less">

View File

@ -70,6 +70,8 @@ export interface MsTableColumnData extends TableColumnData {
isCustomParam?: boolean;
// 插槽表格过滤筛选数据item
filterItem?: any;
// 是否标签编辑列
allowEditTag?: boolean;
// 自定义属性
[key: string]: any;
}

View File

@ -1,5 +1,9 @@
<template>
<div class="flex max-w-[440px] flex-row" @click="emit('click')">
<div
v-if="showTagList.length"
:class="`tag-group-class ${props.allowEdit ? 'cursor-pointer' : ''}`"
@click="emit('click')"
>
<MsTag v-for="tag of showTagList" :key="tag.id" :width="getTagWidth(tag)" :size="props.size" v-bind="attrs">
{{ props.isStringTag ? tag : tag[props.nameKey] }}
</MsTag>
@ -15,6 +19,10 @@
</MsTag>
</a-tooltip>
</div>
<!-- 避免在标签为空时增大点击区域快速编辑 -->
<div v-else :class="`tag-group-class ${props.allowEdit ? 'min-h-[24px] cursor-pointer' : ''}`" @click="emit('click')">
-
</div>
</template>
<script setup lang="ts">
@ -29,6 +37,7 @@
nameKey?: string;
isStringTag?: boolean; //
size?: Size;
allowEdit?: boolean;
tagPosition?:
| 'top'
| 'tl'
@ -83,4 +92,9 @@
});
</script>
<style scoped lang="less"></style>
<style scoped lang="less">
.tag-group-class {
max-width: 440px;
@apply flex w-full flex-row;
}
</style>

View File

@ -428,13 +428,9 @@
});
}
watch(
[() => props.activeModule, () => props.selectedProtocols],
() => {
loadMockList();
},
{ immediate: true }
);
watch([() => props.activeModule, () => props.selectedProtocols], () => {
loadMockList();
});
const isActivated = computed(() => cacheStore.cacheViews.includes(CacheTabTypeEnum.API_TEST_MOCK_TABLE));

View File

@ -92,6 +92,7 @@
:tag-list="record.reviewNames"
is-string-tag
:show-num="1"
allow-edit
theme="outline"
@click="record.showModuleTree = false"
/>

View File

@ -44,19 +44,31 @@
:tag-list="record.userRoles || []"
type="primary"
theme="outline"
allow-edit
@click="changeUser(record)"
/>
<a-select
<MsSelect
v-else
v-model="record.selectUserList"
:popup-visible="record.showUserSelect"
multiple
class="w-full max-w-[300px]"
:max-tag-count="2"
@popup-visible-change="(value) => userGroupChange(value, record)"
>
<a-option v-for="item of userGroupOptions" :key="item.id" :value="item.id">{{ item.name }}</a-option>
</a-select>
v-model:model-value="record.selectUserList"
v-model:loading="dialogLoading"
:max-tag-count="1"
class="w-full"
:options="userGroupOptions"
:search-keys="['name']"
value-key="id"
label-key="name"
allow-search
:multiple="true"
:placeholder="t('common.pleaseSelect')"
:at-least-one="true"
:fallback-option="
(val:any) => ({
label: userGroupOptions.find((e) => e.id === val)?.name || (val as string),
value: val,
})
"
@popup-visible-change="(value:boolean) => userGroupChange(value as boolean, record)"
/>
</template>
<template #enable="{ record }">
<div v-if="record.enable" class="flex items-center">
@ -106,6 +118,7 @@
import MsTagGroup from '@/components/pure/ms-tag/ms-tag-group.vue';
import MsBatchModal from '@/components/business/ms-batch-modal/index.vue';
import MsRemoveButton from '@/components/business/ms-remove-button/MsRemoveButton.vue';
import MsSelect from '@/components/business/ms-select';
import AddMemberModal from './addMemberModal.vue';
import inviteModal from '@/views/setting/system/components/inviteModal.vue';
@ -173,6 +186,7 @@
dataIndex: 'userRoles',
showDrag: true,
isTag: true,
allowEditTag: true,
width: 300,
},
{
@ -345,24 +359,24 @@
const batchModalRef = ref();
//
const addUserGroup = async (target: string[]) => {
const { selectedIds, excludeIds, selectAll } = batchParams.value;
const params = {
projectId: lastProjectId.value,
userIds: batchParams.value.selectedIds || [],
selectAll: !!selectAll,
excludeIds: excludeIds || [],
selectIds: selectedIds || [],
roleIds: target,
condition: {
keyword: keyword.value,
filter: {
...propsRes.value.filter,
roleIds: roleIds.value ? [roleIds.value] : [],
},
combine: batchParams.value.condition,
},
};
try {
const { selectedIds, excludeIds, selectAll } = batchParams.value;
const params = {
projectId: lastProjectId.value,
userIds: batchParams.value.selectedIds || [],
selectAll: !!selectAll,
excludeIds: excludeIds || [],
selectIds: selectedIds || [],
roleIds: target,
condition: {
keyword: keyword.value,
filter: {
...propsRes.value.filter,
roleIds: roleIds.value ? [roleIds.value] : [],
},
combine: batchParams.value.condition,
},
};
await batchModalRef.value.batchRequestFun(addProjectUserGroup, params);
resetSelector();
initData();
@ -393,15 +407,17 @@
addMemberVisible.value = true;
projectMemberRef.value.initProjectMemberOptions();
};
const dialogLoading = ref(false);
//
const editProjectMember = async (record: ProjectMemberItem) => {
const params: ActionProjectMember = {
projectId: lastProjectId.value,
userId: record.id,
roleIds: record.selectUserList,
};
try {
dialogLoading.value = true;
const params: ActionProjectMember = {
projectId: lastProjectId.value,
userId: record.id,
roleIds: record.selectUserList,
};
await addOrUpdateProjectMember(params);
Message.success(t('project.member.batchUpdateSuccess'));
record.showUserSelect = false;
@ -409,6 +425,8 @@
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
dialogLoading.value = false;
}
};

View File

@ -42,23 +42,31 @@
v-if="!record.showProjectSelect"
:tag-list="record.projectIdNameMap || []"
theme="outline"
allow-edit
@click="changeUserOrProject(record, 'project')"
>
</MsTagGroup>
<a-select
<MsSelect
v-else
v-model="record.selectProjectList"
multiple
:max-tag-count="2"
size="small"
class="w-full max-w-[300px]"
:popup-visible="record.showProjectSelect"
@change="(value) => selectUserOrProject(value, record, 'project')"
@popup-visible-change="visibleChange($event, record, 'project')"
>
<a-option v-for="item of projectOptions" :key="item.id" :value="item.id">{{ item.name }}</a-option>
</a-select>
<span v-if="(record.projectIdNameMap || []).length === 0">-</span>
v-model:model-value="record.selectProjectList"
v-model:loading="dialogLoading"
:max-tag-count="1"
class="w-full"
:options="projectOptions"
:search-keys="['name']"
value-key="id"
label-key="name"
allow-search
:multiple="true"
:placeholder="t('common.pleaseSelect')"
:fallback-option="
(val) => ({
label: projectOptions.find((e) => e.id === val)?.name || (val as string),
value: val,
})
"
@popup-visible-change="(value) => visibleChange(value, record, 'project')"
/>
</template>
<template #userRoleIdNameMap="{ record }">
<MsTagGroup
@ -66,22 +74,32 @@
:tag-list="record.userRoleIdNameMap || []"
type="primary"
theme="outline"
allow-edit
@click="changeUserOrProject(record, 'user')"
>
</MsTagGroup>
<a-select
<MsSelect
v-else
v-model="record.selectUserList"
multiple
:max-tag-count="2"
class="w-full max-w-[300px]"
:popup-visible="record.showUserSelect"
@change="(value) => selectUserOrProject(value, record, 'user')"
v-model:model-value="record.selectUserList"
v-model:loading="dialogLoading"
:max-tag-count="1"
class="w-full"
:options="userGroupOptions"
:search-keys="['name']"
value-key="id"
label-key="name"
allow-search
:multiple="true"
:placeholder="t('common.pleaseSelect')"
:at-least-one="true"
:fallback-option="
(val) => ({
label: userGroupOptions.find((e) => e.id === val)?.name || (val as string),
value: val,
})
"
@popup-visible-change="(value) => visibleChange(value, record, 'user')"
>
<a-option v-for="item of userGroupOptions" :key="item.id" :value="item.id">{{ item.name }}</a-option>
</a-select>
<span v-if="(record.userRoleIdNameMap || []).length === 0">-</span>
/>
</template>
<template #enable="{ record }">
<div v-if="record.enable" class="flex items-center">
@ -94,9 +112,9 @@
</div>
</template>
<template #action="{ record }">
<MsButton v-permission="['ORGANIZATION_MEMBER:READ+UPDATE']" @click="addOrEditMember('edit', record)">{{
t('organization.member.edit')
}}</MsButton>
<MsButton v-permission="['ORGANIZATION_MEMBER:READ+UPDATE']" @click="addOrEditMember('edit', record)">
{{ t('organization.member.edit') }}
</MsButton>
<MsRemoveButton
v-permission="['ORGANIZATION_MEMBER:READ+DELETE']"
position="br"
@ -146,6 +164,7 @@
import MsTagGroup from '@/components/pure/ms-tag/ms-tag-group.vue';
import MSBatchModal from '@/components/business/ms-batch-modal/index.vue';
import MsRemoveButton from '@/components/business/ms-remove-button/MsRemoveButton.vue';
import MsSelect from '@/components/business/ms-select';
import AddMemberModal from './components/addMemberModal.vue';
import inviteModal from '@/views/setting/system/components/inviteModal.vue';
@ -216,6 +235,7 @@
showInTable: true,
showDrag: true,
isTag: true,
allowEditTag: true,
},
{
title: 'organization.member.tableColunmUsergroup',
@ -224,6 +244,7 @@
showInTable: true,
isTag: true,
showDrag: true,
allowEditTag: true,
width: 300,
},
{
@ -278,6 +299,7 @@
}
);
const keyword = ref('');
const dialogLoading = ref(false);
const tableSelected = ref<(string | number)[]>([]);
//
const selectedData = ref<string[] | undefined>([]);
@ -387,6 +409,7 @@
//
const updateUserOrProject = async (record: MemberItem) => {
try {
dialogLoading.value = true;
const params = {
organizationId: lastOrganizationId.value,
projectIds: [...record.selectProjectList],
@ -403,6 +426,7 @@
} finally {
record.showUserSelect = false;
record.showProjectSelect = false;
dialogLoading.value = false;
}
};
//
@ -423,17 +447,6 @@
record.selectProjectList = (record.projectIdNameMap || []).map((item) => item.id);
record.selectUserList = (record.userRoleIdNameMap || []).map((item) => item.id);
};
//
const selectUserOrProject = (value: any, record: MemberItem, type: string) => {
if (!hasAnyPermission(['ORGANIZATION_MEMBER:READ+UPDATE'])) {
return;
}
if (type === 'project') {
record.selectProjectList = value;
} else {
record.selectUserList = value;
}
};
//
const visibleChange = (visible: boolean, record: MemberItem, type: string) => {
const originMapIds =

View File

@ -45,6 +45,7 @@
:tag-list="record.userRoleList"
type="primary"
theme="outline"
allow-edit
@click="handleTagClick(record)"
/>
<MsSelect
@ -132,6 +133,7 @@
label: (val as Record<string, any>).name,
value: val,
})"
class="w-full"
:object-value="true"
value-key="id"
label-key="name"
@ -379,6 +381,7 @@
slotName: 'userGroup',
isTag: true,
showDrag: true,
allowEditTag: true,
width: 300,
},
{