feat(功能用例): 脑图用例评论&接口部分 bug 修复

This commit is contained in:
baiqi 2024-05-22 17:04:47 +08:00 committed by 刘瑞斌
parent 481bd86b44
commit bb100c6715
16 changed files with 156 additions and 129 deletions

View File

@ -6,19 +6,16 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { useRoute, useRouter } from 'vue-router';
import { useEventListener, useWindowSize } from '@vueuse/core'; import { useEventListener, useWindowSize } from '@vueuse/core';
import { Message } from '@arco-design/web-vue'; import { Message } from '@arco-design/web-vue';
import MsSysUpgradeTip from '@/components/pure/ms-sys-upgrade-tip/index.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 { saveBaseUrl } from '@/api/modules/setting/config';
import { getUserHasProjectPermission } from '@/api/modules/system';
import { GetPlatformIconUrl } from '@/api/requrls/setting/config'; import { GetPlatformIconUrl } from '@/api/requrls/setting/config';
// import GlobalSetting from '@/components/pure/global-setting/index.vue'; // import GlobalSetting from '@/components/pure/global-setting/index.vue';
import useLocale from '@/locale/useLocale'; 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 { useUserStore } from '@/store';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import useLicenseStore from '@/store/modules/setting/license'; import useLicenseStore from '@/store/modules/setting/license';
@ -26,15 +23,12 @@
import { setFavicon, watchStyle, watchTheme } from '@/utils/theme'; import { setFavicon, watchStyle, watchTheme } from '@/utils/theme';
import { getPublicKeyRequest } from './api/modules/user'; import { getPublicKeyRequest } from './api/modules/user';
import { getFirstRouteNameByPermission } from './utils/permission';
import enUS from '@arco-design/web-vue/es/locale/lang/en-us'; import enUS from '@arco-design/web-vue/es/locale/lang/en-us';
import zhCN from '@arco-design/web-vue/es/locale/lang/zh-cn'; import zhCN from '@arco-design/web-vue/es/locale/lang/zh-cn';
const appStore = useAppStore(); const appStore = useAppStore();
const userStore = useUserStore(); const userStore = useUserStore();
const licenseStore = useLicenseStore(); const licenseStore = useLicenseStore();
const router = useRouter();
const route = useRoute();
const { currentLocale } = useLocale(); const { currentLocale } = useLocale();
const locale = computed(() => { 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 getPublicKey = async () => {
const publicKey = await getPublicKeyRequest(); const publicKey = await getPublicKeyRequest();
@ -120,7 +77,7 @@
onBeforeMount(async () => { onBeforeMount(async () => {
await getPublicKey(); await getPublicKey();
if (WHITE_LIST.find((el) => el.path === window.location.hash.split('#')[1]) === undefined) { if (WHITE_LIST.find((el) => el.path === window.location.hash.split('#')[1]) === undefined) {
await checkIsLogin(); await userStore.checkIsLogin();
} }
const { height } = useWindowSize(); const { height } = useWindowSize();
appStore.innerHeight = height.value; appStore.innerHeight = height.value;

View File

@ -1,5 +1,4 @@
import MSR from '@/api/http/index'; import MSR from '@/api/http/index';
import { associatedProjectOptionsUrl } from '@/api/requrls/case-management/featureCase';
import { ProjectListUrl, ProjectSwitchUrl } from '@/api/requrls/project-management/project'; import { ProjectListUrl, ProjectSwitchUrl } from '@/api/requrls/project-management/project';
import type { ProjectListItem } from '@/models/setting/project'; import type { ProjectListItem } from '@/models/setting/project';

View File

@ -272,7 +272,7 @@
.arco-select-view-single, .arco-select-view-single,
.arco-select { .arco-select {
width: 100%; width: 100%;
border: 1px solid var(--color-text-input-border); border: 1px solid var(--color-text-n8);
background-color: var(--color-text-fff); background-color: var(--color-text-fff);
&:not(:disabled, .arco-input-tag-disabled, .arco-input-disabled, .arco-select-view-disabled):hover { &:not(:disabled, .arco-input-tag-disabled, .arco-input-disabled, .arco-select-view-disabled):hover {
border-color: rgb(var(--primary-5)) !important; border-color: rgb(var(--primary-5)) !important;

View File

@ -96,32 +96,3 @@ body {
background: rgb(var(--primary-6)); 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;
}
}
}

View File

@ -1,23 +1,19 @@
<template> <template>
<div class="flex flex-row gap-[8px] break-words"> <div class="flex flex-row gap-[8px] break-words">
<div class="p-1"> <MsAvatar :avatar="creatorInfo.avatar" /></div> <MsAvatar :avatar="creatorInfo.avatar" />
<div class="flex w-full flex-col"> <div class="flex flex-1 flex-col">
<div class="font-medium text-[var(--color-text-1)]"> <div class="font-medium leading-[22px] text-[var(--color-text-1)]">
{{ creatorInfo.name }} {{ creatorInfo.name }}
<span v-if="props.element.replyUser">{{ t('ms.comment.reply') }} {{ replyUserName }}</span> <span v-if="props.element.replyUser">{{ t('ms.comment.reply') }} {{ replyUserName }}</span>
</div> </div>
<div v-dompurify-html="props.element.content" class="markdown-body mt-[4px] break-words break-all"></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="mt-[8px] flex items-center justify-between">
<div class="text-[var(--color-text-4)]">{{ <div class="text-[12px] leading-[16px] text-[var(--color-text-4)]">
dayjs(props.element.updateTime).format('YYYY-MM-DD HH:mm:ss') {{ dayjs(props.element.updateTime).format('YYYY-MM-DD HH:mm:ss') }}
}}</div> </div>
<div class="ml-[24px] flex flex-row gap-[16px]"> <div class="flex gap-[8px]">
<div <div v-if="props.mode === 'parent'" class="comment-btn" @click="expendChange">
v-if="props.mode === 'parent' && element.childComments?.length"
class="comment-btn"
@click="expendChange"
>
<MsIconfont type="icon-icon_comment_outlined" /> <MsIconfont type="icon-icon_comment_outlined" />
<span>{{ !expendComment ? t('ms.comment.expendComment') : t('ms.comment.collapseComment') }}</span> <span>{{ !expendComment ? t('ms.comment.expendComment') : t('ms.comment.collapseComment') }}</span>
<span class="text-[var(--color-text-4)]">({{ element.childComments?.length }})</span> <span class="text-[var(--color-text-4)]">({{ element.childComments?.length }})</span>
@ -29,26 +25,8 @@
@click="replyClick" @click="replyClick"
> >
<MsIconfont type="icon-icon_reply" /> <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> </div>
<MoreAction v-if="hasAuth" :list="actionsList" @select="handleMoreActionSelect"></MoreAction>
</div> </div>
</div> </div>
</div> </div>
@ -61,6 +39,8 @@
import MsAvatar from '@/components/pure/ms-avatar/index.vue'; import MsAvatar from '@/components/pure/ms-avatar/index.vue';
import MsIconfont from '@/components/pure/ms-icon-font/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 { useI18n } from '@/hooks/useI18n';
import useUserStore from '@/store/modules/user/index'; import useUserStore from '@/store/modules/user/index';
@ -101,6 +81,9 @@
const expendComment = ref(false); const expendComment = ref(false);
const expendChange = () => { const expendChange = () => {
if (!props.element.childComments?.length) {
return;
}
expendComment.value = !expendComment.value; expendComment.value = !expendComment.value;
emit('expend', expendComment.value); emit('expend', expendComment.value);
}; };
@ -119,6 +102,30 @@
status.value = 'delete'; 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(() => { const creatorInfo = computed(() => {
return props.element.commentUserInfos.filter((item) => item != null && item.id === props.element.createUser)[0]; return props.element.commentUserInfos.filter((item) => item != null && item.id === props.element.createUser)[0];
}); });
@ -133,13 +140,12 @@
<style lang="less" scoped> <style lang="less" scoped>
.comment-btn { .comment-btn {
display: flex; @apply flex cursor-pointer items-center;
align-items: center;
padding: 2px 8px; padding: 2px 8px;
font-size: 12px;
border-radius: 4px; border-radius: 4px;
color: var(--color-text-1); color: var(--color-text-4);
flex-direction: row;
gap: 4px; gap: 4px;
cursor: pointer;
} }
</style> </style>

View File

@ -5,6 +5,7 @@ import CommentInput from './input.vue';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import './style.less';
import { CommentEvent, CommentItem, CommentParams, CommentType } from './types'; import { CommentEvent, CommentItem, CommentParams, CommentType } from './types';
import message from '@arco-design/web-vue/es/message'; 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>;
}, },
}); });

View File

@ -111,4 +111,9 @@
box-shadow: 1px -1px 4px rgba(2 2 2 / 10%); box-shadow: 1px -1px 4px rgba(2 2 2 / 10%);
@apply absolute bottom-0 w-full bg-white px-4 py-4; @apply absolute bottom-0 w-full bg-white px-4 py-4;
} }
:deep(.rich-wrapper) {
.halo-rich-text-editor {
padding: 8px !important;
}
}
</style> </style>

View File

@ -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;
}
}

