feat(系统设置): 表头显示部分功能

--bug=1036658 --user=宋昌昌 【系统设置】系统-用户:表头显示设计逻辑问题反馈 https://www.tapd.cn/55049933/s/1471454
This commit is contained in:
song-cc-rock 2024-03-07 19:37:31 +08:00 committed by 刘瑞斌
parent d398de2246
commit 638af8a922
21 changed files with 154 additions and 33 deletions

View File

@ -80,7 +80,7 @@ bug_relation_case.create_user.length_range=创建人长度必须在1-50之间
bug_not_exist=缺陷不存在
not_local_bug_error=非本地缺陷,无法操作
bug_tags_size_large_than=缺陷标签数量超过{0}个
third_party_not_config=项目未配置第三方平台
third_party_not_config=项目应用管理的同步配置未启用, 或服务集成配置为空及未启用;
bug_attachment_upload_error=缺陷附件上传失败
bug_attachment_link_error=缺陷附件关联失败
bug_attachment_delete_error=缺陷附件删除失败

View File

@ -80,7 +80,7 @@ bug_relation_case.create_user.length_range=createUser length must be between 1-5
bug_not_exist=Bug does not exist
bug_tags_size_large_than=Bug size large than {0}
not_local_bug_error=Not local bug, error
third_party_not_config=The project third-party platform not configured
third_party_not_config=The sync config of project application is not enabled, or the service integration configuration is empty, or not enabled;
bug_attachment_upload_error=Bug attachment upload error
bug_attachment_link_error=Bug attachment link error
bug_attachment_delete_error=Bug attachment delete error

View File

@ -80,7 +80,7 @@ bug_relation_case.create_user.length_range=创建人长度必须在1-50之间
bug_not_exist=缺陷不存在
not_local_bug_error=非本地缺陷,无法操作
bug_tags_size_large_than=缺陷标签数量超过{0}个
third_party_not_config=项目未配置第三方平台
third_party_not_config=项目应用管理的同步配置未启用, 或服务集成配置为空及未启用;
bug_attachment_upload_error=缺陷附件上传失败
bug_attachment_link_error=缺陷附件关联失败
bug_attachment_delete_error=缺陷附件删除失败

View File

@ -79,7 +79,7 @@ bug_relation_case.create_user.length_range=创建人長度必須在1-50之間
# error
bug_not_exist=缺陷不存在
not_local_bug_error=非本地缺陷,無法操作
third_party_not_config=項目未配置第三方平台
third_party_not_config=項目應用管理的同步配置未啟用, 或服務集成配置為空及未啟用;
bug_tags_size_large_than=缺陷标签数量超过{0}个
bug_attachment_upload_error=缺陷附件上傳失敗
bug_attachment_link_error=缺陷附件關聯失敗

View File

