feat: 页面及按钮权限&环境管理新增环境接口对接
This commit is contained in:
parent
8ca4f27432
commit
09b4b6756a
|
@ -67,6 +67,10 @@
|
|||
const checkIsLogin = async () => {
|
||||
const isLogin = await userStore.isLogin();
|
||||
const isLoginPage = route.name === 'login';
|
||||
if (isLogin && appStore.currentProjectId) {
|
||||
// 当前为登陆状态,且已经选择了项目,初始化当前项目配置
|
||||
appStore.setCurrentMenuConfig();
|
||||
}
|
||||
if (isLoginPage && isLogin) {
|
||||
// 当前页面为登录页面,且已经登录,跳转到首页
|
||||
router.push(WorkbenchRouteEnum.WORKBENCH);
|
||||
|
|
|
@ -12,8 +12,8 @@ import type {
|
|||
} from '@/models/projectManagement/environmental';
|
||||
import { OptionsItem } from '@/models/setting/log';
|
||||
|
||||
export function updateEnv(data: EnvListItem) {
|
||||
return MSR.post<EnvListItem>({ url: envURL.updateEnvUrl, data });
|
||||
export function updateOrAddEnv(data: EnvDetailItem) {
|
||||
return MSR.post<EnvDetailItem>({ url: data.id ? envURL.updateEnvUrl : envURL.addEnvUrl, data });
|
||||
}
|
||||
export function listEnv(data: { projectId: string; keyword: string }) {
|
||||
return MSR.post<EnvListItem[]>({ url: envURL.listEnvUrl, data });
|
||||
|
@ -24,8 +24,8 @@ export function importEnv(data: { request: EnvListItem; fileList: FileItem[] })
|
|||
export function getEntryEnv(data: EnvListItem) {
|
||||
return MSR.post<EnvListItem>({ url: envURL.getEntryEnvUrl, data });
|
||||
}
|
||||
export function exportEnv(data: EnvListItem) {
|
||||
return MSR.post<EnvListItem>({ url: envURL.exportEnvUrl, data });
|
||||
export function exportEnv(id: string) {
|
||||
return MSR.get<EnvListItem>({ url: envURL.exportEnvUrl + id, responseType: 'blob' }, { isTransformResponse: false });
|
||||
}
|
||||
export function editPosEnv(data: EnvListItem) {
|
||||
return MSR.post<EnvListItem>({ url: envURL.editPosEnvUrl, data });
|
||||
|
@ -85,5 +85,8 @@ export function getGlobalParamDetail(id: string) {
|
|||
}
|
||||
/** 项目管理-环境-全局参数-导出 */
|
||||
export function exportGlobalParam(id: string) {
|
||||
return MSR.get<BlobPart>({ url: envURL.exportGlobalParamUrl + id });
|
||||
return MSR.get<BlobPart>(
|
||||
{ url: envURL.exportGlobalParamUrl + id, responseType: 'blob' },
|
||||
{ isTransformResponse: false }
|
||||
);
|
||||
}
|
||||
|
|
|
@ -10,3 +10,7 @@ export function getProjectList(organizationId: string) {
|
|||
export function switchProject(data: { projectId: string; userId: string }) {
|
||||
return MSR.post({ url: ProjectSwitchUrl, data });
|
||||
}
|
||||
|
||||
export function getProjectInfo(projectId: string) {
|
||||
return MSR.get<ProjectListItem>({ url: `/project/get/${projectId}` });
|
||||
}
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
export const ProjectListUrl = '/project/list/options'; // 项目列表
|
||||
export const ProjectSwitchUrl = '/project/switch'; // 切换项目
|
||||
export const projectModuleInfoUrl = '/project/get/'; // 获取项目模块信息
|
||||
|
|
|
@ -0,0 +1,246 @@
|
|||
<template>
|
||||
<div class="flex h-full w-full flex-col">
|
||||
<a-radio-group v-model:model-value="condition.scriptType" size="small" class="mb-[16px]">
|
||||
<a-radio value="manual">{{ t('apiTestDebug.manual') }}</a-radio>
|
||||
<a-radio value="quote">{{ t('apiTestDebug.quote') }}</a-radio>
|
||||
</a-radio-group>
|
||||
<div
|
||||
v-if="scriptType === 'manual'"
|
||||
class="relative h-full w-full rounded-[var(--border-radius-small)] bg-[var(--color-text-n9)] p-[12px]"
|
||||
>
|
||||
<div v-if="isShowEditScriptNameInput" class="absolute left-[12px] z-10 w-[calc(100%-24px)]">
|
||||
<a-input
|
||||
ref="scriptNameInputRef"
|
||||
v-model:model-value="condition.name"
|
||||
:placeholder="t('apiTestDebug.preconditionScriptNamePlaceholder')"
|
||||
:max-length="255"
|
||||
show-word-limit
|
||||
size="small"
|
||||
@press-enter="isShowEditScriptNameInput = false"
|
||||
@blur="isShowEditScriptNameInput = false"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<a-tooltip :content="condition.name">
|
||||
<div class="script-name-container">
|
||||
<div class="one-line-text mr-[4px] max-w-[110px] font-medium text-[var(--color-text-1)]">
|
||||
{{ condition.name }}
|
||||
</div>
|
||||
<MsIcon type="icon-icon_edit_outlined" class="edit-script-name-icon" @click="showEditScriptNameInput" />
|
||||
</div>
|
||||
</a-tooltip>
|
||||
<a-popover class="h-auto" position="top">
|
||||
<div class="text-[rgb(var(--primary-5))]">{{ t('apiTestDebug.scriptEx') }}</div>
|
||||
<template #content>
|
||||
<div class="mb-[8px] flex items-center justify-between">
|
||||
<div class="text-[14px] font-medium text-[var(--color-text-1)]">
|
||||
{{ t('apiTestDebug.scriptEx') }}
|
||||
</div>
|
||||
<a-button
|
||||
type="outline"
|
||||
class="arco-btn-outline--secondary p-[0_8px]"
|
||||
size="mini"
|
||||
@click="copyScriptEx"
|
||||
>
|
||||
{{ t('common.copy') }}
|
||||
</a-button>
|
||||
</div>
|
||||
<div class="flex h-[412px]">
|
||||
<MsCodeEditor
|
||||
v-model:model-value="scriptEx"
|
||||
class="flex-1"
|
||||
theme="MS-text"
|
||||
width="500px"
|
||||
height="388px"
|
||||
:show-full-screen="false"
|
||||
:show-theme-change="false"
|
||||
read-only
|
||||
>
|
||||
</MsCodeEditor>
|
||||
</div>
|
||||
</template>
|
||||
</a-popover>
|
||||
</div>
|
||||
<div class="flex items-center gap-[8px]">
|
||||
<a-button type="outline" class="arco-btn-outline--secondary p-[0_8px]" size="mini">
|
||||
<template #icon>
|
||||
<MsIcon type="icon-icon_undo_outlined" class="text-var(--color-text-4)" size="12" />
|
||||
</template>
|
||||
{{ t('common.revoke') }}
|
||||
</a-button>
|
||||
<a-button type="outline" class="arco-btn-outline--secondary p-[0_8px]" size="mini" @click="clearScript">
|
||||
<template #icon>
|
||||
<MsIcon type="icon-icon_clear" class="text-var(--color-text-4)" size="12" />
|
||||
</template>
|
||||
{{ t('common.clear') }}
|
||||
</a-button>
|
||||
<a-button type="outline" class="arco-btn-outline--secondary p-[0_8px]" size="mini" @click="copyCondition">
|
||||
{{ t('common.copy') }}
|
||||
</a-button>
|
||||
<a-button type="outline" class="arco-btn-outline--secondary p-[0_8px]" size="mini" @click="deleteCondition">
|
||||
{{ t('common.delete') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="flex h-[calc(100%-47px)] flex-col">
|
||||
<div class="mb-[16px] flex w-full items-center bg-[var(--color-text-n9)] p-[12px]">
|
||||
<div class="text-[var(--color-text-2)]">
|
||||
{{ condition.quoteScript.name || '-' }}
|
||||
</div>
|
||||
<a-divider margin="8px" direction="vertical" />
|
||||
<MsButton type="text" class="font-medium">
|
||||
{{ t('apiTestDebug.quote') }}
|
||||
</MsButton>
|
||||
</div>
|
||||
<a-radio-group v-model:model-value="commonScriptShowType" size="small" type="button" class="mb-[8px] w-fit">
|
||||
<a-radio value="parameters">{{ t('apiTestDebug.parameters') }}</a-radio>
|
||||
<a-radio value="scriptContent">{{ t('apiTestDebug.scriptContent') }}</a-radio>
|
||||
</a-radio-group>
|
||||
<MsBaseTable v-show="commonScriptShowType === 'parameters'" v-bind="propsRes" v-on="propsEvent">
|
||||
<template #value="{ record }">
|
||||
<a-tooltip :content="t(record.required ? 'apiTestDebug.paramRequired' : 'apiTestDebug.paramNotRequired')">
|
||||
<div
|
||||
:class="[
|
||||
record.required ? '!text-[rgb(var(--danger-5))]' : '!text-[var(--color-text-brand)]',
|
||||
'!mr-[4px] !p-[4px]',
|
||||
]"
|
||||
>
|
||||
<div>*</div>
|
||||
</div>
|
||||
</a-tooltip>
|
||||
{{ record.type }}
|
||||
</template>
|
||||
</MsBaseTable>
|
||||
<div v-show="commonScriptShowType === 'scriptContent'" class="h-[calc(100%-76px)]">
|
||||
<MsCodeEditor
|
||||
v-model:model-value="condition.quoteScript.script"
|
||||
theme="MS-text"
|
||||
height="100%"
|
||||
:show-full-screen="false"
|
||||
:show-theme-change="false"
|
||||
read-only
|
||||
>
|
||||
</MsCodeEditor>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useClipboard } from '@vueuse/core';
|
||||
import { InputInstance, Message } from '@arco-design/web-vue';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsCodeEditor from '@/components/pure/ms-code-editor/index.vue';
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
import type { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const scriptType = defineModel('scriptType', {
|
||||
type: String,
|
||||
default: 'manual',
|
||||
});
|
||||
|
||||
const condition = defineModel('modelValue', {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
scriptType: 'manual',
|
||||
name: '',
|
||||
script: '',
|
||||
quoteScript: {
|
||||
name: '',
|
||||
script: '',
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const columns: MsTableColumn = [
|
||||
{
|
||||
title: 'apiTestDebug.paramName',
|
||||
dataIndex: 'name',
|
||||
showTooltip: true,
|
||||
},
|
||||
{
|
||||
title: 'apiTestDebug.paramValue',
|
||||
dataIndex: 'value',
|
||||
slotName: 'value',
|
||||
},
|
||||
{
|
||||
title: 'apiTestDebug.desc',
|
||||
dataIndex: 'desc',
|
||||
showTooltip: true,
|
||||
},
|
||||
];
|
||||
|
||||
const { propsRes, propsEvent } = useTable(() => Promise.resolve([]), {
|
||||
scroll: { x: '100%' },
|
||||
columns,
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:data', data: Record<string, any>): void;
|
||||
(e: 'copy'): void;
|
||||
(e: 'delete', id: string): void;
|
||||
(e: 'change'): void;
|
||||
}>();
|
||||
|
||||
// 是否显示脚本名称编辑框
|
||||
const isShowEditScriptNameInput = ref(false);
|
||||
const scriptNameInputRef = ref<InputInstance>();
|
||||
|
||||
function showEditScriptNameInput() {
|
||||
isShowEditScriptNameInput.value = true;
|
||||
nextTick(() => {
|
||||
scriptNameInputRef.value?.focus();
|
||||
});
|
||||
}
|
||||
|
||||
const scriptEx = ref(`2023-12-04 11:19:28 INFO 9026fd6a 1-1 Thread started: 9026fd6a 1-1
|
||||
2023-12-04 11:19:28 ERROR 9026fd6a 1-1 Problem in JSR223 script JSR223Sampler, message: {}
|
||||
In file: inline evaluation of: prev.getResponseCode() import java.net.URI; import org.apache.http.client.method . . . '' Encountered "import" at line 2, column 1.
|
||||
in inline evaluation of: prev.getResponseCode() import java.net.URI; import org.apache.http.client.method . . . '' at line number 2
|
||||
javax.script.ScriptException '' at line number 2
|
||||
javax.script.ScriptException '' at line number 2
|
||||
javax.script.ScriptException '' at line number 2
|
||||
javax.script.ScriptException '' at line number 2
|
||||
javax.script.ScriptException '' at line number 2
|
||||
javax.script.ScriptException
|
||||
org.apache.http.client.method . . . '' at line number 2
|
||||
`);
|
||||
const { copy, isSupported } = useClipboard();
|
||||
const commonScriptShowType = ref<'parameters' | 'scriptContent'>('parameters');
|
||||
function copyScriptEx() {
|
||||
if (isSupported) {
|
||||
copy(scriptEx.value);
|
||||
Message.success(t('apiTestDebug.scriptExCopySuccess'));
|
||||
} else {
|
||||
Message.warning(t('apiTestDebug.copyNotSupport'));
|
||||
}
|
||||
}
|
||||
function clearScript() {
|
||||
condition.value.script = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制条件
|
||||
*/
|
||||
function copyCondition() {
|
||||
emit('copy');
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除条件
|
||||
*/
|
||||
function deleteCondition() {
|
||||
emit('delete', condition.value.id);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
|
@ -63,6 +63,7 @@
|
|||
<ResponseHeaderTab v-if="valueKey === 'responseHeader'" />
|
||||
<ResponseTimeTab v-if="valueKey === 'responseTime'" />
|
||||
<VariableTab v-if="valueKey === 'variable'" />
|
||||
<ScriptTab v-if="valueKey === 'script'" />
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -77,6 +78,7 @@
|
|||
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||
import ResponseHeaderTab from './comp/ResponseHeaderTab.vue';
|
||||
import ResponseTimeTab from './comp/ResponseTimeTab.vue';
|
||||
import ScriptTab from './comp/ScriptTab.vue';
|
||||
import StatusCodeTab from './comp/StatusCodeTab.vue';
|
||||
import VariableTab from './comp/VariableTab.vue';
|
||||
|
||||
|
|
|
@ -89,6 +89,7 @@
|
|||
});
|
||||
}
|
||||
};
|
||||
|
||||
menuTree.value?.forEach((el: RouteRecordRaw | null) => {
|
||||
if (isFind) return; // 节省性能
|
||||
backtrack(el, [el?.name as string]);
|
||||
|
@ -336,6 +337,7 @@
|
|||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
return travel(menuTree.value);
|
||||
};
|
||||
|
||||
|
|
|
@ -79,7 +79,9 @@
|
|||
(item) => name && item?.name && (name as string).includes(item.name as string)
|
||||
);
|
||||
}
|
||||
appStore.setTopMenus(currentParent?.children?.filter((item) => item.meta?.isTopMenu));
|
||||
appStore.setTopMenus(
|
||||
currentParent?.children?.filter((item) => permission.accessRouter(item) && item.meta?.isTopMenu)
|
||||
);
|
||||
setCurrentTopMenu(name as string);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,22 +1,17 @@
|
|||
import { DirectiveBinding } from 'vue';
|
||||
|
||||
import { useUserStore } from '@/store';
|
||||
import { hasAnyPermission } from '@/utils/permission';
|
||||
|
||||
/**
|
||||
* 权限指令,TODO:权限判定按权限点来
|
||||
* 权限指令
|
||||
* @param el dom 节点
|
||||
* @param binding vue 绑定的数据
|
||||
*/
|
||||
function checkPermission(el: HTMLElement, binding: DirectiveBinding) {
|
||||
const { value } = binding;
|
||||
const userStore = useUserStore();
|
||||
const { role } = userStore;
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
if (value.length > 0) {
|
||||
const permissionValues = value;
|
||||
|
||||
const hasPermission = permissionValues.includes(role);
|
||||
const hasPermission = hasAnyPermission(value);
|
||||
if (!hasPermission && el.parentNode) {
|
||||
el.parentNode.removeChild(el);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ export enum CaseManagementRouteEnum {
|
|||
}
|
||||
|
||||
export enum PerformanceTestRouteEnum {
|
||||
PERFORMANCE_TEST = 'performanceTest',
|
||||
PERFORMANCE_TEST = 'loadTest',
|
||||
}
|
||||
|
||||
export enum ProjectManagementRouteEnum {
|
||||
|
@ -57,7 +57,7 @@ export enum UITestRouteEnum {
|
|||
}
|
||||
|
||||
export enum WorkbenchRouteEnum {
|
||||
WORKBENCH = 'workbench',
|
||||
WORKBENCH = 'workstation',
|
||||
}
|
||||
|
||||
export enum SettingRouteEnum {
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
import { RouteLocationNormalized, RouteRecordRaw } from 'vue-router';
|
||||
import { includes } from 'lodash-es';
|
||||
|
||||
import { useUserStore } from '@/store';
|
||||
import { hasAnyPermission, hasFirstMenuPermission } from '@/utils/permission';
|
||||
|
||||
const firstLevelMenu = ['workstation', 'testPlan', 'bugManagement', 'caseManagement', 'apiTest', 'uiTest', 'loadTest'];
|
||||
|
||||
/**
|
||||
* 用户权限
|
||||
* @returns 调用方法
|
||||
*/
|
||||
export default function usePermission() {
|
||||
const userStore = useUserStore();
|
||||
return {
|
||||
/**
|
||||
* 是否为允许访问的路由
|
||||
|
@ -15,35 +17,17 @@ export default function usePermission() {
|
|||
* @returns 是否
|
||||
*/
|
||||
accessRouter(route: RouteLocationNormalized | RouteRecordRaw) {
|
||||
if (includes(firstLevelMenu, route.name)) {
|
||||
// 一级菜单
|
||||
return hasFirstMenuPermission(route.name as string);
|
||||
}
|
||||
return (
|
||||
route.meta?.requiresAuth === false ||
|
||||
!route.meta?.roles ||
|
||||
route.meta?.roles?.includes('*') ||
|
||||
route.meta?.roles?.includes(userStore.role)
|
||||
hasAnyPermission(route.meta?.roles || [])
|
||||
);
|
||||
},
|
||||
/**
|
||||
* 查找第一个允许访问的路由
|
||||
* @param _routers 路由数组
|
||||
* @param role 用户角色
|
||||
* @returns 路由信息 or null
|
||||
*/
|
||||
findFirstPermissionRoute(_routers: any, role = 'admin') {
|
||||
const cloneRouters = [..._routers];
|
||||
while (cloneRouters.length) {
|
||||
const firstElement = cloneRouters.shift();
|
||||
if (
|
||||
firstElement?.meta?.roles?.find((el: string[]) => {
|
||||
return el.includes('*') || el.includes(role);
|
||||
})
|
||||
)
|
||||
return { name: firstElement.name };
|
||||
if (firstElement?.children) {
|
||||
cloneRouters.push(...firstElement.children);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// You can add any rules you want
|
||||
};
|
||||
}
|
||||
|
|
|
@ -38,16 +38,16 @@ export interface EnvConfig {
|
|||
dataSource?: DataSourceItem[];
|
||||
hostConfig?: EnvConfigItem;
|
||||
authConfig?: EnvConfigItem;
|
||||
preScript?: EnvConfigItem;
|
||||
postScript?: EnvConfigItem;
|
||||
assertions?: EnvConfigItem;
|
||||
preScript?: EnvConfigItem[];
|
||||
postScript?: EnvConfigItem[];
|
||||
assertions?: EnvConfigItem[];
|
||||
}
|
||||
export interface EnvDetailItem {
|
||||
id?: string;
|
||||
projectId: string;
|
||||
name: string;
|
||||
config: EnvConfig;
|
||||
mock?: string;
|
||||
mock?: boolean;
|
||||
description?: string;
|
||||
}
|
||||
export interface GlobalParamsItem {
|
||||
|
|
|
@ -13,4 +13,5 @@ export interface ProjectListItem {
|
|||
deleted: boolean;
|
||||
deleteUser: string;
|
||||
enable: boolean;
|
||||
moduleIds: string[];
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { UserState } from '@/store/modules/user/types';
|
||||
|
||||
// 登录信息
|
||||
export interface LoginData {
|
||||
username: string;
|
||||
|
@ -5,37 +7,11 @@ export interface LoginData {
|
|||
authenticate: string;
|
||||
}
|
||||
|
||||
export interface UserRole {
|
||||
id: string;
|
||||
createTime: number;
|
||||
createUser: string;
|
||||
roleId: string;
|
||||
sourceId: string;
|
||||
userId: string;
|
||||
}
|
||||
|
||||
// 登录返回
|
||||
export interface LoginRes {
|
||||
export interface LoginRes extends UserState {
|
||||
csrfToken: string;
|
||||
createTime: number;
|
||||
createUser: string;
|
||||
email: string;
|
||||
enabled: boolean;
|
||||
id: string;
|
||||
language: string;
|
||||
lastOrganizationId: string;
|
||||
lastProjectId: string;
|
||||
name: string;
|
||||
phone: string;
|
||||
platformInfo: string;
|
||||
seleniumServer: string;
|
||||
sessionId: string;
|
||||
source: string;
|
||||
updateTime: number;
|
||||
updateUser: string;
|
||||
userRolePermissions: UserRole[];
|
||||
userRoleRelations: UserRole[];
|
||||
userRoles: UserRole[];
|
||||
token: string;
|
||||
}
|
||||
// 更新本地执行配置
|
||||
export interface UpdateLocalConfigParams {
|
||||
|
@ -94,23 +70,6 @@ export interface Resource {
|
|||
name: string;
|
||||
license: boolean;
|
||||
}
|
||||
export interface UserRolePermission {
|
||||
resource: Resource;
|
||||
permissions: Permission[];
|
||||
type: string;
|
||||
userRole: UserRole;
|
||||
userRolePermissions: Permission[];
|
||||
}
|
||||
|
||||
export interface UserRoleRelation {
|
||||
id: string;
|
||||
userId: string;
|
||||
roleId: string;
|
||||
sourceId: string;
|
||||
organizationId: string;
|
||||
createTime: number;
|
||||
createUser: string;
|
||||
}
|
||||
// 个人信息
|
||||
export interface PersonalOrganization {
|
||||
id: string;
|
||||
|
|
|
@ -270,7 +270,7 @@ const ProjectManagement: AppRouteRecordRaw = {
|
|||
component: () => import('@/views/project-management/environmental/index.vue'),
|
||||
meta: {
|
||||
locale: 'menu.projectManagement.environmentManagement',
|
||||
roles: ['*'],
|
||||
roles: ['PROJECT_ENVIRONMENT:READ'],
|
||||
isTopMenu: true,
|
||||
},
|
||||
},
|
||||
|
|
|
@ -50,7 +50,7 @@ const Setting: AppRouteRecordRaw = {
|
|||
component: () => import('@/views/setting/system/organizationAndProject/index.vue'),
|
||||
meta: {
|
||||
locale: 'menu.settings.system.organizationAndProject',
|
||||
roles: ['*'],
|
||||
roles: ['SYSTEM_ORGANIZATION_PROJECT:READ'],
|
||||
isTopMenu: true,
|
||||
},
|
||||
},
|
||||
|
|
|
@ -4,6 +4,7 @@ import { cloneDeep } from 'lodash-es';
|
|||
|
||||
import type { BreadcrumbItem } from '@/components/business/ms-breadcrumb/types';
|
||||
|
||||
import { getProjectInfo } from '@/api/modules/project-management/basicInfo';
|
||||
import { getPageConfig } from '@/api/modules/setting/config';
|
||||
import { getSystemVersion } from '@/api/modules/system';
|
||||
import { getMenuList } from '@/api/modules/user';
|
||||
|
@ -51,6 +52,7 @@ const useAppStore = defineStore('app', {
|
|||
defaultLoginConfig,
|
||||
defaultPlatformConfig,
|
||||
innerHeight: 0,
|
||||
currentMenuConfig: [],
|
||||
pageConfig: {
|
||||
...defaultThemeConfig,
|
||||
...defaultLoginConfig,
|
||||
|
@ -273,6 +275,18 @@ const useAppStore = defineStore('app', {
|
|||
console.log(error);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置当前项目菜单配置
|
||||
*/
|
||||
async setCurrentMenuConfig() {
|
||||
try {
|
||||
const res = await getProjectInfo(this.currentProjectId);
|
||||
this.currentMenuConfig = res.moduleIds;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
},
|
||||
persist: {
|
||||
paths: ['currentOrgId', 'currentProjectId', 'pageConfig'],
|
||||
|
|
|
@ -2,6 +2,7 @@ import type { MsFileItem } from '@/components/pure/ms-upload/types';
|
|||
import type { BreadcrumbItem } from '@/components/business/ms-breadcrumb/types';
|
||||
|
||||
import type { LoginConfig, PageConfig, PlatformConfig, ThemeConfig } from '@/models/setting/config';
|
||||
import { UserGroupAuthSetting } from '@/models/setting/usergroup';
|
||||
|
||||
import type { RouteRecordNormalized, RouteRecordRaw } from 'vue-router';
|
||||
|
||||
|
@ -35,6 +36,7 @@ export interface AppState {
|
|||
defaultPlatformConfig: PlatformConfig;
|
||||
pageConfig: PageConfig;
|
||||
innerHeight: number;
|
||||
currentMenuConfig: string[];
|
||||
}
|
||||
|
||||
export interface UploadFileTaskState {
|
||||
|
|
|
@ -12,7 +12,8 @@ const useProjectEnvStore = defineStore(
|
|||
'projectEnv',
|
||||
() => {
|
||||
const currentId = ref<string>(ALL_PARAM); // 当前选中的key值
|
||||
const currentEnvDetailInfo = ref<EnvDetailItem>(); // 当前选中的环境详情
|
||||
const currentEnvDetailInfo = ref<EnvDetailItem>({ projectId: '', name: '', config: {} }); // 当前选中的环境详情
|
||||
const backupEnvDetailInfo = ref<EnvDetailItem>({ projectId: '', name: '', config: {} }); // 当前选中的环境详情-备份
|
||||
const allParamDetailInfo = ref<GlobalParams>(); // 全局参数详情
|
||||
const httpNoWarning = ref(true);
|
||||
const getHttpNoWarning = computed(() => httpNoWarning.value);
|
||||
|
@ -25,10 +26,6 @@ const useProjectEnvStore = defineStore(
|
|||
function setHttpNoWarning(noWarning: boolean) {
|
||||
httpNoWarning.value = noWarning;
|
||||
}
|
||||
// 设置环境详情
|
||||
function setEnvDetailInfo(item: EnvDetailItem) {
|
||||
currentEnvDetailInfo.value = item;
|
||||
}
|
||||
// 设置全局参数
|
||||
function setAllParamDetailInfo(item: GlobalParams) {
|
||||
allParamDetailInfo.value = item;
|
||||
|
@ -39,11 +36,14 @@ const useProjectEnvStore = defineStore(
|
|||
const appStore = useAppStore();
|
||||
try {
|
||||
if (id === NEW_ENV_PARAM) {
|
||||
currentEnvDetailInfo.value = undefined;
|
||||
currentEnvDetailInfo.value = { projectId: appStore.currentProjectId, name: '', config: {} };
|
||||
backupEnvDetailInfo.value = { projectId: appStore.currentProjectId, name: '', config: {} };
|
||||
} else if (id === ALL_PARAM) {
|
||||
allParamDetailInfo.value = await getGlobalParamDetail(appStore.currentProjectId);
|
||||
} else if (id !== ALL_PARAM && id) {
|
||||
currentEnvDetailInfo.value = await getDetailEnv(id);
|
||||
const tmpObj = await getDetailEnv(id);
|
||||
currentEnvDetailInfo.value = tmpObj;
|
||||
backupEnvDetailInfo.value = JSON.parse(JSON.stringify(tmpObj));
|
||||
}
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
|
@ -56,10 +56,11 @@ const useProjectEnvStore = defineStore(
|
|||
getHttpNoWarning,
|
||||
httpNoWarning,
|
||||
allParamDetailInfo,
|
||||
currentEnvDetailInfo,
|
||||
backupEnvDetailInfo,
|
||||
groupLength,
|
||||
setCurrentId,
|
||||
setHttpNoWarning,
|
||||
setEnvDetailInfo,
|
||||
setAllParamDetailInfo,
|
||||
initEnvDetail,
|
||||
};
|
||||
|
|
|
@ -4,13 +4,14 @@ import { isLogin as userIsLogin, login as userLogin, logout as userLogout } from
|
|||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { getHashParameters } from '@/utils';
|
||||
import { clearToken, setToken } from '@/utils/auth';
|
||||
import { composePermissions } from '@/utils/permission';
|
||||
import { removeRouteListener } from '@/utils/route-listener';
|
||||
|
||||
import type { LoginData } from '@/models/user';
|
||||
|
||||
import useAppStore from '../app';
|
||||
import useLicenseStore from '../setting/license';
|
||||
import type { UserState } from './types';
|
||||
import { UserState } from './types';
|
||||
|
||||
const useUserStore = defineStore('user', {
|
||||
// 开启数据持久化
|
||||
|
@ -32,12 +33,29 @@ const useUserStore = defineStore('user', {
|
|||
id: undefined,
|
||||
certification: undefined,
|
||||
role: '',
|
||||
userRolePermissions: [],
|
||||
}),
|
||||
|
||||
getters: {
|
||||
userInfo(state: UserState): UserState {
|
||||
return { ...state };
|
||||
},
|
||||
isAdmin(state: UserState): boolean {
|
||||
if (!state.userRolePermissions) return false;
|
||||
return state.userRolePermissions.findIndex((ur) => ur.userRole.id === 'admin') > -1;
|
||||
},
|
||||
currentRole(state: UserState): {
|
||||
projectPermissions: string[];
|
||||
orgPermissions: string[];
|
||||
systemPermissions: string[];
|
||||
} {
|
||||
const appStore = useAppStore();
|
||||
return {
|
||||
projectPermissions: composePermissions(state.userRolePermissions || [], 'PROJECT', appStore.currentProjectId),
|
||||
orgPermissions: composePermissions(state.userRolePermissions || [], 'ORGANIZATION', appStore.currentOrgId),
|
||||
systemPermissions: composePermissions(state.userRolePermissions || [], 'SYSTEM', 'global'),
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
actions: {
|
||||
|
@ -51,7 +69,6 @@ const useUserStore = defineStore('user', {
|
|||
setInfo(partial: Partial<UserState>) {
|
||||
this.$patch(partial);
|
||||
},
|
||||
|
||||
// 重置用户信息
|
||||
resetInfo() {
|
||||
this.$reset();
|
||||
|
|
|
@ -1,4 +1,25 @@
|
|||
export type RoleType = '' | '*' | 'admin' | 'user';
|
||||
export type SystemScopeType = 'PROJECT' | 'ORGANIZATION' | 'SYSTEM';
|
||||
|
||||
export interface UserRole {
|
||||
createTime: number;
|
||||
updateTime: number;
|
||||
createUser: string;
|
||||
description?: string;
|
||||
id: string;
|
||||
name: string;
|
||||
scopeId: string; // 项目/组织/系统 id
|
||||
type: SystemScopeType;
|
||||
}
|
||||
export interface permissionsItem {
|
||||
id: string;
|
||||
permissionId: string;
|
||||
roleId: string;
|
||||
}
|
||||
export interface UserRolePermissions {
|
||||
userRole: UserRole;
|
||||
userRolePermissions: permissionsItem[];
|
||||
}
|
||||
export interface UserState {
|
||||
name?: string;
|
||||
avatar?: string;
|
||||
|
@ -18,4 +39,5 @@ export interface UserState {
|
|||
role: RoleType;
|
||||
lastOrganizationId?: string;
|
||||
lastProjectId?: string;
|
||||
userRolePermissions?: UserRolePermissions[];
|
||||
}
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
import { useAppStore, useUserStore } from '@/store';
|
||||
import { SystemScopeType, UserRole, UserRolePermissions } from '@/store/modules/user/types';
|
||||
|
||||
export function hasPermission(permission: string, typeList: string[]) {
|
||||
const userStore = useUserStore();
|
||||
if (userStore.isAdmin) {
|
||||
return true;
|
||||
}
|
||||
const { projectPermissions, orgPermissions, systemPermissions } = userStore.currentRole;
|
||||
|
||||
if (typeList.includes('PROJECT') && projectPermissions.includes(permission)) {
|
||||
return true;
|
||||
}
|
||||
if (typeList.includes('ORGANIZATION') && orgPermissions.includes(permission)) {
|
||||
return true;
|
||||
}
|
||||
if (typeList.includes('SYSTEM') && systemPermissions.includes(permission)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 判断是否有权限
|
||||
export function hasAnyPermission(permissions: string[], typeList = ['PROJECT', 'ORGANIZATION', 'SYSTEM']) {
|
||||
return permissions.some((permission) => hasPermission(permission, typeList));
|
||||
}
|
||||
|
||||
function filterProject(role: UserRole, id: string) {
|
||||
return role && role.type === 'PROJECT' && role.scopeId === id;
|
||||
}
|
||||
function filterOrganization(role: UserRole, id: string) {
|
||||
return role && role.type === 'ORGANIZATION' && role.scopeId === id;
|
||||
}
|
||||
function filterSystem(role: UserRole, id: string) {
|
||||
return role && role.type === 'SYSTEM' && role.scopeId === id;
|
||||
}
|
||||
|
||||
export function composePermissions(userRolePermissions: UserRolePermissions[], type: SystemScopeType, id: string) {
|
||||
let func: (role: UserRole, val: string) => boolean;
|
||||
switch (type) {
|
||||
case 'PROJECT':
|
||||
func = filterProject;
|
||||
break;
|
||||
case 'ORGANIZATION':
|
||||
func = filterOrganization;
|
||||
break;
|
||||
default:
|
||||
func = filterSystem;
|
||||
break;
|
||||
}
|
||||
return userRolePermissions
|
||||
.filter((ur) => func(ur.userRole, id))
|
||||
.flatMap((role) => role.userRolePermissions)
|
||||
.map((g) => g.permissionId);
|
||||
}
|
||||
|
||||
// 判断当前一级菜单是否有权限
|
||||
export function hasFirstMenuPermission(menuName: string) {
|
||||
const userStore = useUserStore();
|
||||
const appStore = useAppStore();
|
||||
if (userStore.isAdmin || menuName === 'setting' || menuName === 'projectManagement') {
|
||||
// 如果是超级管理员,或者是系统设置菜单,或者是项目菜单,都有权限
|
||||
return true;
|
||||
}
|
||||
const { currentMenuConfig } = appStore;
|
||||
return currentMenuConfig.includes(menuName);
|
||||
}
|
|
@ -15,6 +15,7 @@
|
|||
:max-length="255"
|
||||
class="w-[732px]"
|
||||
:placeholder="t('project.environmental.envNamePlaceholder')"
|
||||
@blur="store.currentEnvDetailInfo.name = form.name"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
@ -32,20 +33,21 @@
|
|||
<PreTab v-else-if="activeKey === 'pre'" />
|
||||
<PostTab v-else-if="activeKey === 'post'" />
|
||||
<AssertTab v-else-if="activeKey === 'assert'" />
|
||||
<DisplayTab v-else-if="activeKey === 'display'" />
|
||||
</div>
|
||||
|
||||
<div class="footer" :style="{ width: '100%' }">
|
||||
<a-button :disabled="!canSave" @click="handleReset">{{ t('common.cancel') }}</a-button>
|
||||
<a-button @click="handleReset">{{ t('common.cancel') }}</a-button>
|
||||
<a-button :disabled="!canSave" type="primary" @click="handleSave">{{ t('common.save') }}</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { isEqual } from 'lodash-es';
|
||||
|
||||
import AssertTab from './envParams/AssertTab.vue';
|
||||
import DataBaseTab from './envParams/DatabaseTab.vue';
|
||||
import DisplayTab from './envParams/DisplayTab.vue';
|
||||
import EnvParamsTab from './envParams/EnvParamsTab.vue';
|
||||
import HostTab from './envParams/HostTab.vue';
|
||||
import HttpTab from './envParams/HttpTab.vue';
|
||||
|
@ -53,17 +55,17 @@
|
|||
import PreTab from './envParams/PreTab.vue';
|
||||
import TcpTab from './envParams/TcpTab.vue';
|
||||
|
||||
import { updateOrAddEnv } from '@/api/modules/project-management/envManagement';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { useAppStore } from '@/store';
|
||||
import useProjectEnvStore, { NEW_ENV_PARAM } from '@/store/modules/setting/useProjectEnvStore';
|
||||
import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore';
|
||||
|
||||
const activeKey = ref('assert');
|
||||
const envForm = ref();
|
||||
const canSave = ref(false);
|
||||
const { t } = useI18n();
|
||||
const loading = ref(false);
|
||||
|
||||
const store = useProjectEnvStore();
|
||||
const appStore = useAppStore();
|
||||
|
||||
const form = reactive({
|
||||
name: '',
|
||||
|
@ -109,26 +111,42 @@
|
|||
];
|
||||
const handleReset = () => {
|
||||
envForm.value?.resetFields();
|
||||
store.initEnvDetail();
|
||||
};
|
||||
const handleSave = () => {
|
||||
envForm.value?.validate(async (valid) => {
|
||||
if (valid) {
|
||||
console.log('form', form);
|
||||
const handleSave = async () => {
|
||||
await envForm.value?.validate(async (valid) => {
|
||||
if (!valid) {
|
||||
try {
|
||||
loading.value = true;
|
||||
store.currentEnvDetailInfo.mock = true;
|
||||
const res = await updateOrAddEnv(store.currentEnvDetailInfo);
|
||||
store.currentEnvDetailInfo = res;
|
||||
Message.success(t('common.saveSuccess'));
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
const initData = async () => {
|
||||
await store.initEnvDetail();
|
||||
};
|
||||
watchEffect(() => {
|
||||
if (store.currentId === NEW_ENV_PARAM) {
|
||||
store.setEnvDetailInfo({
|
||||
name: '',
|
||||
projectId: appStore.currentProjectId,
|
||||
config: {},
|
||||
});
|
||||
} else {
|
||||
initData();
|
||||
if (store.currentId) {
|
||||
store.initEnvDetail();
|
||||
}
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
if (store.currentEnvDetailInfo) {
|
||||
const { currentEnvDetailInfo } = store;
|
||||
form.name = currentEnvDetailInfo.name;
|
||||
}
|
||||
});
|
||||
watchEffect(() => {
|
||||
if (store.currentEnvDetailInfo) {
|
||||
const { currentEnvDetailInfo, backupEnvDetailInfo } = store;
|
||||
canSave.value = !isEqual(currentEnvDetailInfo, backupEnvDetailInfo);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,15 +1,20 @@
|
|||
<template>
|
||||
<div>
|
||||
<ms-assertion />
|
||||
</div>
|
||||
<MsAssertion v-model:params="params" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import MsAssertion from '@/components/business/ms-assertion/index.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore';
|
||||
|
||||
const { t } = useI18n();
|
||||
const store = useProjectEnvStore();
|
||||
|
||||
const params = computed({
|
||||
set: (value: any) => {
|
||||
store.currentEnvDetailInfo.config.assertions = value;
|
||||
},
|
||||
get: () => store.currentEnvDetailInfo.config.assertions || [],
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
|
|
|
@ -49,9 +49,14 @@
|
|||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const store = useProjectEnvStore();
|
||||
|
||||
const innerParam = computed({
|
||||
get: () => (store.currentEnvDetailInfo.config.dataSource || []) as DataSourceItem[],
|
||||
set: (value: DataSourceItem[] | undefined) => {
|
||||
store.currentEnvDetailInfo.config.dataSource = value;
|
||||
},
|
||||
});
|
||||
const keyword = ref('');
|
||||
const tableStore = useTableStore();
|
||||
const addVisible = ref(false);
|
||||
|
@ -156,21 +161,8 @@
|
|||
addVisible.value = true;
|
||||
};
|
||||
const fetchData = () => {};
|
||||
const handleNoWarning = () => {
|
||||
store.setHttpNoWarning(false);
|
||||
};
|
||||
const initData = () => {
|
||||
propsRes.value.data = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'test',
|
||||
desc: 'test',
|
||||
url: 'test',
|
||||
username: 'test',
|
||||
poolMax: 'test',
|
||||
timeout: 'test',
|
||||
},
|
||||
];
|
||||
propsRes.value.data = innerParam.value;
|
||||
};
|
||||
onMounted(() => {
|
||||
initData();
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
<template>
|
||||
<div class="p-[24px]">
|
||||
<a-divider :margin="0" class="!mb-[16px]" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
|
@ -1,13 +1,22 @@
|
|||
<template>
|
||||
<AllPrams v-model:params="AllParams" :table-key="TableKeyEnum.PROJECT_MANAGEMENT_ENV_ENV_PARAM" />
|
||||
<AllPrams v-model:params="allParams" :table-key="TableKeyEnum.PROJECT_MANAGEMENT_ENV_ENV_PARAM" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import AllPrams from '../allParams/index.vue';
|
||||
|
||||
import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore';
|
||||
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
|
||||
const AllParams = ref<[]>([]);
|
||||
const store = useProjectEnvStore();
|
||||
|
||||
const allParams = computed({
|
||||
set: (value: any) => {
|
||||
store.currentEnvDetailInfo.config.commmonVariables = value;
|
||||
},
|
||||
get: () => store.currentEnvDetailInfo.config.commmonVariables || [],
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="p-[24px]">
|
||||
<div>
|
||||
<div class="flex flex-row items-center gap-[8px]">
|
||||
<a-switch v-model:model-value="configSwitch" size="small" />
|
||||
<a-switch type="line" size="small" />
|
||||
<div class="text-[var(--color-text-1)]">{{ t('project.environmental.host.config') }}</div>
|
||||
</div>
|
||||
<div class="mt-[8px]">
|
||||
|
@ -19,18 +19,31 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onClickOutside } from '@vueuse/core';
|
||||
|
||||
import MsBatchForm from '@/components/business/ms-batch-form/index.vue';
|
||||
import { FormItemModel } from '@/components/business/ms-batch-form/types';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore';
|
||||
|
||||
import { EnvConfigItem } from '@/models/projectManagement/environmental';
|
||||
import { FakeTableListItem } from '@/models/projectManagement/menuManagement';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const currentList = ref<FakeTableListItem[]>([]);
|
||||
const store = useProjectEnvStore();
|
||||
|
||||
const configSwitch = ref<boolean>(false);
|
||||
const currentList = computed({
|
||||
get: () => (store.currentEnvDetailInfo.config.hostConfig || []) as FakeTableListItem[],
|
||||
set: (value: EnvConfigItem[] | undefined) => {
|
||||
store.currentEnvDetailInfo.config.hostConfig = value;
|
||||
},
|
||||
});
|
||||
const batchFormRef = ref();
|
||||
onClickOutside(batchFormRef, () => {
|
||||
currentList.value = batchFormRef.value?.getFormResult();
|
||||
});
|
||||
type UserModalMode = 'create' | 'edit';
|
||||
const batchFormModels: Ref<FormItemModel[]> = ref([
|
||||
{
|
||||
|
|
|
@ -68,6 +68,10 @@
|
|||
const tableStore = useTableStore();
|
||||
const addVisible = ref(false);
|
||||
const currentId = ref('');
|
||||
const innerParam = defineModel<TableData[]>('modelValue', {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
});
|
||||
|
||||
const columns: MsTableColumn = [
|
||||
{
|
||||
|
@ -160,15 +164,7 @@
|
|||
store.setHttpNoWarning(false);
|
||||
};
|
||||
const initData = () => {
|
||||
propsRes.value.data = [
|
||||
{
|
||||
host: 'http://www.baidu.com',
|
||||
desc: '百度',
|
||||
applyScope: '全部',
|
||||
enableScope: '全部',
|
||||
value: 'http://www.baidu.com',
|
||||
},
|
||||
];
|
||||
propsRes.value.data = innerParam.value;
|
||||
};
|
||||
onMounted(() => {
|
||||
initData();
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
<template>
|
||||
<div class="p-[24px]">
|
||||
<a-divider :margin="0" class="!mb-[16px]" />
|
||||
</div>
|
||||
<PostTab v-model:params="params" layout="horizontal" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import PostTab from '@/views/api-test/debug/components/debug/postcondition.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore';
|
||||
|
||||
const store = useProjectEnvStore();
|
||||
|
||||
const params = computed({
|
||||
set: (value: any) => {
|
||||
store.currentEnvDetailInfo.config.postScript = value;
|
||||
},
|
||||
get: () => store.currentEnvDetailInfo.config.postScript || [],
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
<template>
|
||||
<div class="p-[24px]">
|
||||
<a-divider :margin="0" class="!mb-[16px]" />
|
||||
</div>
|
||||
<PreTab v-model:params="params" layout="horizontal" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import PreTab from '@/views/api-test/debug/components/debug/precondition.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore';
|
||||
|
||||
const store = useProjectEnvStore();
|
||||
|
||||
const params = computed({
|
||||
set: (value: any) => {
|
||||
store.currentEnvDetailInfo.config.preScript = value;
|
||||
},
|
||||
get: () => store.currentEnvDetailInfo.config.preScript || [],
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
|
|
|
@ -20,17 +20,33 @@
|
|||
</template>
|
||||
<template #operation="{ record }">
|
||||
<template v-if="record.deleted">
|
||||
<MsButton @click="handleRevokeDelete(record)">{{ t('common.revokeDelete') }}</MsButton>
|
||||
<MsButton v-permission="['SYSTEM_ORGANIZATION_PROJECT:READ+RECOVER']" @click="handleRevokeDelete(record)">{{
|
||||
t('common.revokeDelete')
|
||||
}}</MsButton>
|
||||
</template>
|
||||
<template v-else-if="!record.enable">
|
||||
<MsButton @click="handleEnableOrDisableOrg(record)">{{ t('common.enable') }}</MsButton>
|
||||
<MsButton @click="handleDelete(record)">{{ t('common.delete') }}</MsButton>
|
||||
<MsButton v-permission="['SYSTEM_ORGANIZATIN_PROJECT:READ+UPDATE']" @click="handleEnableOrDisableOrg(record)">{{
|
||||
t('common.enable')
|
||||
}}</MsButton>
|
||||
<MsButton v-permission="['SYSTEM_ORGANIZATIN_PROJECT:READ+DELETE']" @click="handleDelete(record)">{{
|
||||
t('common.delete')
|
||||
}}</MsButton>
|
||||
</template>
|
||||
<template v-else>
|
||||
<MsButton @click="showOrganizationModal(record)">{{ t('common.edit') }}</MsButton>
|
||||
<MsButton @click="showAddUserModal(record)">{{ t('system.organization.addMember') }}</MsButton>
|
||||
<MsButton @click="handleEnableOrDisableOrg(record, false)">{{ t('common.end') }}</MsButton>
|
||||
<MsTableMoreAction :list="tableActions" @select="handleMoreAction($event, record)"></MsTableMoreAction>
|
||||
<MsButton v-permission="['SYSTEM_ORGANIZATIN_PROJECT:READ+UPDATE']" @click="showOrganizationModal(record)">{{
|
||||
t('common.edit')
|
||||
}}</MsButton>
|
||||
<MsButton v-permission="['SYSTEM_ORGANIZATIN_PROJECT:READ']" @click="showAddUserModal(record)">{{
|
||||
t('system.organization.addMember')
|
||||
}}</MsButton>
|
||||
<MsButton v-permission="['SYSTEM_ORGANIZATIN_PROJECT:READ']" @click="handleEnableOrDisableOrg(record, false)">{{
|
||||
t('common.end')
|
||||
}}</MsButton>
|
||||
<MsTableMoreAction
|
||||
v-permission="['SYSTEM_ORGANIZATIN_PROJECT:READ+DELETE']"
|
||||
:list="tableActions"
|
||||
@select="handleMoreAction($event, record)"
|
||||
></MsTableMoreAction>
|
||||
</template>
|
||||
</template>
|
||||
</MsBaseTable>
|
||||
|
|
|
@ -17,17 +17,37 @@
|
|||
</template>
|
||||
<template #operation="{ record }">
|
||||
<template v-if="record.deleted">
|
||||
<MsButton @click="handleRevokeDelete(record)">{{ t('common.revokeDelete') }}</MsButton>
|
||||
<MsButton v-permission="['SYSTEM_ORGANIZATION_PROJECT:READ+RECOVER']" @click="handleRevokeDelete(record)">{{
|
||||
t('common.revokeDelete')
|
||||
}}</MsButton>
|
||||
</template>
|
||||
<template v-else-if="!record.enable">
|
||||
<MsButton @click="handleEnableOrDisableProject(record)">{{ t('common.enable') }}</MsButton>
|
||||
<MsButton @click="handleDelete(record)">{{ t('common.delete') }}</MsButton>
|
||||
<MsButton
|
||||
v-permission="['SYSTEM_ORGANIZATIN_PROJECT:READ+UPDATE']"
|
||||
@click="handleEnableOrDisableProject(record)"
|
||||
>{{ t('common.enable') }}</MsButton
|
||||
>
|
||||
<MsButton v-permission="['SYSTEM_ORGANIZATIN_PROJECT:READ+DELETE']" @click="handleDelete(record)">{{
|
||||
t('common.delete')
|
||||
}}</MsButton>
|
||||
</template>
|
||||
<template v-else>
|
||||
<MsButton @click="showAddProjectModal(record)">{{ t('common.edit') }}</MsButton>
|
||||
<MsButton @click="showAddUserModal(record)">{{ t('system.organization.addMember') }}</MsButton>
|
||||
<MsButton @click="handleEnableOrDisableProject(record, false)">{{ t('common.end') }}</MsButton>
|
||||
<MsTableMoreAction :list="tableActions" @select="handleMoreAction($event, record)"></MsTableMoreAction>
|
||||
<MsButton v-permission="['SYSTEM_ORGANIZATIN_PROJECT:READ+UPDATE']" @click="showAddProjectModal(record)">{{
|
||||
t('common.edit')
|
||||
}}</MsButton>
|
||||
<MsButton v-permission="['SYSTEM_ORGANIZATIN_PROJECT:READ']" @click="showAddUserModal(record)">{{
|
||||
t('system.organization.addMember')
|
||||
}}</MsButton>
|
||||
<MsButton
|
||||
v-permission="['SYSTEM_ORGANIZATIN_PROJECT:READ+UPDATE']"
|
||||
@click="handleEnableOrDisableProject(record, false)"
|
||||
>{{ t('common.end') }}</MsButton
|
||||
>
|
||||
<MsTableMoreAction
|
||||
v-permission="['SYSTEM_ORGANIZATIN_PROJECT:READ+DELETE']"
|
||||
:list="tableActions"
|
||||
@select="handleMoreAction($event, record)"
|
||||
></MsTableMoreAction>
|
||||
</template>
|
||||
</template>
|
||||
</MsBaseTable>
|
||||
|
|
Loading…
Reference in New Issue