fix: 修复用例管理显示设置bug&任务中心table权限补充表格列调整

This commit is contained in:
xinxin.wu 2024-04-11 22:15:26 +08:00 committed by Craftsman
parent ecaed710c6
commit e2aaab073b
14 changed files with 449 additions and 319 deletions

View File

@ -62,8 +62,12 @@ export enum TableKeyEnum {
PROJECT_MANAGEMENT_ENV_ALL_PARAM_HEADER = 'projectManagementEnvAllParamHeader', PROJECT_MANAGEMENT_ENV_ALL_PARAM_HEADER = 'projectManagementEnvAllParamHeader',
PROJECT_MANAGEMENT_ENV_ALL_PARAM_VARIABLE = 'projectManagementEnvAllParamVariable', PROJECT_MANAGEMENT_ENV_ALL_PARAM_VARIABLE = 'projectManagementEnvAllParamVariable',
TEST_PLAN_ALL_TABLE = 'testPlanAllTable', TEST_PLAN_ALL_TABLE = 'testPlanAllTable',
TASK_API_CASE = 'taskCenterApiCase', TASK_API_CASE_SYSTEM = 'taskCenterApiCaseSystem',
TASK_SCHEDULE_TASK = 'taskCenterSchedule', TASK_API_CASE_ORGANIZATION = 'taskCenterApiCaseOrganization',
TASK_API_CASE_PROJECT = 'taskCenterApiCaseProject',
TASK_SCHEDULE_TASK_SYSTEM = 'taskCenterScheduleSystem',
TASK_SCHEDULE_TASK_ORGANIZATION = 'taskCenterScheduleOrganization',
TASK_SCHEDULE_TASK_PROJECT = 'taskCenterScheduleProject',
} }
// 具有特殊功能的列 // 具有特殊功能的列

View File

@ -1,11 +1,11 @@
// 模板展示字段icon // 模板展示字段icon
export enum TaskCenterEnum { export enum TaskCenterEnum {
API_CASE = 'API_CASE', // 接口用例 API_CASE = 'API_CASE', // 接口用例
API_SCENARIO = 'API_SCENARIO', // 接口场景 API_SCENARIO = 'API_SCENARIO', // 接口场景 API场景
UI_TEST = 'UI_TEST', // ui测试 UI_TEST = 'UI_TEST', // ui测试
LOAD_TEST = 'LOAD_TEST', // 性能测试 LOAD_TEST = 'LOAD_TEST', // 性能测试
TEST_PLAN = 'TEST_PLAN', // 测试计划 TEST_PLAN = 'TEST_PLAN', // 测试计划
// TEST_RESOURCE = 'TEST_RESOURCE', // 测试资源 TEST_RESOURCE = 'TEST_RESOURCE', // 测试资源
API_IMPORT = 'API_IMPORT', // API导入 API_IMPORT = 'API_IMPORT', // API导入
} }

View File

@ -224,8 +224,8 @@ export interface CaseModuleQueryParams extends TableQueryParams {
export interface TabItemType { export interface TabItemType {
key: string; key: string;
title: string; title: string;
enable: boolean; canHide: boolean;
total: number; isShow: boolean;
} }
// 需求 // 需求
@ -355,3 +355,8 @@ export interface DeleteDependencyParams {
caseId: string; caseId: string;
type: string; type: string;
} }
export interface ContentTabsMap {
tabList: TabItemType[];
backupTabList: TabItemType[];
}

View File

