feat: 批量操作的权限&缺陷管理权限&用户组权限自动勾选查询&解决控制台vite报错

This commit is contained in:
RubyLiu 2024-01-24 16:17:50 +08:00 committed by 刘瑞斌
parent 99d294694c
commit 57f3493219
11 changed files with 109 additions and 40 deletions

View File

@ -76,6 +76,11 @@ export default defineConfig({
}, },
define: { define: {
'process.env': {}, 'process.env': {},
// 定义特性标志
'__VUE_OPTIONS_API__': true,
'__VUE_PROD_DEVTOOLS__': false,
// 设置hydration不匹配详细信息的标志
'__VUE_PROD_HYDRATION_MISMATCH_DETAILS__': true,
}, },
css: { css: {
preprocessorOptions: { preprocessorOptions: {

View File

@ -12,8 +12,13 @@ import type {
} from '@/models/projectManagement/environmental'; } from '@/models/projectManagement/environmental';
import { OptionsItem } from '@/models/setting/log'; import { OptionsItem } from '@/models/setting/log';
export function updateOrAddEnv(data: EnvDetailItem) { export function updateOrAddEnv(data: { request: EnvDetailItem; fileList: FileItem[] }) {
return MSR.post<EnvDetailItem>({ url: data.id ? envURL.updateEnvUrl : envURL.addEnvUrl, data }); return MSR.uploadFile<EnvDetailItem>(
{ url: data.request.id ? envURL.updateEnvUrl : envURL.addEnvUrl },
data,
'',
true
);
} }
export function listEnv(data: { projectId: string; keyword: string }) { export function listEnv(data: { projectId: string; keyword: string }) {
return MSR.post<EnvListItem[]>({ url: envURL.listEnvUrl, data }); return MSR.post<EnvListItem[]>({ url: envURL.listEnvUrl, data });

View File

@ -28,7 +28,10 @@
</template> </template>
<template #cell="{ record, rowIndex }"> <template #cell="{ record, rowIndex }">
<div class="flex flex-row items-center justify-between"> <div class="flex flex-row items-center justify-between">
<a-checkbox-group v-model="record.perChecked" @change="(v) => handleCellAuthChange(v, rowIndex)"> <a-checkbox-group
:model-value="record.perChecked"
@change="(v, e) => handleCellAuthChange(v, rowIndex, record, e)"
>
<a-checkbox <a-checkbox
v-for="item in record.permissions" v-for="item in record.permissions"
:key="item.id" :key="item.id"
@ -339,9 +342,32 @@
handleAllChange(); handleAllChange();
if (!canSave.value) canSave.value = true; if (!canSave.value) canSave.value = true;
}; };
// read
const setAutoRead = (record: TableData, currentValue: string) => {
if (!record.perChecked.includes(currentValue)) {
//
//
record.perChecked.push(currentValue);
const preStr = currentValue.split(':')[0];
const postStr = currentValue.split(':')[1];
const existRead = record.perChecked.some((item: string) => item.split(':')[1] === 'READ');
if (!existRead && postStr !== 'READ') {
record.perChecked.push(`${preStr}:READ`);
}
} else {
//
record.perChecked.splice(record.perChecked.indexOf(currentValue), 1);
}
};
// change // change
const handleCellAuthChange = (values: (string | number | boolean)[], rowIndex: number) => { const handleCellAuthChange = (
values: (string | number | boolean)[],
rowIndex: number,
record: TableData,
e: Event
) => {
setAutoRead(record, (e.target as HTMLInputElement).value);
if (!tableData.value) return; if (!tableData.value) return;
const tmpArr = tableData.value; const tmpArr = tableData.value;
const length = tmpArr[rowIndex].permissions?.length || 0; const length = tmpArr[rowIndex].permissions?.length || 0;

View File

@ -1,26 +1,28 @@
<template> <template>
<a-dropdown :trigger="props.trigger || 'hover'" @select="selectHandler" @popup-visible-change="visibleChange"> <span>
<slot> <a-dropdown :trigger="props.trigger || 'hover'" @select="selectHandler" @popup-visible-change="visibleChange">
<MsButton type="text" size="mini" class="more-icon"> <slot>
<MsIcon type="icon-icon_more_outlined" size="16" class="text-[var(--color-text-4)]" /> <MsButton type="text" size="mini" class="more-icon">
</MsButton> <MsIcon type="icon-icon_more_outlined" size="16" class="text-[var(--color-text-4)]" />
</slot> </MsButton>
<template #content> </slot>
<template v-for="item of props.list"> <template #content>
<a-divider v-if="item.isDivider" :key="`${item.label}-divider`" margin="4px" /> <template v-for="item of props.list">
<a-doption <a-divider v-if="item.isDivider" :key="`${item.label}-divider`" margin="4px" />
v-else <a-doption
:key="item.label" v-else
:class="item.danger ? 'error-6' : ''" :key="item.label"
:disabled="item.disabled" :class="item.danger ? 'error-6' : ''"
:value="item.eventTag" :disabled="item.disabled"
> :value="item.eventTag"
<MsIcon v-if="item.icon" :type="item.icon" /> >
{{ t(item.label || '') }} <MsIcon v-if="item.icon" :type="item.icon" />
</a-doption> {{ t(item.label || '') }}
</a-doption>
</template>
</template> </template>
</template> </a-dropdown>
</a-dropdown> </span>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">

View File

@ -4,7 +4,7 @@
<template v-for="(element, idx) in baseAction" :key="element.label"> <template v-for="(element, idx) in baseAction" :key="element.label">
<a-divider v-if="element.isDivider" class="divider mx-0 my-[6px]" /> <a-divider v-if="element.isDivider" class="divider mx-0 my-[6px]" />
<a-button <a-button
v-if="!element.isDivider && !element.children" v-if="!element.isDivider && !element.children && hasAnyPermission(element.permission as string[])"
class="ml-[12px]" class="ml-[12px]"
:class="{ :class="{
'arco-btn-outline--danger': element.danger, 'arco-btn-outline--danger': element.danger,
@ -15,7 +15,11 @@
>{{ t(element.label as string) }}</a-button >{{ t(element.label as string) }}</a-button
> >
<!-- baseAction多菜单选择 --> <!-- baseAction多菜单选择 -->
<a-dropdown v-if="!element.isDivider && element.children" position="tr" @select="handleSelect"> <a-dropdown
v-if="!element.isDivider && element.children && hasAnyPermission(element.permission as string[])"
position="tr"
@select="handleSelect"
>
<a-button <a-button
class="ml-[12px]" class="ml-[12px]"
:class="{ :class="{
@ -43,7 +47,11 @@
<template #content> <template #content>
<template v-for="element in moreAction" :key="element.label"> <template v-for="element in moreAction" :key="element.label">
<a-divider v-if="element.isDivider" margin="4px" /> <a-divider v-if="element.isDivider" margin="4px" />
<a-doption v-else :value="element" :class="{ delete: element.danger }"> <a-doption
v-else-if="hasAnyPermission(element.permission as string[])"
:value="element"
:class="{ delete: element.danger }"
>
{{ t(element.label as string) }} {{ t(element.label as string) }}
</a-doption> </a-doption>
</template> </template>
@ -59,6 +67,7 @@
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import { getNodeWidth } from '@/utils/dom'; import { getNodeWidth } from '@/utils/dom';
import { hasAnyPermission } from '@/utils/permission';
import { BatchActionConfig, BatchActionParams } from './type'; import { BatchActionConfig, BatchActionParams } from './type';
import ResizeObserver from 'resize-observer-polyfill'; import ResizeObserver from 'resize-observer-polyfill';

View File

@ -127,6 +127,7 @@ export interface BatchActionParams {
isDivider?: boolean; isDivider?: boolean;
danger?: boolean; danger?: boolean;
children?: BatchActionParams[]; children?: BatchActionParams[];
permission?: string[];
} }
export interface BatchActionConfig { export interface BatchActionConfig {
baseAction: BatchActionParams[]; baseAction: BatchActionParams[];

View File

@ -22,7 +22,7 @@ const BugManagement: AppRouteRecordRaw = {
component: () => import('@/views/bug-management/index.vue'), component: () => import('@/views/bug-management/index.vue'),
meta: { meta: {
locale: 'bugManagement.index', locale: 'bugManagement.index',
roles: ['*'], roles: ['PROJECT_BUG:READ'],
isTopMenu: true, isTopMenu: true,
}, },
}, },
@ -33,7 +33,7 @@ const BugManagement: AppRouteRecordRaw = {
component: () => import('@/views/bug-management/edit.vue'), component: () => import('@/views/bug-management/edit.vue'),
meta: { meta: {
locale: 'bugManagement.editBug', locale: 'bugManagement.editBug',
roles: ['*'], roles: ['PROJECT_BUG:READ+ADD', 'PROJECT_BUG:READ+UPDATE'],
breadcrumbs: [ breadcrumbs: [
{ {
name: BugManagementRouteEnum.BUG_MANAGEMENT_INDEX, name: BugManagementRouteEnum.BUG_MANAGEMENT_INDEX,
@ -54,7 +54,7 @@ const BugManagement: AppRouteRecordRaw = {
component: () => import('@/views/bug-management/recycle.vue'), component: () => import('@/views/bug-management/recycle.vue'),
meta: { meta: {
locale: 'bugManagement.recycle', locale: 'bugManagement.recycle',
roles: ['*'], roles: ['PROJECT_BUG:READ'],
isTopMenu: true, isTopMenu: true,
}, },
}, },

View File

@ -22,6 +22,9 @@ export function hasPermission(permission: string, typeList: string[]) {
// 判断是否有权限 // 判断是否有权限
export function hasAnyPermission(permissions: string[], typeList = ['PROJECT', 'ORGANIZATION', 'SYSTEM']) { export function hasAnyPermission(permissions: string[], typeList = ['PROJECT', 'ORGANIZATION', 'SYSTEM']) {
if (!permissions || permissions.length === 0) {
return true;
}
return permissions.some((permission) => hasPermission(permission, typeList)); return permissions.some((permission) => hasPermission(permission, typeList));
} }

View File

@ -13,6 +13,6 @@
const router = useRouter(); const router = useRouter();
const back = () => { const back = () => {
// warning Go to the node that has the permission // warning Go to the node that has the permission
router.push({ name: 'workbench' }); router.push({ name: 'workstation' });
}; };
</script> </script>

View File

@ -8,8 +8,14 @@
> >
<template #left> <template #left>
<div class="flex gap-[12px]"> <div class="flex gap-[12px]">
<a-button type="primary" @click="handleCreate">{{ t('bugManagement.createBug') }} </a-button> <a-button v-permission="['PROJECT_BUG:READ+ADD']" type="primary" @click="handleCreate"
<a-button :disabled="syncBugLoading" type="outline" @click="handleSync" >{{ t('bugManagement.createBug') }}
</a-button>
<a-button
v-permission="['PROJECT_BUG:READ+IMPORT']"
:disabled="syncBugLoading"
type="outline"
@click="handleSync"
>{{ t('bugManagement.syncBug') }} >{{ t('bugManagement.syncBug') }}
</a-button> </a-button>
</div> </div>
@ -40,11 +46,20 @@
</template> </template>
<template #operation="{ record }"> <template #operation="{ record }">
<div class="flex flex-row flex-nowrap"> <div class="flex flex-row flex-nowrap">
<MsButton class="!mr-0" @click="handleCopy(record)">{{ t('common.copy') }}</MsButton> <span v-permission="['PROJECT_BUG:READ+ADD']" class="flex flex-row">
<a-divider direction="vertical" /> <MsButton class="!mr-0" @click="handleCopy(record)">{{ t('common.copy') }}</MsButton>
<MsButton class="!mr-0" @click="handleEdit(record)">{{ t('common.edit') }}</MsButton> <a-divider direction="vertical" />
<a-divider direction="vertical" /> </span>
<MsTableMoreAction :list="moreActionList" trigger="click" @select="handleMoreActionSelect($event, record)" /> <span v-permission="['PROJECT_BUG:READ+UPDATE']" class="flex flex-row">
<MsButton class="!mr-0" @click="handleEdit(record)">{{ t('common.edit') }}</MsButton>
<a-divider direction="vertical" />
</span>
<MsTableMoreAction
v-permission="['PROJECT_BUG:READ+DELETE']"
:list="moreActionList"
trigger="click"
@select="handleMoreActionSelect($event, record)"
/>
</div> </div>
</template> </template>
<template #empty> </template> <template #empty> </template>
@ -364,15 +379,18 @@
{ {
label: 'common.export', label: 'common.export',
eventTag: 'export', eventTag: 'export',
permission: ['PROJECT_BUG:READ+EXPORT'],
}, },
{ {
label: 'common.edit', label: 'common.edit',
eventTag: 'edit', eventTag: 'edit',
permission: ['PROJECT_BUG:READ+UPDATE'],
}, },
{ {
label: 'common.delete', label: 'common.delete',
eventTag: 'delete', eventTag: 'delete',
danger: true, danger: true,
permission: ['PROJECT_BUG:READ+DELETE'],
}, },
], ],
}; };

View File

@ -119,7 +119,7 @@
try { try {
loading.value = true; loading.value = true;
store.currentEnvDetailInfo.mock = true; store.currentEnvDetailInfo.mock = true;
const res = await updateOrAddEnv(store.currentEnvDetailInfo); const res = await updateOrAddEnv({ fileList: [], request: store.currentEnvDetailInfo });
store.currentEnvDetailInfo = res; store.currentEnvDetailInfo = res;
Message.success(t('common.saveSuccess')); Message.success(t('common.saveSuccess'));
} catch (error) { } catch (error) {