feat:新增stock页面
This commit is contained in:
@@ -144,6 +144,14 @@ const router = createRouter({
|
||||
title: "面试宝典",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "stock",
|
||||
path: "/stock",
|
||||
component: () => import("../views/stock/Index.vue"),
|
||||
meta: {
|
||||
title: "股票",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
446
Yi.Bbs.Vue3/src/views/stock/Index.vue
Normal file
446
Yi.Bbs.Vue3/src/views/stock/Index.vue
Normal file
@@ -0,0 +1,446 @@
|
||||
<template>
|
||||
<div class="stock-dashboard">
|
||||
<!-- 顶部选择器区域 -->
|
||||
<div class="stock-header">
|
||||
<div class="title-area">
|
||||
<h2 class="title">意社区股市</h2>
|
||||
</div>
|
||||
|
||||
<div class="selector-area">
|
||||
<el-select v-model="currentStock" placeholder="选择股票" @change="changeStock" size="small">
|
||||
<el-option
|
||||
v-for="item in stockList"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主内容区域 -->
|
||||
<div class="main-content">
|
||||
<!-- 左侧新闻区域 -->
|
||||
<div class="news-section">
|
||||
<div class="section-header">
|
||||
<span class="icon"><i class="el-icon-news"></i></span>
|
||||
<h3>最新市场动态</h3>
|
||||
</div>
|
||||
<div class="news-list">
|
||||
<div v-for="(news, index) in newsList" :key="index" class="news-item">
|
||||
<div class="news-date">{{ news.date }}</div>
|
||||
<div class="news-title">{{ news.title }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 中间股票看板区域 -->
|
||||
<div class="stock-panel">
|
||||
<div class="stock-info">
|
||||
<h3>{{ currentStockInfo.name }} ({{ currentStockInfo.code }})</h3>
|
||||
<div class="price-info">
|
||||
<div class="current-price" :class="{'price-up': priceChange > 0, 'price-down': priceChange < 0}">
|
||||
{{ currentStockInfo.price }}
|
||||
</div>
|
||||
<div class="price-change" :class="{'price-up': priceChange > 0, 'price-down': priceChange < 0}">
|
||||
{{ priceChange > 0 ? '+' : '' }}{{ priceChange }} ({{ priceChangePercent }}%)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 股票图表 -->
|
||||
<div class="stock-chart">
|
||||
<StockChart :stockData="stockChartData" />
|
||||
</div>
|
||||
|
||||
<!-- 交易操作区 -->
|
||||
<div class="trade-actions">
|
||||
<el-input-number v-model="tradeAmount" :min="1" :max="1000" label="数量"></el-input-number>
|
||||
<el-button type="success" @click="buyStock">买入</el-button>
|
||||
<el-button type="danger" @click="sellStock">卖出</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧交易记录 -->
|
||||
<div class="trade-history">
|
||||
<div class="section-header">
|
||||
<span class="icon"><i class="el-icon-time"></i></span>
|
||||
<h3>交易记录</h3>
|
||||
</div>
|
||||
<div class="history-list">
|
||||
<div v-for="(record, index) in tradeHistory" :key="index" class="history-item">
|
||||
<span class="time">{{ record.time }}</span>
|
||||
<span class="type" :class="record.type === 'buy' ? 'buy-type' : 'sell-type'">
|
||||
{{ record.type === 'buy' ? '买入' : '卖出' }}
|
||||
</span>
|
||||
<span class="amount">{{ record.amount }}股</span>
|
||||
<span class="price">¥{{ record.price }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部持仓信息 -->
|
||||
<div class="portfolio">
|
||||
<div class="section-header">
|
||||
<span class="icon"><i class="el-icon-wallet"></i></span>
|
||||
<h3>我的持仓</h3>
|
||||
<span class="total-value">总资产: ¥{{ totalAssets }}</span>
|
||||
</div>
|
||||
<el-table :data="portfolioList" stripe style="width: 100%">
|
||||
<el-table-column prop="name" label="股票名称"></el-table-column>
|
||||
<el-table-column prop="code" label="代码"></el-table-column>
|
||||
<el-table-column prop="amount" label="持有数量"></el-table-column>
|
||||
<el-table-column prop="buyPrice" label="买入均价"></el-table-column>
|
||||
<el-table-column prop="currentPrice" label="当前价格"></el-table-column>
|
||||
<el-table-column prop="profit" label="盈亏">
|
||||
<template #default="scope">
|
||||
<span :class="scope.row.profit >= 0 ? 'price-up' : 'price-down'">
|
||||
{{ scope.row.profit >= 0 ? '+' : '' }}{{ scope.row.profit }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import StockChart from './components/StockChart.vue';
|
||||
|
||||
// 股票列表数据
|
||||
const stockList = ref([
|
||||
{ id: 1, name: '阿里巴巴', code: 'BABA' },
|
||||
{ id: 2, name: '腾讯控股', code: 'TCEHY' },
|
||||
{ id: 3, name: '百度', code: 'BIDU' },
|
||||
{ id: 4, name: '苹果', code: 'AAPL' },
|
||||
{ id: 5, name: '微软', code: 'MSFT' }
|
||||
]);
|
||||
|
||||
// 当前选中的股票
|
||||
const currentStock = ref(1);
|
||||
|
||||
// 当前股票信息
|
||||
const currentStockInfo = ref({
|
||||
name: '阿里巴巴',
|
||||
code: 'BABA',
|
||||
price: 178.54,
|
||||
prevClose: 175.23
|
||||
});
|
||||
|
||||
// 价格变化
|
||||
const priceChange = computed(() => {
|
||||
return parseFloat((currentStockInfo.value.price - currentStockInfo.value.prevClose).toFixed(2));
|
||||
});
|
||||
|
||||
// 价格变化百分比
|
||||
const priceChangePercent = computed(() => {
|
||||
return parseFloat(((priceChange.value / currentStockInfo.value.prevClose) * 100).toFixed(2));
|
||||
});
|
||||
|
||||
// 交易数量
|
||||
const tradeAmount = ref(1);
|
||||
|
||||
// 图表数据
|
||||
const stockChartData = ref([
|
||||
{ date: '2023-05-01', value: 170.23 },
|
||||
{ date: '2023-05-02', value: 172.45 },
|
||||
{ date: '2023-05-03', value: 169.87 },
|
||||
{ date: '2023-05-04', value: 173.25 },
|
||||
{ date: '2023-05-05', value: 175.23 },
|
||||
{ date: '2023-05-06', value: 178.54 }
|
||||
]);
|
||||
|
||||
// 新闻列表
|
||||
const newsList = ref([
|
||||
{ date: '2023-05-06', title: '央行宣布降低存款准备金率,股市普涨' },
|
||||
{ date: '2023-05-05', title: '科技巨头财报超预期,带动市场情绪高涨' },
|
||||
{ date: '2023-05-04', title: '美联储加息25个基点,符合市场预期' },
|
||||
{ date: '2023-05-03', title: '新能源汽车销量持续增长,相关概念股走强' },
|
||||
{ date: '2023-05-02', title: '金融监管政策出台,银行板块承压' },
|
||||
{ date: '2023-05-01', title: '消费数据好于预期,零售业有望反弹' },
|
||||
{ date: '2023-04-30', title: '国内制造业PMI持续扩张,经济复苏势头强劲' },
|
||||
{ date: '2023-04-29', title: '互联网巨头发布一季度财报,云业务成亮点' },
|
||||
{ date: '2023-04-28', title: '全球芯片短缺问题缓解,半导体板块回调' },
|
||||
{ date: '2023-04-27', title: '国际原油价格波动,能源股表现分化' }
|
||||
]);
|
||||
|
||||
// 交易记录
|
||||
const tradeHistory = ref([
|
||||
{ time: '2023-05-06 14:30:25', type: 'buy', amount: 100, price: 178.54 },
|
||||
{ time: '2023-05-06 11:25:18', type: 'sell', amount: 50, price: 177.89 },
|
||||
{ time: '2023-05-05 15:42:36', type: 'buy', amount: 200, price: 175.23 },
|
||||
{ time: '2023-05-05 10:15:42', type: 'buy', amount: 150, price: 174.56 },
|
||||
{ time: '2023-05-04 13:28:57', type: 'sell', amount: 100, price: 173.25 }
|
||||
]);
|
||||
|
||||
// 持仓列表
|
||||
const portfolioList = ref([
|
||||
{ name: '阿里巴巴', code: 'BABA', amount: 200, buyPrice: 172.45, currentPrice: 178.54, profit: 1218 },
|
||||
{ name: '腾讯控股', code: 'TCEHY', amount: 300, buyPrice: 68.25, currentPrice: 71.35, profit: 930 },
|
||||
{ name: '百度', code: 'BIDU', amount: 150, buyPrice: 132.78, currentPrice: 128.65, profit: -619.5 }
|
||||
]);
|
||||
|
||||
// 总资产
|
||||
const totalAssets = computed(() => {
|
||||
const stockValue = portfolioList.value.reduce((sum, stock) => {
|
||||
return sum + stock.currentPrice * stock.amount;
|
||||
}, 0);
|
||||
return (stockValue + 50000).toFixed(2); // 假设有50000现金
|
||||
});
|
||||
|
||||
// 切换股票
|
||||
const changeStock = (stockId) => {
|
||||
// 模拟获取新的股票数据
|
||||
const stock = stockList.value.find(item => item.id === stockId);
|
||||
if (stock) {
|
||||
currentStockInfo.value = {
|
||||
name: stock.name,
|
||||
code: stock.code,
|
||||
price: parseFloat((150 + Math.random() * 50).toFixed(2)),
|
||||
prevClose: parseFloat((150 + Math.random() * 50).toFixed(2))
|
||||
};
|
||||
|
||||
// 模拟更新图表数据
|
||||
// 实际项目中应该通过API获取
|
||||
}
|
||||
};
|
||||
|
||||
// 买入股票
|
||||
const buyStock = () => {
|
||||
// 实现买入逻辑
|
||||
alert(`买入${tradeAmount.value}股 ${currentStockInfo.value.name}`);
|
||||
};
|
||||
|
||||
// 卖出股票
|
||||
const sellStock = () => {
|
||||
// 实现卖出逻辑
|
||||
alert(`卖出${tradeAmount.value}股 ${currentStockInfo.value.name}`);
|
||||
};
|
||||
|
||||
// 生命周期钩子
|
||||
onMounted(() => {
|
||||
// 初始化数据,可以从API获取
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.stock-dashboard {
|
||||
background-color: #0d1117;
|
||||
color: #e6edf3;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
min-height: 100vh;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
||||
}
|
||||
|
||||
.stock-selector {
|
||||
display: none; /* 移除原来的选择器区域 */
|
||||
}
|
||||
|
||||
.stock-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 20px;
|
||||
background-color: #161b22;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 10px rgba(0, 255, 255, 0.1);
|
||||
border: 1px solid #30363d;
|
||||
}
|
||||
|
||||
.title-area {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.selector-area {
|
||||
flex: 0 0 150px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 0;
|
||||
color: #58a6ff;
|
||||
text-shadow: 0 0 5px rgba(88, 166, 255, 0.3);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 2fr 1fr;
|
||||
gap: 20px;
|
||||
height: 52vh;
|
||||
min-height: 320px;
|
||||
}
|
||||
|
||||
.news-section, .stock-panel, .trade-history {
|
||||
background-color: #161b22;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 0 10px rgba(0, 255, 255, 0.1);
|
||||
border: 1px solid #30363d;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #30363d;
|
||||
}
|
||||
|
||||
.section-header h3 {
|
||||
margin: 0;
|
||||
margin-left: 10px;
|
||||
color: #58a6ff;
|
||||
}
|
||||
|
||||
.icon {
|
||||
color: #58a6ff;
|
||||
}
|
||||
|
||||
.news-list {
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.news-item {
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid #30363d;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.news-item:hover {
|
||||
background-color: #1c2128;
|
||||
}
|
||||
|
||||
.news-date {
|
||||
font-size: 0.8em;
|
||||
color: #8b949e;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.news-title {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.stock-info {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.price-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.current-price {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.price-up {
|
||||
color: #3fb950;
|
||||
}
|
||||
|
||||
.price-down {
|
||||
color: #f85149;
|
||||
}
|
||||
|
||||
.stock-chart {
|
||||
flex: 1;
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
.trade-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.history-list {
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.history-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid #30363d;
|
||||
}
|
||||
|
||||
.buy-type {
|
||||
color: #3fb950;
|
||||
}
|
||||
|
||||
.sell-type {
|
||||
color: #f85149;
|
||||
}
|
||||
|
||||
.portfolio {
|
||||
background-color: #161b22;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
box-shadow: 0 0 10px rgba(0, 255, 255, 0.1);
|
||||
border: 1px solid #30363d;
|
||||
height: 1000px;
|
||||
}
|
||||
|
||||
.total-value {
|
||||
margin-left: auto;
|
||||
font-weight: bold;
|
||||
color: #3fb950;
|
||||
}
|
||||
|
||||
/* 修改Element Plus的默认样式以匹配主题 */
|
||||
:deep(.el-select),
|
||||
:deep(.el-input),
|
||||
:deep(.el-button),
|
||||
:deep(.el-table) {
|
||||
--el-bg-color: #161b22;
|
||||
--el-text-color-primary: #e6edf3;
|
||||
--el-border-color: #30363d;
|
||||
}
|
||||
|
||||
:deep(.el-table) {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
:deep(.el-table th) {
|
||||
background-color: #1c2128;
|
||||
}
|
||||
|
||||
:deep(.el-table tr) {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
:deep(.el-table--striped .el-table__body tr.el-table__row--striped td) {
|
||||
background-color: #1c2128;
|
||||
}
|
||||
|
||||
:deep(.el-table td, .el-table th) {
|
||||
border-color: #30363d;
|
||||
}
|
||||
|
||||
:deep(.el-select) {
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
/* 调整表格最大高度 */
|
||||
:deep(.el-table__body-wrapper) {
|
||||
overflow-y: auto;
|
||||
max-height: calc(35vh - 80px);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user