Commit 504490492f83482f32d3af280bd281c1415c6a41
1 parent
562e85dc
feat: add hire modal and fire agent action to overview page
Showing
1 changed file
with
81 additions
and
2 deletions
web/src/views/CompanyDashboard.vue
| ... | ... | @@ -111,8 +111,11 @@ |
| 111 | 111 | <!-- Agent Status Table --> |
| 112 | 112 | <div class="overview-card agents-card"> |
| 113 | 113 | <div class="overview-card-header"> |
| 114 | - <h3>🤖 Agent 状态监控</h3> | |
| 115 | - <span class="agent-count-badge">{{ companyStatus?.agents?.length || 0 }} 个</span> | |
| 114 | + <div style="display:flex; align-items:center; gap:8px;"> | |
| 115 | + <h3>🤖 Agent 状态监控</h3> | |
| 116 | + <span class="agent-count-badge">{{ companyStatus?.agents?.length || 0 }} 个</span> | |
| 117 | + </div> | |
| 118 | + <button class="btn-sm" @click="openHireModal">+ 雇佣 Agent</button> | |
| 116 | 119 | </div> |
| 117 | 120 | <div v-if="companyStatus?.agents?.length > 0" class="agent-status-table"> |
| 118 | 121 | <div class="table-header"> |
| ... | ... | @@ -168,6 +171,7 @@ |
| 168 | 171 | <button class="btn-action-chat" @click="goToAgentChat(agent.id)">💬 聊天</button> |
| 169 | 172 | <button class="btn-action-skills" @click="toggleAgentSkills(agent.id)">📋 技能</button> |
| 170 | 173 | <button class="btn-action-train" @click="triggerTrain(agent.id)">🎓 训练</button> |
| 174 | + <button class="btn-action-fire" @click="fireAgent(agent.id, agent.name)">🗑️ 解雇</button> | |
| 171 | 175 | </div> |
| 172 | 176 | </span> |
| 173 | 177 | </div> |
| ... | ... | @@ -517,6 +521,37 @@ |
| 517 | 521 | </section> |
| 518 | 522 | |
| 519 | 523 | |
| 524 | + <!-- Hire Modal --> | |
| 525 | + <div v-if="showHireModal" class="modal-overlay" @click="showHireModal = false"> | |
| 526 | + <div class="modal-content" style="max-width: 500px;" @click.stop> | |
| 527 | + <div class="modal-header"> | |
| 528 | + <h3>+ 雇佣新 Agent</h3> | |
| 529 | + <button class="btn-close" @click="showHireModal = false">✕</button> | |
| 530 | + </div> | |
| 531 | + <div class="modal-body" style="display: flex; flex-direction: column; gap: 16px;"> | |
| 532 | + <div> | |
| 533 | + <label style="font-size: 13px; font-weight: 600; margin-bottom: 6px; display: block; color: var(--text-primary);">从模板库选择角色 (Role)</label> | |
| 534 | + <select v-model="hireForm.role" class="form-input" style="width: 100%;"> | |
| 535 | + <option value="">-- 请选择预置 Agent 模板 --</option> | |
| 536 | + <option v-for="tpl in templates" :key="tpl.id" :value="tpl.id"> | |
| 537 | + {{ agentEmoji(tpl.type) }} {{ tpl.name }} ({{ tpl.id }}) | |
| 538 | + </option> | |
| 539 | + </select> | |
| 540 | + </div> | |
| 541 | + <div v-if="hireForm.role"> | |
| 542 | + <label style="font-size: 13px; font-weight: 600; margin-bottom: 6px; display: block; color: var(--text-primary);">自定义花名 (可选)</label> | |
| 543 | + <input v-model="hireForm.name" class="form-input" style="width: 100%;" placeholder="留空则使用默认名称" /> | |
| 544 | + </div> | |
| 545 | + </div> | |
| 546 | + <div class="modal-footer" style="padding-top: 16px; margin-top: 8px;"> | |
| 547 | + <button class="btn-cancel" @click="showHireModal = false" style="padding: 6px 12px; border-radius: 6px; border: 1px solid var(--border-primary); background: transparent; color: var(--text-primary); cursor: pointer;">取消</button> | |
| 548 | + <button class="btn-install-large" :disabled="!hireForm.role || hiring" @click="submitHire" style="padding: 6px 16px; font-size: 13px;"> | |
| 549 | + {{ hiring ? '⏳ 办理入职中...' : '🎉 正式雇佣' }} | |
| 550 | + </button> | |
| 551 | + </div> | |
| 552 | + </div> | |
| 553 | + </div> | |
| 554 | + | |
| 520 | 555 | <!-- ═══ Templates Panel ═══ --> |
| 521 | 556 | <div v-if="showTemplates" class="templates-panel"> |
| 522 | 557 | <div class="panel-header"> |
| ... | ... | @@ -569,6 +604,49 @@ const showDropdown = ref(false) |
| 569 | 604 | const expandedAgent = ref(null) |
| 570 | 605 | const agentSkills = ref([]) |
| 571 | 606 | |
| 607 | +const showHireModal = ref(false) | |
| 608 | +const hiring = ref(false) | |
| 609 | +const hireForm = ref({ role: '', name: '' }) | |
| 610 | + | |
| 611 | +function openHireModal() { | |
| 612 | + hireForm.value = { role: '', name: '' }; | |
| 613 | + showHireModal.value = true; | |
| 614 | + if (templates.value.length === 0) loadTemplates(); | |
| 615 | +} | |
| 616 | + | |
| 617 | +async function submitHire() { | |
| 618 | + if (!hireForm.value.role || !selectedCompany.value) return; | |
| 619 | + hiring.value = true; | |
| 620 | + try { | |
| 621 | + const tpl = templates.value.find(t => t.id === hireForm.value.role); | |
| 622 | + await axios.post(`/api/company/${selectedCompany.value.id}/hire`, { | |
| 623 | + role: hireForm.value.role, | |
| 624 | + name: hireForm.value.name || undefined, | |
| 625 | + type: tpl?.type, | |
| 626 | + description: tpl?.description | |
| 627 | + }); | |
| 628 | + showHireModal.value = false; | |
| 629 | + await loadCompanyStatus(selectedCompany.value.id); | |
| 630 | + await loadCompanyAgents(selectedCompany.value.id); | |
| 631 | + } catch (e) { | |
| 632 | + alert(`❌ 雇佣失败: ${e.response?.data?.error || e.message}`); | |
| 633 | + } finally { | |
| 634 | + hiring.value = false; | |
| 635 | + } | |
| 636 | +} | |
| 637 | + | |
| 638 | +async function fireAgent(agentId, agentName) { | |
| 639 | + if (!selectedCompany.value) return; | |
| 640 | + if (!confirm(`⚠️ 确定要彻底解雇 ${agentName || agentId} 吗?将停止其所有运行进程并归档数据!`)) return; | |
| 641 | + try { | |
| 642 | + await axios.post(`/api/company/${selectedCompany.value.id}/fire`, { role: agentId }); | |
| 643 | + await loadCompanyStatus(selectedCompany.value.id); | |
| 644 | + await loadCompanyAgents(selectedCompany.value.id); | |
| 645 | + } catch (e) { | |
| 646 | + alert(`❌ 解雇失败: ${e.response?.data?.error || e.message}`); | |
| 647 | + } | |
| 648 | +} | |
| 649 | + | |
| 572 | 650 | // Files tab |
| 573 | 651 | const companyFiles = ref(null) |
| 574 | 652 | const selectedFilePath = ref(null) |
| ... | ... | @@ -1539,6 +1617,7 @@ function closeDropdown() { |
| 1539 | 1617 | .btn-action-chat { color: var(--accent-light); } |
| 1540 | 1618 | .btn-action-skills { color: var(--blue-text, #60a5fa); } |
| 1541 | 1619 | .btn-action-train { color: var(--purple-text, #a78bfa); } |
| 1620 | +.btn-action-fire { color: var(--red-text, #ef4444); } | |
| 1542 | 1621 | |
| 1543 | 1622 | /* Expandable Skills Panel */ |
| 1544 | 1623 | .agent-expand-panel { | ... | ... |