quant_test / web_development /frontend /src /views /ServicesView.vue
lucky-loster's picture
Upload folder using huggingface_hub
590a501 verified
Raw
History Blame Contribute Delete
5.91 kB
<template>
<div class="services-view">
<div class="page-header">
<h2>服务控制台</h2>
<p>按功能模块启动 / 停止 — 期货仿真、Qlib 因子研究、前端界面</p>
</div>
<el-row :gutter="16" class="summary-row">
<el-col :span="6" v-for="item in summaryCards" :key="item.label">
<el-card shadow="hover" class="summary-card">
<div class="summary-label">{{ item.label }}</div>
<div class="summary-value" :class="item.class">{{ item.value }}</div>
</el-card>
</el-col>
</el-row>
<el-card shadow="never" class="table-card">
<template #header>
<div class="card-header">
<span>功能模块</span>
<el-button size="small" :loading="loading" @click="loadServices">刷新</el-button>
</div>
</template>
<el-table :data="services" v-loading="loading" stripe>
<el-table-column prop="name" label="模块" width="180" />
<el-table-column prop="description" label="说明" min-width="280" />
<el-table-column label="状态" width="120">
<template #default="{ row }">
<el-tag :type="statusType(row.status)" size="small">{{ statusText(row.status) }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="port" label="端口" width="90">
<template #default="{ row }">{{ row.port || '—' }}</template>
</el-table-column>
<el-table-column label="操作" width="220" fixed="right">
<template #default="{ row }">
<el-button
size="small"
type="primary"
:disabled="row.status === 'running'"
:loading="actionId === row.id && actionType === 'start'"
@click="startService(row.id)"
>启动</el-button>
<el-button
size="small"
type="danger"
plain
:disabled="row.status !== 'running'"
:loading="actionId === row.id && actionType === 'stop'"
@click="stopService(row.id)"
>停止</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<el-card shadow="never" class="hint-card">
<template #header>使用说明</template>
<ul class="hint-list">
<li><strong>期货行情</strong>:启动后 Dashboard / 行情页可获取模拟合约数据</li>
<li><strong>期货策略引擎</strong>:启动后可在「策略管理」运行 MA / 布林带 / DualThrust</li>
<li><strong>Qlib 因子研究</strong>:启动后可在「因子研究」查看注册因子、算子库、策略列表</li>
<li><strong>前端界面</strong>:本页面即 Vue 开发服务器;生产环境请 <code>npm run build</code></li>
</ul>
</el-card>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { platformApi } from '../api'
const services = ref([])
const loading = ref(false)
const actionId = ref('')
const actionType = ref('')
const summaryCards = computed(() => {
const total = services.value.length
const running = services.value.filter(s => s.status === 'running').length
const stopped = services.value.filter(s => s.status === 'stopped').length
const error = services.value.filter(s => s.status === 'error').length
return [
{ label: '模块总数', value: total, class: '' },
{ label: '运行中', value: running, class: 'text-success' },
{ label: '已停止', value: stopped, class: 'text-muted' },
{ label: '异常', value: error, class: 'text-danger' },
]
})
function statusType(status) {
if (status === 'running') return 'success'
if (status === 'error') return 'danger'
return 'info'
}
function statusText(status) {
const map = { running: '运行中', stopped: '已停止', error: '异常', starting: '启动中' }
return map[status] || status
}
async function loadServices() {
loading.value = true
try {
const res = await platformApi.listServices()
services.value = res.data.services || []
} catch (e) {
ElMessage.error('加载服务列表失败')
} finally {
loading.value = false
}
}
async function startService(id) {
actionId.value = id
actionType.value = 'start'
try {
const res = await platformApi.startService(id)
services.value = res.data.services || services.value
ElMessage.success(res.data.message || '已启动')
} catch (e) {
ElMessage.error(e.response?.data?.detail || '启动失败')
} finally {
actionId.value = ''
actionType.value = ''
}
}
async function stopService(id) {
actionId.value = id
actionType.value = 'stop'
try {
const res = await platformApi.stopService(id)
services.value = res.data.services || services.value
ElMessage.success(res.data.message || '已停止')
} catch (e) {
ElMessage.error(e.response?.data?.detail || '停止失败')
} finally {
actionId.value = ''
actionType.value = ''
}
}
onMounted(loadServices)
</script>
<style scoped>
.services-view { padding: 0 4px; }
.page-header { margin-bottom: 20px; }
.page-header h2 { margin: 0 0 8px; font-size: 22px; }
.page-header p { margin: 0; color: #909399; font-size: 14px; }
.summary-row { margin-bottom: 16px; }
.summary-card { text-align: center; }
.summary-label { font-size: 13px; color: #909399; margin-bottom: 8px; }
.summary-value { font-size: 28px; font-weight: 600; }
.text-success { color: #67c23a; }
.text-danger { color: #f56c6c; }
.text-muted { color: #909399; }
.card-header { display: flex; justify-content: space-between; align-items: center; }
.table-card { margin-bottom: 16px; }
.hint-list { margin: 0; padding-left: 20px; line-height: 1.8; color: #606266; }
.hint-list code { background: #f5f7fa; padding: 2px 6px; border-radius: 4px; }
</style>