fix(frontend): #91+#92+#93验收三连修——#91:实例编辑保存变新建(onSave无论编辑/新建都POST=建新重复实例;改带editId走PUT /strategy/instances/{id},payload补type按所选文件判定防PUT全量替换把组合实例改写cta;成功提示清(mock)残留文案)+卡片标的行整体移除(#86a实例不承载标的,存量all显示误导);#92:标的池显示统一——constants/strategy.ts新增POOL_LABELS+poolLabel(all→全市场/hs300_subset→HS300子集/ZZ500→中证500等),任务列表标的列+模拟盘列表symbolsShort全走映射(股票代码原样);#93:新建模拟盘加名字只读预览(对齐实盘:选实例后显{实例名}_v{YYYYMMDD}{minor},未选显占位提示);build绿(vue-tsc) [nas]
This commit is contained in:
@@ -17,3 +17,21 @@ export function strategyLabel(fileName: string): string {
|
||||
const key = fileName.replace(/\.py$/, '')
|
||||
return STRATEGY_LABELS[key] || key
|
||||
}
|
||||
|
||||
// 标的池显示名(#92 全链路统一:任务列表/模拟盘列表等不显裸值 all/hs300_subset,
|
||||
// 下拉当时选的什么 label 就显示什么)
|
||||
export const POOL_LABELS: Record<string, string> = {
|
||||
hs300_subset: 'HS300 子集',
|
||||
all: '全市场',
|
||||
HS300: '沪深300',
|
||||
ZZ500: '中证500',
|
||||
ZZ1000: '中证1000',
|
||||
ZZ2000: '中证2000',
|
||||
ALL: '全市场',
|
||||
}
|
||||
|
||||
/** 池值 → 显示名;非池值(股票代码等)原样返回 */
|
||||
export function poolLabel(value: string): string {
|
||||
const v = (value || '').trim()
|
||||
return POOL_LABELS[v] || v
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { ref, computed, watch, onMounted, onUnmounted } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { getTasks, getTaskParams, deleteTask, type TaskListItem } from '@/api/backtest'
|
||||
import { poolLabel } from '@/constants/strategy'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
@@ -270,7 +271,9 @@ function durationText(row: TaskListItem): string {
|
||||
<template #default="{ row }"><span class="chip" :class="`chip-${row.type}`">{{ typeLabel(row.type) }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="strategy" label="策略 / 因子" min-width="130" show-overflow-tooltip />
|
||||
<el-table-column prop="symbol" label="标的" width="130" />
|
||||
<el-table-column label="标的" width="130">
|
||||
<template #default="{ row }">{{ poolLabel(row.symbol) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="88">
|
||||
<template #default="{ row }"><span class="chip" :class="`st-${row.status}`">{{ statusLabel(row.status) }}</span></template>
|
||||
</el-table-column>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import CodeSnapshotDrawer from '@/views/strategy/CodeSnapshotDrawer.vue'
|
||||
import { poolLabel } from '@/constants/strategy'
|
||||
import {
|
||||
listPapers, stopPaper, resumePaper, deletePaper, updatePaper,
|
||||
type PaperAccount,
|
||||
@@ -83,7 +84,9 @@ function symbolsShort(s: string | undefined): string {
|
||||
arr = String(s).split(',').map((x) => x.trim())
|
||||
}
|
||||
if (!arr.length) return '—'
|
||||
return arr.length > 3 ? arr.slice(0, 3).join(',') + ` +${arr.length - 3}` : arr.join(',')
|
||||
// #92: 池值显中文 label(组合账户 symbols=["all"] → 全市场),股票代码原样
|
||||
const shown = arr.map(poolLabel)
|
||||
return shown.length > 3 ? shown.slice(0, 3).join(',') + ` +${shown.length - 3}` : shown.join(',')
|
||||
}
|
||||
const typeLabel: Record<string, string> = { cta: '个股', portfolio: '组合' }
|
||||
function open(a: PaperAccount): void {
|
||||
|
||||
@@ -273,6 +273,12 @@ function onSymbols(v: string): void {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- #93: 名字只读预览(对齐实盘):autoName 选实例后生成,格式 {实例名}_v{YYYYMMDD}{minor} -->
|
||||
<div style="margin-top:16px">
|
||||
<span class="seg-label" style="margin-right:10px">模拟盘名称</span>
|
||||
<span class="mono" style="font-size:13px;color:var(--brand)">{{ form.name || '—(选实例后自动生成)' }}</span>
|
||||
</div>
|
||||
|
||||
</el-card>
|
||||
|
||||
<el-card class="blk" shadow="never">
|
||||
|
||||
@@ -115,16 +115,24 @@ async function onSave(): Promise<void> {
|
||||
})
|
||||
saving.value = true
|
||||
try {
|
||||
await apiClient.post('/strategy/instances', {
|
||||
id: editId.value,
|
||||
const payload = {
|
||||
code_file: form.code_file,
|
||||
name: form.name,
|
||||
// PUT 全量替换:type 按所选文件判定(漏传会被默认 cta 覆盖组合实例)
|
||||
type: selectedCode.value?.type || 'cta',
|
||||
params,
|
||||
symbol_or_pool: form.symbol_or_pool,
|
||||
interval: form.interval,
|
||||
match_session: form.match_session,
|
||||
})
|
||||
ElMessage.success(isEdit.value ? '实例已更新(mock)' : '实例已创建(mock)')
|
||||
}
|
||||
// #91 编辑必须走 PUT:POST 恒为新建(原实现编辑保存再点就多出一个重复实例)
|
||||
if (isEdit.value && editId.value) {
|
||||
await apiClient.put(`/strategy/instances/${editId.value}`, payload)
|
||||
ElMessage.success('实例已更新')
|
||||
} else {
|
||||
await apiClient.post('/strategy/instances', payload)
|
||||
ElMessage.success('实例已创建')
|
||||
}
|
||||
router.push('/strategy')
|
||||
} catch {
|
||||
ElMessage.error('保存失败')
|
||||
|
||||
@@ -318,7 +318,7 @@ const runningRows = computed(() =>
|
||||
<span class="sub mono">#{{ i.id }} · {{ i.interval }} · 更新 {{ i.updated_at }}</span>
|
||||
</div>
|
||||
<div class="params mono muted">{{ paramSummary(i.params) }}</div>
|
||||
<div class="sym mono">{{ i.symbol_or_pool || '—(发起时定)' }}</div>
|
||||
<!-- #91: 标的行移除——#86a 定稿实例不承载标的(发起时定),老实例存量值显示只会误导 -->
|
||||
<div class="ret mono" :class="retClass(latestRet(i))">{{ pct(latestRet(i)) }}<span class="sub">{{ retInfoOf(i).label }}</span></div>
|
||||
<div class="runs">
|
||||
<button class="run-btn" @click="runGo(i, 'backtest')"><span class="lamp" :class="lampOf(i.status.backtest)"></span>回测{{ badge(i, 'backtest') }}</button>
|
||||
|
||||
Reference in New Issue
Block a user