feat(项目管理): 环境管理显示设置

This commit is contained in:
RubyLiu 2024-02-06 18:06:22 +08:00 committed by Craftsman
parent cd1e8d3ca4
commit 58d2fa1b9e
8 changed files with 271 additions and 22 deletions

View File

@ -59,3 +59,15 @@ export interface GlobalParams {
projectId: string;
globalParams: GlobalParamsItem;
}
export interface ContentTabItem {
value: string;
label: string;
canHide: boolean;
isShow: boolean;
}
export interface ContentTabsMap {
tabList: ContentTabItem[];
backupTabList: ContentTabItem[];
}

View File

@ -1,9 +1,11 @@
import { defineStore } from 'pinia';
import localforage from 'localforage';
import { getDetailEnv, getGlobalParamDetail } from '@/api/modules/project-management/envManagement';
import { useAppStore } from '@/store';
import { isArraysEqualWithOrder } from '@/utils/equal';
import { EnvDetailItem, GlobalParams } from '@/models/projectManagement/environmental';
import { ContentTabItem, ContentTabsMap, EnvDetailItem, GlobalParams } from '@/models/projectManagement/environmental';
export const ALL_PARAM = 'allParam';
export const NEW_ENV_PARAM = 'newEnvParam';
@ -11,13 +13,18 @@ export const NEW_ENV_PARAM = 'newEnvParam';
const useProjectEnvStore = defineStore(
'projectEnv',
() => {
const currentId = ref<string>(ALL_PARAM); // 当前选中的key值
// 项目中的key值
const currentId = ref<string>(ALL_PARAM);
// 项目组选中的key值
const currentGroupId = ref<string>('');
const currentEnvDetailInfo = ref<EnvDetailItem>({ projectId: '', name: '', config: {} }); // 当前选中的环境详情
const backupEnvDetailInfo = ref<EnvDetailItem>({ projectId: '', name: '', config: {} }); // 当前选中的环境详情-备份
const allParamDetailInfo = ref<GlobalParams>(); // 全局参数详情
// 当前选中的项目组详情
const groupDetailInfo = ref<GlobalParams>();
const httpNoWarning = ref(true);
const getHttpNoWarning = computed(() => httpNoWarning.value);
const groupLength = ref(0); // 环境分组数据
// 设置选中项
function setCurrentId(id: string) {
currentId.value = id;
@ -51,18 +58,68 @@ const useProjectEnvStore = defineStore(
}
}
// 初始化内容tab列表
async function initContentTabList(arr: ContentTabItem[]) {
try {
const tabsMap = await localforage.getItem<ContentTabsMap>('bugTabsMap');
if (tabsMap) {
// 初始化过了
const { backupTabList } = tabsMap;
const isEqual = isArraysEqualWithOrder<ContentTabItem>(backupTabList, arr);
if (!isEqual) {
tabsMap.tabList = arr;
tabsMap.backupTabList = arr;
await localforage.setItem('bugTabsMap', tabsMap);
}
} else {
// 没初始化过
await localforage.setItem('bugTabsMap', { tabList: arr, backupTabList: arr });
}
} catch (e) {
// eslint-disable-next-line no-console
console.log(e);
}
}
// 获取Tab列表
async function getContentTabList() {
try {
const tabsMap = await localforage.getItem<ContentTabsMap>('bugTabsMap');
if (tabsMap) {
return tabsMap.tabList;
}
return [];
} catch (e) {
// eslint-disable-next-line no-console
console.log(e);
}
}
// 设置Tab列表
async function setContentTabList(arr: ContentTabItem[]) {
const tabsMap = await localforage.getItem<ContentTabsMap>('bugTabsMap');
if (tabsMap) {
const tmpArrList = JSON.parse(JSON.stringify(arr));
tabsMap.tabList = tmpArrList;
await localforage.setItem('bugTabsMap', tabsMap);
}
}
return {
currentId,
currentGroupId,
getHttpNoWarning,
httpNoWarning,
allParamDetailInfo,
currentEnvDetailInfo,
backupEnvDetailInfo,
groupLength,
groupDetailInfo,
setCurrentId,
setHttpNoWarning,
setAllParamDetailInfo,
initEnvDetail,
initContentTabList,
getContentTabList,
setContentTabList,
};
},
{

View File

@ -549,7 +549,6 @@
});
return;
}
debugger;
router.push({
name: BugManagementRouteEnum.BUG_MANAGEMENT_CREATE_SUCCESS,
query: {

View File

@ -1,6 +1,6 @@
<template>
<div class="page">
<template v-if="store.groupLength">
<template v-if="store.currentGroupId">
<div class="header">
<a-form ref="envGroupForm" layout="vertical" :model="form">
<a-form-item

View File

@ -18,8 +18,10 @@
/>
</a-form-item>
</a-form>
<a-tabs v-model:active-key="activeKey" class="no-content">
<a-tab-pane v-for="item of contentTabList" :key="item.value" :title="item.label" />
<a-tabs v-if="contentTabList.length" v-model:active-key="activeKey" class="no-content" @change="handleTabChange">
<a-tab-pane v-for="item of contentTabList" :key="item.value" :title="t(item.label)" />
<a-tab-pane key="displaySetting" :title="t('project.environmental.displaySetting')" />
</a-tabs>
</div>
<a-divider :margin="0" class="!mb-[16px]" />
@ -33,6 +35,7 @@
<PostTab v-else-if="activeKey === 'post'" />
<AssertTab v-else-if="activeKey === 'assert'" />
</div>
<TabSettingDrawer v-model:visible="tabSettingVisible" @init-data="initTab" />
<div class="footer" :style="{ width: '100%' }">
<a-button @click="handleReset">{{ t('common.cancel') }}</a-button>
@ -45,6 +48,7 @@
import { Message } from '@arco-design/web-vue';
import { isEqual } from 'lodash-es';
import TabSettingDrawer from './common/TabSettingDrawer.vue';
import AssertTab from './envParams/AssertTab.vue';
import DataBaseTab from './envParams/DatabaseTab.vue';
import EnvParamsTab from './envParams/EnvParamsTab.vue';
@ -58,11 +62,14 @@
import { useI18n } from '@/hooks/useI18n';
import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore';
const activeKey = ref('assert');
import { ContentTabItem } from '@/models/projectManagement/environmental';
const activeKey = ref('envParams');
const envForm = ref();
const canSave = ref(false);
const { t } = useI18n();
const loading = ref(false);
const tabSettingVisible = ref(false);
const store = useProjectEnvStore();
@ -70,44 +77,61 @@
name: '',
});
const contentTabList = [
const contentTabList = ref<ContentTabItem[]>([]);
const sourceTabList = [
{
value: 'envParams',
label: t('project.environmental.envParams'),
label: 'project.environmental.envParams',
canHide: false,
isShow: true,
},
{
value: 'http',
label: 'HTTP',
label: 'project.environmental.HTTP',
canHide: true,
isShow: true,
},
{
value: 'database',
label: t('project.environmental.database'),
label: 'project.environmental.database',
canHide: true,
isShow: true,
},
{
value: 'host',
label: 'Host',
label: 'project.environmental.HOST',
canHide: true,
isShow: true,
},
{
value: 'tcp',
label: 'TCP',
label: 'project.environmental.TCP',
canHide: true,
isShow: true,
},
{
value: 'pre',
label: t('project.environmental.pre'),
label: 'project.environmental.pre',
canHide: true,
isShow: true,
},
{
value: 'post',
label: t('project.environmental.post'),
label: 'project.environmental.post',
canHide: true,
isShow: true,
},
{
value: 'assert',
label: t('project.environmental.assert'),
},
{
value: 'display',
label: t('project.environmental.displaySetting'),
label: 'project.environmental.assert',
canHide: true,
isShow: true,
},
];
await store.initContentTabList(sourceTabList);
contentTabList.value = ((await store.getContentTabList()) || []).filter((item) => item.isShow);
const handleReset = () => {
envForm.value?.resetFields();
store.initEnvDetail();
@ -148,6 +172,21 @@
canSave.value = !isEqual(currentEnvDetailInfo, backupEnvDetailInfo);
}
});
const initTab = async () => {
tabSettingVisible.value = false;
const tmpArr = (await store.getContentTabList()) || [];
contentTabList.value = tmpArr.filter((item) => item.isShow);
if (contentTabList.value.length) {
activeKey.value = contentTabList.value[0].value;
}
};
const handleTabChange = (key: string | number) => {
if (key === 'displaySetting') {
tabSettingVisible.value = true;
}
};
</script>
<style lang="less" scoped>

