6 changed files with 991 additions and 596 deletions
-
2src/main.js
-
103src/store/emotion.ts
-
1210src/views/AiEmotion.vue
-
223src/views/components/StockTabs.vue
-
6src/views/components/emotionalBottomRadar.vue
-
43src/views/components/marketTemperature.vue
1210
src/views/AiEmotion.vue
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,223 @@ |
|||||
|
<template> |
||||
|
<div class="stock-tabs" v-if="stockList.length > 0"> |
||||
|
<div class="tabs-container"> |
||||
|
<div |
||||
|
v-for="(stock, index) in stockList" |
||||
|
:key="`${stock.stockInfo.code}-${stock.stockInfo.market}`" |
||||
|
:class="['tab-item', { active: index === activeStockIndex }]" |
||||
|
@click="switchStock(index)" |
||||
|
> |
||||
|
<div class="stock-info"> |
||||
|
<span class="stock-name">{{ stock.stockInfo.name }}</span> |
||||
|
<span class="stock-code">{{ stock.stockInfo.code }}</span> |
||||
|
</div> |
||||
|
<button |
||||
|
class="close-btn" |
||||
|
@click.stop="removeStock(index)" |
||||
|
v-if="stockList.length > 1" |
||||
|
> |
||||
|
× |
||||
|
</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="tabs-actions"> |
||||
|
<span class="stock-count">{{ stockCount }}/{{ maxStocks }}</span> |
||||
|
<button |
||||
|
class="clear-all-btn" |
||||
|
@click="clearAllStocks" |
||||
|
v-if="stockList.length > 1" |
||||
|
> |
||||
|
清空全部 |
||||
|
</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { computed } from 'vue' |
||||
|
import { useEmotionStore } from '@/store/emotion' |
||||
|
import { ElMessageBox } from 'element-plus' |
||||
|
|
||||
|
const emotionStore = useEmotionStore() |
||||
|
|
||||
|
// 计算属性 |
||||
|
const stockList = computed(() => emotionStore.stockList) |
||||
|
const activeStockIndex = computed(() => emotionStore.activeStockIndex) |
||||
|
const stockCount = computed(() => emotionStore.stockCount) |
||||
|
const maxStocks = computed(() => emotionStore.maxStocks) |
||||
|
|
||||
|
// 切换股票 |
||||
|
const switchStock = (index) => { |
||||
|
emotionStore.switchStock(index) |
||||
|
} |
||||
|
|
||||
|
// 移除股票 |
||||
|
const removeStock = async (index) => { |
||||
|
try { |
||||
|
await ElMessageBox.confirm( |
||||
|
'确定要移除这只股票吗?', |
||||
|
'提示', |
||||
|
{ |
||||
|
confirmButtonText: '确定', |
||||
|
cancelButtonText: '取消', |
||||
|
type: 'warning', |
||||
|
} |
||||
|
) |
||||
|
emotionStore.removeStock(index) |
||||
|
} catch { |
||||
|
// 用户取消操作 |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 清空所有股票 |
||||
|
const clearAllStocks = async () => { |
||||
|
try { |
||||
|
await ElMessageBox.confirm( |
||||
|
'确定要清空所有股票吗?', |
||||
|
'提示', |
||||
|
{ |
||||
|
confirmButtonText: '确定', |
||||
|
cancelButtonText: '取消', |
||||
|
type: 'warning', |
||||
|
} |
||||
|
) |
||||
|
emotionStore.clearAllStocks() |
||||
|
} catch { |
||||
|
// 用户取消操作 |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.stock-tabs { |
||||
|
background: #f8f9fa; |
||||
|
border-radius: 8px; |
||||
|
padding: 12px; |
||||
|
margin-bottom: 16px; |
||||
|
border: 1px solid #e9ecef; |
||||
|
} |
||||
|
|
||||
|
.tabs-container { |
||||
|
display: flex; |
||||
|
gap: 8px; |
||||
|
flex-wrap: wrap; |
||||
|
margin-bottom: 8px; |
||||
|
} |
||||
|
|
||||
|
.tab-item { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
gap: 8px; |
||||
|
padding: 8px 12px; |
||||
|
background: #ffffff; |
||||
|
border: 1px solid #dee2e6; |
||||
|
border-radius: 6px; |
||||
|
cursor: pointer; |
||||
|
transition: all 0.2s ease; |
||||
|
min-width: 120px; |
||||
|
} |
||||
|
|
||||
|
.tab-item:hover { |
||||
|
border-color: #007bff; |
||||
|
box-shadow: 0 2px 4px rgba(0, 123, 255, 0.1); |
||||
|
} |
||||
|
|
||||
|
.tab-item.active { |
||||
|
background: #007bff; |
||||
|
border-color: #007bff; |
||||
|
color: white; |
||||
|
} |
||||
|
|
||||
|
.stock-info { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
flex: 1; |
||||
|
} |
||||
|
|
||||
|
.stock-name { |
||||
|
font-size: 14px; |
||||
|
font-weight: 500; |
||||
|
line-height: 1.2; |
||||
|
} |
||||
|
|
||||
|
.stock-code { |
||||
|
font-size: 12px; |
||||
|
opacity: 0.8; |
||||
|
line-height: 1.2; |
||||
|
} |
||||
|
|
||||
|
.close-btn { |
||||
|
width: 20px; |
||||
|
height: 20px; |
||||
|
border: none; |
||||
|
background: rgba(0, 0, 0, 0.1); |
||||
|
border-radius: 50%; |
||||
|
cursor: pointer; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
font-size: 14px; |
||||
|
line-height: 1; |
||||
|
transition: background-color 0.2s ease; |
||||
|
} |
||||
|
|
||||
|
.close-btn:hover { |
||||
|
background: rgba(255, 0, 0, 0.2); |
||||
|
} |
||||
|
|
||||
|
.tab-item.active .close-btn { |
||||
|
background: rgba(255, 255, 255, 0.2); |
||||
|
} |
||||
|
|
||||
|
.tab-item.active .close-btn:hover { |
||||
|
background: rgba(255, 255, 255, 0.3); |
||||
|
} |
||||
|
|
||||
|
.tabs-actions { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
padding-top: 8px; |
||||
|
border-top: 1px solid #e9ecef; |
||||
|
} |
||||
|
|
||||
|
.stock-count { |
||||
|
font-size: 12px; |
||||
|
color: #6c757d; |
||||
|
} |
||||
|
|
||||
|
.clear-all-btn { |
||||
|
padding: 4px 8px; |
||||
|
font-size: 12px; |
||||
|
background: #dc3545; |
||||
|
color: white; |
||||
|
border: none; |
||||
|
border-radius: 4px; |
||||
|
cursor: pointer; |
||||
|
transition: background-color 0.2s ease; |
||||
|
} |
||||
|
|
||||
|
.clear-all-btn:hover { |
||||
|
background: #c82333; |
||||
|
} |
||||
|
|
||||
|
/* 响应式设计 */ |
||||
|
@media (max-width: 768px) { |
||||
|
.tabs-container { |
||||
|
gap: 6px; |
||||
|
} |
||||
|
|
||||
|
.tab-item { |
||||
|
min-width: 100px; |
||||
|
padding: 6px 8px; |
||||
|
} |
||||
|
|
||||
|
.stock-name { |
||||
|
font-size: 13px; |
||||
|
} |
||||
|
|
||||
|
.stock-code { |
||||
|
font-size: 11px; |
||||
|
} |
||||
|
} |
||||
|
</style> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue