Merge branch 'feat/neo-skill-self-iteration' of https://github.com/w31r4/AstrBot into feat/neo-skill-self-iteration

This commit is contained in:
RC-CHN
2026-03-02 09:37:42 +08:00
3 changed files with 39 additions and 4 deletions
@@ -113,7 +113,7 @@
<div class="d-flex flex-wrap justify-space-between align-center ga-2 mb-3">
<div>
<div class="text-subtitle-1 font-weight-bold">Neo Skills</div>
<div class="text-caption text-medium-emphasis">筛选候选与发布记录</div>
<div class="text-caption text-medium-emphasis">{{ tm("skills.neoFilterHint") }}</div>
</div>
<v-btn color="primary" prepend-icon="mdi-refresh" variant="flat" @click="fetchNeoData">
{{ tm("skills.refresh") }}
@@ -188,10 +188,24 @@
<v-btn size="x-small" color="warning" variant="tonal" @click="evaluateCandidate(item, false)">
{{ tm("skills.neoReject") }}
</v-btn>
<v-btn size="x-small" color="primary" variant="tonal" @click="promoteCandidate(item, 'canary')">
<v-btn
size="x-small"
color="primary"
variant="tonal"
:loading="isCandidatePromoteLoading(item.id, 'canary')"
:disabled="isCandidatePromoting(item.id)"
@click="promoteCandidate(item, 'canary')"
>
Canary
</v-btn>
<v-btn size="x-small" color="primary" variant="tonal" @click="promoteCandidate(item, 'stable')">
<v-btn
size="x-small"
color="primary"
variant="tonal"
:loading="isCandidatePromoteLoading(item.id, 'stable')"
:disabled="isCandidatePromoting(item.id)"
@click="promoteCandidate(item, 'stable')"
>
Stable
</v-btn>
<v-btn
@@ -347,6 +361,7 @@ export default {
status: "",
stage: "",
});
const candidatePromoteLoading = reactive({});
const payloadDialog = reactive({
show: false,
content: "",
@@ -631,10 +646,21 @@ export default {
}
};
const candidatePromoteLoadingKey = (candidateId, stage) => `${candidateId}:${stage}`;
const isCandidatePromoteLoading = (candidateId, stage) =>
!!candidatePromoteLoading[candidatePromoteLoadingKey(candidateId, stage)];
const isCandidatePromoting = (candidateId) =>
isCandidatePromoteLoading(candidateId, "canary") || isCandidatePromoteLoading(candidateId, "stable");
const promoteCandidate = async (candidate, stage) => {
const candidateId = candidate?.id;
if (!candidateId) return;
const loadingKey = candidatePromoteLoadingKey(candidateId, stage);
if (candidatePromoteLoading[loadingKey]) return;
candidatePromoteLoading[loadingKey] = true;
try {
const res = await axios.post("/api/skills/neo/promote", {
candidate_id: candidate.id,
candidate_id: candidateId,
stage,
sync_to_local: true,
});
@@ -650,6 +676,8 @@ export default {
}
} catch (_err) {
showMessage(tm("skills.neoPromoteFailed"), "error");
} finally {
candidatePromoteLoading[loadingKey] = false;
}
};
@@ -818,6 +846,8 @@ export default {
deleteSkill,
evaluateCandidate,
promoteCandidate,
isCandidatePromoteLoading,
isCandidatePromoting,
rollbackRelease,
deactivateRelease,
handleReleaseLifecycleAction,
@@ -245,6 +245,7 @@
"neoSkillKey": "Filter by skill_key",
"neoStatus": "Candidate Status",
"neoStage": "Release Stage",
"neoFilterHint": "Filter candidates and release records",
"neoAll": "All",
"neoCandidates": "Neo Candidates",
"neoReleases": "Neo Releases",
@@ -258,6 +259,9 @@
"neoRollback": "Rollback",
"neoRollbackSuccess": "Rollback succeeded",
"neoRollbackFailed": "Rollback failed",
"neoDeactivate": "Deactivate",
"neoDeactivateSuccess": "Deactivated successfully",
"neoDeactivateFailed": "Failed to deactivate",
"neoSync": "Sync",
"neoSyncSuccess": "Sync succeeded",
"neoSyncFailed": "Sync failed",
@@ -245,6 +245,7 @@
"neoSkillKey": "skill_key 过滤",
"neoStatus": "候选状态",
"neoStage": "发布阶段",
"neoFilterHint": "筛选候选与发布记录",
"neoAll": "全部",
"neoCandidates": "Neo Candidates",
"neoReleases": "Neo Releases",