|
|
@@ -2,52 +2,78 @@
|
|
|
<view class="page-rank">
|
|
|
<scroll-view class="scroll-view" scroll-y>
|
|
|
<view class="content-wrapper" :class="{ 'blur-content': !isLoggedIn }">
|
|
|
- <!-- 股票列表 -->
|
|
|
- <view v-if="myStocks.length > 0" class="stock-list">
|
|
|
+ <!-- 上证指数卡片 -->
|
|
|
+ <view class="index-card">
|
|
|
+ <view class="index-left">
|
|
|
+ <view class="index-price-row">
|
|
|
+ <text :class="['index-price', getIndexChangeClass(indexData.changePercent)]">
|
|
|
+ {{ formatIndexPrice(indexData.currentPrice) }}
|
|
|
+ </text>
|
|
|
+ <text :class="['index-change', getIndexChangeClass(indexData.changePercent)]">
|
|
|
+ {{ indexData.priceChange || '--' }}
|
|
|
+ </text>
|
|
|
+ </view>
|
|
|
+ <view class="index-name-row">
|
|
|
+ <text class="index-name">{{ indexData.stockName || '上证指数' }}</text>
|
|
|
+ <text :class="['index-percent', getIndexChangeClass(indexData.changePercent)]">
|
|
|
+ {{ indexData.changePercent || '--' }}
|
|
|
+ </text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 切换按钮 -->
|
|
|
+ <view class="view-switch">
|
|
|
+ <view class="switch-btn" @click="toggleViewMode">
|
|
|
+ <text class="switch-icon">{{ viewMode === 'list' ? '📊' : '📋' }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 列表视图 -->
|
|
|
+ <view v-if="viewMode === 'list' && myStocks.length > 0" class="stock-list">
|
|
|
+ <stock-list-item
|
|
|
+ v-for="(stock, index) in myStocks"
|
|
|
+ :key="stock.code"
|
|
|
+ :stock="stock"
|
|
|
+ :show-delete="true"
|
|
|
+ @delete="removeStock(index)"
|
|
|
+ @click="handleStockClick(stock, index)"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 表格视图 -->
|
|
|
+ <view v-if="viewMode === 'table' && myStocks.length > 0" class="stock-table">
|
|
|
+ <!-- 表头 -->
|
|
|
+ <view class="table-header">
|
|
|
+ <text class="th-name">股票</text>
|
|
|
+ <text class="th-date">自选日</text>
|
|
|
+ <text class="th-price">自选价</text>
|
|
|
+ <text class="th-profit">自选收益</text>
|
|
|
+ </view>
|
|
|
+ <!-- 表格内容 -->
|
|
|
<view
|
|
|
v-for="(stock, index) in myStocks"
|
|
|
- :key="index"
|
|
|
- class="stock-card"
|
|
|
+ :key="stock.code"
|
|
|
+ class="table-row"
|
|
|
+ @click="handleStockClick(stock, index)"
|
|
|
>
|
|
|
- <view class="stock-header">
|
|
|
- <view class="stock-title">
|
|
|
- <text class="stock-name">{{ stock.name }}</text>
|
|
|
+ <view class="td-name">
|
|
|
+ <text class="stock-name">{{ stock.name }}</text>
|
|
|
+ <view class="stock-code-row">
|
|
|
+ <text :class="['stock-tag', getMarketClass(stock.code)]">{{ getMarketTag(stock.code) }}</text>
|
|
|
<text class="stock-code">{{ stock.code }}</text>
|
|
|
</view>
|
|
|
- <view class="delete-btn" @click="removeStock(index)">
|
|
|
- <text class="delete-icon">×</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <view class="stock-body">
|
|
|
- <!-- 涨跌信息 -->
|
|
|
- <view class="quote-row">
|
|
|
- <view class="quote-item">
|
|
|
- <text class="quote-label">涨跌额</text>
|
|
|
- <text
|
|
|
- class="quote-value"
|
|
|
- :class="getChangeClass(stock.priceChange)"
|
|
|
- >{{ stock.priceChange || '--' }}</text>
|
|
|
- </view>
|
|
|
- <view class="quote-item">
|
|
|
- <text class="quote-label">涨跌幅</text>
|
|
|
- <text
|
|
|
- class="quote-value"
|
|
|
- :class="getChangeClass(stock.changePercent)"
|
|
|
- >{{ stock.changePercent || '--' }}</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <view class="info-item">
|
|
|
- <text class="info-label">添加时间</text>
|
|
|
- <text class="info-value">{{ formatDate(stock.addTime) }}</text>
|
|
|
- </view>
|
|
|
</view>
|
|
|
+ <text class="td-date">{{ stock.addDate || '--' }}</text>
|
|
|
+ <text class="td-price">{{ formatPrice(stock.addPrice) }}</text>
|
|
|
+ <text :class="['td-profit', getProfitClass(stock.profitPercent)]">
|
|
|
+ {{ stock.profitPercent || '--' }}
|
|
|
+ </text>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 空状态 -->
|
|
|
- <view v-else class="empty-content">
|
|
|
+ <view v-if="myStocks.length === 0" class="empty-content">
|
|
|
<view class="empty-icon">📊</view>
|
|
|
<text class="empty-text">暂无收藏股票</text>
|
|
|
<text class="empty-desc">在强势池中点击"+"按钮添加股票</text>
|
|
|
@@ -64,12 +90,7 @@
|
|
|
<view class="lock-icon">🔒</view>
|
|
|
<text class="prompt-title">登录后查看我的股票</text>
|
|
|
<text class="prompt-desc">使用微信授权快速登录</text>
|
|
|
-
|
|
|
- <!-- 跳转到登录页按钮 -->
|
|
|
- <button
|
|
|
- class="login-button-native"
|
|
|
- @click="goToLogin"
|
|
|
- >
|
|
|
+ <button class="login-button-native" @click="goToLogin">
|
|
|
<text>登录</text>
|
|
|
</button>
|
|
|
</view>
|
|
|
@@ -81,70 +102,170 @@
|
|
|
import { ref } from 'vue'
|
|
|
import { onLoad, onShow, onHide, onUnload } from '@dcloudio/uni-app'
|
|
|
import { isLoggedIn as checkLoginStatus } from '../../utils/auth.js'
|
|
|
-import { getStockQuotes } from '../../utils/api.js'
|
|
|
+import { getStockQuotes, getIndexQuote, getUserStocks, deleteUserStock } from '../../utils/api.js'
|
|
|
+import StockListItem from '../../components/StockListItem.vue'
|
|
|
|
|
|
const isLoggedIn = ref(false)
|
|
|
const myStocks = ref([])
|
|
|
-let refreshTimer = null // 定时刷新定时器
|
|
|
+const viewMode = ref('list') // 'list' 或 'table'
|
|
|
+
|
|
|
+// 切换视图模式
|
|
|
+const toggleViewMode = () => {
|
|
|
+ viewMode.value = viewMode.value === 'list' ? 'table' : 'list'
|
|
|
+}
|
|
|
+
|
|
|
+const indexData = ref({
|
|
|
+ stockCode: '000001',
|
|
|
+ stockName: '上证指数',
|
|
|
+ currentPrice: null,
|
|
|
+ priceChange: null,
|
|
|
+ changePercent: null
|
|
|
+})
|
|
|
+let refreshTimer = null
|
|
|
+
|
|
|
+// 获取上证指数数据
|
|
|
+const fetchIndexData = async () => {
|
|
|
+ try {
|
|
|
+ const res = await getIndexQuote('000001')
|
|
|
+ if (res.code === 200 && res.data) {
|
|
|
+ indexData.value = { ...indexData.value, ...res.data }
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error('[上证指数] 获取失败:', e.message)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 格式化指数价格
|
|
|
+const formatIndexPrice = (price) => {
|
|
|
+ if (!price) return '--'
|
|
|
+ return parseFloat(price).toFixed(2)
|
|
|
+}
|
|
|
|
|
|
-// 加载我的股票列表
|
|
|
+// 格式化价格
|
|
|
+const formatPrice = (price) => {
|
|
|
+ if (!price) return '--'
|
|
|
+ return parseFloat(price).toFixed(2)
|
|
|
+}
|
|
|
+
|
|
|
+// 获取指数涨跌样式类
|
|
|
+const getIndexChangeClass = (changePercent) => {
|
|
|
+ if (!changePercent) return ''
|
|
|
+ const str = String(changePercent).replace('%', '').replace('+', '')
|
|
|
+ const value = parseFloat(str)
|
|
|
+ if (value > 0) return 'index-up'
|
|
|
+ if (value < 0) return 'index-down'
|
|
|
+ return ''
|
|
|
+}
|
|
|
+
|
|
|
+// 获取收益样式类
|
|
|
+const getProfitClass = (profitPercent) => {
|
|
|
+ if (!profitPercent) return ''
|
|
|
+ const str = String(profitPercent).replace('%', '').replace('+', '')
|
|
|
+ const value = parseFloat(str)
|
|
|
+ if (value > 0) return 'profit-up'
|
|
|
+ if (value < 0) return 'profit-down'
|
|
|
+ return ''
|
|
|
+}
|
|
|
+
|
|
|
+// 获取市场标签
|
|
|
+const getMarketTag = (code) => {
|
|
|
+ if (code.startsWith('6')) return '沪'
|
|
|
+ if (code.startsWith('0')) return '深'
|
|
|
+ if (code.startsWith('3')) return '创'
|
|
|
+ return '沪'
|
|
|
+}
|
|
|
+
|
|
|
+const getMarketClass = (code) => {
|
|
|
+ if (code.startsWith('6')) return 'market-sh'
|
|
|
+ if (code.startsWith('0')) return 'market-sz'
|
|
|
+ if (code.startsWith('3')) return 'market-cy'
|
|
|
+ return 'market-sh'
|
|
|
+}
|
|
|
+
|
|
|
+// 加载我的股票列表(从服务器)
|
|
|
const loadMyStocks = async () => {
|
|
|
- // 只有登录后才加载股票列表
|
|
|
if (!isLoggedIn.value) {
|
|
|
myStocks.value = []
|
|
|
- stopAutoRefresh() // 未登录时停止刷新
|
|
|
+ stopAutoRefresh()
|
|
|
return
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
- const stocks = uni.getStorageSync('my_stocks') || []
|
|
|
- myStocks.value = stocks
|
|
|
- console.log('[我的股票] 加载股票列表:', stocks.length, '只')
|
|
|
+ // 从服务器获取用户自选股票
|
|
|
+ const res = await getUserStocks()
|
|
|
+ console.log('[我的股票] 服务器返回:', JSON.stringify(res))
|
|
|
+
|
|
|
+ if (res.code === 200 && res.data) {
|
|
|
+ // 转换数据格式
|
|
|
+ myStocks.value = res.data.map(item => ({
|
|
|
+ code: item.stockCode,
|
|
|
+ name: item.stockName,
|
|
|
+ addPrice: item.addPrice,
|
|
|
+ addDate: item.addDate,
|
|
|
+ currentPrice: item.currentPrice,
|
|
|
+ profitPercent: item.profitPercent,
|
|
|
+ priceChange: item.priceChange,
|
|
|
+ changePercent: item.changePercent,
|
|
|
+ trendData: item.trendData
|
|
|
+ }))
|
|
|
+ } else {
|
|
|
+ // 如果服务器没有数据,尝试从本地存储加载
|
|
|
+ const localStocks = uni.getStorageSync('my_stocks') || []
|
|
|
+ myStocks.value = localStocks
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取上证指数
|
|
|
+ await fetchIndexData()
|
|
|
|
|
|
- // 如果没有股票数据,停止定时刷新
|
|
|
- if (stocks.length === 0) {
|
|
|
- stopAutoRefresh()
|
|
|
- return
|
|
|
+ // 如果有股票数据,刷新行情
|
|
|
+ if (myStocks.value.length > 0) {
|
|
|
+ await refreshAllQuotes()
|
|
|
}
|
|
|
|
|
|
- // 自动刷新所有股票的实时行情
|
|
|
- await refreshAllQuotes()
|
|
|
+ // 登录后启动定时刷新
|
|
|
+ startAutoRefresh()
|
|
|
} catch (e) {
|
|
|
console.error('加载股票列表失败:', e)
|
|
|
- myStocks.value = []
|
|
|
- stopAutoRefresh() // 加载失败时停止刷新
|
|
|
+ // 失败时从本地存储加载
|
|
|
+ const localStocks = uni.getStorageSync('my_stocks') || []
|
|
|
+ myStocks.value = localStocks
|
|
|
+ startAutoRefresh()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 批量刷新所有股票行情
|
|
|
const refreshAllQuotes = async () => {
|
|
|
- if (myStocks.value.length === 0) {
|
|
|
- console.log('[我的股票] 股票列表为空,停止定时刷新')
|
|
|
- stopAutoRefresh()
|
|
|
- return
|
|
|
- }
|
|
|
+ if (myStocks.value.length === 0) return
|
|
|
|
|
|
try {
|
|
|
const codes = myStocks.value.map(stock => stock.code).join(',')
|
|
|
- console.log('[我的股票] 刷新行情:', codes)
|
|
|
-
|
|
|
const quoteRes = await getStockQuotes(codes)
|
|
|
- console.log('[我的股票] API返回:', JSON.stringify(quoteRes))
|
|
|
|
|
|
if (quoteRes.code === 200 && quoteRes.data && quoteRes.data.length > 0) {
|
|
|
quoteRes.data.forEach(quoteData => {
|
|
|
const index = myStocks.value.findIndex(stock => stock.code === quoteData.stockCode)
|
|
|
if (index !== -1) {
|
|
|
- myStocks.value[index].priceChange = quoteData.priceChange
|
|
|
- myStocks.value[index].changePercent = quoteData.changePercent
|
|
|
- myStocks.value[index].stockName = quoteData.stockName || myStocks.value[index].name
|
|
|
+ const stock = myStocks.value[index]
|
|
|
+ stock.priceChange = quoteData.priceChange
|
|
|
+ stock.changePercent = quoteData.changePercent
|
|
|
+ stock.currentPrice = quoteData.currentPrice
|
|
|
+ stock.name = quoteData.stockName || stock.name
|
|
|
+ stock.trendData = quoteData.trendData || null
|
|
|
+
|
|
|
+ // 计算自选收益(当前价格相对于加入价格的涨跌幅)
|
|
|
+ if (stock.addPrice && quoteData.currentPrice) {
|
|
|
+ const addPrice = parseFloat(stock.addPrice)
|
|
|
+ const currentPrice = parseFloat(quoteData.currentPrice)
|
|
|
+ if (addPrice > 0) {
|
|
|
+ const profit = ((currentPrice - addPrice) / addPrice * 100).toFixed(2)
|
|
|
+ stock.profitPercent = profit >= 0 ? `+${profit}%` : `${profit}%`
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
})
|
|
|
|
|
|
+ // 同步到本地存储
|
|
|
uni.setStorageSync('my_stocks', myStocks.value)
|
|
|
- console.log('[我的股票] 刷新成功')
|
|
|
- } else {
|
|
|
- console.error('[我的股票] 刷新失败:', quoteRes)
|
|
|
}
|
|
|
} catch (e) {
|
|
|
console.error('[我的股票] 刷新异常:', e.message)
|
|
|
@@ -153,17 +274,17 @@ const refreshAllQuotes = async () => {
|
|
|
|
|
|
// 启动定时刷新
|
|
|
const startAutoRefresh = () => {
|
|
|
- // 清除旧的定时器
|
|
|
+ if (!isLoggedIn.value) return
|
|
|
stopAutoRefresh()
|
|
|
|
|
|
const scheduleNextRefresh = () => {
|
|
|
- // 2秒 + 0-1秒的随机数 = 2000-3000ms
|
|
|
- const delay = 2000 + Math.random() * 1000
|
|
|
- console.log(`[我的股票] 下次刷新将在 ${Math.round(delay)}ms 后执行`)
|
|
|
-
|
|
|
+ const delay = 3000 + Math.random() * 1000
|
|
|
refreshTimer = setTimeout(async () => {
|
|
|
- await refreshAllQuotes()
|
|
|
- scheduleNextRefresh() // 递归调度下一次刷新
|
|
|
+ await fetchIndexData()
|
|
|
+ if (myStocks.value.length > 0) {
|
|
|
+ await refreshAllQuotes()
|
|
|
+ }
|
|
|
+ scheduleNextRefresh()
|
|
|
}, delay)
|
|
|
}
|
|
|
|
|
|
@@ -175,35 +296,42 @@ const stopAutoRefresh = () => {
|
|
|
if (refreshTimer) {
|
|
|
clearTimeout(refreshTimer)
|
|
|
refreshTimer = null
|
|
|
- console.log('[我的股票] 停止自动刷新')
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 跳转到登录页
|
|
|
const goToLogin = () => {
|
|
|
- uni.navigateTo({
|
|
|
- url: '/pages/login/login'
|
|
|
- })
|
|
|
+ uni.navigateTo({ url: '/pages/login/login' })
|
|
|
+}
|
|
|
+
|
|
|
+// 点击股票项
|
|
|
+const handleStockClick = (stockItem, idx) => {
|
|
|
+ console.log('点击股票:', stockItem.name, idx)
|
|
|
+ uni.showToast({ title: '股票详情功能开发中', icon: 'none' })
|
|
|
}
|
|
|
|
|
|
// 删除股票
|
|
|
-const removeStock = (index) => {
|
|
|
+const removeStock = async (idx) => {
|
|
|
+ const stock = myStocks.value[idx]
|
|
|
uni.showModal({
|
|
|
title: '确认删除',
|
|
|
- content: `确定要删除 ${myStocks.value[index].name} 吗?`,
|
|
|
+ content: `确定要删除 ${stock.name} 吗?`,
|
|
|
confirmText: '删除',
|
|
|
cancelText: '取消',
|
|
|
- success: (res) => {
|
|
|
+ success: async (res) => {
|
|
|
if (res.confirm) {
|
|
|
- myStocks.value.splice(index, 1)
|
|
|
- // 保存到本地存储
|
|
|
+ try {
|
|
|
+ // 调用服务器删除接口
|
|
|
+ await deleteUserStock(stock.code)
|
|
|
+ } catch (e) {
|
|
|
+ console.error('删除失败:', e)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 从本地列表删除
|
|
|
+ myStocks.value.splice(idx, 1)
|
|
|
uni.setStorageSync('my_stocks', myStocks.value)
|
|
|
- uni.showToast({
|
|
|
- title: '删除成功',
|
|
|
- icon: 'success'
|
|
|
- })
|
|
|
+ uni.showToast({ title: '删除成功', icon: 'success' })
|
|
|
|
|
|
- // 如果删除后列表为空,停止定时刷新
|
|
|
if (myStocks.value.length === 0) {
|
|
|
stopAutoRefresh()
|
|
|
}
|
|
|
@@ -212,35 +340,8 @@ const removeStock = (index) => {
|
|
|
})
|
|
|
}
|
|
|
|
|
|
-// 根据涨跌值返回样式类名
|
|
|
-const getChangeClass = (value) => {
|
|
|
- if (!value || value === '--') return ''
|
|
|
- // 判断是否为正数(涨)
|
|
|
- if (value.startsWith('+') || (value.match(/^[\d.]/) && !value.startsWith('-'))) {
|
|
|
- return 'change-up'
|
|
|
- }
|
|
|
- // 判断是否为负数(跌)
|
|
|
- if (value.startsWith('-')) {
|
|
|
- return 'change-down'
|
|
|
- }
|
|
|
- return ''
|
|
|
-}
|
|
|
-
|
|
|
-// 格式化日期
|
|
|
-const formatDate = (timestamp) => {
|
|
|
- const date = new Date(timestamp)
|
|
|
- const year = date.getFullYear()
|
|
|
- const month = String(date.getMonth() + 1).padStart(2, '0')
|
|
|
- const day = String(date.getDate()).padStart(2, '0')
|
|
|
- const hours = String(date.getHours()).padStart(2, '0')
|
|
|
- const minutes = String(date.getMinutes()).padStart(2, '0')
|
|
|
-
|
|
|
- return `${year}-${month}-${day} ${hours}:${minutes}`
|
|
|
-}
|
|
|
-
|
|
|
onLoad(() => {
|
|
|
isLoggedIn.value = checkLoginStatus()
|
|
|
- console.log('[我的股票] 登录状态:', isLoggedIn.value)
|
|
|
loadMyStocks()
|
|
|
})
|
|
|
|
|
|
@@ -248,21 +349,12 @@ onShow(() => {
|
|
|
isLoggedIn.value = checkLoginStatus()
|
|
|
loadMyStocks()
|
|
|
uni.setNavigationBarTitle({ title: '量化交易大师' })
|
|
|
-
|
|
|
- // 只有登录且有股票数据时才启动定时刷新
|
|
|
- if (isLoggedIn.value && myStocks.value.length > 0) {
|
|
|
- startAutoRefresh()
|
|
|
- } else {
|
|
|
- stopAutoRefresh()
|
|
|
- }
|
|
|
})
|
|
|
|
|
|
-// 页面隐藏时停止刷新
|
|
|
onHide(() => {
|
|
|
stopAutoRefresh()
|
|
|
})
|
|
|
|
|
|
-// 页面卸载时停止刷新
|
|
|
onUnload(() => {
|
|
|
stopAutoRefresh()
|
|
|
})
|
|
|
@@ -286,126 +378,222 @@ onUnload(() => {
|
|
|
min-height: 100%;
|
|
|
}
|
|
|
|
|
|
-/* 股票列表 */
|
|
|
-.stock-list {
|
|
|
+/* 上证指数卡片 */
|
|
|
+.index-card {
|
|
|
display: flex;
|
|
|
- flex-direction: column;
|
|
|
- gap: 24rpx;
|
|
|
-}
|
|
|
-
|
|
|
-.stock-card {
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
background: #ffffff;
|
|
|
border-radius: 24rpx;
|
|
|
padding: 32rpx;
|
|
|
+ margin-bottom: 24rpx;
|
|
|
box-shadow: 0 8rpx 24rpx rgba(37, 52, 94, 0.08);
|
|
|
}
|
|
|
|
|
|
-.stock-header {
|
|
|
+.index-left {
|
|
|
display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- margin-bottom: 24rpx;
|
|
|
- padding-bottom: 24rpx;
|
|
|
- border-bottom: 1rpx solid #f1f2f6;
|
|
|
+ flex-direction: column;
|
|
|
}
|
|
|
|
|
|
-.stock-title {
|
|
|
+.index-price-row {
|
|
|
display: flex;
|
|
|
- flex-direction: column;
|
|
|
- gap: 8rpx;
|
|
|
+ align-items: baseline;
|
|
|
+ margin-bottom: 8rpx;
|
|
|
}
|
|
|
|
|
|
-.stock-name {
|
|
|
- font-size: 34rpx;
|
|
|
+.index-price {
|
|
|
+ font-size: 48rpx;
|
|
|
font-weight: 700;
|
|
|
- color: #222222;
|
|
|
+ margin-right: 16rpx;
|
|
|
}
|
|
|
|
|
|
-.stock-code {
|
|
|
+.index-change {
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+
|
|
|
+.index-name-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.index-name {
|
|
|
font-size: 26rpx;
|
|
|
- color: #5d55e8;
|
|
|
- font-weight: 500;
|
|
|
+ color: #666666;
|
|
|
+ margin-right: 12rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.index-percent {
|
|
|
+ font-size: 26rpx;
|
|
|
+ font-weight: 600;
|
|
|
}
|
|
|
|
|
|
-.delete-btn {
|
|
|
- width: 56rpx;
|
|
|
- height: 56rpx;
|
|
|
- background: #f16565;
|
|
|
- border-radius: 50%;
|
|
|
+.index-up {
|
|
|
+ color: #FF3B30;
|
|
|
+}
|
|
|
+
|
|
|
+.index-down {
|
|
|
+ color: #34C759;
|
|
|
+}
|
|
|
+
|
|
|
+/* 切换按钮 */
|
|
|
+.view-switch {
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ margin-bottom: 16rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.switch-btn {
|
|
|
+ width: 64rpx;
|
|
|
+ height: 64rpx;
|
|
|
+ background: #ffffff;
|
|
|
+ border-radius: 12rpx;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
- box-shadow: 0 4rpx 12rpx rgba(241, 101, 101, 0.3);
|
|
|
+ box-shadow: 0 4rpx 12rpx rgba(37, 52, 94, 0.08);
|
|
|
}
|
|
|
|
|
|
-.delete-icon {
|
|
|
- font-size: 40rpx;
|
|
|
- font-weight: 700;
|
|
|
- color: #ffffff;
|
|
|
- line-height: 1;
|
|
|
+.switch-btn:active {
|
|
|
+ background: #f5f6fb;
|
|
|
+}
|
|
|
+
|
|
|
+.switch-icon {
|
|
|
+ font-size: 28rpx;
|
|
|
}
|
|
|
|
|
|
-.stock-body {
|
|
|
+/* 股票列表 */
|
|
|
+.stock-list {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
- gap: 12rpx;
|
|
|
+ background: #ffffff;
|
|
|
+ border-radius: 24rpx;
|
|
|
+ padding: 0 32rpx;
|
|
|
+ box-shadow: 0 8rpx 24rpx rgba(37, 52, 94, 0.08);
|
|
|
}
|
|
|
|
|
|
-.info-item {
|
|
|
+/* 表格视图 */
|
|
|
+.stock-table {
|
|
|
+ background: #ffffff;
|
|
|
+ border-radius: 24rpx;
|
|
|
+ padding: 0 24rpx;
|
|
|
+ box-shadow: 0 8rpx 24rpx rgba(37, 52, 94, 0.08);
|
|
|
+}
|
|
|
+
|
|
|
+.table-header {
|
|
|
display: flex;
|
|
|
- justify-content: space-between;
|
|
|
align-items: center;
|
|
|
+ padding: 24rpx 0;
|
|
|
+ border-bottom: 1rpx solid #f1f2f6;
|
|
|
}
|
|
|
|
|
|
-.info-label {
|
|
|
- font-size: 26rpx;
|
|
|
- color: #666a7f;
|
|
|
+.table-header text {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #999999;
|
|
|
+ font-weight: 500;
|
|
|
}
|
|
|
|
|
|
-.info-value {
|
|
|
- font-size: 26rpx;
|
|
|
- color: #222222;
|
|
|
- font-weight: 500;
|
|
|
+.th-name {
|
|
|
+ flex: 1;
|
|
|
}
|
|
|
|
|
|
-/* 涨跌信息样式 */
|
|
|
-.quote-row {
|
|
|
+.th-date {
|
|
|
+ width: 160rpx;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.th-price {
|
|
|
+ width: 140rpx;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.th-profit {
|
|
|
+ width: 140rpx;
|
|
|
+ text-align: right;
|
|
|
+}
|
|
|
+
|
|
|
+.table-row {
|
|
|
display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- gap: 24rpx;
|
|
|
- margin-bottom: 16rpx;
|
|
|
- padding: 20rpx;
|
|
|
- background: #f7f8fc;
|
|
|
- border-radius: 16rpx;
|
|
|
+ align-items: center;
|
|
|
+ padding: 24rpx 0;
|
|
|
+ border-bottom: 1rpx solid #f1f2f6;
|
|
|
}
|
|
|
|
|
|
-.quote-item {
|
|
|
+.table-row:last-child {
|
|
|
+ border-bottom: none;
|
|
|
+}
|
|
|
+
|
|
|
+.td-name {
|
|
|
flex: 1;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
+}
|
|
|
+
|
|
|
+.td-name .stock-name {
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #222222;
|
|
|
+ margin-bottom: 4rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.stock-code-row {
|
|
|
+ display: flex;
|
|
|
align-items: center;
|
|
|
}
|
|
|
|
|
|
-.quote-label {
|
|
|
+.stock-tag {
|
|
|
+ font-size: 18rpx;
|
|
|
+ padding: 2rpx 6rpx;
|
|
|
+ border-radius: 4rpx;
|
|
|
+ color: #ffffff;
|
|
|
+ font-weight: 500;
|
|
|
+ margin-right: 8rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.market-sh {
|
|
|
+ background: #FF3B30;
|
|
|
+}
|
|
|
+
|
|
|
+.market-sz {
|
|
|
+ background: #34C759;
|
|
|
+}
|
|
|
+
|
|
|
+.market-cy {
|
|
|
+ background: #FF9500;
|
|
|
+}
|
|
|
+
|
|
|
+.stock-code {
|
|
|
+ font-size: 22rpx;
|
|
|
+ color: #9ca2b5;
|
|
|
+}
|
|
|
+
|
|
|
+.td-date {
|
|
|
+ width: 160rpx;
|
|
|
+ text-align: center;
|
|
|
font-size: 24rpx;
|
|
|
- color: #666a7f;
|
|
|
- margin-bottom: 8rpx;
|
|
|
+ color: #666666;
|
|
|
}
|
|
|
|
|
|
-.quote-value {
|
|
|
- font-size: 32rpx;
|
|
|
- font-weight: 700;
|
|
|
- color: #222222;
|
|
|
+.td-price {
|
|
|
+ width: 140rpx;
|
|
|
+ text-align: center;
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #333333;
|
|
|
+}
|
|
|
+
|
|
|
+.td-profit {
|
|
|
+ width: 140rpx;
|
|
|
+ text-align: right;
|
|
|
+ font-size: 26rpx;
|
|
|
+ font-weight: 600;
|
|
|
}
|
|
|
|
|
|
-/* 涨(红色) */
|
|
|
-.change-up {
|
|
|
- color: #f16565 !important;
|
|
|
+.profit-up {
|
|
|
+ color: #FF3B30;
|
|
|
}
|
|
|
|
|
|
-/* 跌(绿色) */
|
|
|
-.change-down {
|
|
|
- color: #3abf81 !important;
|
|
|
+.profit-down {
|
|
|
+ color: #34C759;
|
|
|
}
|
|
|
|
|
|
/* 空状态 */
|