Compare commits
7 Commits
01cdb71903
...
web
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de5bc2109e | ||
|
|
932629f224 | ||
|
|
5e4e0b7f15 | ||
|
|
a4b94f43c1 | ||
|
|
f411dc0e20 | ||
|
|
344a0d1439 | ||
|
|
05f6a07d26 |
@@ -1643,11 +1643,15 @@ def handle_set_agents_ws(data):
|
||||
"profile": item["Profile"],
|
||||
"Icon": item.get("Icon", ""),
|
||||
"Classification": item.get("Classification", ""),
|
||||
"apiUrl": yaml_data.get("OPENAI_API_BASE"),
|
||||
"apiKey": yaml_data.get("OPENAI_API_KEY"),
|
||||
"apiModel": yaml_data.get("OPENAI_API_MODEL"),
|
||||
"useCustomAPI": False
|
||||
}
|
||||
# 只有 agent.json 里有配置时才写入数据库,否则动态读取 config.yaml
|
||||
if item.get("apiUrl"):
|
||||
agent_config["apiUrl"] = item["apiUrl"]
|
||||
if item.get("apiKey"):
|
||||
agent_config["apiKey"] = item["apiKey"]
|
||||
if item.get("apiModel"):
|
||||
agent_config["apiModel"] = item["apiModel"]
|
||||
AgentProfile_Dict[name] = agent_config
|
||||
|
||||
# 保存到数据库(仅当 save_to_db 为 true 时)
|
||||
@@ -1693,6 +1697,9 @@ def handle_get_agents_ws(data):
|
||||
从 user_agents 数据库表读取
|
||||
如果没有 user_id,会生成新的 user_id 并返回
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
|
||||
request_id = data.get('id')
|
||||
# 前端发送的数据在 data 字段中
|
||||
incoming_data = data.get('data', {})
|
||||
@@ -1717,6 +1724,52 @@ def handle_get_agents_ws(data):
|
||||
print(f"[get_agents] 用户 {user_id} 无配置,回退到 default_user")
|
||||
user_agents = UserAgentCRUD.get_by_user_id(db=db, user_id='default_user')
|
||||
|
||||
# 如果 default_user 也没有配置,则自动从 agent.json 读取并写入数据库
|
||||
if not user_agents:
|
||||
print(f"[get_agents] default_user 无配置,尝试从 agent.json 初始化")
|
||||
# 尝试读取 agent.json 文件
|
||||
possible_paths = [
|
||||
os.path.join(os.getcwd(), "..", "frontend", "public", "agent.json"),
|
||||
os.path.join(os.getcwd(), "frontend", "public", "agent.json"),
|
||||
os.path.join(os.getcwd(), "public", "agent.json"),
|
||||
]
|
||||
default_agents = None
|
||||
for path in possible_paths:
|
||||
if os.path.exists(path):
|
||||
try:
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
default_agents = json.load(f)
|
||||
print(f"[get_agents] 从 {path} 读取到默认智能体配置")
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"[get_agents] 读取 {path} 失败: {e}")
|
||||
|
||||
if default_agents and isinstance(default_agents, list):
|
||||
# 写入数据库作为 default_user
|
||||
for agent in default_agents:
|
||||
agent_config = {
|
||||
"profile": agent.get("Profile", ""),
|
||||
"Icon": agent.get("Icon", ""),
|
||||
"Classification": agent.get("Classification", ""),
|
||||
"useCustomAPI": False
|
||||
}
|
||||
# 只有 agent.json 里有配置时才写入数据库,否则动态读取 config.yaml
|
||||
if agent.get("apiUrl"):
|
||||
agent_config["apiUrl"] = agent["apiUrl"]
|
||||
if agent.get("apiKey"):
|
||||
agent_config["apiKey"] = agent["apiKey"]
|
||||
if agent.get("apiModel"):
|
||||
agent_config["apiModel"] = agent["apiModel"]
|
||||
UserAgentCRUD.upsert(
|
||||
db=db,
|
||||
user_id="default_user",
|
||||
agent_name=agent.get("Name", ""),
|
||||
agent_config=agent_config,
|
||||
)
|
||||
print(f"[get_agents] 成功写入 {len(default_agents)} 个默认智能体到数据库")
|
||||
# 重新查询
|
||||
user_agents = UserAgentCRUD.get_by_user_id(db=db, user_id='default_user')
|
||||
|
||||
# 转换为前端期望的格式
|
||||
agents = []
|
||||
for ua in user_agents:
|
||||
@@ -2804,17 +2857,76 @@ def handle_delete_task_process_node(data):
|
||||
for branch in branches_list:
|
||||
if branch.get('id') == branch_id:
|
||||
# 找到目标分支,删除指定的节点
|
||||
target_branch_content = branch.get('branchContent') # 保存branchContent用于匹配flow_branches
|
||||
nodes = branch.get('nodes', [])
|
||||
tasks = branch.get('tasks', [])
|
||||
|
||||
# 找到并删除节点
|
||||
for i, node in enumerate(nodes):
|
||||
# 找到要删除的节点
|
||||
node_to_delete = None
|
||||
for node in nodes:
|
||||
if node.get('id') == node_id:
|
||||
nodes.pop(i)
|
||||
if i < len(tasks):
|
||||
tasks.pop(i)
|
||||
node_to_delete = node
|
||||
break
|
||||
|
||||
if node_to_delete:
|
||||
# 先获取 original_index(删除前获取,用于同步 flow_branches)
|
||||
node_data = node_to_delete.get('data', {})
|
||||
original_index = node_data.get('originalIndex')
|
||||
|
||||
# ========== 同步更新 flow_branches (在删除前执行) ==========
|
||||
if original_index is not None:
|
||||
flow_branches = existing_branches.get('flow_branches', [])
|
||||
if isinstance(flow_branches, list):
|
||||
# 在 nodes 中查找并删除
|
||||
for flow_branch in flow_branches:
|
||||
flow_nodes = flow_branch.get('nodes', [])
|
||||
if isinstance(flow_nodes, list):
|
||||
for flow_node in flow_nodes:
|
||||
flow_node_data = flow_node.get('data', {})
|
||||
task_data = flow_node_data.get('task', {})
|
||||
if task_data.get('Id') == step_id:
|
||||
task_process = task_data.get('TaskProcess', [])
|
||||
if 0 <= original_index < len(task_process):
|
||||
task_process.pop(original_index)
|
||||
task_data['TaskProcess'] = task_process
|
||||
break
|
||||
|
||||
# 在 tasks 中查找并删除
|
||||
for flow_branch in flow_branches:
|
||||
flow_tasks = flow_branch.get('tasks', [])
|
||||
if isinstance(flow_tasks, list):
|
||||
for task_item in flow_tasks:
|
||||
if task_item.get('Id') == step_id:
|
||||
task_process = task_item.get('TaskProcess', [])
|
||||
if 0 <= original_index < len(task_process):
|
||||
task_process.pop(original_index)
|
||||
task_item['TaskProcess'] = task_process
|
||||
break
|
||||
|
||||
existing_branches['flow_branches'] = flow_branches
|
||||
# ========== 同步更新 flow_branches 结束 ==========
|
||||
|
||||
# 从 nodes 中删除
|
||||
nodes = [n for n in nodes if n.get('id') != node_id]
|
||||
|
||||
# 从 tasks 中删除:使用 originalIndex 精确匹配
|
||||
if original_index is not None and 0 <= original_index < len(tasks):
|
||||
tasks.pop(original_index)
|
||||
else:
|
||||
# 降级方案:使用 agentName + actionType 匹配
|
||||
agent_name = node_data.get('agentName')
|
||||
action_type_key = node_data.get('actionTypeKey', '').lower()
|
||||
action_type_map = {
|
||||
'propose': 'Propose',
|
||||
'review': 'Critique',
|
||||
'improve': 'Improve',
|
||||
'summary': 'Finalize'
|
||||
}
|
||||
target_action_type = action_type_map.get(action_type_key, action_type_key)
|
||||
tasks = [t for t in tasks
|
||||
if not (t.get('AgentName') == agent_name
|
||||
and t.get('ActionType') == target_action_type)]
|
||||
|
||||
# 更新分支数据(包括 nodes, tasks, edges)
|
||||
branch['nodes'] = nodes
|
||||
branch['tasks'] = tasks
|
||||
@@ -3049,11 +3161,9 @@ def ensure_export_dir(task_id: str) -> str:
|
||||
|
||||
def generate_export_file_name(task_name: str, export_type: str) -> str:
|
||||
"""生成导出文件名"""
|
||||
from datetime import datetime
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
# 清理文件名中的非法字符
|
||||
safe_name = "".join(c for c in task_name if c.isalnum() or c in (' ', '-', '_')).strip()
|
||||
return f"{safe_name}_{export_type}_{timestamp}"
|
||||
return f"{safe_name}_{export_type}"
|
||||
|
||||
|
||||
@socketio.on('export')
|
||||
@@ -3243,7 +3353,7 @@ def handle_get_export_list(data):
|
||||
|
||||
# ==================== REST API 接口 ====================
|
||||
|
||||
@app.route('/api/export/<int:record_id>/download', methods=['GET'])
|
||||
@app.route('/export/<int:record_id>/download', methods=['GET'])
|
||||
def download_export(record_id: int):
|
||||
"""下载导出文件"""
|
||||
try:
|
||||
@@ -3270,7 +3380,7 @@ def download_export(record_id: int):
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/export/<int:record_id>/preview', methods=['GET'])
|
||||
@app.route('/export/<int:record_id>/preview', methods=['GET'])
|
||||
def preview_export(record_id: int):
|
||||
"""预览导出文件"""
|
||||
try:
|
||||
@@ -3332,7 +3442,7 @@ def preview_export(record_id: int):
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/export/<int:record_id>/share', methods=['GET'])
|
||||
@app.route('/export/<int:record_id>/share', methods=['GET'])
|
||||
def share_export(record_id: int):
|
||||
"""生成分享链接"""
|
||||
try:
|
||||
@@ -3355,7 +3465,7 @@ def share_export(record_id: int):
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/export/<int:record_id>/share/info', methods=['GET'])
|
||||
@app.route('/export/<int:record_id>/share/info', methods=['GET'])
|
||||
def get_share_info(record_id: int):
|
||||
"""获取分享文件信息(无需登录验证)"""
|
||||
try:
|
||||
@@ -3407,7 +3517,7 @@ def get_shared_plan_page(share_token: str):
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/share/<share_token>/check', methods=['GET'])
|
||||
@app.route('/share/<share_token>/check', methods=['GET'])
|
||||
def check_share_code(share_token: str):
|
||||
"""检查分享链接是否需要提取码"""
|
||||
try:
|
||||
@@ -3431,7 +3541,7 @@ def check_share_code(share_token: str):
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/share/<share_token>', methods=['GET'])
|
||||
@app.route('/share/<share_token>', methods=['GET'])
|
||||
def get_shared_plan_info(share_token: str):
|
||||
"""获取分享任务详情(API 接口,无需登录验证)"""
|
||||
# 获取URL参数中的提取码
|
||||
@@ -3473,7 +3583,7 @@ def get_shared_plan_info(share_token: str):
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/share/import', methods=['POST'])
|
||||
@app.route('/share/import', methods=['POST'])
|
||||
def import_shared_plan():
|
||||
"""导入分享的任务到自己的历史记录(HTTP API,无需 WebSocket)"""
|
||||
try:
|
||||
@@ -3537,7 +3647,7 @@ def import_shared_plan():
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/export/<int:record_id>', methods=['DELETE'])
|
||||
@app.route('/export/<int:record_id>', methods=['DELETE'])
|
||||
def delete_export(record_id: int):
|
||||
"""删除导出记录"""
|
||||
try:
|
||||
|
||||
10
frontend/components.d.ts
vendored
10
frontend/components.d.ts
vendored
@@ -11,22 +11,32 @@ export {}
|
||||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
BranchInput: typeof import('./src/components/BranchInput/index.vue')['default']
|
||||
DeleteConfirmDialog: typeof import('./src/components/DeleteConfirmDialog/index.vue')['default']
|
||||
ElAutocomplete: typeof import('element-plus/es')['ElAutocomplete']
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElCard: typeof import('element-plus/es')['ElCard']
|
||||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||
ElCollapse: typeof import('element-plus/es')['ElCollapse']
|
||||
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
|
||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||
ElDrawer: typeof import('element-plus/es')['ElDrawer']
|
||||
ElEmpty: typeof import('element-plus/es')['ElEmpty']
|
||||
ElIcon: typeof import('element-plus/es')['ElIcon']
|
||||
ElInput: typeof import('element-plus/es')['ElInput']
|
||||
ElPopover: typeof import('element-plus/es')['ElPopover']
|
||||
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
|
||||
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
||||
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
|
||||
ElTable: typeof import('element-plus/es')['ElTable']
|
||||
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
||||
ElTag: typeof import('element-plus/es')['ElTag']
|
||||
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
||||
MultiLineTooltip: typeof import('./src/components/MultiLineTooltip/index.vue')['default']
|
||||
Notification: typeof import('./src/components/Notification/Notification.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
SharePlanDialog: typeof import('./src/components/SharePlanDialog/index.vue')['default']
|
||||
SvgIcon: typeof import('./src/components/SvgIcon/index.vue')['default']
|
||||
TaskContentEditor: typeof import('./src/components/TaskContentEditor/index.vue')['default']
|
||||
}
|
||||
|
||||
821
frontend/pnpm-lock.yaml
generated
821
frontend/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -923,41 +923,8 @@ class Api {
|
||||
downloadExport = async (recordId: number): Promise<void> => {
|
||||
const configStore = useConfigStoreHook()
|
||||
const baseURL = configStore.config.apiBaseUrl || ''
|
||||
const url = `${baseURL}/api/export/${recordId}/download`
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('下载失败')
|
||||
}
|
||||
|
||||
// 获取文件名从 Content-Disposition 头
|
||||
const contentDisposition = response.headers.get('Content-Disposition')
|
||||
let fileName = 'download'
|
||||
if (contentDisposition) {
|
||||
const match = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/)
|
||||
if (match) {
|
||||
fileName = match[1].replace(/['"]/g, '')
|
||||
}
|
||||
}
|
||||
|
||||
// 创建 Blob 并下载
|
||||
const blob = await response.blob()
|
||||
const downloadUrl = window.URL.createObjectURL(blob)
|
||||
const link = document.createElement('a')
|
||||
link.href = downloadUrl
|
||||
link.download = fileName
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
window.URL.revokeObjectURL(downloadUrl)
|
||||
} catch (error) {
|
||||
console.error('下载失败:', error)
|
||||
throw error
|
||||
}
|
||||
// 直接使用 window.location.href 跳转下载,浏览器会自动处理文件名
|
||||
window.location.href = `${baseURL}/export/${recordId}/download`
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -971,7 +938,7 @@ class Api {
|
||||
}> => {
|
||||
const configStore = useConfigStoreHook()
|
||||
const baseURL = configStore.config.apiBaseUrl || ''
|
||||
const url = `${baseURL}/api/export/${recordId}/preview`
|
||||
const url = `${baseURL}/export/${recordId}/preview`
|
||||
|
||||
const response = await request<{
|
||||
content?: string
|
||||
@@ -996,7 +963,7 @@ class Api {
|
||||
}> => {
|
||||
const configStore = useConfigStoreHook()
|
||||
const baseURL = configStore.config.apiBaseUrl || ''
|
||||
const url = `${baseURL}/api/export/${recordId}/share`
|
||||
const url = `${baseURL}/export/${recordId}/share`
|
||||
|
||||
const response = await request<{
|
||||
share_url: string
|
||||
@@ -1012,7 +979,7 @@ class Api {
|
||||
deleteExport = async (recordId: number): Promise<boolean> => {
|
||||
const configStore = useConfigStoreHook()
|
||||
const baseURL = configStore.config.apiBaseUrl || ''
|
||||
const url = `${baseURL}/api/export/${recordId}`
|
||||
const url = `${baseURL}/export/${recordId}`
|
||||
|
||||
try {
|
||||
await request({
|
||||
|
||||
@@ -52,8 +52,12 @@
|
||||
自定义
|
||||
</div>
|
||||
</div>
|
||||
<!-- 提取码显示/输入区域 -->
|
||||
<div v-if="codeType === 'random'" class="random-code-display">
|
||||
<span class="code-value">{{ generatedCode }}</span>
|
||||
</div>
|
||||
<!-- 自定义输入框 -->
|
||||
<div v-if="codeType === 'custom'" class="custom-code-wrapper">
|
||||
<div v-else class="custom-code-wrapper">
|
||||
<el-input
|
||||
v-model="customCode"
|
||||
placeholder="仅支持字母/数字"
|
||||
@@ -405,6 +409,25 @@ defineExpose({
|
||||
}
|
||||
}
|
||||
|
||||
.random-code-display {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 8px;
|
||||
padding: 8px 12px;
|
||||
background-color: var(--color-bg-subtle);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 6px;
|
||||
min-width: 80px;
|
||||
justify-content: center;
|
||||
|
||||
.code-value {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--color-primary);
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.custom-code-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -244,7 +244,12 @@ async function handleSearch() {
|
||||
currentGenerationId.value = response.generation_id || ''
|
||||
// 从 response.data 中获取 task_id(REST API 格式)
|
||||
currentTaskID.value = response.data?.task_id || response.task_id || ''
|
||||
console.log('📋 直接格式: generation_id:', currentGenerationId.value, 'TaskID:', currentTaskID.value)
|
||||
console.log(
|
||||
'📋 直接格式: generation_id:',
|
||||
currentGenerationId.value,
|
||||
'TaskID:',
|
||||
currentTaskID.value
|
||||
)
|
||||
} else {
|
||||
outlineData = response
|
||||
currentGenerationId.value = ''
|
||||
@@ -602,7 +607,7 @@ defineExpose({
|
||||
/>
|
||||
</el-button>
|
||||
</div>
|
||||
<AssignmentButton v-if="planReady" @click="openAgentAllocationDialog" />
|
||||
<!-- <AssignmentButton v-if="planReady" @click="openAgentAllocationDialog" /> -->
|
||||
<!-- 设置按钮 -->
|
||||
<el-button class="setting-button" circle title="设置" @click="openSettingsPanel">
|
||||
<el-icon size="18px"><Setting /></el-icon>
|
||||
|
||||
@@ -124,7 +124,9 @@ const agentsStore = useAgentsStore()
|
||||
<!-- 数据空间 -->
|
||||
<div class="text-[12px]">
|
||||
<span class="text-[var(--color-text)] font-bold">数据空间</span>
|
||||
<div class="text-[var(--color-text-secondary)] mt-1">归属于{{ item.Classification }}数据空间</div>
|
||||
<div class="text-[var(--color-text-secondary)] mt-1">
|
||||
归属于{{ item.Classification }}数据空间
|
||||
</div>
|
||||
</div>
|
||||
<!-- 分割线 -->
|
||||
<div class="h-[1px] w-full bg-[var(--color-border-default)] my-[8px]"></div>
|
||||
@@ -158,8 +160,6 @@ const agentsStore = useAgentsStore()
|
||||
v-if="index1 !== taskProcess.filter(i => i.AgentName === item.Name).length - 1"
|
||||
class="h-[1px] w-full bg-[var(--color-border-default)] my-[8px]"
|
||||
></div>
|
||||
|
||||
<AssignmentButton />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
@@ -80,8 +80,18 @@
|
||||
:title="previewData?.file_name || '文件预览'"
|
||||
width="80%"
|
||||
:close-on-click-modal="true"
|
||||
:show-close="false"
|
||||
class="preview-dialog"
|
||||
>
|
||||
<!-- 自定义关闭按钮 -->
|
||||
<template #header>
|
||||
<div class="dialog-header">
|
||||
<span class="dialog-title">{{ previewData?.file_name || '文件预览' }}</span>
|
||||
<button class="dialog-close-btn" @click="previewVisible = false">
|
||||
<SvgIcon icon-class="close" size="18px" />
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
<div class="preview-content">
|
||||
<div v-if="previewLoading" class="preview-loading">
|
||||
<el-icon class="is-loading"><Loading /></el-icon>
|
||||
@@ -1079,8 +1089,44 @@ onMounted(() => {
|
||||
|
||||
// 预览弹窗样式
|
||||
.preview-dialog {
|
||||
.el-dialog__header {
|
||||
padding: 16px 20px 10px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.dialog-close-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 4px;
|
||||
color: var(--color-text-regular);
|
||||
transition: transform 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -201,7 +201,7 @@ function handleCancel() {
|
||||
</div>
|
||||
</div>
|
||||
<!-- 按钮点击不会冒泡到卡片 -->
|
||||
<BranchButton :step="step" />
|
||||
<!-- <BranchButton :step="step" /> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -409,11 +409,14 @@ const getNodeDeletable = (
|
||||
// 获取所有分支数据
|
||||
const savedBranches = selectionStore.getTaskProcessBranches(taskStepId, currentAgents)
|
||||
|
||||
// 遍历所有分支,用节点 id 在 nodes 数组中查找
|
||||
// 遍历所有分支,查找该节点是否属于某个分支的第一个智能体节点
|
||||
for (const branch of savedBranches) {
|
||||
// 检查该节点是否是该分支的第一个节点
|
||||
const firstNode = branch.nodes?.[0]
|
||||
if (firstNode && firstNode.id === nodeId) {
|
||||
// 找到从 parentNodeId 出发的第一个智能体节点
|
||||
// 遍历分支的所有边,找到从 parentNodeId 出来的边连接的第一个节点
|
||||
const firstEdge = branch.edges?.find((edge: any) => edge.source === branch.parentNodeId)
|
||||
const firstNodeId = firstEdge?.target
|
||||
|
||||
if (firstNodeId && firstNodeId === nodeId) {
|
||||
// 只有该分支的第一个节点才显示删除分支按钮
|
||||
return {
|
||||
isDeletable: true,
|
||||
@@ -452,13 +455,6 @@ const handleDeleteBranch = (nodeId: string) => {
|
||||
ElMessage.error('未找到该分支')
|
||||
return
|
||||
}
|
||||
|
||||
console.log(
|
||||
'[删除分支] 找到的 branchId:',
|
||||
targetBranch.id,
|
||||
'parentNodeId:',
|
||||
nodeInfo.parentNodeId
|
||||
)
|
||||
branchIdToDelete.value = targetBranch.id
|
||||
deleteDialogVisible.value = true
|
||||
}
|
||||
@@ -481,6 +477,16 @@ const confirmDeleteBranch = async () => {
|
||||
return
|
||||
}
|
||||
|
||||
// ========== 新增:检查是否只剩下1个分支 ==========
|
||||
// 如果当前任务只剩下1个分支,则不可删除
|
||||
if (savedBranches.length <= 1) {
|
||||
ElMessage.error('至少需要保留1个分支,无法删除')
|
||||
deleteDialogVisible.value = false
|
||||
branchIdToDelete.value = null
|
||||
return
|
||||
}
|
||||
// ========== 新增结束 ==========
|
||||
|
||||
// 2. 获取该分支的所有节点ID
|
||||
const branchNodeIds = branchToDelete.nodes ? branchToDelete.nodes.map((node: any) => node.id) : []
|
||||
|
||||
@@ -500,6 +506,11 @@ const confirmDeleteBranch = async () => {
|
||||
const TaskID = (window as any).__CURRENT_TASK_ID__
|
||||
if (TaskID) {
|
||||
await selectionStore.deleteTaskProcessBranchFromDB(TaskID, taskStepId, branchId)
|
||||
|
||||
// ========== 同步更新 task_outline ==========
|
||||
// 删除分支后,同步更新 task_outline 中的 TaskProcess 数据
|
||||
await syncTaskOutlineAfterBranchDelete(branchToDelete, taskStepId)
|
||||
// ========== 同步更新结束 ==========
|
||||
}
|
||||
|
||||
// 8. 刷新视图
|
||||
@@ -520,6 +531,239 @@ const handleDeleteNode = (nodeId: string) => {
|
||||
deleteNodeDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 同步更新 task_outline 中删除分支后的数据
|
||||
const syncTaskOutlineAfterBranchDelete = async (branchToDelete: any, taskStepId: string) => {
|
||||
try {
|
||||
// 从 agentsStore 获取 task_outline
|
||||
const taskOutline = agentsStore.agentRawPlan.data
|
||||
if (!taskOutline) {
|
||||
console.warn('[syncTaskOutline] taskOutline 不存在,跳过同步')
|
||||
return
|
||||
}
|
||||
|
||||
// 找到对应的步骤
|
||||
const collaborationProcess = taskOutline['Collaboration Process'] || []
|
||||
const stepIndex = collaborationProcess.findIndex((step: any) => step.Id === taskStepId)
|
||||
|
||||
if (stepIndex === -1) {
|
||||
console.warn('[syncTaskOutline] 未找到对应的步骤:', taskStepId)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取分支中所有要删除的节点信息
|
||||
const nodesToDelete = branchToDelete.nodes || []
|
||||
const agentsToDelete = nodesToDelete.map((node: any) => ({
|
||||
agentName: node.data?.agentName,
|
||||
actionTypeKey: node.data?.actionTypeKey
|
||||
}))
|
||||
|
||||
const step = collaborationProcess[stepIndex]
|
||||
const taskProcess = step.TaskProcess || []
|
||||
|
||||
// 过滤掉要删除的 Action(通过 agentName + actionTypeKey 匹配)
|
||||
const newTaskProcess = taskProcess.filter((action: any) => {
|
||||
const match = agentsToDelete.find(
|
||||
(a: any) => a.agentName === action.AgentName && a.actionTypeKey === action.ActionType
|
||||
)
|
||||
return !match
|
||||
})
|
||||
|
||||
// 更新 step 的 TaskProcess
|
||||
taskOutline['Collaboration Process'][stepIndex].TaskProcess = newTaskProcess
|
||||
|
||||
// 保存到数据库
|
||||
const TaskID = (window as any).__CURRENT_TASK_ID__
|
||||
if (TaskID) {
|
||||
await api.updateTaskOutline(TaskID, taskOutline)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[syncTaskOutline] 分支删除后同步 taskOutline 失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 同步更新 task_outline 中的 TaskProcess 数据(使用已保存的节点信息)
|
||||
const syncTaskOutlineAfterNodeDeleteWithInfo = async (
|
||||
nodeId: string,
|
||||
taskStepId: string,
|
||||
nodeInfo: { agentName: string; actionTypeKey: string }
|
||||
) => {
|
||||
try {
|
||||
// 从 agentsStore 获取 task_outline
|
||||
const rawPlan = agentsStore.agentRawPlan
|
||||
const taskOutline = rawPlan?.data
|
||||
|
||||
if (!taskOutline) {
|
||||
return
|
||||
}
|
||||
|
||||
// 找到对应的步骤
|
||||
const collaborationProcess = taskOutline['Collaboration Process'] || []
|
||||
const stepIndex = collaborationProcess.findIndex((step: any) => step.Id === taskStepId)
|
||||
|
||||
if (stepIndex === -1) {
|
||||
return
|
||||
}
|
||||
|
||||
const step = collaborationProcess[stepIndex]!
|
||||
const taskProcess = step.TaskProcess || []
|
||||
|
||||
const { agentName, actionTypeKey } = nodeInfo
|
||||
|
||||
// actionTypeKey 到 ActionType 的映射
|
||||
const actionTypeKeyToActionType: Record<string, string> = {
|
||||
propose: 'Propose',
|
||||
review: 'Critique',
|
||||
improve: 'Improve',
|
||||
summary: 'Finalize'
|
||||
}
|
||||
|
||||
// 将 actionTypeKey 转换为正确的 ActionType
|
||||
const targetActionType = actionTypeKeyToActionType[actionTypeKey] || actionTypeKey
|
||||
|
||||
// 在 TaskProcess 中找到匹配的 Action 并删除
|
||||
// 通过 agentName + ActionType 匹配
|
||||
const newTaskProcess = taskProcess.filter((action: any) => {
|
||||
// 如果 ActionType 不匹配,直接保留
|
||||
if (action.ActionType !== targetActionType) {
|
||||
return true
|
||||
}
|
||||
// 如果 ActionType 匹配但 agentName 不匹配,保留
|
||||
if (action.AgentName !== agentName) {
|
||||
return true
|
||||
}
|
||||
// 如果 agentName 和 ActionType 都匹配,说明是要删除的节点
|
||||
return false
|
||||
})
|
||||
|
||||
// 检查是否有删除
|
||||
if (newTaskProcess.length === taskProcess.length) {
|
||||
return
|
||||
}
|
||||
|
||||
// 更新 step 的 TaskProcess
|
||||
const targetStep = taskOutline['Collaboration Process']?.[stepIndex]
|
||||
if (targetStep) {
|
||||
targetStep.TaskProcess = newTaskProcess
|
||||
}
|
||||
|
||||
// ========== 同步更新初始分支中的 tasks ==========
|
||||
// 更新初始分支中保存的 tasks,使其与 taskOutline 保持一致
|
||||
const currentAgents = currentTask.value?.AgentSelection || []
|
||||
const savedBranches = selectionStore.getTaskProcessBranches(taskStepId, currentAgents)
|
||||
const initialBranch = savedBranches.find(branch => branch.branchContent === '初始流程')
|
||||
if (initialBranch) {
|
||||
// 更新初始分支的 tasks
|
||||
initialBranch.tasks = newTaskProcess
|
||||
// 保存到数据库
|
||||
saveTaskProcessBranchesToDB()
|
||||
}
|
||||
// ========== 同步更新结束 ==========
|
||||
|
||||
// 保存到数据库
|
||||
const TaskID = (window as any).__CURRENT_TASK_ID__
|
||||
|
||||
if (TaskID) {
|
||||
await api.updateTaskOutline(TaskID, taskOutline)
|
||||
} else {
|
||||
console.error('[syncTaskOutline] TaskID 不存在')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[syncTaskOutline] 同步 taskOutline 失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 同步更新 task_outline 中的 TaskProcess 数据(备用方案,从 store 查找)
|
||||
const syncTaskOutlineAfterNodeDelete = async (nodeId: string, taskStepId: string) => {
|
||||
try {
|
||||
// 从 agentsStore 获取 task_outline
|
||||
const rawPlan = agentsStore.agentRawPlan
|
||||
const taskOutline = rawPlan?.data
|
||||
|
||||
if (!taskOutline) {
|
||||
return
|
||||
}
|
||||
|
||||
// 找到对应的步骤
|
||||
const collaborationProcess = taskOutline['Collaboration Process'] || []
|
||||
const stepIndex = collaborationProcess.findIndex((step: any) => step.Id === taskStepId)
|
||||
|
||||
if (stepIndex === -1) {
|
||||
return
|
||||
}
|
||||
|
||||
const step = collaborationProcess[stepIndex]!
|
||||
const taskProcess = step.TaskProcess || []
|
||||
|
||||
// 获取被删除节点的 agentName 和 actionTypeKey
|
||||
// 需要从分支数据中获取节点信息
|
||||
const currentAgents = currentTask.value?.AgentSelection || []
|
||||
const savedBranches = selectionStore.getTaskProcessBranches(taskStepId, currentAgents)
|
||||
|
||||
const targetBranch = savedBranches.find(branch =>
|
||||
branch.nodes?.some((n: any) => n.id === nodeId)
|
||||
)
|
||||
|
||||
if (!targetBranch) {
|
||||
return
|
||||
}
|
||||
|
||||
const deletedNode = targetBranch.nodes?.find((n: any) => n.id === nodeId)
|
||||
|
||||
if (!deletedNode) {
|
||||
return
|
||||
}
|
||||
|
||||
const agentName = deletedNode.data?.agentName
|
||||
const actionTypeKey = deletedNode.data?.actionTypeKey
|
||||
|
||||
// actionTypeKey 到 ActionType 的映射
|
||||
const actionTypeKeyToActionType: Record<string, string> = {
|
||||
propose: 'Propose',
|
||||
review: 'Critique',
|
||||
improve: 'Improve',
|
||||
summary: 'Finalize'
|
||||
}
|
||||
|
||||
// 将 actionTypeKey 转换为正确的 ActionType
|
||||
const targetActionType = actionTypeKeyToActionType[actionTypeKey] || actionTypeKey
|
||||
|
||||
// 在 TaskProcess 中找到匹配的 Action 并删除
|
||||
// 通过 agentName + ActionType 匹配
|
||||
const newTaskProcess = taskProcess.filter((action: any) => {
|
||||
// 如果 ActionType 不匹配,直接保留
|
||||
if (action.ActionType !== targetActionType) {
|
||||
return true
|
||||
}
|
||||
// 如果 ActionType 匹配但 agentName 不匹配,保留
|
||||
if (action.AgentName !== agentName) {
|
||||
return true
|
||||
}
|
||||
// 如果 agentName 和 ActionType 都匹配,说明是要删除的节点
|
||||
return false
|
||||
})
|
||||
|
||||
// 检查是否有删除
|
||||
if (newTaskProcess.length === taskProcess.length) {
|
||||
return
|
||||
}
|
||||
|
||||
// 更新 step 的 TaskProcess
|
||||
const targetStep = taskOutline['Collaboration Process']?.[stepIndex]
|
||||
if (targetStep) {
|
||||
targetStep.TaskProcess = newTaskProcess
|
||||
}
|
||||
|
||||
// 保存到数据库
|
||||
const TaskID = (window as any).__CURRENT_TASK_ID__
|
||||
|
||||
if (TaskID) {
|
||||
await api.updateTaskOutline(TaskID, taskOutline)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[syncTaskOutline] 同步 taskOutline 失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 确认删除单个节点
|
||||
const confirmDeleteNode = async () => {
|
||||
if (!nodeIdToDelete.value) return
|
||||
@@ -528,6 +772,41 @@ const confirmDeleteNode = async () => {
|
||||
const taskStepId = currentTask.value?.Id
|
||||
const currentAgents = currentTask.value?.AgentSelection || []
|
||||
|
||||
// ========== 新增:检查职责类型数量 ==========
|
||||
// 在删除前检查该分支中该职责类型是否只剩1个,如果是则不可删除
|
||||
if (taskStepId && currentAgents.length > 0) {
|
||||
const savedBranches = selectionStore.getTaskProcessBranches(taskStepId, currentAgents)
|
||||
const targetBranch = savedBranches.find(branch =>
|
||||
branch.nodes?.some((n: any) => n.id === nodeId)
|
||||
)
|
||||
|
||||
if (targetBranch) {
|
||||
// 获取被删除节点的职责类型
|
||||
const deletedNode = targetBranch.nodes?.find((n: any) => n.id === nodeId)
|
||||
const actionTypeKey = deletedNode?.data?.actionTypeKey
|
||||
const actionTypeName = deletedNode?.data?.actionTypeName || '该职责'
|
||||
|
||||
// 统计该分支中每种职责类型的数量
|
||||
const actionTypeCount = new Map<string, number>()
|
||||
targetBranch.nodes?.forEach((n: any) => {
|
||||
const type = n.data?.actionTypeKey
|
||||
if (type) {
|
||||
actionTypeCount.set(type, (actionTypeCount.get(type) || 0) + 1)
|
||||
}
|
||||
})
|
||||
|
||||
// 检查被删除节点对应的职责类型数量
|
||||
const currentCount = actionTypeCount.get(actionTypeKey) || 0
|
||||
if (currentCount <= 1) {
|
||||
ElMessage.error(`${actionTypeName}类型至少需要保留1个节点,无法删除`)
|
||||
deleteNodeDialogVisible.value = false
|
||||
nodeIdToDelete.value = null
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
// ========== 新增结束 ==========
|
||||
|
||||
// 0. 检查被删除的节点是否是分支的第一个节点(带删除分支按钮)
|
||||
const nodeDeletable = getNodeDeletable(nodeId)
|
||||
const deletedBranchId = nodeDeletable.isDeletable ? nodeDeletable.branchId : null
|
||||
@@ -583,7 +862,6 @@ const confirmDeleteNode = async () => {
|
||||
...childIncomingEdge.data,
|
||||
branchId: deletedBranchId
|
||||
}
|
||||
console.log('[删除节点] 已更新新节点的边信息:', childNodeId, deletedBranchId)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -596,6 +874,19 @@ const confirmDeleteNode = async () => {
|
||||
// 找到被删除节点所属的分支
|
||||
const targetBranch = branches.find(branch => branch.nodes?.some((n: any) => n.id === nodeId))
|
||||
|
||||
// ========== 在删除节点之前先保存节点信息 ==========
|
||||
let deletedNodeInfo: { agentName: string; actionTypeKey: string } | null = null
|
||||
if (targetBranch) {
|
||||
const deletedNode = targetBranch.nodes?.find((n: any) => n.id === nodeId)
|
||||
if (deletedNode) {
|
||||
deletedNodeInfo = {
|
||||
agentName: deletedNode.data?.agentName,
|
||||
actionTypeKey: deletedNode.data?.actionTypeKey
|
||||
}
|
||||
}
|
||||
}
|
||||
// ========== 保存节点信息结束 ==========
|
||||
|
||||
if (targetBranch) {
|
||||
// 使用精准删除方法(前端 store)
|
||||
const success = selectionStore.removeNodeFromBranch(
|
||||
@@ -609,8 +900,6 @@ const confirmDeleteNode = async () => {
|
||||
)
|
||||
|
||||
if (success) {
|
||||
console.log('[删除节点] 前端精准删除成功')
|
||||
|
||||
// 调用后端接口删除节点,传递更新后的 edges 数据
|
||||
const TaskID = (window as any).__CURRENT_TASK_ID__
|
||||
if (TaskID) {
|
||||
@@ -621,7 +910,16 @@ const confirmDeleteNode = async () => {
|
||||
nodeId,
|
||||
edges.value
|
||||
)
|
||||
console.log('[删除节点] 后端删除结果:', result)
|
||||
|
||||
// ========== 同步更新 task_outline ==========
|
||||
// 删除节点后,同步更新 task_outline 中的 TaskProcess 数据
|
||||
// 传递之前保存的节点信息,而不是从 store 中查找
|
||||
if (deletedNodeInfo) {
|
||||
await syncTaskOutlineAfterNodeDeleteWithInfo(nodeId, taskStepId, deletedNodeInfo)
|
||||
} else {
|
||||
await syncTaskOutlineAfterNodeDelete(nodeId, taskStepId)
|
||||
}
|
||||
// ========== 同步更新结束 ==========
|
||||
}
|
||||
} else {
|
||||
console.error('[删除节点] 前端精准删除失败')
|
||||
@@ -1732,6 +2030,7 @@ defineExpose({
|
||||
transition: all 0.2s ease;
|
||||
z-index: 10;
|
||||
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.2);
|
||||
opacity: 0;
|
||||
|
||||
&:active {
|
||||
transform: translateX(-50%) scale(0.95);
|
||||
@@ -1744,6 +2043,12 @@ defineExpose({
|
||||
}
|
||||
}
|
||||
|
||||
// hover 时显示添加按钮
|
||||
.task-node-wrapper:hover .external-add-btn,
|
||||
.root-task-node-wrapper:hover .external-add-btn {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.agent-node-wrapper {
|
||||
position: relative;
|
||||
display: flex;
|
||||
@@ -1904,8 +2209,9 @@ defineExpose({
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s ease;
|
||||
transition: background-color 0.2s ease, opacity 0.2s ease;
|
||||
z-index: 100;
|
||||
opacity: 0;
|
||||
|
||||
// 左侧位置
|
||||
&.left {
|
||||
@@ -1930,8 +2236,9 @@ defineExpose({
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s ease;
|
||||
transition: background-color 0.2s ease, opacity 0.2s ease;
|
||||
z-index: 100;
|
||||
opacity: 0;
|
||||
top: -12px;
|
||||
right: -12px;
|
||||
|
||||
@@ -1940,6 +2247,13 @@ defineExpose({
|
||||
}
|
||||
}
|
||||
|
||||
// hover 时显示删除按钮
|
||||
.task-node-wrapper:hover .node-delete-btn,
|
||||
.task-node-wrapper:hover .node-delete-btn-single,
|
||||
.root-task-node-wrapper:hover .node-delete-btn {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
// 边样式 - 与PlanModification.vue保持一致
|
||||
::deep(.vue-flow__edge.selected .vue-flow__edge-path) {
|
||||
stroke: #409eff;
|
||||
|
||||
@@ -356,11 +356,17 @@ const isDeletable = computed(() => props.isDeletable || false)
|
||||
transition: all 0.2s ease;
|
||||
z-index: 10;
|
||||
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.2);
|
||||
opacity: 0;
|
||||
|
||||
&:active {
|
||||
transform: translateX(-50%) scale(0.95);
|
||||
}
|
||||
|
||||
// hover 时显示
|
||||
.node-wrapper:hover & {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
// 取消按钮样式
|
||||
&.cancel-btn {
|
||||
border-color: #f56c6c;
|
||||
@@ -390,8 +396,9 @@ const isDeletable = computed(() => props.isDeletable || false)
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s ease;
|
||||
transition: background-color 0.2s ease, opacity 0.2s ease;
|
||||
z-index: 100;
|
||||
opacity: 0;
|
||||
|
||||
// 左侧位置
|
||||
&.left {
|
||||
@@ -410,6 +417,11 @@ const isDeletable = computed(() => props.isDeletable || false)
|
||||
background-color: #0c0c0c;
|
||||
}
|
||||
}
|
||||
|
||||
// 节点容器 hover 时显示删除按钮
|
||||
.node-wrapper:hover .node-delete-btn {
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -366,7 +366,7 @@ defineExpose({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<BranchButton v-if="planReady" @click="openPlanModification" />
|
||||
<!-- <BranchButton v-if="planReady" @click="openPlanModification" /> -->
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -300,9 +300,18 @@ export const useSelectionStore = defineStore('selection', () => {
|
||||
const nodeIndex = branch.nodes.findIndex((n: any) => n.id === nodeId)
|
||||
if (nodeIndex === -1) return false
|
||||
|
||||
// 精准删除:只删除对应索引的节点和任务
|
||||
// 获取被删除节点的信息
|
||||
const deletedNode = branch.nodes[nodeIndex]
|
||||
const originalIndex = deletedNode?.data?.originalIndex
|
||||
|
||||
// 精准删除:删除 nodes 中的节点
|
||||
branch.nodes.splice(nodeIndex, 1)
|
||||
branch.tasks.splice(nodeIndex, 1)
|
||||
|
||||
// 精准删除 tasks:使用 originalIndex 直接定位
|
||||
// nodes 包含 root 节点,所以 agent 节点的 originalIndex 对应 tasks 的索引
|
||||
if (originalIndex !== undefined && originalIndex < branch.tasks.length) {
|
||||
branch.tasks.splice(originalIndex, 1)
|
||||
}
|
||||
|
||||
// 更新 edges:移除相关边,添加新边
|
||||
if (incomingEdges.length > 0 || outgoingEdges.length > 0) {
|
||||
|
||||
@@ -263,7 +263,7 @@ const downloadFile = async () => {
|
||||
return
|
||||
}
|
||||
|
||||
window.location.href = `${apiBaseUrl}/api/export/${parsed.recordId}/download`
|
||||
window.location.href = `${apiBaseUrl}/export/${parsed.recordId}/download`
|
||||
} catch (e) {
|
||||
console.error('下载失败:', e)
|
||||
ElMessage.error('下载失败')
|
||||
|
||||
@@ -50,10 +50,10 @@ export default defineConfig({
|
||||
// target: 'http://82.157.183.212:21092',
|
||||
// target: 'http://82.157.183.212:21097',
|
||||
target: 'http://localhost:8000',
|
||||
// rewrite: (path: string) => path.replace(/^\/api/, ''),
|
||||
// configure: (proxy, options) => {
|
||||
// console.log('Proxy configured:', options)
|
||||
// },
|
||||
rewrite: (path: string) => path.replace(/^\/api/, ''),
|
||||
configure: (proxy, options) => {
|
||||
console.log('Proxy configured:', options)
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
7
package.json
Normal file
7
package.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.71.2",
|
||||
"@element-plus/icons-vue": "^2.3.2",
|
||||
"docx-preview": "^0.3.7"
|
||||
}
|
||||
}
|
||||
339
pnpm-lock.yaml
generated
Normal file
339
pnpm-lock.yaml
generated
Normal file
@@ -0,0 +1,339 @@
|
||||
lockfileVersion: '9.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
'@anthropic-ai/sdk':
|
||||
specifier: ^0.71.2
|
||||
version: 0.71.2
|
||||
'@element-plus/icons-vue':
|
||||
specifier: ^2.3.2
|
||||
version: 2.3.2(vue@3.5.26)
|
||||
docx-preview:
|
||||
specifier: ^0.3.7
|
||||
version: 0.3.7
|
||||
|
||||
packages:
|
||||
|
||||
'@anthropic-ai/sdk@0.71.2':
|
||||
resolution: {integrity: sha512-TGNDEUuEstk/DKu0/TflXAEt+p+p/WhTlFzEnoosvbaDU2LTjm42igSdlL0VijrKpWejtOKxX0b8A7uc+XiSAQ==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
zod: ^3.25.0 || ^4.0.0
|
||||
peerDependenciesMeta:
|
||||
zod:
|
||||
optional: true
|
||||
|
||||
'@babel/helper-string-parser@7.27.1':
|
||||
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-validator-identifier@7.28.5':
|
||||
resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/parser@7.28.5':
|
||||
resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
hasBin: true
|
||||
|
||||
'@babel/runtime@7.28.6':
|
||||
resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/types@7.28.5':
|
||||
resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@element-plus/icons-vue@2.3.2':
|
||||
resolution: {integrity: sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==}
|
||||
peerDependencies:
|
||||
vue: ^3.2.0
|
||||
|
||||
'@jridgewell/sourcemap-codec@1.5.5':
|
||||
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
|
||||
|
||||
'@vue/compiler-core@3.5.26':
|
||||
resolution: {integrity: sha512-vXyI5GMfuoBCnv5ucIT7jhHKl55Y477yxP6fc4eUswjP8FG3FFVFd41eNDArR+Uk3QKn2Z85NavjaxLxOC19/w==}
|
||||
|
||||
'@vue/compiler-dom@3.5.26':
|
||||
resolution: {integrity: sha512-y1Tcd3eXs834QjswshSilCBnKGeQjQXB6PqFn/1nxcQw4pmG42G8lwz+FZPAZAby6gZeHSt/8LMPfZ4Rb+Bd/A==}
|
||||
|
||||
'@vue/compiler-sfc@3.5.26':
|
||||
resolution: {integrity: sha512-egp69qDTSEZcf4bGOSsprUr4xI73wfrY5oRs6GSgXFTiHrWj4Y3X5Ydtip9QMqiCMCPVwLglB9GBxXtTadJ3mA==}
|
||||
|
||||
'@vue/compiler-ssr@3.5.26':
|
||||
resolution: {integrity: sha512-lZT9/Y0nSIRUPVvapFJEVDbEXruZh2IYHMk2zTtEgJSlP5gVOqeWXH54xDKAaFS4rTnDeDBQUYDtxKyoW9FwDw==}
|
||||
|
||||
'@vue/reactivity@3.5.26':
|
||||
resolution: {integrity: sha512-9EnYB1/DIiUYYnzlnUBgwU32NNvLp/nhxLXeWRhHUEeWNTn1ECxX8aGO7RTXeX6PPcxe3LLuNBFoJbV4QZ+CFQ==}
|
||||
|
||||
'@vue/runtime-core@3.5.26':
|
||||
resolution: {integrity: sha512-xJWM9KH1kd201w5DvMDOwDHYhrdPTrAatn56oB/LRG4plEQeZRQLw0Bpwih9KYoqmzaxF0OKSn6swzYi84e1/Q==}
|
||||
|
||||
'@vue/runtime-dom@3.5.26':
|
||||
resolution: {integrity: sha512-XLLd/+4sPC2ZkN/6+V4O4gjJu6kSDbHAChvsyWgm1oGbdSO3efvGYnm25yCjtFm/K7rrSDvSfPDgN1pHgS4VNQ==}
|
||||
|
||||
'@vue/server-renderer@3.5.26':
|
||||
resolution: {integrity: sha512-TYKLXmrwWKSodyVuO1WAubucd+1XlLg4set0YoV+Hu8Lo79mp/YMwWV5mC5FgtsDxX3qo1ONrxFaTP1OQgy1uA==}
|
||||
peerDependencies:
|
||||
vue: 3.5.26
|
||||
|
||||
'@vue/shared@3.5.26':
|
||||
resolution: {integrity: sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A==}
|
||||
|
||||
core-util-is@1.0.3:
|
||||
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
|
||||
|
||||
csstype@3.2.3:
|
||||
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
|
||||
|
||||
docx-preview@0.3.7:
|
||||
resolution: {integrity: sha512-Lav69CTA/IYZPJTsKH7oYeoZjyg96N0wEJMNslGJnZJ+dMUZK85Lt5ASC79yUlD48ecWjuv+rkcmFt6EVPV0Xg==}
|
||||
|
||||
entities@7.0.0:
|
||||
resolution: {integrity: sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ==}
|
||||
engines: {node: '>=0.12'}
|
||||
|
||||
estree-walker@2.0.2:
|
||||
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
||||
|
||||
immediate@3.0.6:
|
||||
resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==}
|
||||
|
||||
inherits@2.0.4:
|
||||
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||
|
||||
isarray@1.0.0:
|
||||
resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
|
||||
|
||||
json-schema-to-ts@3.1.1:
|
||||
resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
jszip@3.10.1:
|
||||
resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==}
|
||||
|
||||
lie@3.3.0:
|
||||
resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==}
|
||||
|
||||
magic-string@0.30.21:
|
||||
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
|
||||
|
||||
nanoid@3.3.11:
|
||||
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
|
||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||
hasBin: true
|
||||
|
||||
pako@1.0.11:
|
||||
resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
|
||||
|
||||
picocolors@1.1.1:
|
||||
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||
|
||||
postcss@8.5.6:
|
||||
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
process-nextick-args@2.0.1:
|
||||
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
|
||||
|
||||
readable-stream@2.3.8:
|
||||
resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
|
||||
|
||||
safe-buffer@5.1.2:
|
||||
resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
|
||||
|
||||
setimmediate@1.0.5:
|
||||
resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==}
|
||||
|
||||
source-map-js@1.2.1:
|
||||
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
string_decoder@1.1.1:
|
||||
resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
|
||||
|
||||
ts-algebra@2.0.0:
|
||||
resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==}
|
||||
|
||||
util-deprecate@1.0.2:
|
||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
|
||||
vue@3.5.26:
|
||||
resolution: {integrity: sha512-SJ/NTccVyAoNUJmkM9KUqPcYlY+u8OVL1X5EW9RIs3ch5H2uERxyyIUI4MRxVCSOiEcupX9xNGde1tL9ZKpimA==}
|
||||
peerDependencies:
|
||||
typescript: '*'
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
snapshots:
|
||||
|
||||
'@anthropic-ai/sdk@0.71.2':
|
||||
dependencies:
|
||||
json-schema-to-ts: 3.1.1
|
||||
|
||||
'@babel/helper-string-parser@7.27.1': {}
|
||||
|
||||
'@babel/helper-validator-identifier@7.28.5': {}
|
||||
|
||||
'@babel/parser@7.28.5':
|
||||
dependencies:
|
||||
'@babel/types': 7.28.5
|
||||
|
||||
'@babel/runtime@7.28.6': {}
|
||||
|
||||
'@babel/types@7.28.5':
|
||||
dependencies:
|
||||
'@babel/helper-string-parser': 7.27.1
|
||||
'@babel/helper-validator-identifier': 7.28.5
|
||||
|
||||
'@element-plus/icons-vue@2.3.2(vue@3.5.26)':
|
||||
dependencies:
|
||||
vue: 3.5.26
|
||||
|
||||
'@jridgewell/sourcemap-codec@1.5.5': {}
|
||||
|
||||
'@vue/compiler-core@3.5.26':
|
||||
dependencies:
|
||||
'@babel/parser': 7.28.5
|
||||
'@vue/shared': 3.5.26
|
||||
entities: 7.0.0
|
||||
estree-walker: 2.0.2
|
||||
source-map-js: 1.2.1
|
||||
|
||||
'@vue/compiler-dom@3.5.26':
|
||||
dependencies:
|
||||
'@vue/compiler-core': 3.5.26
|
||||
'@vue/shared': 3.5.26
|
||||
|
||||
'@vue/compiler-sfc@3.5.26':
|
||||
dependencies:
|
||||
'@babel/parser': 7.28.5
|
||||
'@vue/compiler-core': 3.5.26
|
||||
'@vue/compiler-dom': 3.5.26
|
||||
'@vue/compiler-ssr': 3.5.26
|
||||
'@vue/shared': 3.5.26
|
||||
estree-walker: 2.0.2
|
||||
magic-string: 0.30.21
|
||||
postcss: 8.5.6
|
||||
source-map-js: 1.2.1
|
||||
|
||||
'@vue/compiler-ssr@3.5.26':
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.5.26
|
||||
'@vue/shared': 3.5.26
|
||||
|
||||
'@vue/reactivity@3.5.26':
|
||||
dependencies:
|
||||
'@vue/shared': 3.5.26
|
||||
|
||||
'@vue/runtime-core@3.5.26':
|
||||
dependencies:
|
||||
'@vue/reactivity': 3.5.26
|
||||
'@vue/shared': 3.5.26
|
||||
|
||||
'@vue/runtime-dom@3.5.26':
|
||||
dependencies:
|
||||
'@vue/reactivity': 3.5.26
|
||||
'@vue/runtime-core': 3.5.26
|
||||
'@vue/shared': 3.5.26
|
||||
csstype: 3.2.3
|
||||
|
||||
'@vue/server-renderer@3.5.26(vue@3.5.26)':
|
||||
dependencies:
|
||||
'@vue/compiler-ssr': 3.5.26
|
||||
'@vue/shared': 3.5.26
|
||||
vue: 3.5.26
|
||||
|
||||
'@vue/shared@3.5.26': {}
|
||||
|
||||
core-util-is@1.0.3: {}
|
||||
|
||||
csstype@3.2.3: {}
|
||||
|
||||
docx-preview@0.3.7:
|
||||
dependencies:
|
||||
jszip: 3.10.1
|
||||
|
||||
entities@7.0.0: {}
|
||||
|
||||
estree-walker@2.0.2: {}
|
||||
|
||||
immediate@3.0.6: {}
|
||||
|
||||
inherits@2.0.4: {}
|
||||
|
||||
isarray@1.0.0: {}
|
||||
|
||||
json-schema-to-ts@3.1.1:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.6
|
||||
ts-algebra: 2.0.0
|
||||
|
||||
jszip@3.10.1:
|
||||
dependencies:
|
||||
lie: 3.3.0
|
||||
pako: 1.0.11
|
||||
readable-stream: 2.3.8
|
||||
setimmediate: 1.0.5
|
||||
|
||||
lie@3.3.0:
|
||||
dependencies:
|
||||
immediate: 3.0.6
|
||||
|
||||
magic-string@0.30.21:
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
|
||||
nanoid@3.3.11: {}
|
||||
|
||||
pako@1.0.11: {}
|
||||
|
||||
picocolors@1.1.1: {}
|
||||
|
||||
postcss@8.5.6:
|
||||
dependencies:
|
||||
nanoid: 3.3.11
|
||||
picocolors: 1.1.1
|
||||
source-map-js: 1.2.1
|
||||
|
||||
process-nextick-args@2.0.1: {}
|
||||
|
||||
readable-stream@2.3.8:
|
||||
dependencies:
|
||||
core-util-is: 1.0.3
|
||||
inherits: 2.0.4
|
||||
isarray: 1.0.0
|
||||
process-nextick-args: 2.0.1
|
||||
safe-buffer: 5.1.2
|
||||
string_decoder: 1.1.1
|
||||
util-deprecate: 1.0.2
|
||||
|
||||
safe-buffer@5.1.2: {}
|
||||
|
||||
setimmediate@1.0.5: {}
|
||||
|
||||
source-map-js@1.2.1: {}
|
||||
|
||||
string_decoder@1.1.1:
|
||||
dependencies:
|
||||
safe-buffer: 5.1.2
|
||||
|
||||
ts-algebra@2.0.0: {}
|
||||
|
||||
util-deprecate@1.0.2: {}
|
||||
|
||||
vue@3.5.26:
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.5.26
|
||||
'@vue/compiler-sfc': 3.5.26
|
||||
'@vue/runtime-dom': 3.5.26
|
||||
'@vue/server-renderer': 3.5.26(vue@3.5.26)
|
||||
'@vue/shared': 3.5.26
|
||||
Reference in New Issue
Block a user