fix(all): 修复bugs

This commit is contained in:
baiqi 2024-04-11 20:46:23 +08:00 committed by Craftsman
parent 814b0ef679
commit 05f4965813
17 changed files with 95 additions and 98 deletions

View File

@ -33,7 +33,9 @@
<ms-base-table v-bind="propsRes" v-model:selected-key="innerCheckedKey" v-on="propsEvent">
<template #name="{ record }">
<div class="flex items-center">
<a-tooltip :content="record.name">
<div class="one-line-text max-w-[200px] cursor-pointer text-[rgb(var(--primary-5))]">{{ record.name }}</div>
</a-tooltip>
<a-popover :title="record.name" position="bottom">
<a-button type="text" class="ml-2 px-0"> {{ t('project.commonScript.preview') }}</a-button>
<template #title>
@ -223,7 +225,6 @@
slotName: 'name',
width: 300,
showInTable: true,
showTooltip: true,
},
{
title: 'project.commonScript.description',

View File

@ -33,7 +33,7 @@
<slot name="title" v-bind="_props"></slot>
</template>
<template v-if="$slots['extra'] || props.nodeMoreActions" #extra="_props">
<div class="sticky right-0 flex items-center justify-between">
<div class="sticky right-[8px] flex items-center justify-between">
<div v-if="_props.hideMoreAction !== true" class="ms-tree-node-extra">
<slot name="extra" v-bind="_props"></slot>
<MsTableMoreAction

View File

@ -53,11 +53,11 @@
</template>
</a-table>
</div>
<div v-if="props.showBottom" v-permission="props.savePermission || []" class="footer" :style="{ width: props.width }">
<div v-if="props.showBottom" v-permission="props.savePermission || []" class="footer">
<ms-button :disabled="!canSave" @click="handleReset">{{ t('system.userGroup.reset') }}</ms-button>
<a-button v-permission="props.savePermission || []" :disabled="!canSave" type="primary" @click="handleSave">{{
t('system.userGroup.save')
}}</a-button>
<a-button v-permission="props.savePermission || []" :disabled="!canSave" type="primary" @click="handleSave">
{{ t('system.userGroup.save') }}
</a-button>
</div>
</template>
@ -91,7 +91,6 @@
export interface TableOperationColumn {
name: OperationName | string;
title?: string | RenderFunction;
width?: number;
fixed?: boolean;
render?: (record: TableData) => VNodeChild;
isLastLeftFixed?: boolean;
@ -101,7 +100,6 @@
defineProps<{
current: CurrentUserGroupItem;
savePermission?: string[];
width?: string;
showBottom?: boolean;
disabled?: boolean;
scroll?: {
@ -117,7 +115,7 @@
scroll() {
return {
x: '800px',
y: 'calc(100vh - 254px)',
y: 'calc(100vh - 264px)',
};
},
}
@ -492,7 +490,7 @@
<style scoped lang="less">
.group-auth-table {
position: relative;
min-height: calc(100vh - 230px);
padding: 24px;
:deep(.arco-table-container) {
border-top: 1px solid var(--color-text-n8) !important;
border-right: 1px solid var(--color-text-n8) !important;
@ -509,10 +507,8 @@
}
}
.footer {
position: fixed;
right: 17px;
bottom: 24px;
z-index: 999;
@apply w-full;
display: flex;
justify-content: flex-end;
padding: 24px;

View File

@ -1,4 +1,5 @@
<template>
<div class="px-[24px]">
<MsBaseTable class="mt-[16px]" v-bind="propsRes" v-on="propsEvent">
<template v-if="hasAnyPermission(props.updatePermission || [])" #quickCreate>
<MsConfirmUserSelector :ok-loading="okLoading" v-bind="userSelectorProps" @confirm="handleAddMember" />
@ -12,6 +13,7 @@
/>
</template>
</MsBaseTable>
</div>
</template>
<script lang="ts" setup>
@ -33,7 +35,6 @@
} from '@/api/modules/setting/usergroup';
import { useI18n } from '@/hooks/useI18n';
import { useAppStore } from '@/store';
import useUserStore from '@/store/modules/user/index';
import { characterLimit, formatPhoneNumber } from '@/utils';
import { hasAnyPermission } from '@/utils/permission';
@ -46,7 +47,6 @@
const systemType = inject<AuthScopeEnum>('systemType');
const { t } = useI18n();
const appStore = useAppStore();
const userStore = useUserStore();
const currentOrgId = computed(() => appStore.currentOrgId);
const okLoading = ref(false);
const props = defineProps<{
@ -114,7 +114,7 @@
getRequestBySystemType(),
{
columns: userGroupUsercolumns,
scroll: { x: '100%', minWidth: 700 },
scroll: { x: '100%', minWidth: 700, y: '100%' },
selectable: false,
noDisable: true,
showSetting: false,

View File

@ -46,20 +46,18 @@
if (sameNameSiblings.length > 1) {
// 1 xpath
const sameNodesIndex = document.evaluate(
`count(ancestor-or-self::*/preceding-sibling::${node.nodeName}) + 1`,
`count(ancestor-or-self::*[local-name()="${node.localName}"]/preceding-sibling::*[local-name()="${node.localName}"]) + 1`,
node,
(prefix) => {
// XML
const root = node.ownerDocument.documentElement;
// URI
const nsUri = root.getAttributeNS('http://www.w3.org/2000/xmlns/', prefix || '');
// URI
const nsUri = node.lookupNamespaceURI(prefix);
return nsUri || null;
},
XPathResult.NUMBER_TYPE,
null
).numberValue; // XPATH
const xpath = `${currentPath}/${node.nodeName}[${sameNodesIndex}]`; // /[]
const xpath = `${currentPath}/*[local-name()="${node.localName}"][${sameNodesIndex}]`; // /[]
tempXmls.value.push({ content: node.nodeName, xpath });
const children = Array.from(node.children);
children.forEach((child) => {
@ -67,7 +65,7 @@
});
} else {
// 1 xpath
const xpath = `${currentPath}/${node.nodeName}`;
const xpath = `${currentPath}/*[local-name()="${node.localName}"]`;
tempXmls.value.push({ content: node.nodeName, xpath });
const children = Array.from(node.children);
children.forEach((child) => {

View File

@ -135,10 +135,6 @@
return Promise.resolve(false);
}
}
if (!props.multiple) {
//
innerFileList.value = [];
}
}
const maxSize = props.maxSize || defaultMaxSize;
const _maxSize = props.sizeUnit === 'MB' ? maxSize * 1024 * 1024 : maxSize * 1024;
@ -146,6 +142,10 @@
Message.warning(t('ms.upload.overSize'));
return Promise.resolve(false);
}
if (!props.multiple) {
//
innerFileList.value = [];
}
const fileFormatMatch = file.name.match(/\.([a-zA-Z0-9]+)$/);
const fileFormatType = fileFormatMatch ? fileFormatMatch[1] : 'none';
//

View File

@ -550,7 +550,8 @@ export function deleteNodes<T>(
targetKeys: (string | number)[],
deleteCondition?: (node: TreeNode<T>, parent?: TreeNode<T>) => boolean,
customKey = 'key'
): void {
): boolean {
let hasDeleted = false;
const targetKeysSet = new Set(targetKeys);
function deleteNodesInTree(tree: TreeNode<T>[]): void {
for (let i = tree.length - 1; i >= 0; i--) {
@ -558,6 +559,7 @@ export function deleteNodes<T>(
if (targetKeysSet.has(node[customKey])) {
if (deleteCondition && deleteCondition(node, node.parent)) {
tree.splice(i, 1); // 直接删除当前节点
hasDeleted = true;
targetKeysSet.delete(node[customKey]); // 删除后从集合中移除
// 重新调整剩余子节点的 sort 序号
for (let j = i; j < tree.length; j++) {
@ -571,6 +573,7 @@ export function deleteNodes<T>(
}
deleteNodesInTree(treeArr);
return hasDeleted;
}
/**

View File

@ -14,10 +14,8 @@ export function matchXMLWithXPath(xmlText: string, xpathQuery: string): xpath.Se
// 创建一个命名空间解析器
const resolver = (prefix: string) => {
// 获取 XML 文档的根元素
const root = xmlDoc.documentElement;
// 从根元素获取命名空间的 URI
const nsUri = root.getAttributeNS('http://www.w3.org/2000/xmlns/', prefix);
// 获取命名空间的 URI
const nsUri = xmlDoc.lookupNamespaceURI(prefix);
return nsUri || null;
};

View File

@ -72,7 +72,7 @@
columns,
scroll: { x: '100%' },
selectable: false,
heightUsed: 374,
heightUsed: 454,
},
(item) => ({
...item,

View File

@ -281,12 +281,21 @@
},
maskClosable: false,
onBeforeOk: async () => {
deleteNodes(scenario.value.steps, checkedKeys.value, (node) => !node.isQuoteScenarioStep, 'uniqueId');
const deleteResult = deleteNodes(
scenario.value.steps,
checkedKeys.value,
(node) => !node.isQuoteScenarioStep,
'uniqueId'
);
if (deleteResult) {
Message.success(t('common.deleteSuccess'));
if (scenario.value.steps.length === 0) {
checkedAll.value = false;
indeterminate.value = false;
}
} else {
Message.warning(t('apiScenario.quoteScenarioStepNotAllowDelete'));
}
},
hideCancel: false,
});

View File

@ -943,10 +943,18 @@
try {
saveLoading.value = true;
if (activeStep.value) {
let url;
let path = '';
try {
url = new URL(saveModalForm.value.path);
path = url.pathname + url.search + url.hash;
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
path = saveModalForm.value.path;
}
const detail = stepDetails.value[activeStep.value.id] as RequestParam;
const fileParams = scenario.value.stepFileParam[activeStep.value.id];
const url = new URL(saveModalForm.value.path);
const path = url.pathname + url.search + url.hash;
const res = await addDefinition({
...saveModalForm.value,
path,
@ -1213,11 +1221,11 @@
function applyStepNameChange(step: ScenarioStepItem) {
const realStep = findNodeByKey<ScenarioStepItem>(steps.value, step.uniqueId, 'uniqueId');
if (realStep) {
realStep.name = tempStepName.value;
realStep.name = tempStepName.value || realStep.name;
realStep.draggable = true; //
}
showStepNameEditInputStepId.value = '';
scenario.value.unSaved = true;
scenario.value.unSaved = !!tempStepName.value;
}
/**
@ -1242,11 +1250,11 @@
function applyStepDescChange(step: ScenarioStepItem) {
const realStep = findNodeByKey<ScenarioStepItem>(steps.value, step.uniqueId, 'uniqueId');
if (realStep) {
realStep.name = tempStepDesc.value;
realStep.name = tempStepDesc.value || realStep.name;
realStep.draggable = true; //
}
showStepDescEditInputStepId.value = '';
scenario.value.unSaved = true;
scenario.value.unSaved = !!tempStepDesc.value;
}
function handleStepContentChange($event, step: ScenarioStepItem) {

View File

@ -192,6 +192,7 @@ export default {
'apiScenario.deleteStepConfirm': 'Are you sure you want to delete {name}?',
'apiScenario.deleteStepConfirmWithChildren':
'Are you sure you want to delete the selected step and all substeps within the step?',
'apiScenario.quoteScenarioStepNotAllowDelete': 'Substeps that reference a scenario cannot be deleted',
// Execution History
'apiScenario.executeHistory.searchPlaceholder': 'Search by ID or name',
'apiScenario.executeHistory.num': 'No.',

View File

@ -183,6 +183,7 @@ export default {
'apiScenario.syncSaveAsCase': '同步添加测试接口用例',
'apiScenario.deleteStepConfirm': '确认删除 {name} 吗?',
'apiScenario.deleteStepConfirmWithChildren': '确认删除所选步骤以及步骤内所有子步骤?',
'apiScenario.quoteScenarioStepNotAllowDelete': '引用场景的子步骤不能删除',
// 执行历史
'apiScenario.executeHistory.searchPlaceholder': '通过ID或名称搜索',
'apiScenario.executeHistory.num': '序号',

View File

@ -8,7 +8,11 @@
</div>
<ms-base-table v-bind="propsRes" no-disable v-on="propsEvent">
<template #name="{ record }">
<a-button type="text" class="px-0" @click="openAuthDetail(record.id)">{{ record.name }}</a-button>
<a-button type="text" class="w-full overflow-hidden px-0" @click="openAuthDetail(record.id)">
<div class="one-line-text">
{{ record.name }}
</div>
</a-button>
</template>
<template #action="{ record }">
<MsButton v-permission="['SYSTEM_PARAMETER_SETTING_AUTH:READ+UPDATE']" @click="editAuth(record)">
@ -637,28 +641,25 @@
slotName: 'name',
dataIndex: 'name',
width: 200,
showInTable: true,
showTooltip: true,
},
{
title: 'system.config.auth.status',
slotName: 'enable',
dataIndex: 'enable',
showInTable: true,
},
{
title: 'system.config.auth.desc',
dataIndex: 'description',
showInTable: true,
showTooltip: true,
},
{
title: 'system.config.auth.createTime',
dataIndex: 'createTime',
showInTable: true,
},
{
title: 'system.config.auth.updateTime',
dataIndex: 'updateTime',
showInTable: true,
},
{
title: hasOperationPermission.value ? 'system.config.auth.action' : '',
@ -785,7 +786,7 @@
enable: true,
description: '',
name: '',
type: 'CAS',
type: 'LDAP',
updateTime: 0,
createTime: 0,
configuration: {},
@ -948,13 +949,14 @@
const showDrawer = ref(false);
const drawerLoading = ref(false);
const authFormRef = ref<FormInstance>();
const authTypeList = ['CAS', 'OIDC', 'OAuth2', 'LDAP'];
// const authTypeList = ['CAS', 'OIDC', 'OAuth2', 'LDAP'];
const authTypeList = ['LDAP'];
const defaultAuth = {
id: '',
enable: true,
description: '',
name: '',
type: 'CAS' as AuthType,
type: 'LDAP' as AuthType,
configuration: {},
};
const activeAuthForm = ref<AuthForm>({

View File

@ -379,7 +379,7 @@
return appStore.menuCollapse ? collapsedWidth : appStore.menuWidth;
});
const pageLoading = ref(false);
const pageConfig = ref({ ...appStore.pageConfig });
const pageConfig = ref({ ...appStore.pageConfig, slogan: t(appStore.pageConfig.slogan) });
const loginPageFullRef = ref<HTMLElement | null>(null);
const platformPageFullRef = ref<HTMLElement | null>(null);
const { isFullScreen: isLoginPageFullscreen, toggleFullScreen: loginFullscreenToggle } =

View File

@ -56,7 +56,7 @@ export default {
'system.config.page.loginPageConfig': '平台登录页设置',
'system.config.page.pagePreview': '页面预览',
'system.config.page.reset': '恢复默认',
'system.config.page.icon': '网站 icon',
'system.config.page.icon': '网站 Icon',
'system.config.page.replace': '替换图片',
'system.config.page.iconTip':
'顶部网站显示的 icon建议使用 SVG 或 PNG 格式透明背景图片,宽高 18px图片大小仅支持 200 KB 以内',
@ -69,10 +69,10 @@ export default {
'system.config.page.slogan': 'Slogan',
'system.config.page.sloganPlaceholder': '请输入 Slogan',
'system.config.page.sloganRequired': 'Slogan不能为空',
'system.config.page.sloganTip': '产品Logo下的 slogan',
'system.config.page.sloganTip': '产品Logo下的 Slogan',
'system.config.page.title': '网站名称',
'system.config.page.titlePlaceholder': '请输入网站名称',
'system.config.page.titleTip': '显示在网页tab的平台名称',
'system.config.page.titleTip': '显示在网页Tab的平台名称',
'system.config.page.loginPreviewTip': 'tips:默认为 MeterSphere 系统界面,支持自定义平台界面设置',
'system.config.page.platformConfig': '平台设置',
'system.config.page.platformLogo': '平台 Logo',

View File

@ -1,5 +1,5 @@
<template>
<div class="card">
<MsCard simple no-content-padding>
<MsSplitBox v-model:width="leftWidth" @expand-change="handleCollapse">
<template #first>
<UserGroupLeft
@ -12,8 +12,8 @@
/>
</template>
<template #second>
<div class="p-[24px]">
<div class="flex flex-row items-center justify-between">
<div class="h-full pt-[24px]">
<div class="flex flex-row items-center justify-between px-[24px]">
<a-tooltip :content="currentUserGroupItem.name">
<div class="one-line-text max-w-[300px] font-medium">{{ currentUserGroupItem.name }}</div>
</a-tooltip>
@ -51,7 +51,6 @@
<AuthTable
v-if="currentTable === 'auth' && couldShowAuth"
:current="currentUserGroupItem"
:width="bottomWidth"
:save-permission="['SYSTEM_USER_ROLE:READ+UPDATE']"
:disabled="!hasAnyPermission(['SYSTEM_USER_ROLE:READ+UPDATE'])"
/>
@ -59,24 +58,22 @@
</div>
</template>
</MsSplitBox>
</div>
</MsCard>
</template>
<script lang="ts" setup>
/**
* @description 系统设置-系统-用户组
*/
import { computed, nextTick, onMounted, provide, ref, watchEffect } from 'vue';
import { useRouter } from 'vue-router';
import MsCard from '@/components/pure/ms-card/index.vue';
import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
import AuthTable from '@/components/business/ms-user-group-comp/authTable.vue';
import UserGroupLeft from '@/components/business/ms-user-group-comp/msUserGroupLeft.vue';
import UserTable from '@/components/business/ms-user-group-comp/userTable.vue';
import { useI18n } from '@/hooks/useI18n';
import { useAppStore } from '@/store';
import { addPixelValues } from '@/utils/css';
import { hasAnyPermission } from '@/utils/permission';
import { CurrentUserGroupItem } from '@/models/setting/usergroup';
@ -97,16 +94,8 @@
});
const userRef = ref();
const appStore = useAppStore();
const leftCollapse = ref(true);
const leftWidth = ref('300px');
const bottomWidth = computed(() => {
const width = appStore.menuCollapse ? '86px' : `${appStore.menuWidth}px`;
if (leftCollapse.value) {
return `calc(100% - ${addPixelValues(width, leftWidth.value, '20px')})`;
}
return `calc(100% - ${addPixelValues(width, '16px')})`;
});
const tableSearch = () => {
if (currentTable.value === 'user' && userRef.value) {
@ -162,13 +151,4 @@
});
</script>
<style lang="less" scoped>
.card {
@apply overflow-hidden bg-white;
position: relative;
height: calc(100vh - 88px);
border-radius: var(--border-radius-large);
box-shadow: 0 0 10px rgb(120 56 135 / 5%);
}
</style>
<style lang="less" scoped></style>