rebuild(runtime): govern market operations and job truth
This commit is contained in:
@@ -19,13 +19,21 @@ function number(value: number | null, digits = 2): string {
|
||||
</div>
|
||||
<span v-if="run" class="tag">{{ run.items.length }} 只</span>
|
||||
</header>
|
||||
<div v-if="run?.status === 'data_incomplete'" class="notice notice-warning">
|
||||
<div v-if="!run || run.status === 'pending'" class="screener-empty">
|
||||
<strong>盘后选股尚未执行</strong>
|
||||
<span>当日收盘行情定稿后由后台自动计算并归档。</span>
|
||||
</div>
|
||||
<div v-else-if="run.status === 'running'" class="screener-empty">
|
||||
<strong>正在计算候选结果</strong>
|
||||
<span>完成后会自动保存本次结果。</span>
|
||||
</div>
|
||||
<div v-else-if="run.status === 'data_incomplete'" class="notice notice-warning">
|
||||
数据尚不完整:{{ run.missing_fields.join("、") }}
|
||||
</div>
|
||||
<div v-else-if="run?.status === 'failed'" class="notice notice-warning">
|
||||
本次计算失败,已隔离该策略,不影响其他策略。
|
||||
<div v-else-if="run.status === 'failed'" class="notice notice-warning">
|
||||
本次计算失败,已隔离该策略,不影响其他策略。{{ run.error_message }}
|
||||
</div>
|
||||
<div v-else-if="!run || run.status === 'no_signal' || !run.items.length" class="screener-empty">
|
||||
<div v-else-if="run.status === 'no_signal' || !run.items.length" class="screener-empty">
|
||||
<strong>暂无符合条件个股</strong>
|
||||
<span>完整数据下无信号会保留为空,不补造候选。</span>
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,18 @@ const emit = defineEmits<{ track: [run: ScreenerRun, candidate: Candidate] }>();
|
||||
const selected = ref(props.runs[0]?.strategy_id ?? props.strategies[0]?.id ?? "");
|
||||
const run = computed(() => props.runs.find((item) => item.strategy_id === selected.value));
|
||||
const strategy = computed(() => props.strategies.find((item) => item.id === (run.value?.strategy_id ?? selected.value)));
|
||||
const hasRun = computed(() => Boolean(run.value));
|
||||
const runState = computed<"idle" | "running" | "failed" | "completed">(() => {
|
||||
if (!run.value || run.value.status === "pending") return "idle";
|
||||
if (run.value.status === "running") return "running";
|
||||
if (run.value.status === "failed") return "failed";
|
||||
return "completed";
|
||||
});
|
||||
const runStateLabel = computed(() => ({
|
||||
idle: "未执行",
|
||||
running: "执行中",
|
||||
failed: "失败",
|
||||
completed: "已完成",
|
||||
})[runState.value]);
|
||||
|
||||
watch(
|
||||
() => props.runs,
|
||||
@@ -26,10 +37,13 @@ watch(
|
||||
<header class="stage-heading">
|
||||
<div><span>当前阶段自动候选</span><strong>{{ strategy?.display_name ?? "等待盘后判定" }}</strong></div>
|
||||
<p>{{ strategy?.description ?? "每日收盘数据定稿后自动生成,结果允许为空。" }}</p>
|
||||
<span class="tag">盘后自动</span>
|
||||
<span class="tag" :class="{ warning: runState === 'failed' }">{{ runStateLabel }}</span>
|
||||
</header>
|
||||
<div class="stage-flow" aria-label="自动选股流程">
|
||||
<span :class="{ done: hasRun }">阶段识别</span><i></i><span :class="{ done: hasRun }">策略匹配</span><i></i><span :class="{ done: hasRun }">自动计算</span><i></i><span :class="{ done: hasRun }">结果归档</span>
|
||||
<span :class="{ done: runState !== 'idle' }">阶段识别</span><i></i>
|
||||
<span :class="{ done: runState !== 'idle' }">策略匹配</span><i></i>
|
||||
<span :class="{ done: runState === 'running' || runState === 'completed' }">自动计算</span><i></i>
|
||||
<span :class="{ done: runState === 'completed' }">结果归档</span>
|
||||
</div>
|
||||
<nav v-if="runs.length > 1" class="stage-run-tabs" aria-label="当日阶段策略">
|
||||
<button v-for="item in runs" :key="item.id" type="button" :class="{ active: selected === item.strategy_id }" @click="selected = item.strategy_id">{{ item.strategy_name }}</button>
|
||||
|
||||
@@ -18,6 +18,18 @@ const selected = ref(props.strategies[0]?.id ?? "");
|
||||
const strategy = computed(() => props.strategies.find((item) => item.id === selected.value) ?? filtered.value[0]);
|
||||
const run = computed(() => props.runs.find((item) => item.strategy_id === strategy.value?.id));
|
||||
const regimeLabels: Record<string, string> = { ice: "冰点", repair: "修复", fermentation: "发酵", climax: "高潮", divergence: "分化", retreat: "退潮" };
|
||||
|
||||
function statusLabel(strategyId: string): string {
|
||||
const status = props.runs.find((item) => item.strategy_id === strategyId)?.status;
|
||||
return ({
|
||||
pending: "未执行",
|
||||
running: "执行中",
|
||||
completed: "有候选",
|
||||
no_signal: "暂无信号",
|
||||
data_incomplete: "数据不足",
|
||||
failed: "计算失败",
|
||||
} as Record<string, string>)[status ?? "pending"] ?? "未执行";
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -32,7 +44,7 @@ const regimeLabels: Record<string, string> = { ice: "冰点", repair: "修复",
|
||||
<div class="strategy-items" :class="`is-${view}`">
|
||||
<button v-for="item in filtered" :key="item.id" type="button" :class="{ active: strategy?.id === item.id }" @click="selected = item.id">
|
||||
<strong>{{ item.display_name }}</strong><small>{{ item.formula.meta?.category }}</small>
|
||||
<span :class="['strategy-status', runs.find((run) => run.strategy_id === item.id)?.status]">{{ runs.find((run) => run.strategy_id === item.id)?.status === 'completed' ? '有候选' : runs.find((run) => run.strategy_id === item.id)?.status === 'data_incomplete' ? '数据不足' : '暂无信号' }}</span>
|
||||
<span :class="['strategy-status', runs.find((run) => run.strategy_id === item.id)?.status]">{{ statusLabel(item.id) }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
Reference in New Issue
Block a user