184 lines
5.4 KiB
Vue
184 lines
5.4 KiB
Vue
<script setup lang="ts">
|
|
import { onMounted, reactive, ref } from 'vue'
|
|
import { listContracts, listScores, type Score } from '@/api/scores'
|
|
import ScoreDetailDrawer from '@/components/ScoreDetailDrawer.vue'
|
|
import { parseTsCode } from '@/utils/contract'
|
|
|
|
const filter = reactive<{
|
|
ts_code?: string
|
|
range: [string, string] | []
|
|
signal?: string
|
|
limit: number
|
|
}>({
|
|
ts_code: undefined,
|
|
range: [],
|
|
signal: undefined,
|
|
limit: 200,
|
|
})
|
|
|
|
const contracts = ref<string[]>([])
|
|
const rows = ref<Score[]>([])
|
|
const loading = ref(false)
|
|
const drawerScoreId = ref<number | null>(null)
|
|
|
|
async function reload() {
|
|
loading.value = true
|
|
try {
|
|
const [start, end] = filter.range || []
|
|
rows.value = await listScores({
|
|
ts_code: filter.ts_code,
|
|
start: start || undefined,
|
|
end: end || undefined,
|
|
signal: filter.signal,
|
|
limit: filter.limit,
|
|
})
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
function toggleSignal(s: string) {
|
|
filter.signal = filter.signal === s ? undefined : s
|
|
reload()
|
|
}
|
|
|
|
function signalTagType(s: string) {
|
|
if (s.includes('强烈看多')) return 'success'
|
|
if (s.includes('偏多')) return ''
|
|
if (s.includes('偏空')) return 'warning'
|
|
if (s.includes('强烈看空')) return 'danger'
|
|
return 'info'
|
|
}
|
|
|
|
onMounted(async () => {
|
|
contracts.value = await listContracts().catch(() => [])
|
|
await reload()
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div class="page">
|
|
<el-card shadow="never" class="filter-card">
|
|
<el-form :inline="true">
|
|
<el-form-item label="合约">
|
|
<el-select
|
|
v-model="filter.ts_code"
|
|
placeholder="全部合约"
|
|
clearable
|
|
filterable
|
|
style="width: 200px"
|
|
>
|
|
<el-option v-for="c in contracts" :key="c" :label="c" :value="c" />
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item label="日期">
|
|
<el-date-picker
|
|
v-model="filter.range"
|
|
type="daterange"
|
|
value-format="YYYYMMDD"
|
|
range-separator="→"
|
|
start-placeholder="起"
|
|
end-placeholder="止"
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item label="条数">
|
|
<el-input-number v-model="filter.limit" :min="10" :max="500" :step="50" />
|
|
</el-form-item>
|
|
<el-form-item>
|
|
<el-button type="primary" :loading="loading" @click="reload">查询</el-button>
|
|
</el-form-item>
|
|
<el-form-item label="快捷">
|
|
<el-button-group class="signal-group">
|
|
<el-button
|
|
:type="filter.signal === '强烈看多' ? 'success' : ''"
|
|
@click="toggleSignal('强烈看多')"
|
|
>
|
|
强烈看多
|
|
</el-button>
|
|
<el-button
|
|
:type="filter.signal === '偏多' ? 'primary' : ''"
|
|
@click="toggleSignal('偏多')"
|
|
>
|
|
偏多
|
|
</el-button>
|
|
<el-button
|
|
:type="filter.signal === '偏空' ? 'warning' : ''"
|
|
@click="toggleSignal('偏空')"
|
|
>
|
|
偏空
|
|
</el-button>
|
|
<el-button
|
|
:type="filter.signal === '强烈看空' ? 'danger' : ''"
|
|
@click="toggleSignal('强烈看空')"
|
|
>
|
|
强烈看空
|
|
</el-button>
|
|
</el-button-group>
|
|
</el-form-item>
|
|
</el-form>
|
|
</el-card>
|
|
|
|
<el-table :data="rows" v-loading="loading" stripe class="score-table">
|
|
<el-table-column prop="trade_date" label="日期" width="100" />
|
|
<el-table-column label="品种" width="80">
|
|
<template #default="{ row }">
|
|
{{ parseTsCode(row.ts_code).symbol }}
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="合约" width="80">
|
|
<template #default="{ row }">
|
|
{{ parseTsCode(row.ts_code).contract }}
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="close" label="收盘" width="90" />
|
|
<el-table-column prop="oi" label="持仓" width="100" />
|
|
<el-table-column prop="oi_chg" label="持仓变化" width="100" />
|
|
<el-table-column prop="short_term" label="短期(7d)" width="90" />
|
|
<el-table-column prop="medium_term" label="中期(15d)" width="90" />
|
|
<el-table-column prop="long_term" label="长期(30d)" width="90" />
|
|
<el-table-column prop="composite" label="综合" width="80">
|
|
<template #default="{ row }">
|
|
<strong>{{ row.composite.toFixed(2) }}</strong>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="signal" label="信号" min-width="160">
|
|
<template #default="{ row }">
|
|
<el-tag :type="signalTagType(row.signal)">{{ row.signal }}</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="操作" width="80" fixed="right">
|
|
<template #default="{ row }">
|
|
<el-button type="primary" link @click="drawerScoreId = row.id">明细</el-button>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
|
|
<ScoreDetailDrawer
|
|
:score-id="drawerScoreId"
|
|
@close="drawerScoreId = null"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.page {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12px;
|
|
}
|
|
.filter-card :deep(.el-card__body) {
|
|
padding: 12px 16px;
|
|
}
|
|
.signal-group :deep(.el-button) {
|
|
transition: none !important;
|
|
}
|
|
.signal-group :deep(.el-button:focus),
|
|
.signal-group :deep(.el-button:active) {
|
|
outline: none;
|
|
box-shadow: none;
|
|
}
|
|
.score-table {
|
|
background: var(--el-bg-color);
|
|
}
|
|
</style>
|