feat(项目设置): 菜单管理误报规则批量操作

This commit is contained in:
RubyLiu 2023-10-19 20:07:38 +08:00 committed by Craftsman
parent 2984c54917
commit 45e7e45064
13 changed files with 306 additions and 151 deletions

View File

@ -4,6 +4,7 @@ import * as Url from '@/api/requrls/project-management/menuManagement';
import { TableQueryParams } from '@/models/common';
import type {
FakeTableListItem,
FakeTableOperationParams,
MenuTableConfigItem,
MenuTableListItem,
MenuTableListParams,
@ -122,20 +123,20 @@ export function postFakeTableList(data: TableQueryParams) {
return MSR.post<FakeTableListItem[]>({ url: `${Url.postFakeTableUrl}`, data });
}
// 误报规则新增
export function postAddFake(data: any) {
export function postAddFake(data: FakeTableListItem[]) {
return MSR.post<FakeTableListItem[]>({ url: Url.postFakeTableAddUrl, data });
}
// 误报规则更新
export function postUpdateFake(data: any) {
export function postUpdateFake(data: FakeTableListItem[]) {
return MSR.post<FakeTableListItem[]>({ url: Url.postFakeTableUpdateUrl, data });
}
// 误报规则启用禁用
export function postUpdateEnableFake(data: any) {
export function postUpdateEnableFake(data: FakeTableOperationParams) {
return MSR.post<FakeTableListItem[]>({ url: Url.postFakeTableEnableUrl, data });
}
// 误报规则删除
export function getDeleteFake(data: any) {
return MSR.get<FakeTableListItem[]>({ url: Url.getFakeTableDeleteUrl, data });
export function getDeleteFake(data: FakeTableOperationParams) {
return MSR.post<FakeTableListItem[]>({ url: Url.getFakeTableDeleteUrl, data });
}

View File

@ -0,0 +1 @@
<svg fill="currentColor" viewBox="0 -256 1024 1024" width="1em" height="1em"><path d="M583.338667 17.066667c18.773333 0 34.133333 15.36 34.133333 34.133333v349.013333l313.344-101.888a34.133333 34.133333 0 0 1 43.008 22.016l42.154667 129.706667a34.133333 34.133333 0 0 1-21.845334 43.178667l-315.733333 102.4 208.896 287.744a34.133333 34.133333 0 0 1-7.509333 47.786666l-110.421334 80.213334a34.133333 34.133333 0 0 1-47.786666-7.509334L505.685333 706.218667 288.426667 1005.226667a34.133333 34.133333 0 0 1-47.786667 7.509333l-110.421333-80.213333a34.133333 34.133333 0 0 1-7.509334-47.786667l214.186667-295.253333L29.013333 489.813333a34.133333 34.133333 0 0 1-22.016-43.008l42.154667-129.877333a34.133333 34.133333 0 0 1 43.008-22.016l320.512 104.106667L412.672 51.2c0-18.773333 15.36-34.133333 34.133333-34.133333h136.533334z"></path></svg>

After

Width:  |  Height:  |  Size: 844 B

View File

@ -24,7 +24,6 @@
:key="`${model.filed}${index}`"
:field="`list[${index}].${model.filed}`"
:class="index > 0 ? 'hidden-item' : 'mb-0 flex-1'"
:label="index === 0 && model.label ? t(model.label) : ''"
:rules="
model.rules?.map((e) => {
if (e.notRepeat === true) {
@ -41,6 +40,14 @@
:content-flex="model.type !== 'multiple'"
:merge-props="model.type !== 'multiple'"
>
<template #label>
<div class="inline-flex flex-row">
<div>{{ index === 0 && model.label ? t(model.label) : '' }}</div>
<div v-if="model.hasRedStar" class="ml-[2px] flex items-center">
<svg-icon width="6px" height="6px" name="form-star" class="text-[rgb(var(--danger-6))]" />
</div>
</div>
</template>
<a-input
v-if="model.type === 'input'"
v-model="element[model.filed]"
@ -60,12 +67,13 @@
/>
<MsTagsInput
v-if="model.type === 'tagInput'"
v-model="element[model.filed]"
v-model:model-value="element[model.filed]"
class="flex-1"
:placeholder="t(model.placeholder || 'common.tagPlaceholder')"
allow-clear
unique-value
retain-input-value
:max-tag-count="2"
/>
<a-select
v-if="model.type === 'select'"
@ -75,7 +83,7 @@
:options="model.options"
:field-names="model.filedNames"
/>
<div v-if="model.type === 'multiple'" class="flex flex-row items-center gap-[4px]">
<div v-if="model.type === 'multiple'" class="flex flex-row gap-[4px]">
<a-form-item
v-for="(child, childIndex) in model.children"
:key="`${child.filed}${childIndex}${index}`"
@ -85,6 +93,7 @@
:hide-asterisk="child.hideAsterisk"
:hide-label="child.hideLabel"
class="hidden-item"
:rules="child.rules"
>
<a-input
v-if="child.type === 'input'"
@ -101,7 +110,6 @@
:placeholder="t(child.placeholder || '')"
:options="child.options"
:field-names="child.filedNames"
:default-value="child.defaultValue"
/>
</a-form-item>
</div>
@ -109,6 +117,7 @@
<div v-if="showEnable">
<a-switch
v-model="element.enable"
class="mt-[8px]"
:style="{ 'margin-top': index === 0 && !props.isShowDrag ? '36px' : '' }"
size="small"
/>
@ -192,7 +201,24 @@
*/
watchEffect(() => {
props.models.forEach((e) => {
formItem[e.filed] = e.type === 'inputNumber' ? null : '';
//
let value = null;
if (e.type === 'inputNumber') {
value = null;
} else if (e.type === 'tagInput') {
value = [];
} else {
value = e.defaultValue;
}
formItem[e.filed] = value;
if (props.showEnable) {
//
formItem.enable = false;
}
//
e.children?.forEach((child) => {
formItem[child.filed] = child.type === 'inputNumber' ? null : child.defaultValue;
});
});
form.value.list = [{ ...formItem }];
if (props.defaultVals?.length) {

View File

@ -24,6 +24,7 @@ export interface FormItemModel {
filedNames?: SelectFieldNames; // select option 选项字段名
className?: string; // 自定义样式
defaultValue?: string | string[] | number | number[] | boolean; // 默认值
hasRedStar?: boolean; // 是否有红星
}
declare const _default: import('vue').DefineComponent<

View File

@ -178,7 +178,6 @@
//
const removeField = (index: number) => {
debugger;
formModels.value.splice(index, 1);
};

View File

@ -6,6 +6,7 @@
:allow-clear="props.allowClear"
:retain-input-value="props.retainInputValue"
:unique-value="props.uniqueValue"
:max-tag-count="props.maxTagCount"
@press-enter="tagInputEnter"
@blur="tagInputBlur"
>
@ -39,6 +40,7 @@
customPrefix?: boolean;
customTag?: boolean;
customSuffix?: boolean;
maxTagCount?: number;
}>(),
{
retainInputValue: true,

View File

@ -61,7 +61,7 @@ export default function useModal() {
},
openDeleteModal: (options: DeleteModalOptions) => {
const deleteLoading = ref<boolean>(false);
Modal.warning({
Modal.error({
okText: t('common.confirmDelete'),
cancelText: t('common.cancel'),
hideCancel: false,

View File

@ -63,4 +63,5 @@ export default {
'common.setting': '设置',
'common.resetDefault': '恢复默认',
'common.tagPlaceholder': '添加标签回车结束',
'common.batchModify': '批量修改',
};

View File

@ -1,3 +1,5 @@
import { TableQueryParams } from '../common';
export interface MenuTableConfigItem {
[key: string]: any;
}
@ -28,9 +30,21 @@ export type SelectValue =
export interface FakeTableListItem {
name: string;
enable: boolean;
enable?: boolean;
label: string[];
rule: string;
creator: string;
updateDate: string;
type: string | string[];
id?: string;
projectId?: string;
typeList?: string[];
}
export interface FakeTableOperationParams {
projectId: string;
excludeIds?: string[]; // 排除的id
selectedIds?: string[]; // 选中的id
selectAll: boolean; // 是否跨页全选
params?: TableQueryParams; // 查询参数
enable?: boolean; // 是否启用
}

View File

@ -1,7 +1,7 @@
<template>
<MsCard simple>
<div class="mb-4 flex items-center justify-between">
<a-button type="primary" @click="showAddRule">{{ t('project.menu.addFalseAlertRules') }}</a-button>
<a-button type="primary" @click="showAddRule(undefined)">{{ t('project.menu.addFalseAlertRules') }}</a-button>
<a-input-search
v-model="keyword"
:placeholder="t('project.menu.nameSearch')"
@ -11,20 +11,33 @@
@search="fetchData"
></a-input-search>
</div>
<MsBaseTable v-bind="propsRes" v-on="propsEvent">
<MsBaseTable
v-bind="propsRes"
:action-config="tableBatchActions"
v-on="propsEvent"
@batch-action="handleTableBatch"
>
<template #label="{ record }">
<MsTagGroup is-string-tag theme="outline" :tag-list="record.typeList"> </MsTagGroup>
</template>
<template #operation="{ record }">
<template v-if="record.deleted">
<MsButton @click="handleRevokeDelete(record)">{{ t('common.revokeDelete') }}</MsButton>
</template>
<template v-else-if="!record.enable">
<MsButton @click="handleEnableOrDisableProject(record)">{{ t('common.enable') }}</MsButton>
<MsButton @click="handleDelete(record)">{{ t('common.delete') }}</MsButton>
<template v-if="!record.enable">
<MsButton class="!mr-0" @click="handleEnableOrDisableProject(record.id)">{{ t('common.enable') }}</MsButton>
<a-divider direction="vertical" />
<MsButton class="!mr-0" @click="handleDelete(record.id)">{{ t('common.delete') }}</MsButton>
</template>
<template v-else>
<MsButton @click="showAddProjectModal(record)">{{ t('common.edit') }}</MsButton>
<MsButton @click="showAddUserModal(record)">{{ t('system.organization.addMember') }}</MsButton>
<MsButton @click="handleEnableOrDisableProject(record, false)">{{ t('common.end') }}</MsButton>
<MsTableMoreAction :list="tableActions" @select="handleMoreAction($event, record)"></MsTableMoreAction>
<MsButton class="!mr-0" @click="showAddRule(record)">{{ t('common.edit') }}</MsButton>
<a-divider direction="vertical" />
<MsButton class="!mr-0" @click="handleEnableOrDisableProject(record.id, false)">{{
t('common.disable')
}}</MsButton>
<a-divider direction="vertical" />
<MsTableMoreAction
class="!mr-0"
:list="tableActions"
@select="handleMoreAction($event, record)"
></MsTableMoreAction>
</template>
</template>
</MsBaseTable>
@ -39,47 +52,49 @@
:body-style="{ padding: '0px' }"
:width="1200"
:ok-loading="addLoading"
:ok-text="ruleFormMode === 'create' ? t('common.add') : t('common.update')"
@cancel="handleCancel(false)"
@confirm="handleConfirm"
>
<a-form ref="ruleFormRef" class="rounded-[4px]" :model="ruleForm" layout="vertical">
<MsBatchForm
ref="batchFormRef"
:models="batchFormModels"
:form-mode="ruleFormMode"
add-text="system.user.addUser"
:default-vals="ruleForm.list"
show-enable
></MsBatchForm>
</a-form>
<MsBatchForm
ref="batchFormRef"
:models="batchFormModels"
:form-mode="ruleFormMode"
add-text="project.menu.rule.addResource"
:default-vals="currentList"
show-enable
:is-show-drag="false"
></MsBatchForm>
</MsDrawer>
</template>
<script lang="ts" setup>
import { FormInstance, Message, TableData } from '@arco-design/web-vue';
import { Message, TableData } from '@arco-design/web-vue';
import MsButton from '@/components/pure/ms-button/index.vue';
import MsCard from '@/components/pure/ms-card/index.vue';
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import { MsTableColumn } from '@/components/pure/ms-table/type';
import { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable';
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
import MsTagGroup from '@/components/pure/ms-tag/ms-tag-group.vue';
import MsBatchForm from '@/components/business/ms-batch-form/index.vue';
import { FormItemModel } from '@/components/business/ms-batch-form/types';
import { postFakeTableList } from '@/api/modules/project-management/menuManagement';
import {
createOrUpdateProjectByOrg,
deleteProjectByOrg,
enableOrDisableProjectByOrg,
postProjectTableByOrg,
revokeDeleteProjectByOrg,
} from '@/api/modules/setting/organizationAndProject';
getDeleteFake,
postAddFake,
postFakeTableList,
postUpdateEnableFake,
postUpdateFake,
} from '@/api/modules/project-management/menuManagement';
import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal';
import { useAppStore } from '@/store';
import { validateEmail, validatePhone } from '@/utils/validate';
import { FakeTableListItem } from '@/models/projectManagement/menuManagement';
import { TableKeyEnum } from '@/enums/tableEnum';
type UserModalMode = 'create' | 'edit';
@ -89,69 +104,112 @@
const currentProjectId = computed(() => appStore.currentProjectId);
const addVisible = ref(false);
const addLoading = ref(false);
const ruleFormRef = ref<FormInstance>();
const batchFormRef = ref<FormInstance>();
const batchFormRef = ref();
const ruleFormMode = ref<UserModalMode>('create');
const ruleForm = reactive({
name: '',
enable: true,
label: '',
type: '',
creator: '',
updateTime: '',
list: [],
});
const currentList = ref<FakeTableListItem[]>([]);
const headerOptions = computed(() => [
{ label: 'Response Headers', value: 'headers' },
{ label: 'Response Data', value: 'data' },
{ label: 'Response Body', value: 'body' },
]);
const relationOptions = computed(() => [
{ label: '包含', value: 'contain' },
{ label: '不包含', value: 'notContain' },
{ label: '等于', value: 'equal' },
{ label: '不等于', value: 'notEqual' },
{ label: '正则匹配', value: 'regex' },
{ label: '以...开始', value: 'startWith' },
{ label: '以...结束', value: 'endWith' },
]);
const tableBatchActions = {
baseAction: [
{
label: 'common.batchModify',
eventTag: 'batchModify',
},
{
label: 'common.enable',
eventTag: 'batchEnable',
},
{
label: 'common.disable',
eventTag: 'batchDisable',
},
{
label: 'common.delete',
eventTag: 'batchDelete',
danger: true,
},
],
};
const getRowRuleString = (record: TableData) => {
const header = headerOptions.value.find((item) => item.value === record.respType)?.label;
const relation = relationOptions.value.find((item) => item.value === record.relation)?.label;
return `${header} ${relation} ${record.expression}`;
};
const rulesColumn: MsTableColumn = [
{
title: 'project.menu.rule.name',
dataIndex: 'name',
width: 100,
showTooltip: true,
width: 149,
},
{
title: 'project.menu.rule.enable',
dataIndex: 'enable',
showTooltip: true,
width: 143,
},
{
title: 'project.menu.rule.label',
dataIndex: 'label',
width: 100,
showTooltip: true,
dataIndex: 'type',
slotName: 'label',
isTag: true,
width: 146,
},
{
title: 'project.menu.rule.rule',
dataIndex: 'type',
width: 100,
dataIndex: 'ruleResult',
showTooltip: true,
},
{
title: 'project.menu.rule.creator',
dataIndex: 'creator',
width: 100,
dataIndex: 'createUser',
width: 108,
showTooltip: true,
},
{
title: 'project.menu.rule.updateTime',
dataIndex: 'updateTime',
width: 100,
showTooltip: true,
width: 210,
},
{
title: 'project.menu.rule.operation',
dataIndex: 'operation',
slotName: 'operation',
width: 100,
showTooltip: true,
width: 169,
},
];
const { propsRes, propsEvent, loadList, setKeyword, setLoadListParams } = useTable(postFakeTableList, {
columns: rulesColumn,
tableKey: TableKeyEnum.PROJECT_MANAGEMENT_MENU_FALSE_ALERT,
selectable: true,
noDisable: false,
size: 'default',
});
const { propsRes, propsEvent, loadList, setKeyword, setLoadListParams } = useTable(
postFakeTableList,
{
scroll: { x: 1200 },
columns: rulesColumn,
tableKey: TableKeyEnum.PROJECT_MANAGEMENT_MENU_FALSE_ALERT,
selectable: true,
noDisable: false,
size: 'default',
},
(record: TableData) => {
record.typeList = record.type.split(',');
record.ruleResult = getRowRuleString(record);
return record;
}
);
const { openDeleteModal, openModal } = useModal();
@ -162,13 +220,22 @@
await loadList();
};
const handleDelete = (record: TableData) => {
const handleDelete = (v: string | BatchActionQueryParams) => {
openDeleteModal({
title: t('system.organization.deleteName', { name: record.name }),
content: t('system.organization.deleteTip'),
title: t('project.menu.rule.deleteRule', { size: typeof v === 'string' ? 1 : v.currentSelectCount }),
content: t('project.menu.rule.deleteRuleTip'),
onBeforeOk: async () => {
try {
await deleteProjectByOrg(record.id);
if (typeof v === 'string') {
//
await getDeleteFake({ selectedIds: [v], projectId: currentProjectId.value, selectAll: false });
} else {
//
await getDeleteFake({
...v,
projectId: currentProjectId.value,
});
}
Message.success(t('common.deleteSuccess'));
fetchData();
} catch (error) {
@ -181,7 +248,7 @@
const handleMoreAction = (tag: ActionsItem, record: TableData) => {
if (tag.eventTag === 'delete') {
handleDelete(record);
handleDelete(record.id);
}
};
@ -193,19 +260,34 @@
},
];
const handleEnableOrDisableProject = async (record: any, isEnable = true) => {
const title = isEnable ? t('system.project.enableTitle') : t('system.project.endTitle');
const content = isEnable ? t('system.project.enableContent') : t('system.project.endContent');
const handleEnableOrDisableProject = async (v: string | BatchActionQueryParams, isEnable = true) => {
const title = isEnable ? t('project.menu.rule.enableRule') : t('project.menu.rule.disableRule');
const content = isEnable ? t('project.menu.rule.enableRuleTip') : t('project.menu.rule.disableRuleTip');
const okText = isEnable ? t('common.confirmEnable') : t('common.confirmClose');
openModal({
type: 'error',
type: 'info',
cancelText: t('common.cancel'),
title,
content,
okText,
onBeforeOk: async () => {
try {
await enableOrDisableProjectByOrg(record.id, isEnable);
if (typeof v === 'string') {
// /
await postUpdateEnableFake({
selectedIds: [v],
projectId: currentProjectId.value,
enable: isEnable,
selectAll: false,
});
} else {
// /
await postUpdateEnableFake({
...v,
projectId: currentProjectId.value,
enable: isEnable,
});
}
Message.success(isEnable ? t('common.enableSuccess') : t('common.closeSuccess'));
fetchData();
} catch (error) {
@ -216,59 +298,91 @@
hideCancel: false,
});
};
const handleRevokeDelete = async (record: TableData) => {
openModal({
type: 'error',
cancelText: t('common.cancel'),
title: t('system.project.revokeDeleteTitle', { name: record.name }),
content: t('system.project.enableContent'),
okText: t('common.revokeDelete'),
onBeforeOk: async () => {
try {
await revokeDeleteProjectByOrg(record.id);
Message.success(t('common.revokeDeleteSuccess'));
fetchData();
} catch (error) {
// eslint-disable-next-line no-console
console.error(error);
const showAddRule = (record?: FakeTableListItem | FakeTableListItem[]) => {
if (record) {
//
ruleFormMode.value = 'edit';
if (record instanceof Array) {
record.forEach((item) => {
if (typeof item.type === 'string') {
item.type = item.type.split(',');
}
});
//
currentList.value = record;
} else {
//
if (typeof record.type === 'string') {
record.type = record.type.split(',');
}
},
hideCancel: false,
});
};
const showAddProjectModal = (record: any) => {
console.log(record);
};
const showAddUserModal = (record: any) => {
console.log(record);
};
const showAddRule = () => {
currentList.value = [record];
}
} else {
ruleFormMode.value = 'create';
}
addVisible.value = true;
};
const handleConfirm = () => {
addVisible.value = false;
};
const handleCancel = (shouldSearch: boolean) => {
const handleCancel = (shouldSearch: boolean, isClose = true) => {
if (shouldSearch) {
fetchData();
}
addVisible.value = false;
if (isClose) {
addVisible.value = false;
}
};
const handleConfirm = () => {
batchFormRef.value.formValidate(async (list: FakeTableListItem[]) => {
try {
addLoading.value = true;
// eslint-disable-next-line no-console
const tmpArr = JSON.parse(JSON.stringify(list)) as FakeTableListItem[];
tmpArr.forEach((element) => {
if (ruleFormMode.value === 'create') {
element.projectId = currentProjectId.value;
} else if (element.typeList) {
delete element.typeList;
}
element.type = element.type instanceof Array ? element.type.join(',') : '';
});
if (ruleFormMode.value === 'create') {
await postAddFake(tmpArr);
Message.success(t('common.addSuccess'));
} else {
await postUpdateFake(tmpArr);
Message.success(t('common.updateSuccess'));
}
handleCancel(true, false);
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
addLoading.value = false;
}
});
};
/**
* 校验用户姓名
* @param value 输入的值
* @param callback 失败回调入参是提示信息
* 处理表格选中后批量操作
* @param event 批量操作事件对象
*/
function checkUerName(value: string | undefined, callback: (error?: string) => void) {
if (value === '' || value === undefined) {
callback(t('system.user.createUserNameNotNull'));
} else if (value.length > 50) {
callback(t('system.user.createUserNameOverLength'));
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
switch (event.eventTag) {
case 'batchModify':
// showAddRule(params);
break;
case 'batchEnable':
handleEnableOrDisableProject(params);
break;
case 'batchDisable':
handleEnableOrDisableProject(params, false);
break;
default:
handleDelete(params);
}
}
@ -278,9 +392,8 @@
type: 'input',
label: 'project.menu.rule.ruleName',
rules: [
{ required: true, message: t('system.user.createUserNameNotNull') },
{ validator: checkUerName },
{ notRepeat: true, message: 'system.user.createUserEmailNoRepeat' },
{ required: true, message: t('project.menu.rule.ruleNameNotNull') },
{ notRepeat: true, message: 'project.menu.rule.ruleNameRepeat' },
],
},
{
@ -292,40 +405,26 @@
filed: 'rule',
type: 'multiple',
label: 'project.menu.rule.rule',
// rules: [{ required: true, message: t('system.user.createUserEmailNotNull') }],
hasRedStar: true,
children: [
{
filed: 'respType', // -/header/data/body
type: 'select',
rules: [{ required: true, message: t('system.user.createUserEmailNotNull') }],
options: [
{ label: 'Response Headers', value: 'headers' },
{ label: 'Response Data', value: 'data' },
{ label: 'Response Body', value: 'body' },
],
options: headerOptions.value,
className: 'w-[205px]',
defaultValue: 'headers',
},
{
filed: 'relation', // -
type: 'select',
options: [
{ label: '包含', value: 'contain' },
{ label: '不包含', value: 'notContain' },
{ label: '等于', value: 'equal' },
{ label: '不等于', value: 'notEqual' },
{ label: '正则匹配', value: 'regex' },
{ label: '以...开始', value: 'startWith' },
{ label: '以...结束', value: 'endWith' },
],
rules: [{ required: true, message: t('system.user.createUserEmailNotNull') }],
options: relationOptions.value,
className: 'w-[120px]',
defaultValue: 'contain',
defaultValue: 'equal',
},
{
filed: 'expression', // -
type: 'input',
rules: [{ required: true, message: t('system.user.createUserEmailNotNull') }],
rules: [{ required: true, message: t('project.menu.rule.expressionNotNull') }],
className: 'w-[301px]',
},
],

View File

@ -72,4 +72,14 @@ export default {
'project.menu.rule.updateTime': '更新时间',
'project.menu.rule.operation': '操作',
'project.menu.rule.ruleName': '规则名称',
'project.menu.rule.ruleNameNotNull': '规则名称不能为空',
'project.menu.rule.ruleNameRepeat': '名称重复请修改',
'project.menu.rule.expressionNotNull': '限制条件不能为空',
'project.menu.rule.addResource': '添加资源',
'project.menu.rule.disableRule': '禁用规则',
'project.menu.rule.disableRuleTip': '禁用后,不展示在规则切换列表',
'project.menu.rule.enableRule': '启用规则',
'project.menu.rule.enableRuleTip': '开启后,展示在规则切换列表',
'project.menu.rule.deleteRule': '确认删除 {size} 条误报规则吗?',
'project.menu.rule.deleteRuleTip': '删除后,仅对新执行的测试报告生效,请谨慎操作!',
};

View File

@ -120,7 +120,9 @@
</template>
</a-input>
</div>
<div class="ml-[8px] text-[rgb(var(--primary-7))]" @click="pushFar">{{ t('project.menu.far') }}</div>
<div class="ml-[8px] cursor-pointer text-[rgb(var(--primary-7))]" @click="pushFar">{{
t('project.menu.far')
}}</div>
<a-tooltip :content="t('project.menu.API_ERROR_REPORT_RULE_TIP')" position="right">
<div>
<MsIcon class="ml-[4px] text-[rgb(var(--primary-5))]" type="icon-icon-maybe_outlined" />

View File

@ -110,4 +110,3 @@
color: var(--color-text-4);
}
</style>
@/api/modules/setting/organizationAndProject