|
@@ -83,7 +83,7 @@
|
|
|
<!-- ── ① 技能(SKILL.md 包) ──────────────────────────────── -->
|
|
<!-- ── ① 技能(SKILL.md 包) ──────────────────────────────── -->
|
|
|
<a-spin v-if="activeTab === 'skill'" :spinning="loading">
|
|
<a-spin v-if="activeTab === 'skill'" :spinning="loading">
|
|
|
<div v-if="skills.length" class="ai-plugin__grid">
|
|
<div v-if="skills.length" class="ai-plugin__grid">
|
|
|
- <article v-for="skill in skills" :key="skill.path || skill.name" class="ai-plugin__card">
|
|
|
|
|
|
|
+ <article v-for="skill in skills" :key="skill.name" class="ai-plugin__card">
|
|
|
<div class="ai-plugin__card-head">
|
|
<div class="ai-plugin__card-head">
|
|
|
<span class="ai-plugin__card-icon">
|
|
<span class="ai-plugin__card-icon">
|
|
|
<Icon icon="mdi:script-text-outline" :size="18" />
|
|
<Icon icon="mdi:script-text-outline" :size="18" />
|
|
@@ -120,6 +120,7 @@
|
|
|
</div>
|
|
</div>
|
|
|
</article>
|
|
</article>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <div v-else-if="loading" class="ai-spin-placeholder" aria-hidden="true"></div>
|
|
|
<EmptyState
|
|
<EmptyState
|
|
|
v-else
|
|
v-else
|
|
|
title="还没有技能"
|
|
title="还没有技能"
|
|
@@ -170,6 +171,7 @@
|
|
|
</div>
|
|
</div>
|
|
|
</article>
|
|
</article>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <div v-else-if="packsLoading" class="ai-spin-placeholder" aria-hidden="true"></div>
|
|
|
<EmptyState
|
|
<EmptyState
|
|
|
v-else
|
|
v-else
|
|
|
title="还没有工具包"
|
|
title="还没有工具包"
|
|
@@ -213,6 +215,7 @@
|
|
|
</div>
|
|
</div>
|
|
|
</article>
|
|
</article>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <div v-else-if="loading" class="ai-spin-placeholder" aria-hidden="true"></div>
|
|
|
<EmptyState
|
|
<EmptyState
|
|
|
v-else
|
|
v-else
|
|
|
:title="tools.length ? '没有匹配的工具' : '还没有同步到工具清单'"
|
|
:title="tools.length ? '没有匹配的工具' : '还没有同步到工具清单'"
|
|
@@ -363,7 +366,7 @@
|
|
|
</div>
|
|
</div>
|
|
|
</a-modal>
|
|
</a-modal>
|
|
|
|
|
|
|
|
- <!-- 弹框:新增 / 编辑技能(SKILL.md + scripts/ references/ assets/ testcases/ 附属文件) -->
|
|
|
|
|
|
|
+ <!-- 弹框:新增 / 编辑技能(SKILL.md + scripts/ references/ 附属文件) -->
|
|
|
<SkillEditorModal
|
|
<SkillEditorModal
|
|
|
v-model:open="skillCreateOpen"
|
|
v-model:open="skillCreateOpen"
|
|
|
:existing="skillNames"
|
|
:existing="skillNames"
|
|
@@ -372,7 +375,7 @@
|
|
|
/>
|
|
/>
|
|
|
|
|
|
|
|
<!-- 弹框:技能详情(只读,与「新增 / 编辑技能」同构) -->
|
|
<!-- 弹框:技能详情(只读,与「新增 / 编辑技能」同构) -->
|
|
|
- <SkillDetailModal v-model:open="skillOpen" :skill="skillViewing" :case-id="caseId" />
|
|
|
|
|
|
|
+ <SkillDetailModal v-model:open="skillOpen" :skill="skillViewing" />
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
@@ -394,7 +397,6 @@
|
|
|
import { EmptyState } from '@/core/components/EmptyState';
|
|
import { EmptyState } from '@/core/components/EmptyState';
|
|
|
import Icon from '@/core/components/Icon/src/Icon.vue';
|
|
import Icon from '@/core/components/Icon/src/Icon.vue';
|
|
|
import { useMessage } from '@/core/hooks/web/useMessage';
|
|
import { useMessage } from '@/core/hooks/web/useMessage';
|
|
|
- import { useUserStore } from '@/core/store/modules/case';
|
|
|
|
|
import { deleteSkill, installSkillZip, listSkills, listTools, toggleSkill } from '../../api/capabilityApi';
|
|
import { deleteSkill, installSkillZip, listSkills, listTools, toggleSkill } from '../../api/capabilityApi';
|
|
|
import { createToolPack, deleteToolPack, listToolPacks, updateToolPack } from '../../api/toolPackApi';
|
|
import { createToolPack, deleteToolPack, listToolPacks, updateToolPack } from '../../api/toolPackApi';
|
|
|
// 工具名 → 中文展示名。工具名是模型调用用的标识(英文),页面只显示中文,两者互不影响。
|
|
// 工具名 → 中文展示名。工具名是模型调用用的标识(英文),页面只显示中文,两者互不影响。
|
|
@@ -411,7 +413,6 @@
|
|
|
const ASwitch = Switch;
|
|
const ASwitch = Switch;
|
|
|
|
|
|
|
|
const { showMessage } = useMessage();
|
|
const { showMessage } = useMessage();
|
|
|
- const userStore = useUserStore();
|
|
|
|
|
|
|
|
|
|
type PluginTab = 'skill' | 'pack' | 'tool';
|
|
type PluginTab = 'skill' | 'pack' | 'tool';
|
|
|
const activeTab = ref<PluginTab>('skill');
|
|
const activeTab = ref<PluginTab>('skill');
|
|
@@ -438,7 +439,6 @@
|
|
|
const fileRef = ref<HTMLInputElement>();
|
|
const fileRef = ref<HTMLInputElement>();
|
|
|
|
|
|
|
|
/** 当前案件ID:只用于附带展示「该案件 agent 配置的只读技能仓库」,技能本身与案件无关 */
|
|
/** 当前案件ID:只用于附带展示「该案件 agent 配置的只读技能仓库」,技能本身与案件无关 */
|
|
|
- const caseId = computed(() => (userStore.getCaseInfo?.id ? String(userStore.getCaseInfo.id) : null));
|
|
|
|
|
|
|
|
|
|
const summary = computed(
|
|
const summary = computed(
|
|
|
() => `${skills.value.length} 个技能 · ${packs.value.length} 个工具包 · ${tools.value.length} 个工具`,
|
|
() => `${skills.value.length} 个技能 · ${packs.value.length} 个工具包 · ${tools.value.length} 个工具`,
|
|
@@ -526,7 +526,7 @@
|
|
|
try {
|
|
try {
|
|
|
const [toolList, skillList] = await Promise.all([
|
|
const [toolList, skillList] = await Promise.all([
|
|
|
listTools().catch(() => [] as AgentTool[]),
|
|
listTools().catch(() => [] as AgentTool[]),
|
|
|
- listSkills(caseId.value).catch(() => [] as Skill[]),
|
|
|
|
|
|
|
+ listSkills().catch(() => [] as Skill[]),
|
|
|
loadPacks(),
|
|
loadPacks(),
|
|
|
]);
|
|
]);
|
|
|
tools.value = toolList || [];
|
|
tools.value = toolList || [];
|
|
@@ -553,9 +553,7 @@
|
|
|
/* ---------------- 技能 ---------------- */
|
|
/* ---------------- 技能 ---------------- */
|
|
|
|
|
|
|
|
function sourceMeta(skill: Skill) {
|
|
function sourceMeta(skill: Skill) {
|
|
|
- return skill.source === 'repo'
|
|
|
|
|
- ? { label: '配置仓库', cls: '' }
|
|
|
|
|
- : { label: skill.managed ? '用户技能' : '技能', cls: '' };
|
|
|
|
|
|
|
+ return { label: skill.managed ? '我的技能' : '技能', cls: '' };
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -619,7 +617,7 @@
|
|
|
function confirmRemove(skill: Skill) {
|
|
function confirmRemove(skill: Skill) {
|
|
|
Modal.confirm({
|
|
Modal.confirm({
|
|
|
title: '卸载技能',
|
|
title: '卸载技能',
|
|
|
- content: `确认删除技能「${skill.name}」?该技能目录会被删除,且不可恢复。`,
|
|
|
|
|
|
|
+ content: `确认删除技能「${skill.name}」?技能与其附属文件会被删除,且不可恢复。`,
|
|
|
okText: '卸载',
|
|
okText: '卸载',
|
|
|
okType: 'primary',
|
|
okType: 'primary',
|
|
|
okButtonProps: { danger: true },
|
|
okButtonProps: { danger: true },
|