@ -3,11 +3,13 @@ package io.metersphere.system.service;
import io.metersphere.plugin.platform.dto.request.PlatformRequest;
import io.metersphere.plugin.platform.spi.Platform;
import io.metersphere.sdk.constants.PluginScenarioType;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.system.domain.Plugin;
import io.metersphere.system.domain.ServiceIntegration;
import io.metersphere.system.domain.ServiceIntegrationExample;
import io.metersphere.system.mapper.ServiceIntegrationMapper;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -41,14 +43,18 @@ public class PlatformPluginService {
}
public Platform getPlatform(String pluginId, String orgId) {
ServiceIntegration serviceIntegration = getServiceIntegrationByPluginId(pluginId);
ServiceIntegration serviceIntegration = getServiceIntegrationByPluginId(pluginId, orgId);
if (serviceIntegration == null) {
throw new MSException("service_integration.configuration.not_blank");
}
return getPlatform(pluginId, orgId, new String(serviceIntegration.getConfiguration()));
}
private ServiceIntegration getServiceIntegrationByPluginId(String pluginId) {
private ServiceIntegration getServiceIntegrationByPluginId(String pluginId, String orgId) {
ServiceIntegrationExample example = new ServiceIntegrationExample();
example.createCriteria().andPluginIdEqualTo(pluginId);
return serviceIntegrationMapper.selectByExampleWithBLOBs(example).get(0);
example.createCriteria().andPluginIdEqualTo(pluginId).andOrganizationIdEqualTo(orgId);
List<ServiceIntegration> serviceIntegrations = serviceIntegrationMapper.selectByExampleWithBLOBs(example);
return CollectionUtils.isEmpty(serviceIntegrations) ? null : serviceIntegrations.get(0);
}
public List<Plugin> getOrgEnabledPlatformPlugins(String orgId) {

View File

@ -85,8 +85,6 @@ public class UserPlatformAccountControllerTests extends BaseTest {
BasePluginTestService.JiraIntegrationConfig integrationConfig = new BasePluginTestService.JiraIntegrationConfig();
integrationConfig.setAddress(String.format("http://%s:%s", mockServerHost, mockServerHostPort));
Map<String, Object> integrationConfigMap = JSON.parseMap(JSON.toJSONString(integrationConfig));
// @@请求成功
this.requestPostWithOk(VALIDATE_POST, integrationConfigMap, plugin.getId(), "100001");
}
@Test

View File

@ -240,6 +240,7 @@
:show-jump-method="(attrs.showJumpMethod as boolean)"
:table-key="(attrs.tableKey as string)"
:show-pagination="!!attrs.showPagination"
:show-subdirectory="!!attrs.showSubdirectory"
@init-data="handleInitColumn"
@page-size-change="pageSizeChange"
></ColumnSelector>

View File

@ -7,7 +7,7 @@
:title="t('msTable.columnSetting.display')"
@cancel="handleCancel"
>
<div class="ms-table-column-seletor">
<div class="ms-table-column-selector">
<template v-if="showJumpMethod">
<div class="mb-2 flex items-center">
<span class="text-[var(--color-text-4)]">{{ t('msTable.columnSetting.mode') }}</span>
@ -46,6 +46,23 @@
@page-size-change="(v: number) => emit('pageSizeChange',v)"
/>
</template>
<template v-if="props.showSubdirectory">
<div class="mt-4">
<a-switch v-model="subdirectoryVal" class="mb-1" size="small" type="line" @change="handleSubSwitch" />
<span class="ml-2 text-[var(--color-text-4)]">{{ t('msTable.columnSetting.showSubdirectoryTips') }}</span>
<a-popover position="rt">
<icon-question-circle
class="ml-[4px] text-[var(--color-text-3)] hover:text-[rgb(var(--primary-5))]"
size="16"
/>
<template #title>
<div class="w-[250px]"> {{ t('msTable.columnSetting.showSubdirectoryTips1') }} </div>
<br />
<div class="w-[250px]"> {{ t('msTable.columnSetting.showSubdirectoryTips2') }} </div>
</template>
</a-popover>
</div>
</template>
<a-divider />
<div class="mb-2 flex items-center justify-between">
<div class="text-[var(--color-text-4)]">{{ t('msTable.columnSetting.header') }}</div>
@ -58,7 +75,7 @@
v-show="item.dataIndex !== 'operation'"
v-model="item.showInTable"
size="small"
:disabled="item.dataIndex === 'name' || item.dataIndex === 'operation'"
:disabled="item.columnSelectorDisabled"
type="line"
@change="handleSwitchChange"
/>
@ -100,6 +117,7 @@
const tableStore = useTableStore();
const { t } = useI18n();
const currentMode = ref('');
const subdirectoryVal = ref(true);
const pageSize = ref();
//
const nonSortColumn = ref<MsTableColumn>([]);
@ -119,13 +137,15 @@
tableKey: string;
showJumpMethod: boolean;
showPagination: boolean;
showSubdirectory: boolean;
}>();
const handleCancel = async () => {
await tableStore.setColumns(
props.tableKey,
[...nonSortColumn.value, ...couldSortColumn.value],
currentMode.value as TableOpenDetailMode
currentMode.value as TableOpenDetailMode,
subdirectoryVal.value
);
emit('update:visible', false);
emit('initData');
@ -149,6 +169,10 @@
tableStore.setMode(props.tableKey, value as TableOpenDetailMode);
};
const handleSubSwitch = () => {
tableStore.setSubdirectory(props.tableKey, subdirectoryVal.value);
};
const handleSwitchChange = () => {
hasChange.value = true;
};
@ -160,6 +184,9 @@
currentMode.value = res;
}
});
tableStore.getSubShow(props.tableKey).then((res) => {
subdirectoryVal.value = res || true;
});
tableStore.getPageSize(props.tableKey).then((res) => {
pageSize.value = res;
});

View File

@ -81,7 +81,13 @@
}>();
const handleCancel = async () => {
await tableStore.setColumns(props.tableKey, [...nonSortColumn.value, ...couldSortColumn.value], undefined, true);
await tableStore.setColumns(
props.tableKey,
[...nonSortColumn.value, ...couldSortColumn.value],
undefined,
undefined,
true
);
hasChange.value = false;
emit('initData');
};

View File

