finish work

This commit is contained in:
锦恢 2025-07-02 04:56:41 +08:00
parent 27c3f24089
commit a735bbf023
13 changed files with 747 additions and 485 deletions

View File

@ -3,6 +3,15 @@
--main-color: #CB81DA;
--main-dark-color: #2D323B;
--main-light-color: rgba(203, 129, 218, 0.7);
--main-light-color-90: rgba(203, 129, 218, 0.9);
--main-light-color-80: rgba(203, 129, 218, 0.8);
--main-light-color-70: rgba(203, 129, 218, 0.7);
--main-light-color-60: rgba(203, 129, 218, 0.6);
--main-light-color-50: rgba(203, 129, 218, 0.5);
--main-light-color-40: rgba(203, 129, 218, 0.4);
--main-light-color-30: rgba(203, 129, 218, 0.3);
--main-light-color-20: rgba(203, 129, 218, 0.2);
--main-light-color-10: rgba(203, 129, 218, 0.1);
--sidebar-width: 330px;
--right-nav-width: 50px;
--time-scale-height: 30px;

View File

@ -73,6 +73,6 @@ const onRadioGroupChange = () => {
}
.setting-button:active {
transform: scale(1.1);
transform: scale(0.95);
}
</style>

View File

@ -3,29 +3,18 @@
<div class="tabs-container">
<el-scrollbar>
<div class="scroll-tabs-container">
<span
class="tab"
v-for="(tab, index) of tabs.content"
:key="tab.id"
:class="{ 'active-tab': tabs.activeIndex === index }"
@click="setActiveTab(index)"
>
<span class="tab" v-for="(tab, index) of tabs.content" :key="tab.id"
:class="{ 'active-tab': tabs.activeIndex === index }" @click="setActiveTab(index)">
<span>
<span :class="`iconfont ${tab.icon}`"></span>
<span class="tab-name">{{ tab.name }}</span>
</span>
<span
class="iconfont icon-close"
@click.stop="closeTab(index)"
></span>
<span class="iconfont icon-close" @click.stop="closeTab(index)"></span>
</span>
</div>
</el-scrollbar>
<span
class="add-button iconfont icon-add"
@click="pageAddNewTab"
>
<span class="add-button iconfont icon-add" @click="pageAddNewTab">
</span>
</div>
@ -122,7 +111,7 @@ function setActiveTab(index: number) {
}
.tabs-container .tab:active {
transform: scale(1.05);
transform: scale(0.95);
transition: var(--animation-3s);
}

View File