View File

@ -0,0 +1,134 @@
<template>
<MsDrawer
:visible="innerVisible"
:width="480"
unmount-on-close
:footer="false"
:title="t('project.environmental.displaySetting')"
@cancel="handleCancel"
>
<div class="ms-table-column-seletor">
<div class="mb-2 flex items-center justify-between">
<div class="text-[var(--color-text-4)]">{{ t('project.environmental.displaySetting') }}</div>
<MsButton v-if="hasChange" @click="handleReset">{{ t('msTable.columnSetting.resetDefault') }}</MsButton>
</div>
<div class="flex-col">
<div v-for="item in nonCloseColumn" :key="item.value" class="column-item">
<div>{{ t(item.label) }}</div>
<a-switch v-model="item.isShow" disabled size="small" type="line" @change="handleSwitchChange" />
</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 v-for="element in couldCloseColumn" :key="element.value" class="column-drag-item">
<div class="flex w-[90%] items-center">
<span class="ml-[8px]">{{ t(element.label) }}</span>
</div>
<a-switch v-model="element.isShow" size="small" type="line" @change="handleSwitchChange" />
</div>
</div>
</MsDrawer>
</template>
<script lang="ts" setup>
import { onBeforeMount, ref } from 'vue';
import MsButton from '@/components/pure/ms-button/index.vue';
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
import { useI18n } from '@/hooks/useI18n';
import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore';
import { ContentTabItem } from '@/models/projectManagement/environmental';
const store = useProjectEnvStore();
const { t } = useI18n();
const innerVisible = defineModel<boolean>('visible', { default: false });
const nonCloseColumn = ref<ContentTabItem[]>([]);
//
const couldCloseColumn = ref<ContentTabItem[]>([]);
//
const hasChange = ref(false);
const emit = defineEmits<{
(e: 'initData'): void;
}>();
const handleCancel = async () => {
await store.setContentTabList([...nonCloseColumn.value, ...couldCloseColumn.value]);
emit('initData');
};
const loadColumn = async () => {
const res = (await store.getContentTabList()) || [];
nonCloseColumn.value = res.filter((item) => !item.canHide);
couldCloseColumn.value = res.filter((item) => item.canHide);
};
const handleReset = () => {
loadColumn();
hasChange.value = false;
};
const handleSwitchChange = () => {
hasChange.value = true;
};
onBeforeMount(() => {
loadColumn();
});
</script>
<style lang="less" scoped>
:deep(.arco-divider-horizontal) {
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 12px 8px 36px;
&: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>

View File

@ -20,11 +20,15 @@ export default {
'project.environmental.envNamePlaceholder': 'Please enter the environment name',
'project.environmental.envNameRequired': 'Environment name cannot be empty',
'project.environmental.database': 'Database',
'project.environmental.HTTP': 'HTTP',
'project.environmental.HOST': 'HOST',
'project.environmental.TCP': 'TCP',
'project.environmental.pre': 'Pre',
'project.environmental.post': 'Post',
'project.environmental.host': 'Host',
'project.environmental.assert': 'Assertion',
'project.environmental.displaySetting': 'Display Setting',
'project.environmental.nonClose': 'Do not close the above properties',
'project.environmental.httpTitle': 'When multiple enable conditions are met, match in order from top to bottom',
'project.environmental.httpNoWarning': 'No warning',
'project.environmental.addHttp': 'Add HTTP',

View File

@ -28,12 +28,16 @@ export default {
'project.environmental.newEnv': '未命名环境',
'project.environmental.envNamePlaceholder': '请输入环境名称',
'project.environmental.envNameRequired': '环境名称不能为空',
'project.environmental.HTTP': 'HTTP',
'project.environmental.HOST': 'HOST',
'project.environmental.TCP': 'TCP',
'project.environmental.database': '数据库',
'project.environmental.pre': '前置',
'project.environmental.post': '后置',
'project.environmental.host': '域名',
'project.environmental.assert': '断言',
'project.environmental.displaySetting': '显示设置',
'project.environmental.nonClose': '以上属性不关闭',
'project.environmental.httpTitle': '当满足多个启用条件时,按从上到下的顺序匹配',
'project.environmental.httpNoWarning': '不在提醒',
'project.environmental.addHttp': '添加 HTTP',