新增手动同步数据功能:点击侧边栏"同步数据"调用批量打分接口,完成后跳转打分列表并刷新

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
fish
2026-05-04 23:26:04 +08:00
parent a7e1c9f416
commit cff4319321
4 changed files with 45 additions and 1 deletions

View File

@@ -42,6 +42,20 @@ func (d *Deps) RunPipeline(w http.ResponseWriter, r *http.Request) {
_, _ = io.Copy(w, resp.Body) _, _ = io.Copy(w, resp.Body)
} }
func (d *Deps) RunBatch(w http.ResponseWriter, r *http.Request) {
client := &http.Client{Timeout: 120 * time.Second}
resp, err := client.Post(d.TushareURL+"/api/v1/run/batch", "application/json", nil)
if err != nil {
writeErr(w, http.StatusBadGateway, fmt.Sprintf("tushare service unavailable: %v", err))
return
}
defer resp.Body.Close()
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(resp.StatusCode)
_, _ = io.Copy(w, resp.Body)
}
func (d *Deps) GetActiveContract(w http.ResponseWriter, r *http.Request) { func (d *Deps) GetActiveContract(w http.ResponseWriter, r *http.Request) {
symbol := r.URL.Query().Get("symbol") symbol := r.URL.Query().Get("symbol")
if symbol == "" { if symbol == "" {

View File

@@ -31,6 +31,7 @@ func New(d *handlers.Deps, dist fs.FS) http.Handler {
r.Get("/contracts/active", d.GetActiveContract) r.Get("/contracts/active", d.GetActiveContract)
r.Get("/candles", d.ListCandles) r.Get("/candles", d.ListCandles)
r.Post("/run", d.RunPipeline) r.Post("/run", d.RunPipeline)
r.Post("/run/batch", d.RunBatch)
r.Group(func(r chi.Router) { r.Group(func(r chi.Router) {
r.Use(mw.RequireAdmin) r.Use(mw.RequireAdmin)

View File

@@ -6,6 +6,7 @@ import { useAuthStore } from '@/stores/auth'
import { useThemeStore } from '@/stores/theme' import { useThemeStore } from '@/stores/theme'
import { useMobile } from '@/composables/useMobile' import { useMobile } from '@/composables/useMobile'
import { resetAllData } from '@/api/admin' import { resetAllData } from '@/api/admin'
import { runBatch } from '@/api/run'
const auth = useAuthStore() const auth = useAuthStore()
const theme = useThemeStore() const theme = useThemeStore()
@@ -15,6 +16,7 @@ const { isMobile } = useMobile()
const drawerOpen = ref(false) const drawerOpen = ref(false)
const resetting = ref(false) const resetting = ref(false)
const syncing = ref(false)
const showLayout = computed(() => route.meta.layout !== 'blank' && !!auth.token) const showLayout = computed(() => route.meta.layout !== 'blank' && !!auth.token)
@@ -57,6 +59,23 @@ async function handleReset() {
resetting.value = false resetting.value = false
} }
} }
async function handleSync() {
syncing.value = true
try {
await runBatch()
ElMessage.success('同步完成')
if (route.path === '/scores') {
router.go(0)
} else {
router.push('/scores')
}
} catch {
ElMessage.error('同步失败')
} finally {
syncing.value = false
}
}
</script> </script>
<template> <template>
@@ -73,6 +92,9 @@ async function handleReset() {
> >
<el-menu-item index="/scores">打分列表</el-menu-item> <el-menu-item index="/scores">打分列表</el-menu-item>
<el-menu-item index="/chart">K 线 / 持仓</el-menu-item> <el-menu-item index="/chart">K 线 / 持仓</el-menu-item>
<el-menu-item :index="() => {}" @click="handleSync" :disabled="syncing">
同步数据
</el-menu-item>
<el-menu-item index="/run">手动打分</el-menu-item> <el-menu-item index="/run">手动打分</el-menu-item>
<el-menu-item v-if="auth.isAdmin" index="/admin/users">用户管理</el-menu-item> <el-menu-item v-if="auth.isAdmin" index="/admin/users">用户管理</el-menu-item>
<el-menu-item v-if="auth.isAdmin" :index="() => {}" @click="handleReset" :disabled="resetting"> <el-menu-item v-if="auth.isAdmin" :index="() => {}" @click="handleReset" :disabled="resetting">
@@ -100,6 +122,9 @@ async function handleReset() {
> >
<el-menu-item index="/scores">打分列表</el-menu-item> <el-menu-item index="/scores">打分列表</el-menu-item>
<el-menu-item index="/chart">K 线 / 持仓</el-menu-item> <el-menu-item index="/chart">K 线 / 持仓</el-menu-item>
<el-menu-item :index="() => {}" @click="handleSync" :disabled="syncing">
同步数据
</el-menu-item>
<el-menu-item index="/run">手动打分</el-menu-item> <el-menu-item index="/run">手动打分</el-menu-item>
<el-menu-item v-if="auth.isAdmin" index="/admin/users">用户管理</el-menu-item> <el-menu-item v-if="auth.isAdmin" index="/admin/users">用户管理</el-menu-item>
</el-menu> </el-menu>

View File

@@ -30,6 +30,10 @@ export function runPipeline(req: RunRequest) {
return client.post<RunResponse>('/run', req).then((r) => r.data) return client.post<RunResponse>('/run', req).then((r) => r.data)
} }
export function runBatch() {
return client.post('/run/batch').then((r) => r.data)
}
export function getActiveContract(symbol: string) { export function getActiveContract(symbol: string) {
return client return client
.get<ActiveContract>('/contracts/active', { params: { symbol } }) .get<ActiveContract>('/contracts/active', { params: { symbol } })