View File

@ -160,7 +160,7 @@
</a-spin> </a-spin>
</div> </div>
<div v-else-if="activeExtraKey === 'comments'" class="pl-[16px]"> <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)]"> <div class="text-[var(--color-text-4)]">
{{ {{
t('ms.minders.commentTotal', { t('ms.minders.commentTotal', {

View File

@ -164,8 +164,18 @@
} }
} }
.ms-minder-editor-extra--visible { .ms-minder-editor-extra--visible {
width: 40%; width: 35%;
min-width: 360px;
transition: all 300ms ease-in-out; transition: all 300ms ease-in-out;
animation: minWidth 300ms ease-in-out;
}
@keyframes minWidth {
from {
min-width: 0;
}
to {
min-width: 360px;
}
} }
} }
</style> </style>

View File

@ -517,14 +517,14 @@
} }
@apply relative overflow-hidden; @apply relative overflow-hidden;
:deep(.halo-rich-text-editor .ProseMirror) { :deep(.halo-rich-text-editor .ProseMirror) {
padding: 16px 24px !important; padding: 16px !important;
height: 130px; height: 130px;
p:first-child { p:first-child {
margin-top: 0; margin-top: 0;
} }
} }
:deep(.halo-rich-text-editor) { :deep(.halo-rich-text-editor) {
padding: 16px 24px !important; padding: 16px !important;
.editor-header { .editor-header {
.ms-scroll-bar(); .ms-scroll-bar();

View File

@ -733,12 +733,12 @@
} }
.ms-base-table--hasQuickCreate { .ms-base-table--hasQuickCreate {
:deep(.arco-table-body:not(.arco-scrollbar-container)) { :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)) { :deep(.arco-table-element:not(.arco-table-header .arco-table-element)) {
padding-bottom: 54px; padding-bottom: 50px;
tbody { tbody {
transform: translateY(54px); transform: translateY(50px);
} }
} }
:deep(.arco-table-tr:first-child) { :deep(.arco-table-tr:first-child) {
@ -749,9 +749,9 @@
.ms-base-table-quickCreate { .ms-base-table-quickCreate {
@apply absolute left-0 flex w-full items-center; @apply absolute left-0 flex w-full items-center;
top: 55px; top: 39px;
z-index: 11; z-index: 11;
padding: 16px; padding: 14px 16px;
background-color: var(--color-text-n9); background-color: var(--color-text-n9);
} }
} }

View File

@ -217,7 +217,6 @@
async function selectProject( async function selectProject(
value: string | number | boolean | Record<string, any> | (string | number | boolean | Record<string, any>)[] value: string | number | boolean | Record<string, any> | (string | number | boolean | Record<string, any>)[]
) { ) {
appStore.setCurrentProjectId(value as string);
try { try {
appStore.showLoading(); appStore.showLoading();
await switchProject({ await switchProject({
@ -228,13 +227,14 @@
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(error); console.log(error);
} finally { } finally {
await userStore.checkIsLogin();
appStore.hideLoading(); appStore.hideLoading();
router.replace({ router.replace({
path: route.path, path: route.path,
query: { query: {
...route.query, ...route.query,
orgId: appStore.currentOrgId, orgId: appStore.currentOrgId,
pId: appStore.currentProjectId, pId: value as string,
}, },
}); });
} }

View File

@ -1,5 +1,8 @@
import { useRouter } from 'vue-router';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { getProjectInfo } from '@/api/modules/project-management/project';
import { getUserHasProjectPermission } from '@/api/modules/system';
import { import {
getAuthenticationList, getAuthenticationList,
getLocalConfig, getLocalConfig,
@ -8,10 +11,12 @@ import {
logout as userLogout, logout as userLogout,
} from '@/api/modules/user'; } from '@/api/modules/user';
import { useI18n } from '@/hooks/useI18n'; 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 useLicenseStore from '@/store/modules/setting/license';
import { getHashParameters } from '@/utils'; import { getHashParameters } from '@/utils';
import { clearToken, setToken } from '@/utils/auth'; import { clearToken, setToken } from '@/utils/auth';
import { composePermissions } from '@/utils/permission'; import { composePermissions, getFirstRouteNameByPermission } from '@/utils/permission';
import { removeRouteListener } from '@/utils/route-listener'; import { removeRouteListener } from '@/utils/route-listener';
import type { LoginData } from '@/models/user'; import type { LoginData } from '@/models/user';
@ -120,6 +125,7 @@ const useUserStore = defineStore('user', {
const res = await getAuthenticationList(); const res = await getAuthenticationList();
this.loginType = res; this.loginType = res;
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console
console.log(error); console.log(error);
} }
}, },
@ -201,6 +207,45 @@ const useUserStore = defineStore('user', {
console.log(error); 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 });
}
},
}, },
}); });

