feat(环境管理): 断言基本页面&评论逻辑修改
This commit is contained in:
parent
e1bfeadd2e
commit
ba3d33c24e
|
@ -0,0 +1,152 @@
|
|||
<template>
|
||||
<div class="ms-assertion">
|
||||
<a-dropdown trigger="hover" @select="handleSelect">
|
||||
<a-button class="w-[84px]" type="outline">
|
||||
<div class="flex flex-row items-center gap-[8px]">
|
||||
<icon-plus />
|
||||
<span>{{ t('ms.assertion.button') }}</span>
|
||||
</div>
|
||||
</a-button>
|
||||
<template #content>
|
||||
<a-doption v-for="item in assertOption" :key="item.value" :value="item.value">{{ item.label }}</a-doption>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
<div class="ms-assertion-body">
|
||||
<article class="ms-assertion-body-left">
|
||||
<div
|
||||
v-for="(item, index) in activeOption"
|
||||
:key="item.value"
|
||||
class="ms-assertion-body-left-item"
|
||||
@click="handleItemClick(item)"
|
||||
>
|
||||
<div class="ms-assertion-body-left-item-row">
|
||||
<span class="ms-assertion-body-left-item-row-num">{{ index + 1 }}</span>
|
||||
<span class="ms-assertion-body-left-item-row-title">{{ item.label }}</span>
|
||||
</div>
|
||||
<div class="ms-assertion-body-left-item-switch">
|
||||
<a-switch type="line" size="small" />
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<section class="ms-assertion-body-right"> </section>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
defineOptions({
|
||||
name: 'MsAssertion',
|
||||
});
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const assertOptionSource = [
|
||||
{
|
||||
label: t('ms.assertion.statusCode'),
|
||||
value: 'statusCode',
|
||||
},
|
||||
{
|
||||
label: t('ms.assertion.responseHeader'),
|
||||
value: 'responseHeader',
|
||||
},
|
||||
{
|
||||
label: t('ms.assertion.responseBody'),
|
||||
value: 'responseBody',
|
||||
},
|
||||
{
|
||||
label: t('ms.assertion.responseTime'),
|
||||
value: 'responseTime',
|
||||
},
|
||||
{
|
||||
label: t('ms.assertion.param'),
|
||||
value: 'param',
|
||||
},
|
||||
{
|
||||
label: t('ms.assertion.script'),
|
||||
value: 'script',
|
||||
},
|
||||
];
|
||||
|
||||
const selectIds = ref<string[]>([]);
|
||||
|
||||
const activeKey = ref<string>('');
|
||||
|
||||
const assertOption = computed(() => {
|
||||
return assertOptionSource.filter((item) => !selectIds.value.includes(item.value));
|
||||
});
|
||||
|
||||
const activeOption = computed(() => {
|
||||
return assertOptionSource.filter((item) => selectIds.value.includes(item.value));
|
||||
});
|
||||
|
||||
const handleSelect = (value: string | number | Record<string, any> | undefined) => {
|
||||
selectIds.value.push(value as string);
|
||||
};
|
||||
|
||||
const handleItemClick = (item: { label: string; value: string }) => {
|
||||
activeKey.value = item.value;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ms-assertion {
|
||||
width: 100%;
|
||||
&-body {
|
||||
display: flex;
|
||||
margin-top: 8px;
|
||||
flex-flow: row nowrap;
|
||||
gap: 8px;
|
||||
&-left {
|
||||
display: flex;
|
||||
padding: 12px;
|
||||
width: 216px;
|
||||
height: calc(100vh - 394px);
|
||||
background-color: var(--color-text-n9);
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
&-item {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
background-color: var(--color-text-fff);
|
||||
cursor: pointer;
|
||||
&-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
&-num {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
color: var(--color-text-4);
|
||||
background-color: var(--color-text-n8);
|
||||
line-height: 16px;
|
||||
}
|
||||
&-title {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: var(--color-text-1);
|
||||
line-height: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&-right {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
border: 1px solid var(--color-text-n8);
|
||||
border-radius: 4px;
|
||||
background: var(--color-text-fff);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,3 @@
|
|||
export default {
|
||||
'ms.assertion.button': 'Assertion',
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
export default {
|
||||
'ms.assertion.button': '断言',
|
||||
'ms.assertion.statusCode': '状态码',
|
||||
'ms.assertion.responseHeader': '响应头',
|
||||
'ms.assertion.responseBody': '响应体',
|
||||
'ms.assertion.responseTime': '响应时间',
|
||||
'ms.assertion.param': '变量',
|
||||
'ms.assertion.script': '脚本',
|
||||
};
|
|
@ -26,7 +26,7 @@
|
|||
<MsIconfont type="icon-icon_edit_outlined" />
|
||||
<span>{{ t('ms.comment.edit') }}</span>
|
||||
</div>
|
||||
<div v-if="hasEditAuth" class="comment-btn" @click="deleteClick">
|
||||
<div class="comment-btn" @click="deleteClick">
|
||||
<MsIconfont type="icon-icon_delete-trash_outlined" />
|
||||
<span>{{ t('ms.comment.delete') }}</span>
|
||||
</div>
|
||||
|
@ -51,14 +51,19 @@
|
|||
const userStore = useUserStore();
|
||||
const { t } = useI18n();
|
||||
|
||||
defineOptions({ name: 'MsCommentItem' });
|
||||
|
||||
const props = defineProps<{
|
||||
element: CommentItem; // 评论的具体内容
|
||||
mode: 'parent' | 'child'; // 父级评论还是子级评论
|
||||
onReply?: () => void; // 回复
|
||||
onEdit?: () => void; // 编辑
|
||||
onDelete?: () => void; // 删除
|
||||
}>();
|
||||
|
||||
// 是否拥有编辑|删除权限
|
||||
const hasEditAuth = computed(() => {
|
||||
return props.element.commentUserInfo.id === userStore.id;
|
||||
return props.element.createUser === userStore.id;
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
|
|
@ -16,6 +16,10 @@ export default defineComponent({
|
|||
type: Array as PropType<CommentItem[]>,
|
||||
default: () => [],
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean as PropType<boolean>,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
emits: {
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
|
@ -23,11 +27,19 @@ export default defineComponent({
|
|||
delete: (value: string) => true, // 删除评论
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const { commentList } = toRefs(props);
|
||||
const currentItem = reactive<{ id: string; parentId: string }>({ id: '', parentId: '' });
|
||||
const { commentList, disabled } = toRefs(props);
|
||||
const currentItem = reactive<{ id: string; parentId?: string }>({
|
||||
id: '',
|
||||
parentId: '',
|
||||
});
|
||||
const { t } = useI18n();
|
||||
const { openModal } = useModal();
|
||||
|
||||
const resetCurrentItem = () => {
|
||||
currentItem.id = '';
|
||||
currentItem.parentId = '';
|
||||
};
|
||||
|
||||
const handlePublish = (content: string, item: CommentItem) => {
|
||||
const params: CommentParams = {
|
||||
...item,
|
||||
|
@ -36,9 +48,10 @@ export default defineComponent({
|
|||
};
|
||||
emit('updateOrAdd', params, (result: boolean) => {
|
||||
if (result) {
|
||||
message.success(t('common.publishSuccess'));
|
||||
message.success(t('common.publishSuccessfully'));
|
||||
resetCurrentItem();
|
||||
} else {
|
||||
message.error(t('common.publishFail'));
|
||||
message.error(t('common.publishFailed'));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -60,12 +73,30 @@ export default defineComponent({
|
|||
});
|
||||
};
|
||||
|
||||
const handleReply = (item: CommentItem) => {
|
||||
if (item.childComments) {
|
||||
// 父级评论
|
||||
currentItem.id = item.id;
|
||||
} else {
|
||||
// 子级评论
|
||||
currentItem.id = item.parentId || '';
|
||||
currentItem.parentId = item.id;
|
||||
}
|
||||
};
|
||||
|
||||
const handelEdit = (item: CommentItem) => {
|
||||
currentItem.id = item.id;
|
||||
currentItem.parentId = item.parentId || '';
|
||||
};
|
||||
|
||||
const renderInput = (item: CommentItem) => {
|
||||
return (
|
||||
<CommentInput
|
||||
isShowAvatar={false}
|
||||
isUseBottom={false}
|
||||
onPublish={(content: string) => handlePublish(content, item)}
|
||||
defaultValue={item.content || ''}
|
||||
onCancel={() => resetCurrentItem()}
|
||||
{...item}
|
||||
/>
|
||||
);
|
||||
|
@ -79,14 +110,8 @@ export default defineComponent({
|
|||
return (
|
||||
<div class="flex flex-col">
|
||||
<Item
|
||||
onReply={() => {
|
||||
currentItem.id = item.id;
|
||||
currentItem.parentId = item.parentId || '';
|
||||
}}
|
||||
onEdit={() => {
|
||||
currentItem.id = item.id;
|
||||
currentItem.parentId = item.parentId || '';
|
||||
}}
|
||||
onReply={() => handleReply(item)}
|
||||
onEdit={() => handelEdit(item)}
|
||||
onDelete={() => handleDelete(item)}
|
||||
mode={'child'}
|
||||
element={item}
|
||||
|
@ -100,11 +125,18 @@ export default defineComponent({
|
|||
const renderParentList = (list: CommentItem[]) => {
|
||||
return list.map((item) => {
|
||||
return (
|
||||
<Item mode={'parent'} onDelete={() => handleDelete(item)} element={item}>
|
||||
<div class="rounded border border-[var(--color-text-7)] p-[16px]">
|
||||
{renderChildrenList(item.childComments)}
|
||||
</div>
|
||||
</Item>
|
||||
<>
|
||||
<Item
|
||||
mode={'parent'}
|
||||
onReply={() => handleReply(item)}
|
||||
onEdit={() => handelEdit(item)}
|
||||
onDelete={() => handleDelete(item)}
|
||||
element={item}
|
||||
>
|
||||
<div class="rounded border border-[var(--color-text-7)] p-[16px]"></div>
|
||||
</Item>
|
||||
{item.id === currentItem.id && renderInput(item)}
|
||||
</>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -22,28 +22,32 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { useVModel } from '@vueuse/core';
|
||||
|
||||
import MsAvatar from '@/components/pure/ms-avatar/index.vue';
|
||||
import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
defineOptions({ name: 'MsCommentInput' });
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
// const currentContent = defineModel<string>('content', { required: true });
|
||||
|
||||
const props = defineProps<{
|
||||
content: string;
|
||||
isShowAvatar: boolean; // 是否显示评论人头像
|
||||
isUseBottom: boolean; // 是否被用于底部
|
||||
defaultValue?: string; // 默认值
|
||||
}>();
|
||||
|
||||
const currentContent = ref(props.defaultValue || '');
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'update:content', value: string): void;
|
||||
(event: 'publish', value: string): void;
|
||||
(event: 'cancel'): void;
|
||||
}>();
|
||||
|
||||
const isActive = ref(false);
|
||||
const currentContent = useVModel(props, 'content', emit);
|
||||
|
||||
const publish = () => {
|
||||
emit('publish', currentContent.value);
|
||||
|
@ -53,6 +57,7 @@
|
|||
const cancelClick = () => {
|
||||
isActive.value = false;
|
||||
currentContent.value = '';
|
||||
emit('cancel');
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@ export default {
|
|||
'common.newSuccess': 'Added successfully',
|
||||
'common.publish': 'Publish',
|
||||
'common.publishSuccessfully': 'Published successfully',
|
||||
'common.publishFailed': 'Published failed',
|
||||
'common.string': 'String',
|
||||
'common.number': 'Number',
|
||||
'common.boolean': 'Boolean',
|
||||
|
|
|
@ -83,6 +83,7 @@ export default {
|
|||
'common.newSuccess': '新增成功',
|
||||
'common.publish': '发布',
|
||||
'common.publishSuccessfully': '发布成功',
|
||||
'common.publishFailed': '发布失败',
|
||||
'common.string': '字符串',
|
||||
'common.number': '数字',
|
||||
'common.boolean': '布尔',
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import type { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import AllParamsTable from '../allParams/AllParamsTable.vue';
|
||||
import AllParamsTable from './allParams/AllParamsTable.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore';
|
|
@ -43,19 +43,19 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import AssertTab from './AssertTab.vue';
|
||||
import DataBaseTab from './DatabaseTab.vue';
|
||||
import DisplayTab from './DisplayTab.vue';
|
||||
import EnvParamsTab from './EnvParamsTab.vue';
|
||||
import HostTab from './HostTab.vue';
|
||||
import HttpTab from './HttpTab.vue';
|
||||
import PostTab from './PostTab.vue';
|
||||
import PreTab from './PreTab.vue';
|
||||
import TcpTab from './TcpTab.vue';
|
||||
import AssertTab from './envParams/AssertTab.vue';
|
||||
import DataBaseTab from './envParams/DatabaseTab.vue';
|
||||
import DisplayTab from './envParams/DisplayTab.vue';
|
||||
import EnvParamsTab from './envParams/EnvParamsTab.vue';
|
||||
import HostTab from './envParams/HostTab.vue';
|
||||
import HttpTab from './envParams/HttpTab.vue';
|
||||
import PostTab from './envParams/PostTab.vue';
|
||||
import PreTab from './envParams/PreTab.vue';
|
||||
import TcpTab from './envParams/TcpTab.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
const activeKey = ref('http');
|
||||
const activeKey = ref('assert');
|
||||
const envForm = ref();
|
||||
const canSave = ref(false);
|
||||
const { t } = useI18n();
|
|
@ -12,7 +12,7 @@
|
|||
</template>
|
||||
<a-input
|
||||
v-model:model-value="record.name"
|
||||
:placeholder="t('ms.apiTestDebug.paramNamePlaceholder')"
|
||||
:placeholder="t('project.environmental.paramNamePlaceholder')"
|
||||
class="param-input"
|
||||
@input="(val) => addTableLine(val)"
|
||||
/>
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
<template>
|
||||
<div class="p-[24px]">
|
||||
<a-divider :margin="0" class="!mb-[16px]" />
|
||||
<div>
|
||||
<ms-assertion />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import MsAssertion from '@/components/business/ms-assertion/index.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
|
|
@ -188,8 +188,8 @@
|
|||
import MsMoreAction from '@/components/pure/ms-table-more-action/index.vue';
|
||||
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||
import AllParamBox from './components/AllParamBox.vue';
|
||||
import EnvGroupBox from './components/envGroup/EnvGroupBox.vue';
|
||||
import EnvParamBox from './components/envParams/EnvParamBox.vue';
|
||||
import EnvGroupBox from './components/EnvGroupBox.vue';
|
||||
import EnvParamBox from './components/EnvParamBox.vue';
|
||||
import RenamePop from './components/RenamePop.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
|
|
@ -11,6 +11,7 @@ export default {
|
|||
'project.environmental.mustContain': '必含',
|
||||
'project.environmental.searchParamsHolder': '通过名称或标签搜索',
|
||||
'project.environmental.paramName': '参数名称',
|
||||
'project.environmental.paramNamePlaceholder': '请输入参数名称',
|
||||
'project.environmental.paramType': '类型',
|
||||
'project.environmental.paramTypeTooltip': 'json:仅支持 UI 测试',
|
||||
'project.environmental.paramValue': '参数值',
|
||||
|
|
Loading…
Reference in New Issue