fix: 修复Skill.vue模板语法问题
- 将template标签改为div - 修复条件渲染语法 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -371,10 +371,10 @@ onMounted(() => {
|
|||||||
<div class="flex items-center justify-end gap-3 p-5 border-t border-dark-600 bg-dark-700/50">
|
<div class="flex items-center justify-end gap-3 p-5 border-t border-dark-600 bg-dark-700/50">
|
||||||
<button @click="closeImportDialog" class="btn-secondary">Cancel</button>
|
<button @click="closeImportDialog" class="btn-secondary">Cancel</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</div>
|
||||||
|
|
||||||
<!-- 第二步:编辑内容 -->
|
<!-- 第二步:编辑内容 -->
|
||||||
<template v-else>
|
<div v-else>
|
||||||
<div class="flex items-center justify-between p-5 border-b border-dark-600 bg-dark-700/50">
|
<div class="flex items-center justify-between p-5 border-b border-dark-600 bg-dark-700/50">
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<div class="w-10 h-10 rounded-xl bg-gradient-to-br from-blue-500 to-indigo-500 flex items-center justify-center">
|
<div class="w-10 h-10 rounded-xl bg-gradient-to-br from-blue-500 to-indigo-500 flex items-center justify-center">
|
||||||
@@ -408,7 +408,7 @@ onMounted(() => {
|
|||||||
{{ isImporting ? 'Importing...' : 'Import' }}
|
{{ isImporting ? 'Importing...' : 'Import' }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Teleport>
|
</Teleport>
|
||||||
|
|||||||
@@ -1,301 +0,0 @@
|
|||||||
import { ref, computed } from 'vue'
|
|
||||||
import { ElMessageBox, ElMessage } from 'element-plus'
|
|
||||||
|
|
||||||
const API_BASE = 'http://localhost:8082'
|
|
||||||
|
|
||||||
export interface Skill {
|
|
||||||
id: string
|
|
||||||
skill_name: string
|
|
||||||
skill_type: string
|
|
||||||
skill_desc: string
|
|
||||||
path: string
|
|
||||||
status: string
|
|
||||||
created_at?: string
|
|
||||||
updated_at?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useSkills() {
|
|
||||||
const skills = ref<Skill[]>([])
|
|
||||||
const skillsLoading = ref(false)
|
|
||||||
|
|
||||||
// 获取技能列表
|
|
||||||
const fetchSkills = async (type?: string) => {
|
|
||||||
skillsLoading.value = true
|
|
||||||
try {
|
|
||||||
let url = `${API_BASE}/skill/list`
|
|
||||||
if (type) {
|
|
||||||
url += `?type=${type}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch(url)
|
|
||||||
const result = await response.json()
|
|
||||||
|
|
||||||
if (result.list) {
|
|
||||||
skills.value = result.list.map((skill: any) => ({
|
|
||||||
id: skill.id,
|
|
||||||
skill_name: skill.skill_name,
|
|
||||||
skill_type: skill.skill_type,
|
|
||||||
skill_desc: skill.skill_desc || '',
|
|
||||||
path: skill.path || '',
|
|
||||||
status: skill.status || 'active',
|
|
||||||
created_at: skill.created_at,
|
|
||||||
updated_at: skill.updated_at,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
return result.list || []
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to fetch skills:', error)
|
|
||||||
return []
|
|
||||||
} finally {
|
|
||||||
skillsLoading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 同步技能
|
|
||||||
const syncSkills = async () => {
|
|
||||||
try {
|
|
||||||
const response = await fetch(`${API_BASE}/skill/sync`)
|
|
||||||
const data = await response.json()
|
|
||||||
await fetchSkills()
|
|
||||||
return data
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to sync skills:', error)
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取技能详情
|
|
||||||
const fetchSkillById = async (id: string) => {
|
|
||||||
try {
|
|
||||||
const response = await fetch(`${API_BASE}/skill/${id}`)
|
|
||||||
const data = await response.json()
|
|
||||||
return data.skill
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to fetch skill:', error)
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建技能
|
|
||||||
const createSkill = async (skill: Partial<Skill>) => {
|
|
||||||
try {
|
|
||||||
const response = await fetch(`${API_BASE}/skill/add`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify(skill),
|
|
||||||
})
|
|
||||||
const data = await response.json()
|
|
||||||
await fetchSkills()
|
|
||||||
return data
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to create skill:', error)
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新技能
|
|
||||||
const updateSkill = async (id: string, skill: Partial<Skill>) => {
|
|
||||||
try {
|
|
||||||
const response = await fetch(`${API_BASE}/skill/${id}`, {
|
|
||||||
method: 'PUT',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify(skill),
|
|
||||||
})
|
|
||||||
const data = await response.json()
|
|
||||||
await fetchSkills()
|
|
||||||
return data
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to update skill:', error)
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除技能
|
|
||||||
const deleteSkill = async (id: string) => {
|
|
||||||
try {
|
|
||||||
const response = await fetch(`${API_BASE}/skill/${id}`, {
|
|
||||||
method: 'DELETE',
|
|
||||||
})
|
|
||||||
const data = await response.json()
|
|
||||||
await fetchSkills()
|
|
||||||
return data
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to delete skill:', error)
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 按类型获取技能
|
|
||||||
const getSkillsByType = (type: string) => {
|
|
||||||
return skills.value.filter(skill => skill.skill_type === type)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取所有分类
|
|
||||||
const categories = computed(() => {
|
|
||||||
const cats = new Set(skills.value.map(skill => skill.skill_type))
|
|
||||||
return Array.from(cats)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 搜索和筛选
|
|
||||||
const searchQuery = ref('')
|
|
||||||
const filterStatus = ref('all')
|
|
||||||
|
|
||||||
// 编辑状态
|
|
||||||
const isEditing = ref(false)
|
|
||||||
const isCreating = ref(false)
|
|
||||||
const editingSkill = ref<Skill | null>(null)
|
|
||||||
|
|
||||||
// 表单
|
|
||||||
const editForm = ref({
|
|
||||||
skill_name: '',
|
|
||||||
skill_desc: '',
|
|
||||||
skill_type: 'user',
|
|
||||||
})
|
|
||||||
|
|
||||||
const newSkillForm = ref({
|
|
||||||
skill_name: '',
|
|
||||||
skill_desc: '',
|
|
||||||
skill_type: 'user',
|
|
||||||
})
|
|
||||||
|
|
||||||
// 筛选
|
|
||||||
const filteredSkills = computed(() => {
|
|
||||||
return skills.value.filter(skill => {
|
|
||||||
const matchSearch = skill.skill_name.toLowerCase().includes(searchQuery.value.toLowerCase()) ||
|
|
||||||
(skill.skill_desc && skill.skill_desc.toLowerCase().includes(searchQuery.value.toLowerCase()))
|
|
||||||
const matchStatus = filterStatus.value === 'all' || skill.status === filterStatus.value
|
|
||||||
return matchSearch && matchStatus
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// 状态样式
|
|
||||||
const statusClass = (status: string) => {
|
|
||||||
switch (status) {
|
|
||||||
case 'active': return 'bg-green-500'
|
|
||||||
case 'inactive': return 'bg-gray-500'
|
|
||||||
case 'error': return 'bg-red-500'
|
|
||||||
default: return 'bg-gray-500'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 打开创建弹窗
|
|
||||||
const openCreate = () => {
|
|
||||||
newSkillForm.value = { skill_name: '', skill_desc: '', skill_type: 'user' }
|
|
||||||
isCreating.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 关闭创建弹窗
|
|
||||||
const closeCreate = () => {
|
|
||||||
isCreating.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存新技能
|
|
||||||
const saveNewSkill = async () => {
|
|
||||||
try {
|
|
||||||
await createSkill({
|
|
||||||
skill_name: newSkillForm.value.skill_name,
|
|
||||||
skill_desc: newSkillForm.value.skill_desc,
|
|
||||||
skill_type: newSkillForm.value.skill_type,
|
|
||||||
status: 'active',
|
|
||||||
})
|
|
||||||
ElMessage.success('Skill created successfully')
|
|
||||||
isCreating.value = false
|
|
||||||
} catch (error) {
|
|
||||||
ElMessage.error('Failed to create skill')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 打开编辑弹窗
|
|
||||||
const openEdit = (skill: Skill) => {
|
|
||||||
editingSkill.value = skill
|
|
||||||
editForm.value = {
|
|
||||||
skill_name: skill.skill_name,
|
|
||||||
skill_desc: skill.skill_desc,
|
|
||||||
skill_type: skill.skill_type,
|
|
||||||
}
|
|
||||||
isEditing.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 关闭编辑弹窗
|
|
||||||
const closeEdit = () => {
|
|
||||||
isEditing.value = false
|
|
||||||
editingSkill.value = null
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存编辑
|
|
||||||
const saveEdit = async () => {
|
|
||||||
try {
|
|
||||||
await updateSkill(editingSkill.value!.id, {
|
|
||||||
skill_name: editForm.value.skill_name,
|
|
||||||
skill_desc: editForm.value.skill_desc,
|
|
||||||
skill_type: editForm.value.skill_type,
|
|
||||||
})
|
|
||||||
ElMessage.success('Skill updated successfully')
|
|
||||||
isEditing.value = false
|
|
||||||
} catch (error) {
|
|
||||||
ElMessage.error('Failed to update skill')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 切换状态
|
|
||||||
const toggleStatus = async (skill: Skill) => {
|
|
||||||
const newStatus = skill.status === 'active' ? 'inactive' : 'active'
|
|
||||||
try {
|
|
||||||
await updateSkill(skill.id, { status: newStatus })
|
|
||||||
skill.status = newStatus
|
|
||||||
} catch (error) {
|
|
||||||
ElMessage.error('Failed to update status')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除技能
|
|
||||||
const handleDeleteSkill = async (id: string) => {
|
|
||||||
try {
|
|
||||||
await ElMessageBox.confirm('Are you sure you want to delete this skill?', 'Confirm Delete', {
|
|
||||||
confirmButtonText: 'Delete',
|
|
||||||
cancelButtonText: 'Cancel',
|
|
||||||
type: 'warning',
|
|
||||||
})
|
|
||||||
|
|
||||||
await deleteSkill(id)
|
|
||||||
ElMessage.success('Skill deleted successfully')
|
|
||||||
} catch (error: any) {
|
|
||||||
if (error !== 'cancel') {
|
|
||||||
console.error('Failed to delete skill:', error)
|
|
||||||
ElMessage.error('Failed to delete skill')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
// State
|
|
||||||
skills,
|
|
||||||
skillsLoading,
|
|
||||||
searchQuery,
|
|
||||||
filterStatus,
|
|
||||||
isEditing,
|
|
||||||
isCreating,
|
|
||||||
editingSkill,
|
|
||||||
editForm,
|
|
||||||
newSkillForm,
|
|
||||||
categories,
|
|
||||||
// Computed
|
|
||||||
filteredSkills,
|
|
||||||
// Methods
|
|
||||||
fetchSkills,
|
|
||||||
syncSkills,
|
|
||||||
statusClass,
|
|
||||||
openCreate,
|
|
||||||
closeCreate,
|
|
||||||
saveNewSkill,
|
|
||||||
openEdit,
|
|
||||||
closeEdit,
|
|
||||||
saveEdit,
|
|
||||||
toggleStatus,
|
|
||||||
deleteSkill: handleDeleteSkill,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user