mirror of
https://gitee.com/fit2cloud-feizhiyun/MeterSphere.git
synced 2024-12-12 13:05:13 +08:00
feat(系统设置): 授权管理到期需求添加&环境bug&优化用例管理菜单空白问题
This commit is contained in:
parent
08b638b0d6
commit
c4744ceeb2
@ -5,6 +5,7 @@ import {
|
|||||||
AddDemandUrl,
|
AddDemandUrl,
|
||||||
AddDependOnRelationUrl,
|
AddDependOnRelationUrl,
|
||||||
AssociatedDebuggerUrl,
|
AssociatedDebuggerUrl,
|
||||||
|
associatedProjectOptionsUrl,
|
||||||
BatchAssociationDemandUrl,
|
BatchAssociationDemandUrl,
|
||||||
BatchCopyCaseUrl,
|
BatchCopyCaseUrl,
|
||||||
BatchDeleteCaseUrl,
|
BatchDeleteCaseUrl,
|
||||||
@ -94,6 +95,7 @@ import type {
|
|||||||
UpdateModule,
|
UpdateModule,
|
||||||
} from '@/models/caseManagement/featureCase';
|
} from '@/models/caseManagement/featureCase';
|
||||||
import type { CommonList, ModuleTreeNode, MoveModules, TableQueryParams } from '@/models/common';
|
import type { CommonList, ModuleTreeNode, MoveModules, TableQueryParams } from '@/models/common';
|
||||||
|
import { ProjectListItem } from '@/models/setting/project';
|
||||||
|
|
||||||
// 获取模块树
|
// 获取模块树
|
||||||
export function getCaseModuleTree(params: TableQueryParams) {
|
export function getCaseModuleTree(params: TableQueryParams) {
|
||||||
@ -421,5 +423,9 @@ export function dragSort(data: DragCase) {
|
|||||||
export function getChangeHistoryList(data: TableQueryParams) {
|
export function getChangeHistoryList(data: TableQueryParams) {
|
||||||
return MSR.post<CommonList<ChangeHistoryItem>>({ url: getChangeHistoryListUrl, data });
|
return MSR.post<CommonList<ChangeHistoryItem>>({ url: getChangeHistoryListUrl, data });
|
||||||
}
|
}
|
||||||
|
// 获取已关联缺陷列表
|
||||||
|
export function getAssociatedProjectOptions(orgId: string, module: string) {
|
||||||
|
return MSR.get<ProjectListItem[]>({ url: `${associatedProjectOptionsUrl}/${orgId}/${module}` });
|
||||||
|
}
|
||||||
|
|
||||||
export default {};
|
export default {};
|
||||||
|
@ -149,3 +149,5 @@ export const dragSortUrl = '/functional/case/edit/pos';
|
|||||||
export const getChangeHistoryListUrl = '/functional/case/operation-history';
|
export const getChangeHistoryListUrl = '/functional/case/operation-history';
|
||||||
// 取消关联用例
|
// 取消关联用例
|
||||||
export const cancelDisassociate = '/functional/case/test/disassociate/case';
|
export const cancelDisassociate = '/functional/case/test/disassociate/case';
|
||||||
|
// 关联用例关联功能用例项目下拉
|
||||||
|
export const associatedProjectOptionsUrl = '/project/list/options';
|
||||||
|
@ -363,7 +363,7 @@
|
|||||||
import { TableColumnData, TableData } from '@arco-design/web-vue';
|
import { TableColumnData, TableData } from '@arco-design/web-vue';
|
||||||
import { cloneDeep } from 'lodash-es';
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
|
||||||
import { statusCodeOptions } from '@/components/pure/ms-advance-filter';
|
import { EQUAL, statusCodeOptions } from '@/components/pure/ms-advance-filter';
|
||||||
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||||
import { TableOperationColumn } from '@/components/business/ms-user-group-comp/authTable.vue';
|
import { TableOperationColumn } from '@/components/business/ms-user-group-comp/authTable.vue';
|
||||||
import fastExtraction from '@/views/api-test/components/fastExtraction/index.vue';
|
import fastExtraction from '@/views/api-test/components/fastExtraction/index.vue';
|
||||||
@ -513,6 +513,7 @@
|
|||||||
variableType: RequestExtractEnvType.TEMPORARY,
|
variableType: RequestExtractEnvType.TEMPORARY,
|
||||||
extractScope: RequestExtractScope.BODY,
|
extractScope: RequestExtractScope.BODY,
|
||||||
expression: '',
|
expression: '',
|
||||||
|
condition: EQUAL.value,
|
||||||
extractType: RequestExtractExpressionEnum.JSON_PATH,
|
extractType: RequestExtractExpressionEnum.JSON_PATH,
|
||||||
expressionMatchingRule: RequestExtractExpressionRuleType.EXPRESSION,
|
expressionMatchingRule: RequestExtractExpressionRuleType.EXPRESSION,
|
||||||
resultMatchingRule: RequestExtractResultMatchingRule.RANDOM,
|
resultMatchingRule: RequestExtractResultMatchingRule.RANDOM,
|
||||||
|
@ -24,11 +24,24 @@
|
|||||||
<div class="flex h-full">
|
<div class="flex h-full">
|
||||||
<div class="w-[292px] border-r border-[var(--color-text-n8)] p-[16px]">
|
<div class="w-[292px] border-r border-[var(--color-text-n8)] p-[16px]">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<MsProjectSelect
|
<div v-if="!props.hideProjectSelect" class="flex w-full flex-1">
|
||||||
v-if="innerProject && !props.hideProjectSelect"
|
<a-select
|
||||||
v-model:project="innerProject"
|
v-model="innerProject"
|
||||||
class="mb-[16px]"
|
class="mb-[16px] flex-1"
|
||||||
/>
|
:default-value="innerProject"
|
||||||
|
allow-search
|
||||||
|
:placeholder="t('common.pleaseSelect')"
|
||||||
|
>
|
||||||
|
<template #arrow-icon>
|
||||||
|
<icon-caret-down />
|
||||||
|
</template>
|
||||||
|
<a-tooltip v-for="item of projectList" :key="item.id" :mouse-enter-delay="500" :content="item.name">
|
||||||
|
<a-option :value="item.id" :class="item.id === innerProject ? 'arco-select-option-selected' : ''">
|
||||||
|
{{ item.name }}
|
||||||
|
</a-option>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-select>
|
||||||
|
</div>
|
||||||
<a-select v-if="caseType === 'API'" v-model="protocolType" class="mb-[16px] ml-2 max-w-[90px]">
|
<a-select v-if="caseType === 'API'" v-model="protocolType" class="mb-[16px] ml-2 max-w-[90px]">
|
||||||
<a-option v-for="item of protocolOptions" :key="item" :value="item">{{ item }}</a-option>
|
<a-option v-for="item of protocolOptions" :key="item" :value="item">{{ item }}</a-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
@ -159,13 +172,15 @@
|
|||||||
import type { MsTreeNodeData } from '@/components/business/ms-tree/types';
|
import type { MsTreeNodeData } from '@/components/business/ms-tree/types';
|
||||||
import caseLevel from './caseLevel.vue';
|
import caseLevel from './caseLevel.vue';
|
||||||
|
|
||||||
import { getCustomFieldsTable } from '@/api/modules/case-management/featureCase';
|
import { getAssociatedProjectOptions, getCustomFieldsTable } from '@/api/modules/case-management/featureCase';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
import { mapTree } from '@/utils';
|
import { mapTree } from '@/utils';
|
||||||
|
|
||||||
import type { CaseManagementTable } from '@/models/caseManagement/featureCase';
|
import type { CaseManagementTable } from '@/models/caseManagement/featureCase';
|
||||||
import type { CommonList, ModuleTreeNode, TableQueryParams } from '@/models/common';
|
import type { CommonList, ModuleTreeNode, TableQueryParams } from '@/models/common';
|
||||||
|
import type { ProjectListItem } from '@/models/setting/project';
|
||||||
|
import { CaseLinkEnum } from '@/enums/caseEnum';
|
||||||
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
|
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
|
||||||
|
|
||||||
import type { CaseLevel } from './types';
|
import type { CaseLevel } from './types';
|
||||||
@ -185,7 +200,7 @@
|
|||||||
getTableFunc: (params: TableQueryParams) => Promise<CommonList<CaseManagementTable>>; // 获取表请求函数
|
getTableFunc: (params: TableQueryParams) => Promise<CommonList<CaseManagementTable>>; // 获取表请求函数
|
||||||
tableParams?: TableQueryParams; // 查询表格的额外的参数
|
tableParams?: TableQueryParams; // 查询表格的额外的参数
|
||||||
okButtonDisabled?: boolean; // 确认按钮是否禁用
|
okButtonDisabled?: boolean; // 确认按钮是否禁用
|
||||||
currentSelectCase: string | number | Record<string, any> | undefined; // 当前选中的用例类型
|
currentSelectCase: keyof typeof CaseLinkEnum; // 当前选中的用例类型
|
||||||
moduleOptions?: { label: string; value: string }[]; // 功能模块对应用例下拉
|
moduleOptions?: { label: string; value: string }[]; // 功能模块对应用例下拉
|
||||||
confirmLoading: boolean;
|
confirmLoading: boolean;
|
||||||
associatedIds: string[]; // 已关联用例id集合用于去重已关联
|
associatedIds: string[]; // 已关联用例id集合用于去重已关联
|
||||||
@ -239,7 +254,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const innerVisible = useVModel(props, 'visible', emit);
|
const innerVisible = useVModel(props, 'visible', emit);
|
||||||
const innerProject = useVModel(props, 'projectId', emit);
|
const innerProject = ref<string | undefined>(props.projectId);
|
||||||
|
|
||||||
const protocolType = ref('HTTP'); // 协议类型
|
const protocolType = ref('HTTP'); // 协议类型
|
||||||
const protocolOptions = ref(['HTTP']);
|
const protocolOptions = ref(['HTTP']);
|
||||||
@ -323,6 +338,7 @@
|
|||||||
|
|
||||||
const keyword = ref('');
|
const keyword = ref('');
|
||||||
const version = ref('');
|
const version = ref('');
|
||||||
|
const projectList = ref<ProjectListItem[]>([]);
|
||||||
|
|
||||||
function getCaseLevelColumn() {
|
function getCaseLevelColumn() {
|
||||||
if (!props.isHiddenCaseLevel) {
|
if (!props.isHiddenCaseLevel) {
|
||||||
@ -576,6 +592,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function initProjectList(setDefault: boolean) {
|
||||||
|
try {
|
||||||
|
projectList.value = await getAssociatedProjectOptions(appStore.currentOrgId, caseType.value);
|
||||||
|
if (setDefault) {
|
||||||
|
innerProject.value = projectList.value[0].id;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function searchCase() {
|
function searchCase() {
|
||||||
getLoadListParams();
|
getLoadListParams();
|
||||||
loadList();
|
loadList();
|
||||||
@ -631,10 +658,14 @@
|
|||||||
() => props.visible,
|
() => props.visible,
|
||||||
(val) => {
|
(val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
|
if (!props.hideProjectSelect) {
|
||||||
|
initProjectList(true);
|
||||||
|
} else {
|
||||||
resetSelector();
|
resetSelector();
|
||||||
initModules();
|
initModules();
|
||||||
searchCase();
|
searchCase();
|
||||||
initFilter();
|
initFilter();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
cancel();
|
cancel();
|
||||||
}
|
}
|
||||||
@ -655,10 +686,12 @@
|
|||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => innerProject.value,
|
() => innerProject.value,
|
||||||
() => {
|
(val) => {
|
||||||
if (innerVisible.value) {
|
if (val) {
|
||||||
searchCase();
|
resetSelector();
|
||||||
initModules();
|
initModules();
|
||||||
|
searchCase();
|
||||||
|
initFilter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -128,7 +128,7 @@ function replaceRestParams(path: string, restMap: Record<string, any>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 返回最终groovyCode 代码模板片段
|
// 返回最终groovyCode 代码模板片段
|
||||||
function _groovyCodeTemplate(obj: Record<string, any>) {
|
export function _groovyCodeTemplate(obj: Record<string, any>) {
|
||||||
const { requestUrl, requestMethod, headers, body } = obj;
|
const { requestUrl, requestMethod, headers, body } = obj;
|
||||||
const params = `[
|
const params = `[
|
||||||
'url': '${requestUrl}',
|
'url': '${requestUrl}',
|
||||||
|
@ -26,8 +26,12 @@
|
|||||||
|
|
||||||
import MsSelect from '@/components/business/ms-select/index';
|
import MsSelect from '@/components/business/ms-select/index';
|
||||||
|
|
||||||
|
import { useUserStore } from '@/store';
|
||||||
|
|
||||||
import initOptionsFunc, { UserRequestTypeEnum } from './utils';
|
import initOptionsFunc, { UserRequestTypeEnum } from './utils';
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
|
||||||
defineOptions({ name: 'MsUserSelector' });
|
defineOptions({ name: 'MsUserSelector' });
|
||||||
|
|
||||||
export interface MsUserSelectorOption {
|
export interface MsUserSelectorOption {
|
||||||
|
@ -2,12 +2,14 @@ import { App } from 'vue';
|
|||||||
|
|
||||||
import outerClick from './outerClick';
|
import outerClick from './outerClick';
|
||||||
import permission from './permission';
|
import permission from './permission';
|
||||||
|
import validateExpiration from './validateExpiration';
|
||||||
import validateLicense from './validateLicense';
|
import validateLicense from './validateLicense';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
install(Vue: App) {
|
install(Vue: App) {
|
||||||
Vue.directive('permission', permission);
|
Vue.directive('permission', permission);
|
||||||
Vue.directive('xpack', validateLicense);
|
Vue.directive('xpack', validateLicense);
|
||||||
|
Vue.directive('expire', validateExpiration);
|
||||||
Vue.directive('outer', outerClick);
|
Vue.directive('outer', outerClick);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
26
frontend/src/directive/validateExpiration/index.ts
Normal file
26
frontend/src/directive/validateExpiration/index.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { useAppStore } from '@/store';
|
||||||
|
import useLicenseStore from '@/store/modules/setting/license';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 权限指令,TODO:校验license
|
||||||
|
* @param el dom 节点
|
||||||
|
*/
|
||||||
|
|
||||||
|
function checkHasLicenseExpiration(el: HTMLElement) {
|
||||||
|
const licenseStore = useLicenseStore();
|
||||||
|
const appStore = useAppStore();
|
||||||
|
const isValid = licenseStore.expiredDuring && appStore.packageType === 'enterprise';
|
||||||
|
|
||||||
|
if (!isValid && el.parentNode) {
|
||||||
|
el.parentNode.removeChild(el);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
mounted(el: HTMLElement) {
|
||||||
|
checkHasLicenseExpiration(el);
|
||||||
|
},
|
||||||
|
updated(el: HTMLElement) {
|
||||||
|
checkHasLicenseExpiration(el);
|
||||||
|
},
|
||||||
|
};
|
@ -20,4 +20,12 @@ export enum LastExecuteResults {
|
|||||||
FAILED = 'FAILED',
|
FAILED = 'FAILED',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum CaseLinkEnum {
|
||||||
|
API = 'API',
|
||||||
|
SCENARIO = 'SCENARIO',
|
||||||
|
UI = 'UI',
|
||||||
|
PERFORMANCE = 'PERFORMANCE',
|
||||||
|
FUNCTIONAL = 'FUNCTIONAL',
|
||||||
|
}
|
||||||
|
|
||||||
export default {};
|
export default {};
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
import { getLicenseInfo } from '@/api/modules/setting/authorizedManagement';
|
import { getLicenseInfo } from '@/api/modules/setting/authorizedManagement';
|
||||||
|
|
||||||
const useLicenseStore = defineStore('license', {
|
const useLicenseStore = defineStore('license', {
|
||||||
persist: true,
|
persist: true,
|
||||||
state: (): { status: string | null } => ({
|
state: (): { status: string | null; expiredDuring: boolean; expiredDays: number } => ({
|
||||||
status: '',
|
status: '',
|
||||||
|
expiredDuring: false,
|
||||||
|
expiredDays: 0,
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
setLicenseStatus(status: string) {
|
setLicenseStatus(status: string) {
|
||||||
@ -17,6 +20,21 @@ const useLicenseStore = defineStore('license', {
|
|||||||
hasLicense() {
|
hasLicense() {
|
||||||
return this.status && this.status === 'valid';
|
return this.status && this.status === 'valid';
|
||||||
},
|
},
|
||||||
|
getExpirationTime(resTime: string) {
|
||||||
|
const today = Date.now();
|
||||||
|
const startDate = dayjs(today).format('YYYY-MM-DD');
|
||||||
|
const endDate = dayjs(resTime);
|
||||||
|
|
||||||
|
const daysDifference = endDate.diff(startDate, 'day');
|
||||||
|
this.expiredDays = daysDifference;
|
||||||
|
if (daysDifference <= 30 && daysDifference >= 0) {
|
||||||
|
this.expiredDuring = true;
|
||||||
|
} else if (daysDifference <= 0 && daysDifference >= -30) {
|
||||||
|
this.expiredDuring = true;
|
||||||
|
} else {
|
||||||
|
this.expiredDuring = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
// license校验
|
// license校验
|
||||||
async getValidateLicense() {
|
async getValidateLicense() {
|
||||||
try {
|
try {
|
||||||
@ -25,6 +43,8 @@ const useLicenseStore = defineStore('license', {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.setLicenseStatus(result.status);
|
this.setLicenseStatus(result.status);
|
||||||
|
// 计算license时间
|
||||||
|
this.getExpirationTime(result.license.expired);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
<transition name="fade">
|
<transition name="fade">
|
||||||
<div v-show="!expandIds.includes(item.value) && isShowContent(item.value)" class="expandContent">
|
<div v-show="!expandIds.includes(item.value) && isShowContent(item.value)" class="expandContent">
|
||||||
<div v-if="item.value === ResponseComposition.BODY" class="res-item">
|
<div v-if="item.value === ResponseComposition.BODY" class="res-item">
|
||||||
<ResBody :request-result="props.requestResult" @copy="copyScript" />
|
<ResBody ref="resBodyRef" :request-result="props.requestResult" @copy="copyScript" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!expandIds.includes(item.value) && item.value === ResponseComposition.CONSOLE" class="res-item">
|
<div v-if="!expandIds.includes(item.value) && item.value === ResponseComposition.CONSOLE" class="res-item">
|
||||||
<ResConsole :console="props.console?.trim()" />
|
<ResConsole :console="props.console?.trim()" />
|
||||||
@ -92,9 +92,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const { copy, isSupported } = useClipboard({ legacy: true });
|
const { copy, isSupported } = useClipboard({ legacy: true });
|
||||||
|
|
||||||
|
const resBodyRef = ref();
|
||||||
function copyScript() {
|
function copyScript() {
|
||||||
|
const encodingFormatValue = resBodyRef.value.responseEditorRef.getEncodingCode();
|
||||||
if (isSupported) {
|
if (isSupported) {
|
||||||
copy(props.requestResult?.responseResult.body || '');
|
copy(encodingFormatValue || '');
|
||||||
Message.success(t('common.copySuccess'));
|
Message.success(t('common.copySuccess'));
|
||||||
} else {
|
} else {
|
||||||
Message.warning(t('apiTestDebug.copyNotSupport'));
|
Message.warning(t('apiTestDebug.copyNotSupport'));
|
||||||
|
@ -70,7 +70,7 @@
|
|||||||
/>
|
/>
|
||||||
{{ t('caseManagement.featureCase.follow') }}
|
{{ t('caseManagement.featureCase.follow') }}
|
||||||
</MsButton>
|
</MsButton>
|
||||||
<MsButton type="icon" status="secondary" class="!rounded-[var(--border-radius-small)]">
|
<MsButton type="icon" status="secondary" class="mr-2 !rounded-[var(--border-radius-small)]">
|
||||||
<a-dropdown position="br" :hide-on-select="false">
|
<a-dropdown position="br" :hide-on-select="false">
|
||||||
<div>
|
<div>
|
||||||
<icon-more class="mr-1" />
|
<icon-more class="mr-1" />
|
||||||
|
@ -111,6 +111,7 @@
|
|||||||
import { hasAnyPermission } from '@/utils/permission';
|
import { hasAnyPermission } from '@/utils/permission';
|
||||||
|
|
||||||
import type { TableQueryParams } from '@/models/common';
|
import type { TableQueryParams } from '@/models/common';
|
||||||
|
import { CaseLinkEnum } from '@/enums/caseEnum';
|
||||||
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
|
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
|
||||||
|
|
||||||
import Message from '@arco-design/web-vue/es/message';
|
import Message from '@arco-design/web-vue/es/message';
|
||||||
@ -201,7 +202,7 @@
|
|||||||
|
|
||||||
const associatedIds = ref<string[]>([]);
|
const associatedIds = ref<string[]>([]);
|
||||||
|
|
||||||
const currentSelectCase = ref<string>('');
|
const currentSelectCase = ref<keyof typeof CaseLinkEnum>('FUNCTIONAL');
|
||||||
|
|
||||||
const modulesTreeParams = ref<TableQueryParams>({});
|
const modulesTreeParams = ref<TableQueryParams>({});
|
||||||
|
|
||||||
@ -233,7 +234,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const caseTypeOptions = ref<{ label: string; value: string }[]>([]);
|
const caseTypeOptions = ref<{ label: string; value: string }[]>([
|
||||||
|
{
|
||||||
|
label: 'menu.caseManagement.featureCase',
|
||||||
|
value: 'FUNCTIONAL',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
const modulesCount = ref<Record<string, any>>({});
|
const modulesCount = ref<Record<string, any>>({});
|
||||||
|
|
||||||
@ -255,25 +261,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const moduleMaps: Record<string, { label: string; value: string }[]> = {
|
|
||||||
caseManagement: [
|
|
||||||
{
|
|
||||||
value: 'FUNCTIONAL',
|
|
||||||
label: t('menu.caseManagement.featureCase'),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
async function getEnabledModules() {
|
|
||||||
const result = await postTabletList({ projectId: currentProjectId.value });
|
|
||||||
const caseArr = result.filter((item) => Object.keys(moduleMaps).includes(item.module));
|
|
||||||
caseArr.forEach((item: any) => {
|
|
||||||
const currentModule = moduleMaps[item.module];
|
|
||||||
caseTypeOptions.value.push(...currentModule);
|
|
||||||
});
|
|
||||||
currentSelectCase.value = caseTypeOptions.value[0].value;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function searchCase() {
|
async function searchCase() {
|
||||||
setKeyword(keyword.value);
|
setKeyword(keyword.value);
|
||||||
setLoadListParams({
|
setLoadListParams({
|
||||||
@ -300,14 +287,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
getEnabledModules();
|
|
||||||
getFetch();
|
getFetch();
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.bugId,
|
() => props.bugId,
|
||||||
() => {
|
() => {
|
||||||
getEnabledModules();
|
|
||||||
getFetch();
|
getFetch();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -803,7 +803,10 @@
|
|||||||
|
|
||||||
function renameCopyBug() {
|
function renameCopyBug() {
|
||||||
if (isCopy.value) {
|
if (isCopy.value) {
|
||||||
form.value.title = `copy_${form.value.title}`;
|
const copyName = `copy_${form.value.title}`;
|
||||||
|
if (copyName.length > 255) {
|
||||||
|
form.value.title = copyName.slice(0, 255);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@
|
|||||||
/>
|
/>
|
||||||
{{ t('caseManagement.featureCase.follow') }}
|
{{ t('caseManagement.featureCase.follow') }}
|
||||||
</MsButton>
|
</MsButton>
|
||||||
<MsButton type="icon" status="secondary" class="!rounded-[var(--border-radius-small)]">
|
<MsButton type="icon" status="secondary" class="mr-2 !rounded-[var(--border-radius-small)]">
|
||||||
<a-dropdown position="br" :hide-on-select="false">
|
<a-dropdown position="br" :hide-on-select="false">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<icon-more class="mr-2" />
|
<icon-more class="mr-2" />
|
||||||
@ -238,7 +238,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
@ -395,14 +395,14 @@
|
|||||||
historyCount,
|
historyCount,
|
||||||
} = detail;
|
} = detail;
|
||||||
const countMap: Record<string, any> = {
|
const countMap: Record<string, any> = {
|
||||||
case: caseCount,
|
case: caseCount || '0',
|
||||||
dependency: relateEdgeCount,
|
dependency: relateEdgeCount || '0',
|
||||||
caseReview: caseReviewCount,
|
caseReview: caseReviewCount || '0',
|
||||||
testPlan: testPlanCount,
|
testPlan: testPlanCount || '0',
|
||||||
bug: bugCount,
|
bug: bugCount || '0',
|
||||||
requirement: demandCount,
|
requirement: demandCount || '0',
|
||||||
comments: commentCount,
|
comments: commentCount || '0',
|
||||||
changeHistory: historyCount,
|
changeHistory: historyCount || '0',
|
||||||
};
|
};
|
||||||
featureCaseStore.initCountMap(countMap);
|
featureCaseStore.initCountMap(countMap);
|
||||||
}
|
}
|
||||||
@ -639,6 +639,9 @@
|
|||||||
canHide: true,
|
canHide: true,
|
||||||
isShow: true,
|
isShow: true,
|
||||||
},
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const caseTab: TabItemType[] = [
|
||||||
{
|
{
|
||||||
value: 'dependency',
|
value: 'dependency',
|
||||||
label: t('caseManagement.featureCase.dependency'),
|
label: t('caseManagement.featureCase.dependency'),
|
||||||
@ -664,9 +667,8 @@
|
|||||||
isShow: true,
|
isShow: true,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
let buggerTab: TabItemType[] = [];
|
|
||||||
const moduleTabMap: Record<string, TabItemType[]> = {
|
const buggerTab: TabItemType[] = [
|
||||||
bugManagement: [
|
|
||||||
{
|
{
|
||||||
value: 'requirement',
|
value: 'requirement',
|
||||||
label: t('caseManagement.featureCase.requirement'),
|
label: t('caseManagement.featureCase.requirement'),
|
||||||
@ -679,28 +681,17 @@
|
|||||||
canHide: true,
|
canHide: true,
|
||||||
isShow: true,
|
isShow: true,
|
||||||
},
|
},
|
||||||
],
|
];
|
||||||
};
|
|
||||||
|
|
||||||
let newTabDefaultSettingList: TabItemType[] = [];
|
// 计算模块开启是否展示缺陷和需求
|
||||||
/**
|
const newTabDefaultSettingList = computed(() => {
|
||||||
* 获取开启的模块
|
if (appStore.currentMenuConfig.includes('bugManagement')) {
|
||||||
*/
|
return [...tabDefaultSettingList, ...buggerTab, ...caseTab];
|
||||||
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]);
|
|
||||||
}
|
}
|
||||||
|
return [...tabDefaultSettingList, ...caseTab];
|
||||||
});
|
});
|
||||||
newTabDefaultSettingList = [...tabDefaultSettingList.slice(0, 2), ...buggerTab, ...tabDefaultSettingList.slice(2)];
|
|
||||||
}
|
|
||||||
|
|
||||||
await getTabModule();
|
featureCaseStore.initContentTabList([...newTabDefaultSettingList.value]);
|
||||||
|
|
||||||
featureCaseStore.initContentTabList(newTabDefaultSettingList);
|
|
||||||
tabSetting.value = ((await featureCaseStore.getContentTabList()) || []).filter((item) => item.isShow);
|
tabSetting.value = ((await featureCaseStore.getContentTabList()) || []).filter((item) => item.isShow);
|
||||||
|
|
||||||
async function handleUploadImage(file: File) {
|
async function handleUploadImage(file: File) {
|
||||||
|
@ -51,7 +51,6 @@
|
|||||||
</ms-base-table>
|
</ms-base-table>
|
||||||
<MsCaseAssociate
|
<MsCaseAssociate
|
||||||
v-model:visible="innerVisible"
|
v-model:visible="innerVisible"
|
||||||
v-model:project-id="innerProject"
|
|
||||||
v-model:currentSelectCase="currentSelectCase"
|
v-model:currentSelectCase="currentSelectCase"
|
||||||
:ok-button-disabled="associateForm.reviewers.length === 0"
|
:ok-button-disabled="associateForm.reviewers.length === 0"
|
||||||
:get-modules-func="getPublicLinkModuleTree"
|
:get-modules-func="getPublicLinkModuleTree"
|
||||||
@ -95,6 +94,7 @@
|
|||||||
import { hasAnyPermission } from '@/utils/permission';
|
import { hasAnyPermission } from '@/utils/permission';
|
||||||
|
|
||||||
import type { TableQueryParams } from '@/models/common';
|
import type { TableQueryParams } from '@/models/common';
|
||||||
|
import { CaseLinkEnum } from '@/enums/caseEnum';
|
||||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||||
|
|
||||||
import Message from '@arco-design/web-vue/es/message';
|
import Message from '@arco-design/web-vue/es/message';
|
||||||
@ -190,19 +190,17 @@
|
|||||||
|
|
||||||
const associatedIds = ref<string[]>([]);
|
const associatedIds = ref<string[]>([]);
|
||||||
|
|
||||||
const currentSelectCase = ref<string>('');
|
const currentSelectCase = ref<keyof typeof CaseLinkEnum>('API');
|
||||||
|
|
||||||
const modulesTreeParams = ref<TableQueryParams>({});
|
const modulesTreeParams = ref<TableQueryParams>({});
|
||||||
|
|
||||||
const getTableParams = ref<TableQueryParams>({});
|
const getTableParams = ref<TableQueryParams>({});
|
||||||
|
|
||||||
function handleSelect(value: string | number | Record<string, any> | undefined) {
|
function handleSelect(value: string | number | Record<string, any> | undefined) {
|
||||||
currentSelectCase.value = value as string;
|
currentSelectCase.value = value as keyof typeof CaseLinkEnum;
|
||||||
innerVisible.value = true;
|
innerVisible.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const caseTypeOptions = ref<{ label: string; value: string }[]>([]);
|
|
||||||
|
|
||||||
const modulesCount = ref<Record<string, any>>({});
|
const modulesCount = ref<Record<string, any>>({});
|
||||||
|
|
||||||
const confirmLoading = ref<boolean>(false);
|
const confirmLoading = ref<boolean>(false);
|
||||||
@ -235,8 +233,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const moduleMaps: Record<string, { label: string; value: string }[]> = {
|
// @desc 这个模块不使用动态获取模块需求调整目前这些菜单也写死
|
||||||
apiTest: [
|
const caseTypeOptions = ref<{ label: string; value: keyof typeof CaseLinkEnum }[]>([
|
||||||
{
|
{
|
||||||
value: 'API',
|
value: 'API',
|
||||||
label: t('caseManagement.featureCase.apiCase'),
|
label: t('caseManagement.featureCase.apiCase'),
|
||||||
@ -245,34 +243,16 @@
|
|||||||
value: 'SCENARIO',
|
value: 'SCENARIO',
|
||||||
label: t('caseManagement.featureCase.sceneCase'),
|
label: t('caseManagement.featureCase.sceneCase'),
|
||||||
},
|
},
|
||||||
],
|
// TODO 这个版本不显示
|
||||||
// uiTest: [
|
|
||||||
// {
|
// {
|
||||||
// value: 'UI',
|
// value: 'UI',
|
||||||
// label: t('caseManagement.featureCase.uiCase'),
|
// label: t('caseManagement.featureCase.uiCase'),
|
||||||
// },
|
// },
|
||||||
// ],
|
|
||||||
// loadTest: [
|
|
||||||
// {
|
// {
|
||||||
// value: 'PERFORMANCE',
|
// value: 'PERFORMANCE',
|
||||||
// label: t('caseManagement.featureCase.propertyCase'),
|
// label: t('caseManagement.featureCase.propertyCase'),
|
||||||
// },
|
// },
|
||||||
// ],
|
]);
|
||||||
};
|
|
||||||
|
|
||||||
async function getEnabledModules() {
|
|
||||||
// const result = await postTabletList({ projectId: currentProjectId.value });
|
|
||||||
// const caseArr = result.filter((item) => Object.keys(moduleMaps).includes(item.module));
|
|
||||||
// caseArr.forEach((item: any) => {
|
|
||||||
// const currentModule = moduleMaps[item.module];
|
|
||||||
// caseTypeOptions.value.push(...currentModule);
|
|
||||||
// });
|
|
||||||
Object.keys(moduleMaps).forEach((item: any) => {
|
|
||||||
const currentModule = moduleMaps[item];
|
|
||||||
caseTypeOptions.value.push(...currentModule);
|
|
||||||
});
|
|
||||||
currentSelectCase.value = caseTypeOptions.value[0].value;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function cancelLink(record: any) {
|
async function cancelLink(record: any) {
|
||||||
try {
|
try {
|
||||||
@ -292,20 +272,8 @@
|
|||||||
setKeyword(keyword.value);
|
setKeyword(keyword.value);
|
||||||
await loadList();
|
await loadList();
|
||||||
}
|
}
|
||||||
const activeTab = computed(() => featureCaseStore.activeTab);
|
|
||||||
|
|
||||||
// watch(
|
|
||||||
// () => activeTab.value,
|
|
||||||
// (val) => {
|
|
||||||
// if (val === 'case') {
|
|
||||||
// getEnabledModules();
|
|
||||||
// getFetch();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
getEnabledModules();
|
|
||||||
getFetch();
|
getFetch();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -88,6 +88,7 @@
|
|||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
|
|
||||||
import { BaseAssociateCaseRequest } from '@/models/caseManagement/caseReview';
|
import { BaseAssociateCaseRequest } from '@/models/caseManagement/caseReview';
|
||||||
|
import { CaseLinkEnum } from '@/enums/caseEnum';
|
||||||
import { ProjectManagementRouteEnum } from '@/enums/routeEnum';
|
import { ProjectManagementRouteEnum } from '@/enums/routeEnum';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
@ -142,7 +143,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentSelectCase = ref<string | number | Record<string, any> | undefined>('');
|
const currentSelectCase = ref<keyof typeof CaseLinkEnum>('FUNCTIONAL');
|
||||||
|
|
||||||
// const associatedIds = useVModel(props, 'associatedIds', emit);
|
// const associatedIds = useVModel(props, 'associatedIds', emit);
|
||||||
const confirmLoading = ref<boolean>(false);
|
const confirmLoading = ref<boolean>(false);
|
||||||
|
@ -1,527 +0,0 @@
|
|||||||
import { Language, LanguageEnum } from '@/components/pure/ms-code-editor/types';
|
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
|
||||||
|
|
||||||
import type { CommonScriptMenu } from '@/models/projectManagement/commonScript';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
export const SCRIPT_MENU: CommonScriptMenu[] = [
|
|
||||||
{
|
|
||||||
title: t('project.code_segment.importApiTest'),
|
|
||||||
value: 'api_definition',
|
|
||||||
command: 'api_definition',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('project.code_segment.newApiTest'),
|
|
||||||
value: 'new_api_request',
|
|
||||||
command: 'new_api_request',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('project.processor.codeTemplateGetVariable'),
|
|
||||||
value: 'vars.get("variable_name")',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('project.processor.codeTemplateSetVariable'),
|
|
||||||
value: 'vars.put("variable_name", "variable_value")',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('project.processor.codeTemplateGetResponseHeader'),
|
|
||||||
value: 'prev.getResponseHeaders()',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('project.processor.codeTemplateGetResponseCode'),
|
|
||||||
value: 'prev.getResponseCode()',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('project.processor.codeTemplateGetResponseResult'),
|
|
||||||
value: 'prev.getResponseDataAsString()',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('project.processor.paramEnvironmentSetGlobalVariable'),
|
|
||||||
value: `vars.put(\${__metersphere_env_id}+"key","value");\nvars.put("key","value");`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('project.processor.insertPublicScript'),
|
|
||||||
value: 'custom_function',
|
|
||||||
command: 'custom_function',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('project.processor.terminationTest'),
|
|
||||||
value: 'api_stop',
|
|
||||||
command: 'api_stop',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
// 处理groovyCode 请求头
|
|
||||||
function getGroovyHeaders(requestHeaders: Record<string, any>) {
|
|
||||||
let headers = '[';
|
|
||||||
let index = 1;
|
|
||||||
// for (const [k, v] of requestHeaders) {
|
|
||||||
// if (index !== 1) {
|
|
||||||
// headers += ',';
|
|
||||||
// }
|
|
||||||
// // 拼装
|
|
||||||
// headers += `'${k}':'${v}'`;
|
|
||||||
// index++;
|
|
||||||
// }
|
|
||||||
requestHeaders.forEach(([k, v]: any[]) => {
|
|
||||||
if (index !== 1) {
|
|
||||||
headers += ',';
|
|
||||||
}
|
|
||||||
headers += `'${k}':'${v}'`;
|
|
||||||
index++;
|
|
||||||
});
|
|
||||||
headers += ']';
|
|
||||||
return headers;
|
|
||||||
}
|
|
||||||
// 解析请求url
|
|
||||||
function getRequestPath(requestArgs: any, requestPath: string) {
|
|
||||||
if (requestArgs.size > 0) {
|
|
||||||
requestPath += '?';
|
|
||||||
let index = 1;
|
|
||||||
requestArgs.forEach(([k, v]: any[]) => {
|
|
||||||
if (index !== 1) {
|
|
||||||
requestPath += '&';
|
|
||||||
}
|
|
||||||
requestPath = `${requestPath + k}=${v}`;
|
|
||||||
index++;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return requestPath;
|
|
||||||
}
|
|
||||||
// 处理mockPath
|
|
||||||
function getMockPath(domain: string, port: string, socket: string) {
|
|
||||||
if (domain === socket || !port) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
const str = `${domain}:${port}`;
|
|
||||||
// 获取socket之后的路径
|
|
||||||
return socket.substring(str.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理请求参数
|
|
||||||
function replaceRestParams(path: string, restMap: Map<string, string>) {
|
|
||||||
if (!path) {
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
let arr: any[] | null = path.match(/{([\w]+)}/g);
|
|
||||||
if (Array.isArray(arr) && arr.length > 0) {
|
|
||||||
arr = Array.from(new Set(arr));
|
|
||||||
arr.forEach((str) => {
|
|
||||||
try {
|
|
||||||
const temp = str.substr(1);
|
|
||||||
const param = temp.substring(0, temp.length - 1);
|
|
||||||
if (str && restMap.has(param)) {
|
|
||||||
path = path.replace(new RegExp(str, 'g'), restMap.get(param) || '');
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
// nothing
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 返回最终groovyCode 代码模板片段
|
|
||||||
function _groovyCodeTemplate(obj: Record<string, any>) {
|
|
||||||
const { requestUrl, requestMethod, headers, body } = obj;
|
|
||||||
const params = `[
|
|
||||||
'url': '${requestUrl}',
|
|
||||||
'method': '${requestMethod}', // POST/GET
|
|
||||||
'headers': ${headers}, // 请求headers 例:{'Content-type':'application/json'}
|
|
||||||
'data': ${body} // 参数
|
|
||||||
]`;
|
|
||||||
return `import groovy.json.JsonOutput
|
|
||||||
import groovy.json.JsonSlurper
|
|
||||||
|
|
||||||
def params = ${params}
|
|
||||||
def headers = params['headers']
|
|
||||||
// json数据
|
|
||||||
def data = params['data']
|
|
||||||
def conn = new URL(params['url']).openConnection()
|
|
||||||
conn.setRequestMethod(params['method'])
|
|
||||||
if (headers) {
|
|
||||||
headers.each {
|
|
||||||
k,v -> conn.setRequestProperty(k, v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (data) {
|
|
||||||
// 输出请求参数
|
|
||||||
log.info(data)
|
|
||||||
conn.doOutput = true
|
|
||||||
def writer = new OutputStreamWriter(conn.outputStream)
|
|
||||||
writer.write(data)
|
|
||||||
writer.flush()
|
|
||||||
writer.close()
|
|
||||||
}
|
|
||||||
log.info(conn.content.text)
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理groovyCode语言
|
|
||||||
function groovyCode(requestObj: Record<string, any>) {
|
|
||||||
const {
|
|
||||||
requestHeaders = new Map(),
|
|
||||||
requestBody = '',
|
|
||||||
domain = '',
|
|
||||||
port = '',
|
|
||||||
requestMethod = '',
|
|
||||||
host = '',
|
|
||||||
protocol = '',
|
|
||||||
requestArguments = new Map(),
|
|
||||||
requestRest = new Map(),
|
|
||||||
requestBodyKvs = new Map(),
|
|
||||||
bodyType,
|
|
||||||
} = requestObj;
|
|
||||||
|
|
||||||
let { requestPath = '' } = requestObj;
|
|
||||||
let requestUrl = '';
|
|
||||||
if (requestMethod.toLowerCase() === 'get' && requestBodyKvs) {
|
|
||||||
// 如果是get方法要将kv值加入argument中
|
|
||||||
requestBodyKvs.forEach(([k, v]: any[]) => {
|
|
||||||
requestArguments.set(k, v);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
requestPath = getRequestPath(requestArguments, requestPath);
|
|
||||||
const path = getMockPath(domain, port, host);
|
|
||||||
requestPath = path + replaceRestParams(requestPath, requestRest);
|
|
||||||
if (protocol && host && requestPath) {
|
|
||||||
requestUrl = `${protocol}://${domain}${port ? `:${port}` : ''}${requestPath}`;
|
|
||||||
}
|
|
||||||
let body = JSON.stringify(requestBody);
|
|
||||||
if (requestMethod === 'POST' && bodyType === 'kvs') {
|
|
||||||
body = '"';
|
|
||||||
|
|
||||||
requestBodyKvs.forEach(([k, v]: any[]) => {
|
|
||||||
if (body !== '"') {
|
|
||||||
body += '&';
|
|
||||||
}
|
|
||||||
body += `${k}=${v}`;
|
|
||||||
});
|
|
||||||
body += '"';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bodyType && bodyType.toUpperCase() === 'RAW') {
|
|
||||||
requestHeaders.set('Content-type', 'text/plain');
|
|
||||||
}
|
|
||||||
const headers = getGroovyHeaders(requestHeaders);
|
|
||||||
const obj = { requestUrl, requestMethod, headers, body };
|
|
||||||
return _groovyCodeTemplate(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取请求头
|
|
||||||
function getHeaders(requestHeaders: Map<string, string>) {
|
|
||||||
let headers = '{';
|
|
||||||
let index = 1;
|
|
||||||
requestHeaders.forEach(([k, v]) => {
|
|
||||||
if (index !== 1) {
|
|
||||||
headers += ',';
|
|
||||||
}
|
|
||||||
// 拼装
|
|
||||||
headers += `'${k}':'${v}'`;
|
|
||||||
index++;
|
|
||||||
});
|
|
||||||
headers += '}';
|
|
||||||
return headers;
|
|
||||||
}
|
|
||||||
// 获取pythonCode 模板
|
|
||||||
function _pythonCodeTemplate(obj: Record<string, any>) {
|
|
||||||
const { requestBodyKvs, requestPath, requestMethod, connType, domain, port } = obj;
|
|
||||||
let { headers } = obj;
|
|
||||||
let reqBody = obj.requestBody;
|
|
||||||
if (requestMethod.toLowerCase() === 'post' && obj.bodyType === 'kvs' && obj.requestBodyKvs) {
|
|
||||||
reqBody = 'urllib.urlencode({';
|
|
||||||
requestBodyKvs.forEach(([k, v]: any[]) => {
|
|
||||||
reqBody += `'${k}':'${v}'`;
|
|
||||||
});
|
|
||||||
reqBody += `})`;
|
|
||||||
if (headers === '{}') {
|
|
||||||
headers = "{'Content-type': 'application/x-www-form-urlencoded', 'Accept': 'text/plain'}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const host = domain + (port ? `:${port}` : '');
|
|
||||||
|
|
||||||
return `import httplib,urllib
|
|
||||||
params = ${reqBody} #例 {'username':'test'}
|
|
||||||
headers = ${headers} #例 {'Content-Type':'application/json'} 或 {'Content-type': 'application/x-www-form-urlencoded', 'Accept': 'text/plain'}
|
|
||||||
host = '${host}'
|
|
||||||
path = '${requestPath}'
|
|
||||||
method = '${requestMethod}' # POST/GET
|
|
||||||
|
|
||||||
conn = httplib.${connType}(host)
|
|
||||||
conn.request(method, path, params, headers)
|
|
||||||
res = conn.getresponse()
|
|
||||||
data = unicode(res.read(), 'utf-8')
|
|
||||||
log.info(data)
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理pythonCode语言
|
|
||||||
function pythonCode(requestObj: Record<string, any>) {
|
|
||||||
const {
|
|
||||||
requestHeaders = new Map(),
|
|
||||||
requestMethod = '',
|
|
||||||
host = '',
|
|
||||||
domain = '',
|
|
||||||
port = '',
|
|
||||||
protocol = 'http',
|
|
||||||
requestArguments = new Map(),
|
|
||||||
requestBodyKvs = new Map(),
|
|
||||||
bodyType,
|
|
||||||
requestRest = new Map(),
|
|
||||||
} = requestObj;
|
|
||||||
let { requestBody = '', requestPath = '/' } = requestObj;
|
|
||||||
let connType = 'HTTPConnection';
|
|
||||||
if (protocol === 'https') {
|
|
||||||
connType = 'HTTPSConnection';
|
|
||||||
}
|
|
||||||
const headers = getHeaders(requestHeaders);
|
|
||||||
requestBody = requestBody ? JSON.stringify(requestBody) : '{}';
|
|
||||||
if (requestMethod.toLowerCase() === 'get' && requestBodyKvs) {
|
|
||||||
requestBodyKvs.forEach(([k, v]: any[]) => {
|
|
||||||
requestArguments.set(k, v);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
requestPath = getRequestPath(requestArguments, requestPath);
|
|
||||||
const path = getMockPath(domain, port, host);
|
|
||||||
requestPath = path + replaceRestParams(requestPath, requestRest);
|
|
||||||
const obj = { requestBody, headers, requestPath, requestMethod, requestBodyKvs, bodyType, connType, domain, port };
|
|
||||||
return _pythonCodeTemplate(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取javaBeanshell代码模板
|
|
||||||
function _beanshellTemplate(obj: Record<string, any>) {
|
|
||||||
const {
|
|
||||||
requestHeaders = new Map(),
|
|
||||||
requestBodyKvs = new Map(),
|
|
||||||
bodyType = '',
|
|
||||||
requestMethod = 'GET',
|
|
||||||
protocol = 'http',
|
|
||||||
requestArguments = new Map(),
|
|
||||||
domain = '',
|
|
||||||
host = '',
|
|
||||||
port = '',
|
|
||||||
requestRest = new Map(),
|
|
||||||
} = obj;
|
|
||||||
let { requestPath = '/', requestBody = '' } = obj;
|
|
||||||
|
|
||||||
const path = getMockPath(domain, port, host);
|
|
||||||
requestPath = path + replaceRestParams(requestPath, requestRest);
|
|
||||||
let uri = `new URIBuilder()
|
|
||||||
.setScheme("${protocol}")
|
|
||||||
.setHost("${domain}")
|
|
||||||
.setPath("${requestPath}")
|
|
||||||
`;
|
|
||||||
// http 请求类型
|
|
||||||
const method = requestMethod.toLowerCase().replace(/^\S/, (s: string) => s.toUpperCase());
|
|
||||||
const httpMethodCode = `Http${method} request = new Http${method}(uri);`;
|
|
||||||
// 设置参数
|
|
||||||
requestArguments.forEach(([k, v]: any[]) => {
|
|
||||||
uri += `.setParameter("${k}", "${v}")`;
|
|
||||||
});
|
|
||||||
if (method === 'Get' && requestBodyKvs) {
|
|
||||||
requestBodyKvs.forEach(([k, v]: any[]) => {
|
|
||||||
uri += `.setParameter("${k}", "${v}")`;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let postKvsParam = '';
|
|
||||||
if (method === 'Post') {
|
|
||||||
// 设置post参数
|
|
||||||
requestBodyKvs.forEach(([k, v]: any[]) => {
|
|
||||||
postKvsParam += `nameValueList.add(new BasicNameValuePair("${k}", "${v}"));\r\n`;
|
|
||||||
});
|
|
||||||
if (postKvsParam !== '') {
|
|
||||||
postKvsParam = `List nameValueList = new ArrayList();\r\n${postKvsParam}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (port) {
|
|
||||||
uri += `.setPort(${port}) // int类型端口
|
|
||||||
`;
|
|
||||||
uri += ` .build();`;
|
|
||||||
} else {
|
|
||||||
uri += `// .setPort(${port}) // int类型端口
|
|
||||||
`;
|
|
||||||
uri += ` .build();`;
|
|
||||||
}
|
|
||||||
// 设置请求头
|
|
||||||
let setHeader = '';
|
|
||||||
requestHeaders.forEach(([k, v]: any[]) => {
|
|
||||||
setHeader = `${setHeader}request.setHeader("${k}", "${v}");\n`;
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
requestBody = JSON.stringify(requestBody);
|
|
||||||
if (!requestBody || requestBody === 'null') {
|
|
||||||
requestBody = '';
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
requestBody = '';
|
|
||||||
}
|
|
||||||
let postMethodCode = '';
|
|
||||||
if (requestMethod === 'POST') {
|
|
||||||
if (bodyType === 'kvs') {
|
|
||||||
postMethodCode = `${postKvsParam}\r\n request.setEntity(new UrlEncodedFormEntity(nameValueList, "UTF-8"));`;
|
|
||||||
} else {
|
|
||||||
postMethodCode = `request.setEntity(new StringEntity(StringEscapeUtils.unescapeJava(payload)));`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return `import java.net.URI;
|
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
|
||||||
import org.apache.http.client.methods.*;
|
|
||||||
import org.apache.commons.text.StringEscapeUtils;
|
|
||||||
import org.apache.http.client.utils.URIBuilder;
|
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
|
||||||
import org.apache.http.impl.client.HttpClients;
|
|
||||||
import org.apache.http.util.EntityUtils;
|
|
||||||
import org.apache.http.entity.StringEntity;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import org.apache.http.NameValuePair;
|
|
||||||
import org.apache.http.message.BasicNameValuePair;
|
|
||||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
|
||||||
|
|
||||||
// 创建Httpclient对象
|
|
||||||
CloseableHttpClient httpclient = HttpClients.createDefault();
|
|
||||||
// 参数
|
|
||||||
String payload = ${requestBody};
|
|
||||||
// 定义请求的参数
|
|
||||||
URI uri = ${uri}
|
|
||||||
// 创建http请求
|
|
||||||
${httpMethodCode}
|
|
||||||
${setHeader}
|
|
||||||
${postMethodCode}
|
|
||||||
log.info(uri.toString());
|
|
||||||
//response 对象
|
|
||||||
CloseableHttpResponse response = null;
|
|
||||||
|
|
||||||
response = httpclient.execute(request);
|
|
||||||
// 判断返回状态是否为200
|
|
||||||
if (response.getStatusLine().getStatusCode() == 200) {
|
|
||||||
String content = EntityUtils.toString(response.getEntity(), "UTF-8");
|
|
||||||
log.info(content);
|
|
||||||
}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理java语言
|
|
||||||
function javaCode(requestObj: Record<string, any>) {
|
|
||||||
return _beanshellTemplate(requestObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取js语言代码模板
|
|
||||||
function _jsTemplate(obj: Record<string, any>) {
|
|
||||||
const {
|
|
||||||
requestHeaders = new Map(),
|
|
||||||
requestMethod = 'GET',
|
|
||||||
protocol = 'http',
|
|
||||||
requestArguments = new Map(),
|
|
||||||
host = '',
|
|
||||||
domain = '',
|
|
||||||
port = '',
|
|
||||||
requestBodyKvs = new Map(),
|
|
||||||
bodyType = '',
|
|
||||||
requestRest = new Map(),
|
|
||||||
} = obj;
|
|
||||||
let url = '';
|
|
||||||
let { requestBody = '', requestPath = '/' } = obj;
|
|
||||||
requestPath = replaceRestParams(requestPath, requestRest);
|
|
||||||
if (protocol && domain && port) {
|
|
||||||
const path = getMockPath(domain, port, host);
|
|
||||||
requestPath = path + requestPath;
|
|
||||||
url = `${protocol}://${domain}${port ? `:${port}` : ''}${requestPath}`;
|
|
||||||
} else if (protocol && domain) {
|
|
||||||
url = `${protocol}://${domain}${requestPath}`;
|
|
||||||
}
|
|
||||||
if (requestMethod.toLowerCase() === 'get' && requestBodyKvs) {
|
|
||||||
// 如果是get方法要将kv值加入argument中
|
|
||||||
requestBodyKvs.forEach(([k, v]: any[]) => {
|
|
||||||
requestArguments.set(k, v);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
url = getRequestPath(requestArguments, url);
|
|
||||||
try {
|
|
||||||
requestBody = JSON.stringify(requestBody);
|
|
||||||
} catch (e) {
|
|
||||||
requestBody = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
let connStr = '';
|
|
||||||
if (bodyType && bodyType.toUpperCase() === 'RAW') {
|
|
||||||
requestHeaders.set('Content-type', 'text/plain');
|
|
||||||
}
|
|
||||||
requestHeaders.forEach(([k, v]: any[]) => {
|
|
||||||
connStr += `conn.setRequestProperty("${k}","${v}");\n`;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (requestMethod === 'POST' && bodyType === 'kvs') {
|
|
||||||
requestBody = '"';
|
|
||||||
requestBodyKvs.forEach(([k, v]: any[]) => {
|
|
||||||
if (requestBody !== '"') {
|
|
||||||
requestBody += '&';
|
|
||||||
}
|
|
||||||
requestBody += `${k}=${v}`;
|
|
||||||
});
|
|
||||||
requestBody += '"';
|
|
||||||
}
|
|
||||||
let postParamExecCode = '';
|
|
||||||
if (requestBody && requestBody !== '' && requestBody !== '""') {
|
|
||||||
postParamExecCode = `
|
|
||||||
var opt = new java.io.DataOutputStream(conn.getOutputStream());
|
|
||||||
var t = (new java.lang.String(parameterData)).getBytes("utf-8");
|
|
||||||
opt.write(t);
|
|
||||||
opt.flush();
|
|
||||||
opt.close();
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `var urlStr = "${url}"; // 请求地址
|
|
||||||
var requestMethod = "${requestMethod}"; // 请求类型
|
|
||||||
var parameterData = ${requestBody}; // 请求参数
|
|
||||||
var url = new java.net.URL(urlStr);
|
|
||||||
var conn = url.openConnection();
|
|
||||||
conn.setRequestMethod(requestMethod);
|
|
||||||
conn.setDoOutput(true);
|
|
||||||
${connStr}conn.connect();
|
|
||||||
${postParamExecCode}
|
|
||||||
var res = "";
|
|
||||||
var rspCode = conn.getResponseCode();
|
|
||||||
if (rspCode == 200) {
|
|
||||||
var ipt = conn.getInputStream();
|
|
||||||
var reader = new java.io.BufferedReader(new java.io.InputStreamReader(ipt, "UTF-8"));
|
|
||||||
var lines;
|
|
||||||
while((lines = reader.readLine()) !== null) {
|
|
||||||
res += lines;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.info(res);
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理js语言
|
|
||||||
function jsCode(requestObj: Record<string, any>) {
|
|
||||||
return _jsTemplate(requestObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getCodeTemplate(language: Language, requestObj: any) {
|
|
||||||
switch (language) {
|
|
||||||
case LanguageEnum.GROOVY:
|
|
||||||
return groovyCode(requestObj);
|
|
||||||
case LanguageEnum.PYTHON:
|
|
||||||
return pythonCode(requestObj);
|
|
||||||
case LanguageEnum.BEANSHELL:
|
|
||||||
return javaCode(requestObj);
|
|
||||||
case LanguageEnum.NASHORNSCRIPT:
|
|
||||||
return jsCode(requestObj);
|
|
||||||
case LanguageEnum.RHINOSCRIPT:
|
|
||||||
return jsCode(requestObj);
|
|
||||||
case LanguageEnum.JAVASCRIPT:
|
|
||||||
return jsCode(requestObj);
|
|
||||||
default:
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {};
|
|
@ -8,6 +8,7 @@
|
|||||||
:on-before-ok="beforeConfirm"
|
:on-before-ok="beforeConfirm"
|
||||||
:cancel-button-props="{ disabled: loading }"
|
:cancel-button-props="{ disabled: loading }"
|
||||||
@popup-visible-change="reset"
|
@popup-visible-change="reset"
|
||||||
|
@cancel="handleCancel()"
|
||||||
>
|
>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div class="mb-[8px] text-[14px] font-medium text-[var(--color-text-1)]">{{
|
<div class="mb-[8px] text-[14px] font-medium text-[var(--color-text-1)]">{{
|
||||||
|
@ -348,8 +348,8 @@
|
|||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
await batchModalRef.value.batchRequestFun(addProjectUserGroup, params);
|
await batchModalRef.value.batchRequestFun(addProjectUserGroup, params);
|
||||||
initData();
|
|
||||||
resetSelector();
|
resetSelector();
|
||||||
|
initData();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
@ -345,8 +345,8 @@
|
|||||||
params.userRoleIds = target;
|
params.userRoleIds = target;
|
||||||
}
|
}
|
||||||
if (currentType) await batchModalRef.value.batchRequestFun(currentType.request, params);
|
if (currentType) await batchModalRef.value.batchRequestFun(currentType.request, params);
|
||||||
initData();
|
|
||||||
resetSelector();
|
resetSelector();
|
||||||
|
initData();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 批量操作
|
// 批量操作
|
||||||
|
@ -619,10 +619,15 @@
|
|||||||
loading.value = true;
|
loading.value = true;
|
||||||
const res = await templateApiMaps[props.mode].detail(route.query.id as string);
|
const res = await templateApiMaps[props.mode].detail(route.query.id as string);
|
||||||
const { name, customFields, systemFields } = res;
|
const { name, customFields, systemFields } = res;
|
||||||
|
let copyName = `copy_${name}`;
|
||||||
|
if (copyName.length > 255) {
|
||||||
|
copyName = copyName.slice(0, 255);
|
||||||
|
}
|
||||||
templateForm.value = {
|
templateForm.value = {
|
||||||
...res,
|
...res,
|
||||||
name: route.params.mode === 'copy' ? `copy_${name}` : name,
|
name: route.params.mode === 'copy' ? copyName : name,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (route.params.mode === 'copy') {
|
if (route.params.mode === 'copy') {
|
||||||
templateForm.value.id = undefined;
|
templateForm.value.id = undefined;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
<template>
|
||||||
|
<div v-expire class="mb-4">
|
||||||
|
<a-alert type="warning">{{
|
||||||
|
licenseStore.expiredDays >= 0 && licenseStore.expiredDays <= 30
|
||||||
|
? t('system.authorized.LicenseExpirationPromptLessThanThirty', { day: licenseStore.expiredDays })
|
||||||
|
: t('system.authorized.LicenseExpirationPromptGreaterThanThirty')
|
||||||
|
}}</a-alert>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
import useLicenseStore from '@/store/modules/setting/license';
|
||||||
|
|
||||||
|
const licenseStore = useLicenseStore();
|
||||||
|
const { t } = useI18n();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<MsCard :loading="loading" simple>
|
<MsCard :loading="loading" simple>
|
||||||
|
<ExpireAlert />
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<div class="content-wrapper">
|
<div class="content-wrapper">
|
||||||
<div class="authorized_logo">
|
<div class="authorized_logo">
|
||||||
@ -119,6 +120,7 @@
|
|||||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||||
import MsUpload from '@/components/pure/ms-upload/index.vue';
|
import MsUpload from '@/components/pure/ms-upload/index.vue';
|
||||||
|
import ExpireAlert from './components/expireAlert.vue';
|
||||||
|
|
||||||
import { addLicense, getLicenseInfo } from '@/api/modules/setting/authorizedManagement';
|
import { addLicense, getLicenseInfo } from '@/api/modules/setting/authorizedManagement';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
@ -143,6 +145,7 @@
|
|||||||
const result = await getLicenseInfo();
|
const result = await getLicenseInfo();
|
||||||
licenseInfo.value = result;
|
licenseInfo.value = result;
|
||||||
licenseStore.setLicenseStatus(licenseInfo.value?.status);
|
licenseStore.setLicenseStatus(licenseInfo.value?.status);
|
||||||
|
licenseStore.getExpirationTime(licenseInfo.value.license.expired);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -15,4 +15,8 @@ export default {
|
|||||||
'system.authorized.licenseCode': 'License Code',
|
'system.authorized.licenseCode': 'License Code',
|
||||||
'system.authorized.licenseSuccessTip': 'Authorized Successfully!',
|
'system.authorized.licenseSuccessTip': 'Authorized Successfully!',
|
||||||
'system.authorized.LicenseIsRequired': 'License Code is required',
|
'system.authorized.LicenseIsRequired': 'License Code is required',
|
||||||
|
'system.authorized.LicenseExpirationPromptLessThanThirty':
|
||||||
|
'The remaining {day} of system authorization expires. In order not to affect your use, please contact the staff as soon as possible',
|
||||||
|
'system.authorized.LicenseExpirationPromptGreaterThanThirty':
|
||||||
|
'System authorization has expired, if you need help, please contact the working staff',
|
||||||
};
|
};
|
||||||
|
@ -15,4 +15,7 @@ export default {
|
|||||||
'system.authorized.licenseCode': 'License Code',
|
'system.authorized.licenseCode': 'License Code',
|
||||||
'system.authorized.licenseSuccessTip': '授权成功',
|
'system.authorized.licenseSuccessTip': '授权成功',
|
||||||
'system.authorized.LicenseIsRequired': 'License Code 是必填项',
|
'system.authorized.LicenseIsRequired': 'License Code 是必填项',
|
||||||
|
'system.authorized.LicenseExpirationPromptLessThanThirty':
|
||||||
|
'系统授权剩余 {day} 天到期,为了不影响您的使用,请尽快联系工作人员',
|
||||||
|
'system.authorized.LicenseExpirationPromptGreaterThanThirty': '系统授权已过期,如需帮助,请联系工作人员',
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<ExpireAlert />
|
||||||
<MsTabCard v-model:active-tab="activeTab" :title="t('system.config.parameterConfig')" :tab-list="tabList" />
|
<MsTabCard v-model:active-tab="activeTab" :title="t('system.config.parameterConfig')" :tab-list="tabList" />
|
||||||
<baseConfig v-if="activeTab === 'baseConfig'" v-show="activeTab === 'baseConfig'" />
|
<baseConfig v-if="activeTab === 'baseConfig'" v-show="activeTab === 'baseConfig'" />
|
||||||
<pageConfig v-if="isInitPageConfig" v-show="activeTab === 'pageConfig'" />
|
<pageConfig v-if="isInitPageConfig" v-show="activeTab === 'pageConfig'" />
|
||||||
@ -13,6 +14,7 @@
|
|||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
import MsTabCard from '@/components/pure/ms-tab-card/index.vue';
|
import MsTabCard from '@/components/pure/ms-tab-card/index.vue';
|
||||||
|
import ExpireAlert from '@/views/setting/system/authorizedManagement/components/expireAlert.vue';
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useLicenseStore from '@/store/modules/setting/license';
|
import useLicenseStore from '@/store/modules/setting/license';
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<ExpireAlert />
|
||||||
<logCards mode="SYSTEM"></logCards>
|
<logCards mode="SYSTEM"></logCards>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -7,6 +8,7 @@
|
|||||||
* @description 系统设置-日志
|
* @description 系统设置-日志
|
||||||
*/
|
*/
|
||||||
import logCards from './components/logCards.vue';
|
import logCards from './components/logCards.vue';
|
||||||
|
import ExpireAlert from '@/views/setting/system/authorizedManagement/components/expireAlert.vue';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
<style lang="less" scoped></style>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<MsCard simple>
|
<MsCard simple>
|
||||||
|
<ExpireAlert />
|
||||||
<div class="mb-4 flex items-center justify-between">
|
<div class="mb-4 flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<a-button
|
<a-button
|
||||||
@ -52,6 +53,7 @@
|
|||||||
import AddProjectModal from './components/addProjectModal.vue';
|
import AddProjectModal from './components/addProjectModal.vue';
|
||||||
import SystemOrganization from './components/systemOrganization.vue';
|
import SystemOrganization from './components/systemOrganization.vue';
|
||||||
import SystemProject from './components/systemProject.vue';
|
import SystemProject from './components/systemProject.vue';
|
||||||
|
import ExpireAlert from '@/views/setting/system/authorizedManagement/components/expireAlert.vue';
|
||||||
|
|
||||||
import { getOrgAndProjectCount } from '@/api/modules/setting/organizationAndProject';
|
import { getOrgAndProjectCount } from '@/api/modules/setting/organizationAndProject';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/* stylelint-disable order/properties-order */
|
/* stylelint-disable order/properties-order */
|
||||||
<template>
|
<template>
|
||||||
<MsCard simple>
|
<MsCard simple>
|
||||||
|
<ExpireAlert />
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<a-alert :closable="true" class="mb-4">
|
<a-alert :closable="true" class="mb-4">
|
||||||
<div>
|
<div>
|
||||||
@ -19,6 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||||
import pluginTable from './components/pluginTable.vue';
|
import pluginTable from './components/pluginTable.vue';
|
||||||
|
import ExpireAlert from '@/views/setting/system/authorizedManagement/components/expireAlert.vue';
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<MsCard :loading="loading" simple>
|
<MsCard :loading="loading" simple>
|
||||||
|
<ExpireAlert />
|
||||||
<div class="mb-4 flex items-center justify-between">
|
<div class="mb-4 flex items-center justify-between">
|
||||||
<a-button v-permission="['SYSTEM_TEST_RESOURCE_POOL:READ+ADD']" v-xpack type="primary" @click="addPool">
|
<a-button v-permission="['SYSTEM_TEST_RESOURCE_POOL:READ+ADD']" v-xpack type="primary" @click="addPool">
|
||||||
{{ t('system.resourcePool.createPool') }}
|
{{ t('system.resourcePool.createPool') }}
|
||||||
@ -91,6 +92,7 @@
|
|||||||
import type { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
import type { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||||
import { TagType, Theme } from '@/components/pure/ms-tag/ms-tag.vue';
|
import { TagType, Theme } from '@/components/pure/ms-tag/ms-tag.vue';
|
||||||
import JobTemplateDrawer from './components/jobTemplateDrawer.vue';
|
import JobTemplateDrawer from './components/jobTemplateDrawer.vue';
|
||||||
|
import ExpireAlert from '@/views/setting/system/authorizedManagement/components/expireAlert.vue';
|
||||||
|
|
||||||
import { delPoolInfo, getPoolInfo, getPoolList, togglePoolStatus } from '@/api/modules/setting/resourcePool';
|
import { delPoolInfo, getPoolInfo, getPoolList, togglePoolStatus } from '@/api/modules/setting/resourcePool';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<MsCard simple no-content-padding>
|
<MsCard simple no-content-padding>
|
||||||
|
<div class="p-4 pb-0">
|
||||||
|
<ExpireAlert />
|
||||||
|
</div>
|
||||||
<TaskCenter group="system" />
|
<TaskCenter group="system" />
|
||||||
</MsCard>
|
</MsCard>
|
||||||
</template>
|
</template>
|
||||||
@ -9,6 +12,7 @@
|
|||||||
|
|
||||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||||
import TaskCenter from '@/views/project-management/taskCenter/component/taskCom.vue';
|
import TaskCenter from '@/views/project-management/taskCenter/component/taskCom.vue';
|
||||||
|
import ExpireAlert from '@/views/setting/system/authorizedManagement/components/expireAlert.vue';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<MsCard simple>
|
<MsCard simple>
|
||||||
|
<ExpireAlert />
|
||||||
<div class="mb-4 flex items-center justify-between">
|
<div class="mb-4 flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<a-button
|
<a-button
|
||||||
@ -18,7 +19,12 @@
|
|||||||
>
|
>
|
||||||
{{ t('system.user.emailInvite') }}
|
{{ t('system.user.emailInvite') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-button v-permission="['SYSTEM_USER:READ+IMPORT']" class="mr-3" type="outline" @click="showImportModal">
|
<a-button
|
||||||
|
v-permission="['SYSTEM_USER:READ+IMPORT', 'SYSTEM_USER_ROLE:READ']"
|
||||||
|
class="mr-3"
|
||||||
|
type="outline"
|
||||||
|
@click="showImportModal"
|
||||||
|
>
|
||||||
{{ t('system.user.importUser') }}
|
{{ t('system.user.importUser') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
@ -306,6 +312,7 @@
|
|||||||
import MsSelect from '@/components/business/ms-select';
|
import MsSelect from '@/components/business/ms-select';
|
||||||
import batchModal from './components/batchModal.vue';
|
import batchModal from './components/batchModal.vue';
|
||||||
import inviteModal from './components/inviteModal.vue';
|
import inviteModal from './components/inviteModal.vue';
|
||||||
|
import ExpireAlert from '@/views/setting/system/authorizedManagement/components/expireAlert.vue';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
batchCreateUser,
|
batchCreateUser,
|
||||||
|
@ -12,8 +12,9 @@
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #second>
|
<template #second>
|
||||||
<div class="flex h-full flex-col gap-[16px] overflow-hidden pt-[24px]">
|
<div class="flex h-full flex-col overflow-hidden pt-[24px]">
|
||||||
<div class="flex flex-row items-center justify-between px-[24px]">
|
<ExpireAlert class="px-4" />
|
||||||
|
<div class="mb-4 flex flex-row items-center justify-between px-[24px]">
|
||||||
<a-tooltip :content="currentUserGroupItem.name">
|
<a-tooltip :content="currentUserGroupItem.name">
|
||||||
<div class="one-line-text max-w-[300px] font-medium">{{ currentUserGroupItem.name }}</div>
|
<div class="one-line-text max-w-[300px] font-medium">{{ currentUserGroupItem.name }}</div>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
@ -72,6 +73,7 @@
|
|||||||
import AuthTable from '@/components/business/ms-user-group-comp/authTable.vue';
|
import AuthTable from '@/components/business/ms-user-group-comp/authTable.vue';
|
||||||
import UserGroupLeft from '@/components/business/ms-user-group-comp/msUserGroupLeft.vue';
|
import UserGroupLeft from '@/components/business/ms-user-group-comp/msUserGroupLeft.vue';
|
||||||
import UserTable from '@/components/business/ms-user-group-comp/userTable.vue';
|
import UserTable from '@/components/business/ms-user-group-comp/userTable.vue';
|
||||||
|
import ExpireAlert from '@/views/setting/system/authorizedManagement/components/expireAlert.vue';
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import { hasAnyPermission } from '@/utils/permission';
|
import { hasAnyPermission } from '@/utils/permission';
|
||||||
|
Loading…
Reference in New Issue
Block a user