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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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>
</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', {

View File

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

View File

@ -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();

View File

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

View File

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

View File

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

View File

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

View File

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