@@ -0,0 +1,539 @@
|
||||
<template>
|
||||
<div class="ai-decision-records">
|
||||
<a-spin :spinning="loading">
|
||||
<a-table
|
||||
:columns="columns"
|
||||
:data-source="decisions"
|
||||
:pagination="paginationConfig"
|
||||
:scroll="{ x: 'max-content' }"
|
||||
row-key="id"
|
||||
size="small"
|
||||
>
|
||||
<template slot="reasoning" slot-scope="text">
|
||||
<a-tooltip :title="text">
|
||||
<div class="reasoning-text">{{ text }}</div>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template slot="decisions" slot-scope="decisionList">
|
||||
<a-tag
|
||||
v-for="(d, index) in decisionList"
|
||||
:key="index"
|
||||
:color="getActionColor(d.action)"
|
||||
style="margin-right: 4px;"
|
||||
>
|
||||
{{ getActionText(d.action) }}: {{ d.symbol }}
|
||||
</a-tag>
|
||||
</template>
|
||||
<template slot="confidence" slot-scope="confidence">
|
||||
<a-progress
|
||||
:percent="Math.round(confidence * 100)"
|
||||
:status="confidence > 0.7 ? 'success' : confidence > 0.4 ? 'active' : 'exception'"
|
||||
:show-info="true"
|
||||
size="small"
|
||||
/>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-spin>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getAIDecisions } from '@/api/ai-trading'
|
||||
|
||||
export default {
|
||||
name: 'AIDecisionRecords',
|
||||
props: {
|
||||
strategyId: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
decisions: [],
|
||||
pagination: {
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
paginationConfig () {
|
||||
return {
|
||||
...this.pagination,
|
||||
showTotal: (total) => this.$t('ai-trading-assistant.table.totalRecords', { total }),
|
||||
onChange: this.handlePageChange,
|
||||
onShowSizeChange: this.handlePageSizeChange
|
||||
}
|
||||
},
|
||||
columns () {
|
||||
return [
|
||||
{
|
||||
title: this.$t('ai-trading-assistant.table.time'),
|
||||
dataIndex: 'created_at',
|
||||
key: 'created_at',
|
||||
width: 180,
|
||||
customRender: (text) => {
|
||||
return new Date(text * 1000).toLocaleString('zh-CN')
|
||||
}
|
||||
},
|
||||
{
|
||||
title: this.$t('ai-trading-assistant.table.reasoning'),
|
||||
dataIndex: 'decision.reasoning',
|
||||
key: 'reasoning',
|
||||
width: 300,
|
||||
scopedSlots: { customRender: 'reasoning' }
|
||||
},
|
||||
{
|
||||
title: this.$t('ai-trading-assistant.table.decisions'),
|
||||
dataIndex: 'decision.decisions',
|
||||
key: 'decisions',
|
||||
width: 200,
|
||||
scopedSlots: { customRender: 'decisions' }
|
||||
},
|
||||
{
|
||||
title: this.$t('ai-trading-assistant.table.riskAssessment'),
|
||||
dataIndex: 'decision.risk_assessment',
|
||||
key: 'risk_assessment',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: this.$t('ai-trading-assistant.table.confidence'),
|
||||
dataIndex: 'decision.confidence',
|
||||
key: 'confidence',
|
||||
width: 150,
|
||||
scopedSlots: { customRender: 'confidence' }
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
strategyId: {
|
||||
immediate: true,
|
||||
handler () {
|
||||
this.loadDecisions()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async loadDecisions () {
|
||||
if (!this.strategyId) return
|
||||
|
||||
this.loading = true
|
||||
try {
|
||||
const res = await getAIDecisions(this.strategyId, {
|
||||
page: this.pagination.current,
|
||||
limit: this.pagination.pageSize
|
||||
})
|
||||
if (res.code === 1) {
|
||||
// 处理返回的数据格式
|
||||
const data = res.data
|
||||
let decisions = []
|
||||
let total = 0
|
||||
|
||||
// 兼容新旧格式
|
||||
if (data && typeof data === 'object') {
|
||||
if (Array.isArray(data)) {
|
||||
// 旧格式:直接是数组
|
||||
decisions = data
|
||||
total = data.length
|
||||
} else if (data.decisions) {
|
||||
// 新格式:包含 decisions 和 total
|
||||
decisions = data.decisions || []
|
||||
total = data.total || 0
|
||||
}
|
||||
}
|
||||
|
||||
this.decisions = decisions.map(item => ({
|
||||
...item,
|
||||
decision: item.decision || {}
|
||||
}))
|
||||
this.pagination.total = total
|
||||
}
|
||||
} catch (error) {
|
||||
this.$message.error(this.$t('ai-trading-assistant.messages.loadDecisionsFailed'))
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
getActionColor (action) {
|
||||
const colorMap = {
|
||||
buy: 'green',
|
||||
sell: 'red',
|
||||
short: 'orange',
|
||||
close_short: 'blue',
|
||||
hold: 'cyan'
|
||||
}
|
||||
return colorMap[action] || 'default'
|
||||
},
|
||||
getActionText (action) {
|
||||
const actionMap = {
|
||||
buy: this.$t('ai-trading-assistant.table.buy'),
|
||||
sell: this.$t('ai-trading-assistant.table.sell'),
|
||||
short: this.$t('ai-trading-assistant.table.short'),
|
||||
close_short: this.$t('ai-trading-assistant.table.closeShort'),
|
||||
hold: this.$t('ai-trading-assistant.table.hold')
|
||||
}
|
||||
return actionMap[action] || action
|
||||
},
|
||||
handlePageChange (page, pageSize) {
|
||||
this.pagination.current = page
|
||||
this.pagination.pageSize = pageSize
|
||||
this.loadDecisions()
|
||||
},
|
||||
handlePageSizeChange (current, size) {
|
||||
this.pagination.current = 1
|
||||
this.pagination.pageSize = size
|
||||
this.loadDecisions()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ai-decision-records {
|
||||
width: 100%;
|
||||
min-height: 300px;
|
||||
overflow-x: auto;
|
||||
overflow-y: visible;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
color: var(--text-color, #1f1f1f);
|
||||
|
||||
.reasoning-text {
|
||||
max-width: 200px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
color: var(--text-color, #1f1f1f);
|
||||
}
|
||||
|
||||
// 确保 hold 标签(cyan)在所有主题下都有足够的对比度
|
||||
/deep/ .ant-tag {
|
||||
&.ant-tag-cyan {
|
||||
background-color: #13c2c2 !important;
|
||||
border-color: #13c2c2 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 表格容器横向滚动
|
||||
/deep/ .ant-table-wrapper {
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
// 适配主题色
|
||||
/deep/ .ant-table {
|
||||
background: var(--table-row-bg, #fff);
|
||||
color: var(--text-color, #1f1f1f);
|
||||
|
||||
.ant-table-thead > tr > th {
|
||||
background: var(--table-header-bg, #fafafa);
|
||||
color: var(--text-color, #1f1f1f);
|
||||
border-bottom-color: var(--table-border-color, #e8e8e8);
|
||||
|
||||
.ant-table-column-title {
|
||||
color: var(--text-color, #1f1f1f);
|
||||
}
|
||||
}
|
||||
|
||||
.ant-table-tbody > tr:hover > td {
|
||||
background-color: var(--hover-bg-color, #fafafa);
|
||||
}
|
||||
|
||||
.ant-table-tbody > tr > td {
|
||||
background: var(--table-row-bg, #fff);
|
||||
color: var(--text-color, #1f1f1f);
|
||||
border-bottom-color: var(--table-border-color, #e8e8e8);
|
||||
}
|
||||
|
||||
.ant-table-body {
|
||||
&::-webkit-scrollbar {
|
||||
height: 6px;
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: var(--table-row-bg, #fff);
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #bfbfbf;
|
||||
border-radius: 4px;
|
||||
|
||||
&:hover {
|
||||
background: #a6a6a6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 进度条使用主题色
|
||||
/deep/ .ant-progress {
|
||||
.ant-progress-bg {
|
||||
background-color: var(--primary-color, #1890ff);
|
||||
}
|
||||
|
||||
&.ant-progress-status-success .ant-progress-bg {
|
||||
background-color: #52c41a;
|
||||
}
|
||||
|
||||
&.ant-progress-status-exception .ant-progress-bg {
|
||||
background-color: #ff4d4f;
|
||||
}
|
||||
}
|
||||
|
||||
// 自定义滚动条样式
|
||||
&::-webkit-scrollbar {
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #888;
|
||||
border-radius: 4px;
|
||||
|
||||
&:hover {
|
||||
background: #555;
|
||||
}
|
||||
}
|
||||
|
||||
// 分页器主题适配
|
||||
/deep/ .ant-pagination {
|
||||
color: var(--text-color, #1f1f1f);
|
||||
|
||||
.ant-pagination-total-text {
|
||||
color: var(--text-color-secondary, #8c8c8c);
|
||||
}
|
||||
|
||||
.ant-pagination-item {
|
||||
background: var(--table-row-bg, #fff);
|
||||
border-color: var(--table-border-color, #e8e8e8);
|
||||
|
||||
a {
|
||||
color: var(--text-color, #1f1f1f);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: var(--primary-color, #1890ff);
|
||||
|
||||
a {
|
||||
color: var(--primary-color, #1890ff);
|
||||
}
|
||||
}
|
||||
|
||||
&.ant-pagination-item-active {
|
||||
background: var(--primary-color, #1890ff);
|
||||
border-color: var(--primary-color, #1890ff);
|
||||
|
||||
a {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-pagination-prev,
|
||||
.ant-pagination-next {
|
||||
.ant-pagination-item-link {
|
||||
background: var(--table-row-bg, #fff);
|
||||
border-color: var(--table-border-color, #e8e8e8);
|
||||
color: var(--text-color, #1f1f1f);
|
||||
|
||||
&:hover {
|
||||
border-color: var(--primary-color, #1890ff);
|
||||
color: var(--primary-color, #1890ff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-pagination-options {
|
||||
.ant-select-selector {
|
||||
background: var(--table-row-bg, #fff);
|
||||
border-color: var(--table-border-color, #e8e8e8);
|
||||
color: var(--text-color, #1f1f1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
// 全局样式:暗色主题下的标签优化
|
||||
.trading-assistant.theme-dark {
|
||||
.ai-decision-records {
|
||||
/deep/ .ant-table {
|
||||
background: var(--table-row-bg, #1e222d);
|
||||
color: var(--text-color, #d1d4dc);
|
||||
|
||||
.ant-table-thead > tr > th {
|
||||
background: var(--table-header-bg, #252932) !important;
|
||||
color: var(--text-color, #d1d4dc) !important;
|
||||
border-bottom-color: var(--table-border-color, #2a2e39);
|
||||
|
||||
.ant-table-column-title {
|
||||
color: var(--text-color, #d1d4dc) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-table-tbody > tr > td {
|
||||
background: var(--table-row-bg, #1e222d);
|
||||
color: var(--text-color, #d1d4dc);
|
||||
border-bottom-color: var(--table-border-color, #2a2e39);
|
||||
}
|
||||
|
||||
.ant-table-tbody > tr:hover > td {
|
||||
background-color: var(--table-hover-bg, #252932);
|
||||
}
|
||||
|
||||
.ant-table-body {
|
||||
&::-webkit-scrollbar-track {
|
||||
background: var(--table-row-bg, #1e222d);
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #555;
|
||||
|
||||
&:hover {
|
||||
background: #777;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.reasoning-text {
|
||||
color: var(--text-color, #d1d4dc);
|
||||
}
|
||||
|
||||
/deep/ .ant-tag {
|
||||
// hold 标签使用青色,确保在暗色背景下可见
|
||||
&.ant-tag-cyan {
|
||||
background-color: #13c2c2 !important;
|
||||
border-color: #13c2c2 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
// 其他标签在暗色主题下的优化
|
||||
&.ant-tag-green {
|
||||
background-color: #52c41a !important;
|
||||
border-color: #52c41a !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
&.ant-tag-red {
|
||||
background-color: #ff4d4f !important;
|
||||
border-color: #ff4d4f !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
&.ant-tag-orange {
|
||||
background-color: #fa8c16 !important;
|
||||
border-color: #fa8c16 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
&.ant-tag-blue {
|
||||
background-color: var(--primary-color, #1890ff) !important;
|
||||
border-color: var(--primary-color, #1890ff) !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
// default 标签在暗色主题下的优化
|
||||
&.ant-tag-default {
|
||||
background-color: #434343 !important;
|
||||
border-color: #434343 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 进度条在暗色主题下使用主题色
|
||||
/deep/ .ant-progress {
|
||||
.ant-progress-bg {
|
||||
background-color: var(--primary-color, #1890ff);
|
||||
}
|
||||
|
||||
&.ant-progress-status-success .ant-progress-bg {
|
||||
background-color: #52c41a;
|
||||
}
|
||||
|
||||
&.ant-progress-status-exception .ant-progress-bg {
|
||||
background-color: #ff4d4f;
|
||||
}
|
||||
}
|
||||
|
||||
// 暗色主题下的滚动条样式
|
||||
&::-webkit-scrollbar-track {
|
||||
background: #2a2e39;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #555;
|
||||
|
||||
&:hover {
|
||||
background: #777;
|
||||
}
|
||||
}
|
||||
|
||||
// 暗色主题下的分页器
|
||||
/deep/ .ant-pagination {
|
||||
color: var(--text-color, #d1d4dc);
|
||||
|
||||
.ant-pagination-total-text {
|
||||
color: var(--text-color-secondary, #868993);
|
||||
}
|
||||
|
||||
.ant-pagination-item {
|
||||
background: var(--table-row-bg, #1e222d);
|
||||
border-color: var(--table-border-color, #2a2e39);
|
||||
|
||||
a {
|
||||
color: var(--text-color, #d1d4dc);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: var(--primary-color, #1890ff);
|
||||
|
||||
a {
|
||||
color: var(--primary-color, #1890ff);
|
||||
}
|
||||
}
|
||||
|
||||
&.ant-pagination-item-active {
|
||||
background: var(--primary-color, #1890ff);
|
||||
border-color: var(--primary-color, #1890ff);
|
||||
|
||||
a {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-pagination-prev,
|
||||
.ant-pagination-next {
|
||||
.ant-pagination-item-link {
|
||||
background: var(--table-row-bg, #1e222d);
|
||||
border-color: var(--table-border-color, #2a2e39);
|
||||
color: var(--text-color, #d1d4dc);
|
||||
|
||||
&:hover {
|
||||
border-color: var(--primary-color, #1890ff);
|
||||
color: var(--primary-color, #1890ff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-pagination-options {
|
||||
.ant-select-selector {
|
||||
background: var(--table-row-bg, #1e222d);
|
||||
border-color: var(--table-border-color, #2a2e39);
|
||||
color: var(--text-color, #d1d4dc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,733 @@
|
||||
<template>
|
||||
<div class="position-records">
|
||||
<div v-if="positions.length === 0 && !loading" class="empty-state">
|
||||
<a-empty :description="$t('trading-assistant.table.noPositions')" />
|
||||
</div>
|
||||
<a-table
|
||||
v-else
|
||||
:columns="columns"
|
||||
:data-source="positions"
|
||||
:loading="loading"
|
||||
:pagination="false"
|
||||
size="small"
|
||||
rowKey="id"
|
||||
:scroll="{ x: 800 }"
|
||||
>
|
||||
<template slot="symbol" slot-scope="text, record">
|
||||
<strong>{{ record.symbol || text }}</strong>
|
||||
</template>
|
||||
<template slot="side" slot-scope="text, record">
|
||||
<a-tag :color="(record.side || text) === 'long' ? 'green' : 'red'">
|
||||
{{ (record.side || text) === 'long' ? $t('trading-assistant.table.long') : $t('trading-assistant.table.short') }}
|
||||
</a-tag>
|
||||
</template>
|
||||
<template slot="entryPrice" slot-scope="text, record">
|
||||
${{ parseFloat(record.entry_price || text || 0).toFixed(4) }}
|
||||
</template>
|
||||
<template slot="currentPrice" slot-scope="text, record">
|
||||
${{ parseFloat(record.current_price || text || 0).toFixed(4) }}
|
||||
</template>
|
||||
<template slot="size" slot-scope="text, record">
|
||||
{{ parseFloat(record.size || text || 0).toFixed(4) }}
|
||||
</template>
|
||||
<template slot="unrealizedPnl" slot-scope="text, record">
|
||||
<span :class="{ 'profit': parseFloat(record.unrealized_pnl || text || 0) > 0, 'loss': parseFloat(record.unrealized_pnl || text || 0) < 0 }">
|
||||
${{ parseFloat(record.unrealized_pnl || text || 0).toFixed(2) }}
|
||||
</span>
|
||||
</template>
|
||||
<template slot="pnlPercent" slot-scope="text, record">
|
||||
<span :class="{ 'profit': parseFloat(record.pnl_percent || text || 0) > 0, 'loss': parseFloat(record.pnl_percent || text || 0) < 0 }">
|
||||
{{ parseFloat(record.pnl_percent || text || 0).toFixed(2) }}%
|
||||
</span>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getStrategyPositions } from '@/api/strategy'
|
||||
|
||||
export default {
|
||||
name: 'PositionRecords',
|
||||
props: {
|
||||
strategyId: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
marketType: {
|
||||
type: String,
|
||||
default: 'swap'
|
||||
},
|
||||
leverage: {
|
||||
type: [Number, String],
|
||||
default: 1
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
positions: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
columns () {
|
||||
return [
|
||||
{
|
||||
title: this.$t('trading-assistant.table.symbol'),
|
||||
dataIndex: 'symbol',
|
||||
key: 'symbol',
|
||||
width: 120,
|
||||
scopedSlots: { customRender: 'symbol' }
|
||||
},
|
||||
{
|
||||
title: this.$t('trading-assistant.table.side'),
|
||||
dataIndex: 'side',
|
||||
key: 'side',
|
||||
width: 80,
|
||||
scopedSlots: { customRender: 'side' }
|
||||
},
|
||||
{
|
||||
title: this.$t('trading-assistant.table.size'),
|
||||
dataIndex: 'size',
|
||||
key: 'size',
|
||||
width: 120,
|
||||
scopedSlots: { customRender: 'size' }
|
||||
},
|
||||
{
|
||||
title: this.$t('trading-assistant.table.entryPrice'),
|
||||
dataIndex: 'entry_price',
|
||||
key: 'entry_price',
|
||||
width: 120,
|
||||
scopedSlots: { customRender: 'entryPrice' }
|
||||
},
|
||||
{
|
||||
title: this.$t('trading-assistant.table.currentPrice'),
|
||||
dataIndex: 'current_price',
|
||||
key: 'current_price',
|
||||
width: 120,
|
||||
scopedSlots: { customRender: 'currentPrice' }
|
||||
},
|
||||
{
|
||||
title: this.$t('trading-assistant.table.unrealizedPnl'),
|
||||
dataIndex: 'unrealized_pnl',
|
||||
key: 'unrealized_pnl',
|
||||
width: 120,
|
||||
scopedSlots: { customRender: 'unrealizedPnl' }
|
||||
},
|
||||
{
|
||||
title: this.$t('trading-assistant.table.pnlPercent'),
|
||||
dataIndex: 'pnl_percent',
|
||||
key: 'pnl_percent',
|
||||
width: 100,
|
||||
scopedSlots: { customRender: 'pnlPercent' }
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
strategyId: {
|
||||
handler (val) {
|
||||
if (val) {
|
||||
this.loadPositions()
|
||||
// 每5秒刷新一次持仓
|
||||
this.startPolling()
|
||||
} else {
|
||||
this.stopPolling()
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.stopPolling()
|
||||
},
|
||||
methods: {
|
||||
async loadPositions () {
|
||||
if (!this.strategyId) return
|
||||
|
||||
try {
|
||||
const res = await getStrategyPositions(this.strategyId)
|
||||
if (res.code === 1) {
|
||||
// 确保数据格式正确,处理可能的字段名不一致
|
||||
const rawPositions = res.data.positions || []
|
||||
|
||||
this.positions = rawPositions.map((position, index) => {
|
||||
const mt = String(this.marketType || 'swap').toLowerCase()
|
||||
let lev = parseFloat(this.leverage)
|
||||
if (!isFinite(lev) || lev <= 0) lev = 1
|
||||
if (mt === 'spot') lev = 1
|
||||
|
||||
const entryPrice = parseFloat(position.entry_price || position.entryPrice || '0') || 0
|
||||
const size = parseFloat(position.size || '0') || 0
|
||||
const pnl = parseFloat(position.unrealized_pnl || position.unrealizedPnl || '0') || 0
|
||||
let pnlPercent = parseFloat(position.pnl_percent || position.pnlPercent || '0') || 0
|
||||
|
||||
// Prefer margin-based pnl% (pnl / (notional / leverage)).
|
||||
// If backend already returns pnl_percent, we still recompute from pnl/entry/size to keep it consistent.
|
||||
if (entryPrice > 0 && size > 0) {
|
||||
pnlPercent = (pnl / (entryPrice * size)) * 100 * lev
|
||||
} else if (mt !== 'spot') {
|
||||
pnlPercent = pnlPercent * lev
|
||||
}
|
||||
|
||||
const mapped = {
|
||||
id: position.id || index,
|
||||
symbol: position.symbol || '',
|
||||
side: position.side || 'long',
|
||||
size: position.size || '0',
|
||||
entry_price: position.entry_price || position.entryPrice || '0',
|
||||
current_price: position.current_price || position.currentPrice || '0',
|
||||
unrealized_pnl: position.unrealized_pnl || position.unrealizedPnl || '0',
|
||||
pnl_percent: pnlPercent,
|
||||
updated_at: position.updated_at || position.updatedAt || ''
|
||||
}
|
||||
return mapped
|
||||
})
|
||||
} else {
|
||||
// 不显示错误,可能策略还没有持仓
|
||||
this.positions = []
|
||||
}
|
||||
} catch (error) {
|
||||
this.positions = []
|
||||
}
|
||||
},
|
||||
startPolling () {
|
||||
this.stopPolling()
|
||||
this.pollingTimer = setInterval(() => {
|
||||
this.loadPositions()
|
||||
}, 5000)
|
||||
},
|
||||
stopPolling () {
|
||||
if (this.pollingTimer) {
|
||||
clearInterval(this.pollingTimer)
|
||||
this.pollingTimer = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.position-records {
|
||||
width: 100%;
|
||||
min-height: 300px;
|
||||
padding: 0;
|
||||
|
||||
.empty-state {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 200px;
|
||||
padding: 40px 0;
|
||||
}
|
||||
|
||||
::v-deep .ant-table {
|
||||
font-size: 13px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
// 自定义细滚动条
|
||||
::v-deep .ant-table-body {
|
||||
overflow-x: auto;
|
||||
scrollbar-width: thin; // Firefox - 细滚动条
|
||||
scrollbar-color: rgba(0, 0, 0, 0.2) transparent; // Firefox - 滑块颜色和轨道颜色
|
||||
&::-webkit-scrollbar {
|
||||
height: 6px; // 横向滚动条高度
|
||||
width: 6px; // 纵向滚动条宽度
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent; // 轨道背景透明
|
||||
border-radius: 3px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: rgba(0, 0, 0, 0.2); // 滑块颜色
|
||||
border-radius: 3px;
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.3); // 悬停时颜色
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表格容器的滚动条样式
|
||||
::v-deep .ant-table-container {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
|
||||
&::-webkit-scrollbar {
|
||||
height: 6px;
|
||||
width: 6px;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
border-radius: 3px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 3px;
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 所有可能的表格滚动容器的滚动条样式
|
||||
::v-deep .ant-table-content,
|
||||
::v-deep .ant-table-wrapper {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
|
||||
&::-webkit-scrollbar {
|
||||
height: 6px;
|
||||
width: 6px;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
border-radius: 3px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 3px;
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .ant-table-thead > tr > th {
|
||||
background: #fafafa;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
}
|
||||
|
||||
::v-deep .ant-table-tbody > tr > td {
|
||||
padding: 12px 16px;
|
||||
color: #333;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
}
|
||||
|
||||
// 暗黑主题适配
|
||||
&.theme-dark,
|
||||
.theme-dark & {
|
||||
::v-deep .ant-table {
|
||||
background: #1e222d !important;
|
||||
color: #d1d4dc !important;
|
||||
}
|
||||
|
||||
::v-deep .ant-table-thead > tr > th {
|
||||
background: #2a2e39 !important;
|
||||
color: #d1d4dc !important;
|
||||
border-bottom-color: #363c4e !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
::v-deep .ant-table-tbody > tr > td {
|
||||
background: #1e222d !important;
|
||||
color: #d1d4dc !important;
|
||||
border-bottom-color: #363c4e !important;
|
||||
}
|
||||
|
||||
::v-deep .ant-table-tbody > tr:hover > td {
|
||||
background: #2a2e39 !important;
|
||||
}
|
||||
|
||||
::v-deep .ant-table-tbody > tr > td strong {
|
||||
color: #d1d4dc !important;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .ant-table-tbody > tr:hover > td {
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
::v-deep .ant-empty {
|
||||
margin: 40px 0;
|
||||
|
||||
.ant-empty-description {
|
||||
color: #8c8c8c;
|
||||
}
|
||||
}
|
||||
|
||||
.profit {
|
||||
color: #52c41a;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.loss {
|
||||
color: #ff4d4f;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
// 移动端适配
|
||||
@media (max-width: 768px) {
|
||||
min-height: 200px;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
// 移动端也使用细滚动条
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
|
||||
&::-webkit-scrollbar {
|
||||
height: 4px;
|
||||
width: 4px;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
border-radius: 2px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 2px;
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
min-height: 150px;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
::v-deep .ant-table {
|
||||
font-size: 12px;
|
||||
min-width: 700px; // 确保表格最小宽度,触发横向滚动
|
||||
}
|
||||
|
||||
// 移动端也使用细滚动条
|
||||
::v-deep .ant-table-body,
|
||||
::v-deep .ant-table-container,
|
||||
::v-deep .ant-table-wrapper {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
|
||||
&::-webkit-scrollbar {
|
||||
height: 4px;
|
||||
width: 4px;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
border-radius: 2px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 2px;
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .ant-table-thead > tr > th {
|
||||
padding: 8px 10px;
|
||||
font-size: 11px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
::v-deep .ant-table-tbody > tr > td {
|
||||
padding: 8px 10px;
|
||||
font-size: 11px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
::v-deep .ant-empty {
|
||||
margin: 20px 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
::v-deep .ant-table {
|
||||
font-size: 11px;
|
||||
min-width: 600px;
|
||||
}
|
||||
|
||||
::v-deep .ant-table-thead > tr > th {
|
||||
padding: 6px 8px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
::v-deep .ant-table-tbody > tr > td {
|
||||
padding: 6px 8px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.profit,
|
||||
.loss {
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
// 暗黑主题适配 - 使用更高优先级的选择器覆盖 scoped 样式
|
||||
// 必须使用完整的 scoped 选择器路径来覆盖
|
||||
.theme-dark .position-records .ant-table-tbody > tr > td,
|
||||
.theme-dark .position-records[data-v] .ant-table-tbody > tr > td,
|
||||
body.dark .position-records .ant-table-tbody > tr > td,
|
||||
body.realdark .position-records .ant-table-tbody > tr > td {
|
||||
color: #d1d4dc !important;
|
||||
background: #1e222d !important;
|
||||
border-bottom-color: #363c4e !important;
|
||||
}
|
||||
|
||||
.theme-dark .position-records .ant-table-thead > tr > th,
|
||||
.theme-dark .position-records[data-v] .ant-table-thead > tr > th,
|
||||
body.dark .position-records .ant-table-thead > tr > th,
|
||||
body.realdark .position-records .ant-table-thead > tr > th {
|
||||
background: #2a2e39 !important;
|
||||
color: #d1d4dc !important;
|
||||
border-bottom-color: #363c4e !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
||||
.theme-dark .position-records .ant-table,
|
||||
.theme-dark .position-records[data-v] .ant-table,
|
||||
body.dark .position-records .ant-table,
|
||||
body.realdark .position-records .ant-table {
|
||||
background: #1e222d !important;
|
||||
color: #d1d4dc !important;
|
||||
}
|
||||
|
||||
.theme-dark .position-records .ant-table-tbody > tr > td *,
|
||||
.theme-dark .position-records[data-v] .ant-table-tbody > tr > td *,
|
||||
body.dark .position-records .ant-table-tbody > tr > td *,
|
||||
body.realdark .position-records .ant-table-tbody > tr > td * {
|
||||
color: #d1d4dc !important;
|
||||
}
|
||||
|
||||
.theme-dark .position-records .ant-table-tbody > tr:hover > td,
|
||||
.theme-dark .position-records[data-v] .ant-table-tbody > tr:hover > td,
|
||||
body.dark .position-records .ant-table-tbody > tr:hover > td,
|
||||
body.realdark .position-records .ant-table-tbody > tr:hover > td {
|
||||
background: #2a2e39 !important;
|
||||
}
|
||||
|
||||
// 确保表头文字可见
|
||||
.theme-dark .position-records .ant-table-thead > tr > th,
|
||||
.theme-dark .position-records[data-v] .ant-table-thead > tr > th,
|
||||
body.dark .position-records .ant-table-thead > tr > th,
|
||||
body.realdark .position-records .ant-table-thead > tr > th {
|
||||
.ant-table-column-title {
|
||||
color: #d1d4dc !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 通用选择器作为后备
|
||||
.theme-dark .position-records[data-v] .ant-table-tbody > tr > td,
|
||||
.theme-dark [class*="position-records"][data-v] .ant-table-tbody > tr > td {
|
||||
color: #d1d4dc !important;
|
||||
background: #1e222d !important;
|
||||
border-bottom-color: #363c4e !important;
|
||||
}
|
||||
|
||||
.theme-dark .position-records[data-v] .ant-table-thead > tr > th,
|
||||
.theme-dark [class*="position-records"][data-v] .ant-table-thead > tr > th {
|
||||
background: #2a2e39 !important;
|
||||
color: #d1d4dc !important;
|
||||
border-bottom-color: #363c4e !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
// 暗黑主题适配 - 使用最高优先级的选择器覆盖 scoped 样式
|
||||
// 关键:必须使用与 scoped 样式完全相同的选择器结构,加上 theme-dark 前缀
|
||||
// 使用属性选择器的精确匹配来覆盖 scoped 样式
|
||||
|
||||
// 方法1:精确匹配 data-v-6c1eb557
|
||||
.theme-dark .position-records[data-v-6c1eb557] .ant-table-tbody > tr > td,
|
||||
.theme-dark [data-v-6c1eb557].position-records .ant-table-tbody > tr > td,
|
||||
.theme-dark [data-v-6c1eb557] .position-records .ant-table-tbody > tr > td {
|
||||
color: #d1d4dc !important;
|
||||
background: #1e222d !important;
|
||||
border-bottom-color: #363c4e !important;
|
||||
}
|
||||
|
||||
// 方法2:使用属性选择器前缀匹配(更通用)
|
||||
.theme-dark [data-v-6c1eb557] .ant-table-tbody > tr > td {
|
||||
color: #d1d4dc !important;
|
||||
background: #1e222d !important;
|
||||
border-bottom-color: #363c4e !important;
|
||||
}
|
||||
|
||||
.theme-dark .position-records[data-v-6c1eb557] .ant-table-thead > tr > th,
|
||||
.theme-dark [data-v-6c1eb557].position-records .ant-table-thead > tr > th {
|
||||
background: #2a2e39 !important;
|
||||
color: #d1d4dc !important;
|
||||
border-bottom-color: #363c4e !important;
|
||||
}
|
||||
|
||||
.theme-dark .position-records[data-v-6c1eb557] .ant-table,
|
||||
.theme-dark [data-v-6c1eb557].position-records .ant-table {
|
||||
background: #1e222d !important;
|
||||
color: #d1d4dc !important;
|
||||
}
|
||||
|
||||
.theme-dark .position-records[data-v-6c1eb557] .ant-table-tbody > tr:hover > td,
|
||||
.theme-dark [data-v-6c1eb557].position-records .ant-table-tbody > tr:hover > td {
|
||||
background: #2a2e39 !important;
|
||||
}
|
||||
|
||||
// body.dark 和 body.realdark 支持
|
||||
body.dark .position-records[data-v-6c1eb557] .ant-table-tbody > tr > td,
|
||||
body.dark [data-v-6c1eb557].position-records .ant-table-tbody > tr > td,
|
||||
body.dark [data-v-6c1eb557] .position-records .ant-table-tbody > tr > td,
|
||||
body.realdark .position-records[data-v-6c1eb557] .ant-table-tbody > tr > td,
|
||||
body.realdark [data-v-6c1eb557].position-records .ant-table-tbody > tr > td,
|
||||
body.realdark [data-v-6c1eb557] .position-records .ant-table-tbody > tr > td {
|
||||
color: #d1d4dc !important;
|
||||
background: #1e222d !important;
|
||||
border-bottom-color: #363c4e !important;
|
||||
}
|
||||
|
||||
// 方法2:使用属性选择器前缀匹配(更通用)
|
||||
body.dark [data-v-6c1eb557] .ant-table-tbody > tr > td,
|
||||
body.realdark [data-v-6c1eb557] .ant-table-tbody > tr > td {
|
||||
color: #d1d4dc !important;
|
||||
background: #1e222d !important;
|
||||
border-bottom-color: #363c4e !important;
|
||||
}
|
||||
|
||||
body.dark .position-records[data-v-6c1eb557] .ant-table-thead > tr > th,
|
||||
body.dark [data-v-6c1eb557].position-records .ant-table-thead > tr > th,
|
||||
body.dark [data-v-6c1eb557] .position-records .ant-table-thead > tr > th,
|
||||
body.realdark .position-records[data-v-6c1eb557] .ant-table-thead > tr > th,
|
||||
body.realdark [data-v-6c1eb557].position-records .ant-table-thead > tr > th,
|
||||
body.realdark [data-v-6c1eb557] .position-records .ant-table-thead > tr > th {
|
||||
background: #2a2e39 !important;
|
||||
color: #d1d4dc !important;
|
||||
border-bottom-color: #363c4e !important;
|
||||
}
|
||||
|
||||
// 方法2:使用属性选择器前缀匹配(更通用)
|
||||
body.dark [data-v-6c1eb557] .ant-table-thead > tr > th,
|
||||
body.realdark [data-v-6c1eb557] .ant-table-thead > tr > th {
|
||||
background: #2a2e39 !important;
|
||||
color: #d1d4dc !important;
|
||||
border-bottom-color: #363c4e !important;
|
||||
}
|
||||
|
||||
// 通用后备选择器(如果 data-v 值变化)
|
||||
.theme-dark .position-records[data-v] .ant-table-tbody > tr > td,
|
||||
body.dark .position-records[data-v] .ant-table-tbody > tr > td,
|
||||
body.realdark .position-records[data-v] .ant-table-tbody > tr > td {
|
||||
color: #d1d4dc !important;
|
||||
background: #1e222d !important;
|
||||
border-bottom-color: #363c4e !important;
|
||||
}
|
||||
|
||||
.theme-dark .position-records[data-v] .ant-table-thead > tr > th,
|
||||
body.dark .position-records[data-v] .ant-table-thead > tr > th,
|
||||
body.realdark .position-records[data-v] .ant-table-thead > tr > th {
|
||||
background: #2a2e39 !important;
|
||||
color: #d1d4dc !important;
|
||||
border-bottom-color: #363c4e !important;
|
||||
}
|
||||
|
||||
// 其他样式
|
||||
.theme-dark .position-records[data-v-6c1eb557] .ant-empty .ant-empty-description,
|
||||
body.dark .position-records[data-v-6c1eb557] .ant-empty .ant-empty-description,
|
||||
body.realdark .position-records[data-v-6c1eb557] .ant-empty .ant-empty-description {
|
||||
color: #868993 !important;
|
||||
}
|
||||
|
||||
.theme-dark .position-records[data-v-6c1eb557] .profit,
|
||||
body.dark .position-records[data-v-6c1eb557] .profit,
|
||||
body.realdark .position-records[data-v-6c1eb557] .profit {
|
||||
color: #52c41a !important;
|
||||
}
|
||||
|
||||
.theme-dark .position-records[data-v-6c1eb557] .loss,
|
||||
body.dark .position-records[data-v-6c1eb557] .loss,
|
||||
body.realdark .position-records[data-v-6c1eb557] .loss {
|
||||
color: #ff4d4f !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
// 最终覆盖方案:使用更长的选择器链确保最高优先级
|
||||
// 直接匹配 scoped 样式生成的完整选择器路径
|
||||
.theme-dark .trading-assistant .position-records[data-v-6c1eb557] .ant-table-tbody > tr > td,
|
||||
.theme-dark .trading-assistant [data-v-6c1eb557].position-records .ant-table-tbody > tr > td,
|
||||
body.dark .trading-assistant .position-records[data-v-6c1eb557] .ant-table-tbody > tr > td,
|
||||
body.dark .trading-assistant [data-v-6c1eb557].position-records .ant-table-tbody > tr > td,
|
||||
body.realdark .trading-assistant .position-records[data-v-6c1eb557] .ant-table-tbody > tr > td,
|
||||
body.realdark .trading-assistant [data-v-6c1eb557].position-records .ant-table-tbody > tr > td {
|
||||
color: #d1d4dc !important;
|
||||
background: #1e222d !important;
|
||||
border-bottom-color: #363c4e !important;
|
||||
}
|
||||
|
||||
.theme-dark .trading-assistant .position-records[data-v-6c1eb557] .ant-table-thead > tr > th,
|
||||
.theme-dark .trading-assistant [data-v-6c1eb557].position-records .ant-table-thead > tr > th,
|
||||
body.dark .trading-assistant .position-records[data-v-6c1eb557] .ant-table-thead > tr > th,
|
||||
body.dark .trading-assistant [data-v-6c1eb557].position-records .ant-table-thead > tr > th,
|
||||
body.realdark .trading-assistant .position-records[data-v-6c1eb557] .ant-table-thead > tr > th,
|
||||
body.realdark .trading-assistant [data-v-6c1eb557].position-records .ant-table-thead > tr > th {
|
||||
background: #2a2e39 !important;
|
||||
color: #d1d4dc !important;
|
||||
border-bottom-color: #363c4e !important;
|
||||
}
|
||||
|
||||
// 暗黑主题滚动条样式
|
||||
.theme-dark .position-records[data-v-6c1eb557] .ant-table-body,
|
||||
.theme-dark .position-records[data-v-6c1eb557] .ant-table-container,
|
||||
.theme-dark .position-records[data-v-6c1eb557] .ant-table-content,
|
||||
.theme-dark .position-records[data-v-6c1eb557] .ant-table-wrapper,
|
||||
body.dark .position-records[data-v-6c1eb557] .ant-table-body,
|
||||
body.dark .position-records[data-v-6c1eb557] .ant-table-container,
|
||||
body.dark .position-records[data-v-6c1eb557] .ant-table-content,
|
||||
body.dark .position-records[data-v-6c1eb557] .ant-table-wrapper,
|
||||
body.realdark .position-records[data-v-6c1eb557] .ant-table-body,
|
||||
body.realdark .position-records[data-v-6c1eb557] .ant-table-container,
|
||||
body.realdark .position-records[data-v-6c1eb557] .ant-table-content,
|
||||
body.realdark .position-records[data-v-6c1eb557] .ant-table-wrapper {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(209, 212, 220, 0.3) transparent;
|
||||
&::-webkit-scrollbar {
|
||||
height: 6px;
|
||||
width: 6px;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
border-radius: 3px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: rgba(209, 212, 220, 0.3);
|
||||
border-radius: 3px;
|
||||
&:hover {
|
||||
background: rgba(209, 212, 220, 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 通用后备选择器
|
||||
.theme-dark .position-records[data-v] .ant-table-body,
|
||||
.theme-dark .position-records[data-v] .ant-table-container,
|
||||
.theme-dark .position-records[data-v] .ant-table-content,
|
||||
.theme-dark .position-records[data-v] .ant-table-wrapper,
|
||||
body.dark .position-records[data-v] .ant-table-body,
|
||||
body.dark .position-records[data-v] .ant-table-container,
|
||||
body.dark .position-records[data-v] .ant-table-content,
|
||||
body.dark .position-records[data-v] .ant-table-wrapper,
|
||||
body.realdark .position-records[data-v] .ant-table-body,
|
||||
body.realdark .position-records[data-v] .ant-table-container,
|
||||
body.realdark .position-records[data-v] .ant-table-content,
|
||||
body.realdark .position-records[data-v] .ant-table-wrapper {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(209, 212, 220, 0.3) transparent;
|
||||
&::-webkit-scrollbar {
|
||||
height: 6px;
|
||||
width: 6px;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
border-radius: 3px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: rgba(209, 212, 220, 0.3);
|
||||
border-radius: 3px;
|
||||
&:hover {
|
||||
background: rgba(209, 212, 220, 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user