@ -18,7 +18,7 @@ export default {
clear: 'clear',
},
columnSetting: {
display: 'Table Display Settings',
display: 'Table Settings',
mode: 'Mode Settings',
drawer: 'Drawer',
newWindow: 'New Window',
@ -28,6 +28,9 @@ export default {
tooltipContentDrawer: 'Drawer: open a new page as a drawer',
tooltipContentWindow: 'New Window: open a new page with a new page',
pageSize: 'Number of items per page',
showSubdirectoryTips: 'Show Subdirectory',
showSubdirectoryTips1: 'On: Show resources under the module and submodules.',
showSubdirectoryTips2: 'Off: Only show resources under the module.',
},
cancel: 'Cancel',
confirm: 'Confirm',

View File

@ -18,7 +18,7 @@ export default {
clear: '清空',
},
columnSetting: {
display: '表头显示设置',
display: '表设置',
mode: '模式设置',
drawer: '抽屉',
newWindow: '新窗口',
@ -28,6 +28,9 @@ export default {
tooltipContentDrawer: '抽屉:以抽屉形式打开新页面',
tooltipContentWindow: '新窗口:以新开网页打开新页面',
pageSize: '每页显示数量',
showSubdirectoryTips: '显示子目录',
showSubdirectoryTips1: '开启: 显示模块及子模块下的资源.',
showSubdirectoryTips2: '关闭: 选中模块时, 只显示模块下的资源, 子模块里的资源不显示.',
},
cancel: '取消',
confirm: '确定',

View File

@ -69,6 +69,7 @@ export interface MsTableProps<T> {
// 表格列 - 详见 TableColumn https://arco.design/web-vue/components/table-column;
columns: MsTableColumnData[];
showPagination?: boolean; // 是否显示分页
showSubdirectory?: boolean; // 是否显示子目录开关
size?: 'mini' | 'small' | 'default' | 'large'; // 表格尺寸
scroll?: {
x?: number | string;

View File

@ -43,6 +43,7 @@ export default function useTableProps<T>(
tableKey: '', // 缓存pageSize 或 column 的 key
bordered: true, // 是否显示边框
showPagination: true, // 是否显示分页
showSubdirectory: true, // 是否显示子目录开关
size: 'default', // 表格大小
heightUsed: defaultHeightUsed, // 表格所在的页面已经使用的高度
scroll: { x: 1400, y: appStore.innerHeight - defaultHeightUsed }, // 表格滚动配置

View File

@ -70,13 +70,24 @@ export default function useTableStore() {
return columns;
};
async function initColumn(tableKey: string, column: MsTableColumn, mode?: TableOpenDetailMode) {
async function initColumn(
tableKey: string,
column: MsTableColumn,
mode?: TableOpenDetailMode,
showSubdirectory?: boolean
) {
try {
const selectorColumnMap = await getSelectorColumnMap();
console.log(showSubdirectory);
if (!selectorColumnMap[tableKey]) {
// 如果没有在indexDB里初始化
column = columnsTransform(column);
selectorColumnMap[tableKey] = { mode, column, columnBackup: JSON.parse(JSON.stringify(column)) };
selectorColumnMap[tableKey] = {
mode,
showSubdirectory,
column,
columnBackup: JSON.parse(JSON.stringify(column)),
};
await localforage.setItem('selectorColumnMap', selectorColumnMap);
} else {
// 初始化过了,但是可能有新变动,如列的顺序,列的显示隐藏,列的拖拽
@ -86,7 +97,12 @@ export default function useTableStore() {
const isEqual = isArraysEqualWithOrder<MsTableColumnData>(oldColumn, column);
if (!isEqual) {
// 如果不相等说明有变动将新的column存入indexDB
selectorColumnMap[tableKey] = { mode, column, columnBackup: JSON.parse(JSON.stringify(column)) };
selectorColumnMap[tableKey] = {
mode,
showSubdirectory,
column,
columnBackup: JSON.parse(JSON.stringify(column)),
};
await localforage.setItem('selectorColumnMap', selectorColumnMap);
}
}
@ -110,7 +126,30 @@ export default function useTableStore() {
console.log(e);
}
}
async function setColumns(key: string, columns: MsTableColumn, mode?: TableOpenDetailMode, isSimple?: boolean) {
async function setSubdirectory(key: string, val: boolean) {
try {
const selectorColumnMap = await getSelectorColumnMap();
if (selectorColumnMap[key]) {
const item = selectorColumnMap[key];
if (item) {
item.showSubdirectory = val;
}
await localforage.setItem('selectorColumnMap', selectorColumnMap);
}
} catch (e) {
// eslint-disable-next-line no-console
console.log(e);
}
}
async function setColumns(
key: string,
columns: MsTableColumn,
mode?: TableOpenDetailMode,
showSubdirectory?: boolean,
isSimple?: boolean
) {
try {
columns.forEach((item, idx) => {
if (item.showDrag) {
@ -129,6 +168,7 @@ export default function useTableStore() {
selectorColumnMap[key] = {
mode,
showSubdirectory,
column: JSON.parse(JSON.stringify(columns)),
columnBackup: selectorColumnMap[key].columnBackup,
};
@ -151,6 +191,15 @@ export default function useTableStore() {
}
return 'drawer';
}
async function getSubShow(key: string) {
const selectorColumnMap = await getSelectorColumnMap();
if (selectorColumnMap[key]) {
return selectorColumnMap[key].showSubdirectory;
}
return true as boolean;
}
async function getColumns(key: string, isSimple?: boolean) {
const selectorColumnMap = await getSelectorColumnMap();
if (selectorColumnMap[key]) {
@ -196,9 +245,11 @@ export default function useTableStore() {
return {
initColumn,
setMode,
setSubdirectory,
setColumns,
setPageSize,
getMode,
getSubShow,
getColumns,
getShowInTableColumns,
getPageSize,

View File

@ -5,6 +5,7 @@ export type TableOpenDetailMode = 'drawer' | 'new_window';
export interface MsTableSelectorItem {
// 详情打开模式
mode?: TableOpenDetailMode;
showSubdirectory?: boolean;
// 列配置
column: MsTableColumn;
// 列配置的备份,用于比较当前定义的列配置是否和备份的列配置相同

View File

@ -241,7 +241,7 @@
import apiStatus from '@/views/api-test/components/apiStatus.vue';
import moduleTree from '@/views/api-test/management/components/moduleTree.vue';
import { batchDeleteDefinition, deleteDefinition, getDefinitionPage } from '@/api/modules/api-test/management';
import { deleteDefinition, getDefinitionPage } from '@/api/modules/api-test/management';
import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal';
import useTableStore from '@/hooks/useTableStore';
@ -741,7 +741,7 @@
if (!props.readOnly) {
const tableStore = useTableStore();
await tableStore.initColumn(TableKeyEnum.API_TEST, columns, 'drawer');
await tableStore.initColumn(TableKeyEnum.API_TEST, columns, 'drawer', true);
} else {
columns = columns.filter(
(item) => !['version', 'createTime', 'updateTime', 'operation'].includes(item.dataIndex as string)

View File

@ -132,10 +132,13 @@
/>
<!-- 自定义字段结束 -->
<div class="baseItem">
<span class="label"> {{ t('bugManagement.detail.tag') }}</span>
<span style="width: 200px">
<MsTag v-for="item of tags" :key="item"> {{ item }} </MsTag>
</span>
<a-form-item field="tags" :label="t('system.orgTemplate.tags')">
<MsTagsInput v-model:model-value="tags" />
</a-form-item>
<!-- <span class="label"> {{ t('bugManagement.detail.tag') }}</span>-->
<!-- <span style="width: 200px">-->
<!-- <MsTag v-for="item of tags" :key="item"> {{ item }} </MsTag>-->
<!-- </span>-->
</div>
</div>
</template>
@ -166,7 +169,7 @@
import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
import MsTab from '@/components/pure/ms-tab/index.vue';
import type { MsPaginationI } from '@/components/pure/ms-table/type';
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
import { CommentInput } from '@/components/business/ms-comment';
import { CommentParams } from '@/components/business/ms-comment/types';
import MsDetailDrawer from '@/components/business/ms-detail-drawer/index.vue';

View File

@ -248,6 +248,8 @@
sortDirections: ['ascend', 'descend'],
sorter: true,
},
showInTable: true,
columnSelectorDisabled: true,
},
{
title: 'bugManagement.bugName',
@ -258,6 +260,8 @@
sortDirections: ['ascend', 'descend'],
sorter: true,
},
showInTable: true,
columnSelectorDisabled: true,
},
{
title: 'bugManagement.status',
@ -265,6 +269,7 @@
width: 84,
slotName: 'status',
showDrag: true,
showInTable: true,
},
{
title: 'bugManagement.handleMan',
@ -272,6 +277,7 @@
showTooltip: true,
width: 75,
showDrag: true,
showInTable: true,
},
{
title: 'bugManagement.numberOfCase',
@ -279,12 +285,14 @@
slotName: 'numberOfCase',
width: 80,
showDrag: true,
showInTable: true,
},
{
title: 'bugManagement.belongPlatform',
width: 135,
showDrag: true,
dataIndex: 'platform',
showInTable: true,
},
{
title: 'bugManagement.tag',
@ -292,6 +300,7 @@
isStringTag: true,
width: 200,
dataIndex: 'tags',
showInTable: true,
},
{
title: 'bugManagement.creator',
@ -303,6 +312,7 @@
sortDirections: ['ascend', 'descend'],
sorter: true,
},
showInTable: true,
},
{
title: 'bugManagement.createTime',
@ -313,6 +323,7 @@
sortDirections: ['ascend', 'descend'],
sorter: true,
},
showInTable: true,
},
{
title: 'bugManagement.updateUser',
@ -324,6 +335,7 @@
sortDirections: ['ascend', 'descend'],
sorter: true,
},
showInTable: true,
},
{
title: 'bugManagement.updateTime',
@ -334,6 +346,7 @@
sortDirections: ['ascend', 'descend'],
sorter: true,
},
showInTable: true,
},
{
title: 'common.operation',
@ -344,6 +357,9 @@
},
];
const customColumns = await getCustomFieldColumns();
customColumns.forEach((item) => {
item.showInTable = item.title === '严重程度';
});
await tableStore.initColumn(TableKeyEnum.BUG_MANAGEMENT, columns.concat(customColumns), 'drawer');
const { propsRes, propsEvent, setKeyword, setAdvanceFilter, setLoadListParams, setProps, resetSelector, loadList } =
@ -352,6 +368,7 @@
{
tableKey: TableKeyEnum.BUG_MANAGEMENT,
selectable: true,
showJumpMethod: true,
noDisable: false,
showSetting: true,
},

View File

@ -315,7 +315,7 @@
<script setup lang="ts">
import { ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { Message, TableChangeExtra, TableColumnData, TableData } from '@arco-design/web-vue';
import { Message, TableChangeExtra, TableData } from '@arco-design/web-vue';
import { CustomTypeMaps, MsAdvanceFilter } from '@/components/pure/ms-advance-filter';
import { FilterFormItem, FilterResult, FilterType } from '@/components/pure/ms-advance-filter/type';
@ -337,7 +337,6 @@
import AddDemandModal from './tabContent/tabDemand/addDemandModal.vue';
import ThirdDemandDrawer from './tabContent/tabDemand/thirdDemandDrawer.vue';
import TableFilter from './tableFilter.vue';
import TableFormChange from './tableFormChange.vue';
import {
batchAssociationDemand,
@ -370,7 +369,6 @@
DragCase,
} from '@/models/caseManagement/featureCase';
import type { TableQueryParams } from '@/models/common';
import { StatusType } from '@/enums/caseEnum';
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
import { ColumnEditTypeEnum, TableKeyEnum } from '@/enums/tableEnum';
@ -488,6 +486,7 @@
'showTooltip': true,
'ellipsis': true,
'showDrag': false,
'columnSelectorDisabled': true,
},
{
title: 'caseManagement.featureCase.tableColumnName',
@ -503,6 +502,7 @@
},
ellipsis: true,
showDrag: false,
columnSelectorDisabled: true,
},
{
title: 'caseManagement.featureCase.tableColumnLevel',
@ -821,6 +821,7 @@
showSetting: true,
heightUsed: 380,
enableDrag: true,
showSubdirectory: true,
},
(record) => {
return {
@ -1230,7 +1231,7 @@
...customFieldsColumns,
...columns.slice(columns.length - 1, columns.length),
];
await tableStore.initColumn(TableKeyEnum.CASE_MANAGEMENT_TABLE, fullColumns, 'drawer');
await tableStore.initColumn(TableKeyEnum.CASE_MANAGEMENT_TABLE, fullColumns, 'drawer', true);
}
//

View File

@ -457,7 +457,7 @@
},
];
const tableStore = useTableStore();
await tableStore.initColumn(TableKeyEnum.CASE_MANAGEMENT_REVIEW, columns, 'drawer');
await tableStore.initColumn(TableKeyEnum.CASE_MANAGEMENT_REVIEW, columns, 'drawer', true);
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable(
getReviewList,
{
@ -466,6 +466,7 @@
selectable: true,
showSelectAll: true,
heightUsed: 344,
showSubdirectory: true,
},
(item) => {
return {

View File

@ -597,7 +597,7 @@
},
];
const tableStore = useTableStore();
await tableStore.initColumn(TableKeyEnum.FILE_MANAGEMENT_FILE, columns, 'drawer');
await tableStore.initColumn(TableKeyEnum.FILE_MANAGEMENT_FILE, columns, 'drawer', true);
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector, resetPagination } = useTable(
getFileList,
{
@ -609,6 +609,7 @@
'PROJECT_FILE_MANAGEMENT:READ+DELETE',
]),
showSelectAll: true,
showSubdirectory: true,
},
(item) => {
return {