@ -1,4 +1,5 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import localforage from 'localforage';
import { import {
getCaseDefaultFields, getCaseDefaultFields,
@ -6,8 +7,9 @@ import {
getCaseModulesCounts, getCaseModulesCounts,
getRecycleModulesCounts, getRecycleModulesCounts,
} from '@/api/modules/case-management/featureCase'; } from '@/api/modules/case-management/featureCase';
import { isArraysEqualWithOrder } from '@/utils/equal';
import type { CaseModuleQueryParams, CustomAttributes, TabItemType } from '@/models/caseManagement/featureCase'; import type { ContentTabsMap, CustomAttributes, TabItemType } from '@/models/caseManagement/featureCase';
import { ModuleTreeNode, TableQueryParams } from '@/models/common'; import { ModuleTreeNode, TableQueryParams } from '@/models/common';
import useAppStore from '../app'; import useAppStore from '../app';
@ -20,7 +22,7 @@ const useFeatureCaseStore = defineStore('featureCase', {
modulesCount: Record<string, any>; // 用例树模块数量 modulesCount: Record<string, any>; // 用例树模块数量
recycleModulesCount: Record<string, any>; // 回收站模块数量 recycleModulesCount: Record<string, any>; // 回收站模块数量
operatingState: boolean; // 操作状态 operatingState: boolean; // 操作状态
tabSettingList: TabItemType[]; // 详情tab countMap: Record<string, any>;
activeTab: string; // 激活tab activeTab: string; // 激活tab
defaultFields: CustomAttributes[]; defaultFields: CustomAttributes[];
defaultCount: Record<string, any>; defaultCount: Record<string, any>;
@ -30,10 +32,19 @@ const useFeatureCaseStore = defineStore('featureCase', {
modulesCount: {}, modulesCount: {},
recycleModulesCount: {}, recycleModulesCount: {},
operatingState: false, operatingState: false,
tabSettingList: [],
activeTab: 'detail', activeTab: 'detail',
defaultFields: [], defaultFields: [],
defaultCount: {}, defaultCount: {},
countMap: {
case: '0',
dependency: '0',
caseReview: '0',
testPlan: '0',
bug: '0',
requirement: '0',
comments: '0',
changeHistory: '0',
},
}), }),
actions: { actions: {
// 设置选择moduleId // 设置选择moduleId
@ -51,7 +62,6 @@ const useFeatureCaseStore = defineStore('featureCase', {
// 获取模块数量 // 获取模块数量
async getCaseModulesCount(params: TableQueryParams) { async getCaseModulesCount(params: TableQueryParams) {
try { try {
// this.modulesCount = {};
this.modulesCount = await getCaseModulesCounts(params); this.modulesCount = await getCaseModulesCounts(params);
} catch (error) { } catch (error) {
console.log(error); console.log(error);
@ -65,40 +75,17 @@ const useFeatureCaseStore = defineStore('featureCase', {
console.log(error); console.log(error);
} }
}, },
// 设置菜单
setTab(list: TabItemType[]) {
this.tabSettingList = list;
},
// 获取显示的tab
getTab() {
return this.tabSettingList.filter((item) => item.enable);
},
// 设置激活tab // 设置激活tab
setActiveTab(active: string | number) { setActiveTab(active: string | number) {
this.activeTab = active as string; this.activeTab = active as string;
}, },
// 设置菜单模块列表数量 // 设置菜单模块列表数量
setListCount(type: string, count = 0) { setListCount(type: string, count = 0) {
this.tabSettingList = this.tabSettingList.map((item: any) => { this.countMap[type] = count;
if (type === item.key) {
return {
...item,
total: count,
};
}
return {
...item,
};
});
}, },
// 初始化count // 初始化count
initCountMap(countMap: Record<string, any>) { initCountMap(countMap: Record<string, any>) {
this.tabSettingList = this.tabSettingList.map((item) => { this.countMap = { ...countMap };
return {
...item,
total: countMap[item.key] || 0,
};
});
}, },
// 获取默认模版 // 获取默认模版
async getDefaultTemplate() { async getDefaultTemplate() {
@ -114,7 +101,6 @@ const useFeatureCaseStore = defineStore('featureCase', {
getSystemCaseLevelFields() { getSystemCaseLevelFields() {
return this.defaultFields.find((item: any) => item.internal && item.fieldName === '用例等级')?.options || []; return this.defaultFields.find((item: any) => item.internal && item.fieldName === '用例等级')?.options || [];
}, },
// 获取详情 // 获取详情
async getCaseCounts(caseId: string) { async getCaseCounts(caseId: string) {
try { try {
@ -144,6 +130,43 @@ const useFeatureCaseStore = defineStore('featureCase', {
console.log(error); console.log(error);
} }
}, },
async initContentTabList(arr: TabItemType[]) {
try {
const tabsMap = await localforage.getItem<ContentTabsMap>('caseTabsMap');
if (tabsMap) {
const { backupTabList } = tabsMap;
const isEqual = isArraysEqualWithOrder<TabItemType>(backupTabList, arr);
if (!isEqual) {
tabsMap.tabList = arr;
tabsMap.backupTabList = arr;
await localforage.setItem('caseTabsMap', tabsMap);
}
} else {
await localforage.setItem('caseTabsMap', { tabList: arr, backupTabList: arr });
}
} catch (e) {
console.log(e);
}
},
async getContentTabList() {
try {
const tabsMap = await localforage.getItem<ContentTabsMap>('caseTabsMap');
if (tabsMap) {
return tabsMap.tabList;
}
return [];
} catch (e) {
console.log(e);
}
},
async setContentTabList(arr: TabItemType[]) {
const tabsMap = await localforage.getItem<ContentTabsMap>('caseTabsMap');
if (tabsMap) {
const tmpArrList = JSON.parse(JSON.stringify(arr));
tabsMap.tabList = tmpArrList;
await localforage.setItem('caseTabsMap', tabsMap);
}
},
}, },
}); });

View File

@ -100,14 +100,14 @@
<div class="leftWrapper h-full"> <div class="leftWrapper h-full">
<div class="header h-[50px]"> <div class="header h-[50px]">
<a-menu mode="horizontal" :default-selected-keys="[activeTab || 'detail']" @menu-item-click="clickMenu"> <a-menu mode="horizontal" :default-selected-keys="[activeTab || 'detail']" @menu-item-click="clickMenu">
<a-menu-item key="detail">{{ t('caseManagement.featureCase.detail') }} </a-menu-item>
<a-menu-item v-for="tab of tabSetting" :key="tab.key"> <a-menu-item v-for="tab of tabSetting" :key="tab.key">
<div class="flex items-center"> <div class="flex items-center">
<span>{{ t(tab.title) }}</span> <span>{{ t(tab.title) }}</span>
<a-badge <a-badge
v-if="getTotal(tab.key)"
class="ml-1" class="ml-1"
:class="activeTab === tab.key ? 'active' : ''" :class="activeTab === tab.key ? 'active' : ''"
:text="getTotal(tab.total)" :text="getTotal(tab.key)"
/> </div /> </div
></a-menu-item> ></a-menu-item>
<a-menu-item key="setting"> <a-menu-item key="setting">
@ -252,7 +252,7 @@
</div> </div>
</template> </template>
</MsDetailDrawer> </MsDetailDrawer>
<SettingDrawer ref="settingDrawerRef" v-model:visible="showSettingDrawer" /> <SettingDrawer ref="settingDrawerRef" v-model:visible="showSettingDrawer" @init-data="initTab" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -282,6 +282,7 @@
getCaseDetail, getCaseDetail,
getCaseModuleTree, getCaseModuleTree,
} from '@/api/modules/case-management/featureCase'; } from '@/api/modules/case-management/featureCase';
import { postTabletList } from '@/api/modules/project-management/menuManagement';
import { PreviewEditorImageUrl } from '@/api/requrls/case-management/featureCase'; import { PreviewEditorImageUrl } from '@/api/requrls/case-management/featureCase';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
@ -339,11 +340,12 @@
showSettingDrawer.value = true; showSettingDrawer.value = true;
} }
const tabSettingList = computed(() => { // const tabSettingList = computed(() => {
return featureCaseStore.tabSettingList; // return featureCaseStore.tabSettingList;
}); // });
const tabSetting = ref<TabItemType[]>([...tabSettingList.value]); // const tabSetting = ref<TabItemType[]>([...tabSettingList.value]);
const tabSetting = ref<TabItemType[]>([]);
const activeTab = ref<string | number>('detail'); const activeTab = ref<string | number>('detail');
function clickMenu(key: string | number) { function clickMenu(key: string | number) {
activeTab.value = key; activeTab.value = key;
@ -565,21 +567,14 @@
tabDetailRef.value.handleOK(); tabDetailRef.value.handleOK();
} }
function getTotal(total: number): string { function getTotal(key: string) {
if (total === 0) { switch (key) {
return '0'; case 'detail':
return '';
default:
break;
} }
if (total && total !== 0) { return featureCaseStore.countMap[key] > 99 ? '99+' : `${featureCaseStore.countMap[key]}` || '';
if (total <= 99) {
return String(total);
}
if (total > 99) {
return `${total}+`;
}
}
return `${total}+`;
} }
watch( watch(
@ -610,14 +605,6 @@
} }
); );
watch(
() => tabSettingList.value,
() => {
tabSetting.value = featureCaseStore.getTab();
},
{ deep: true, immediate: true }
);
const content = ref(''); const content = ref('');
const commentRef = ref(); const commentRef = ref();
const isActive = ref<boolean>(false); const isActive = ref<boolean>(false);
@ -652,9 +639,83 @@
tabDetailRef.value.handleOK(); tabDetailRef.value.handleOK();
}, 300); }, 300);
onMounted(() => { const tabDefaultSettingList: TabItemType[] = [
settingDrawerRef.value.getTabModule(); {
key: 'detail',
title: 'caseManagement.featureCase.detail',
canHide: false,
isShow: true,
},
{
key: 'case',
title: 'caseManagement.featureCase.case',
canHide: true,
isShow: true,
},
{
key: 'dependency',
title: 'caseManagement.featureCase.dependency',
canHide: true,
isShow: true,
},
{
key: 'caseReview',
title: 'caseManagement.featureCase.caseReview',
canHide: true,
isShow: true,
},
{
key: 'comments',
title: 'caseManagement.featureCase.comments',
canHide: true,
isShow: true,
},
{
key: 'changeHistory',
title: 'caseManagement.featureCase.changeHistory',
canHide: true,
isShow: true,
},
];
let buggerTab: TabItemType[] = [];
const moduleTabMap: Record<string, TabItemType[]> = {
bugManagement: [
{
key: 'requirement',
title: 'caseManagement.featureCase.requirement',
canHide: true,
isShow: true,
},
{
key: 'bug',
title: 'caseManagement.featureCase.bug',
canHide: true,
isShow: true,
},
],
};
let newTabDefaultSettingList: TabItemType[] = [];
/**
* 获取开启的模块
*/
async function getTabModule() {
buggerTab = [];
const result = await postTabletList({ projectId: currentProjectId.value });
const enableModuleArr = result.filter((item: any) => item.module === 'bugManagement');
enableModuleArr.forEach((item) => {
if (item.module === 'bugManagement') {
buggerTab.push(...moduleTabMap[item.module]);
}
}); });
newTabDefaultSettingList = [...tabDefaultSettingList.slice(0, 2), ...buggerTab, ...tabDefaultSettingList.slice(2)];
}
await getTabModule();
featureCaseStore.initContentTabList(newTabDefaultSettingList);
tabSetting.value = ((await featureCaseStore.getContentTabList()) || []).filter((item) => item.isShow);
async function handleUploadImage(file: File) { async function handleUploadImage(file: File) {
const { data } = await editorUploadFile({ const { data } = await editorUploadFile({
@ -662,6 +723,13 @@
}); });
return data; return data;
} }
const initTab = async () => {
showSettingDrawer.value = false;
const tmpArr = (await featureCaseStore.getContentTabList()) || [];
tabSetting.value = tmpArr.filter((item) => item.isShow);
activeTab.value = 'detail';
};
</script> </script>
<style scoped lang="less"> <style scoped lang="less">