@ -140,6 +140,11 @@ onMounted(async () => {
transition: var(--animation-3s);
}
.prompt-template-container>.item:active {
transform: scale(0.95);
transition: var(--animation-3s);
}
.prompt-template-container>.item.active {
background-color: var(--main-light-color);
transition: var(--animation-3s);

View File

@ -157,6 +157,11 @@ h3.resource-template .iconfont.icon-restart:hover {
transition: var(--animation-3s);
}
.resource-template-container > .item:active {
transform: scale(0.95);
transition: var(--animation-3s);
}
.resource-template-container > .item.active {
background-color: var(--main-light-color);
transition: var(--animation-3s);

View File

@ -167,6 +167,11 @@ h3.resource-template .iconfont.icon-restart:hover {
transition: var(--animation-3s);
}
.resource-template-container > .item:active {
transform: scale(0.95);
transition: var(--animation-3s);
}
.resource-title {
font-weight: bold;
max-width: 250px;

View File

@ -4,14 +4,18 @@
<div style="display: flex; align-items: center;">
<span>Tool Diagram</span>
&ensp;
<el-button size="small" type="primary" @click="() => {}">重置</el-button>
<el-button size="small" type="primary" @click="() => {}">开启自检程序</el-button>
<el-button size="small" type="primary" @click="() => context.reset()">重置</el-button>
<el-button size="small" type="primary" @click="() => startTest()">开启自检程序</el-button>
</div>
</template>
<el-scrollbar height="80vh">
<!-- <Diagram /> -->
<SwimPool />
<Diagram />
</el-scrollbar>
<transition name="main-fade" mode="out-in">
<div class="caption" v-show="context.caption.value">
{{ context.caption }}
</div>
</transition>
</el-dialog>
<!-- <el-button @click="showDiagram = true" type="primary" style="margin-bottom: 16px;">
Show Tool Diagram
@ -19,11 +23,21 @@
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { provide, ref } from 'vue';
import Diagram from './diagram.vue';
import SwimPool from './swim-pool.vue';
const showDiagram = ref(true);
const context = {
reset: () => {},
caption: ref('')
};
provide('context', context);
function startTest() {
}
</script>
<style>
@ -31,4 +45,23 @@ const showDiagram = ref(true);
margin-top: 30px !important;
}
.no-padding-dialog .caption {
position: absolute;
left: 20px;
bottom: 10px;
margin: 0 auto;
width: fit-content;
min-height: 32px;
background: rgba(245, 247, 250, 0.05);
border-radius: 8px;
box-shadow: 0 2px 8px 0 rgba(0,0,0,0.06);
color: var(--main-color);
font-size: 15px;
display: flex;
align-items: center;
justify-content: center;
padding: 6px 16px;
z-index: 10;
transition: background 0.2s;
}
</style>

View File

@ -5,7 +5,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, nextTick, reactive } from 'vue';
import { ref, onMounted, nextTick, reactive, inject } from 'vue';
import * as d3 from 'd3';
import ELK, { type ElkNode } from 'elkjs/lib/elk.bundled.js';
import { mcpClientAdapter } from '@/views/connect/core';
@ -195,7 +195,7 @@ function renderSvg() {
.attr('y1', d => d.section.startPoint.y + 30)
.attr('x2', d => d.section.endPoint.x + 30)
.attr('y2', d => d.section.endPoint.y + 30)
.attr('opacity', 1); // update opacity 1
.attr('opacity', 1);
// --- ---
const nodeGroup = svg.selectAll<SVGGElement, any>('.node')
@ -220,6 +220,15 @@ function renderSvg() {
.on('mouseup', function (event, d) {
event.stopPropagation();
if (state.selectedNodeId && state.selectedNodeId !== d.id) {
// 线
const exists = state.edges.some(
e =>
Array.isArray(e.sources) &&
Array.isArray(e.targets) &&
e.sources[0] === state.selectedNodeId &&
e.targets[0] === d.id
);
if (!exists) {
state.edges.push({
id: `e${state.selectedNodeId}_${d.id}_${Date.now()}`,
sources: [state.selectedNodeId],
@ -228,19 +237,43 @@ function renderSvg() {
state.selectedNodeId = null;
recomputeLayout().then(renderSvg);
} else {
state.selectedNodeId = d.id;
//
state.selectedNodeId = null;
renderSvg();
}
context.caption.value = '';
} else {
state.selectedNodeId = d.id;
renderSvg();
context.caption.value = '选择另一个节点以构建顺序';
}
state.draggingNodeId = null;
})
.on('mouseover', function (event, d) {
d3.select(this).select('rect')
.transition()
.duration(200)
.attr('stroke', 'var(--main-color)')
.attr('stroke-width', 2);
})
.on('mouseout', function (event, d) {
if (state.selectedNodeId === d.id) {
return;
}
d3.select(this).select('rect')
.transition()
.duration(200)
.attr('stroke', 'var(--main-light-color-10)')
.attr('stroke-width', 1);
});
nodeGroupEnter.append('rect')
.attr('width', d => d.width)
.attr('height', d => d.height)
.attr('rx', 16)
.attr('fill', 'var(--main-color)')
.attr('opacity', d => state.selectedNodeId === d.id ? 0.25 : 0.12)
.attr('stroke', 'var(--main-color)')
.attr('fill', 'var(--main-light-color-20)')
.attr('stroke', d => state.selectedNodeId === d.id ? 'var(--main-color)' : 'var(--main-light-color-10)')
.attr('stroke-width', 2);
nodeGroupEnter.append('text')
@ -270,10 +303,47 @@ function renderSvg() {
nodeGroup.select('rect')
.transition()
.duration(400)
.attr('opacity', d => state.selectedNodeId === d.id ? 0.55 : 0.12)
.attr('stroke-width', d => state.selectedNodeId === d.id ? 4 : 2)
.attr('stroke', d => state.selectedNodeId === d.id ? 'var(--main-color)' : 'var(--main-color)')
.attr('fill', d => state.selectedNodeId === d.id ? 'var(--main-color)' : 'var(--main-color)');
.attr('stroke-width', d => state.selectedNodeId === d.id ? 2 : 1)
.attr('stroke', d => state.selectedNodeId === d.id ? 'var(--main-color)' : 'var(--main-light-color-10)');
//
svg.selectAll<SVGLineElement, any>('.edge')
.on('mouseover', function () {
d3.select(this)
.transition()
.duration(200)
.attr('stroke', 'var(--main-color)')
.attr('stroke-width', 4.5);
context.caption.value = '点击边以删除';
})
.on('mouseout', function () {
d3.select(this)
.transition()
.duration(200)
.attr('stroke', 'var(--main-color)')
.attr('stroke-width', 2.5);
context.caption.value = '';
})
.on('click', function (event, d) {
// edge
state.edges = state.edges.filter(e => {
// edge
if (e.sections) {
// section
return !e.sections.some((section: any, idx: number) =>
((e.id || '') + '-' + (section.id || idx)) === d.id
);
}
// edge
return e.id !== d.id && e.id !== d.section?.id;
});
recomputeLayout().then(renderSvg);
event.stopPropagation();
});
//
prevNodes = state.nodes.map(n => ({ ...n }));
@ -297,6 +367,9 @@ function resetConnections() {
recomputeLayout().then(renderSvg);
}
const context = inject('context') as any;
context.reset = resetConnections;
onMounted(() => {
nextTick(drawDiagram);
});

View File

@ -296,7 +296,7 @@ watch(() => tabStorage.currentToolName, () => {
}
.el-button:active {
transform: scale(1.05);
transform: scale(0.95);
transition: transform 0.08s;
}
</style>

View File

@ -128,6 +128,11 @@ onMounted(async () => {
transition: var(--animation-3s);
}
.tool-list-container>.item:active {
transform: scale(0.95);
transition: var(--animation-3s);
}
.tool-list-container>.item:hover {
background-color: var(--main-light-color);
transition: var(--animation-3s);

View File

@ -108,6 +108,7 @@ function chooseDebugMode(index: number) {
.welcome-container > span {
flex: 1 1 calc(50% - 100px);
box-sizing: border-box;
transition: .3s transform ease-in-out;
}
.debug-option {

View File

@ -32,6 +32,11 @@ export function onGeneralColorChange(colorString: string) {
document?.documentElement.style.setProperty(
'--main-light-color', `rgba(${r}, ${g}, ${b}, 0.7)`);
for (let i = 1; i <= 9; ++ i) {
document?.documentElement.style.setProperty(
`--main-light-color-${i}0`, `rgba(${r}, ${g}, ${b}, 0.${i})`);
}
}
export const predefinedColors = [

878
yarn.lock

File diff suppressed because it is too large Load Diff