View File

@ -384,7 +384,7 @@
const copyCsvVariables = defaultScenarioInfo.scenarioConfig.variable.csvVariables.map((e) => ({ const copyCsvVariables = defaultScenarioInfo.scenarioConfig.variable.csvVariables.map((e) => ({
...e, ...e,
copyId: e.id, copyId: e.id,
id: getGenerateId(), id: isCopy ? getGenerateId() : e.id,
})); }));
if (isCopy) { if (isCopy) {
// copyFromStepId // copyFromStepId

View File

@ -30,14 +30,14 @@
</a-popover> </a-popover>
</template> </template>
<template #right> <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]"> <a-radio value="list" class="show-type-icon !m-[2px]">
<MsIcon :size="14" type="icon-icon_view-list_outlined" /> <MsIcon :size="14" type="icon-icon_view-list_outlined" />
</a-radio> </a-radio>
<a-radio value="xMind" class="show-type-icon !m-[2px]"> <a-radio value="xMind" class="show-type-icon !m-[2px]">
<MsIcon :size="14" type="icon-icon_mindnote_outlined" /> <MsIcon :size="14" type="icon-icon_mindnote_outlined" />
</a-radio> </a-radio>
</a-radio-group> --> </a-radio-group>
</template> </template>
</MsAdvanceFilter> </MsAdvanceFilter>
<ms-base-table <ms-base-table