feat(版本管理): 版本管理&脑图调整

This commit is contained in:
baiqi 2023-11-08 14:36:53 +08:00 committed by 刘瑞斌
parent 684e3cf965
commit 62d7a62ce1
25 changed files with 970 additions and 659 deletions

View File

@ -0,0 +1,60 @@
import MSR from '@/api/http';
import {
AddVersion,
DeleteVersion,
EnableVersion,
GetVersionOptions,
GetVersionStatus,
ToggleVersionStatus,
UpdateVersion,
UseLatestVersion,
VersionPage,
} from '@/api/requrls/project-management/projectVersion';
import type { CommonList, TableQueryParams } from '@/models/common';
import type { ProjectCommon, ProjectItem, ProjectVersionOption } from '@/models/projectManagement/projectVersion';
// 更新版本
export function updateVersion(data: ProjectItem) {
return MSR.post({ url: UpdateVersion, data });
}
// 获取版本列表
export function getVersionList(data: TableQueryParams) {
return MSR.post<CommonList<ProjectItem>>({ url: VersionPage, data });
}
// 添加版本
export function addVersion(data: ProjectCommon) {
return MSR.post({ url: AddVersion, data });
}
// 切换版本状态
export function toggleVersionStatus(id: string) {
return MSR.get({ url: ToggleVersionStatus, params: id });
}
// 切换最新版本
export function useLatestVersion(id: string) {
return MSR.get({ url: UseLatestVersion, params: id });
}
// 开启/关闭项目版本
export function toggleVersion(id: string) {
return MSR.get({ url: EnableVersion, params: id });
}
// 获取项目版本列表选项
export function getVersionOptions(id: string) {
return MSR.get<ProjectVersionOption[]>({ url: GetVersionOptions, params: id });
}
// 获取版本状态
export function getVersionStatus(id: string) {
return MSR.get<boolean>({ url: GetVersionStatus, params: id });
}
// 删除版本
export function deleteVersion(id: string) {
return MSR.get({ url: DeleteVersion, params: id });
}

View File

