first commit
This commit is contained in:
300
frontend/src/views/AlgorithmsView.vue
Normal file
300
frontend/src/views/AlgorithmsView.vue
Normal file
@@ -0,0 +1,300 @@
|
||||
<template>
|
||||
<div class="algorithms-container">
|
||||
<!-- 页面标题 -->
|
||||
<h1>算法列表</h1>
|
||||
|
||||
<!-- 筛选和搜索 -->
|
||||
<div class="filter-section">
|
||||
<el-form :inline="true" class="filter-form">
|
||||
<el-form-item label="算法类型">
|
||||
<el-select v-model="selectedType" placeholder="选择算法类型" @change="handleTypeChange">
|
||||
<el-option label="全部" value="" />
|
||||
<el-option label="边缘计算" value="edge_computing" />
|
||||
<el-option label="医疗算法" value="medical" />
|
||||
<el-option label="计算机视觉" value="computer_vision" />
|
||||
<el-option label="自然语言处理" value="nlp" />
|
||||
<el-option label="机器学习" value="ml" />
|
||||
<el-option label="强化学习" value="reinforcement_learning" />
|
||||
<el-option label="自动驾驶算法" value="autonomous_driving" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="搜索">
|
||||
<el-input
|
||||
v-model="searchKeyword"
|
||||
placeholder="输入算法名称或描述"
|
||||
clearable
|
||||
@keyup.enter="handleSearch"
|
||||
>
|
||||
<template #append>
|
||||
<el-button @click="handleSearch"><el-icon><search /></el-icon></el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 算法列表 -->
|
||||
<div class="algorithms-list">
|
||||
<el-loading v-if="algorithmStore.loading" :fullscreen="true" text="加载中..." />
|
||||
|
||||
<div v-else-if="algorithmStore.algorithms.length === 0" class="empty-state">
|
||||
<el-icon class="empty-icon"><document /></el-icon>
|
||||
<p>暂无算法数据</p>
|
||||
</div>
|
||||
|
||||
<el-card v-else v-for="algorithm in filteredAlgorithms" :key="algorithm.id" class="algorithm-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<h2>{{ algorithm.name }}</h2>
|
||||
<span class="algorithm-type">{{ getAlgorithmTypeName(algorithm.type) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="card-body">
|
||||
<p class="algorithm-description">{{ algorithm.description }}</p>
|
||||
|
||||
<div class="algorithm-meta">
|
||||
<span class="meta-item">
|
||||
<el-icon><time /></el-icon>
|
||||
创建时间: {{ formatDate(algorithm.created_at) }}
|
||||
</span>
|
||||
<span class="meta-item">
|
||||
<el-icon><folder /></el-icon>
|
||||
版本数: {{ algorithm.versions.length }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="card-actions">
|
||||
<router-link :to="`/algorithm/${algorithm.id}`" class="detail-btn">
|
||||
<el-button type="primary" size="small">查看详情</el-button>
|
||||
</router-link>
|
||||
<router-link :to="`/algorithm/${algorithm.id}/call`" class="call-btn">
|
||||
<el-button type="success" size="small">立即调用</el-button>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-section">
|
||||
<el-pagination
|
||||
v-if="algorithmStore.algorithms.length > 0"
|
||||
layout="prev, pager, next"
|
||||
:total="algorithmStore.algorithms.length"
|
||||
:page-size="pageSize"
|
||||
:current-page="currentPage"
|
||||
@current-change="handlePageChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { useAlgorithmStore } from '../stores/algorithm'
|
||||
import { Search, Time, Folder, Document } from '@element-plus/icons-vue'
|
||||
|
||||
// 获取算法存储
|
||||
const algorithmStore = useAlgorithmStore()
|
||||
|
||||
// 筛选和分页
|
||||
const selectedType = ref('')
|
||||
const searchKeyword = ref('')
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
|
||||
// 算法类型映射
|
||||
const algorithmTypes = {
|
||||
computer_vision: '计算机视觉',
|
||||
nlp: '自然语言处理',
|
||||
ml: '机器学习',
|
||||
reinforcement_learning: '强化学习',
|
||||
edge_computing: '边缘计算',
|
||||
medical: '医疗算法',
|
||||
autonomous_driving: '自动驾驶算法'
|
||||
}
|
||||
|
||||
// 获取算法类型的中文名称
|
||||
const getAlgorithmTypeName = (type: string) => {
|
||||
return algorithmTypes[type as keyof typeof algorithmTypes] || type
|
||||
}
|
||||
|
||||
// 筛选算法
|
||||
const filteredAlgorithms = computed(() => {
|
||||
let algorithms = algorithmStore.algorithms
|
||||
|
||||
// 按类型筛选
|
||||
if (selectedType.value) {
|
||||
algorithms = algorithms.filter(algorithm => algorithm.type === selectedType.value)
|
||||
}
|
||||
|
||||
// 按关键词搜索
|
||||
if (searchKeyword.value) {
|
||||
const keyword = searchKeyword.value.toLowerCase()
|
||||
algorithms = algorithms.filter(algorithm =>
|
||||
algorithm.name.toLowerCase().includes(keyword) ||
|
||||
algorithm.description.toLowerCase().includes(keyword)
|
||||
)
|
||||
}
|
||||
|
||||
// 分页
|
||||
const start = (currentPage.value - 1) * pageSize.value
|
||||
const end = start + pageSize.value
|
||||
return algorithms.slice(start, end)
|
||||
})
|
||||
|
||||
// 处理类型变更
|
||||
const handleTypeChange = () => {
|
||||
currentPage.value = 1
|
||||
}
|
||||
|
||||
// 处理搜索
|
||||
const handleSearch = () => {
|
||||
currentPage.value = 1
|
||||
}
|
||||
|
||||
// 处理分页变更
|
||||
const handlePageChange = (page: number) => {
|
||||
currentPage.value = page
|
||||
}
|
||||
|
||||
// 格式化日期
|
||||
const formatDate = (dateString: string) => {
|
||||
const date = new Date(dateString)
|
||||
return date.toLocaleString()
|
||||
}
|
||||
|
||||
// 加载算法列表
|
||||
onMounted(async () => {
|
||||
await algorithmStore.fetchAlgorithms()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.algorithms-container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.algorithms-container h1 {
|
||||
font-size: 28px;
|
||||
margin-bottom: 30px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.filter-section {
|
||||
margin-bottom: 30px;
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.filter-form {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.algorithms-list {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 60px 0;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 64px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.algorithm-card {
|
||||
margin-bottom: 20px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.algorithm-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.card-header h2 {
|
||||
font-size: 20px;
|
||||
margin: 0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.algorithm-type {
|
||||
padding: 4px 12px;
|
||||
background-color: #ecf5ff;
|
||||
color: #409EFF;
|
||||
border-radius: 16px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.algorithm-description {
|
||||
color: #606266;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.algorithm-meta {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-bottom: 20px;
|
||||
font-size: 14px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.meta-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.card-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.pagination-section {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.filter-form {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.algorithm-meta {
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.card-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.card-actions a {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user