feat(功能用例): 脑图用例评论&接口部分 bug 修复
This commit is contained in:
parent
481bd86b44
commit
bb100c6715
|
@ -6,19 +6,16 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useEventListener, useWindowSize } from '@vueuse/core';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
import MsSysUpgradeTip from '@/components/pure/ms-sys-upgrade-tip/index.vue';
|
||||
|
||||
import { getProjectInfo } from '@/api/modules/project-management/basicInfo';
|
||||
import { saveBaseUrl } from '@/api/modules/setting/config';
|
||||
import { getUserHasProjectPermission } from '@/api/modules/system';
|
||||
import { GetPlatformIconUrl } from '@/api/requrls/setting/config';
|
||||
// import GlobalSetting from '@/components/pure/global-setting/index.vue';
|
||||
import useLocale from '@/locale/useLocale';
|
||||
import { NO_PROJECT_ROUTE_NAME, WHITE_LIST } from '@/router/constants';
|
||||
import { WHITE_LIST } from '@/router/constants';
|
||||
import { useUserStore } from '@/store';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import useLicenseStore from '@/store/modules/setting/license';
|
||||
|
@ -26,15 +23,12 @@
|
|||
import { setFavicon, watchStyle, watchTheme } from '@/utils/theme';
|
||||
|
||||
import { getPublicKeyRequest } from './api/modules/user';
|
||||
import { getFirstRouteNameByPermission } from './utils/permission';
|
||||
import enUS from '@arco-design/web-vue/es/locale/lang/en-us';
|
||||
import zhCN from '@arco-design/web-vue/es/locale/lang/zh-cn';
|
||||
|
||||
const appStore = useAppStore();
|
||||
const userStore = useUserStore();
|
||||
const licenseStore = useLicenseStore();
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
const { currentLocale } = useLocale();
|
||||
const locale = computed(() => {
|
||||
|
@ -74,43 +68,6 @@
|
|||
}
|
||||
});
|
||||
|
||||
const checkIsLogin = async () => {
|
||||
const isLogin = await userStore.isLogin();
|
||||
const isLoginPage = route.name === 'login';
|
||||
if (isLogin && appStore.currentProjectId !== 'no_such_project') {
|
||||
// 当前为登陆状态,且已经选择了项目,初始化当前项目配置
|
||||
try {
|
||||
const HasProjectPermission = await getUserHasProjectPermission(appStore.currentProjectId);
|
||||
if (!HasProjectPermission) {
|
||||
// 没有项目权限(用户所在的当前项目被禁用&用户被移除出去该项目)
|
||||
router.push({
|
||||
name: NO_PROJECT_ROUTE_NAME,
|
||||
});
|
||||
return;
|
||||
}
|
||||
const res = await getProjectInfo(appStore.currentProjectId);
|
||||
if (!res) {
|
||||
// 如果项目被删除或者被禁用,跳转到无项目页面
|
||||
router.push({
|
||||
name: NO_PROJECT_ROUTE_NAME,
|
||||
});
|
||||
}
|
||||
|
||||
if (res) {
|
||||
appStore.setCurrentMenuConfig(res?.moduleIds || []);
|
||||
}
|
||||
} catch (err) {
|
||||
appStore.setCurrentMenuConfig([]);
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
if (isLoginPage && isLogin) {
|
||||
// 当前页面为登录页面,且已经登录,跳转到首页
|
||||
const currentRouteName = getFirstRouteNameByPermission(router.getRoutes());
|
||||
router.push({ name: currentRouteName });
|
||||
}
|
||||
};
|
||||
// 获取公钥
|
||||
const getPublicKey = async () => {
|
||||
const publicKey = await getPublicKeyRequest();
|
||||
|
@ -120,7 +77,7 @@
|
|||
onBeforeMount(async () => {
|
||||
await getPublicKey();
|
||||
if (WHITE_LIST.find((el) => el.path === window.location.hash.split('#')[1]) === undefined) {
|
||||
await checkIsLogin();
|
||||
await userStore.checkIsLogin();
|
||||
}
|
||||
const { height } = useWindowSize();
|
||||
appStore.innerHeight = height.value;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import MSR from '@/api/http/index';
|
||||
import { associatedProjectOptionsUrl } from '@/api/requrls/case-management/featureCase';
|
||||
import { ProjectListUrl, ProjectSwitchUrl } from '@/api/requrls/project-management/project';
|
||||
|
||||
import type { ProjectListItem } from '@/models/setting/project';
|
||||
|
|
|
@ -272,7 +272,7 @@
|
|||
.arco-select-view-single,
|
||||
.arco-select {
|
||||
width: 100%;
|
||||
border: 1px solid var(--color-text-input-border);
|
||||
border: 1px solid var(--color-text-n8);
|
||||
background-color: var(--color-text-fff);
|
||||
&:not(:disabled, .arco-input-tag-disabled, .arco-input-disabled, .arco-select-view-disabled):hover {
|
||||
border-color: rgb(var(--primary-5)) !important;
|
||||
|
|
|
@ -96,32 +96,3 @@ body {
|
|||
background: rgb(var(--primary-6));
|
||||
}
|
||||
}
|
||||
|
||||
/* 评论组件的样式 */
|
||||
.ms-comment-child-container {
|
||||
padding: 16px;
|
||||
border: 0.5px solid var(--color-text-input-border); /* 设置近似 0.5px 的边框 */
|
||||
border-radius: 4px;
|
||||
}
|
||||
.markdown-body ol {
|
||||
list-style: decimal !important;
|
||||
}
|
||||
.markdown-body ul {
|
||||
list-style: disc !important;
|
||||
}
|
||||
.markdown-body ul li[data-type='taskItem'] {
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
list-style: none !important;
|
||||
@apply my-6 flex items-center;
|
||||
label {
|
||||
margin-right: 4px;
|
||||
@apply flex items-center;
|
||||
}
|
||||
> div {
|
||||
@apply flex items-center;
|
||||
> p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,19 @@
|
|||
<template>
|
||||
<div class="flex flex-row gap-[8px] break-words">
|
||||
<div class="p-1"> <MsAvatar :avatar="creatorInfo.avatar" /></div>
|
||||
<div class="flex w-full flex-col">
|
||||
<div class="font-medium text-[var(--color-text-1)]">
|
||||
<MsAvatar :avatar="creatorInfo.avatar" />
|
||||
<div class="flex flex-1 flex-col">
|
||||
<div class="font-medium leading-[22px] text-[var(--color-text-1)]">
|
||||
{{ creatorInfo.name }}
|
||||
<span v-if="props.element.replyUser">{{ t('ms.comment.reply') }} {{ replyUserName }}</span>
|
||||
</div>
|
||||
<div v-dompurify-html="props.element.content" class="markdown-body mt-[4px] break-words break-all"></div>
|
||||
|
||||
<div class="mb-4 mt-[16px] flex flex-row items-center">
|
||||
<div class="text-[var(--color-text-4)]">{{
|
||||
dayjs(props.element.updateTime).format('YYYY-MM-DD HH:mm:ss')
|
||||
}}</div>
|
||||
<div class="ml-[24px] flex flex-row gap-[16px]">
|
||||
<div
|
||||
v-if="props.mode === 'parent' && element.childComments?.length"
|
||||
class="comment-btn"
|
||||
@click="expendChange"
|
||||
>
|
||||
<div class="mt-[8px] flex items-center justify-between">
|
||||
<div class="text-[12px] leading-[16px] text-[var(--color-text-4)]">
|
||||
{{ dayjs(props.element.updateTime).format('YYYY-MM-DD HH:mm:ss') }}
|
||||
</div>
|
||||
<div class="flex gap-[8px]">
|
||||
<div v-if="props.mode === 'parent'" class="comment-btn" @click="expendChange">
|
||||
<MsIconfont type="icon-icon_comment_outlined" />
|
||||
<span>{{ !expendComment ? t('ms.comment.expendComment') : t('ms.comment.collapseComment') }}</span>
|
||||
<span class="text-[var(--color-text-4)]">({{ element.childComments?.length }})</span>
|
||||
|
@ -29,26 +25,8 @@
|
|||
@click="replyClick"
|
||||
>
|
||||
<MsIconfont type="icon-icon_reply" />
|
||||
<span>{{ t('ms.comment.reply') }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="hasAuth"
|
||||
class="comment-btn hover:bg-[var(--color-bg-3)]"
|
||||
:class="{ 'bg-[var(--color-text-n8)]': status === 'edit' }"
|
||||
@click="editClick"
|
||||
>
|
||||
<MsIconfont type="icon-icon_edit_outlined" />
|
||||
<span>{{ t('ms.comment.edit') }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="hasAuth"
|
||||
class="comment-btn hover:bg-[rgb(var(--danger-1))]"
|
||||
:class="{ 'bg-[rgb(var(--danger-2))]': status === 'delete' }"
|
||||
@click="deleteClick"
|
||||
>
|
||||
<MsIconfont type="icon-icon_delete-trash_outlined" />
|
||||
<span>{{ t('ms.comment.delete') }}</span>
|
||||
</div>
|
||||
<MoreAction v-if="hasAuth" :list="actionsList" @select="handleMoreActionSelect"></MoreAction>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -61,6 +39,8 @@
|
|||
|
||||
import MsAvatar from '@/components/pure/ms-avatar/index.vue';
|
||||
import MsIconfont from '@/components/pure/ms-icon-font/index.vue';
|
||||
import MoreAction from '@/components/pure/ms-table-more-action/index.vue';
|
||||
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useUserStore from '@/store/modules/user/index';
|
||||
|
@ -101,6 +81,9 @@
|
|||
const expendComment = ref(false);
|
||||
|
||||
const expendChange = () => {
|
||||
if (!props.element.childComments?.length) {
|
||||
return;
|
||||
}
|
||||
expendComment.value = !expendComment.value;
|
||||
emit('expend', expendComment.value);
|
||||
};
|
||||
|
@ -119,6 +102,30 @@
|
|||
status.value = 'delete';
|
||||
};
|
||||
|
||||
const actionsList: ActionsItem[] = [
|
||||
{
|
||||
label: t('ms.comment.edit'),
|
||||
eventTag: 'edit',
|
||||
permission: ['PROJECT_BUG:READ+COMMENT', 'FUNCTIONAL_CASE:READ+COMMENT'],
|
||||
icon: 'icon-icon_edit_outlined',
|
||||
},
|
||||
{
|
||||
label: t('ms.comment.delete'),
|
||||
eventTag: 'delete',
|
||||
permission: ['PROJECT_BUG:READ+COMMENT', 'FUNCTIONAL_CASE:READ+COMMENT'],
|
||||
danger: true,
|
||||
icon: 'icon-icon_delete-trash_outlined',
|
||||
},
|
||||
];
|
||||
|
||||
function handleMoreActionSelect(item: ActionsItem) {
|
||||
if (item.eventTag === 'edit') {
|
||||
editClick();
|
||||
} else if (item.eventTag === 'delete') {
|
||||
deleteClick();
|
||||
}
|
||||
}
|
||||
|
||||
const creatorInfo = computed(() => {
|
||||
return props.element.commentUserInfos.filter((item) => item != null && item.id === props.element.createUser)[0];
|
||||
});
|
||||
|
@ -133,13 +140,12 @@
|
|||
|
||||
<style lang="less" scoped>
|
||||
.comment-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@apply flex cursor-pointer items-center;
|
||||
|
||||
padding: 2px 8px;
|
||||
font-size: 12px;
|
||||
border-radius: 4px;
|
||||
color: var(--color-text-1);
|
||||
flex-direction: row;
|
||||
color: var(--color-text-4);
|
||||
gap: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -5,6 +5,7 @@ import CommentInput from './input.vue';
|
|||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import './style.less';
|
||||
import { CommentEvent, CommentItem, CommentParams, CommentType } from './types';
|
||||
import message from '@arco-design/web-vue/es/message';
|
||||
|
||||
|
@ -190,6 +191,6 @@ export default defineComponent({
|
|||
));
|
||||
};
|
||||
|
||||
return () => <div class="ms-comment gap[24px] flex flex-col">{renderParentList(commentList.value)}</div>;
|
||||
return () => <div class="ms-comment flex flex-col gap-[16px]">{renderParentList(commentList.value)}</div>;
|
||||
},
|
||||
});
|
||||
|
|
|
@ -111,4 +111,9 @@
|
|||
box-shadow: 1px -1px 4px rgba(2 2 2 / 10%);
|
||||
@apply absolute bottom-0 w-full bg-white px-4 py-4;
|
||||
}
|
||||
:deep(.rich-wrapper) {
|
||||
.halo-rich-text-editor {
|
||||
padding: 8px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/* 评论组件的样式 */
|
||||
.ms-comment-child-container {
|
||||
padding: 16px;
|
||||
border: 0.5px solid var(--color-text-input-border); /* 设置近似 0.5px 的边框 */
|
||||
border-radius: 4px;
|
||||
}
|
||||
.markdown-body {
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
color: var(--color-text-2) !important;
|
||||
ul {
|
||||
list-style: disc !important;
|
||||
li[data-type='taskItem'] {
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
list-style: none !important;
|
||||
@apply my-6 flex items-center;
|
||||
label {
|
||||
margin-right: 4px;
|
||||
@apply flex items-center;
|
||||
}
|
||||
> div {
|
||||
@apply flex items-center;
|
||||
> p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ol {
|
||||
list-style: decimal !important;
|
||||
}
|
||||
}
|
|
@ -160,7 +160,7 @@
|
|||
</a-spin>
|
||||
</div>
|
||||
<div v-else-if="activeExtraKey === 'comments'" class="pl-[16px]">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="mb-[16px] flex items-center justify-between">
|
||||
<div class="text-[var(--color-text-4)]">
|
||||
{{
|
||||
t('ms.minders.commentTotal', {
|
||||
|
|
|
@ -164,8 +164,18 @@
|
|||
}
|
||||
}
|
||||
.ms-minder-editor-extra--visible {
|
||||
width: 40%;
|
||||
width: 35%;
|
||||
min-width: 360px;
|
||||
transition: all 300ms ease-in-out;
|
||||
animation: minWidth 300ms ease-in-out;
|
||||
}
|
||||
@keyframes minWidth {
|
||||
from {
|
||||
min-width: 0;
|
||||
}
|
||||
to {
|
||||
min-width: 360px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -517,14 +517,14 @@
|
|||
}
|
||||
@apply relative overflow-hidden;
|
||||
:deep(.halo-rich-text-editor .ProseMirror) {
|
||||
padding: 16px 24px !important;
|
||||
padding: 16px !important;
|
||||
height: 130px;
|
||||
p:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
:deep(.halo-rich-text-editor) {
|
||||
padding: 16px 24px !important;
|
||||
padding: 16px !important;
|
||||
.editor-header {
|
||||
.ms-scroll-bar();
|
||||
|
||||
|
|
|
@ -733,12 +733,12 @@
|
|||
}
|
||||
.ms-base-table--hasQuickCreate {
|
||||
:deep(.arco-table-body:not(.arco-scrollbar-container)) {
|
||||
padding-top: 54px;
|
||||
padding-top: 50px;
|
||||
}
|
||||
:deep(.arco-table-element:not(.arco-table-header .arco-table-element)) {
|
||||
padding-bottom: 54px;
|
||||
padding-bottom: 50px;
|
||||
tbody {
|
||||
transform: translateY(54px);
|
||||
transform: translateY(50px);
|
||||
}
|
||||
}
|
||||
:deep(.arco-table-tr:first-child) {
|
||||
|
@ -749,9 +749,9 @@
|
|||
.ms-base-table-quickCreate {
|
||||
@apply absolute left-0 flex w-full items-center;
|
||||
|
||||
top: 55px;
|
||||
top: 39px;
|
||||
z-index: 11;
|
||||
padding: 16px;
|
||||
padding: 14px 16px;
|
||||
background-color: var(--color-text-n9);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -217,7 +217,6 @@
|
|||
async function selectProject(
|
||||
value: string | number | boolean | Record<string, any> | (string | number | boolean | Record<string, any>)[]
|
||||
) {
|
||||
appStore.setCurrentProjectId(value as string);
|
||||
try {
|
||||
appStore.showLoading();
|
||||
await switchProject({
|
||||
|
@ -228,13 +227,14 @@
|
|||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
await userStore.checkIsLogin();
|
||||
appStore.hideLoading();
|
||||
router.replace({
|
||||
path: route.path,
|
||||
query: {
|
||||
...route.query,
|
||||
orgId: appStore.currentOrgId,
|
||||
pId: appStore.currentProjectId,
|
||||
pId: value as string,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import { useRouter } from 'vue-router';
|
||||
import { defineStore } from 'pinia';
|
||||
|
||||
import { getProjectInfo } from '@/api/modules/project-management/project';
|
||||
import { getUserHasProjectPermission } from '@/api/modules/system';
|
||||
import {
|
||||
getAuthenticationList,
|
||||
getLocalConfig,
|
||||
|
@ -8,10 +11,12 @@ import {
|
|||
logout as userLogout,
|
||||
} from '@/api/modules/user';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useUser from '@/hooks/useUser';
|
||||
import { NO_PROJECT_ROUTE_NAME } from '@/router/constants';
|
||||
import useLicenseStore from '@/store/modules/setting/license';
|
||||
import { getHashParameters } from '@/utils';
|
||||
import { clearToken, setToken } from '@/utils/auth';
|
||||
import { composePermissions } from '@/utils/permission';
|
||||
import { composePermissions, getFirstRouteNameByPermission } from '@/utils/permission';
|
||||
import { removeRouteListener } from '@/utils/route-listener';
|
||||
|
||||
import type { LoginData } from '@/models/user';
|
||||
|
@ -120,6 +125,7 @@ const useUserStore = defineStore('user', {
|
|||
const res = await getAuthenticationList();
|
||||
this.loginType = res;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
|
@ -201,6 +207,45 @@ const useUserStore = defineStore('user', {
|
|||
console.log(error);
|
||||
}
|
||||
},
|
||||
async checkIsLogin() {
|
||||
const { isLoginPage } = useUser();
|
||||
const router = useRouter();
|
||||
const appStore = useAppStore();
|
||||
const isLogin = await this.isLogin(true);
|
||||
if (isLogin && appStore.currentProjectId !== 'no_such_project') {
|
||||
// 当前为登陆状态,且已经选择了项目,初始化当前项目配置
|
||||
try {
|
||||
const HasProjectPermission = await getUserHasProjectPermission(appStore.currentProjectId);
|
||||
if (!HasProjectPermission) {
|
||||
// 没有项目权限(用户所在的当前项目被禁用&用户被移除出去该项目)
|
||||
router.push({
|
||||
name: NO_PROJECT_ROUTE_NAME,
|
||||
});
|
||||
return;
|
||||
}
|
||||
const res = await getProjectInfo(appStore.currentProjectId);
|
||||
if (!res) {
|
||||
// 如果项目被删除或者被禁用,跳转到无项目页面
|
||||
router.push({
|
||||
name: NO_PROJECT_ROUTE_NAME,
|
||||
});
|
||||
}
|
||||
|
||||
if (res) {
|
||||
appStore.setCurrentMenuConfig(res?.moduleIds || []);
|
||||
}
|
||||
} catch (err) {
|
||||
appStore.setCurrentMenuConfig([]);
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
if (isLoginPage() && isLogin) {
|
||||
// 当前页面为登录页面,且已经登录,跳转到首页
|
||||
const currentRouteName = getFirstRouteNameByPermission(router.getRoutes());
|
||||
router.push({ name: currentRouteName });
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -384,7 +384,7 @@
|
|||
const copyCsvVariables = defaultScenarioInfo.scenarioConfig.variable.csvVariables.map((e) => ({
|
||||
...e,
|
||||
copyId: e.id,
|
||||
id: getGenerateId(),
|
||||
id: isCopy ? getGenerateId() : e.id,
|
||||
}));
|
||||
if (isCopy) {
|
||||
// 场景被复制,递归处理节点,增加copyFromStepId
|
||||
|
|
|
@ -30,14 +30,14 @@
|
|||
</a-popover>
|
||||
</template>
|
||||
<template #right>
|
||||
<!-- <a-radio-group v-model:model-value="showType" type="button" size="small" class="list-show-type">
|
||||
<a-radio-group v-model:model-value="showType" type="button" size="small" class="list-show-type">
|
||||
<a-radio value="list" class="show-type-icon !m-[2px]">
|
||||
<MsIcon :size="14" type="icon-icon_view-list_outlined" />
|
||||
</a-radio>
|
||||
<a-radio value="xMind" class="show-type-icon !m-[2px]">
|
||||
<MsIcon :size="14" type="icon-icon_mindnote_outlined" />
|
||||
</a-radio>
|
||||
</a-radio-group> -->
|
||||
</a-radio-group>
|
||||
</template>
|
||||
</MsAdvanceFilter>
|
||||
<ms-base-table
|
||||
|
|
Loading…
Reference in New Issue