@ -0,0 +1,9 @@
export const UpdateVersion = '/project/version/update'; // 更新版本
export const VersionPage = '/project/version/list'; // 版本列表
export const AddVersion = '/project/version/add'; // 新增版本
export const ToggleVersionStatus = '/project/version/switch/status'; // 启用/禁用版本
export const UseLatestVersion = '/project/version/switch/latest'; // 使用最新版本
export const EnableVersion = '/project/version/switch/enable'; // 启用版本
export const GetVersionOptions = '/project/version/option'; // 获取版本下拉列表
export const GetVersionStatus = '/project/version/enable'; // 获取版本状态
export const DeleteVersion = '/project/version/delete'; // 获取版本状态

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -171,6 +171,12 @@
.btn-text-sec-active(); .btn-text-sec-active();
.btn-text-sec-disabled(); .btn-text-sec-disabled();
} }
.arco-btn-text--danger {
color: rgb(var(--danger-6)) !important;
.btn-text-danger-hover();
.btn-text-danger-active();
.btn-text-danger-disabled();
}
.arco-btn-outline { .arco-btn-outline {
border: 1px solid rgb(var(--primary-5)) !important; border: 1px solid rgb(var(--primary-5)) !important;
color: rgb(var(--primary-5)) !important; color: rgb(var(--primary-5)) !important;

View File

@ -162,6 +162,21 @@
color: rgb(var(--primary-3)) !important; color: rgb(var(--primary-3)) !important;
} }
} }
.btn-text-danger-hover() {
&:not(:disabled):hover {
background-color: rgb(var(--danger-1)) !important;
}
}
.btn-text-danger-active() {
&:not(:disabled):active {
background-color: var(--danger-2) !important;
}
}
.btn-text-danger-disabled() {
&:disabled {
color: rgb(var(--danger-2)) !important;
}
}
/** 滚动条 **/ /** 滚动条 **/
.ms-scroll-bar() { .ms-scroll-bar() {

View File

@ -22,6 +22,7 @@ export default {
expand_six: 'Expand six level', expand_six: 'Expand six level',
}, },
insert: { insert: {
insert: 'Insert',
down: 'Subordinate', down: 'Subordinate',
up: 'Superior', up: 'Superior',
same: 'Same', same: 'Same',

View File

@ -14,14 +14,9 @@ export default {
expand: { expand: {
expand: '展开', expand: '展开',
folding: '收起', folding: '收起',
expand_one: '展开到一级节点',
expand_tow: '展开到二级节点',
expand_three: '展开到三级节点',
expand_four: '展开到四级节点',
expand_five: '展开到五级节点',
expand_six: '展开到六级节点',
}, },
insert: { insert: {
insert: '插入',
down: '插入下级主题', down: '插入下级主题',
up: '插入上级主题', up: '插入上级主题',
same: '插入同级主题', same: '插入同级主题',

View File

@ -1,56 +1,31 @@
<template> <template>
<header> <header>
<a-tabs v-model="activeName" class="mind_tab-content"> <div class="mind-tab-panel">
<a-tab-pane key="editMenu" :title="t('minder.main.header.minder')"> <edit-menu
<div class="mind-tab-panel"> :minder="minder"
<edit-menu :move-enable="props.moveEnable"
:minder="minder" :sequence-enable="props.sequenceEnable"
:move-enable="props.moveEnable" :tag-enable="props.tagEnable"
:sequence-enable="props.sequenceEnable" :progress-enable="props.progressEnable"
:tag-enable="props.tagEnable" :priority-count="props.priorityCount"
:progress-enable="props.progressEnable" :priority-prefix="props.priorityPrefix"
:priority-count="props.priorityCount" :tag-edit-check="props.tagEditCheck"
:priority-prefix="props.priorityPrefix" :tag-disable-check="props.tagDisableCheck"
:tag-edit-check="props.tagEditCheck" :priority-disable-check="props.priorityDisableCheck"
:tag-disable-check="props.tagDisableCheck" :priority-start-with-zero="props.priorityStartWithZero"
:priority-disable-check="props.priorityDisableCheck" :tags="props.tags"
:priority-start-with-zero="props.priorityStartWithZero" :distinct-tags="props.distinctTags"
:tags="props.tags" :del-confirm="props.delConfirm"
:distinct-tags="props.distinctTags" />
:del-confirm="props.delConfirm" </div>
/>
</div>
</a-tab-pane>
<a-tab-pane key="viewMenu" :title="t('minder.main.header.style')">
<div class="mind-tab-panel">
<view-menu
v-if="props.viewMenuEnable"
:minder="minder"
:default-mold="props.defaultMold"
:arrange-enable="props.arrangeEnable"
:mold-enable="props.moldEnable"
:font-enable="props.fontEnable"
:style-enable="props.styleEnable"
@mold-change="handleMoldChange"
/>
</div>
</a-tab-pane>
</a-tabs>
</header> </header>
</template> </template>
<script lang="ts" name="headerVue" setup> <script lang="ts" name="headerVue" setup>
import { ref } from 'vue';
import editMenu from '../menu/edit/editMenu.vue'; import editMenu from '../menu/edit/editMenu.vue';
import viewMenu from '../menu/view/viewMenu.vue';
import { useI18n } from '@/hooks/useI18n';
import { delProps, editMenuProps, moleProps, priorityProps, tagProps, viewMenuProps } from '../props'; import { delProps, editMenuProps, moleProps, priorityProps, tagProps, viewMenuProps } from '../props';
const { t } = useI18n();
const props = defineProps({ const props = defineProps({
...editMenuProps, ...editMenuProps,
...moleProps, ...moleProps,
@ -60,15 +35,6 @@
...viewMenuProps, ...viewMenuProps,
minder: null, minder: null,
}); });
const emit = defineEmits<{
(e: 'moldChange', data: number): void;
}>();
const activeName = ref('editMenu');
function handleMoldChange(data: number) {
emit('moldChange', data);
}
</script> </script>
<style lang="less"> <style lang="less">
@ -80,42 +46,3 @@
} }
} }
</style> </style>
<style lang="less" scoped>
header {
@apply bg-white;
font-size: 12px;
& > ul {
@apply m-0 flex items-center p-0;
height: 30px;
background-color: #e1e1e1;
li {
@apply inline-flex h-full list-none;
width: 80px;
line-height: 30px;
a {
@apply text-center no-underline;
font-size: 14px;
color: #337ab7;
}
a:hover,
a:focus {
color: #23527c;
}
}
li.selected {
@apply bg-white;
a {
@apply text-black;
}
}
}
}
.arco-tabs-content {
padding-top: 10px;
}
</style>

View File

@ -1,17 +1,17 @@
<template> <template>
<div class="edit-del-group"> <div class="menu-item">
<div class="edit menu-btn" :disabled="textDisabled" @click="edit"> <a-button
<i class="tab-icons" /> class="arco-btn-outline--secondary mb-[4px]"
<span> :disabled="removeNodeDisabled"
{{ t('minder.commons.edit') }} type="outline"
</span> size="small"
</div> @click="del"
<div class="del menu-btn" :disabled="removeNodeDisabled" @click="del"> >
<i class="tab-icons" /> <template #icon>
<span> <icon-minus />
{{ t('minder.commons.delete') }} </template>
</span> </a-button>
</div> {{ t('minder.commons.delete') }}
</div> </div>
</template> </template>
@ -21,14 +21,13 @@
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import { delProps } from '../../props'; import { delProps } from '../../props';
import { isDeleteDisableNode, isDisableNode } from '../../script/tool/utils'; import { isDeleteDisableNode } from '../../script/tool/utils';
const { t } = useI18n(); const { t } = useI18n();
const props = defineProps(delProps); const props = defineProps(delProps);
let minder = reactive<any>({}); let minder = reactive<any>({});
const textDisabled = ref(true);
const removeNodeDisabled = ref(true); const removeNodeDisabled = ref(true);
function checkDisabled() { function checkDisabled() {
@ -40,7 +39,6 @@
} }
const node = minder.getSelectedNode(); const node = minder.getSelectedNode();
removeNodeDisabled.value = !node || !!isDeleteDisableNode(minder) || node.parent === null; removeNodeDisabled.value = !node || !!isDeleteDisableNode(minder) || node.parent === null;
textDisabled.value = !node || !!isDisableNode(minder);
} }
onMounted(() => { onMounted(() => {
@ -52,26 +50,6 @@
}); });
}); });
function editNode() {
if (!minder.queryCommandValue) return;
const editor = window.minderEditor;
const receiverElement = editor.receiver.element;
const { fsm } = editor;
const { receiver } = editor;
receiverElement.innerText = minder.queryCommandValue('text');
fsm.jump('input', 'input-request');
receiver.selectAll();
}
function edit() {
if (textDisabled.value || !minder.queryCommandState) {
return;
}
if (minder.queryCommandState('text') !== -1) {
editNode();
}
}
function del() { function del() {
if (removeNodeDisabled.value || !minder.queryCommandState || !minder.execCommand) { if (removeNodeDisabled.value || !minder.queryCommandState || !minder.execCommand) {
return; return;

View File

@ -1,51 +1,97 @@
<template> <template>
<div class="menu-container"> <div class="menu-container">
<expand /> <div class="menu-group">
<selection /> <div class="menu-item">
<insert-box /> <a-button class="arco-btn-outline--secondary mb-[4px]" type="outline" size="small" @click="expand">
<move-box :move-enable="props.moveEnable" /> <template #icon>
<edit-del :del-confirm="props.delConfirm" /> <icon-plus />
<sequence-box </template>
v-if="props.sequenceEnable" </a-button>
:priority-prefix="props.priorityPrefix" {{ t('minder.menu.expand.expand') }}
:priority-count="props.priorityCount" </div>
:priority-disable-check="props.priorityDisableCheck" <div class="menu-item">
:priority-start-with-zero="props.priorityStartWithZero" <a-button class="arco-btn-outline--secondary mb-[4px]" type="outline" size="small" @click="folding">
/> <template #icon>
<progress-box v-if="props.progressEnable" /> <icon-minus />
<tag-box </template>
v-if="props.tagEnable" </a-button>
:tags="props.tags" {{ t('minder.menu.expand.folding') }}
:tag-disable-check="props.tagDisableCheck" </div>
:tag-edit-check="props.tagEditCheck" <move-box :move-enable="props.moveEnable" />
:distinct-tags="props.distinctTags" <insert-box />
/> <edit-del :del-confirm="props.delConfirm" />
</div>
<div class="menu-group">
<tag-box
v-if="props.tagEnable"
:tags="props.tags"
:tag-disable-check="props.tagDisableCheck"
:tag-edit-check="props.tagEditCheck"
:distinct-tags="props.distinctTags"
/>
</div>
<div class="menu-group">
<sequence-box
v-if="props.sequenceEnable"
:priority-prefix="props.priorityPrefix"
:priority-count="props.priorityCount"
:priority-disable-check="props.priorityDisableCheck"
:priority-start-with-zero="props.priorityStartWithZero"
/>
</div>
</div> </div>
</template> </template>
<script lang="ts" name="editMenu" setup> <script lang="ts" name="editMenu" setup>
import editDel from './editDel.vue'; import editDel from './editDel.vue';
import expand from './expand.vue';
import insertBox from './insertBox.vue'; import insertBox from './insertBox.vue';
import moveBox from './moveBox.vue'; import moveBox from './moveBox.vue';
import progressBox from './progressBox.vue';
import selection from './selection.vue';
import sequenceBox from './sequenceBox.vue'; import sequenceBox from './sequenceBox.vue';
import TagBox from './tagBox.vue'; import TagBox from './tagBox.vue';
import { useI18n } from '@/hooks/useI18n';
import { delProps, editMenuProps, priorityProps, tagProps } from '../../props'; import { delProps, editMenuProps, priorityProps, tagProps } from '../../props';
const props = defineProps({ ...editMenuProps, ...priorityProps, ...tagProps, ...delProps }); const props = defineProps({ ...editMenuProps, ...priorityProps, ...tagProps, ...delProps });
</script>
<style lang="less" scoped> const { t } = useI18n();
.menu-container {
height: 60px;
i {
@apply inline-block;
width: 20px; const hasSelectedNode = ref(false);
height: 20px; let minder = reactive<any>({});
onMounted(() => {
nextTick(() => {
minder = window.minder;
if (minder.on) {
minder.on('selectionchange', () => {
hasSelectedNode.value = Object.keys(minder).length > 0 && minder.getSelectedNode();
});
}
});
});
/**
* 展开
*/
function expand() {
const state = window.minder?.queryCommandState('Expand');
if (state === 0) {
//
window.minder?.execCommand('Expand');
} else {
window.minder?.execCommand('ExpandToLevel', 999);
} }
} }
</style>
/**
* 收起
*/
function folding() {
if (hasSelectedNode.value) {
window.minder?.execCommand('Collapse');
} else {
window.minder?.execCommand('ExpandToLevel', 1);
}
}
</script>

View File

@ -1,20 +1,7 @@
<template> <template>
<div class="expand-group"> <div class="expand-group">
<a-button class="tab-icons expand" type="text" @click="expandAll" /> <a-button class="tab-icons expand" type="text" @click="expand" />
<a-dropdown :popup-max-height="false" @select="handleCommand"> {{ t('minder.menu.expand.expand') }}
<span class="dropdown-link">
{{ t('minder.menu.expand.expand') }}
<icon-caret-down />
</span>
<template #content>
<a-doption value="1">{{ t('minder.menu.expand.expand_one') }}</a-doption>
<a-doption value="2">{{ t('minder.menu.expand.expand_tow') }}</a-doption>
<a-doption value="3">{{ t('minder.menu.expand.expand_three') }}</a-doption>
<a-doption value="4">{{ t('minder.menu.expand.expand_four') }}</a-doption>
<a-doption value="5">{{ t('minder.menu.expand.expand_five') }}</a-doption>
<a-doption value="6">{{ t('minder.menu.expand.expand_six') }}</a-doption>
</template>
</a-dropdown>
</div> </div>
</template> </template>
@ -23,12 +10,8 @@
const { t } = useI18n(); const { t } = useI18n();
function handleCommand(command: string | number | Record<string, any> | undefined) { function expand() {
window.minder?.execCommand('ExpandToLevel', command); window.minder?.execCommand('Expand', 9999);
}
function expandAll() {
window.minder?.execCommand('ExpandToLevel', 9999);
} }
</script> </script>

View File

@ -1,25 +1,23 @@
<template> <template>
<div class="insert-group"> <div class="menu-item">
<div class="insert-child-box menu-btn" :disabled="appendChildNodeDisabled" @click="execCommand('AppendChildNode')"> <a-dropdown @select="handleCommand">
<i class="tab-icons" /> <a-button
<span>{{ t('minder.menu.insert.down') }}</span> class="arco-btn-outline--secondary mb-[4px]"
</div> :disabled="appendChildNodeDisabled && appendParentNodeDisabled && appendSiblingNodeDisabled"
<div type="outline"
class="insert-parent-box menu-btn" size="small"
:disabled="appendParentNodeDisabled" >
@click="execCommand('AppendParentNode')" <template #icon>
> <icon-plus />
<i class="tab-icons" /> </template>
<span>{{ t('minder.menu.insert.up') }}</span> </a-button>
</div> <template #content>
<div <a-doption :disabled="appendChildNodeDisabled" value="down">{{ t('minder.menu.insert.down') }}</a-doption>
class="insert-sibling-box menu-btn" <a-doption :disabled="appendParentNodeDisabled" value="up">{{ t('minder.menu.insert.up') }}</a-doption>
:disabled="appendSiblingNodeDisabled" <a-doption :disabled="appendSiblingNodeDisabled" value="same">{{ t('minder.menu.insert.same') }}</a-doption>
@click="execCommand('AppendSiblingNode')" </template>
> </a-dropdown>
<i class="tab-icons" /> {{ t('minder.menu.insert.insert') }}
<span>{{ t('minder.menu.insert.same') }}</span>
</div>
</div> </div>
</template> </template>
@ -64,4 +62,20 @@
minder.value.execCommand(command); minder.value.execCommand(command);
} }
} }
function handleCommand(val: string | number | Record<string, any> | undefined) {
switch (val) {
case 'down':
execCommand('AppendChildNode');
break;
case 'up':
execCommand('AppendParentNode');
break;
case 'same':
execCommand('AppendSiblingNode');
break;
default:
break;
}
}
</script> </script>

