fix(系统管理): 修改部分xpackbug&权限补充

This commit is contained in:
xinxin.wu 2024-01-30 17:22:46 +08:00 committed by 刘瑞斌
parent 357325017a
commit 0700c81946
35 changed files with 298 additions and 182 deletions

View File

@ -52,7 +52,6 @@
onBeforeMount(async () => { onBeforeMount(async () => {
try { try {
await appStore.initSystemPackage(); //
await appStore.initSystemVersion(); // await appStore.initSystemVersion(); //
// license // license
if (appStore.packageType === 'enterprise') { if (appStore.packageType === 'enterprise') {

View File

@ -19,5 +19,5 @@ export function switchUserOrg(organizationId: string, userId: string) {
// 获取当前系统的版本 // 获取当前系统的版本
export function getPackageType() { export function getPackageType() {
return MSR.get<'community' | 'enterprise'>({ url: PackageTypeUrl }, { ignoreCancelToken: true }); return MSR.get<string>({ url: PackageTypeUrl });
} }

View File

@ -78,6 +78,11 @@
margin-top: 16px; margin-top: 16px;
} }
} }
.arco-modal-wrapper.arco-modal-wrapper-align-center {
.arco-modal {
top: -5% !important;
}
}
.ms-usemodal { .ms-usemodal {
.arco-modal-body { .arco-modal-body {
@apply p-0; @apply p-0;

View File

@ -48,7 +48,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="config-card"> <div v-xpack class="config-card">
<div class="config-card-title"> <div class="config-card-title">
<div class="config-card-title-text">{{ t('ms.personal.uiLocalExecution') }}</div> <div class="config-card-title-text">{{ t('ms.personal.uiLocalExecution') }}</div>
<MsTag <MsTag

View File

@ -21,13 +21,10 @@
import usePermission from '@/hooks/usePermission'; import usePermission from '@/hooks/usePermission';
import appClientMenus from '@/router/app-menus'; import appClientMenus from '@/router/app-menus';
import { useAppStore } from '@/store'; import { useAppStore } from '@/store';
import useLicenseStore from '@/store/modules/setting/license';
import { listenerRouteChange } from '@/utils/route-listener'; import { listenerRouteChange } from '@/utils/route-listener';
import { RouteEnum } from '@/enums/routeEnum'; import { RouteEnum } from '@/enums/routeEnum';
const licenseStore = useLicenseStore();
const copyRouters = cloneDeep(appClientMenus) as RouteRecordRaw[]; const copyRouters = cloneDeep(appClientMenus) as RouteRecordRaw[];
const permission = usePermission(); const permission = usePermission();
const appStore = useAppStore(); const appStore = useAppStore();
@ -111,6 +108,10 @@
function menuClickHandler() { function menuClickHandler() {
activeMenus.value = [appStore.getCurrentTopMenu?.name || '']; activeMenus.value = [appStore.getCurrentTopMenu?.name || ''];
} }
onBeforeMount(() => {
appStore.initSystemPackage();
});
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -21,7 +21,7 @@ export default {
'menu.workbench': '工作台', 'menu.workbench': '工作台',
'menu.testPlan': '测试计划', 'menu.testPlan': '测试计划',
'menu.bugManagement': '缺陷管理', 'menu.bugManagement': '缺陷管理',
'menu.caseManagement': '功能测试', 'menu.caseManagement': '用例管理',
'menu.apiTest': '接口测试', 'menu.apiTest': '接口测试',
'menu.apiTest.debug': '接口调试', 'menu.apiTest.debug': '接口调试',
'menu.apiTest.management': '接口管理', 'menu.apiTest.management': '接口管理',

View File

@ -1,22 +1,30 @@
import { useAppStore } from '@/store';
import { clearToken, hasToken, isLoginExpires } from '@/utils/auth'; import { clearToken, hasToken, isLoginExpires } from '@/utils/auth';
import NProgress from 'nprogress'; // progress bar import NProgress from 'nprogress'; // progress bar
import type { LocationQueryRaw, Router } from 'vue-router'; import type { LocationQueryRaw, Router } from 'vue-router';
export default function setupUserLoginInfoGuard(router: Router) { export default function setupUserLoginInfoGuard(router: Router) {
router.beforeEach((to, from, next) => { router.beforeEach(async (to, from, next) => {
NProgress.start(); NProgress.start();
if (isLoginExpires()) { if (isLoginExpires()) {
clearToken(); clearToken();
} }
if (to.name !== 'login' && hasToken(to.name as string)) { if (to.name !== 'login' && hasToken(to.name as string)) {
const appStore = useAppStore();
if (!appStore.packageType) {
await appStore.initSystemPackage();
next(); next();
} else {
next();
}
} else { } else {
// 未登录的都直接跳转至登录页,访问的页面地址缓存到 query 上 // 未登录的都直接跳转至登录页,访问的页面地址缓存到 query 上
if (to.name === 'login') { if (to.name === 'login') {
next(); next();
return; return;
} }
next({ next({
name: 'login', name: 'login',
query: { query: {

View File

@ -3,28 +3,28 @@ import { PerformanceTestRouteEnum } from '@/enums/routeEnum';
import { DEFAULT_LAYOUT } from '../base'; import { DEFAULT_LAYOUT } from '../base';
import type { AppRouteRecordRaw } from '../types'; import type { AppRouteRecordRaw } from '../types';
const PerformanceTest: AppRouteRecordRaw = { // const PerformanceTest: AppRouteRecordRaw = {
path: '/performance-test', // path: '/performance-test',
name: PerformanceTestRouteEnum.PERFORMANCE_TEST, // name: PerformanceTestRouteEnum.PERFORMANCE_TEST,
redirect: '/performance-test/index', // redirect: '/performance-test/index',
component: DEFAULT_LAYOUT, // component: DEFAULT_LAYOUT,
meta: { // meta: {
locale: 'menu.performanceTest', // locale: 'menu.performanceTest',
icon: 'icon-icon_performance-test-filled', // icon: 'icon-icon_performance-test-filled',
order: 6, // order: 6,
hideChildrenInMenu: true, // hideChildrenInMenu: true,
roles: ['LOAD_TEST:READ'], // roles: ['LOAD_TEST:READ'],
}, // },
children: [ // children: [
{ // {
path: 'index', // path: 'index',
name: 'performanceTestIndex', // name: 'performanceTestIndex',
component: () => import('@/views/performance-test/index.vue'), // component: () => import('@/views/performance-test/index.vue'),
meta: { // meta: {
roles: ['LOAD_TEST:READ'], // roles: ['LOAD_TEST:READ'],
}, // },
}, // },
], // ],
}; // };
export default PerformanceTest; // export default PerformanceTest;

View File

@ -227,7 +227,7 @@ const Setting: AppRouteRecordRaw = {
component: () => import('@/views/setting/organization/template/components/ordFieldSetting.vue'), component: () => import('@/views/setting/organization/template/components/ordFieldSetting.vue'),
meta: { meta: {
locale: 'menu.settings.organization.templateFieldSetting', locale: 'menu.settings.organization.templateFieldSetting',
roles: ['*'], roles: ['ORGANIZATION_TEMPLATE:READ'],
breadcrumbs: [ breadcrumbs: [
{ {
name: SettingRouteEnum.SETTING_ORGANIZATION_TEMPLATE, name: SettingRouteEnum.SETTING_ORGANIZATION_TEMPLATE,
@ -248,7 +248,7 @@ const Setting: AppRouteRecordRaw = {
component: () => import('@/views/setting/organization/template/components/templateManagement.vue'), component: () => import('@/views/setting/organization/template/components/templateManagement.vue'),
meta: { meta: {
locale: 'menu.settings.organization.templateManagementList', locale: 'menu.settings.organization.templateManagementList',
roles: ['*'], roles: ['ORGANIZATION_TEMPLATE:READ'],
breadcrumbs: [ breadcrumbs: [
{ {
name: SettingRouteEnum.SETTING_ORGANIZATION_TEMPLATE, name: SettingRouteEnum.SETTING_ORGANIZATION_TEMPLATE,

View File

@ -3,31 +3,31 @@ import { TestPlanRouteEnum } from '@/enums/routeEnum';
import { DEFAULT_LAYOUT } from '../base'; import { DEFAULT_LAYOUT } from '../base';
import type { AppRouteRecordRaw } from '../types'; import type { AppRouteRecordRaw } from '../types';
const TestPlan: AppRouteRecordRaw = { // const TestPlan: AppRouteRecordRaw = {
path: '/test-plan', // path: '/test-plan',
name: TestPlanRouteEnum.TEST_PLAN, // name: TestPlanRouteEnum.TEST_PLAN,
redirect: '/test-plan/testPlanIndex', // redirect: '/test-plan/testPlanIndex',
component: DEFAULT_LAYOUT, // component: DEFAULT_LAYOUT,
meta: { // meta: {
locale: 'menu.testPlan', // locale: 'menu.testPlan',
icon: 'icon-icon_test-tracking_filled', // icon: 'icon-icon_test-tracking_filled',
order: 1, // order: 1,
hideChildrenInMenu: true, // hideChildrenInMenu: true,
roles: ['TEST_PLAN:READ'], // roles: ['TEST_PLAN:READ'],
}, // },
children: [ // children: [
// 测试计划 // // 测试计划
{ // {
path: 'testPlanIndex', // path: 'testPlanIndex',
name: TestPlanRouteEnum.TEST_PLAN_INDEX, // name: TestPlanRouteEnum.TEST_PLAN_INDEX,
component: () => import('@/views/test-plan/testPlan/index.vue'), // component: () => import('@/views/test-plan/testPlan/index.vue'),
meta: { // meta: {
locale: 'menu.testPlan', // locale: 'menu.testPlan',
roles: ['TEST_PLAN:READ'], // roles: ['TEST_PLAN:READ'],
isTopMenu: true, // isTopMenu: true,
}, // },
}, // },
], // ],
}; // };
export default TestPlan; // export default TestPlan;

View File

@ -3,28 +3,28 @@ import { UITestRouteEnum } from '@/enums/routeEnum';
import { DEFAULT_LAYOUT } from '../base'; import { DEFAULT_LAYOUT } from '../base';
import type { AppRouteRecordRaw } from '../types'; import type { AppRouteRecordRaw } from '../types';
const UiTest: AppRouteRecordRaw = { // const UiTest: AppRouteRecordRaw = {
path: '/ui-test', // path: '/ui-test',
name: UITestRouteEnum.UI_TEST, // name: UITestRouteEnum.UI_TEST,
redirect: '/ui-test/index', // redirect: '/ui-test/index',
component: DEFAULT_LAYOUT, // component: DEFAULT_LAYOUT,
meta: { // meta: {
locale: 'menu.uiTest', // locale: 'menu.uiTest',
icon: 'icon-icon_ui-test-filled', // icon: 'icon-icon_ui-test-filled',
order: 5, // order: 5,
hideChildrenInMenu: true, // hideChildrenInMenu: true,
roles: ['UI_INDEX:READ'], // roles: ['UI_INDEX:READ'],
}, // },
children: [ // children: [
{ // {
path: 'index', // path: 'index',
name: 'uiTestIndex', // name: 'uiTestIndex',
component: () => import('@/views/ui-test/index.vue'), // component: () => import('@/views/ui-test/index.vue'),
meta: { // meta: {
roles: ['UI_INDEX:READ'], // roles: ['UI_INDEX:READ'],
}, // },
}, // },
], // ],
}; // };
export default UiTest; // export default UiTest;

View File

@ -3,28 +3,28 @@ import { WorkbenchRouteEnum } from '@/enums/routeEnum';
import { DEFAULT_LAYOUT } from '../base'; import { DEFAULT_LAYOUT } from '../base';
import type { AppRouteRecordRaw } from '../types'; import type { AppRouteRecordRaw } from '../types';
const Workbench: AppRouteRecordRaw = { // const Workbench: AppRouteRecordRaw = {
path: '/workbench', // path: '/workbench',
name: WorkbenchRouteEnum.WORKBENCH, // name: WorkbenchRouteEnum.WORKBENCH,
redirect: '/workbench/index', // redirect: '/workbench/index',
component: DEFAULT_LAYOUT, // component: DEFAULT_LAYOUT,
meta: { // meta: {
locale: 'menu.workbench', // locale: 'menu.workbench',
icon: 'icon-icon_pc_filled', // icon: 'icon-icon_pc_filled',
order: 0, // order: 0,
hideChildrenInMenu: true, // hideChildrenInMenu: true,
roles: ['WORKSTATION_INDEX:READ'], // roles: ['WORKSTATION_INDEX:READ'],
}, // },
children: [ // children: [
{ // {
path: 'index', // path: 'index',
name: 'workbenchIndex', // name: 'workbenchIndex',
component: () => import('@/views/workbench/index.vue'), // component: () => import('@/views/workbench/index.vue'),
meta: { // meta: {
roles: ['WORKSTATION_INDEX:READ'], // roles: ['WORKSTATION_INDEX:READ'],
}, // },
}, // },
], // ],
}; // };
export default Workbench; // export default Workbench;

View File

@ -58,7 +58,7 @@ const useAppStore = defineStore('app', {
...defaultLoginConfig, ...defaultLoginConfig,
...defaultPlatformConfig, ...defaultPlatformConfig,
}, },
packageType: 'community', packageType: '',
}), }),
getters: { getters: {
@ -201,6 +201,16 @@ const useAppStore = defineStore('app', {
setCurrentProjectId(id: string) { setCurrentProjectId(id: string) {
this.currentProjectId = id; this.currentProjectId = id;
}, },
/**
*
*/
setPackageType(type: string) {
this.packageType = type;
},
// 重置系统包的版本
resetSystemPackageType() {
this.packageType = '';
},
/** /**
* *
*/ */

View File

@ -37,7 +37,7 @@ export interface AppState {
pageConfig: PageConfig; pageConfig: PageConfig;
innerHeight: number; innerHeight: number;
currentMenuConfig: string[]; currentMenuConfig: string[];
packageType: 'community' | 'enterprise'; packageType: string;
} }
export interface UploadFileTaskState { export interface UploadFileTaskState {

View File

@ -1,11 +1,11 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { getOrdTemplate, getProTemplate } from '@/api/modules/setting/template'; import { getOrdTemplate, getProTemplate } from '@/api/modules/setting/template';
import { hasAnyPermission } from '@/utils/permission';
import useAppStore from '../app'; import useAppStore from '../app';
const appStore = useAppStore(); const appStore = useAppStore();
const useTemplateStore = defineStore('template', { const useTemplateStore = defineStore('template', {
persist: true, persist: true,
state: (): { state: (): {
@ -33,8 +33,13 @@ const useTemplateStore = defineStore('template', {
const currentOrgId = computed(() => appStore.currentOrgId); const currentOrgId = computed(() => appStore.currentOrgId);
const currentProjectId = computed(() => appStore.currentProjectId); const currentProjectId = computed(() => appStore.currentProjectId);
try { try {
if (currentOrgId.value && hasAnyPermission(['ORGANIZATION_TEMPLATE:READ'])) {
this.ordStatus = await getOrdTemplate(currentOrgId.value); this.ordStatus = await getOrdTemplate(currentOrgId.value);
}
if (currentProjectId.value && hasAnyPermission(['PROJECT_TEMPLATE:READ'])) {
this.projectStatus = await getProTemplate(currentProjectId.value); this.projectStatus = await getProTemplate(currentProjectId.value);
}
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }

View File

@ -83,12 +83,6 @@ const useUserStore = defineStore('user', {
appStore.setCurrentOrgId(res.lastOrganizationId || ''); appStore.setCurrentOrgId(res.lastOrganizationId || '');
appStore.setCurrentProjectId(res.lastProjectId || ''); appStore.setCurrentProjectId(res.lastProjectId || '');
this.setInfo(res); this.setInfo(res);
// 登录后初始化系统包版本
appStore.initSystemPackage();
if (appStore.packageType === 'enterprise') {
const licenseStore = useLicenseStore();
licenseStore.getValidateLicense();
}
} catch (err) { } catch (err) {
clearToken(); clearToken();
throw err; throw err;
@ -104,6 +98,7 @@ const useUserStore = defineStore('user', {
licenseStore.removeLicenseStatus(); licenseStore.removeLicenseStatus();
appStore.clearServerMenu(); appStore.clearServerMenu();
appStore.hideLoading(); appStore.hideLoading();
appStore.resetSystemPackageType();
}, },
// 登出 // 登出
async logout() { async logout() {

View File

@ -403,7 +403,7 @@
{ {
title: 'caseManagement.featureCase.tableColumnVersion', title: 'caseManagement.featureCase.tableColumnVersion',
slotName: 'versionName', slotName: 'versionName',
dataIndex: 'versionNam', dataIndex: 'versionName',
width: 300, width: 300,
showTooltip: true, showTooltip: true,
showInTable: true, showInTable: true,
@ -481,20 +481,20 @@
const tableBatchActions = { const tableBatchActions = {
baseAction: [ baseAction: [
{ // {
label: 'caseManagement.featureCase.export', // label: 'caseManagement.featureCase.export',
eventTag: 'export', // eventTag: 'export',
children: [ // children: [
{ // {
label: 'caseManagement.featureCase.exportExcel', // label: 'caseManagement.featureCase.exportExcel',
eventTag: 'exportExcel', // eventTag: 'exportExcel',
}, // },
{ // {
label: 'caseManagement.featureCase.exportXMind', // label: 'caseManagement.featureCase.exportXMind',
eventTag: 'exportXMind', // eventTag: 'exportXMind',
}, // },
], // ],
}, // },
{ {
label: 'common.edit', label: 'common.edit',
eventTag: 'batchEdit', eventTag: 'batchEdit',
@ -1171,9 +1171,12 @@
} }
function showCaseDetailEvent(record: TableData, column: TableColumnData, ev: Event) { function showCaseDetailEvent(record: TableData, column: TableColumnData, ev: Event) {
showDetailDrawer.value = false;
if (column.title === 'name' || column.title === 'num') { if (column.title === 'name' || column.title === 'num') {
const rowIndex = propsRes.value.data.map((item: any) => item.id).indexOf(record.id); const rowIndex = propsRes.value.data.map((item: any) => item.id).indexOf(record.id);
showCaseDetail(record.id, rowIndex); showDetailDrawer.value = true;
activeDetailId.value = record.id;
activeCaseIndex.value = rowIndex;
} }
} }
onMounted(() => { onMounted(() => {

View File

@ -278,7 +278,7 @@
{ {
title: 'caseManagement.featureCase.tableColumnVersion', title: 'caseManagement.featureCase.tableColumnVersion',
slotName: 'versionName', slotName: 'versionName',
dataIndex: 'versionNam', dataIndex: 'versionName',
width: 300, width: 300,
showTooltip: true, showTooltip: true,
showInTable: true, showInTable: true,

View File

@ -36,20 +36,7 @@
const route = useRoute(); const route = useRoute();
const licenseStore = useLicenseStore(); const licenseStore = useLicenseStore();
function getProjectVersion() { const sourceMenuList = ref([
if (licenseStore.hasLicense()) {
return [
{
key: 'projectVersion',
title: t('project.permission.projectVersion'),
level: 2,
name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_PERMISSION_VERSION,
},
];
}
return [];
}
const sourceMenuList = [
{ {
key: 'project', key: 'project',
title: t('project.permission.project'), title: t('project.permission.project'),
@ -68,7 +55,12 @@
level: 2, level: 2,
name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_PERMISSION_MENU_MANAGEMENT, name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_PERMISSION_MENU_MANAGEMENT,
}, },
...getProjectVersion(), {
key: 'projectVersion',
title: t('project.permission.projectVersion'),
level: 2,
name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_PERMISSION_VERSION,
},
{ {
key: 'memberPermission', key: 'memberPermission',
title: t('project.permission.memberPermission'), title: t('project.permission.memberPermission'),
@ -87,13 +79,16 @@
level: 2, level: 2,
name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_PERMISSION_USER_GROUP, name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_PERMISSION_USER_GROUP,
}, },
]; ]);
const menuList = computed(() => { const menuList = computed(() => {
const routerList = router.getRoutes(); const routerList = router.getRoutes();
return sourceMenuList.filter((item) => { return sourceMenuList.value.filter((item) => {
if (item.name) { if (item.name) {
const routerItem = routerList.find((rou) => rou.name === item.name); const routerItem = routerList.find((rou) => rou.name === item.name);
if (!routerItem) return false; if (!routerItem) return false;
if (routerItem.name === ProjectManagementRouteEnum.PROJECT_MANAGEMENT_PERMISSION_VERSION) {
return licenseStore.hasLicense() && permission.accessRouter(routerItem);
}
return permission.accessRouter(routerItem); return permission.accessRouter(routerItem);
} }
return true; return true;
@ -122,6 +117,7 @@
onBeforeMount(() => { onBeforeMount(() => {
setInitRoute(); setInitRoute();
licenseStore.getValidateLicense();
}); });
</script> </script>

View File

@ -1,5 +1,11 @@
<template> <template>
<MsCard has-breadcrumb simple> <FieldSetting mode="project" /></MsCard> <MsCard has-breadcrumb simple>
<FieldSetting
mode="project"
:delete-permission="['PROJECT_TEMPLATE:READ+DELETE']"
:update-permission="['PROJECT_TEMPLATE:READ+UPDATE']"
:create-permission="['PROJECT_TEMPLATE:READ+ADD']"
/></MsCard>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">

View File

@ -42,7 +42,7 @@
</div> </div>
</template> </template>
<template #operation="{ record }"> <template #operation="{ record }">
<div class="flex flex-row flex-nowrap items-center"> <div v-if="!record.enablePlatformDefault" class="flex flex-row flex-nowrap items-center">
<MsButton v-permission="['PROJECT_TEMPLATE:READ+UPDATE']" @click="editTemplate(record.id)">{{ <MsButton v-permission="['PROJECT_TEMPLATE:READ+UPDATE']" @click="editTemplate(record.id)">{{
t('system.orgTemplate.edit') t('system.orgTemplate.edit')
}}</MsButton> }}</MsButton>

View File

@ -1,6 +1,11 @@
<template> <template>
<MsCard has-breadcrumb simple> <MsCard has-breadcrumb simple>
<WorkflowTable mode="project" /> <WorkflowTable
mode="project"
:delete-permission="['PROJECT_TEMPLATE:READ+DELETE']"
:update-permission="['PROJECT_TEMPLATE:READ+UPDATE']"
:create-permission="['PROJECT_TEMPLATE:READ+ADD']"
/>
</MsCard> </MsCard>
</template> </template>

View File

@ -1,7 +1,9 @@
<template> <template>
<MsCard simple> <MsCard simple>
<div class="mb-[16px] flex items-center justify-between"> <div class="mb-[16px] flex items-center justify-between">
<a-button type="primary" @click="showAddProject">{{ t('system.organization.createProject') }}</a-button> <a-button v-permission="['ORGANIZATION_PROJECT:READ+ADD']" type="primary" @click="showAddProject">{{
t('system.organization.createProject')
}}</a-button>
<a-input-search <a-input-search
v-model="keyword" v-model="keyword"
:placeholder="t('system.user.searchUser')" :placeholder="t('system.user.searchUser')"

View File

@ -53,7 +53,7 @@
type="outline" type="outline"
class="arco-btn-outline--secondary" class="arco-btn-outline--secondary"
size="mini" size="mini"
:disabled="!item.config" :disabled="!item.config || !hasAnyPermission(['SYSTEM_SERVICE_INTEGRATION:READ+UPDATE'])"
@click="getValidateHandler(item)" @click="getValidateHandler(item)"
>{{ t('organization.service.testLink') }}</a-button >{{ t('organization.service.testLink') }}</a-button
></span ></span
@ -61,6 +61,7 @@
</a-tooltip> </a-tooltip>
<a-button <a-button
v-else v-else
:disabled="!item.config || !hasAnyPermission(['SYSTEM_SERVICE_INTEGRATION:READ+UPDATE'])"
type="outline" type="outline"
class="arco-btn-outline--secondary" class="arco-btn-outline--secondary"
size="mini" size="mini"
@ -112,6 +113,7 @@
v-model="item.enable" v-model="item.enable"
size="small" size="small"
type="line" type="line"
:disabled="!hasAnyPermission(['SYSTEM_SERVICE_INTEGRATION:READ+UPDATE'])"
@change="(v) => changeStatus(v, item.id)" @change="(v) => changeStatus(v, item.id)"
/> />
</span> </span>
@ -138,6 +140,7 @@
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
import { useAppStore } from '@/store'; import { useAppStore } from '@/store';
import { characterLimit } from '@/utils'; import { characterLimit } from '@/utils';
import { hasAnyPermission } from '@/utils/permission';
import type { ServiceItem, ServiceList } from '@/models/setting/serviceIntegration'; import type { ServiceItem, ServiceList } from '@/models/setting/serviceIntegration';
import { SettingRouteEnum } from '@/enums/routeEnum'; import { SettingRouteEnum } from '@/enums/routeEnum';

View File

@ -7,7 +7,13 @@
}}</a-alert> }}</a-alert>
<div class="mb-4 flex items-center justify-between"> <div class="mb-4 flex items-center justify-between">
<span v-if="isEnabledTemplate" class="font-medium">{{ t('system.orgTemplate.fieldList') }}</span> <span v-if="isEnabledTemplate" class="font-medium">{{ t('system.orgTemplate.fieldList') }}</span>
<a-button v-else type="primary" :disabled="isDisabled" @click="fieldHandler"> <a-button
v-else
v-permission="props.createPermission"
type="primary"
:disabled="isDisabled"
@click="fieldHandler"
>
{{ t('system.orgTemplate.addField') }} {{ t('system.orgTemplate.addField') }}
</a-button> </a-button>
<a-input-search <a-input-search
@ -52,12 +58,15 @@
:ok-text="t('system.orgTemplate.confirm')" :ok-text="t('system.orgTemplate.confirm')"
@confirm="handleOk(record)" @confirm="handleOk(record)"
> >
<MsButton class="!mr-0">{{ t('system.orgTemplate.edit') }}</MsButton></MsPopConfirm <MsButton v-permission="props.updatePermission" class="!mr-0">{{
t('system.orgTemplate.edit')
}}</MsButton></MsPopConfirm
> >
<a-divider v-if="!record.internal" class="h-[12px]" direction="vertical" /> <a-divider v-if="!record.internal" class="h-[12px]" direction="vertical" />
<MsTableMoreAction <MsTableMoreAction
v-if="!record.internal" v-if="!record.internal"
v-permission="props.deletePermission"
:list="moreActions" :list="moreActions"
@select="(item) => handleMoreActionSelect(item, record)" @select="(item) => handleMoreActionSelect(item, record)"
/> />
@ -157,6 +166,9 @@
const props = defineProps<{ const props = defineProps<{
mode: 'organization' | 'project'; mode: 'organization' | 'project';
deletePermission?: string[];
createPermission?: string[];
updatePermission?: string[];
}>(); }>();
const currentOrd = computed(() => appStore.currentOrgId); const currentOrd = computed(() => appStore.currentOrgId);

View File

@ -1,5 +1,11 @@
<template> <template>
<MsCard has-breadcrumb simple> <FieldSetting mode="organization" /></MsCard> <MsCard has-breadcrumb simple>
<FieldSetting
mode="organization"
:delete-permission="['ORGANIZATION_TEMPLATE:READ+DELETE']"
:update-permission="['ORGANIZATION_TEMPLATE:READ+UPDATE']"
:create-permission="['ORGANIZATION_TEMPLATE:READ+ADD']"
/></MsCard>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">

View File

@ -15,7 +15,7 @@
<span @click="fieldSetting">{{ t('system.orgTemplate.fieldSetting') }}</span> <span @click="fieldSetting">{{ t('system.orgTemplate.fieldSetting') }}</span>
<a-divider direction="vertical" /> <a-divider direction="vertical" />
</span> </span>
<span v-permission="['ORGANIZATION_TEMPLATE:READ']" class="operation hover:text-[rgb(var(--primary-5))]"> <span class="operation hover:text-[rgb(var(--primary-5))]">
<span @click="templateManagement">{{ t('system.orgTemplate.TemplateManagement') }}</span> <span @click="templateManagement">{{ t('system.orgTemplate.TemplateManagement') }}</span>
<a-divider v-if="isEnableProject || props.cardItem.key === 'BUG'" direction="vertical" /> <a-divider v-if="isEnableProject || props.cardItem.key === 'BUG'" direction="vertical" />
</span> </span>

View File

@ -34,7 +34,7 @@
{{ record.enableThirdPart ? t('system.orgTemplate.yes') : t('system.orgTemplate.no') }} {{ record.enableThirdPart ? t('system.orgTemplate.yes') : t('system.orgTemplate.no') }}
</template> </template>
<template #operation="{ record }"> <template #operation="{ record }">
<div class="flex flex-row flex-nowrap items-center"> <div v-if="!record.enablePlatformDefault" class="flex flex-row flex-nowrap items-center">
<MsButton v-permission="['ORGANIZATION_TEMPLATE:READ+UPDATE']" @click="editTemplate(record.id)">{{ <MsButton v-permission="['ORGANIZATION_TEMPLATE:READ+UPDATE']" @click="editTemplate(record.id)">{{
t('system.orgTemplate.edit') t('system.orgTemplate.edit')
}}</MsButton> }}</MsButton>

View File

@ -1,6 +1,11 @@
<template> <template>
<MsCard has-breadcrumb simple> <MsCard has-breadcrumb simple>
<WorkflowTable mode="organization" /> <WorkflowTable
mode="organization"
:delete-permission="['ORGANIZATION_TEMPLATE:READ+DELETE']"
:update-permission="['ORGANIZATION_TEMPLATE:READ+UPDATE']"
:create-permission="['ORGANIZATION_TEMPLATE:READ+ADD']"
/>
</MsCard> </MsCard>
</template> </template>

View File

@ -74,6 +74,7 @@
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
import useTemplateStore from '@/store/modules/setting/template'; import useTemplateStore from '@/store/modules/setting/template';
import { hasAnyPermission } from '@/utils/permission';
import type { UpdateWorkFlowSetting, WorkFlowType } from '@/models/setting/template'; import type { UpdateWorkFlowSetting, WorkFlowType } from '@/models/setting/template';
@ -89,6 +90,9 @@
columnItem: TableColumnData; columnItem: TableColumnData;
cellCoordinates: { rowId: string; columnId: string }; cellCoordinates: { rowId: string; columnId: string };
totalData: WorkFlowType[]; totalData: WorkFlowType[];
deletePermission?: string[];
createPermission?: string[];
updatePermission?: string[];
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
@ -149,6 +153,9 @@
// class // class
function setSelectClass() { function setSelectClass() {
if (!hasAnyPermission(props.updatePermission || [])) {
return;
}
if (isUnCreateWorkFlow.value && isSelected.value) { if (isUnCreateWorkFlow.value && isSelected.value) {
styleClass.value = { styleClass.value = {
wrapper: { _select_unCreate_Selected: true }, wrapper: { _select_unCreate_Selected: true },
@ -220,6 +227,9 @@
// //
function createFlowStep() { function createFlowStep() {
if (!hasAnyPermission(props.updatePermission || [])) {
return;
}
if (isEnableProjectState.value) { if (isEnableProjectState.value) {
return; return;
} }
@ -231,6 +241,9 @@
const updateOrdWorkStateFlow = getWorkFlowRequestApi(props.mode).updateFlow; const updateOrdWorkStateFlow = getWorkFlowRequestApi(props.mode).updateFlow;
// //
async function changeWorkFlow(type: string) { async function changeWorkFlow(type: string) {
if (!hasAnyPermission(props.updatePermission || [])) {
return;
}
try { try {
loading.value = true; loading.value = true;
const params: UpdateWorkFlowSetting = { const params: UpdateWorkFlowSetting = {
@ -254,6 +267,9 @@
// //
function cancelFlowStep() { function cancelFlowStep() {
if (!hasAnyPermission(props.updatePermission || [])) {
return;
}
if (isEnableProjectState.value) { if (isEnableProjectState.value) {
return; return;
} }

View File

@ -9,9 +9,14 @@
</a-alert> </a-alert>
<div class="mb-4"> <div class="mb-4">
<div class="mb-4 flex items-center" <div class="mb-4 flex items-center"
><a-button v-if="!isEnableProjectState" class="mr-2" type="outline" @click="addStatus">{{ ><a-button
t('system.orgTemplate.addState') v-if="!isEnableProjectState"
}}</a-button> v-permission="props.createPermission"
class="mr-2"
type="outline"
@click="addStatus"
>{{ t('system.orgTemplate.addState') }}</a-button
>
<span v-else class="mr-2 font-medium text-[var(--color-text-1)]">工作流</span> <span v-else class="mr-2 font-medium text-[var(--color-text-1)]">工作流</span>
<a-popover title="" position="right"> <a-popover title="" position="right">
<MsButton class="!mr-1">{{ t('system.orgTemplate.example') }}</MsButton> <MsButton class="!mr-1">{{ t('system.orgTemplate.example') }}</MsButton>
@ -72,6 +77,7 @@
<div <div
v-if="!isEnableProjectState" v-if="!isEnableProjectState"
v-permission="props.updatePermission"
class="action mr-2 flex h-8 w-8 items-center justify-center rounded opacity-0" class="action mr-2 flex h-8 w-8 items-center justify-center rounded opacity-0"
> >
<MsTableMoreAction <MsTableMoreAction
@ -88,6 +94,9 @@
:state-item="record" :state-item="record"
:cell-coordinates="cellCoordinates" :cell-coordinates="cellCoordinates"
:total-data="dataList" :total-data="dataList"
:delete-permission="props.deletePermission"
:update-permission="props.updatePermission"
:create-permission="props.createPermission"
@click="selectCard(record, column.dataIndex)" @click="selectCard(record, column.dataIndex)"
@ok="getWorkFetchList()" @ok="getWorkFetchList()"
/> />
@ -102,16 +111,28 @@
> >
<template #cell="{ record }"> <template #cell="{ record }">
<div class="ml-4 flex items-center"> <div class="ml-4 flex items-center">
<MsButton v-if="!isEnableProjectState" class="!mr-0 ml-4" @click="editWorkStatus(record)">{{ <MsButton
t('common.edit') v-if="!isEnableProjectState"
}}</MsButton> v-permission="props.updatePermission"
<a-divider v-if="!isEnableProjectState" class="h-[12px]" direction="vertical" /> class="!mr-0 ml-4"
@click="editWorkStatus(record)"
>{{ t('common.edit') }}</MsButton
>
<a-divider
v-if="!isEnableProjectState"
v-permission="props.updatePermission"
class="h-[12px]"
direction="vertical"
/>
<a-checkbox <a-checkbox
v-if="!isEnableProjectState" v-if="!isEnableProjectState"
v-model="record.currentState" v-model="record.currentState"
:disabled="!hasAnyPermission(props.updatePermission || [])"
@change="(value) => changeState(value, record)" @change="(value) => changeState(value, record)"
> >
<MsButton class="!mr-0">{{ t('system.orgTemplate.endState') }}</MsButton></a-checkbox <MsButton v-permission="props.updatePermission" class="!mr-0">{{
t('system.orgTemplate.endState')
}}</MsButton></a-checkbox
> >
<a-divider v-if="!isEnableProjectState" class="h-[12px]" direction="vertical" /> <a-divider v-if="!isEnableProjectState" class="h-[12px]" direction="vertical" />
<MsButton class="!mr-0" @click="detailWorkStatus(record)">{{ t('system.orgTemplate.details') }}</MsButton> <MsButton class="!mr-0" @click="detailWorkStatus(record)">{{ t('system.orgTemplate.details') }}</MsButton>
@ -183,6 +204,7 @@
import { useAppStore } from '@/store'; import { useAppStore } from '@/store';
import useTemplateStore from '@/store/modules/setting/template'; import useTemplateStore from '@/store/modules/setting/template';
import { characterLimit } from '@/utils'; import { characterLimit } from '@/utils';
import { hasAnyPermission } from '@/utils/permission';
import type { SetStateType, WorkFlowType } from '@/models/setting/template'; import type { SetStateType, WorkFlowType } from '@/models/setting/template';
@ -195,6 +217,9 @@
const props = defineProps<{ const props = defineProps<{
mode: 'organization' | 'project'; // || mode: 'organization' | 'project'; // ||
deletePermission?: string[];
createPermission?: string[];
updatePermission?: string[];
}>(); }>();
const currentOrgId = computed(() => appStore.currentOrgId); const currentOrgId = computed(() => appStore.currentOrgId);
@ -356,6 +381,9 @@
const dragChangeRequest = getWorkFlowRequestApi(props.mode).dragChange; const dragChangeRequest = getWorkFlowRequestApi(props.mode).dragChange;
// //
async function handleChange(_data: TableData[]) { async function handleChange(_data: TableData[]) {
if (!hasAnyPermission(props.updatePermission || [])) {
return;
}
const originIds = dataList.value.map((item: any) => item.id); const originIds = dataList.value.map((item: any) => item.id);
dataList.value = _data as WorkFlowType[]; dataList.value = _data as WorkFlowType[];
const dataIds = _data.map((item: any) => item.id); const dataIds = _data.map((item: any) => item.id);

View File

@ -91,7 +91,7 @@
></a-input> ></a-input>
<MsFormItemSub :text="t('system.config.baseInfo.pageUrlSub', { url: defaultUrl })" @fill="fillDefaultUrl" /> <MsFormItemSub :text="t('system.config.baseInfo.pageUrlSub', { url: defaultUrl })" @fill="fillDefaultUrl" />
</a-form-item> </a-form-item>
<a-form-item :label="t('system.config.prometheus')" field="prometheusHost" asterisk-position="end"> <a-form-item v-xpack :label="t('system.config.prometheus')" field="prometheusHost" asterisk-position="end">
<a-input <a-input
v-model:model-value="baseInfoForm.prometheusHost" v-model:model-value="baseInfoForm.prometheusHost"
:max-length="250" :max-length="250"

View File

@ -33,7 +33,8 @@
const tabList = ref([ const tabList = ref([
{ key: 'baseConfig', title: t('system.config.baseConfig'), permission: ['SYSTEM_PARAMETER_SETTING_BASE:READ'] }, { key: 'baseConfig', title: t('system.config.baseConfig'), permission: ['SYSTEM_PARAMETER_SETTING_BASE:READ'] },
{ key: 'pageConfig', title: t('system.config.pageConfig'), permission: ['SYSTEM_PARAMETER_SETTING_DISPLAY:READ'] }, { key: 'pageConfig', title: t('system.config.pageConfig'), permission: ['SYSTEM_PARAMETER_SETTING_DISPLAY:READ'] },
{ key: 'authConfig', title: t('system.config.authConfig'), permission: ['SYSTEM_PARAMETER_SETTING_AUTH:READ'] }, // TODO
// { key: 'authConfig', title: t('system.config.authConfig'), permission: ['SYSTEM_PARAMETER_SETTING_AUTH:READ'] },
{ key: 'memoryCleanup', title: t('system.config.memoryCleanup'), permission: [] }, { key: 'memoryCleanup', title: t('system.config.memoryCleanup'), permission: [] },
]); ]);
@ -53,14 +54,19 @@
} }
); );
const licenseStore = useLicenseStore(); const licenseStore = useLicenseStore();
onMounted(() => {
if (route.query.tab === 'authConfig' && route.query.id) { async function getXpackTab() {
authConfigRef.value?.openAuthDetail(route.query.id as string); await licenseStore.getValidateLicense();
}
if (!licenseStore.hasLicense()) { if (!licenseStore.hasLicense()) {
const excludes = ['baseConfig', 'memoryCleanup']; const excludes = ['baseConfig', 'memoryCleanup'];
tabList.value = tabList.value.filter((item: any) => excludes.includes(item.key)); tabList.value = tabList.value.filter((item: any) => excludes.includes(item.key));
} }
}
onMounted(() => {
if (route.query.tab === 'authConfig' && route.query.id) {
authConfigRef.value?.openAuthDetail(route.query.id as string);
}
getXpackTab();
}); });
</script> </script>

View File

@ -61,7 +61,7 @@ export default {
'system.plugin.enablePluginSuccess': '启用成功', 'system.plugin.enablePluginSuccess': '启用成功',
'system.plugin.disablePluginContent': '项目无法与该平台集成且该平台默认模版不可用,谨慎操作!', 'system.plugin.disablePluginContent': '项目无法与该平台集成且该平台默认模版不可用,谨慎操作!',
'system.plugin.alertDescribe': 'system.plugin.alertDescribe':
'MeterSphereV2.10LTS 版本支持 DevOps、API 导入、请求、项目管理、协议类型的插件,具体支持插件请', 'MeterSphere V2.10 LTS 版本支持 DevOps、API 导入、请求、项目管理、协议类型的插件,具体支持插件请',
'system.plugin.viewTable': '查看表格', 'system.plugin.viewTable': '查看表格',
'system.plugin.downAddress': '更多开源插件,请在此下载', 'system.plugin.downAddress': '更多开源插件,请在此下载',
'system.plugin.goDownload': '去下载', 'system.plugin.goDownload': '去下载',

View File

@ -38,7 +38,11 @@
<MsButton v-permission="['SYSTEM_USER:READ+UPDATE']" @click="showUserModal('edit', record)">{{ <MsButton v-permission="['SYSTEM_USER:READ+UPDATE']" @click="showUserModal('edit', record)">{{
t('system.user.editUser') t('system.user.editUser')
}}</MsButton> }}</MsButton>
<MsTableMoreAction :list="tableActions" @select="handleSelect($event, record)"></MsTableMoreAction> <MsTableMoreAction
v-if="hasAnyPermission(['SYSTEM_USER:READ+UPDATE', 'SYSTEM_USER:READ+UPDATE', 'SYSTEM_USER:READ+DELETE'])"
:list="tableActions"
@select="handleSelect($event, record)"
></MsTableMoreAction>
</template> </template>
</template> </template>
</ms-base-table> </ms-base-table>
@ -219,6 +223,7 @@
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
import { useTableStore } from '@/store'; import { useTableStore } from '@/store';
import { characterLimit } from '@/utils'; import { characterLimit } from '@/utils';
import { hasAnyPermission } from '@/utils/permission';
import { validateEmail, validatePhone } from '@/utils/validate'; import { validateEmail, validatePhone } from '@/utils/validate';
import type { SimpleUserInfo, SystemRole, UserListItem } from '@/models/setting/user'; import type { SimpleUserInfo, SystemRole, UserListItem } from '@/models/setting/user';