fix(全局): 项目管理/测试计划/脑图部分 bug 修复
This commit is contained in:
parent
c1a3f918e4
commit
0ad5eb7e64
|
@ -1,5 +1,4 @@
|
|||
import MSR from '@/api/http/index';
|
||||
import * as bugURL from '@/api/requrls/bug-management';
|
||||
|
||||
import { CommonList, TableQueryParams } from '@/models/common';
|
||||
|
||||
|
@ -91,5 +90,5 @@ export function getMessageReadAll(resourceType?: string) {
|
|||
}
|
||||
|
||||
export function getMessageUnReadCount(projectId: string) {
|
||||
return MSR.get<number>({ url: '/notification/un-read', params: projectId });
|
||||
return MSR.get<number>({ url: '/notification/un-read', params: projectId }, { ignoreCancelToken: true });
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
>
|
||||
{{ t('common.save') }}
|
||||
</a-button>
|
||||
<a-button type="secondary" :disabled="saveLoading">{{ t('common.cancel') }}</a-button>
|
||||
<a-button type="secondary" :disabled="saveLoading" @click="handleCancel">{{ t('common.cancel') }}</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -47,6 +47,7 @@
|
|||
import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
|
||||
import { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
|
||||
import { MinderJsonNode } from '@/components/pure/ms-minder-editor/props';
|
||||
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||
|
||||
import { getCaseDefaultFields, updateCaseRequest } from '@/api/modules/case-management/featureCase';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
@ -61,6 +62,9 @@
|
|||
activeCase: Record<string, any>;
|
||||
loading: boolean;
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
(e: 'cancel'): void;
|
||||
}>();
|
||||
|
||||
const appStore = useAppStore();
|
||||
const userStore = useUserStore();
|
||||
|
@ -149,7 +153,7 @@
|
|||
fileList: [],
|
||||
});
|
||||
const selectedNode: MinderJsonNode = window.minder.getSelectedNode();
|
||||
if (selectedNode.data) {
|
||||
if (selectedNode?.data) {
|
||||
selectedNode.data.text = baseInfoForm.value.name;
|
||||
}
|
||||
Message.success(t('common.saveSuccess'));
|
||||
|
@ -164,6 +168,9 @@
|
|||
}
|
||||
});
|
||||
}
|
||||
function handleCancel() {
|
||||
emit('cancel');
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.activeCase.id,
|
||||
|
|
|
@ -17,7 +17,12 @@
|
|||
@save="handleMinderSave"
|
||||
>
|
||||
<template #extractTabContent>
|
||||
<baseInfo v-if="activeExtraKey === 'baseInfo'" :loading="baseInfoLoading" :active-case="activeCase" />
|
||||
<baseInfo
|
||||
v-if="activeExtraKey === 'baseInfo'"
|
||||
:loading="baseInfoLoading"
|
||||
:active-case="activeCase"
|
||||
@cancel="handleBaseInfoCancel"
|
||||
/>
|
||||
<attachment
|
||||
v-else-if="activeExtraKey === 'attachment'"
|
||||
v-model:model-value="fileList"
|
||||
|
@ -69,7 +74,7 @@
|
|||
const topTags = [moduleTag, caseTag];
|
||||
const descTags = [t('ms.minders.stepDesc'), t('ms.minders.textDesc')];
|
||||
const importJson = ref<MinderJson>({
|
||||
root: {},
|
||||
root: {} as MinderJsonNode,
|
||||
template: 'default',
|
||||
treePath: [],
|
||||
});
|
||||
|
@ -552,6 +557,11 @@
|
|||
fileList.value = [];
|
||||
}
|
||||
|
||||
function handleBaseInfoCancel() {
|
||||
extraVisible.value = false;
|
||||
resetExtractInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理脑图节点激活/点击
|
||||
* @param node 被激活/点击的节点
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useUserStore from '@/store/modules/user';
|
||||
import { encrypted } from '@/utils';
|
||||
import { clearToken } from '@/utils/auth';
|
||||
import { validatePasswordLength, validateWordPassword } from '@/utils/validate';
|
||||
|
||||
const router = useRouter();
|
||||
|
@ -111,6 +112,7 @@
|
|||
}, 1000);
|
||||
setTimeout(() => {
|
||||
clearInterval(timer);
|
||||
clearToken();
|
||||
router.push({
|
||||
name: 'login',
|
||||
query: {
|
||||
|
|
|
@ -92,6 +92,8 @@
|
|||
import useMinderStore from '@/store/modules/components/minder-editor';
|
||||
import { findNodePathByKey } from '@/utils';
|
||||
|
||||
import { MinderEventName } from '@/enums/minderEnum';
|
||||
|
||||
import { editMenuProps, insertProps, mainEditorProps, MinderJsonNode, priorityProps, tagProps } from '../props';
|
||||
import Editor from '../script/editor';
|
||||
import { markChangeNode, markDeleteNode } from '../script/tool/utils';
|
||||
|
@ -222,8 +224,12 @@
|
|||
const menuVisible = ref(false);
|
||||
const menuPopupOffset = ref([0, 0]);
|
||||
|
||||
function switchNode(node: any) {
|
||||
innerImportJson.value = cloneDeep(findNodePathByKey([props.importJson.root], node.id, 'data', 'id'));
|
||||
/**
|
||||
* 切换脑图展示的节点层级
|
||||
* @param node 切换的节点
|
||||
*/
|
||||
function switchNode(node: MinderJsonNode) {
|
||||
innerImportJson.value = cloneDeep(findNodePathByKey([props.importJson.root], node.data?.id, 'data', 'id'));
|
||||
innerImportJson.value.data.expandState = 'expand';
|
||||
window.minder.importJson(innerImportJson.value);
|
||||
window.minder.execCommand('template', Object.keys(window.kityminder.Minder.getTemplateList())[minderStore.mold]);
|
||||
|
@ -232,7 +238,7 @@
|
|||
watch(
|
||||
() => minderStore.event.timestamp,
|
||||
() => {
|
||||
if (minderStore.event.name === 'hotbox') {
|
||||
if (minderStore.event.name === MinderEventName.HOTBOX && minderStore.event.nodePosition) {
|
||||
const nodeDomWidth = minderStore.event.nodeDom?.getBoundingClientRect().width || 0;
|
||||
menuPopupOffset.value = [
|
||||
minderStore.event.nodePosition.x + nodeDomWidth / 2,
|
||||
|
@ -240,12 +246,16 @@
|
|||
];
|
||||
menuVisible.value = true;
|
||||
}
|
||||
if (minderStore.event.name === 'enterNode') {
|
||||
switchNode(minderStore.event.nodeData);
|
||||
if (minderStore.event.name === MinderEventName.ENTER_NODE && minderStore.event.node) {
|
||||
switchNode(minderStore.event.node);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* 执行插入
|
||||
* @param command 插入命令
|
||||
*/
|
||||
function execInsertCommand(command: string) {
|
||||
const node: MinderJsonNode = window.minder.getSelectedNode();
|
||||
if (props.insertNode) {
|
||||
|
@ -257,6 +267,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理快捷菜单选择
|
||||
* @param val 选择的菜单项
|
||||
*/
|
||||
function handleMinderMenuSelect(val: string | number | Record<string, any> | undefined) {
|
||||
const selectedNode = window.minder.getSelectedNode();
|
||||
switch (val) {
|
||||
|
|
|
@ -19,10 +19,15 @@
|
|||
import { nextTick, onMounted, reactive, ref } from 'vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useMinderStore from '@/store/modules/components/minder-editor';
|
||||
import { MinderNodePosition } from '@/store/modules/components/minder-editor/types';
|
||||
|
||||
import { MinderEventName } from '@/enums/minderEnum';
|
||||
|
||||
import { delProps } from '../../props';
|
||||
import { isDeleteDisableNode } from '../../script/tool/utils';
|
||||
|
||||
const minderStore = useMinderStore();
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps(delProps);
|
||||
|
@ -54,10 +59,20 @@
|
|||
if (removeNodeDisabled.value || !minder.queryCommandState || !minder.execCommand) {
|
||||
return;
|
||||
}
|
||||
const node = minder.getSelectedNode();
|
||||
let position: MinderNodePosition | undefined;
|
||||
if (node) {
|
||||
if (props.delConfirm) {
|
||||
props.delConfirm();
|
||||
props.delConfirm(node);
|
||||
return;
|
||||
}
|
||||
const box = node.getRenderBox();
|
||||
position = {
|
||||
x: box.cx,
|
||||
y: box.cy,
|
||||
};
|
||||
minderStore.dispatchEvent(MinderEventName.DELETE_NODE, position, node.rc.node, node.data);
|
||||
}
|
||||
minder.forceRemoveNode();
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -19,8 +19,8 @@ export interface MinderJsonNodeData {
|
|||
[key: string]: any;
|
||||
}
|
||||
export interface MinderJsonNode {
|
||||
data: MinderJsonNodeData;
|
||||
parent?: MinderJsonNode;
|
||||
data?: MinderJsonNodeData;
|
||||
children?: MinderJsonNode[];
|
||||
[key: string]: any; // minder 内置字段
|
||||
}
|
||||
|
@ -148,8 +148,9 @@ export const moleProps = {
|
|||
};
|
||||
|
||||
export const delProps = {
|
||||
// 节点删除确认
|
||||
delConfirm: {
|
||||
type: Function,
|
||||
type: Function as PropType<(node: MinderJsonNode) => void>,
|
||||
default: null,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import useMinderStore from '@/store/modules/components/minder-editor';
|
||||
import type { MinderNodePosition } from '@/store/modules/components/minder-editor/types';
|
||||
|
||||
interface Position {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
import { MinderEventName } from '@/enums/minderEnum';
|
||||
|
||||
function HotboxRuntime(this: any) {
|
||||
const { fsm } = this;
|
||||
|
@ -18,14 +16,14 @@ function HotboxRuntime(this: any) {
|
|||
|
||||
function handleHotBoxShow() {
|
||||
const node = minder.getSelectedNode();
|
||||
let position: Position | undefined;
|
||||
let position: MinderNodePosition | undefined;
|
||||
if (node) {
|
||||
const box = node.getRenderBox();
|
||||
position = {
|
||||
x: box.cx,
|
||||
y: box.cy,
|
||||
};
|
||||
minderStore.dispatchEvent('hotbox', position, node.rc.node);
|
||||
minderStore.dispatchEvent(MinderEventName.HOTBOX, position, node.rc.node);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,14 +46,14 @@ function HotboxRuntime(this: any) {
|
|||
e.preventDefault(); // 阻止默认行为
|
||||
// 执行进入模块方法
|
||||
const node = minder.getSelectedNode();
|
||||
let position: Position | undefined;
|
||||
let position: MinderNodePosition | undefined;
|
||||
if (node) {
|
||||
const box = node.getRenderBox();
|
||||
position = {
|
||||
x: box.cx,
|
||||
y: box.cy,
|
||||
};
|
||||
minderStore.dispatchEvent('enterNode', position, node.rc.node, node.data);
|
||||
minderStore.dispatchEvent(MinderEventName.ENTER_NODE, position, node.rc.node, node.data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,8 +68,8 @@
|
|||
modelValue.value = result;
|
||||
nextTick(() => {
|
||||
initNumberAndType();
|
||||
});
|
||||
emit('change', modelValue.value);
|
||||
});
|
||||
}
|
||||
|
||||
const option = [
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
export enum MinderEventName {
|
||||
'DELETE_NODE' = 'DELETE_NODE', // 删除节点
|
||||
'HOTBOX' = 'HOTBOX', // 热键菜单
|
||||
'ENTER_NODE' = 'ENTER_NODE', // 进入节点
|
||||
}
|
||||
|
||||
export default {};
|
|
@ -1,30 +1,41 @@
|
|||
import { defineStore } from 'pinia';
|
||||
|
||||
import type { MinderJsonNode } from '@/components/pure/ms-minder-editor/props';
|
||||
|
||||
import type { MinderEventName } from '@/enums/minderEnum';
|
||||
|
||||
import { MinderNodePosition, MinderState } from './types';
|
||||
|
||||
// 脑图组件的 store
|
||||
const useMinderStore = defineStore('minder', {
|
||||
state: (): MinderState => ({
|
||||
event: {
|
||||
name: '',
|
||||
name: '' as MinderEventName,
|
||||
timestamp: 0,
|
||||
nodePosition: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
nodeDom: undefined,
|
||||
nodeData: undefined,
|
||||
node: undefined,
|
||||
},
|
||||
mold: 0,
|
||||
}),
|
||||
actions: {
|
||||
dispatchEvent(name: string, position: MinderNodePosition, nodeDom?: HTMLElement, nodeData?: Record<string, any>) {
|
||||
/**
|
||||
* 脑图组件派发事件
|
||||
* @param name 事件名称
|
||||
* @param position 触发事件的节点/鼠标位置
|
||||
* @param nodeDom 节点 DOM
|
||||
* @param node 节点
|
||||
*/
|
||||
dispatchEvent(name: MinderEventName, position?: MinderNodePosition, nodeDom?: HTMLElement, node?: MinderJsonNode) {
|
||||
this.event = {
|
||||
name,
|
||||
timestamp: Date.now(),
|
||||
nodePosition: position,
|
||||
nodeDom,
|
||||
nodeData,
|
||||
node,
|
||||
};
|
||||
},
|
||||
setMold(val: number) {
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
import type { MinderJsonNode } from '@/components/pure/ms-minder-editor/props';
|
||||
|
||||
import type { MinderEventName } from '@/enums/minderEnum';
|
||||
|
||||
export interface MinderNodePosition {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
export interface MinderEvent {
|
||||
name: string;
|
||||
name: MinderEventName;
|
||||
timestamp: number;
|
||||
nodePosition: MinderNodePosition;
|
||||
nodePosition?: MinderNodePosition;
|
||||
nodeDom?: HTMLElement;
|
||||
nodeData?: Record<string, any>;
|
||||
node?: MinderJsonNode;
|
||||
}
|
||||
|
||||
export interface MinderState {
|
||||
|
|
|
@ -142,11 +142,13 @@ const useUserStore = defineStore('user', {
|
|||
appStore.resetSystemPackageType();
|
||||
},
|
||||
// 登出
|
||||
async logout() {
|
||||
async logout(silence = false) {
|
||||
try {
|
||||
const { t } = useI18n();
|
||||
if (!silence) {
|
||||
const appStore = useAppStore();
|
||||
appStore.showLoading(t('message.logouting'));
|
||||
}
|
||||
await userLogout();
|
||||
} finally {
|
||||
this.logoutCallBack();
|
||||
|
|
|
@ -162,7 +162,7 @@
|
|||
setLoading(true);
|
||||
try {
|
||||
try {
|
||||
await userStore.logout(); // 登录之前先注销,防止未登出就继续登录导致报错
|
||||
await userStore.logout(true); // 登录之前先注销,防止未登出就继续登录导致报错
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('logout error', error);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
export default {
|
||||
'login.form.title': 'One-stop open source continuous testing platform',
|
||||
'login.form.title': 'Modern, open-source test management and interface testing tools',
|
||||
'login.form.userName.errMsg': 'Username cannot be empty',
|
||||
'login.form.password.errMsg': 'Password cannot be empty',
|
||||
'login.form.login.errMsg': 'Login error, refresh and try again',
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
export default {
|
||||
'login.form.title': '一站式开源持续测试平台',
|
||||
'login.form.title': '现代化、开源的测试管理和接口测试工具',
|
||||
'login.form.userName.errMsg': '邮箱不能为空',
|
||||
'login.form.password.errMsg': '密码不能为空',
|
||||
'login.form.login.errMsg': '登录出错,请刷新重试',
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
value-format="timestamp"
|
||||
:separator="t('common.to')"
|
||||
:time-picker-props="{
|
||||
defaultValue: ['00:00:00', '00:00:00'],
|
||||
defaultValue: tempRange,
|
||||
}"
|
||||
:disabled-time="disabledTime"
|
||||
@select="handleTimeSelect"
|
||||
|
@ -196,14 +196,14 @@
|
|||
return (nodeData as ModuleTreeNode).name.toLowerCase().indexOf(searchValue.toLowerCase()) > -1;
|
||||
}
|
||||
|
||||
const tempRange = ref<(Date | string | number | undefined)[]>([]);
|
||||
const tempRange = ref<(Date | string | number)[]>(['00:00:00', '00:00:00']);
|
||||
|
||||
function makeLessNumbers(value: number) {
|
||||
function makeLessNumbers(value: number, isSecond = false) {
|
||||
const res = [];
|
||||
for (let i = 0; i < value; i++) {
|
||||
res.push(i);
|
||||
}
|
||||
return res;
|
||||
return isSecond && res.length === 0 ? [0] : res; // 秒至少相差 1 秒
|
||||
}
|
||||
|
||||
function disabledTime(current: Date, type: 'start' | 'end'): DisabledTimeProps {
|
||||
|
@ -230,7 +230,7 @@
|
|||
currentDate.isSame(startDate, 'h') &&
|
||||
currentDate.isSame(startDate, 'm')
|
||||
) {
|
||||
return makeLessNumbers(startDate.get('s'));
|
||||
return makeLessNumbers(startDate.get('s'), true);
|
||||
}
|
||||
return [];
|
||||
},
|
||||
|
@ -240,7 +240,15 @@
|
|||
}
|
||||
|
||||
function handleTimeSelect(value: (Date | string | number | undefined)[]) {
|
||||
tempRange.value = value;
|
||||
if (value) {
|
||||
// const start = dayjs(value[0]);
|
||||
// const end = dayjs(value[1]);
|
||||
// if (start.isSame(end, 'D') && end.hour() === 0 && end.minute() === 0 && end.second() === 0) {
|
||||
// const newEnd = end.hour(23).minute(59).second(59);
|
||||
// value[1] = newEnd.valueOf();
|
||||
// }
|
||||
tempRange.value = value as number[];
|
||||
}
|
||||
}
|
||||
|
||||
const switchList: SwitchListModel[] = [
|
||||
|
|
Loading…
Reference in New Issue