View File

@ -1,13 +1,31 @@
<template> <template>
<div class="move-group"> <div class="menu-item">
<div class="move-up menu-btn" :disabled="arrangeUpDisabled" @click="execCommand('ArrangeUp')"> <a-button
<i class="tab-icons" /> class="arco-btn-outline--secondary mb-[4px]"
<span>{{ t('minder.menu.move.up') }}</span> :disabled="arrangeUpDisabled"
</div> type="outline"
<div class="move-down menu-btn" :disabled="arrangeDownDisabled" @click="execCommand('ArrangeDown')"> size="small"
<i class="tab-icons" /> @click="execCommand('ArrangeUp')"
<span>{{ t('minder.menu.move.down') }}</span> >
</div> <template #icon>
<icon-plus />
</template>
</a-button>
{{ t('minder.menu.move.up') }}
</div>
<div class="menu-item">
<a-button
class="arco-btn-outline--secondary mb-[4px]"
:disabled="arrangeDownDisabled"
type="outline"
size="small"
@click="execCommand('ArrangeDown')"
>
<template #icon>
<icon-plus />
</template>
</a-button>
{{ t('minder.menu.move.down') }}
</div> </div>
</template> </template>

View File

@ -1,6 +1,11 @@
<template> <template>
<div :disabled="commandDisabled"> <div class="flex items-center">
<a-button class="delete-btn !mx-[4px] !my-0 !h-[23px] !w-[23px] !p-[2px]" shape="circle" @click="execCommand()"> <a-button
:disabled="commandDisabled"
class="delete-btn !mx-[4px] !my-0 !h-[23px] !w-[23px] !p-[2px]"
shape="circle"
@click="execCommand()"
>
<template #icon> <template #icon>
<icon-delete /> <icon-delete />
</template> </template>
@ -9,6 +14,7 @@
<a-button <a-button
v-if="pIndex != 0" v-if="pIndex != 0"
:key="item" :key="item"
:disabled="commandDisabled"
class="priority-btn mr-[4px] h-[22px] w-[22px] rounded-[8px] pr-[5px] text-[12px]" class="priority-btn mr-[4px] h-[22px] w-[22px] rounded-[8px] pr-[5px] text-[12px]"
:class="'priority-btn_' + pIndex" :class="'priority-btn_' + pIndex"
size="small" size="small"
@ -98,7 +104,7 @@
border-bottom: 3px solid #840023; border-bottom: 3px solid #840023;
background-color: #ff1200; background-color: #ff1200;
} }
.priority-btn_1:hover { .priority-btn_1:hover:not(:disabled) {
border-bottom: 3px solid #840023; border-bottom: 3px solid #840023;
color: white; color: white;
background-color: #ff1200; background-color: #ff1200;
@ -107,7 +113,7 @@
border-bottom: 3px solid #01467f; border-bottom: 3px solid #01467f;
background-color: #0074ff; background-color: #0074ff;
} }
.priority-btn_2:hover { .priority-btn_2:hover:not(:disabled) {
border-bottom: 3px solid #01467f; border-bottom: 3px solid #01467f;
color: white; color: white;
background-color: #0074ff; background-color: #0074ff;
@ -116,7 +122,7 @@
border-bottom: 3px solid #006300; border-bottom: 3px solid #006300;
background-color: #00af00; background-color: #00af00;
} }
.priority-btn_3:hover { .priority-btn_3:hover:not(:disabled) {
border-bottom: 3px solid #006300; border-bottom: 3px solid #006300;
color: white; color: white;
background-color: #00af00; background-color: #00af00;
@ -125,7 +131,7 @@
border-bottom: 3px solid #b25000; border-bottom: 3px solid #b25000;
background-color: #ff962e; background-color: #ff962e;
} }
.priority-btn_4:hover { .priority-btn_4:hover:not(:disabled) {
border-bottom: 3px solid #b25000; border-bottom: 3px solid #b25000;
color: white; color: white;
background-color: #ff962e; background-color: #ff962e;
@ -134,7 +140,7 @@
border-bottom: 3px solid #4720c4; border-bottom: 3px solid #4720c4;
background-color: #a464ff; background-color: #a464ff;
} }
.priority-btn_5:hover { .priority-btn_5:hover:not(:disabled) {
border-bottom: 3px solid #4720c4; border-bottom: 3px solid #4720c4;
color: white; color: white;
background-color: #a464ff; background-color: #a464ff;
@ -143,7 +149,7 @@
border-bottom: 3px solid #515151; border-bottom: 3px solid #515151;
background-color: #a3a3a3; background-color: #a3a3a3;
} }
.priority-btn_6:hover { .priority-btn_6:hover:not(:disabled) {
border-bottom: 3px solid #515151; border-bottom: 3px solid #515151;
color: white; color: white;
background-color: #a3a3a3; background-color: #a3a3a3;

View File

@ -1,13 +1,14 @@
<template> <template>
<div :disabled="commandDisabled"> <div class="flex items-center">
<a-tag <a-tag
v-for="item in props.tags" v-for="item in props.tags"
:key="item" :key="item"
size="small"
:color="getResourceColor(item)" :color="getResourceColor(item)"
:class="commandDisabled ? 'disabledTag' : ''"
@click="editResource(item)" @click="editResource(item)"
>{{ item }}</a-tag
> >
{{ item }}
</a-tag>
</div> </div>
</template> </template>
@ -92,10 +93,10 @@
.arco-tag:first-child { .arco-tag:first-child {
margin-left: 4px; margin-left: 4px;
} }
.add-btn { .disabledTag {
padding: 0 !important; @apply !cursor-not-allowed;
width: 36px;
height: 24px; color: var(--color-text-4);
border-style: dashed !important; background-color: var(--color-secondary-disabled);
} }
</style> </style>

View File

@ -3,277 +3,19 @@
@apply h-full w-full; @apply h-full w-full;
.menu-container { .menu-container {
@apply flex; @apply flex;
& > div {
@apply inline-flex flex-wrap items-center overflow-hidden;
border-right: 1px dashed #eeeeee; height: 60px;
} .menu-group {
& > div:last-of-type { @apply flex;
@apply border-r-0;
}
}
.menu-btn {
@apply flex cursor-pointer items-center justify-center;
}
.menu-btn:not([disabled='true']):hover {
background-color: rgb(var(--primary-9));
}
.menu-btn[disabled='true'] {
opacity: 0.7;
}
.tab-icons {
@apply inline-flex;
width: 20px; padding: 4px 8px;
height: 20px; gap: 4px;
} &:not(:last-child) {
.do-group { border-right: 1px dashed #eeeeee;
@apply h-full;
padding: 0 5px;
width: 40px;
p {
@apply m-0 flex items-center justify-center;
height: 50%;
}
.undo i {
background-position: 0 -1240px;
}
.redo i {
background-position: 0 -1220px;
}
}
.insert-group {
width: 110px;
& > div {
margin: 0 5px;
}
.insert-sibling-box {
i {
background-position: 0 -20px;
} }
} .menu-item {
.insert-parent-box { @apply flex flex-col items-center justify-center;
i {
background-position: 0 -40px;
} }
} }
} }
.edit-del-group,
.move-group {
@apply flex items-center justify-center;
width: 70px;
}
.move-group {
.move-up {
i {
background-position: 0 -280px;
}
}
.move-down {
i {
background-position: 0 -300px;
}
}
}
.edit-del-group {
.edit {
i {
background-position: 0 -60px;
}
}
.del {
i {
background-position: 0 -80px;
}
}
}
.attachment-group {
@apply flex items-center justify-center;
width: 185px;
button {
@apply flex items-center justify-center border-none bg-transparent bg-no-repeat p-0 outline-none;
width: 45px;
height: 20px;
background-position: right;
span {
margin-left: 15px;
}
}
button:hover {
background-color: rgb(var(--primary-9));
}
& > div {
@apply flex h-full flex-wrap items-center justify-center;
width: 60px;
}
.insert {
@apply bg-no-repeat;
height: 25px;
}
.link {
.insert {
background-position: 50% -100px;
}
}
.img {
.insert {
background-position: 50% -125px;
}
}
.remark {
.insert {
background-position: 50% -1150px;
}
}
}
.progress-group,
.sequence-group {
@apply flex items-center justify-center;
width: 135px;
ul {
@apply m-0 list-none p-0;
width: 120px;
li {
@apply inline-block;
margin: 2px;
width: 20px;
height: 20px;
}
}
}
.sequence-group {
.loop(@i) when (@i >= 0) {
.sequence-@{i} {
background-position: 0 -20px * (-1 + @i);
}
.loop(@i - 1);
}
.loop(9);
}
.progress-group {
.loop(@i) when (@i >= 0) {
.progress-@{i} {
background-position: 0 -20px * (-1 + @i);
}
.loop(@i - 1);
}
.loop(9);
}
.arrange-group {
width: 65px;
.arrange {
@apply flex flex-wrap items-center justify-center;
}
.tab-icons {
@apply m-0 inline-block bg-no-repeat;
width: 25px;
height: 25px;
background-position: 0 -150px;
}
}
.style-group {
width: 150px;
.clear-style-btn {
@apply flex flex-wrap items-center justify-center;
width: 65px;
.tab-icons {
@apply m-0 inline-block bg-no-repeat;
width: 25px;
height: 25px;
background-position: 0 -175px;
}
}
.copy-paste-panel {
width: 70px;
.tab-icons {
@apply inline-block;
width: 20px;
height: 20px;
}
.copy-style {
.tab-icons {
background-position: 0 -200px;
}
}
.paste-style {
.tab-icons {
background-position: 0 -220px;
}
}
}
}
.font-group {
width: 250px;
* {
font-size: 12px;
}
.font-family-select {
width: 150px;
}
.font-size-select {
margin-left: 5px;
width: 80px;
}
.font-bold,
.font-italic {
@apply my-0 inline-block;
margin: 0 3px;
width: 20px;
height: 20px;
}
.font-bold {
background-position: 0 -242px;
}
.font-italic {
background-position: 0 -262px;
}
}
.expand-group,
.selection-group {
@apply flex items-center justify-center;
margin: 0 5px;
width: 60px;
button {
@apply border-none outline-none;
}
span {
font-size: 12px;
}
}
.expand-group {
.expand {
width: 40px;
height: 25px;
background-position: center -995px;
}
i {
font-size: 12px;
}
}
.selection-group {
.selection {
width: 40px;
height: 25px;
background-position: 7px -1175px;
}
i {
font-size: 12px;
}
}
} }

