feat:rename subtree from frontend-vue to frontend

This commit is contained in:
zhaoweijie
2025-11-20 09:56:51 +08:00
parent 1aa9e280b0
commit ab8c9e294d
80 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,141 @@
<script setup lang="ts">
import { getActionTypeDisplay, getAgentMapIcon } from '@/layout/components/config.ts'
import SvgIcon from '@/components/SvgIcon/index.vue'
import { type Agent, useAgentsStore } from '@/stores'
import { v4 as uuidv4 } from 'uuid'
const porps = defineProps<{
agentList: Agent[]
}>()
const taskProcess = computed(() => {
const list = agentsStore.currentTask?.TaskProcess ?? []
return list.map((item) => ({
...item,
key: uuidv4(),
}))
})
const agentsStore = useAgentsStore()
</script>
<template>
<div
v-for="item in porps.agentList"
:key="item.Name"
class="user-item"
:class="agentsStore.currentTask?.AgentSelection?.includes(item.Name) ? 'active-card' : ''"
>
<div class="flex items-center justify-between relative h-[41px]">
<div
class="w-[44px] h-[44px] rounded-full flex items-center justify-center flex-shrink-0 relative right-[2px] icon-container"
:style="{ background: getAgentMapIcon(item.Name).color }"
>
<svg-icon
:icon-class="getAgentMapIcon(item.Name).icon"
color="var(--color-text)"
size="24px"
/>
</div>
<div class="flex-1 text-[14px] flex flex-col items-end justify-end truncate ml-1">
<span
class="w-full truncate text-right"
:style="
agentsStore.currentTask?.AgentSelection?.includes(item.Name) ? 'color:#00F3FF' : ''
"
>{{ item.Name }}</span
>
<div
v-if="agentsStore.currentTask?.AgentSelection?.includes(item.Name)"
class="flex items-center gap-[7px] h-[8px] mr-1"
>
<!-- 小圆点 -->
<div
v-for="item1 in taskProcess.filter((i) => i.AgentName === item.Name)"
:key="item1.key"
class="w-[6px] h-[6px] rounded-full"
:style="{ background: getActionTypeDisplay(item1.ActionType)?.color }"
></div>
</div>
</div>
</div>
<!-- 职责信息只有当执行流程中有当前智能体并且鼠标移入时才显示 -->
<div class="duty-info">
<div class="w-full flex justify-center">
<div
class="rounded-[9px] bg-[var(--color-bg-quaternary)] text-[12px] py-0.5 px-5 text-center my-2"
>
当前职责
</div>
</div>
<div class="p-[8px] pt-0">
<div
v-for="(item1, index1) in taskProcess.filter((i) => i.AgentName === item.Name)"
:key="item1.key"
class="text-[12px]"
>
<div>
<div class="mx-1 inline-block h-[14px]">
<div
:style="{ background: getActionTypeDisplay(item1.ActionType)?.color }"
class="w-[6px] h-[6px] rounded-full mt-[7px]"
></div>
</div>
<span :style="{ color: getActionTypeDisplay(item1.ActionType)?.color }"
>{{ getActionTypeDisplay(item1.ActionType)?.name }}</span
>
<span>{{ item1.Description }}</span>
</div>
<!-- 分割线 -->
<div
v-if="index1 !== taskProcess.filter((i) => i.AgentName === item.Name).length - 1"
class="h-[1px] w-full bg-[#494B51] my-[8px]"
></div>
</div>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.user-item {
background: #1d222b;
border-radius: 40px;
padding-right: 12px;
cursor: pointer;
transition: all 0.25s ease;
color: #969696;
border: 2px solid transparent;
.duty-info {
transition: height 0.25s ease;
height: 0;
overflow: hidden;
}
& + .user-item {
margin-top: 8px;
}
&:hover {
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.2);
color: #b8b8b8;
}
}
.active-card {
background:
linear-gradient(#171B22, #171B22) padding-box,
linear-gradient(to right, #00c8d2, #315ab4) border-box;
&:hover {
border-radius: 20px;
.duty-info {
height: auto;
}
.icon-container {
bottom: 2px;
}
}
}
</style>

View File

@@ -0,0 +1,190 @@
<script setup lang="ts">
import { ElNotification } from 'element-plus'
import { pick } from 'lodash'
import api from '@/api/index.ts'
import SvgIcon from '@/components/SvgIcon/index.vue'
import { agentMapDuty } from '@/layout/components/config.ts'
import { type Agent, useAgentsStore } from '@/stores'
import { onMounted } from 'vue'
import { readConfig } from '@/utils/readJson.ts'
import AgentRepoList from './AgentRepoList.vue'
const agentsStore = useAgentsStore()
// 如果agentsStore.agents不存在就读取默认配置的json文件
onMounted(async () => {
if (!agentsStore.agents.length) {
const res = await readConfig<Agent[]>('agent.json')
agentsStore.setAgents(res)
}
await api.setAgents(agentsStore.agents.map((item) => pick(item, ['Name', 'Profile'])))
})
// 上传agent文件
const fileInput = ref<HTMLInputElement>()
const triggerFileSelect = () => {
fileInput.value?.click()
}
const handleFileSelect = (event: Event) => {
const input = event.target as HTMLInputElement
if (input.files && input.files[0]) {
const file = input.files[0]
readFileContent(file)
}
}
const readFileContent = async (file: File) => {
const reader = new FileReader()
reader.onload = async (e) => {
if (!e.target?.result) {
return
}
try {
const json = JSON.parse(e.target.result?.toString?.() ?? '{}')
// 处理 JSON 数据
if (Array.isArray(json)) {
const isValid = json.every(
(item) =>
typeof item.Name === 'string' &&
typeof item.Icon === 'string' &&
typeof item.Profile === 'string',
)
if (isValid) {
// 处理有效的 JSON 数据
agentsStore.setAgents(
json.map((item) => ({
Name: item.Name,
Icon: item.Icon.replace(/\.png$/, ''),
Profile: item.Profile,
Classification: item.Classification,
})),
)
await api.setAgents(json.map((item) => pick(item, ['Name', 'Profile'])))
} else {
ElNotification.error({
title: '错误',
message: 'JSON 格式错误',
})
}
} else {
console.error('JSON is not an array')
ElNotification.error({
title: '错误',
message: 'JSON 格式错误',
})
}
} catch (e) {
console.error(e)
}
}
reader.readAsText(file)
}
// 根据currentTask排序agent列表
const agentList = computed(() => {
const selected: Agent[] = []
const unselected: {
title: string
data: Agent[]
}[] = []
const obj: Record<string, Agent[]> = {}
if (!agentsStore.agents.length) {
return {
selected,
unselected,
}
}
for (const agent of agentsStore.agents) {
// if (agentsStore.currentTask?.AgentSelection?.includes(agent.Name)) {
// selected.push(agent)
// continue
// }
if (obj[agent.Classification]) {
obj[agent.Classification]!.push(agent)
} else {
const arr = [agent]
obj[agent.Classification] = arr
unselected.push({
title: agent.Classification,
data: arr,
})
}
}
return {
selected,
unselected: unselected,
}
})
</script>
<template>
<div class="agent-repo h-full flex flex-col" id="agent-repo">
<!-- 头部 -->
<div class="flex items-center justify-between">
<span class="text-[18px] font-bold">智能体库</span>
<!-- 上传文件 -->
<input type="file" accept=".json" @change="handleFileSelect" class="hidden" ref="fileInput" />
<div class="plus-button" @click="triggerFileSelect">
<svg-icon icon-class="plus" color="var(--color-text)" size="18px" />
</div>
</div>
<!-- 智能体列表 -->
<div class="pt-[18px] flex-1 overflow-y-auto relative">
<!-- 已选中的智能体 -->
<AgentRepoList :agent-list="agentList.selected" />
<!-- 为选择的智能体 -->
<div v-for="agent in agentList.unselected" :key="agent.title">
<p class="text-[12px] font-bold py-[8px]">{{ agent.title }}</p>
<AgentRepoList :agent-list="agent.data" />
</div>
</div>
<!-- 底部提示栏 -->
<div class="w-full grid grid-cols-3 gap-x-[10px] bg-[#1d222b] rounded-[20px] p-[8px] mt-[10px]">
<div
v-for="item in Object.values(agentMapDuty)"
:key="item.key"
class="flex items-center justify-center gap-x-1"
>
<span class="text-[12px]">{{ item.name }}</span>
<div class="w-[8px] h-[8px] rounded-full" :style="{ background: item.color }"></div>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.agent-repo {
padding: 0 8px;
.plus-button {
background: #1d2128;
width: 24px;
height: 24px;
padding: 0;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s ease;
&:hover {
background: #374151;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
}
}
}
#agent-repo {
:deep(.agent-repo-item-popover) {
padding: 0;
border-radius: 20px;
background: var(--color-bg-secondary);
}
}
</style>