View File

@ -6,9 +6,10 @@
:width="480" :width="480"
unmount-on-close unmount-on-close
:footer="false" :footer="false"
class="tab-setting-drawer" class="column-drawer"
@cancel="handleCancel"
> >
<div class="header mb-1 flex h-[22px] items-center justify-between"> <div class="header mb-2 flex h-[22px] items-center justify-between">
<div class="flex items-center text-[var(--color-text-4)]" <div class="flex items-center text-[var(--color-text-4)]"
>{{ t('caseManagement.featureCase.detailDisplaySetting') }} >{{ t('caseManagement.featureCase.detailDisplaySetting') }}
@ -23,11 +24,24 @@
/></span> /></span>
</a-tooltip> </a-tooltip>
</div> </div>
<div class="cursor-pointer text-[rgb(var(--primary-5))]" @click="setDefault" <MsButton v-if="hasChange" class="cursor-pointer text-[rgb(var(--primary-5))]" @click="handleReset"
>{{ t('caseManagement.featureCase.recoverDefault') }} >{{ t('caseManagement.featureCase.recoverDefault') }}
</MsButton>
</div>
<div class="ms-table-column-seletor">
<div class="flex-col">
<div v-for="item in nonCloseColumn" :key="item.key" class="column-item">
<div>{{ t(item.title) }}</div>
<a-switch v-model="item.isShow" disabled size="small" type="line" @change="handleSwitchChange" />
</div> </div>
</div> </div>
<div> <a-divider orientation="center" class="non-sort"
><span class="one-line-text text-xs text-[var(--color-text-4)]">{{
t('project.environmental.nonClose')
}}</span></a-divider
>
<!-- <div>
<div class="itemTab"> <div class="itemTab">
<span>{{ t('caseManagement.featureCase.detail') }}</span> <span>{{ t('caseManagement.featureCase.detail') }}</span>
<a-switch v-model="detailEnable" size="small" :disabled="true" type="line" /> <a-switch v-model="detailEnable" size="small" :disabled="true" type="line" />
@ -37,150 +51,56 @@
t('caseManagement.featureCase.nonClosableTab') t('caseManagement.featureCase.nonClosableTab')
}}</span></a-divider }}</span></a-divider
> >
<div v-for="item of tabSettingList" :key="item.key" class="itemTab"> </div> -->
<span>{{ t(item.title) }}</span> <VueDraggable
<a-switch v-model="item.enable" size="small" type="line" /> v-model="couldCloseColumn"
class="ms-assertion-body-left"
ghost-class="ghost"
handle=".column-drag-item"
>
<div v-for="element in couldCloseColumn" :key="element.key" class="column-drag-item">
<div class="flex w-[90%] items-center">
<span class="ml-[8px]">{{ t(element.title) }}</span>
</div> </div>
<a-switch v-model="element.isShow" size="small" type="line" @change="handleSwitchChange" />
</div>
</VueDraggable>
</div> </div>
</MsDrawer> </MsDrawer>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { ref } from 'vue';
import { VueDraggable } from 'vue-draggable-plus';
import MsButton from '@/components/pure/ms-button/index.vue';
import MsDrawer from '@/components/pure/ms-drawer/index.vue'; import MsDrawer from '@/components/pure/ms-drawer/index.vue';
import { postTabletList } from '@/api/modules/project-management/menuManagement';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import { useAppStore } from '@/store';
import useFeatureCaseStore from '@/store/modules/case/featureCase'; import useFeatureCaseStore from '@/store/modules/case/featureCase';
import useLicenseStore from '@/store/modules/setting/license';
import type { TabItemType } from '@/models/caseManagement/featureCase'; import type { TabItemType } from '@/models/caseManagement/featureCase';
const licenseStore = useLicenseStore();
const { t } = useI18n(); const { t } = useI18n();
const featureCaseStore = useFeatureCaseStore(); const featureCaseStore = useFeatureCaseStore();
const appStore = useAppStore();
const currentProjectId = computed(() => appStore.currentProjectId);
const props = defineProps<{ const props = defineProps<{
visible: boolean; visible: boolean;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:visible', val: boolean): void; (e: 'update:visible', val: boolean): void;
(e: 'initData'): void;
}>(); }>();
const showSettingVisible = ref<boolean>(false); const showSettingVisible = ref<boolean>(false);
const detailEnable = ref<boolean>(true);
const moduleTab = ref<Record<string, TabItemType[]>>({ const nonCloseColumn = ref<TabItemType[]>([]);
bugManagement: [
{
key: 'requirement',
title: 'caseManagement.featureCase.requirement',
enable: true,
total: 0,
},
{
key: 'bug',
title: 'caseManagement.featureCase.bug',
enable: true,
total: 0,
},
],
// testPlan: [
// {
// key: 'testPlan',
// title: 'caseManagement.featureCase.testPlan',
// enable: true,
// },
// ],
});
let buggerTab: TabItemType[] = []; const couldCloseColumn = ref<TabItemType[]>([]);
// let testPlanTab: TabItemType[] = [];
function getTabList() { const hasChange = ref(false);
return [
{
key: 'changeHistory',
title: 'caseManagement.featureCase.changeHistory',
enable: true,
total: 0,
},
];
}
const tabDefaultSettingList = ref<TabItemType[]>([
{
key: 'case',
title: 'caseManagement.featureCase.case',
enable: true,
total: 0,
},
{
key: 'dependency',
title: 'caseManagement.featureCase.dependency',
enable: true,
total: 0,
},
{
key: 'caseReview',
title: 'caseManagement.featureCase.caseReview',
enable: true,
total: 0,
},
{
key: 'comments',
title: 'caseManagement.featureCase.comments',
enable: true,
total: 0,
},
// TOTO Xpack
...getTabList(),
]);
async function getTabModule() {
buggerTab = [];
// testPlanTab = [];
const result = await postTabletList({ projectId: currentProjectId.value });
// TODO
// const enableModuleArr = result.filter((item: any) => item.module === 'testPlan' || item.module === 'bugManagement');
const enableModuleArr = result.filter((item: any) => item.module === 'bugManagement');
enableModuleArr.forEach((item) => {
if (item.module === 'bugManagement') {
buggerTab.push(...moduleTab.value[item.module]);
}
// else if (item.module === 'testPlan') {
// testPlanTab.push(...moduleTab.value[item.module]);
// }
});
const newTabDefaultSettingList = [
tabDefaultSettingList.value[0],
...buggerTab,
...tabDefaultSettingList.value.slice(1, -2),
// ...testPlanTab,
tabDefaultSettingList.value[tabDefaultSettingList.value.length - 2],
tabDefaultSettingList.value[tabDefaultSettingList.value.length - 1],
];
featureCaseStore.setTab(newTabDefaultSettingList);
}
const tabList = computed(() => featureCaseStore.tabSettingList);
const tabSettingList = ref([...tabList.value]);
function setDefault() {
tabSettingList.value = tabSettingList.value.map((item: any) => {
return {
...item,
enable: true,
};
});
}
watch( watch(
() => props.visible, () => props.visible,
@ -196,18 +116,28 @@
} }
); );
watch( const handleCancel = async () => {
() => tabSettingList.value, await featureCaseStore.setContentTabList([...nonCloseColumn.value, ...couldCloseColumn.value]);
(val) => { emit('initData');
featureCaseStore.setTab(val as TabItemType[]); };
},
{
deep: true,
}
);
defineExpose({ const loadTab = async () => {
getTabModule, const res = (await featureCaseStore.getContentTabList()) || [];
nonCloseColumn.value = res.filter((item) => !item.canHide && item.key !== 'SETTING');
couldCloseColumn.value = res.filter((item) => item.canHide);
};
const handleReset = () => {
loadTab();
hasChange.value = false;
};
const handleSwitchChange = () => {
hasChange.value = true;
};
onBeforeMount(() => {
loadTab();
}); });
</script> </script>
@ -219,7 +149,52 @@
</style> </style>
<style> <style>
.tab-setting-drawer .ms-drawer-body-scrollbar { :deep(.arco-divider-horizontal) {
min-width: auto !important; margin: 16px 0;
border-bottom-color: var(--color-text-n8);
}
:deep(.arco-divider-text) {
padding: 0 8px;
}
.mode-button {
display: flex;
flex-flow: row nowrap;
align-items: center;
.active-color {
color: rgba(var(--primary-5));
}
.mode-button-title {
margin-left: 4px;
}
}
.column-item {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
padding: 8px 16px;
&:hover {
border-radius: 6px;
background: var(--color-text-n9);
}
}
.column-drag-item {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
padding: 8px 12px;
&:hover {
border-radius: 6px;
background-color: var(--color-text-n9);
}
}
.ghost {
border: 1px dashed rgba(var(--primary-5));
background-color: rgba(var(--primary-1));
}
.non-sort {
font-size: 12px;
line-height: 16px;
} }
</style> </style>