View File

@ -1,7 +1,7 @@
<template> <template>
<div <div
:class="`ms-button ms-button-${props.type} ms-button--${props.status} ${ :class="`ms-button ms-button-${props.type} ms-button--${props.status} ${
props.disabled || props.loading ? 'ms-button--disabled' : '' props.disabled || props.loading ? `ms-button--${props.status}--disabled` : ''
}`" }`"
@click="clickHandler" @click="clickHandler"
> >
@ -45,9 +45,13 @@
border-radius: var(--border-radius-mini); border-radius: var(--border-radius-mini);
line-height: 22px; line-height: 22px;
} }
.ms-button--disabled { .ms-button--primary--disabled {
color: var(--color-text-4) !important; color: var(--color-text-4) !important;
} }
.ms-button--danger--disabled {
color: rgb(var(--danger-2)) !important;
cursor: not-allowed;
}
.ms-button-text { .ms-button-text {
@apply p-0; @apply p-0;

View File

@ -440,7 +440,7 @@
return typeof props.rowClass === 'function' ? props.rowClass(record, rowIndex) : props.rowClass; return typeof props.rowClass === 'function' ? props.rowClass(record, rowIndex) : props.rowClass;
} }
if (!record.enable && !props.noDisable) { if (record.enable === false && !props.noDisable) {
return 'ms-table-row-disabled'; return 'ms-table-row-disabled';
} }
} }

View File

@ -0,0 +1,23 @@
// 项目版本公共信息
export interface ProjectCommon {
name: string;
description?: string;
status?: boolean;
publishTime?: number;
latest?: boolean;
projectId: string;
}
// 项目版本项
export interface ProjectItem extends ProjectCommon {
createTime: number;
createUser: string;
id: string;
}
// 项目版本选项列表
export interface ProjectVersionOption {
name: string;
id: string;
latest: boolean;
enable: boolean;
}

View File

@ -33,11 +33,13 @@
</div> </div>
</div> </div>
<FilterPanel v-show="isExpandFilter"></FilterPanel> <FilterPanel v-show="isExpandFilter"></FilterPanel>
<MinderEditor :tags="['模块', '用例', '前置条件', '备注', '步骤', '预期结果']" tag-enable sequence-enable />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { ref } from 'vue';
import MinderEditor from '@/components/pure/minder-editor/minderEditor.vue';
import MsTag from '@/components/pure/ms-tag/ms-tag.vue'; import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
import FilterPanel from '@/components/business/ms-filter-panel/searchForm.vue'; import FilterPanel from '@/components/business/ms-filter-panel/searchForm.vue';

View File

@ -1,169 +1,578 @@
<template> <template>
<div>项目版本 waiting for development </div> <a-spin v-if="!projectVersionStatus" :loading="loading" class="h-full w-full">
<MsFormCreate v-model:form-rule="formRules" :form-create-key="FormCreateKeyEnum.ORGANIZE_TEMPLATE" /> <div class="flex h-full flex-col items-center p-[24px]">
<br /> <div class="mt-[200px] text-[16px] font-medium text-[var(--color-text-1)]">
<br /> {{ t('project.projectVersion.version') }}
</div>
<div class="mt-[16px] text-[var(--color-text-4)]">{{ t('project.projectVersion.tip') }}</div>
<div class="mt-[24px] flex justify-between gap-[16px]">
<div class="tip-card">
<img src="@/assets/images/project_assign.png" width="78" height="60" class="tip-icon" />
<div>
<div class="tip-title">{{ t('project.projectVersion.assign') }}</div>
<div class="tip-sub-text">{{ t('project.projectVersion.assignTip') }}</div>
</div>
</div>
<div class="tip-card">
<img src="@/assets/images/project_filter.png" width="78" height="60" class="tip-icon" />
<div>
<div class="tip-title">{{ t('project.projectVersion.filter') }}</div>
<div class="tip-sub-text">{{ t('project.projectVersion.filterTip') }}</div>
</div>
</div>
<div class="tip-card">
<img src="@/assets/images/project_compare.png" width="78" height="60" class="tip-icon" />
<div>
<div class="tip-title">{{ t('project.projectVersion.compare') }}</div>
<div class="tip-sub-text">{{ t('project.projectVersion.compareTip') }}</div>
</div>
</div>
</div>
<div class="mt-[40px] flex justify-center">
<a-button type="outline" @click="() => openProjectVersion(true)">
{{ t('project.projectVersion.openVersion') }}
</a-button>
</div>
</div>
</a-spin>
<div v-if="projectVersionStatus">
<div class="flex justify-between">
<div>
<a-switch
v-model:model-value="projectVersionStatus"
size="small"
:before-change="(val) => openProjectVersion(val)"
>
</a-switch>
<span class="ml-[4px] font-medium">{{ t('project.projectVersion.version') }}</span>
</div>
<a-input-search
v-model:model-value="keyword"
:placeholder="t('project.projectVersion.searchPlaceholder')"
class="w-[230px]"
allow-clear
@search="searchVersion"
@press-enter="searchVersion"
/>
</div>
<MsBaseTable v-bind="propsRes" v-on="propsEvent">
<template #statusTitle>
<div class="flex items-center">
{{ t('project.projectVersion.status') }}
<a-popover :title="t('project.projectVersion.statusTip')" position="right">
<icon-info-circle class="ml-[4px] hover:text-[rgb(var(--primary-5))]" size="16" />
<template #content>
<div class="mt-[12px] w-[256px] rounded-[var(--border-radius-small)] bg-[var(--color-text-n9)] p-[12px]">
<div class="statusTipContent">
<div class="px-[8px] py-[4px] text-[14px] font-medium text-[var(--color-text-1)]">
{{ t('project.projectVersion.versionInfo') }}
</div>
<div
class="flex items-center rounded-[var(--border-radius-small)] bg-[rgb(var(--primary-1))] px-[8px] py-[4px] text-[14px] text-[rgb(var(--primary-6))]"
>
<div class="flex">
v4.0
<div class="ml-[4px] bg-[rgb(var(--primary-9))] px-[4px] text-[rgb(var(--primary-6))]">
{{ t('project.projectVersion.versionLatest') }}
</div>
</div>
<icon-check class="ml-auto text-[rgb(var(--primary-6))]" />
</div>
<div class="flex items-center px-[8px] py-[4px] text-[14px] text-[var(--color-text-1)]"> v3.0 </div>
<div class="flex items-center px-[8px] py-[4px] text-[14px] text-[var(--color-text-1)]"> v2.0 </div>
<div class="flex items-center px-[8px] py-[4px] text-[14px] text-[var(--color-text-1)]"> v1.0 </div>
</div>
</div>
</template>
</a-popover>
</div>
</template>
<template #quickCreate>
<a-form
v-if="showQuickCreateForm"
ref="quickCreateFormRef"
:model="quickCreateForm"
layout="inline"
size="small"
class="flex items-center"
>
<a-form-item
field="name"
:rules="[{ required: true, message: t('project.projectVersion.versionNameRequired') }]"
no-style
>
<a-input
v-model:model-value="quickCreateForm.name"
:placeholder="t('project.projectVersion.versionNamePlaceholder')"
class="w-[262px]"
/>
</a-form-item>
<a-form-item field="publishTime" no-style>
<a-date-picker
v-model:model-value="quickCreateForm.publishTime"
:placeholder="t('project.projectVersion.publishTimePlaceholder')"
show-time
class="ml-[8px] w-[262px]"
/>
</a-form-item>
<a-form-item no-style>
<a-button type="outline" size="mini" class="ml-[12px] mr-[8px] px-[8px]" @click="quickCreateConfirm">
{{ t('common.confirm') }}
</a-button>
<a-button
type="outline"
class="arco-btn-outline--secondary px-[8px]"
size="mini"
@click="quickCreateCancel"
>
{{ t('common.cancel') }}
</a-button>
</a-form-item>
</a-form>
<MsButton v-else @click="showQuickCreateForm = true">
<MsIcon type="icon-icon_add_outlined" size="14" class="mr-[8px]" />
{{ t('project.projectVersion.quickCreate') }}
</MsButton>
</template>
<template #status="{ record }">
<a-switch
v-model:model-value="record.status"
size="small"
:before-change="(val) => handleStatusChange(val, record)"
></a-switch>
</template>
<template #latest="{ record }">
<a-switch
v-model:model-value="record.latest"
:disabled="record.latest"
:before-change="() => handleUseLatestVersionChange(record)"
size="small"
/>
</template>
<template #action="{ record }">
<a-tooltip :content="t('project.projectVersion.latestVersionDeleteTip')" :disabled="!record.latest">
<MsButton
type="text"
:loading="delLoading"
:disabled="record.latest"
status="danger"
size="small"
@click="delVersion(record)"
>
{{ t('common.delete') }}
</MsButton>
</a-tooltip>
</template>
</MsBaseTable>
<a-modal
v-model:visible="latestModalVisible"
title="Modal Form"
:on-before-ok="handleBeforeLatestModalOk"
class="p-[4px]"
title-align="start"
body-class="px-0 py-[8px]"
:ok-text="t('common.confirmClose')"
:ok-button-props="{ status: 'danger' }"
@cancel="handleLatestModalCancel"
>
<template #title>
<div class="flex items-center justify-start">
<icon-exclamation-circle-fill size="20" class="mr-[8px] text-[rgb(var(--danger-6))]" />
<div class="text-[var(--color-text-1)]">
{{ t('project.projectVersion.confirmCloseTitle', { name: activeRecord.name }) }}
</div>
</div>
</template>
<div>
<div>{{ t('project.projectVersion.confirmCloseTipContent1') }}</div>
<div>{{ t('project.projectVersion.confirmCloseTipContent2') }}</div>
<a-select
v-model:model-value="replaceVersion"
class="mt-[10px]"
:placeholder="t('project.projectVersion.replaceVersionPlaceholder')"
:options="
versionOptions
.filter((e) => e.id !== activeRecord.id)
.map((e) => ({ ...e, disabled: !e.enable, value: e.id, label: e.name }))
"
/>
</div>
</a-modal>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { FormInstance, Message } from '@arco-design/web-vue';
import dayjs from 'dayjs';
import MsFormCreate from '@/components/pure/ms-form-create/form-create.vue'; import MsButton from '@/components/pure/ms-button/index.vue';
import type { FormItem } from '@/components/pure/ms-form-create/types'; import MsIcon from '@/components/pure/ms-icon-font/index.vue';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import type { MsTableColumn } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable';
import { FormCreateKeyEnum } from '@/enums/formCreateEnum'; import {
addVersion,
deleteVersion,
getVersionList,
getVersionOptions,
getVersionStatus,
toggleVersion,
toggleVersionStatus,
updateVersion,
useLatestVersion,
} from '@/api/modules/project-management/projectVersion';
import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal';
import useAppStore from '@/store/modules/app';
const formRules = ref<FormItem[]>([ import { ProjectItem, ProjectVersionOption } from '@/models/projectManagement/projectVersion';
{ import { ColumnEditTypeEnum } from '@/enums/tableEnum';
type: 'SELECT',
name: 'name',
label: '姓名',
value: '',
subDesc: '请输入姓名',
required: true,
options: [
{
value: '1001',
text: '单选',
},
{
value: '1002',
text: '多选',
},
],
},
{
type: 'MULTIPLE_SELECT',
name: 'gender',
label: '性别',
value: [],
subDesc: '请选择性别',
optionMethod: 'getGenderOptions',
inputSearch: true,
required: true,
couplingConfig: {
type: 'initOptions',
cascade: 'name',
matchRule: 'includes',
},
options: [ const { t } = useI18n();
{ const appStore = useAppStore();
value: '1', const { openModal } = useModal();
text: '单选',
},
{
value: '2',
text: '多选',
},
],
},
{
type: 'TEXTAREA',
name: 'member',
label: '成员',
value: '',
required: true,
},
{
type: 'MULTIPLE_MEMBER',
name: 'multiple_member',
label: '多选成员',
value: [],
required: true,
options: [
{
value: '1',
text: '单选',
},
{
value: '2',
text: '多选',
},
],
},
{
type: 'INT',
name: 'birthday1',
label: '出生日期',
value: 0,
subDesc: '请选择出生日期',
required: true,
},
{
type: 'DATE',
name: 'birthday',
label: '出生日期',
value: '',
subDesc: '请选择出生日期',
required: true,
},
{
type: 'MULTIPLE_MEMBER',
name: 'radio',
label: '单选',
value: '',
subDesc: '请选择出生日期',
inputSearch: true,
required: true,
options: [
{
value: '1',
text: '单选',
},
{
value: '2',
text: '多选',
},
],
couplingConfig: {
type: 'initOptions',
cascade: 'member',
matchRule: 'includes',
},
},
{
type: 'SELECT',
name: 'selectName',
label: '单选',
value: '',
subDesc: '请选择出生日期',
inputSearch: true,
required: true,
options: [
{
value: '1',
text: '单选',
},
{
value: '2',
text: '多选',
},
],
couplingConfig: {
type: 'initOptions',
cascade: 'member',
matchRule: 'includes',
},
},
]);
const options = ref({ const loading = ref(false);
resetBtn: false, const projectVersionStatus = ref(false);
submitBtn: false,
on: false, async function getProjectVersionStatus() {
form: { try {
layout: 'vertical', loading.value = true;
labelAlign: 'left', const res = await getVersionStatus(appStore.currentProjectId);
}, projectVersionStatus.value = res;
row: { } catch (error) {
gutter: 0, // eslint-disable-next-line no-console
}, console.log(error);
wrap: { } finally {
'asterisk-position': 'end', loading.value = false;
'validate-trigger': ['change'], }
}, }
/**
* 切换项目版本开关
* @param val 开关
*/
async function openProjectVersion(val?: string | number | boolean) {
try {
loading.value = true;
await toggleVersion(appStore.currentProjectId);
Message.success(!val ? t('common.closeSuccess') : t('project.projectVersion.openVersionSuccess'));
return true;
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
return false;
} finally {
loading.value = false;
await getProjectVersionStatus();
}
}
onBeforeMount(() => {
getProjectVersionStatus();
}); });
/**
* 更新版本名称
* @param record 当前行数据
*/
async function updateVersionName(record: ProjectItem) {
try {
await updateVersion({
...record,
publishTime: dayjs(record.publishTime).valueOf(),
createTime: dayjs(record.createTime).valueOf(),
});
Message.success(t('common.updateSuccess'));
return Promise.resolve(true);
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
return Promise.resolve(false);
}
}
const keyword = ref('');
const columns: MsTableColumn = [
{
title: 'project.projectVersion.versionName',
dataIndex: 'name',
showTooltip: true,
editType: ColumnEditTypeEnum.INPUT,
width: 150,
},
{
title: 'project.projectVersion.status',
dataIndex: 'status',
slotName: 'status',
titleSlotName: 'statusTitle',
width: 80,
},
{
title: 'project.projectVersion.latest',
dataIndex: 'latest',
slotName: 'latest',
width: 80,
},
{
title: 'project.projectVersion.publishTime',
dataIndex: 'publishTime',
sortable: {
sortDirections: ['ascend', 'descend'],
},
width: 180,
},
{
title: 'project.projectVersion.createTime',
dataIndex: 'createTime',
sortable: {
sortDirections: ['ascend', 'descend'],
},
width: 180,
},
{
title: 'project.projectVersion.creator',
dataIndex: 'createUser',
},
{
title: 'common.operation',
fixed: 'right',
slotName: 'action',
dataIndex: 'operation',
width: 80,
},
];
const { propsRes, propsEvent, loadList, setKeyword, setLoadListParams } = useTable(
getVersionList,
{
columns,
size: 'default',
},
(item) => {
return {
...item,
publishTime: item.publishTime ? dayjs(item.publishTime).format('YYYY-MM-DD HH:mm:ss') : '',
};
},
updateVersionName
);
function searchVersion() {
setKeyword(keyword.value);
loadList();
}
onBeforeMount(async () => {
setLoadListParams({
projectId: appStore.currentProjectId,
});
searchVersion();
});
const showQuickCreateForm = ref(false);
const quickCreateFormRef = ref<FormInstance>();
const quickCreateForm = ref({
name: '',
publishTime: '',
});
const quickCreateLoading = ref(false);
function quickCreateCancel() {
showQuickCreateForm.value = false;
quickCreateForm.value = {
name: '',
publishTime: '',
};
quickCreateFormRef.value?.resetFields();
}
/**
* 快速创建版本
*/
function quickCreateConfirm() {
quickCreateFormRef.value?.validate(async (errors) => {
if (!errors) {
try {
quickCreateLoading.value = true;
await addVersion({
...quickCreateForm.value,
projectId: appStore.currentProjectId,
publishTime: quickCreateForm.value.publishTime
? dayjs(quickCreateForm.value.publishTime).valueOf()
: undefined,
latest: false,
status: false,
});
Message.success(t('common.createSuccess'));
quickCreateCancel();
loadList();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
quickCreateLoading.value = false;
}
}
});
}
const latestModalVisible = ref(false);
const activeRecord = ref<ProjectItem>({
id: '',
name: '',
latest: false,
status: false,
publishTime: 0,
createTime: 0,
createUser: '',
projectId: '',
});
const replaceVersion = ref('');
const versionOptions = ref<ProjectVersionOption[]>([]);
function handleLatestModalCancel() {
latestModalVisible.value = false;
replaceVersion.value = '';
}
/**
* 拦截切换最新版确认
* @param done 关闭弹窗
*/
async function handleBeforeLatestModalOk(done: (closed: boolean) => void) {
try {
if (replaceVersion.value !== '') {
await useLatestVersion(replaceVersion.value);
}
await toggleVersionStatus(activeRecord.value.id);
Message.success(t('project.projectVersion.close', { name: activeRecord.value.name }));
loadList();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
done(false);
} finally {
done(true);
}
}
/**
* 拦截切换最新版
* @param record 当前行数据
*/
async function handleUseLatestVersionChange(record: ProjectItem) {
try {
await useLatestVersion(record.id);
Message.success(t('project.projectVersion.switchLatestSuccess', { name: record.name }));
loadList();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
return false;
}
}
/**
* 拦截切换状态
* @param val 开关
* @param type 状态类型
* @param record 当前行数据
*/
async function handleStatusChange(val: string | number | boolean, record: ProjectItem) {
try {
if (!val && record.latest) {
//
const res = await getVersionOptions(appStore.currentProjectId);
versionOptions.value = res;
latestModalVisible.value = true;
activeRecord.value = record;
return false;
}
if (!val) {
//
openModal({
type: 'error',
title: t('project.projectVersion.confirmCloseTitle', { name: record.name }),
content: t('project.projectVersion.confirmCloseTip'),
okText: t('common.confirmClose'),
cancelText: t('common.cancel'),
okButtonProps: {
status: 'danger',
},
onBeforeOk: async () => {
try {
await toggleVersionStatus(record.id);
Message.success(t('project.projectVersion.close', { name: record.name }));
loadList();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
},
hideCancel: false,
});
} else {
await toggleVersionStatus(record.id);
Message.success(t('project.projectVersion.open', { name: record.name }));
loadList();
}
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
return false;
}
}
const delLoading = ref(false);
async function delVersion(record: ProjectItem) {
try {
delLoading.value = true;
await deleteVersion(record.id);
Message.success(t('common.deleteSuccess'));
loadList();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
delLoading.value = false;
}
}
</script> </script>
<style scoped></style> <style lang="less" scoped>
.tip-card {
@apply flex;
gap: 12px;
padding: 16px;
border-radius: var(--border-radius-medium);
background-color: var(--color-text-n9);
.tip-icon {
box-shadow: 0 4px 10px -1px rgb(100 100 102 / 15%);
}
.tip-title {
@apply font-medium;
color: var(--color-text-1);
}
.tip-sub-text {
margin-top: 4px;
font-size: 12px;
color: var(--color-text-4);
}
}
.statusTipContent {
@apply flex flex-col;
padding: 6px;
border: 0.5px solid rgb(212 212 216 / 100%);
border-radius: var(--border-radius-medium);
background: white;
box-shadow: 0 5px 5px -3px rgb(0 0 0 / 10%), 0 8px 10px 1px rgb(0 0 0 / 6%), 0 3px 14px 2px rgb(0 0 0 / 5%);
gap: 2px;
}
</style>

View File

@ -0,0 +1,37 @@
export default {
'project.projectVersion.version': 'Project version',
'project.projectVersion.tip':
'Project version management is mainly divided into file management and use case management to ensure the traceability of project files during the project process.',
'project.projectVersion.assign': 'Version designation',
'project.projectVersion.assignTip':
'You can specify that the content of a certain change in the resource is the content of the specified version number.',
'project.projectVersion.compare': 'Version comparison',
'project.projectVersion.compareTip':
'The resource details page provides version switching and version comparison functions.',
'project.projectVersion.filter': 'Version filter',
'project.projectVersion.filterTip': 'Added version display column and version filtering function to resource list',
'project.projectVersion.openVersion': 'Enable project version',
'project.projectVersion.openVersionSuccess': 'Activated successfully',
'project.projectVersion.versionName': 'Version name',
'project.projectVersion.status': 'Status',
'project.projectVersion.latest': 'Latest version',
'project.projectVersion.publishTime': 'Release time',
'project.projectVersion.createTime': 'Creation time',
'project.projectVersion.creator': 'Creator',
'project.projectVersion.searchPlaceholder': 'Search by ID/name',
'project.projectVersion.quickCreate': 'Quickly create versions',
'project.projectVersion.versionNamePlaceholder': 'Please enter version name',
'project.projectVersion.versionNameRequired': 'Version name cannot be empty',
'project.projectVersion.publishTimePlaceholder': 'Please select a release date',
'project.projectVersion.open': '{name} is turned on',
'project.projectVersion.close': '{name} is closed',
'project.projectVersion.switchLatestSuccess': 'The latest version has been switched to {name}',
'project.projectVersion.confirmCloseTitle': 'Are you sure you want to close {name}?',
'project.projectVersion.confirmCloseTip':
'After closing, the resource list will not display the data of this version, please operate with caution!',
'project.projectVersion.confirmCloseTipContent1':
'It is currently the latest version. After closing, the default display data of the list will be empty;',
'project.projectVersion.confirmCloseTipContent2': 'You can switch other versions to the latest version',
'project.projectVersion.replaceVersionPlaceholder': 'Please select an alternative version',
'project.projectVersion.latestVersionDeleteTip': 'The latest version cannot be deleted',
};

View File

@ -0,0 +1,35 @@
export default {
'project.projectVersion.version': '项目版本',
'project.projectVersion.tip': '项目版本管理主要分为文件管理和用例管理,保证项目文件在项目过程中可追溯性',
'project.projectVersion.assign': '版本指定',
'project.projectVersion.assignTip': '可指定资源的某一次变更内容为指定版本号的内容',
'project.projectVersion.compare': '版本对比',
'project.projectVersion.compareTip': '资源详情页提供版本切换和版本对比的功能',
'project.projectVersion.filter': '版本筛选',
'project.projectVersion.filterTip': '资源列表处增加版本展示列和版本过滤功能',
'project.projectVersion.openVersion': '启用项目版本',
'project.projectVersion.openVersionSuccess': '启用成功',
'project.projectVersion.versionName': '版本名称',
'project.projectVersion.status': '状态',
'project.projectVersion.latest': '最新版',
'project.projectVersion.publishTime': '发布时间',
'project.projectVersion.createTime': '创建时间',
'project.projectVersion.creator': '创建人',
'project.projectVersion.searchPlaceholder': '通过ID/名称搜索',
'project.projectVersion.quickCreate': '快速创建版本',
'project.projectVersion.versionNamePlaceholder': '请输入版本名称',
'project.projectVersion.versionNameRequired': '版本名称不能为空',
'project.projectVersion.publishTimePlaceholder': '请选择发布日期',
'project.projectVersion.open': '{name} 已开启',
'project.projectVersion.close': '{name} 已关闭',
'project.projectVersion.switchLatestSuccess': '最新版已切换为 {name}',
'project.projectVersion.confirmCloseTitle': '确认关闭 {name} 吗?',
'project.projectVersion.confirmCloseTip': '关闭后,资源列表将不展示该版本的数据,请谨慎操作!',
'project.projectVersion.confirmCloseTipContent1': '当前为最新版本,关闭后,会导致列表默认展示数据为空;',
'project.projectVersion.confirmCloseTipContent2': '可切换其他版本为最新版本',
'project.projectVersion.replaceVersionPlaceholder': '请选择替换版本',
'project.projectVersion.latestVersionDeleteTip': '最新版本不可删除',
'project.projectVersion.statusTip': '关闭后在版本信息下拉框则不显示',
'project.projectVersion.versionInfo': '版本信息示例',
'project.projectVersion.versionLatest': '最新版本',
};