@@ -7,6 +7,8 @@
< / div >
< div class = "selector-area" >
< div class = "user-money" > 当前钱钱 : < span class = "money-value" > { { userInfo . money || 0 } } < / span > < / div >
< el-select
v-model = "currentStock"
placeholder = "选择股票"
@@ -24,6 +26,15 @@
< span class = "stock-code" > { { item . code } } < / span >
< / el-option >
< / el-select >
< el-button
type = "primary"
size = "small"
class = "return-button"
@click ="returnToHome"
>
< i class = "el-icon-back" > < / i > 返回社区
< / el-button >
< / div >
< / div >
@@ -44,6 +55,7 @@
v-for = "news in newsList"
:key = "news.id"
class = "news-item"
@click ="showNewsDetail(news)"
>
< div class = "news-date" >
{ { dayjs ( news . publishTime ) . format ( 'YYYY-MM-DD' ) } }
@@ -144,7 +156,7 @@
< div class = "section-header" >
< span class = "icon" > < i class = "el-icon-wallet" > < / i > < / span >
< h3 > 我的持仓 < / h3 >
< span class = "total-value" > 总资产 : ¥ { { totalAssets } } < / span >
< span class = "total-value" > 持有钱钱 : ¥ { { totalAssets } } < / span >
< / div >
< div v-if = "isLoadingPortfolio" class="loading-portfolio" >
@@ -170,14 +182,52 @@
< / el-table >
< / template >
< / div >
<!-- 添加新闻详情弹窗 -- >
< el-dialog
v-model = "newsDialogVisible"
:title = "currentNewsDetail.title"
width = "50%"
class = "news-detail-dialog"
>
< div class = "news-detail-header" >
< span class = "news-detail-time" > { { dayjs ( currentNewsDetail . publishTime ) . format ( 'YYYY-MM-DD HH:mm:ss' ) } } < / span >
< span class = "news-detail-source" v-if = "currentNewsDetail.source" > 来源 : {{ currentNewsDetail.source }} < / span >
< / div >
< div class = "news-detail-content" > { { currentNewsDetail . content } } < / div >
< / el-dialog >
< / div >
< / template >
< script setup >
import { ref , computed , onMounted , reactive } from 'vue' ;
import StockChart from './components/StockChart.vue' ;
import { getStockNews , getUserHoldings , getUserTransactions , getStockPriceRecords , getStockMarkets } from '@/apis/stockApi.js' ;
import { getStockNews , getUserHoldings , getUserTransactions , getStockPriceRecords , getStockMarkets , buyStock as buyStockApi , sellStock as sellStockApi } from '@/apis/stockApi.js' ;
import { getBbsUserProfile } from '@/apis/userApi.js' ;
import { dayjs } from 'element-plus' ;
import { ElMessage , ElMessageBox } from 'element-plus' ;
import { useRouter } from 'vue-router' ;
import useUserStore from "@/stores/user" ;
// 获取路由器实例
const router = useRouter ( ) ;
const userStore = useUserStore ( ) ;
const userInfo = ref ( { } ) ;
// 返回首页函数
const returnToHome = ( ) => {
router . push ( '/index' ) ;
} ;
// 获取用户信息,包括钱钱
const loadUserInfo = async ( ) => {
try {
const { data } = await getBbsUserProfile ( userStore . id ) ;
userInfo . value = data ;
} catch ( error ) {
console . error ( '获取用户信息失败:' , error ) ;
}
} ;
// 股票列表数据
const stockList = ref ( [ ] ) ;
@@ -221,7 +271,6 @@ const fetchStockMarkets = async () => {
// 加载默认选中股票的数据
await fetchStockPriceRecords ( ) ;
await fetchTradeHistory ( ) ;
}
} catch ( error ) {
console . error ( '获取股市列表失败:' , error ) ;
@@ -385,7 +434,7 @@ const totalAssets = computed(() => {
const stockValue = portfolioList . value . reduce ( ( sum , stock ) => {
return sum + parseFloat ( stock . currentPrice ) * stock . amount ;
} , 0 ) ;
return ( stockValue + 50000 ) . toFixed ( 2 ) ; // 假设有50000现金
return ( stockValue + ( userInfo . value . money || 0 ) ) . toFixed ( 2 ) ; // 使用API获取的钱钱, 而不是固定值
} ) ;
// 切换股票
@@ -408,20 +457,98 @@ const changeStock = async (stockId) => {
} ;
// 买入股票
const buyStock = ( ) => {
// 实现买入逻辑
alert ( ` 买入 ${ tradeAmount . value } 股 ${ currentStockInfo . value . name } ` ) ;
const buyStock = async ( ) => {
if ( ! currentStock . value ) {
ElMessage . warning ( '请先选择股票' ) ;
return ;
}
try {
await ElMessageBox . confirm (
` 确定要买入 ${ tradeAmount . value } 股 ${ currentStockInfo . value . name } 吗? ` ,
'买入确认' ,
{
confirmButtonText : '确定' ,
cancelButtonText : '取消' ,
type : 'warning' ,
}
) ;
await buyStockApi ( {
stockId : currentStock . value ,
quantity : tradeAmount . value
} ) ;
ElMessage . success ( ` 已成功买入 ${ tradeAmount . value } 股 ${ currentStockInfo . value . name } ` ) ;
// 刷新数据
await Promise . all ( [
fetchTradeHistory ( ) ,
fetchPortfolioList ( ) ,
loadUserInfo ( ) // 买入后更新用户钱钱
] ) ;
} catch ( error ) {
if ( error !== 'cancel' ) {
console . error ( '买入股票失败:' , error ) ;
}
}
} ;
// 卖出股票
const sellStock = ( ) => {
// 实现卖出逻辑
alert ( ` 卖出 ${ tradeAmount . value } 股 ${ currentStockInfo . value . name } ` ) ;
const sellStock = async ( ) => {
if ( ! currentStock . value ) {
ElMessage . warning ( '请先选择股票' ) ;
return ;
}
try {
await ElMessageBox . confirm (
` 确定要卖出 ${ tradeAmount . value } 股 ${ currentStockInfo . value . name } 吗? ` ,
'卖出确认' ,
{
confirmButtonText : '确定' ,
cancelButtonText : '取消' ,
type : 'warning' ,
}
) ;
await sellStockApi ( {
StockId : currentStock . value ,
Quantity : tradeAmount . value
} ) ;
ElMessage . success ( ` 已成功卖出 ${ tradeAmount . value } 股 ${ currentStockInfo . value . name } ` ) ;
// 刷新数据
await Promise . all ( [
fetchTradeHistory ( ) ,
fetchPortfolioList ( ) ,
loadUserInfo ( ) // 卖出后更新用户钱钱
] ) ;
} catch ( error ) {
if ( error !== 'cancel' ) {
console . error ( '卖出股票失败:' , error ) ;
}
}
} ;
// 新闻详情弹窗
const newsDialogVisible = ref ( false ) ;
const currentNewsDetail = ref ( {
title : '' ,
content : '' ,
publishTime : '' ,
source : ''
} ) ;
// 显示新闻详情
const showNewsDetail = ( news ) => {
currentNewsDetail . value = news ;
newsDialogVisible . value = true ;
} ;
// 生命周期钩子
onMounted ( async ( ) => {
// 先获取股市列表
await fetchStockMarkets ( ) ;
@@ -431,6 +558,9 @@ onMounted(async () => {
fetchPortfolioList ( ) ,
fetchTradeHistory ( )
] ) ;
// 加载用户信息
await loadUserInfo ( ) ;
} ) ;
< / script >
@@ -469,8 +599,9 @@ onMounted(async () => {
}
. selector - area {
flex : 0 0 150 p x;
text - align : right ;
display : fle x;
align - items : center ;
gap : 10 px ;
}
. title {
@@ -803,4 +934,84 @@ onMounted(async () => {
margin - top : 5 px ;
font - size : 12 px ;
}
/* 新闻详情弹窗样式 */
. news - detail - dialog : deep ( . el - dialog _ _header ) {
padding : 15 px 20 px ;
border - bottom : 1 px solid # 30363 d ;
}
. news - detail - dialog : deep ( . el - dialog _ _title ) {
font - size : 18 px ;
font - weight : bold ;
color : # ffffff ! important ;
text - shadow : 0 0 3 px rgba ( 255 , 255 , 255 , 0.3 ) ;
}
. news - detail - dialog : deep ( . el - dialog _ _body ) {
padding : 20 px ;
color : # e6edf3 ;
}
. news - detail - header {
display : flex ;
justify - content : space - between ;
margin - bottom : 15 px ;
padding - bottom : 10 px ;
border - bottom : 1 px solid # 30363 d ;
color : # 8 b949e ;
font - size : 0.9 em ;
}
. news - detail - content {
line - height : 1.6 ;
white - space : pre - line ;
}
/* 修改Element弹窗适应深色主题 */
. stock - dashboard : deep ( . el - dialog ) {
background - color : # 161 b22 ;
border : 1 px solid # 30363 d ;
border - radius : 8 px ;
box - shadow : 0 0 15 px rgba ( 0 , 0 , 0 , 0.5 ) ;
}
. stock - dashboard : deep ( . el - dialog _ _headerbtn . el - dialog _ _close ) {
color : # 8 b949e ;
}
. stock - dashboard : deep ( . el - dialog _ _headerbtn : hover . el - dialog _ _close ) {
color : # 58 a6ff ;
}
. return - button {
margin - left : 10 px ;
background - color : # 58 a6ff ;
border - color : # 58 a6ff ;
transition : all 0.3 s ;
}
. return - button : hover {
background - color : # 388 bfd ;
border - color : # 388 bfd ;
transform : translateY ( - 2 px ) ;
box - shadow : 0 2 px 5 px rgba ( 88 , 166 , 255 , 0.4 ) ;
}
. user - money {
color : # e6edf3 ;
font - size : 14 px ;
margin - right : 15 px ;
padding : 4 px 8 px ;
background - color : # 21262 d ;
border - radius : 4 px ;
border : 1 px solid # 30363 d ;
}
. money - value {
font - weight : bold ;
color : # 7 ee787 ;
margin - left : 4 px ;
}
< / style >