View File

@ -112,13 +112,14 @@
title: 'caseManagement.featureCase.changeType', title: 'caseManagement.featureCase.changeType',
slotName: 'type', slotName: 'type',
dataIndex: 'type', dataIndex: 'type',
width: 200, width: 100,
}, },
{ {
title: 'caseManagement.featureCase.operator', title: 'caseManagement.featureCase.operator',
dataIndex: 'createUserName', dataIndex: 'createUserName',
slotName: 'createUserName', slotName: 'createUserName',
width: 150, width: 150,
showTooltip: true,
}, },
{ {
title: 'caseManagement.featureCase.tableColumnUpdateTime', title: 'caseManagement.featureCase.tableColumnUpdateTime',

View File

@ -44,15 +44,15 @@
</div> </div>
</template> </template>
<template v-else> <template v-else>
<span v-permission="['PROJECT_APPLICATION_API:UPDATE']" class="flex flex-row"> <span v-permission="['PROJECT_APPLICATION_API:UPDATE']" class="flex flex-row items-center">
<MsButton class="!mr-0" @click="showAddRule(record)">{{ t('common.edit') }}</MsButton> <MsButton class="!mr-0" @click="showAddRule(record)">{{ t('common.edit') }}</MsButton>
<a-divider direction="vertical" /> <a-divider class="h-[16px]" direction="vertical" />
</span> </span>
<span v-permission="['PROJECT_APPLICATION_API:UPDATE']" class="flex flex-row"> <span v-permission="['PROJECT_APPLICATION_API:UPDATE']" class="flex flex-row items-center">
<MsButton class="!mr-0" @click="handleEnableOrDisableProject(record.id, false)">{{ <MsButton class="!mr-0" @click="handleEnableOrDisableProject(record.id, false)">{{
t('common.disable') t('common.disable')
}}</MsButton> }}</MsButton>
<a-divider direction="vertical" /> <a-divider class="h-[16px]" direction="vertical" />
</span> </span>
<MsTableMoreAction <MsTableMoreAction
v-permission="['PROJECT_APPLICATION_API:UPDATE']" v-permission="['PROJECT_APPLICATION_API:UPDATE']"
@ -66,7 +66,7 @@
</MsCard> </MsCard>
<MsDrawer <MsDrawer
v-model:visible="addVisible" v-model:visible="addVisible"
:title="t('project.menu.addFalseAlertRules')" :title="ruleFormMode === 'create' ? t('project.menu.addFalseAlertRules') : t('project.menu.updateFalseAlertRules')"
:destroy-on-close="true" :destroy-on-close="true"
:closable="true" :closable="true"
:mask-closable="false" :mask-closable="false"
@ -171,8 +171,7 @@
const relation = relationOptions.value.find((item) => item.value === record.relation)?.label; const relation = relationOptions.value.find((item) => item.value === record.relation)?.label;
return `${header} ${relation} ${record.expression}`; return `${header} ${relation} ${record.expression}`;
}; };
const initBatchFormModels: FormItemModel[] = [
const batchFormModels: Ref<FormItemModel[]> = ref([
{ {
filed: 'name', filed: 'name',
type: 'input', type: 'input',
@ -214,7 +213,9 @@
}, },
], ],
}, },
]); ];
const batchFormModels: Ref<FormItemModel[]> = ref([...initBatchFormModels]);
const rulesColumn: MsTableColumn = [ const rulesColumn: MsTableColumn = [
{ {
@ -411,6 +412,8 @@
if (shouldSearch) { if (shouldSearch) {
fetchData(); fetchData();
} }
batchFormModels.value = [...initBatchFormModels];
currentList.value = [];
addVisible.value = false; addVisible.value = false;
}; };

View File

@ -132,7 +132,7 @@
emit('cancel', shouldSearch); emit('cancel', shouldSearch);
sessionStorage.removeItem('platformKey'); sessionStorage.removeItem('platformKey');
form.PLATFORM_KEY = ''; form.PLATFORM_KEY = '';
fApi.value.clearValidateState(); fApi.value?.clearValidateState();
}; };
const handlePlatformChange = async (value: SelectValue) => { const handlePlatformChange = async (value: SelectValue) => {
platformRules.value = []; platformRules.value = [];

View File

@ -68,6 +68,7 @@ export default {
'project.menu.preview': 'Preview', 'project.menu.preview': 'Preview',
'project.menu.pleaseInputJiraKey': 'Please enter JIRA project key', 'project.menu.pleaseInputJiraKey': 'Please enter JIRA project key',
'project.menu.addFalseAlertRules': 'Add False Alert Rules', 'project.menu.addFalseAlertRules': 'Add False Alert Rules',
'project.menu.updateFalseAlertRules': 'update False Alert Rules',
'project.menu.nameSearch': 'Search by Name', 'project.menu.nameSearch': 'Search by Name',
// Sync defects // Sync defects
'project.menu.defect.enableTip': 'project.menu.defect.enableTip':

View File

@ -63,6 +63,7 @@ export default {
'project.menu.preview': '预览', 'project.menu.preview': '预览',
'project.menu.pleaseInputJiraKey': '请输入 JIRA 项目 key', 'project.menu.pleaseInputJiraKey': '请输入 JIRA 项目 key',
'project.menu.addFalseAlertRules': '新增误报规则', 'project.menu.addFalseAlertRules': '新增误报规则',
'project.menu.updateFalseAlertRules': '更新误报规则',
'project.menu.nameSearch': '通过名称搜索', 'project.menu.nameSearch': '通过名称搜索',
// 同步缺陷 // 同步缺陷
'project.menu.defect.enableTip': '开启:平台创建的缺陷同步至第三方项目管理平台', 'project.menu.defect.enableTip': '开启:平台创建的缺陷同步至第三方项目管理平台',

View File

@ -24,18 +24,20 @@
> >
<template #resourceNum="{ record }"> <template #resourceNum="{ record }">
<div <div
v-if="!record.integrated && hasAnyPermission(permissionsMap[props.group][props.moduleType].jump)" v-if="!record.integrated"
type="text" type="text"
class="one-line-text flex w-full text-[rgb(var(--primary-5))]" class="one-line-text flex w-full"
:class="[hasJumpPermission ? 'text-[rgb(var(--primary-5))]' : '']"
@click="showDetail(record.resourceId)" @click="showDetail(record.resourceId)"
>{{ record.resourceNum }} >{{ record.resourceNum }}
</div> </div>
</template> </template>
<template #resourceName="{ record }"> <template #resourceName="{ record }">
<div <div
v-if="!record.integrated && hasAnyPermission(permissionsMap[props.group][props.moduleType].jump)" v-if="!record.integrated"
type="text" type="text"
class="one-line-text flex w-full text-[rgb(var(--primary-5))]" class="one-line-text flex max-w-[300px]"
:class="[hasJumpPermission ? 'text-[rgb(var(--primary-5))]' : '']"
@click="showDetail(record.resourceId)" @click="showDetail(record.resourceId)"
>{{ record.resourceName }} >{{ record.resourceName }}
</div> </div>
@ -171,7 +173,7 @@
import { TableKeyEnum } from '@/enums/tableEnum'; import { TableKeyEnum } from '@/enums/tableEnum';
import { ExecutionMethodsLabel, TaskCenterEnum } from '@/enums/taskCenter'; import { ExecutionMethodsLabel, TaskCenterEnum } from '@/enums/taskCenter';
import { TaskStatus } from './utils'; import { ordAndProjectColumn, TaskStatus } from './utils';
const { openNewPage } = useOpenNewPage(); const { openNewPage } = useOpenNewPage();
const tableStore = useTableStore(); const tableStore = useTableStore();
@ -243,6 +245,8 @@
batchStop: batchStopRealProjectApi, batchStop: batchStopRealProjectApi,
}, },
}); });
const hasJumpPermission = computed(() => hasAnyPermission(permissionsMap[props.group][props.moduleType].jump));
const hasOperationPermission = computed(() => hasAnyPermission(permissionsMap[props.group][props.moduleType].stop));
const columns: MsTableColumn = [ const columns: MsTableColumn = [
{ {
@ -267,24 +271,6 @@
showInTable: true, showInTable: true,
columnSelectorDisabled: true, columnSelectorDisabled: true,
}, },
{
title: 'project.belongProject',
dataIndex: 'projectName',
slotName: 'projectName',
showTooltip: true,
showDrag: true,
width: 200,
showInTable: true,
},
{
title: 'project.belongOrganization',
dataIndex: 'organizationName',
slotName: 'organizationName',
showTooltip: true,
showDrag: true,
width: 200,
showInTable: true,
},
{ {
title: 'project.taskCenter.executionResult', title: 'project.taskCenter.executionResult',
dataIndex: 'status', dataIndex: 'status',
@ -295,7 +281,7 @@
sorter: true, sorter: true,
}, },
showInTable: true, showInTable: true,
width: 150, width: 200,
showDrag: true, showDrag: true,
}, },
{ {
@ -336,15 +322,30 @@
title: 'common.operation', title: 'common.operation',
slotName: 'operation', slotName: 'operation',
dataIndex: 'operation', dataIndex: 'operation',
width: 180,
fixed: 'right', fixed: 'right',
width: hasOperationPermission.value ? 180 : 50,
}, },
]; ];
const groupColumnsMap = {
system: {
key: TableKeyEnum.TASK_API_CASE_SYSTEM,
columns: [...ordAndProjectColumn, ...columns],
},
organization: {
key: TableKeyEnum.TASK_API_CASE_ORGANIZATION,
columns: [...ordAndProjectColumn.slice(-1), ...columns],
},
project: {
key: TableKeyEnum.TASK_API_CASE_PROJECT,
columns,
},
};
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable( const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable(
loadRealMap.value[props.group].list, loadRealMap.value[props.group].list,
{ {
tableKey: TableKeyEnum.TASK_API_CASE, tableKey: groupColumnsMap[props.group].key,
scroll: { scroll: {
x: 1400, x: 1400,
}, },
@ -547,6 +548,9 @@
* 跳转接口用例详情 * 跳转接口用例详情
*/ */
function showDetail(id: string) { function showDetail(id: string) {
if (!hasJumpPermission.value) {
return;
}
if (props.moduleType === 'API_CASE') { if (props.moduleType === 'API_CASE') {
openNewPage(RouteEnum.API_TEST_MANAGEMENT, { openNewPage(RouteEnum.API_TEST_MANAGEMENT, {
cId: id, cId: id,
@ -560,7 +564,7 @@
} }
onMounted(async () => { onMounted(async () => {
await tableStore.initColumn(TableKeyEnum.TASK_API_CASE, columns, 'drawer', true); await tableStore.initColumn(groupColumnsMap[props.group].key, groupColumnsMap[props.group].columns, 'drawer', true);
}); });
</script> </script>

View File

@ -27,24 +27,20 @@
> >
<template #resourceNum="{ record }"> <template #resourceNum="{ record }">
<div <div
v-if=" v-if="props.moduleType === TaskCenterEnum.API_SCENARIO"
props.moduleType === TaskCenterEnum.API_SCENARIO &&
hasAnyPermission(permissionsMap[props.group][props.moduleType].jump)
"
type="text" type="text"
class="one-line-text flex w-full text-[rgb(var(--primary-5))]" class="one-line-text flex w-full"
:class="[hasJumpPermission ? 'text-[rgb(var(--primary-5))]' : '']"
@click="showDetail(record.resourceId)" @click="showDetail(record.resourceId)"
>{{ record.resourceNum }} >{{ record.resourceNum }}
</div> </div>
</template> </template>
<template #resourceName="{ record }"> <template #resourceName="{ record }">
<div <div
v-if=" v-if="props.moduleType === TaskCenterEnum.API_SCENARIO"
props.moduleType === TaskCenterEnum.API_SCENARIO &&
hasAnyPermission(permissionsMap[props.group][props.moduleType].jump)
"
type="text" type="text"
class="one-line-text flex w-full text-[rgb(var(--primary-5))]" class="one-line-text flex max-w-[300px]"
:class="[hasJumpPermission ? 'text-[rgb(var(--primary-5))]' : '']"
@click="showDetail(record.resourceId)" @click="showDetail(record.resourceId)"
>{{ record.resourceName }} >{{ record.resourceName }}
</div> </div>
@ -136,7 +132,7 @@
import { TableKeyEnum } from '@/enums/tableEnum'; import { TableKeyEnum } from '@/enums/tableEnum';
import { TaskCenterEnum } from '@/enums/taskCenter'; import { TaskCenterEnum } from '@/enums/taskCenter';
import { resourceTypeMap } from './utils'; import { ordAndProjectColumn, resourceTypeMap } from './utils';
const { openNewPage } = useOpenNewPage(); const { openNewPage } = useOpenNewPage();
@ -151,74 +147,7 @@
}>(); }>();
const keyword = ref<string>(''); const keyword = ref<string>('');
const columns: MsTableColumn = [
{
title: 'project.taskCenter.resourceID',
dataIndex: 'resourceNum',
slotName: 'resourceNum',
width: 140,
showInTable: true,
showTooltip: true,
showDrag: false,
columnSelectorDisabled: true,
},
{
title: 'project.taskCenter.resourceName',
slotName: 'resourceName',
dataIndex: 'resourceName',
width: 200,
showDrag: false,
showTooltip: true,
columnSelectorDisabled: true,
showInTable: true,
},
{
title: 'project.taskCenter.operationRule',
dataIndex: 'value',
slotName: 'value',
showInTable: true,
width: 300,
showDrag: true,
showTooltip: true,
},
{
title: 'project.taskCenter.operator',
slotName: 'createUserName',
dataIndex: 'createUserName',
showInTable: true,
width: 200,
showDrag: true,
showTooltip: true,
},
{
title: 'project.taskCenter.operating',
slotName: 'createTime',
dataIndex: 'createTime',
showInTable: true,
width: 200,
showDrag: true,
},
{
title: 'project.taskCenter.nextExecutionTime',
slotName: 'nextTime',
dataIndex: 'nextTime',
showInTable: true,
width: 200,
showDrag: true,
sortable: {
sortDirections: ['ascend', 'descend'],
sorter: true,
},
},
{
title: 'common.operation',
slotName: 'operation',
dataIndex: 'operation',
width: 180,
fixed: 'right',
showDrag: false,
},
];
const syncFrequencyOptions = [ const syncFrequencyOptions = [
{ label: t('apiTestManagement.timeTaskHour'), value: '0 0 0/1 * * ?' }, { label: t('apiTestManagement.timeTaskHour'), value: '0 0 0/1 * * ?' },
{ label: t('apiTestManagement.timeTaskSixHour'), value: '0 0 0/6 * * ?' }, { label: t('apiTestManagement.timeTaskSixHour'), value: '0 0 0/6 * * ?' },
@ -282,11 +211,102 @@
}, },
}, },
}; };
const hasOperationPermission = computed(() =>
hasAnyPermission([...permissionsMap[props.group][props.moduleType].edit])
);
const columns: MsTableColumn = [
{
title: 'project.taskCenter.resourceID',
dataIndex: 'resourceNum',
slotName: 'resourceNum',
width: 140,
showInTable: true,
showTooltip: true,
showDrag: false,
sortIndex: 1,
columnSelectorDisabled: true,
fixed: 'left',
},
{
title: 'project.taskCenter.resourceName',
slotName: 'resourceName',
dataIndex: 'resourceName',
width: 300,
showDrag: false,
showTooltip: true,
sortIndex: 2,
columnSelectorDisabled: true,
showInTable: true,
},
{
title: 'project.taskCenter.operationRule',
dataIndex: 'value',
slotName: 'value',
showInTable: true,
width: 300,
showDrag: true,
showTooltip: true,
},
{
title: 'project.taskCenter.operator',
slotName: 'createUserName',
dataIndex: 'createUserName',
showInTable: true,
width: 200,
showDrag: true,
showTooltip: true,
},
{
title: 'project.taskCenter.operating',
slotName: 'createTime',
dataIndex: 'createTime',
showInTable: true,
width: 200,
showDrag: true,
},
{
title: 'project.taskCenter.nextExecutionTime',
slotName: 'nextTime',
dataIndex: 'nextTime',
showInTable: true,
width: 200,
showDrag: true,
sortable: {
sortDirections: ['ascend', 'descend'],
sorter: true,
},
},
{
title: 'common.operation',
slotName: 'operation',
dataIndex: 'operation',
fixed: 'right',
showDrag: false,
width: hasOperationPermission.value ? 180 : 50,
},
];
const groupColumnsMap = {
system: {
key: TableKeyEnum.TASK_SCHEDULE_TASK_SYSTEM,
columns: [...ordAndProjectColumn, ...columns],
},
organization: {
key: TableKeyEnum.TASK_SCHEDULE_TASK_ORGANIZATION,
columns: [...ordAndProjectColumn.slice(-1), ...columns],
},
project: {
key: TableKeyEnum.TASK_SCHEDULE_TASK_PROJECT,
columns,
},
};
const hasJumpPermission = computed(() => hasAnyPermission(permissionsMap[props.group][props.moduleType].jump));
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable( const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable(
loadRealMap.value[props.group].list, loadRealMap.value[props.group].list,
{ {
tableKey: TableKeyEnum.TASK_SCHEDULE_TASK, tableKey: groupColumnsMap[props.group].key,
scroll: { scroll: {
x: 1200, x: 1200,
}, },
@ -388,6 +408,9 @@
*/ */
function showDetail(id: string) { function showDetail(id: string) {
if (!hasJumpPermission.value) {
return;
}
if (props.moduleType === 'API_SCENARIO') { if (props.moduleType === 'API_SCENARIO') {
openNewPage(RouteEnum.API_TEST_SCENARIO, { openNewPage(RouteEnum.API_TEST_SCENARIO, {
id, id,
@ -489,12 +512,11 @@
if (val) { if (val) {
resetSelector(); resetSelector();
initData(); initData();
console.log(permissionsMap[props.group][props.moduleType].edit);
} }
} }
); );
onMounted(async () => { onMounted(async () => {
await tableStore.initColumn(TableKeyEnum.TASK_SCHEDULE_TASK, columns, 'drawer', true); await tableStore.initColumn(groupColumnsMap[props.group].key, groupColumnsMap[props.group].columns, 'drawer', true);
}); });
</script> </script>

View File

@ -1,3 +1,5 @@
import type { MsTableColumn } from '@/components/pure/ms-table/type';
import { TaskCenterEnum } from '@/enums/taskCenter'; import { TaskCenterEnum } from '@/enums/taskCenter';
export const TaskStatus = { export const TaskStatus = {
@ -169,4 +171,25 @@ export const resourceTypeMap = {
}, },
}; };
export const ordAndProjectColumn: MsTableColumn = [
{
title: 'project.belongOrganization',
dataIndex: 'organizationName',
slotName: 'organizationName',
showTooltip: true,
showDrag: true,
width: 200,
showInTable: true,
},
{
title: 'project.belongProject',
dataIndex: 'projectName',
slotName: 'projectName',
showTooltip: true,
showDrag: true,
width: 200,
showInTable: true,
},
];
export default {}; export default {};