rebuild(stage-6): deliver emotion and market pools

This commit is contained in:
leefer
2026-07-30 03:03:53 +08:00
parent 889963862a
commit 59f6011ae8
30 changed files with 1751 additions and 9 deletions
+16 -1
View File
@@ -2,6 +2,7 @@
import { computed, onBeforeUnmount, onMounted, ref } from "vue";
import { useRoute, useRouter } from "vue-router";
import { marketApi } from "../../shared/api/market";
import { useMarketStore } from "../../shared/stores/market";
import { useSessionStore } from "../../shared/stores/session";
import { useUiStore } from "../../shared/stores/ui";
@@ -14,6 +15,7 @@ const session = useSessionStore();
const ui = useUiStore();
const menuOpen = ref(false);
const menuRoot = ref<HTMLElement | null>(null);
const refreshing = ref(false);
const title = computed(() => {
if (route.name === "system") return "系统管理";
@@ -56,6 +58,19 @@ async function endSession(action: "logout" | "switch-account"): Promise<void> {
}
}
async function refreshMarket(): Promise<void> {
if (refreshing.value) return;
refreshing.value = true;
try {
const result = await marketApi.syncSnapshot(market.selectedDate);
ui.showToast(`${result.trade_date} 行情快照已更新,刷新页面后读取新数据`);
} catch (error) {
ui.showToast(error instanceof Error ? error.message : "行情刷新失败,请稍后重试");
} finally {
refreshing.value = false;
}
}
onMounted(() => document.addEventListener("mousedown", closeOnOutside));
onBeforeUnmount(() => document.removeEventListener("mousedown", closeOnOutside));
</script>
@@ -74,7 +89,7 @@ onBeforeUnmount(() => document.removeEventListener("mousedown", closeOnOutside))
<button class="btn btn-small" type="button" :title="ui.theme === 'light' ? '切换夜间模式' : '切换日间模式'" @click="ui.toggleTheme">
{{ ui.theme === "light" ? "夜间" : "日间" }}
</button>
<button v-if="session.isAdmin" class="btn btn-small desktop-only" type="button" @click="ui.showToast('行情刷新任务暂不可用')">后台刷新</button>
<button v-if="session.isAdmin" class="btn btn-small desktop-only" type="button" :disabled="refreshing" @click="refreshMarket">{{ refreshing ? "刷新中" : "后台刷新" }}</button>
<button v-if="session.isAdmin" class="btn btn-small desktop-only" type="button" @click="router.push('/system')">系统管理</button>
<div class="identity-cluster">
<button v-if="session.isMember" class="tag tag-vip" type="button" title="查看会员状态" @click="ui.openDialog('membership')">V 会员</button>
@@ -3,6 +3,7 @@ import { computed } from "vue";
import { useRoute } from "vue-router";
import EmptyState from "../../shared/components/EmptyState.vue";
import MarketWorkspaceView from "../../pages/market/MarketWorkspaceView.vue";
import { useMarketStore } from "../../shared/stores/market";
import { useSessionStore } from "../../shared/stores/session";
import { useUiStore } from "../../shared/stores/ui";
@@ -16,10 +17,16 @@ const workspace = computed(() => findWorkspace(String(route.params.workspace)) ?
const locked = computed(
() => ["screener", "mentor", "heaven"].includes(workspace.value.key) && !session.account?.smart_access,
);
const implementedMarket = computed(() =>
["emotion", "pool", "broken", "limit-down", "yesterday", "performance"].includes(
workspace.value.key,
),
);
</script>
<template>
<main class="page-frame">
<MarketWorkspaceView v-if="implementedMarket" :workspace-key="workspace.key" />
<main v-else class="page-frame">
<header class="page-header">
<h1>{{ workspace.title }}</h1>
<p class="page-subtitle">{{ workspace.description }} · 数据日期 {{ market.selectedDate }}</p>