Merge branch 'milestone-20251031-简版功能开发' of http://39.101.133.168:8807/qimaohong/deepChartVueApp into dongqian/feature-20251022181325-deepmate简版
zhaowenkang/feature-20251028181547-行情页面
-
5.hbuilderx/launch.json
-
14api/deepMate/deepMate.js
-
223api/tcpConnection.js
-
392common/canvasMethod.js
-
354common/stockTimeInformation.js
-
142common/util.js
-
56components/DeepMate.vue
-
190components/IndexCard.vue
-
78main.js
-
726package-lock.json
-
8package.json
-
115pages.json
-
362pages/deepMate/deepMate.vue
-
63pages/deepMate/scroll/scroll.vue
-
579pages/home/globalIndex.vue
-
2046pages/home/marketCondition.vue
-
488pages/home/marketDetail.vue
-
924pages/home/marketSituation.vue
-
296pages/home/member.vue
-
22pages/morningMarketAnalysis/morningMarketAnalysis.vue
-
86pages/setting/about.vue
-
213pages/setting/account.vue
-
85pages/setting/bind.vue
-
142pages/setting/email.vue
-
68pages/setting/font.vue
-
165pages/setting/general.vue
-
76pages/setting/introduce.vue
-
221pages/setting/market.vue
-
62pages/setting/message.vue
-
82pages/setting/newVersion.vue
-
144pages/setting/nextPwd.vue
-
171pages/setting/password.vue
-
143pages/setting/phone.vue
-
108pages/setting/push.vue
-
87pages/setting/server.vue
-
111pages/setting/share.vue
-
64pages/setting/theme.vue
-
2pages/start/login/login.vue
-
BINstatic/marketSituation-image/back.png
-
BINstatic/marketSituation-image/bg.png
-
BINstatic/marketSituation-image/history.png
-
BINstatic/marketSituation-image/map.png
-
BINstatic/marketSituation-image/marketCondition-image/favorites.png
-
BINstatic/marketSituation-image/marketCondition-image/function.png
-
BINstatic/marketSituation-image/marketCondition-image/index.png
-
BINstatic/marketSituation-image/marketCondition-image/setting2.png
-
BINstatic/marketSituation-image/menu.png
-
BINstatic/marketSituation-image/more.png
-
BINstatic/marketSituation-image/mySeclected.png
-
BINstatic/marketSituation-image/search.png
-
BINstatic/marketSituation-image/warn.png
-
BINstatic/my/BlackTheme.png
-
BINstatic/my/Check-in.png
-
BINstatic/my/MarketSettings.png
-
BINstatic/my/QRcode.png
-
BINstatic/my/Settings.png
-
BINstatic/my/about.png
-
BINstatic/my/aboutDC.png
-
BINstatic/my/award.png
-
BINstatic/my/bell.png
-
BINstatic/my/bindedEmail.png
-
BINstatic/my/bindedPhone.png
-
BINstatic/my/changeBindPhone.png
-
BINstatic/my/changeEmail.png
-
BINstatic/my/common.png
-
BINstatic/my/connection.png
-
BINstatic/my/editName.png
-
BINstatic/my/greenBackground.png
-
BINstatic/my/greenRise.png
-
BINstatic/my/hideEye.png
-
BINstatic/my/invite.png
-
BINstatic/my/menu.png
-
BINstatic/my/myFriends.png
-
BINstatic/my/openEye.png
-
BINstatic/my/opinion.png
-
BINstatic/my/outline.png
-
BINstatic/my/polylines.png
-
BINstatic/my/redRise.png
-
BINstatic/my/security.png
-
BINstatic/my/setting.png
-
BINstatic/my/share.png
-
BINstatic/my/shareBackground.png
-
BINstatic/my/shareFriends.png
-
BINstatic/my/unlock.png
-
BINstatic/my/update.png
-
BINstatic/my/verification.png
-
BINstatic/my/whiteTheme.png
-
2utils/http.js
@ -0,0 +1,223 @@ |
|||
/** |
|||
* TCP连接工具类 |
|||
* 用于处理TCP连接、发送消息和断开连接 |
|||
*/ |
|||
|
|||
// 引用TCP插件
|
|||
const TCPSocket = uni.requireNativePlugin('Aimer-TCPPlugin'); |
|||
|
|||
// TCP连接配置
|
|||
const TCP_CONFIG = { |
|||
ip: '192.168.1.9', |
|||
port: '8080', |
|||
channel: '1', // 可选 1~20
|
|||
charsetname: 'UTF-8' // 默认UTF-8,可选GBK
|
|||
}; |
|||
|
|||
/** |
|||
* TCP连接管理类 |
|||
*/ |
|||
class TCPConnection { |
|||
constructor() { |
|||
this.isConnected = false; |
|||
this.connectionCallbacks = []; |
|||
this.messageCallbacks = []; |
|||
} |
|||
|
|||
/** |
|||
* TCP初始化连接 |
|||
* @param {Object} config - 连接配置 {ip, port, channel, charsetname} |
|||
* @param {Function} callback - 连接状态回调函数 |
|||
*/ |
|||
connect(config = {}, callback = null) { |
|||
const connectionConfig = { |
|||
channel: config.channel || TCP_CONFIG.channel, |
|||
ip: config.ip || TCP_CONFIG.ip, |
|||
port: config.port || TCP_CONFIG.port |
|||
}; |
|||
|
|||
// 如果指定了字符集,添加到配置中
|
|||
if (config.charsetname || TCP_CONFIG.charsetname) { |
|||
connectionConfig.charsetname = config.charsetname || TCP_CONFIG.charsetname; |
|||
} |
|||
|
|||
TCPSocket.connect( |
|||
connectionConfig, |
|||
result => { |
|||
/** |
|||
* status : 0 连接成功 |
|||
* status : 1 断开连接 |
|||
* receivedMsg : 服务器返回字符串(普通的字符串交互) |
|||
* receivedHexMsg : 服务器返回字节数组(单片机、智能家居等硬件数据交互) |
|||
*/ |
|||
if (result.status == '0') { |
|||
// TCP连接成功
|
|||
this.isConnected = true; |
|||
console.log('TCP连接成功'); |
|||
this._notifyConnectionCallbacks('connected', result); |
|||
} else if (result.status == '1') { |
|||
// TCP断开连接
|
|||
this.isConnected = false; |
|||
console.log('TCP断开连接'); |
|||
this._notifyConnectionCallbacks('disconnected', result); |
|||
} |
|||
|
|||
if (result.receivedMsg) { |
|||
// 服务器返回字符串
|
|||
console.log('收到字符串消息:', result.receivedMsg); |
|||
this._notifyMessageCallbacks('string', result.receivedMsg); |
|||
} |
|||
|
|||
// if (result.receivedHexMsg) {
|
|||
// // 硬件服务器返回16进制数据
|
|||
// console.log('收到16进制消息:', result.receivedHexMsg);
|
|||
// let msg = result.receivedHexMsg;
|
|||
// let sum = msg.length / 2;
|
|||
// let arr = [];
|
|||
// for (let k = 0; k < sum; k++) {
|
|||
// let i = msg.substring(k * 2, k * 2 + 2);
|
|||
// arr.push(i);
|
|||
// }
|
|||
// console.log('解析后的16进制数组:', arr);
|
|||
// this._notifyMessageCallbacks('hex', result.receivedHexMsg, arr);
|
|||
// }
|
|||
|
|||
// 执行回调函数
|
|||
if (callback && typeof callback === 'function') { |
|||
callback(result); |
|||
} |
|||
} |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* TCP发送消息(普通的字符串交互) |
|||
* @param {String|Object} message - 要发送的消息,如果是对象会自动转换为JSON字符串 |
|||
* @param {Object} config - 发送配置 {channel, charsetname} |
|||
*/ |
|||
send(message, config = {}) { |
|||
if (!this.isConnected) { |
|||
console.warn('TCP未连接,无法发送消息'); |
|||
return false; |
|||
} |
|||
|
|||
// 如果message是对象,转换为JSON字符串
|
|||
let messageStr = message; |
|||
if (typeof message === 'object') { |
|||
messageStr = JSON.stringify(message) + '\n'; |
|||
} |
|||
|
|||
const sendConfig = { |
|||
channel: config.channel || '1', // 注意:channel应该是字符串
|
|||
message: messageStr |
|||
}; |
|||
|
|||
// 如果指定了字符编码,添加到配置中
|
|||
if (config.charsetname) { |
|||
sendConfig.charsetname = config.charsetname; |
|||
} |
|||
|
|||
TCPSocket.send(sendConfig); |
|||
console.log('js成功发送TCP消息:', messageStr); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* TCP断开连接 |
|||
* @param {Object} config - 断开配置 {channel} |
|||
*/ |
|||
disconnect(config = {}) { |
|||
const disconnectConfig = { |
|||
channel: config.channel || TCP_CONFIG.channel |
|||
}; |
|||
|
|||
TCPSocket.disconnect(disconnectConfig); |
|||
this.isConnected = false; |
|||
console.log('TCP连接已断开', disconnectConfig); |
|||
} |
|||
|
|||
/** |
|||
* 添加连接状态监听器 |
|||
* @param {Function} callback - 回调函数 (status, result) => {} |
|||
*/ |
|||
onConnectionChange(callback) { |
|||
if (typeof callback === 'function') { |
|||
this.connectionCallbacks.push(callback); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 添加消息监听器 |
|||
* @param {Function} callback - 回调函数 (type, message, parsedArray) => {} |
|||
*/ |
|||
onMessage(callback) { |
|||
if (typeof callback === 'function') { |
|||
this.messageCallbacks.push(callback); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 移除连接状态监听器 |
|||
* @param {Function} callback - 要移除的回调函数 |
|||
*/ |
|||
removeConnectionListener(callback) { |
|||
const index = this.connectionCallbacks.indexOf(callback); |
|||
if (index > -1) { |
|||
this.connectionCallbacks.splice(index, 1); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 移除消息监听器 |
|||
* @param {Function} callback - 要移除的回调函数 |
|||
*/ |
|||
removeMessageListener(callback) { |
|||
const index = this.messageCallbacks.indexOf(callback); |
|||
if (index > -1) { |
|||
this.messageCallbacks.splice(index, 1); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 获取连接状态 |
|||
* @returns {Boolean} 连接状态 |
|||
*/ |
|||
getConnectionStatus() { |
|||
return this.isConnected; |
|||
} |
|||
|
|||
/** |
|||
* 通知连接状态回调 |
|||
* @private |
|||
*/ |
|||
_notifyConnectionCallbacks(status, result) { |
|||
this.connectionCallbacks.forEach(callback => { |
|||
try { |
|||
callback(status, result); |
|||
} catch (error) { |
|||
console.error('连接状态回调执行错误:', error); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 通知消息回调 |
|||
* @private |
|||
*/ |
|||
_notifyMessageCallbacks(type, message, parsedArray = null) { |
|||
this.messageCallbacks.forEach(callback => { |
|||
try { |
|||
callback(type, message, parsedArray); |
|||
} catch (error) { |
|||
console.error('消息回调执行错误:', error); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
|
|||
// 创建TCP连接实例
|
|||
const tcpConnection = new TCPConnection(); |
|||
|
|||
// 导出TCP连接实例和类
|
|||
export default tcpConnection; |
|||
export { TCPConnection, TCP_CONFIG }; |
|||
@ -0,0 +1,392 @@ |
|||
/** |
|||
* 功能:Canvas绘制方法。 |
|||
* 作者:洪锡林 |
|||
* 时间:2025年10月25日 |
|||
* |
|||
* @format |
|||
*/ |
|||
|
|||
import { utils } from "./util.js"; |
|||
export const HCharts = { |
|||
// 清除画布
|
|||
clearCanvas(ctx, width, height) { |
|||
ctx.clearRect(0, 0, width, height); |
|||
ctx.setFillStyle("#ffffff"); |
|||
ctx.fillRect(0, 0, width, height); |
|||
}, |
|||
// 设置画布颜色
|
|||
setCanvasColor(ctx, width, height, color) { |
|||
ctx.clearRect(0, 0, width, height); |
|||
ctx.setFillStyle(color); |
|||
ctx.fillRect(0, 0, width, height); |
|||
}, |
|||
// 绘制文本工具函数
|
|||
drawText(ctx, text, x, y, fontSize = 12, color = "#333", align = "left") { |
|||
ctx.setFontSize(fontSize); |
|||
ctx.setFillStyle(color); |
|||
ctx.setTextAlign(align); |
|||
ctx.fillText(text, x, y); |
|||
}, |
|||
/** |
|||
* 功能:绘制网格系统。 |
|||
* 作者:洪锡林 |
|||
* 时间:2025年10月25日 |
|||
* |
|||
* grid:[{ |
|||
* top:顶部距离 |
|||
* bottom:底部距离 |
|||
* left:左侧距离 |
|||
* right:右侧距离 |
|||
* lineColor:网格线颜色 |
|||
* lineWidth:网格线宽度 |
|||
* horizontalLineNum:水平网格线数量 |
|||
* verticalLineNum:垂直网格线数量 |
|||
* label:{ |
|||
* fontSize:字体大小 |
|||
* color:字体颜色 |
|||
* onlyTwo:是否只有两个标签 |
|||
* text:[{ |
|||
* value:值标签 |
|||
* ratio:比例标签 |
|||
* },{ |
|||
* value:值标签 |
|||
* ratio:比例标签 |
|||
* },...] |
|||
* },...] |
|||
*/ |
|||
// 绘制网格系统
|
|||
drawGrid(ctx, width, height, grid, openTime, closeTime) { |
|||
// 测试数据
|
|||
// const preClosePrice = prevClosePrice;
|
|||
for (let i = 0; i < grid.length; ++i) { |
|||
const top = grid[i].top; |
|||
const bottom = grid[i].bottom; |
|||
const left = grid[i].left; |
|||
const right = grid[i].right; |
|||
const lineColor = grid[i].lineColor; |
|||
const lineWidth = grid[i].lineWidth; |
|||
const horizontalLineNum = grid[i].horizontalLineNum - 1; |
|||
const verticalLineNum = grid[i].verticalLineNum - 1; |
|||
let label; |
|||
if (grid[i].label) { |
|||
label = grid[i].label; |
|||
} |
|||
ctx.setStrokeStyle(lineColor); |
|||
ctx.setLineWidth(lineWidth); |
|||
|
|||
// 画图底的开盘收盘时间
|
|||
if (i == 0 && openTime && closeTime) { |
|||
HCharts.drawText(ctx, openTime, 6, height - bottom + 12, 14, "#686868", "left"); |
|||
HCharts.drawText(ctx, closeTime, width - 6, height - bottom + 12, 14, "#686868", "right"); |
|||
} |
|||
// 绘制水平网格线
|
|||
for (let j = 0; j <= horizontalLineNum; j++) { |
|||
const y = top + (j * (height - bottom - top)) / horizontalLineNum; |
|||
ctx.beginPath(); |
|||
if (label.lineStyle[j] == "dash") { |
|||
ctx.setLineDash([5, 5]); |
|||
} |
|||
ctx.moveTo(left, y); |
|||
ctx.lineTo(width - right, y); |
|||
ctx.stroke(); |
|||
ctx.setLineDash([]); |
|||
} |
|||
// 绘制垂直网格线
|
|||
for (let i = 0; i <= verticalLineNum; i++) { |
|||
const x = ((width - left - right) * i) / verticalLineNum; |
|||
ctx.beginPath(); |
|||
ctx.moveTo(x + left, top); |
|||
ctx.lineTo(x + left, height - bottom); |
|||
ctx.stroke(); |
|||
} |
|||
} |
|||
}, |
|||
// 绘制价格标签
|
|||
drawAxisLabels(ctx, width, height, grid) { |
|||
for (let i = 0; i < grid.length; ++i) { |
|||
const top = grid[i].top; |
|||
const bottom = grid[i].bottom; |
|||
const left = grid[i].left; |
|||
const right = grid[i].right; |
|||
const horizontalLineNum = grid[i].horizontalLineNum - 1; |
|||
let label; |
|||
if (grid[i].label) { |
|||
label = grid[i].label; |
|||
} |
|||
// 绘制水平网格线
|
|||
for (let j = 0; j <= horizontalLineNum; j++) { |
|||
const y = top + (j * (height - bottom - top)) / horizontalLineNum; |
|||
// 价格标签
|
|||
if (label) { |
|||
let valueXText = left + 1; |
|||
let ratioXText = width - right - 1; |
|||
let yText = y + 10; |
|||
if (j == horizontalLineNum) { |
|||
yText = y - 1; |
|||
} |
|||
let valueAlign = "left"; |
|||
let ratioAlign = "right"; |
|||
let fontSize = label.fontSize; |
|||
let textColor = label.color[j]; |
|||
if (label.onlyTwo) { |
|||
if (j == 0) { |
|||
HCharts.drawText(ctx, label.text[0].value, valueXText, yText, fontSize, label.color[0], valueAlign); |
|||
} else if (j == horizontalLineNum) { |
|||
HCharts.drawText(ctx, label.text[1].value, valueXText, yText, fontSize, label.color[1], valueAlign); |
|||
} |
|||
} else { |
|||
HCharts.drawText(ctx, label.text[j].value, valueXText, yText, fontSize, textColor, valueAlign); |
|||
} |
|||
|
|||
if (typeof label.text[j]?.ratio !== "undefined") { |
|||
HCharts.drawText(ctx, label.text[j].ratio, ratioXText, yText, fontSize, textColor, ratioAlign); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
// 绘制价格曲线
|
|||
drawPriceLine(ctx, width, height, data, grid, priceRange) { |
|||
if (!data.length) return; |
|||
// 上下边距1
|
|||
const top = grid[0].top; |
|||
const bottom = grid[0].bottom; |
|||
const left = grid[0].left; |
|||
const right = grid[0].right; |
|||
const pointLen = 240; |
|||
const priceDiff = priceRange.max - priceRange.min; |
|||
// 绘制价格曲线
|
|||
ctx.setStrokeStyle("#000"); |
|||
ctx.setLineWidth(1); |
|||
ctx.beginPath(); |
|||
|
|||
data.forEach((item, index) => { |
|||
const x = left + (index * (width - left - right)) / pointLen; |
|||
const y = top + (height - top - bottom) * (1 - (item.price - priceRange.min) / priceDiff); |
|||
if (index === 0) { |
|||
ctx.moveTo(x, y); |
|||
} else { |
|||
// 使用贝塞尔曲线平滑连接
|
|||
const prevPoint = data[index - 1]; |
|||
const prevX = left + ((index - 1) * (width - left - right)) / pointLen; |
|||
const prevY = top + (height - top + -bottom) * (1 - (prevPoint.price - priceRange.min) / priceDiff); |
|||
const cp1x = (prevX + x) / 2; |
|||
const cp1y = prevY; |
|||
const cp2x = (prevX + x) / 2; |
|||
const cp2y = y; |
|||
ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y); |
|||
} |
|||
}); |
|||
ctx.stroke(); |
|||
// 绘制渐变背景
|
|||
HCharts.drawGradientBackground(ctx, width, height, data, grid, priceRange); |
|||
}, |
|||
|
|||
// 绘制渐变背景
|
|||
drawGradientBackground(ctx, width, height, data, grid, priceRange) { |
|||
// 上下边距1
|
|||
const top = grid[0].top; |
|||
const bottom = grid[0].bottom; |
|||
const left = grid[0].left; |
|||
const right = grid[0].right; |
|||
const pointLen = 240; |
|||
const priceDiff = priceRange.max - priceRange.min; |
|||
|
|||
const gradient = ctx.createLinearGradient(0, left, 0, height - top); |
|||
gradient.addColorStop(0, "rgba(0, 0, 0, 0.3)"); |
|||
gradient.addColorStop(1, "rgba(0, 0, 0, 0.05)"); |
|||
|
|||
ctx.beginPath(); |
|||
|
|||
// 绘制价格曲线路径
|
|||
data.forEach((item, index) => { |
|||
const x = left + (index * (width - left - right)) / pointLen; |
|||
const y = top + (height - top - bottom) * (1 - (item.price - priceRange.min) / priceDiff); |
|||
|
|||
if (index === 0) { |
|||
ctx.moveTo(x, y); |
|||
} else { |
|||
const prevPoint = data[index - 1]; |
|||
const prevX = left + ((index - 1) * (width - left - right)) / pointLen; |
|||
const prevY = top + (height - top - bottom) * (1 - (prevPoint.price - priceRange.min) / priceDiff); |
|||
|
|||
const cp1x = (prevX + x) / 2; |
|||
const cp1y = prevY; |
|||
const cp2x = (prevX + x) / 2; |
|||
const cp2y = y; |
|||
|
|||
ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y); |
|||
} |
|||
}); |
|||
|
|||
// 闭合路径
|
|||
const lastX = left + ((data.length - 1) * (width - left - right)) / pointLen; |
|||
ctx.lineTo(lastX, height - bottom); |
|||
ctx.lineTo(left, height - bottom); |
|||
ctx.closePath(); |
|||
|
|||
ctx.setFillStyle(gradient); |
|||
ctx.fill(); |
|||
}, |
|||
// 绘制成交量
|
|||
drawVolume(ctx, width, height, data, index, pointLen, grid, volumeRange, offset) { |
|||
if (!data.length) return; |
|||
|
|||
const top = grid[index - 1].top; |
|||
const bottom = grid[index - 1].bottom; |
|||
const left = grid[index - 1].left; |
|||
const right = grid[index - 1].right; |
|||
|
|||
data.forEach((item, index) => { |
|||
const x = offset + left + (index * (width - left - right)) / pointLen; |
|||
const barWidth = (width - left - right) / pointLen - 0.5; |
|||
const barHeight = (item.volume / volumeRange.max) * (height - bottom - top); |
|||
// 根据涨跌设置颜色
|
|||
const isRise = index === 0 || item.price >= data[index - 1].price || item.close >= data[index - 1].close; |
|||
ctx.setFillStyle(isRise ? "green" : "red"); |
|||
|
|||
ctx.fillRect(x - barWidth / 2, height - bottom - barHeight, barWidth, barHeight); |
|||
}); |
|||
}, |
|||
// 字符宽度近似计算(避免使用 measureText)
|
|||
getApproximateTextWidth(text, fontSize = 10) { |
|||
// 中文字符约等于 fontSize,英文字符约等于 fontSize * 0.6
|
|||
let width = 0; |
|||
for (let char of text) { |
|||
// 判断是否为中文字符
|
|||
if (char.match(/[\u4e00-\u9fa5]/)) { |
|||
width += fontSize; |
|||
} else { |
|||
width += fontSize * 0.6; |
|||
} |
|||
} |
|||
return width; |
|||
}, |
|||
// 绘制顶部价格显示
|
|||
drawTopPriceDisplay(ctx, grid, text) { |
|||
for (let i = 0; i < text.length; i++) { |
|||
let x = grid[i].left; |
|||
let y = grid[i].top - 4; |
|||
for (let j = 0; j < text[i].length; j++) { |
|||
ctx.setFillStyle(text[i][j].color); |
|||
ctx.setFontSize(10); |
|||
ctx.setTextAlign("left"); |
|||
ctx.fillText(text[i][j].name + ":" + text[i][j].value, x, y); |
|||
x += HCharts.getApproximateTextWidth(text[i][j].name + ":" + text[i][j].value) + 5; |
|||
} |
|||
} |
|||
}, |
|||
// 绘制坐标轴标签
|
|||
drawCrosshairAxisLabels(ctx, width, height, grid, crosshair) { |
|||
const { x, y } = crosshair; |
|||
// X轴时间标签
|
|||
if (crosshair.currentData && (crosshair.currentData.time || crosshair.currentData.date)) { |
|||
const timeText = crosshair.currentData.time || crosshair.currentData.date; |
|||
const xBoxWidth = crosshair.currentData.time ? 40 : 70; |
|||
const xBoxHeight = 15; |
|||
ctx.setFillStyle("#629AF5"); |
|||
|
|||
if (x - xBoxWidth / 2 <= grid[0].left) { |
|||
ctx.fillRect(grid[0].left, height - grid[0].bottom, xBoxWidth, xBoxHeight); |
|||
} else if (x + xBoxWidth / 2 < width - grid[0].right) { |
|||
ctx.fillRect(x - xBoxWidth / 2, height - grid[0].bottom, xBoxWidth, xBoxHeight); |
|||
} else { |
|||
ctx.fillRect(width - grid[0].right - xBoxWidth, height - grid[0].bottom, xBoxWidth, xBoxHeight); |
|||
} |
|||
|
|||
ctx.setFillStyle("#fff"); |
|||
ctx.setFontSize(12); |
|||
ctx.setTextAlign("center"); |
|||
|
|||
if (x - xBoxWidth / 2 <= grid[0].left) { |
|||
ctx.fillText(timeText, grid[0].left + xBoxWidth / 2, height - grid[0].bottom + 12); |
|||
} else if (x + xBoxWidth / 2 < width - grid[0].right) { |
|||
ctx.fillText(timeText, x, height - grid[0].bottom + 12); |
|||
} else { |
|||
ctx.fillText(timeText, width - grid[0].right - xBoxWidth / 2, height - grid[0].bottom + 12); |
|||
} |
|||
} |
|||
|
|||
// Y轴价格标签
|
|||
if (crosshair.currentData) { |
|||
const priceText = utils.formatPrice(crosshair.currentData.price); |
|||
const yBoxWidth = 50; |
|||
const yBoxHeight = 14; |
|||
ctx.setFillStyle("#629AF5"); |
|||
if (x < grid[0].left + yBoxWidth + 5) { |
|||
ctx.fillRect(width - grid[0].right - yBoxWidth, y - yBoxHeight / 2, yBoxWidth, yBoxHeight); |
|||
} else { |
|||
ctx.fillRect(grid[0].left, y - yBoxHeight / 2, yBoxWidth, yBoxHeight); |
|||
} |
|||
|
|||
ctx.setFillStyle("#fff"); |
|||
ctx.setFontSize(11); |
|||
ctx.setTextAlign("center"); |
|||
if (x < grid[0].left + yBoxWidth + 5) { |
|||
ctx.fillText(priceText, width - grid[0].right - yBoxWidth / 2, y + 3); |
|||
} else { |
|||
ctx.fillText(priceText, grid[0].left + yBoxWidth / 2, y + 3); |
|||
} |
|||
} |
|||
}, |
|||
// 绘制十字准线
|
|||
drawCrosshair(ctx, width, height, grid, crosshair, text) { |
|||
if (!ctx) return; |
|||
const { x, y } = crosshair; |
|||
if (crosshair.show) { |
|||
// 每次绘制前先清除整个画布
|
|||
ctx.clearRect(0, 0, width, height); |
|||
|
|||
// 绘制垂直准线1
|
|||
ctx.setStrokeStyle("#000"); |
|||
ctx.setLineWidth(1); |
|||
// ctx.setLineDash([5, 5]);
|
|||
|
|||
for (let i = 0; i < grid.length; i++) { |
|||
ctx.beginPath(); |
|||
ctx.moveTo(x, grid[i].top); |
|||
ctx.lineTo(x, height - grid[i].bottom); |
|||
ctx.stroke(); |
|||
} |
|||
// ctx.beginPath();
|
|||
// ctx.moveTo(x, grid[0].top);
|
|||
// ctx.lineTo(x, height - grid[0].bottom);
|
|||
// ctx.stroke();
|
|||
|
|||
// // 绘制垂直准线2
|
|||
// ctx.beginPath();
|
|||
// ctx.moveTo(x, grid[1].top);
|
|||
// ctx.lineTo(x, height - grid[1].bottom);
|
|||
// ctx.stroke();
|
|||
|
|||
// 绘制水平准线
|
|||
ctx.beginPath(); |
|||
ctx.moveTo(grid[0].left, y); |
|||
ctx.lineTo(width - grid[0].right, y); |
|||
ctx.stroke(); |
|||
|
|||
ctx.setLineDash([]); |
|||
|
|||
// 绘制焦点圆点 - 黑边白心(更小)
|
|||
// 先绘制白色填充
|
|||
ctx.setFillStyle("#ffffff"); |
|||
ctx.beginPath(); |
|||
ctx.arc(x, y, 2, 0, Math.PI * 2); |
|||
ctx.fill(); |
|||
|
|||
// 再绘制黑色边框
|
|||
ctx.setStrokeStyle("#000000"); |
|||
ctx.setLineWidth(1); |
|||
ctx.setLineDash([]); |
|||
ctx.beginPath(); |
|||
ctx.arc(x, y, 2, 0, Math.PI * 2); |
|||
ctx.stroke(); |
|||
|
|||
// 绘制坐标轴标签
|
|||
HCharts.drawCrosshairAxisLabels(ctx, width, height, grid, crosshair); |
|||
} |
|||
// 绘制顶部价格显示
|
|||
HCharts.drawTopPriceDisplay(ctx, grid, text); |
|||
ctx.draw(false); |
|||
}, |
|||
}; |
|||
@ -0,0 +1,354 @@ |
|||
/** @format */ |
|||
|
|||
export const prevClosePrice = 14.95; // 前一日收盘价(元)
|
|||
export const timeData = [ |
|||
// 上午时段:9:30-11:30(共120个数据点)
|
|||
{ time: "09:30", price: 15.0, volume: 28500 }, // 开盘价15.00元,开盘放量
|
|||
{ time: "09:31", price: 15.08, volume: 25300 }, |
|||
{ time: "09:32", price: 15.12, volume: 22800 }, |
|||
{ time: "09:33", price: 15.09, volume: 19600 }, |
|||
{ time: "09:34", price: 15.15, volume: 17200 }, |
|||
{ time: "09:35", price: 15.18, volume: 15800 }, |
|||
{ time: "09:36", price: 15.16, volume: 14300 }, |
|||
{ time: "09:37", price: 15.2, volume: 13500 }, |
|||
{ time: "09:38", price: 15.17, volume: 12800 }, |
|||
{ time: "09:39", price: 15.22, volume: 12100 }, |
|||
{ time: "09:40", price: 15.25, volume: 11500 }, |
|||
{ time: "09:41", price: 15.23, volume: 10800 }, |
|||
{ time: "09:42", price: 15.26, volume: 10200 }, |
|||
{ time: "09:43", price: 15.24, volume: 9800 }, |
|||
{ time: "09:44", price: 15.28, volume: 9500 }, |
|||
{ time: "09:45", price: 15.3, volume: 9200 }, |
|||
{ time: "09:46", price: 15.27, volume: 8800 }, |
|||
{ time: "09:47", price: 15.29, volume: 8500 }, |
|||
{ time: "09:48", price: 15.32, volume: 8200 }, |
|||
{ time: "09:49", price: 15.3, volume: 7900 }, |
|||
{ time: "09:50", price: 15.33, volume: 7600 }, |
|||
{ time: "09:51", price: 15.31, volume: 7400 }, |
|||
{ time: "09:52", price: 15.34, volume: 7200 }, |
|||
{ time: "09:53", price: 15.32, volume: 7000 }, |
|||
{ time: "09:54", price: 15.35, volume: 6800 }, |
|||
{ time: "09:55", price: 15.33, volume: 6600 }, |
|||
{ time: "09:56", price: 15.36, volume: 6500 }, |
|||
{ time: "09:57", price: 15.34, volume: 6300 }, |
|||
{ time: "09:58", price: 15.37, volume: 6200 }, |
|||
{ time: "09:59", price: 15.35, volume: 6100 }, |
|||
{ time: "10:00", price: 15.38, volume: 6000 }, |
|||
{ time: "10:01", price: 15.36, volume: 5900 }, |
|||
{ time: "10:02", price: 15.39, volume: 5800 }, |
|||
{ time: "10:03", price: 15.37, volume: 5700 }, |
|||
{ time: "10:04", price: 15.4, volume: 5600 }, |
|||
{ time: "10:05", price: 15.38, volume: 5500 }, |
|||
{ time: "10:06", price: 15.41, volume: 15400 }, |
|||
{ time: "10:07", price: 15.39, volume: 5300 }, |
|||
{ time: "10:08", price: 15.42, volume: 5200 }, |
|||
{ time: "10:09", price: 15.4, volume: 5100 }, |
|||
{ time: "10:10", price: 15.43, volume: 5000 }, |
|||
{ time: "10:11", price: 15.41, volume: 5100 }, |
|||
{ time: "10:12", price: 15.44, volume: 5200 }, |
|||
{ time: "10:13", price: 15.42, volume: 5300 }, |
|||
{ time: "10:14", price: 15.45, volume: 5400 }, |
|||
{ time: "10:15", price: 15.43, volume: 5500 }, |
|||
{ time: "10:16", price: 15.46, volume: 5600 }, |
|||
{ time: "10:17", price: 15.44, volume: 5700 }, |
|||
{ time: "10:18", price: 15.47, volume: 5800 }, |
|||
{ time: "10:19", price: 15.45, volume: 5900 }, |
|||
{ time: "10:20", price: 15.48, volume: 6000 }, |
|||
{ time: "10:21", price: 15.46, volume: 6100 }, |
|||
{ time: "10:22", price: 15.49, volume: 6200 }, |
|||
{ time: "10:23", price: 15.47, volume: 6300 }, |
|||
{ time: "10:24", price: 15.5, volume: 6400 }, |
|||
{ time: "10:25", price: 15.48, volume: 6500 }, |
|||
{ time: "10:26", price: 15.51, volume: 6600 }, |
|||
{ time: "10:27", price: 15.49, volume: 6700 }, |
|||
{ time: "10:28", price: 15.52, volume: 6800 }, |
|||
{ time: "10:29", price: 15.5, volume: 6900 }, |
|||
{ time: "10:30", price: 15.53, volume: 7000 }, |
|||
{ time: "10:31", price: 15.51, volume: 7100 }, |
|||
{ time: "10:32", price: 15.54, volume: 7200 }, |
|||
{ time: "10:33", price: 15.52, volume: 7300 }, |
|||
{ time: "10:34", price: 15.55, volume: 7400 }, |
|||
{ time: "10:35", price: 15.53, volume: 7500 }, |
|||
{ time: "10:36", price: 15.56, volume: 7600 }, |
|||
{ time: "10:37", price: 15.54, volume: 7700 }, |
|||
{ time: "10:38", price: 15.57, volume: 7800 }, |
|||
{ time: "10:39", price: 15.55, volume: 7900 }, |
|||
{ time: "10:40", price: 15.58, volume: 8000 }, |
|||
{ time: "10:41", price: 15.56, volume: 8100 }, |
|||
{ time: "10:42", price: 15.59, volume: 8200 }, |
|||
{ time: "10:43", price: 15.57, volume: 8300 }, |
|||
{ time: "10:44", price: 15.6, volume: 8400 }, // 全天最高价15.60元
|
|||
{ time: "10:45", price: 15.58, volume: 8300 }, |
|||
{ time: "10:46", price: 15.56, volume: 8200 }, |
|||
{ time: "10:47", price: 15.54, volume: 8100 }, |
|||
{ time: "10:48", price: 15.52, volume: 8000 }, |
|||
{ time: "10:49", price: 15.5, volume: 7900 }, |
|||
{ time: "10:50", price: 15.48, volume: 7800 }, |
|||
{ time: "10:51", price: 15.46, volume: 7700 }, |
|||
{ time: "10:52", price: 15.44, volume: 7600 }, |
|||
{ time: "10:53", price: 15.42, volume: 7500 }, |
|||
{ time: "10:54", price: 15.4, volume: 7400 }, |
|||
{ time: "10:55", price: 15.38, volume: 7300 }, |
|||
{ time: "10:56", price: 15.36, volume: 7200 }, |
|||
{ time: "10:57", price: 15.34, volume: 7100 }, |
|||
{ time: "10:58", price: 15.32, volume: 7000 }, |
|||
{ time: "10:59", price: 15.3, volume: 6900 }, |
|||
{ time: "11:00", price: 15.28, volume: 6800 }, |
|||
{ time: "11:01", price: 15.26, volume: 6700 }, |
|||
{ time: "11:02", price: 15.24, volume: 6600 }, |
|||
{ time: "11:03", price: 15.22, volume: 6500 }, |
|||
{ time: "11:04", price: 15.2, volume: 6400 }, // 全天最低价15.20元
|
|||
{ time: "11:05", price: 15.22, volume: 6500 }, |
|||
{ time: "11:06", price: 15.24, volume: 6600 }, |
|||
{ time: "11:07", price: 15.26, volume: 6700 }, |
|||
{ time: "11:08", price: 15.28, volume: 6800 }, |
|||
{ time: "11:09", price: 15.3, volume: 6900 }, |
|||
{ time: "11:10", price: 15.32, volume: 7000 }, |
|||
{ time: "11:11", price: 15.34, volume: 7100 }, |
|||
{ time: "11:12", price: 15.36, volume: 7200 }, |
|||
{ time: "11:13", price: 15.38, volume: 7300 }, |
|||
{ time: "11:14", price: 15.4, volume: 7400 }, |
|||
{ time: "11:15", price: 15.42, volume: 7500 }, |
|||
{ time: "11:16", price: 15.44, volume: 7600 }, |
|||
{ time: "11:17", price: 15.46, volume: 7700 }, |
|||
{ time: "11:18", price: 15.48, volume: 7800 }, |
|||
{ time: "11:19", price: 15.5, volume: 7900 }, |
|||
{ time: "11:20", price: 15.45, volume: 8300 }, |
|||
{ time: "11:21", price: 15.47, volume: 8600 }, |
|||
{ time: "11:22", price: 15.43, volume: 9100 }, |
|||
{ time: "11:23", price: 15.46, volume: 9500 }, |
|||
{ time: "11:24", price: 15.49, volume: 10200 }, |
|||
{ time: "11:25", price: 15.5, volume: 11500 }, |
|||
{ time: "11:26", price: 15.48, volume: 12800 }, |
|||
{ time: "11:27", price: 15.52, volume: 14300 }, |
|||
{ time: "11:28", price: 15.5, volume: 16500 }, |
|||
{ time: "11:29", price: 15.53, volume: 19800 }, // 午盘收盘价15.53元
|
|||
|
|||
// 下午时段:13:00-15:00(共120个数据点)
|
|||
{ time: "13:00", price: 15.55, volume: 24600 }, // 午后开盘冲高
|
|||
{ time: "13:01", price: 15.58, volume: 21300 }, |
|||
{ time: "13:02", price: 15.6, volume: 18700 }, // 再次触及全天最高价
|
|||
{ time: "13:03", price: 15.57, volume: 16200 }, |
|||
{ time: "13:04", price: 15.55, volume: 14500 }, |
|||
{ time: "13:05", price: 15.52, volume: 12800 }, |
|||
{ time: "13:06", price: 15.5, volume: 11300 }, |
|||
{ time: "13:07", price: 15.48, volume: 10100 }, |
|||
{ time: "13:08", price: 15.5, volume: 9500 }, |
|||
{ time: "13:09", price: 15.47, volume: 8900 }, |
|||
{ time: "13:10", price: 15.45, volume: 8300 }, |
|||
{ time: "13:11", price: 15.43, volume: 7800 }, |
|||
{ time: "13:12", price: 15.46, volume: 7500 }, |
|||
{ time: "13:13", price: 15.44, volume: 7200 }, |
|||
{ time: "13:14", price: 15.42, volume: 6900 }, |
|||
{ time: "13:15", price: 15.45, volume: 6700 }, |
|||
{ time: "13:16", price: 15.43, volume: 6500 }, |
|||
{ time: "13:17", price: 15.4, volume: 6300 }, |
|||
{ time: "13:18", price: 15.42, volume: 6100 }, |
|||
{ time: "13:19", price: 15.39, volume: 5900 }, |
|||
{ time: "13:20", price: 15.41, volume: 5800 }, |
|||
{ time: "13:21", price: 15.39, volume: 5700 }, |
|||
{ time: "13:22", price: 15.42, volume: 5600 }, |
|||
{ time: "13:23", price: 15.4, volume: 5500 }, |
|||
{ time: "13:24", price: 15.43, volume: 5400 }, |
|||
{ time: "13:25", price: 15.41, volume: 5300 }, |
|||
{ time: "13:26", price: 15.44, volume: 5200 }, |
|||
{ time: "13:27", price: 15.42, volume: 5100 }, |
|||
{ time: "13:28", price: 15.45, volume: 5000 }, |
|||
{ time: "13:29", price: 15.43, volume: 5100 }, |
|||
{ time: "13:30", price: 15.46, volume: 5200 }, |
|||
{ time: "13:31", price: 15.44, volume: 5300 }, |
|||
{ time: "13:32", price: 15.47, volume: 5400 }, |
|||
{ time: "13:33", price: 15.45, volume: 5500 }, |
|||
{ time: "13:34", price: 15.48, volume: 5600 }, |
|||
{ time: "13:35", price: 15.46, volume: 5700 }, |
|||
{ time: "13:36", price: 15.49, volume: 5800 }, |
|||
{ time: "13:37", price: 15.47, volume: 5900 }, |
|||
{ time: "13:38", price: 15.5, volume: 6000 }, |
|||
{ time: "13:39", price: 15.48, volume: 6100 }, |
|||
{ time: "13:40", price: 15.51, volume: 6200 }, |
|||
{ time: "13:41", price: 15.49, volume: 6300 }, |
|||
{ time: "13:42", price: 15.52, volume: 6400 }, |
|||
{ time: "13:43", price: 15.5, volume: 6500 }, |
|||
{ time: "13:44", price: 15.53, volume: 6600 }, |
|||
{ time: "13:45", price: 15.51, volume: 6700 }, |
|||
{ time: "13:46", price: 15.54, volume: 6800 }, |
|||
{ time: "13:47", price: 15.52, volume: 6900 }, |
|||
{ time: "13:48", price: 15.55, volume: 7000 }, |
|||
{ time: "13:49", price: 15.53, volume: 7100 }, |
|||
{ time: "13:50", price: 15.56, volume: 7200 }, |
|||
{ time: "13:51", price: 15.54, volume: 7300 }, |
|||
{ time: "13:52", price: 15.57, volume: 7400 }, |
|||
{ time: "13:53", price: 15.55, volume: 7500 }, |
|||
{ time: "13:54", price: 15.58, volume: 7600 }, |
|||
{ time: "13:55", price: 15.56, volume: 7700 }, |
|||
{ time: "13:56", price: 15.59, volume: 7800 }, |
|||
{ time: "13:57", price: 15.57, volume: 7900 }, |
|||
{ time: "13:58", price: 15.6, volume: 8000 }, // 第三次触及全天最高价
|
|||
{ time: "13:59", price: 15.58, volume: 8100 }, |
|||
{ time: "14:00", price: 15.56, volume: 8200 }, |
|||
{ time: "14:01", price: 15.54, volume: 8300 }, |
|||
{ time: "14:02", price: 15.52, volume: 8400 }, |
|||
{ time: "14:03", price: 15.5, volume: 8300 }, |
|||
{ time: "14:04", price: 15.48, volume: 8200 }, |
|||
{ time: "14:05", price: 15.46, volume: 8100 }, |
|||
{ time: "14:06", price: 15.44, volume: 8000 }, |
|||
{ time: "14:07", price: 15.42, volume: 7900 }, |
|||
{ time: "14:08", price: 15.4, volume: 7800 }, |
|||
{ time: "14:09", price: 15.38, volume: 7700 }, |
|||
{ time: "14:10", price: 15.36, volume: 7600 }, |
|||
{ time: "14:11", price: 15.34, volume: 7500 }, |
|||
{ time: "14:12", price: 15.32, volume: 7400 }, |
|||
{ time: "14:13", price: 15.3, volume: 7300 }, |
|||
{ time: "14:14", price: 15.28, volume: 7200 }, |
|||
{ time: "14:15", price: 15.26, volume: 7100 }, |
|||
{ time: "14:16", price: 15.24, volume: 7000 }, |
|||
{ time: "14:17", price: 15.22, volume: 6900 }, |
|||
{ time: "14:18", price: 15.2, volume: 6800 }, // 再次触及全天最低价
|
|||
{ time: "14:19", price: 15.22, volume: 6700 }, |
|||
{ time: "14:20", price: 15.24, volume: 6600 }, |
|||
{ time: "14:21", price: 15.26, volume: 6500 }, |
|||
{ time: "14:22", price: 15.28, volume: 6400 }, |
|||
{ time: "14:23", price: 15.3, volume: 6300 }, |
|||
{ time: "14:24", price: 15.32, volume: 6200 }, |
|||
{ time: "14:25", price: 15.34, volume: 6100 }, |
|||
{ time: "14:26", price: 15.36, volume: 6000 }, |
|||
{ time: "14:27", price: 15.38, volume: 5900 }, |
|||
{ time: "14:28", price: 15.4, volume: 5800 }, |
|||
{ time: "14:29", price: 15.42, volume: 5700 }, |
|||
{ time: "14:30", price: 15.44, volume: 5600 }, |
|||
{ time: "14:31", price: 15.46, volume: 5500 }, |
|||
{ time: "14:32", price: 15.48, volume: 5400 }, |
|||
{ time: "14:33", price: 15.5, volume: 5300 }, |
|||
{ time: "14:34", price: 15.52, volume: 5200 }, |
|||
{ time: "14:35", price: 15.54, volume: 5100 }, |
|||
{ time: "14:36", price: 15.56, volume: 5000 }, |
|||
{ time: "14:37", price: 15.54, volume: 5100 }, |
|||
{ time: "14:38", price: 15.52, volume: 5200 }, |
|||
{ time: "14:39", price: 15.5, volume: 5300 }, |
|||
{ time: "14:40", price: 15.48, volume: 5400 }, |
|||
{ time: "14:41", price: 15.46, volume: 5500 }, |
|||
{ time: "14:42", price: 15.44, volume: 5600 }, |
|||
{ time: "14:43", price: 15.42, volume: 5700 }, |
|||
{ time: "14:44", price: 15.4, volume: 5800 }, |
|||
{ time: "14:45", price: 15.38, volume: 5900 }, |
|||
{ time: "14:46", price: 15.36, volume: 6000 }, |
|||
{ time: "14:47", price: 15.34, volume: 6100 }, |
|||
{ time: "14:48", price: 15.32, volume: 6200 }, |
|||
{ time: "14:49", price: 15.3, volume: 6300 }, |
|||
{ time: "14:50", price: 15.42, volume: 9800 }, // 尾盘开始放量
|
|||
{ time: "14:51", price: 15.45, volume: 11500 }, |
|||
{ time: "14:52", price: 15.43, volume: 13200 }, |
|||
{ time: "14:53", price: 15.46, volume: 15800 }, |
|||
{ time: "14:54", price: 15.44, volume: 18500 }, |
|||
{ time: "14:55", price: 15.47, volume: 21300 }, |
|||
{ time: "14:56", price: 15.45, volume: 24600 }, |
|||
{ time: "14:57", price: 15.48, volume: 27800 }, |
|||
{ time: "14:58", price: 15.46, volume: 31200 }, // 尾盘成交量峰值
|
|||
{ time: "14:59", price: 15.45, volume: 28500 }, // 当日收盘价15.45元
|
|||
]; |
|||
export const klineData = [ |
|||
// 第1天(起始点,位于区间中部)
|
|||
{ date: "2015-10-11", open: 16.5, high: 16.8, low: 16.2, close: 16.6, volume: 185000 }, |
|||
// 第2-90天(区间震荡:15.5-17.5元)
|
|||
{ date: "2015-10-12", open: 16.6, high: 16.9, low: 16.4, close: 16.7, volume: 192000 }, |
|||
{ date: "2015-10-13", open: 16.7, high: 17.0, low: 16.5, close: 16.6, volume: 188000 }, |
|||
{ date: "2015-10-14", open: 16.6, high: 16.8, low: 16.3, close: 16.4, volume: 175000 }, |
|||
{ date: "2015-10-15", open: 16.4, high: 16.7, low: 16.2, close: 16.5, volume: 181000 }, |
|||
{ date: "2015-10-16", open: 16.5, high: 16.9, low: 16.3, close: 16.8, volume: 195000 }, |
|||
{ date: "2015-10-17", open: 16.8, high: 17.1, low: 16.6, close: 16.7, volume: 202000 }, |
|||
{ date: "2015-10-18", open: 16.7, high: 16.9, low: 16.4, close: 16.5, volume: 183000 }, |
|||
{ date: "2015-10-19", open: 16.5, high: 16.7, low: 16.1, close: 16.3, volume: 172000 }, |
|||
{ date: "2015-10-20", open: 16.3, high: 16.6, low: 16.0, close: 16.4, volume: 178000 }, |
|||
{ date: "2015-10-21", open: 16.4, high: 16.8, low: 16.2, close: 16.6, volume: 189000 }, |
|||
{ date: "2015-10-22", open: 16.6, high: 17.0, low: 16.5, close: 16.9, volume: 205000 }, |
|||
{ date: "2015-10-23", open: 16.9, high: 17.2, low: 16.7, close: 16.8, volume: 212000 }, |
|||
{ date: "2015-10-24", open: 16.8, high: 17.0, low: 16.5, close: 16.6, volume: 193000 }, |
|||
{ date: "2015-10-25", open: 16.6, high: 16.8, low: 16.2, close: 16.3, volume: 176000 }, |
|||
{ date: "2015-10-26", open: 16.3, high: 16.6, low: 16.0, close: 16.5, volume: 184000 }, |
|||
{ date: "2015-10-27", open: 16.5, high: 16.9, low: 16.4, close: 16.7, volume: 196000 }, |
|||
{ date: "2015-10-28", open: 16.7, high: 17.1, low: 16.6, close: 16.9, volume: 208000 }, |
|||
{ date: "2015-10-29", open: 16.9, high: 17.3, low: 16.8, close: 17.0, volume: 215000 }, |
|||
{ date: "2015-10-30", open: 17.0, high: 17.2, low: 16.7, close: 16.8, volume: 201000 }, |
|||
{ date: "2015-10-31", open: 16.8, high: 17.0, low: 16.5, close: 16.6, volume: 189000 }, |
|||
{ date: "2015-11-01", open: 16.6, high: 16.8, low: 16.2, close: 16.4, volume: 175000 }, |
|||
{ date: "2015-11-02", open: 16.4, high: 16.7, low: 16.1, close: 16.3, volume: 171000 }, |
|||
{ date: "2015-11-03", open: 16.3, high: 16.6, low: 16.0, close: 16.5, volume: 182000 }, |
|||
{ date: "2015-11-04", open: 16.5, high: 16.9, low: 16.3, close: 16.7, volume: 194000 }, |
|||
{ date: "2015-11-05", open: 16.7, high: 17.1, low: 16.6, close: 16.8, volume: 203000 }, |
|||
{ date: "2015-11-06", open: 16.8, high: 17.0, low: 16.5, close: 16.6, volume: 190000 }, |
|||
{ date: "2015-11-07", open: 16.6, high: 16.8, low: 16.3, close: 16.4, volume: 178000 }, |
|||
{ date: "2015-11-08", open: 16.4, high: 16.7, low: 16.1, close: 16.3, volume: 173000 }, |
|||
{ date: "2015-11-09", open: 16.3, high: 16.6, low: 15.9, close: 16.2, volume: 168000 }, // 触及区间下沿
|
|||
{ date: "2015-11-10", open: 16.2, high: 16.5, low: 16.0, close: 16.4, volume: 176000 }, |
|||
{ date: "2015-11-11", open: 16.4, high: 16.8, low: 16.3, close: 16.6, volume: 187000 }, |
|||
{ date: "2015-11-12", open: 16.6, high: 17.0, low: 16.5, close: 16.8, volume: 198000 }, |
|||
{ date: "2015-11-13", open: 16.8, high: 17.2, low: 16.7, close: 16.9, volume: 206000 }, |
|||
{ date: "2015-11-14", open: 16.9, high: 17.3, low: 16.8, close: 17.1, volume: 218000 }, |
|||
{ date: "2015-11-15", open: 17.1, high: 17.4, low: 16.9, close: 17.0, volume: 212000 }, |
|||
{ date: "2015-11-16", open: 17.0, high: 17.2, low: 16.7, close: 16.8, volume: 197000 }, |
|||
{ date: "2015-11-17", open: 16.8, high: 17.0, low: 16.5, close: 16.6, volume: 185000 }, |
|||
{ date: "2015-11-18", open: 16.6, high: 16.8, low: 16.3, close: 16.4, volume: 177000 }, |
|||
{ date: "2015-11-19", open: 16.4, high: 16.7, low: 16.1, close: 16.3, volume: 172000 }, |
|||
{ date: "2015-11-20", open: 16.3, high: 16.6, low: 16.0, close: 16.5, volume: 183000 }, |
|||
{ date: "2015-11-21", open: 16.5, high: 16.9, low: 16.4, close: 16.7, volume: 195000 }, |
|||
{ date: "2015-11-22", open: 16.7, high: 17.1, low: 16.6, close: 16.9, volume: 204000 }, |
|||
{ date: "2015-11-23", open: 16.9, high: 17.2, low: 16.8, close: 17.0, volume: 213000 }, |
|||
{ date: "2015-11-24", open: 17.0, high: 17.3, low: 16.9, close: 17.1, volume: 221000 }, |
|||
{ date: "2015-11-25", open: 17.1, high: 17.4, low: 17.0, close: 17.2, volume: 228000 }, // 触及区间上沿
|
|||
{ date: "2015-11-26", open: 17.2, high: 17.3, low: 16.8, close: 16.9, volume: 215000 }, |
|||
{ date: "2015-11-27", open: 16.9, high: 17.1, low: 16.6, close: 16.7, volume: 199000 }, |
|||
{ date: "2015-11-28", open: 16.7, high: 16.9, low: 16.4, close: 16.5, volume: 186000 }, |
|||
{ date: "2015-11-29", open: 16.5, high: 16.7, low: 16.2, close: 16.3, volume: 175000 }, |
|||
{ date: "2015-11-30", open: 16.3, high: 16.6, low: 16.0, close: 16.4, volume: 179000 }, |
|||
{ date: "2015-12-01", open: 16.4, high: 16.8, low: 16.3, close: 16.6, volume: 188000 }, |
|||
{ date: "2015-12-02", open: 16.6, high: 17.0, low: 16.5, close: 16.8, volume: 199000 }, |
|||
{ date: "2015-12-03", open: 16.8, high: 17.2, low: 16.7, close: 16.9, volume: 207000 }, |
|||
{ date: "2015-12-04", open: 16.9, high: 17.1, low: 16.6, close: 16.7, volume: 193000 }, |
|||
{ date: "2015-12-05", open: 16.7, high: 16.9, low: 16.4, close: 16.5, volume: 182000 }, |
|||
{ date: "2015-12-06", open: 16.5, high: 16.7, low: 16.2, close: 16.3, volume: 173000 }, |
|||
{ date: "2015-12-07", open: 16.3, high: 16.6, low: 15.9, close: 16.1, volume: 167000 }, // 触及区间下沿
|
|||
{ date: "2015-12-08", open: 16.1, high: 16.4, low: 16.0, close: 16.3, volume: 174000 }, |
|||
{ date: "2015-12-09", open: 16.3, high: 16.7, low: 16.2, close: 16.5, volume: 185000 }, |
|||
{ date: "2015-12-10", open: 16.5, high: 16.9, low: 16.4, close: 16.7, volume: 196000 }, |
|||
{ date: "2015-12-11", open: 16.7, high: 17.1, low: 16.6, close: 16.9, volume: 205000 }, |
|||
{ date: "2015-12-12", open: 16.9, high: 17.3, low: 16.8, close: 17.0, volume: 214000 }, |
|||
{ date: "2015-12-13", open: 17.0, high: 17.2, low: 16.8, close: 16.9, volume: 203000 }, |
|||
{ date: "2015-12-14", open: 16.9, high: 17.1, low: 16.6, close: 16.7, volume: 191000 }, |
|||
{ date: "2015-12-15", open: 16.7, high: 16.9, low: 16.4, close: 16.5, volume: 180000 }, |
|||
{ date: "2015-12-16", open: 16.5, high: 16.7, low: 16.2, close: 16.3, volume: 172000 }, |
|||
{ date: "2015-12-17", open: 16.3, high: 16.6, low: 16.0, close: 16.4, volume: 178000 }, |
|||
{ date: "2015-12-18", open: 16.4, high: 16.8, low: 16.3, close: 16.6, volume: 189000 }, |
|||
{ date: "2015-12-19", open: 16.6, high: 17.0, low: 16.5, close: 16.8, volume: 200000 }, |
|||
{ date: "2015-12-20", open: 16.8, high: 17.2, low: 16.7, close: 16.9, volume: 208000 }, |
|||
{ date: "2015-12-21", open: 16.9, high: 17.3, low: 16.8, close: 17.1, volume: 219000 }, |
|||
{ date: "2015-12-22", open: 17.1, high: 17.4, low: 17.0, close: 17.2, volume: 226000 }, // 触及区间上沿
|
|||
{ date: "2015-12-23", open: 17.2, high: 17.3, low: 16.8, close: 16.9, volume: 213000 }, |
|||
{ date: "2015-12-24", open: 16.9, high: 17.1, low: 16.6, close: 16.7, volume: 198000 }, |
|||
{ date: "2015-12-25", open: 16.7, high: 16.9, low: 16.4, close: 16.5, volume: 185000 }, |
|||
{ date: "2015-12-26", open: 16.5, high: 16.7, low: 16.2, close: 16.3, volume: 174000 }, |
|||
{ date: "2015-12-27", open: 16.3, high: 16.6, low: 16.0, close: 16.5, volume: 183000 }, |
|||
{ date: "2015-12-28", open: 16.5, high: 16.9, low: 16.4, close: 16.7, volume: 195000 }, |
|||
{ date: "2015-12-29", open: 16.7, high: 17.1, low: 16.6, close: 16.9, volume: 204000 }, |
|||
{ date: "2015-12-30", open: 16.9, high: 17.2, low: 16.8, close: 17.0, volume: 212000 }, |
|||
{ date: "2015-12-31", open: 17.0, high: 17.3, low: 16.9, close: 17.1, volume: 220000 }, |
|||
{ date: "2016-01-01", open: 17.1, high: 17.2, low: 16.8, close: 16.9, volume: 207000 }, |
|||
{ date: "2016-01-02", open: 16.9, high: 17.1, low: 16.6, close: 16.7, volume: 193000 }, |
|||
{ date: "2016-01-03", open: 16.7, high: 16.9, low: 16.4, close: 16.5, volume: 181000 }, |
|||
{ date: "2016-01-04", open: 16.5, high: 16.7, low: 16.2, close: 16.3, volume: 172000 }, |
|||
{ date: "2016-01-05", open: 16.3, high: 16.6, low: 15.9, close: 16.2, volume: 168000 }, // 触及区间下沿
|
|||
{ date: "2016-01-06", open: 16.2, high: 16.5, low: 16.0, close: 16.4, volume: 175000 }, |
|||
{ date: "2016-01-07", open: 16.4, high: 16.8, low: 16.3, close: 16.6, volume: 186000 }, |
|||
{ date: "2016-01-08", open: 16.6, high: 17.0, low: 16.5, close: 16.8, volume: 197000 }, |
|||
{ date: "2016-01-09", open: 16.8, high: 17.2, low: 16.7, close: 16.9, volume: 206000 }, |
|||
{ date: "2016-01-10", open: 16.9, high: 17.3, low: 16.8, close: 17.1, volume: 217000 }, |
|||
{ date: "2016-01-11", open: 17.1, high: 17.4, low: 17.0, close: 17.2, volume: 225000 }, // 触及区间上沿
|
|||
{ date: "2016-01-12", open: 17.2, high: 17.3, low: 16.8, close: 16.9, volume: 212000 }, |
|||
{ date: "2016-01-13", open: 16.9, high: 17.1, low: 16.6, close: 16.7, volume: 197000 }, |
|||
{ date: "2016-01-14", open: 16.7, high: 16.9, low: 16.4, close: 16.5, volume: 184000 }, |
|||
{ date: "2016-01-15", open: 16.5, high: 16.7, low: 16.2, close: 16.4, volume: 175000 }, |
|||
{ date: "2016-01-16", open: 16.4, high: 16.7, low: 16.1, close: 16.3, volume: 171000 }, |
|||
{ date: "2016-01-17", open: 16.3, high: 16.6, low: 16.0, close: 16.5, volume: 182000 }, |
|||
{ date: "2016-01-18", open: 16.5, high: 16.9, low: 16.4, close: 16.7, volume: 194000 }, |
|||
{ date: "2016-01-19", open: 16.7, high: 17.1, low: 16.6, close: 16.9, volume: 203000 }, |
|||
{ date: "2016-01-20", open: 16.9, high: 17.2, low: 16.8, close: 17.0, volume: 212000 }, |
|||
]; |
|||
@ -0,0 +1,142 @@ |
|||
var util = {} |
|||
util.data = {} |
|||
util.data.base_url = 'https://dbqb.nfdxy.net/devApi' |
|||
// util.data.base_url = 'https://dbqb.nfdxy.net/prodApi'
|
|||
|
|||
// AJAX 请求方法
|
|||
util.request = (url, callback, data = {}, failCallback) => { |
|||
url = util.data.base_url + url |
|||
console.log('请求该接口->', url, '请求参数为->', data); |
|||
uni.request({ |
|||
url: url, //仅为示例,并非真实接口地址。
|
|||
data, |
|||
method: 'post', |
|||
header: { |
|||
'content-type': 'application/json', |
|||
'version': uni.getSystemInfoSync().appVersion, |
|||
'client': uni.getSystemInfoSync().platform == 'ios' ? 'ios' : 'android', |
|||
'token': uni.getStorageSync('token') |
|||
}, |
|||
sslVerify: false, |
|||
success: callback, |
|||
fail: failCallback |
|||
}); |
|||
} |
|||
|
|||
export default util |
|||
|
|||
// 画图需要用到的方法
|
|||
export const utils = { |
|||
// 格式化价格
|
|||
formatPrice(price) { |
|||
return price.toFixed(2); |
|||
}, |
|||
// 计算数据范围
|
|||
calculateDataRange(data, key) { |
|||
if (!data || data.length === 0) { |
|||
return { |
|||
min: 0, |
|||
max: 0, |
|||
}; |
|||
} |
|||
const values = data.map((item) => item[key]); |
|||
return { |
|||
min: Math.min(...values), |
|||
max: Math.max(...values), |
|||
}; |
|||
}, |
|||
// 计算标签
|
|||
calculateLabel(data, type = 2, preClosePrice = 0, key, num) { |
|||
let label = []; |
|||
if (key === "price") { |
|||
// 分时价格区间
|
|||
if (type == 1) { |
|||
const priceRange = utils.calculateDataRange(data, "price"); |
|||
const theMost = Math.max(priceRange.max - preClosePrice, preClosePrice - priceRange.min); |
|||
const mid = (num - 1) / 2; |
|||
// 计算分时价格标签
|
|||
label[mid] = { |
|||
value: utils.formatPrice(preClosePrice), |
|||
ratio: utils.formatPrice(0) + "%", |
|||
}; |
|||
for (let i = 0; i < mid; i++) { |
|||
label[i] = { |
|||
value: utils.formatPrice(preClosePrice + (theMost * (mid - i)) / mid), |
|||
ratio: utils.formatPrice((100 * (theMost * (mid - i))) / mid / preClosePrice) + "%", |
|||
}; |
|||
|
|||
label[num - 1 - i] = { |
|||
value: utils.formatPrice(preClosePrice - (theMost * (mid - i)) / mid), |
|||
ratio: utils.formatPrice((-1 * 100 * (theMost * (mid - i))) / mid / preClosePrice) + |
|||
"%", |
|||
}; |
|||
} |
|||
timeChartObject.value.max = preClosePrice + theMost; |
|||
timeChartObject.value.min = preClosePrice - theMost; |
|||
return label; |
|||
} else { |
|||
const highPriceRange = utils.calculateDataRange(data, "high"); |
|||
const lowPriceRange = utils.calculateDataRange(data, "low"); |
|||
const priceDiff = highPriceRange.max * 1.01 - lowPriceRange.min * 0.99; |
|||
for (let i = 0; i < num; ++i) { |
|||
label[i] = { |
|||
value: utils.formatPrice(highPriceRange.max - (i * priceDiff) / num), |
|||
}; |
|||
} |
|||
return label; |
|||
} |
|||
} else if (key === "volume") { |
|||
const volumeRange = utils.calculateDataRange(data, "volume"); |
|||
label[0] = { |
|||
value: utils.formatPrice(volumeRange.max), |
|||
}; |
|||
label[1] = { |
|||
value: utils.formatPrice(0), |
|||
}; |
|||
return label; |
|||
} |
|||
return null; |
|||
}, |
|||
// 线性插值
|
|||
lerp(start, end, factor) { |
|||
return start + (end - start) * factor; |
|||
}, |
|||
// 股市数值格式化方法
|
|||
formatStockNumber(value, decimalPlaces = 2) { |
|||
const num = Number(value); |
|||
if (isNaN(num)) return "0"; |
|||
|
|||
const absNum = Math.abs(num); |
|||
const sign = num < 0 ? "-" : ""; |
|||
|
|||
if (absNum >= 1000000000000) { |
|||
// 万亿级别
|
|||
return sign + (absNum / 1000000000000).toFixed(decimalPlaces) + "万亿"; |
|||
} else if (absNum >= 100000000) { |
|||
// 亿级别
|
|||
return sign + (absNum / 100000000).toFixed(decimalPlaces) + "亿"; |
|||
} else if (absNum >= 10000) { |
|||
// 万级别
|
|||
return sign + (absNum / 10000).toFixed(decimalPlaces) + "万"; |
|||
} else { |
|||
// 小于万的直接显示
|
|||
return sign + absNum.toFixed(decimalPlaces); |
|||
} |
|||
}, |
|||
}; |
|||
|
|||
// 防抖函数
|
|||
export const throttle = (fn, delay = 1000) => { |
|||
//距离上一次的执行时间
|
|||
let lastTime = 0; |
|||
return function() { |
|||
let _this = this; |
|||
let _arguments = arguments; |
|||
let now = new Date().getTime(); |
|||
//如果距离上一次执行超过了delay才能再次执行
|
|||
if (now - lastTime > delay) { |
|||
fn.apply(_this, _arguments); |
|||
lastTime = now; |
|||
} |
|||
}; |
|||
}; |
|||
@ -0,0 +1,190 @@ |
|||
<template> |
|||
<view class="index-card"> |
|||
<view class="card-header"> |
|||
<view class="flag-container"> |
|||
<image :src="flagIcon" class="flag-icon" mode="aspectFit"></image> |
|||
</view> |
|||
<text class="index-name">{{ stockName }}</text> |
|||
</view> |
|||
|
|||
<view class="price-info"> |
|||
<text class="current-price" :style="{ color: priceColor }">{{ currentPrice }}</text> |
|||
<view class="change-info"> |
|||
<text class="change-amount" :style="{ color: priceColor }">{{ changeAmount }}</text> |
|||
<text class="change-percent" :style="{ color: priceColor }">{{ changePercent }}</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="chart-container"> |
|||
<view class="mini-chart" :style="{ backgroundColor: chartBgColor }"> |
|||
<!-- 这里可以放置实际的图表组件,目前用简单的波浪线表示 --> |
|||
<view class="chart-line" :style="{ borderColor: priceColor }"></view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { computed } from 'vue' |
|||
|
|||
// 定义组件属性 |
|||
const props = defineProps({ |
|||
// 国旗图标路径 |
|||
flagIcon: { |
|||
type: String, |
|||
required: true |
|||
}, |
|||
// 指数名称 |
|||
stockName: { |
|||
type: String, |
|||
required: true |
|||
}, |
|||
// 当前价格 |
|||
currentPrice: { |
|||
type: [String, Number], |
|||
required: true |
|||
}, |
|||
// 涨跌金额 |
|||
changeAmount: { |
|||
type: [String, Number], |
|||
required: true |
|||
}, |
|||
// 涨跌幅 |
|||
changePercent: { |
|||
type: [String, Number], |
|||
required: true |
|||
}, |
|||
// 是否上涨 |
|||
isRising: { |
|||
type: Boolean, |
|||
default: true |
|||
} |
|||
}) |
|||
|
|||
// 计算价格颜色 |
|||
const priceColor = computed(() => { |
|||
return props.isRising ? '#00C853' : '#FF1744' |
|||
}) |
|||
|
|||
// 计算图表背景色 |
|||
const chartBgColor = computed(() => { |
|||
return props.isRising ? '#E8F5E8' : '#FFEBEE' |
|||
}) |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.index-card { |
|||
background-color: #ffffff; |
|||
border-radius: 12rpx; |
|||
padding: 20rpx; |
|||
margin: 16rpx; |
|||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1); |
|||
border: 1rpx solid #f0f0f0; |
|||
} |
|||
|
|||
.card-header { |
|||
display: flex; |
|||
align-items: center; |
|||
margin-bottom: 16rpx; |
|||
} |
|||
|
|||
.flag-container { |
|||
width: 48rpx; |
|||
height: 32rpx; |
|||
margin-right: 12rpx; |
|||
border-radius: 4rpx; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.flag-icon { |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
|
|||
.index-name { |
|||
font-size: 28rpx; |
|||
font-weight: 500; |
|||
color: #333333; |
|||
flex: 1; |
|||
white-space: nowrap; |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
} |
|||
|
|||
.price-info { |
|||
margin-bottom: 20rpx; |
|||
} |
|||
|
|||
.current-price { |
|||
font-size: 36rpx; |
|||
font-weight: bold; |
|||
display: block; |
|||
margin-bottom: 8rpx; |
|||
} |
|||
|
|||
.change-info { |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 16rpx; |
|||
} |
|||
|
|||
.change-amount { |
|||
font-size: 24rpx; |
|||
font-weight: 500; |
|||
} |
|||
|
|||
.change-percent { |
|||
font-size: 24rpx; |
|||
font-weight: 500; |
|||
} |
|||
|
|||
.chart-container { |
|||
height: 80rpx; |
|||
border-radius: 8rpx; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.mini-chart { |
|||
width: 100%; |
|||
height: 100%; |
|||
position: relative; |
|||
border-radius: 8rpx; |
|||
} |
|||
|
|||
.chart-line { |
|||
position: absolute; |
|||
bottom: 20rpx; |
|||
left: 10rpx; |
|||
right: 10rpx; |
|||
height: 2rpx; |
|||
border-top: 2rpx solid; |
|||
border-style: solid; |
|||
} |
|||
|
|||
/* 添加一些波浪效果 */ |
|||
.chart-line::before { |
|||
content: ''; |
|||
position: absolute; |
|||
top: -10rpx; |
|||
left: 20%; |
|||
width: 20rpx; |
|||
height: 20rpx; |
|||
border: 2rpx solid; |
|||
border-color: inherit; |
|||
border-radius: 50%; |
|||
background: transparent; |
|||
} |
|||
|
|||
.chart-line::after { |
|||
content: ''; |
|||
position: absolute; |
|||
top: -6rpx; |
|||
right: 30%; |
|||
width: 12rpx; |
|||
height: 12rpx; |
|||
border: 2rpx solid; |
|||
border-color: inherit; |
|||
border-radius: 50%; |
|||
background: transparent; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,726 @@ |
|||
{ |
|||
"name": "deepChartVueApp", |
|||
"lockfileVersion": 3, |
|||
"requires": true, |
|||
"packages": { |
|||
"": { |
|||
"dependencies": { |
|||
"@dcloudio/uni-ui": "^1.5.11", |
|||
"@element-plus/icons-vue": "^2.3.2", |
|||
"element-plus": "^2.11.5", |
|||
"marked": "^2.0.1", |
|||
"pinia": "^3.0.3", |
|||
"pinia-plugin-persistedstate": "^4.5.0", |
|||
"vue-i18n": "^9.14.5" |
|||
} |
|||
}, |
|||
"node_modules/@babel/helper-string-parser": { |
|||
"version": "7.27.1", |
|||
"license": "MIT", |
|||
"peer": true, |
|||
"engines": { |
|||
"node": ">=6.9.0" |
|||
} |
|||
}, |
|||
"node_modules/@babel/helper-validator-identifier": { |
|||
"version": "7.28.5", |
|||
"license": "MIT", |
|||
"peer": true, |
|||
"engines": { |
|||
"node": ">=6.9.0" |
|||
} |
|||
}, |
|||
"node_modules/@babel/parser": { |
|||
"version": "7.28.5", |
|||
"license": "MIT", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@babel/types": "^7.28.5" |
|||
}, |
|||
"bin": { |
|||
"parser": "bin/babel-parser.js" |
|||
}, |
|||
"engines": { |
|||
"node": ">=6.0.0" |
|||
} |
|||
}, |
|||
"node_modules/@babel/types": { |
|||
"version": "7.28.5", |
|||
"license": "MIT", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@babel/helper-string-parser": "^7.27.1", |
|||
"@babel/helper-validator-identifier": "^7.28.5" |
|||
}, |
|||
"engines": { |
|||
"node": ">=6.9.0" |
|||
} |
|||
}, |
|||
"node_modules/@ctrl/tinycolor": { |
|||
"version": "3.6.1", |
|||
"resolved": "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", |
|||
"integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", |
|||
"license": "MIT", |
|||
"engines": { |
|||
"node": ">=10" |
|||
} |
|||
}, |
|||
"node_modules/@dcloudio/uni-ui": { |
|||
"version": "1.5.11", |
|||
"resolved": "https://registry.npmmirror.com/@dcloudio/uni-ui/-/uni-ui-1.5.11.tgz", |
|||
"integrity": "sha512-DBtk046ofmeFd82zRI7d89SoEwrAxYzUN3WVPm1DIBkpLPG5F5QDNkHMnZGu2wNrMEmGBjBpUh3vqEY1L3jaMw==", |
|||
"license": "Apache-2.0" |
|||
}, |
|||
"node_modules/@element-plus/icons-vue": { |
|||
"version": "2.3.2", |
|||
"resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.3.2.tgz", |
|||
"integrity": "sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==", |
|||
"license": "MIT", |
|||
"peerDependencies": { |
|||
"vue": "^3.2.0" |
|||
} |
|||
}, |
|||
"node_modules/@floating-ui/core": { |
|||
"version": "1.7.3", |
|||
"resolved": "https://registry.npmmirror.com/@floating-ui/core/-/core-1.7.3.tgz", |
|||
"integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", |
|||
"license": "MIT", |
|||
"dependencies": { |
|||
"@floating-ui/utils": "^0.2.10" |
|||
} |
|||
}, |
|||
"node_modules/@floating-ui/dom": { |
|||
"version": "1.7.4", |
|||
"resolved": "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.7.4.tgz", |
|||
"integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", |
|||
"license": "MIT", |
|||
"dependencies": { |
|||
"@floating-ui/core": "^1.7.3", |
|||
"@floating-ui/utils": "^0.2.10" |
|||
} |
|||
}, |
|||
"node_modules/@floating-ui/utils": { |
|||
"version": "0.2.10", |
|||
"resolved": "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.10.tgz", |
|||
"integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", |
|||
"license": "MIT" |
|||
}, |
|||
"node_modules/@intlify/core-base": { |
|||
"version": "9.14.5", |
|||
"resolved": "https://registry.npmmirror.com/@intlify/core-base/-/core-base-9.14.5.tgz", |
|||
"integrity": "sha512-5ah5FqZG4pOoHjkvs8mjtv+gPKYU0zCISaYNjBNNqYiaITxW8ZtVih3GS/oTOqN8d9/mDLyrjD46GBApNxmlsA==", |
|||
"license": "MIT", |
|||
"dependencies": { |
|||
"@intlify/message-compiler": "9.14.5", |
|||
"@intlify/shared": "9.14.5" |
|||
}, |
|||
"engines": { |
|||
"node": ">= 16" |
|||
}, |
|||
"funding": { |
|||
"url": "https://github.com/sponsors/kazupon" |
|||
} |
|||
}, |
|||
"node_modules/@intlify/message-compiler": { |
|||
"version": "9.14.5", |
|||
"resolved": "https://registry.npmmirror.com/@intlify/message-compiler/-/message-compiler-9.14.5.tgz", |
|||
"integrity": "sha512-IHzgEu61/YIpQV5Pc3aRWScDcnFKWvQA9kigcINcCBXN8mbW+vk9SK+lDxA6STzKQsVJxUPg9ACC52pKKo3SVQ==", |
|||
"license": "MIT", |
|||
"dependencies": { |
|||
"@intlify/shared": "9.14.5", |
|||
"source-map-js": "^1.0.2" |
|||
}, |
|||
"engines": { |
|||
"node": ">= 16" |
|||
}, |
|||
"funding": { |
|||
"url": "https://github.com/sponsors/kazupon" |
|||
} |
|||
}, |
|||
"node_modules/@intlify/shared": { |
|||
"version": "9.14.5", |
|||
"resolved": "https://registry.npmmirror.com/@intlify/shared/-/shared-9.14.5.tgz", |
|||
"integrity": "sha512-9gB+E53BYuAEMhbCAxVgG38EZrk59sxBtv3jSizNL2hEWlgjBjAw1AwpLHtNaeda12pe6W20OGEa0TwuMSRbyQ==", |
|||
"license": "MIT", |
|||
"engines": { |
|||
"node": ">= 16" |
|||
}, |
|||
"funding": { |
|||
"url": "https://github.com/sponsors/kazupon" |
|||
} |
|||
}, |
|||
"node_modules/@jridgewell/sourcemap-codec": { |
|||
"version": "1.5.5", |
|||
"license": "MIT", |
|||
"peer": true |
|||
}, |
|||
"node_modules/@popperjs/core": { |
|||
"name": "@sxzz/popperjs-es", |
|||
"version": "2.11.7", |
|||
"resolved": "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz", |
|||
"integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==", |
|||
"license": "MIT", |
|||
"funding": { |
|||
"type": "opencollective", |
|||
"url": "https://opencollective.com/popperjs" |
|||
} |
|||
}, |
|||
"node_modules/@types/lodash": { |
|||
"version": "4.17.20", |
|||
"resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.17.20.tgz", |
|||
"integrity": "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==", |
|||
"license": "MIT" |
|||
}, |
|||
"node_modules/@types/lodash-es": { |
|||
"version": "4.17.12", |
|||
"resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.12.tgz", |
|||
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", |
|||
"license": "MIT", |
|||
"dependencies": { |
|||
"@types/lodash": "*" |
|||
} |
|||
}, |
|||
"node_modules/@types/web-bluetooth": { |
|||
"version": "0.0.16", |
|||
"resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz", |
|||
"integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==", |
|||
"license": "MIT" |
|||
}, |
|||
"node_modules/@vue/compiler-core": { |
|||
"version": "3.5.22", |
|||
"license": "MIT", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@babel/parser": "^7.28.4", |
|||
"@vue/shared": "3.5.22", |
|||
"entities": "^4.5.0", |
|||
"estree-walker": "^2.0.2", |
|||
"source-map-js": "^1.2.1" |
|||
} |
|||
}, |
|||
"node_modules/@vue/compiler-dom": { |
|||
"version": "3.5.22", |
|||
"license": "MIT", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@vue/compiler-core": "3.5.22", |
|||
"@vue/shared": "3.5.22" |
|||
} |
|||
}, |
|||
"node_modules/@vue/compiler-sfc": { |
|||
"version": "3.5.22", |
|||
"license": "MIT", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@babel/parser": "^7.28.4", |
|||
"@vue/compiler-core": "3.5.22", |
|||
"@vue/compiler-dom": "3.5.22", |
|||
"@vue/compiler-ssr": "3.5.22", |
|||
"@vue/shared": "3.5.22", |
|||
"estree-walker": "^2.0.2", |
|||
"magic-string": "^0.30.19", |
|||
"postcss": "^8.5.6", |
|||
"source-map-js": "^1.2.1" |
|||
} |
|||
}, |
|||
"node_modules/@vue/compiler-ssr": { |
|||
"version": "3.5.22", |
|||
"license": "MIT", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@vue/compiler-dom": "3.5.22", |
|||
"@vue/shared": "3.5.22" |
|||
} |
|||
}, |
|||
"node_modules/@vue/devtools-api": { |
|||
"version": "7.7.7", |
|||
"license": "MIT", |
|||
"dependencies": { |
|||
"@vue/devtools-kit": "^7.7.7" |
|||
} |
|||
}, |
|||
"node_modules/@vue/devtools-kit": { |
|||
"version": "7.7.7", |
|||
"license": "MIT", |
|||
"dependencies": { |
|||
"@vue/devtools-shared": "^7.7.7", |
|||
"birpc": "^2.3.0", |
|||
"hookable": "^5.5.3", |
|||
"mitt": "^3.0.1", |
|||
"perfect-debounce": "^1.0.0", |
|||
"speakingurl": "^14.0.1", |
|||
"superjson": "^2.2.2" |
|||
} |
|||
}, |
|||
"node_modules/@vue/devtools-shared": { |
|||
"version": "7.7.7", |
|||
"license": "MIT", |
|||
"dependencies": { |
|||
"rfdc": "^1.4.1" |
|||
} |
|||
}, |
|||
"node_modules/@vue/reactivity": { |
|||
"version": "3.5.22", |
|||
"license": "MIT", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@vue/shared": "3.5.22" |
|||
} |
|||
}, |
|||
"node_modules/@vue/runtime-core": { |
|||
"version": "3.5.22", |
|||
"license": "MIT", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@vue/reactivity": "3.5.22", |
|||
"@vue/shared": "3.5.22" |
|||
} |
|||
}, |
|||
"node_modules/@vue/runtime-dom": { |
|||
"version": "3.5.22", |
|||
"license": "MIT", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@vue/reactivity": "3.5.22", |
|||
"@vue/runtime-core": "3.5.22", |
|||
"@vue/shared": "3.5.22", |
|||
"csstype": "^3.1.3" |
|||
} |
|||
}, |
|||
"node_modules/@vue/server-renderer": { |
|||
"version": "3.5.22", |
|||
"license": "MIT", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@vue/compiler-ssr": "3.5.22", |
|||
"@vue/shared": "3.5.22" |
|||
}, |
|||
"peerDependencies": { |
|||
"vue": "3.5.22" |
|||
} |
|||
}, |
|||
"node_modules/@vue/shared": { |
|||
"version": "3.5.22", |
|||
"license": "MIT", |
|||
"peer": true |
|||
}, |
|||
"node_modules/@vueuse/core": { |
|||
"version": "9.13.0", |
|||
"resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-9.13.0.tgz", |
|||
"integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==", |
|||
"license": "MIT", |
|||
"dependencies": { |
|||
"@types/web-bluetooth": "^0.0.16", |
|||
"@vueuse/metadata": "9.13.0", |
|||
"@vueuse/shared": "9.13.0", |
|||
"vue-demi": "*" |
|||
}, |
|||
"funding": { |
|||
"url": "https://github.com/sponsors/antfu" |
|||
} |
|||
}, |
|||
"node_modules/@vueuse/core/node_modules/vue-demi": { |
|||
"version": "0.14.10", |
|||
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz", |
|||
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", |
|||
"hasInstallScript": true, |
|||
"license": "MIT", |
|||
"bin": { |
|||
"vue-demi-fix": "bin/vue-demi-fix.js", |
|||
"vue-demi-switch": "bin/vue-demi-switch.js" |
|||
}, |
|||
"engines": { |
|||
"node": ">=12" |
|||
}, |
|||
"funding": { |
|||
"url": "https://github.com/sponsors/antfu" |
|||
}, |
|||
"peerDependencies": { |
|||
"@vue/composition-api": "^1.0.0-rc.1", |
|||
"vue": "^3.0.0-0 || ^2.6.0" |
|||
}, |
|||
"peerDependenciesMeta": { |
|||
"@vue/composition-api": { |
|||
"optional": true |
|||
} |
|||
} |
|||
}, |
|||
"node_modules/@vueuse/metadata": { |
|||
"version": "9.13.0", |
|||
"resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.13.0.tgz", |
|||
"integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==", |
|||
"license": "MIT", |
|||
"funding": { |
|||
"url": "https://github.com/sponsors/antfu" |
|||
} |
|||
}, |
|||
"node_modules/@vueuse/shared": { |
|||
"version": "9.13.0", |
|||
"resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.13.0.tgz", |
|||
"integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==", |
|||
"license": "MIT", |
|||
"dependencies": { |
|||
"vue-demi": "*" |
|||
}, |
|||
"funding": { |
|||
"url": "https://github.com/sponsors/antfu" |
|||
} |
|||
}, |
|||
"node_modules/@vueuse/shared/node_modules/vue-demi": { |
|||
"version": "0.14.10", |
|||
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz", |
|||
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", |
|||
"hasInstallScript": true, |
|||
"license": "MIT", |
|||
"bin": { |
|||
"vue-demi-fix": "bin/vue-demi-fix.js", |
|||
"vue-demi-switch": "bin/vue-demi-switch.js" |
|||
}, |
|||
"engines": { |
|||
"node": ">=12" |
|||
}, |
|||
"funding": { |
|||
"url": "https://github.com/sponsors/antfu" |
|||
}, |
|||
"peerDependencies": { |
|||
"@vue/composition-api": "^1.0.0-rc.1", |
|||
"vue": "^3.0.0-0 || ^2.6.0" |
|||
}, |
|||
"peerDependenciesMeta": { |
|||
"@vue/composition-api": { |
|||
"optional": true |
|||
} |
|||
} |
|||
}, |
|||
"node_modules/async-validator": { |
|||
"version": "4.2.5", |
|||
"resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz", |
|||
"integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==", |
|||
"license": "MIT" |
|||
}, |
|||
"node_modules/birpc": { |
|||
"version": "2.6.1", |
|||
"license": "MIT", |
|||
"funding": { |
|||
"url": "https://github.com/sponsors/antfu" |
|||
} |
|||
}, |
|||
"node_modules/copy-anything": { |
|||
"version": "4.0.5", |
|||
"license": "MIT", |
|||
"dependencies": { |
|||
"is-what": "^5.2.0" |
|||
}, |
|||
"engines": { |
|||
"node": ">=18" |
|||
}, |
|||
"funding": { |
|||
"url": "https://github.com/sponsors/mesqueeb" |
|||
} |
|||
}, |
|||
"node_modules/csstype": { |
|||
"version": "3.1.3", |
|||
"license": "MIT", |
|||
"peer": true |
|||
}, |
|||
"node_modules/dayjs": { |
|||
"version": "1.11.18", |
|||
"license": "MIT" |
|||
}, |
|||
"node_modules/deep-pick-omit": { |
|||
"version": "1.2.1", |
|||
"license": "MIT" |
|||
}, |
|||
"node_modules/defu": { |
|||
"version": "6.1.4", |
|||
"license": "MIT" |
|||
}, |
|||
"node_modules/destr": { |
|||
"version": "2.0.5", |
|||
"license": "MIT" |
|||
}, |
|||
"node_modules/element-plus": { |
|||
"version": "2.11.5", |
|||
"resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.11.5.tgz", |
|||
"integrity": "sha512-O+bIVHQCjUDm4GiIznDXRoS8ar2TpWLwfOGnN/Aam0VXf5kbuc4SxdKKJdovWNxmxeqbcwjsSZPKgtXNcqys4A==", |
|||
"license": "MIT", |
|||
"dependencies": { |
|||
"@ctrl/tinycolor": "^3.4.1", |
|||
"@element-plus/icons-vue": "^2.3.2", |
|||
"@floating-ui/dom": "^1.0.1", |
|||
"@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7", |
|||
"@types/lodash": "^4.17.20", |
|||
"@types/lodash-es": "^4.17.12", |
|||
"@vueuse/core": "^9.1.0", |
|||
"async-validator": "^4.2.5", |
|||
"dayjs": "^1.11.18", |
|||
"lodash": "^4.17.21", |
|||
"lodash-es": "^4.17.21", |
|||
"lodash-unified": "^1.0.3", |
|||
"memoize-one": "^6.0.0", |
|||
"normalize-wheel-es": "^1.2.0" |
|||
}, |
|||
"peerDependencies": { |
|||
"vue": "^3.2.0" |
|||
} |
|||
}, |
|||
"node_modules/entities": { |
|||
"version": "4.5.0", |
|||
"license": "BSD-2-Clause", |
|||
"peer": true, |
|||
"engines": { |
|||
"node": ">=0.12" |
|||
}, |
|||
"funding": { |
|||
"url": "https://github.com/fb55/entities?sponsor=1" |
|||
} |
|||
}, |
|||
"node_modules/estree-walker": { |
|||
"version": "2.0.2", |
|||
"license": "MIT", |
|||
"peer": true |
|||
}, |
|||
"node_modules/hookable": { |
|||
"version": "5.5.3", |
|||
"license": "MIT" |
|||
}, |
|||
"node_modules/is-what": { |
|||
"version": "5.5.0", |
|||
"license": "MIT", |
|||
"engines": { |
|||
"node": ">=18" |
|||
}, |
|||
"funding": { |
|||
"url": "https://github.com/sponsors/mesqueeb" |
|||
} |
|||
}, |
|||
"node_modules/lodash": { |
|||
"version": "4.17.21", |
|||
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz", |
|||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", |
|||
"license": "MIT" |
|||
}, |
|||
"node_modules/lodash-es": { |
|||
"version": "4.17.21", |
|||
"resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz", |
|||
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", |
|||
"license": "MIT" |
|||
}, |
|||
"node_modules/lodash-unified": { |
|||
"version": "1.0.3", |
|||
"resolved": "https://registry.npmmirror.com/lodash-unified/-/lodash-unified-1.0.3.tgz", |
|||
"integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==", |
|||
"license": "MIT", |
|||
"peerDependencies": { |
|||
"@types/lodash-es": "*", |
|||
"lodash": "*", |
|||
"lodash-es": "*" |
|||
} |
|||
}, |
|||
"node_modules/magic-string": { |
|||
"version": "0.30.21", |
|||
"license": "MIT", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@jridgewell/sourcemap-codec": "^1.5.5" |
|||
} |
|||
}, |
|||
"node_modules/marked": { |
|||
"version": "2.0.1", |
|||
"license": "MIT", |
|||
"bin": { |
|||
"marked": "bin/marked" |
|||
}, |
|||
"engines": { |
|||
"node": ">= 8.16.2" |
|||
} |
|||
}, |
|||
"node_modules/memoize-one": { |
|||
"version": "6.0.0", |
|||
"resolved": "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz", |
|||
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", |
|||
"license": "MIT" |
|||
}, |
|||
"node_modules/mitt": { |
|||
"version": "3.0.1", |
|||
"license": "MIT" |
|||
}, |
|||
"node_modules/nanoid": { |
|||
"version": "3.3.11", |
|||
"funding": [ |
|||
{ |
|||
"type": "github", |
|||
"url": "https://github.com/sponsors/ai" |
|||
} |
|||
], |
|||
"license": "MIT", |
|||
"peer": true, |
|||
"bin": { |
|||
"nanoid": "bin/nanoid.cjs" |
|||
}, |
|||
"engines": { |
|||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" |
|||
} |
|||
}, |
|||
"node_modules/normalize-wheel-es": { |
|||
"version": "1.2.0", |
|||
"resolved": "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", |
|||
"integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==", |
|||
"license": "BSD-3-Clause" |
|||
}, |
|||
"node_modules/perfect-debounce": { |
|||
"version": "1.0.0", |
|||
"license": "MIT" |
|||
}, |
|||
"node_modules/picocolors": { |
|||
"version": "1.1.1", |
|||
"license": "ISC", |
|||
"peer": true |
|||
}, |
|||
"node_modules/pinia": { |
|||
"version": "3.0.3", |
|||
"license": "MIT", |
|||
"dependencies": { |
|||
"@vue/devtools-api": "^7.7.2" |
|||
}, |
|||
"funding": { |
|||
"url": "https://github.com/sponsors/posva" |
|||
}, |
|||
"peerDependencies": { |
|||
"typescript": ">=4.4.4", |
|||
"vue": "^2.7.0 || ^3.5.11" |
|||
}, |
|||
"peerDependenciesMeta": { |
|||
"typescript": { |
|||
"optional": true |
|||
} |
|||
} |
|||
}, |
|||
"node_modules/pinia-plugin-persistedstate": { |
|||
"version": "4.5.0", |
|||
"license": "MIT", |
|||
"dependencies": { |
|||
"deep-pick-omit": "^1.2.1", |
|||
"defu": "^6.1.4", |
|||
"destr": "^2.0.5" |
|||
}, |
|||
"peerDependencies": { |
|||
"@nuxt/kit": ">=3.0.0", |
|||
"@pinia/nuxt": ">=0.10.0", |
|||
"pinia": ">=3.0.0" |
|||
}, |
|||
"peerDependenciesMeta": { |
|||
"@nuxt/kit": { |
|||
"optional": true |
|||
}, |
|||
"@pinia/nuxt": { |
|||
"optional": true |
|||
}, |
|||
"pinia": { |
|||
"optional": true |
|||
} |
|||
} |
|||
}, |
|||
"node_modules/postcss": { |
|||
"version": "8.5.6", |
|||
"funding": [ |
|||
{ |
|||
"type": "opencollective", |
|||
"url": "https://opencollective.com/postcss/" |
|||
}, |
|||
{ |
|||
"type": "tidelift", |
|||
"url": "https://tidelift.com/funding/github/npm/postcss" |
|||
}, |
|||
{ |
|||
"type": "github", |
|||
"url": "https://github.com/sponsors/ai" |
|||
} |
|||
], |
|||
"license": "MIT", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"nanoid": "^3.3.11", |
|||
"picocolors": "^1.1.1", |
|||
"source-map-js": "^1.2.1" |
|||
}, |
|||
"engines": { |
|||
"node": "^10 || ^12 || >=14" |
|||
} |
|||
}, |
|||
"node_modules/rfdc": { |
|||
"version": "1.4.1", |
|||
"license": "MIT" |
|||
}, |
|||
"node_modules/source-map-js": { |
|||
"version": "1.2.1", |
|||
"license": "BSD-3-Clause", |
|||
"engines": { |
|||
"node": ">=0.10.0" |
|||
} |
|||
}, |
|||
"node_modules/speakingurl": { |
|||
"version": "14.0.1", |
|||
"license": "BSD-3-Clause", |
|||
"engines": { |
|||
"node": ">=0.10.0" |
|||
} |
|||
}, |
|||
"node_modules/superjson": { |
|||
"version": "2.2.3", |
|||
"license": "MIT", |
|||
"dependencies": { |
|||
"copy-anything": "^4" |
|||
}, |
|||
"engines": { |
|||
"node": ">=16" |
|||
} |
|||
}, |
|||
"node_modules/vue": { |
|||
"version": "3.5.22", |
|||
"license": "MIT", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@vue/compiler-dom": "3.5.22", |
|||
"@vue/compiler-sfc": "3.5.22", |
|||
"@vue/runtime-dom": "3.5.22", |
|||
"@vue/server-renderer": "3.5.22", |
|||
"@vue/shared": "3.5.22" |
|||
}, |
|||
"peerDependencies": { |
|||
"typescript": "*" |
|||
}, |
|||
"peerDependenciesMeta": { |
|||
"typescript": { |
|||
"optional": true |
|||
} |
|||
} |
|||
}, |
|||
"node_modules/vue-i18n": { |
|||
"version": "9.14.5", |
|||
"resolved": "https://registry.npmmirror.com/vue-i18n/-/vue-i18n-9.14.5.tgz", |
|||
"integrity": "sha512-0jQ9Em3ymWngyiIkj0+c/k7WgaPO+TNzjKSNq9BvBQaKJECqn9cd9fL4tkDhB5G1QBskGl9YxxbDAhgbFtpe2g==", |
|||
"license": "MIT", |
|||
"dependencies": { |
|||
"@intlify/core-base": "9.14.5", |
|||
"@intlify/shared": "9.14.5", |
|||
"@vue/devtools-api": "^6.5.0" |
|||
}, |
|||
"engines": { |
|||
"node": ">= 16" |
|||
}, |
|||
"funding": { |
|||
"url": "https://github.com/sponsors/kazupon" |
|||
}, |
|||
"peerDependencies": { |
|||
"vue": "^3.0.0" |
|||
} |
|||
}, |
|||
"node_modules/vue-i18n/node_modules/@vue/devtools-api": { |
|||
"version": "6.6.4", |
|||
"resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz", |
|||
"integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", |
|||
"license": "MIT" |
|||
} |
|||
} |
|||
} |
|||
@ -1,10 +1,12 @@ |
|||
{ |
|||
"dependencies": { |
|||
"json-server": "^1.0.0-beta.3", |
|||
"@dcloudio/uni-ui": "^1.5.11", |
|||
"@element-plus/icons-vue": "^2.3.2", |
|||
"element-plus": "^2.11.5", |
|||
"vue-i18n": "^9.14.5", |
|||
"marked": "^2.0.1", |
|||
"pinia": "^3.0.3", |
|||
"pinia-plugin-persistedstate": "^4.5.0", |
|||
"vue-i18n": "^11.1.12" |
|||
"pinia-plugin-persistedstate": "^4.5.0" |
|||
} |
|||
|
|||
|
|||
|
|||
@ -1,63 +0,0 @@ |
|||
<template> |
|||
<view class="container"> |
|||
<scroll-view |
|||
class="scroll-view" |
|||
scroll-y="true" |
|||
@scrolltolower="onScrollToLower" |
|||
> |
|||
<button @click="scrollTo">点击滚动</button> |
|||
<view v-for="(item, index) in list" :key="index"> |
|||
{{ item }} |
|||
</view> |
|||
</scroll-view> |
|||
<button @click="addItem">添加内容</button> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
list: Array.from({ length: 20 }, (_, i) => `Item ${i + 1}`), |
|||
}; |
|||
}, |
|||
methods: { |
|||
onScrollToLower() { |
|||
console.log("滚动到底部了"); |
|||
// 可以在这里加载更多数据 |
|||
}, |
|||
addItem() { |
|||
this.list.push(`Item ${this.list.length + 1}`); |
|||
this.$nextTick(() => { |
|||
this.$refs.scrollView.scrollTo({ |
|||
top: 99999, |
|||
duration: 300, |
|||
}); |
|||
}); |
|||
}, |
|||
scrollTo() { |
|||
uni.pageScrollTo({ |
|||
scrollTop: 100, |
|||
duration: 300, |
|||
}); |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style> |
|||
.container { |
|||
height: 100%; |
|||
} |
|||
.scroll-view { |
|||
height: 80%; |
|||
} |
|||
button { |
|||
width: 100%; |
|||
height: 50px; |
|||
line-height: 50px; |
|||
text-align: center; |
|||
background-color: #007aff; |
|||
color: white; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,579 @@ |
|||
<!-- @format --> |
|||
|
|||
<template> |
|||
<view class="main"> |
|||
<!-- 固定头部 --> |
|||
<view class="header_fixed" :style="{ top: iSMT + 'px' }"> |
|||
<view class="header_content"> |
|||
<view class="header_back" @click="goBack"> |
|||
<image src="/static/marketSituation-image/back.png" mode=""></image> |
|||
</view> |
|||
<view class="header_input_wrapper"> |
|||
<image class="search_icon" src="/static/marketSituation-image/search.png" mode="" @click="onSearchClick"></image> |
|||
<input class="header_input" type="text" placeholder="搜索" placeholder-style="color: #A6A6A6; font-size: 22rpx;" v-model="searchValue" @input="onSearchInput" @confirm="onSearchConfirm" /> |
|||
</view> |
|||
<view class="header_icons"> |
|||
<view class="header_icon" @click="selected"> |
|||
<image src="/static/marketSituation-image/mySeclected.png" mode=""></image> |
|||
</view> |
|||
<view class="header_icon" @click="history"> |
|||
<image src="/static/marketSituation-image/history.png" mode=""></image> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view class="warn"> |
|||
<image src="/static/marketSituation-image/warn.png" mode="aspectFit"></image> |
|||
<view class="warn_text_container"> |
|||
<text :class="warnTextClass">{{ $t("marketSituation.warn") }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 内容区域 --> |
|||
<scroll-view class="content" :style="{ top: contentTopPosition + 'px' }" scroll-y="true"> |
|||
<!-- 亚太-中华 --> |
|||
<view class="market-section"> |
|||
<view class="market-header"> |
|||
<text class="market-title">亚太-中华</text> |
|||
<view class="market-more" @click="viewMore('asia-china')"> |
|||
<text class="more-text">查看更多</text> |
|||
<text class="more-arrow">></text> |
|||
</view> |
|||
</view> |
|||
<view class="cards-grid-three"> |
|||
<view v-for="(item, index) in asiachinaIndexes" :key="index" class="card-item"> |
|||
<IndexCard :flagIcon="item.flagIcon" :stockName="item.stockName" :currentPrice="item.currentPrice" :changeAmount="item.changeAmount" :changePercent="item.changePercent" :isRising="item.isRising" @click="viewIndexDetail(item)" /> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 亚太 --> |
|||
<view class="market-section"> |
|||
<view class="market-header"> |
|||
<text class="market-title">亚太</text> |
|||
<view class="market-more" @click="viewMore('asia')"> |
|||
<text class="more-text">查看更多</text> |
|||
<text class="more-arrow">></text> |
|||
</view> |
|||
</view> |
|||
<view class="cards-grid-three"> |
|||
<view v-for="(item, index) in asiaIndexes" :key="index" class="card-item"> |
|||
<IndexCard :flagIcon="item.flagIcon" :stockName="item.stockName" :currentPrice="item.currentPrice" :changeAmount="item.changeAmount" :changePercent="item.changePercent" :isRising="item.isRising" @click="viewIndexDetail(item)" /> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 美洲 --> |
|||
<view class="market-section"> |
|||
<view class="market-header"> |
|||
<text class="market-title">美洲</text> |
|||
<view class="market-more" @click="viewMore('america')"> |
|||
<text class="more-text">查看更多</text> |
|||
<text class="more-arrow">></text> |
|||
</view> |
|||
</view> |
|||
<view class="cards-grid-three"> |
|||
<view v-for="(item, index) in americaIndexes" :key="index" class="card-item"> |
|||
<IndexCard :flagIcon="item.flagIcon" :stockName="item.stockName" :currentPrice="item.currentPrice" :changeAmount="item.changeAmount" :changePercent="item.changePercent" :isRising="item.isRising" @click="viewIndexDetail(item)" /> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 底部安全区域 --> |
|||
<view class="bottom-safe-area"></view> |
|||
</scroll-view> |
|||
</view> |
|||
|
|||
<!-- 底部导航栏 --> |
|||
<footerBar class="static-footer" :type="'marketSituation'"></footerBar> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, onMounted, computed, nextTick, watch } from "vue"; |
|||
import footerBar from "../../components/footerBar.vue"; |
|||
import IndexCard from "../../components/IndexCard.vue"; |
|||
|
|||
// 响应式数据 |
|||
const iSMT = ref(0); // 状态栏高度 |
|||
const contentHeight = ref(0); |
|||
const headerHeight = ref(0); // 头部高度 |
|||
const searchValue = ref(""); // 搜索值 |
|||
const isWarnTextOverflow = ref(false); // warn文字是否溢出 |
|||
|
|||
// warn文字的class计算属性 |
|||
const warnTextClass = computed(() => { |
|||
return isWarnTextOverflow.value ? "warn_text scroll-active" : "warn_text"; |
|||
}); |
|||
|
|||
// 检测warn文字是否溢出 |
|||
const checkWarnTextOverflow = () => { |
|||
nextTick(() => { |
|||
setTimeout(() => { |
|||
const query = uni.createSelectorQuery(); |
|||
|
|||
// 同时查询容器和文字元素 |
|||
query.select(".warn_text_container").boundingClientRect(); |
|||
query.select(".warn_text").boundingClientRect(); |
|||
query.exec((res) => { |
|||
const containerRect = res[0]; |
|||
const textRect = res[1]; |
|||
|
|||
if (!containerRect || !textRect) { |
|||
return; |
|||
} |
|||
|
|||
// 判断文字是否超出容器(留一些余量) |
|||
const isOverflow = textRect.width > containerRect.width - 10; |
|||
|
|||
isWarnTextOverflow.value = isOverflow; |
|||
}); |
|||
}, 500); |
|||
}); |
|||
}; |
|||
|
|||
// 亚太-中华指数数据 |
|||
const asiachinaIndexes = ref([ |
|||
{ |
|||
flagIcon: "/static/c1.png", |
|||
stockName: "上证指数", |
|||
stockCode: "1A0001", |
|||
currentPrice: "3933.96", |
|||
changeAmount: "+24.32", |
|||
changePercent: "+0.62%", |
|||
isRising: true, |
|||
}, |
|||
{ |
|||
flagIcon: "/static/c2.png", |
|||
stockName: "深证成指", |
|||
stockCode: "2A01", |
|||
currentPrice: "45757.90", |
|||
changeAmount: "-123.45", |
|||
changePercent: "-0.27%", |
|||
isRising: false, |
|||
}, |
|||
{ |
|||
flagIcon: "/static/c3.png", |
|||
stockName: "创业板指", |
|||
stockCode: "399006", |
|||
currentPrice: "6606.08", |
|||
changeAmount: "+89.76", |
|||
changePercent: "+1.38%", |
|||
isRising: true, |
|||
}, |
|||
{ |
|||
flagIcon: "/static/c4.png", |
|||
stockName: "沪深300", |
|||
stockCode: "1B0300", |
|||
currentPrice: "45757.90", |
|||
changeAmount: "-89.12", |
|||
changePercent: "-0.19%", |
|||
isRising: false, |
|||
}, |
|||
{ |
|||
flagIcon: "/static/c5.png", |
|||
stockName: "上证50", |
|||
stockCode: "1B0011", |
|||
currentPrice: "45757.90", |
|||
changeAmount: "+234.56", |
|||
changePercent: "+0.52%", |
|||
isRising: true, |
|||
}, |
|||
{ |
|||
flagIcon: "/static/c6.png", |
|||
stockName: "科创50", |
|||
stockCode: "1B0688", |
|||
currentPrice: "22333.96", |
|||
changeAmount: "+156.78", |
|||
changePercent: "+0.71%", |
|||
isRising: true, |
|||
}, |
|||
]); |
|||
|
|||
// 亚太指数数据 |
|||
const asiaIndexes = ref([ |
|||
{ |
|||
flagIcon: "/static/c7.png", |
|||
stockName: "日经225", |
|||
stockCode: "noCode", |
|||
currentPrice: "28456.78", |
|||
changeAmount: "+234.56", |
|||
changePercent: "+0.83%", |
|||
isRising: true, |
|||
}, |
|||
{ |
|||
flagIcon: "/static/c8.png", |
|||
stockName: "韩国KOSPI", |
|||
stockCode: "noCode", |
|||
currentPrice: "2567.89", |
|||
changeAmount: "-12.34", |
|||
changePercent: "-0.48%", |
|||
isRising: false, |
|||
}, |
|||
{ |
|||
flagIcon: "/static/c9.png", |
|||
stockName: "印度孟买", |
|||
stockCode: "noCode", |
|||
currentPrice: "65432.10", |
|||
changeAmount: "+456.78", |
|||
changePercent: "+0.70%", |
|||
isRising: true, |
|||
}, |
|||
]); |
|||
|
|||
// 美洲指数数据 |
|||
const americaIndexes = ref([ |
|||
{ |
|||
flagIcon: "/static/c7.png", |
|||
stockName: "道琼斯指数", |
|||
stockCode: "noCode", |
|||
currentPrice: "34567.89", |
|||
changeAmount: "+123.45", |
|||
changePercent: "+0.36%", |
|||
isRising: true, |
|||
}, |
|||
{ |
|||
flagIcon: "/static/c8.png", |
|||
stockName: "纳斯达克", |
|||
stockCode: "noCode", |
|||
currentPrice: "13456.78", |
|||
changeAmount: "-67.89", |
|||
changePercent: "-0.50%", |
|||
isRising: false, |
|||
}, |
|||
{ |
|||
flagIcon: "/static/c9.png", |
|||
stockName: "标普500", |
|||
stockCode: "noCode", |
|||
currentPrice: "4234.56", |
|||
changeAmount: "+23.45", |
|||
changePercent: "+0.56%", |
|||
isRising: true, |
|||
}, |
|||
]); |
|||
|
|||
// 计算属性:内容区域顶部位置 |
|||
const contentTopPosition = computed(() => { |
|||
const statusBarHeight = iSMT.value || 0; |
|||
const currentHeaderHeight = headerHeight.value > 0 ? headerHeight.value : 100; |
|||
return statusBarHeight + currentHeaderHeight; |
|||
}); |
|||
|
|||
// 方法:返回上一页 |
|||
const goBack = () => { |
|||
uni.navigateBack(); |
|||
}; |
|||
|
|||
// 方法:搜索输入 |
|||
const onSearchInput = (e) => { |
|||
searchValue.value = e.detail.value; |
|||
}; |
|||
|
|||
// 方法:清除搜索 |
|||
const clearSearch = () => { |
|||
searchValue.value = ""; |
|||
}; |
|||
|
|||
// 方法:查看更多 |
|||
const viewMore = (market) => { |
|||
console.log("查看更多:", market); |
|||
uni.navigateTo({ |
|||
url: `/pages/home/marketDetail?market=${market}`, |
|||
}); |
|||
}; |
|||
|
|||
// 方法:查看指数详情 |
|||
const viewIndexDetail = (item) => { |
|||
console.log("查看指数详情:", item.stockName); |
|||
// uni.showToast({ |
|||
// title: `查看 ${item.stockName} 详情`, |
|||
// icon: 'none', |
|||
// duration: 2000 |
|||
// }) |
|||
// 这里可以跳转到具体的指数详情页面 |
|||
uni.navigateTo({ |
|||
url: `/pages/home/marketCondition?stockInformation=${encodeURIComponent(JSON.stringify(item))}`, |
|||
}); |
|||
}; |
|||
|
|||
// 生命周期:页面挂载 |
|||
onMounted(() => { |
|||
// 获取系统信息 |
|||
const systemInfo = uni.getSystemInfoSync(); |
|||
iSMT.value = systemInfo.statusBarHeight || 0; |
|||
|
|||
console.log("全球指数页面加载完成"); |
|||
// 动态计算header实际高度 |
|||
uni |
|||
.createSelectorQuery() |
|||
.select(".header_fixed") |
|||
.boundingClientRect((rect) => { |
|||
if (rect) { |
|||
headerHeight.value = rect.height; |
|||
console.log("Header实际高度:", headerHeight.value, "px"); |
|||
} |
|||
}) |
|||
.exec(); |
|||
// 检测warn文字是否溢出 |
|||
checkWarnTextOverflow(); |
|||
}); |
|||
|
|||
// 监听headerHeight变化,重新计算contentHeight |
|||
watch(headerHeight, (newHeight) => { |
|||
if (newHeight > 0) { |
|||
const systemInfo = uni.getSystemInfoSync(); |
|||
const windowHeight = systemInfo.windowHeight; |
|||
const statusBarHeight = systemInfo.statusBarHeight || 0; |
|||
const footerHeight = 100; |
|||
|
|||
contentHeight.value = windowHeight - statusBarHeight - newHeight - footerHeight; |
|||
console.log("重新计算contentHeight:", contentHeight.value); |
|||
} |
|||
}); |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.main { |
|||
position: relative; |
|||
height: 100vh; |
|||
overflow: hidden; |
|||
background-color: #f5f5f5; |
|||
} |
|||
|
|||
/* 状态栏占位 */ |
|||
.top { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
z-index: 1001; |
|||
background-color: #ffffff; |
|||
} |
|||
|
|||
/* 固定头部样式 */ |
|||
.header_fixed { |
|||
position: fixed; |
|||
left: 0; |
|||
right: 0; |
|||
z-index: 1000; |
|||
background-color: #ffffff; |
|||
padding: 20rpx 0 0 0; |
|||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1); |
|||
} |
|||
|
|||
.header_content { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
height: 80rpx; |
|||
padding: 0 20rpx; |
|||
margin-bottom: 10rpx; |
|||
} |
|||
|
|||
.header_back { |
|||
margin-right: 20rpx; |
|||
width: 25rpx; |
|||
height: 30rpx; |
|||
} |
|||
|
|||
.header_back image { |
|||
width: 25rpx; |
|||
height: 30rpx; |
|||
} |
|||
|
|||
.header_input_wrapper { |
|||
display: flex; |
|||
align-items: center; |
|||
width: 100%; |
|||
margin: 0 20rpx 0 0; |
|||
height: 70rpx; |
|||
border-radius: 35rpx; |
|||
background-color: #ffffff; |
|||
border: 1rpx solid #e9ecef; |
|||
padding: 0 80rpx 0 30rpx; |
|||
font-size: 28rpx; |
|||
color: #5c5c5c; |
|||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1); |
|||
} |
|||
|
|||
.search_icon { |
|||
width: 40rpx; |
|||
height: 40rpx; |
|||
opacity: 0.6; |
|||
} |
|||
|
|||
.header_input { |
|||
margin-left: 10rpx; |
|||
} |
|||
|
|||
.header_icons { |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 15rpx; |
|||
} |
|||
|
|||
.header_icon { |
|||
width: 40rpx; |
|||
height: 40rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.header_icon image { |
|||
width: 40rpx; |
|||
height: 40rpx; |
|||
} |
|||
|
|||
.warn { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: flex-start; |
|||
gap: 10rpx; |
|||
font-size: 28rpx; |
|||
color: #666666; |
|||
padding: 20rpx; |
|||
max-width: 100%; |
|||
overflow: hidden; |
|||
position: relative; |
|||
} |
|||
|
|||
.warn image { |
|||
width: 40rpx; |
|||
height: 40rpx; |
|||
flex-shrink: 0; |
|||
/* 防止图片被压缩 */ |
|||
position: relative; |
|||
z-index: 2; |
|||
/* 确保图片在最上层 */ |
|||
} |
|||
|
|||
.warn_text_container { |
|||
flex: 1; |
|||
overflow: hidden; |
|||
position: relative; |
|||
min-width: 0; |
|||
/* 允许容器收缩 */ |
|||
} |
|||
|
|||
.warn_text { |
|||
display: block; |
|||
white-space: nowrap; |
|||
will-change: transform; |
|||
/* 优化动画性能 */ |
|||
} |
|||
|
|||
/* 文字滚动动画 */ |
|||
@keyframes scrollText { |
|||
0% { |
|||
transform: translateX(0); |
|||
} |
|||
|
|||
20% { |
|||
transform: translateX(0); |
|||
} |
|||
|
|||
80% { |
|||
transform: translateX(-85%); |
|||
} |
|||
|
|||
100% { |
|||
transform: translateX(-85%); |
|||
} |
|||
} |
|||
|
|||
/* 当文字超长时启用滚动动画 */ |
|||
.warn_text.scroll-active { |
|||
animation: scrollText 12s linear infinite; |
|||
animation-delay: 2s; |
|||
/* 延迟2秒开始滚动,让用户先看到开头 */ |
|||
} |
|||
|
|||
/* 内容区域 */ |
|||
.content { |
|||
position: fixed; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: 120rpx; |
|||
background-color: #f5f5f5; |
|||
padding: 0; |
|||
} |
|||
|
|||
/* 市场分组 */ |
|||
.market-section { |
|||
background-color: white; |
|||
border-radius: 20rpx; |
|||
} |
|||
|
|||
.market-header { |
|||
margin: 20rpx 20rpx 0 20rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
margin-bottom: 10rpx; |
|||
padding-bottom: 10rpx; |
|||
border-bottom: 2rpx solid #f0f0f0; |
|||
} |
|||
|
|||
.market-title { |
|||
font-size: 32rpx; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.market-more { |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 8rpx; |
|||
} |
|||
|
|||
.more-text { |
|||
font-size: 24rpx; |
|||
color: #666; |
|||
} |
|||
|
|||
.more-arrow { |
|||
font-size: 20rpx; |
|||
color: #666; |
|||
font-weight: bold; |
|||
} |
|||
|
|||
/* 三列卡片网格 */ |
|||
.cards-grid-three { |
|||
display: grid; |
|||
grid-template-columns: repeat(3, 1fr); |
|||
} |
|||
|
|||
.card-item { |
|||
background-color: white; |
|||
border-radius: 16rpx; |
|||
overflow: hidden; |
|||
transition: transform 0.2s ease, box-shadow 0.2s ease; |
|||
} |
|||
|
|||
.card-item:active { |
|||
transform: scale(0.98); |
|||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.12); |
|||
} |
|||
|
|||
/* 底部安全区域 */ |
|||
.bottom-safe-area { |
|||
height: 40rpx; |
|||
background-color: transparent; |
|||
} |
|||
|
|||
/* 底部导航栏 */ |
|||
.static-footer { |
|||
position: fixed; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
z-index: 1000; |
|||
} |
|||
|
|||
/* 响应式设计 */ |
|||
@media (max-width: 400rpx) { |
|||
.cards-grid-three { |
|||
grid-template-columns: repeat(2, 1fr); |
|||
} |
|||
} |
|||
</style> |
|||
2046
pages/home/marketCondition.vue
File diff suppressed because it is too large
View File
@ -0,0 +1,488 @@ |
|||
<!-- @format --> |
|||
|
|||
<template> |
|||
<view class="main"> |
|||
<!-- 自定义导航栏 --> |
|||
<view class="header_fixed" :style="{ top: iSMT + 'px' }"> |
|||
<view class="header-content"> |
|||
<view class="header-left" @click="goBack"> |
|||
<text class="back-text">‹</text> |
|||
</view> |
|||
<view class="header-center"> |
|||
<text class="header-title">{{ marketTitle }}</text> |
|||
</view> |
|||
<view class="header-right"> |
|||
<image src="/static/marketSituation-image/search.png" class="header-icon" mode="aspectFit"></image> |
|||
<text class="more-text">···</text> |
|||
</view> |
|||
</view> |
|||
<!-- 表头 --> |
|||
<view class="table-header"> |
|||
<view class="header-item name-column"> |
|||
<text class="header-text">名称</text> |
|||
</view> |
|||
<view class="header-item price-column" @click="sortByPrice"> |
|||
<text class="header-text">最新</text> |
|||
<text class="sort-icon">{{ sortType === "price" ? (sortOrder === "asc" ? "↑" : "↓") : "↕" }}</text> |
|||
</view> |
|||
<view class="header-item change-column" @click="sortByChange"> |
|||
<text class="header-text">涨幅</text> |
|||
<text class="sort-icon">{{ sortType === "change" ? (sortOrder === "asc" ? "↑" : "↓") : "↕" }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 内容区域 --> |
|||
<scroll-view class="content" :style="{ top: contentTopPosition + 'px' }" scroll-y="true"> |
|||
<!-- 股票列表 --> |
|||
<view class="stock-list"> |
|||
<view class="stock-row" v-for="(stock, index) in sortedStockList" :key="index" @click="viewStockDetail(stock)"> |
|||
<view class="stock-cell name-column"> |
|||
<view class="stock-name">{{ stock.stockName }}</view> |
|||
<view class="stock-code">{{ stock.stockCode }}</view> |
|||
</view> |
|||
<view class="stock-cell price-column"> |
|||
<text class="stock-price" :class="stock.isRising ? 'rising' : 'falling'"> |
|||
{{ typeof stock.price === "number" ? stock.price.toFixed(2) : stock.price }} |
|||
</text> |
|||
</view> |
|||
<view class="stock-cell change-column"> |
|||
<text class="stock-change" :class="stock.isRising ? 'rising' : 'falling'"> |
|||
{{ stock.change || stock.changePercent }} |
|||
</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 底部安全区域 --> |
|||
<!-- <view class="bottom-safe-area"></view> --> |
|||
</scroll-view> |
|||
</view> |
|||
|
|||
<!-- 底部导航栏 --> |
|||
<!-- <footerBar class="static-footer" :type="'marketSituation'"></footerBar> --> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, computed, onMounted, watch } from "vue"; |
|||
import { onLoad } from "@dcloudio/uni-app"; |
|||
import footerBar from "@/components/footerBar.vue"; |
|||
|
|||
// 响应式数据 |
|||
const iSMT = ref(0); |
|||
const headerHeight = ref(80); |
|||
const marketType = ref("america"); |
|||
const marketTitle = ref("美洲"); |
|||
const sortType = ref(""); // 排序类型:'price' 或 'change' |
|||
const sortOrder = ref("desc"); // 排序顺序:'asc' 或 'desc' |
|||
|
|||
// 股票数据 |
|||
const stockList = ref([ |
|||
{ |
|||
stockName: "Telecommunication", |
|||
stockCode: "888607", |
|||
price: 1349.47, |
|||
change: "+7.67%", |
|||
isRising: true, |
|||
}, |
|||
{ |
|||
stockName: "Other", |
|||
stockCode: "888607", |
|||
price: 1349.47, |
|||
change: "+6.67%", |
|||
isRising: true, |
|||
}, |
|||
{ |
|||
stockName: "Consumer Discretio...", |
|||
stockCode: "888610", |
|||
price: 1349.47, |
|||
change: "+5.67%", |
|||
isRising: true, |
|||
}, |
|||
{ |
|||
stockName: "Telecommunication", |
|||
stockCode: "888607", |
|||
price: 1349.47, |
|||
change: "+4.67%", |
|||
isRising: true, |
|||
}, |
|||
{ |
|||
stockName: "Other", |
|||
stockCode: "888611", |
|||
price: 1359.47, |
|||
change: "+3.67%", |
|||
isRising: true, |
|||
}, |
|||
{ |
|||
stockName: "Consumer Discretio...", |
|||
stockCode: "888610", |
|||
price: 1349.47, |
|||
change: "+2.67%", |
|||
isRising: true, |
|||
}, |
|||
{ |
|||
stockName: "Telecommunication", |
|||
stockCode: "888607", |
|||
price: 1349.47, |
|||
change: "+1.67%", |
|||
isRising: true, |
|||
}, |
|||
{ |
|||
stockName: "Other", |
|||
stockCode: "888611", |
|||
price: 1009.98, |
|||
change: "-1.67%", |
|||
isRising: false, |
|||
}, |
|||
{ |
|||
stockName: "Consumer Discretio...", |
|||
stockCode: "888610", |
|||
price: 1009.98, |
|||
change: "-0.67%", |
|||
isRising: false, |
|||
}, |
|||
{ |
|||
stockName: "Telecommunication", |
|||
stockCode: "888607", |
|||
price: 1009.98, |
|||
change: "-0.67%", |
|||
isRising: false, |
|||
}, |
|||
{ |
|||
stockName: "Other", |
|||
stockCode: "888611", |
|||
price: 1009.98, |
|||
change: "-1.67%", |
|||
isRising: false, |
|||
}, |
|||
{ |
|||
stockName: "Consumer Discretio...", |
|||
stockCode: "888610", |
|||
price: 1009.98, |
|||
change: "-4.67%", |
|||
isRising: false, |
|||
}, |
|||
{ |
|||
stockName: "Consumer Discretio...", |
|||
stockCode: "888610", |
|||
price: 1009.98, |
|||
change: "-3.67%", |
|||
isRising: false, |
|||
}, |
|||
{ |
|||
stockName: "Consumer Discretio...", |
|||
stockCode: "888610", |
|||
price: 1009.98, |
|||
change: "-3.67%", |
|||
isRising: false, |
|||
}, |
|||
]); |
|||
|
|||
// 计算属性 |
|||
const contentTopPosition = computed(() => { |
|||
return iSMT.value + headerHeight.value; |
|||
}); |
|||
|
|||
const sortedStockList = computed(() => { |
|||
console.log("计算sortedStockList,原始数据长度:", stockList.value.length); |
|||
let list = [...stockList.value]; |
|||
|
|||
if (sortType.value === "price") { |
|||
list.sort((a, b) => { |
|||
return sortOrder.value === "asc" ? a.price - b.price : b.price - a.price; |
|||
}); |
|||
} else if (sortType.value === "change") { |
|||
list.sort((a, b) => { |
|||
const aChange = parseFloat(a.change.replace(/[+%-]/g, "")); |
|||
const bChange = parseFloat(b.change.replace(/[+%-]/g, "")); |
|||
return sortOrder.value === "asc" ? aChange - bChange : bChange - aChange; |
|||
}); |
|||
} |
|||
|
|||
console.log("排序后数据长度:", list.length); |
|||
return list; |
|||
}); |
|||
|
|||
// 页面加载时接收参数 |
|||
onLoad((options) => { |
|||
if (options && options.market) { |
|||
marketType.value = options.market; |
|||
switch (options.market) { |
|||
case "america": |
|||
marketTitle.value = "美洲"; |
|||
break; |
|||
case "asia": |
|||
marketTitle.value = "亚太"; |
|||
break; |
|||
case "asia-china": |
|||
marketTitle.value = "亚太-中华"; |
|||
break; |
|||
default: |
|||
marketTitle.value = "全球指数"; |
|||
} |
|||
} |
|||
}); |
|||
|
|||
// 方法 |
|||
const goBack = () => { |
|||
uni.navigateBack(); |
|||
}; |
|||
|
|||
const sortByPrice = () => { |
|||
if (sortType.value === "price") { |
|||
sortOrder.value = sortOrder.value === "asc" ? "desc" : "asc"; |
|||
} else { |
|||
sortType.value = "price"; |
|||
sortOrder.value = "desc"; |
|||
} |
|||
}; |
|||
|
|||
const sortByChange = () => { |
|||
if (sortType.value === "change") { |
|||
sortOrder.value = sortOrder.value === "asc" ? "desc" : "asc"; |
|||
} else { |
|||
sortType.value = "change"; |
|||
sortOrder.value = "desc"; |
|||
} |
|||
}; |
|||
|
|||
const viewStockDetail = (stock) => { |
|||
console.log("查看股票详情:", stock); |
|||
// 这里可以跳转到股票详情页面 |
|||
uni.navigateTo({ |
|||
url: `/pages/home/marketCondition?stockInformation=${encodeURIComponent(JSON.stringify(stock))}`, |
|||
}); |
|||
}; |
|||
|
|||
onMounted(() => { |
|||
// 获取状态栏高度 |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
// 动态计算header实际高度 |
|||
uni |
|||
.createSelectorQuery() |
|||
.select(".header_fixed") |
|||
.boundingClientRect((rect) => { |
|||
if (rect) { |
|||
headerHeight.value = rect.height; |
|||
console.log("Header实际高度:", headerHeight.value, "px"); |
|||
} |
|||
}) |
|||
.exec(); |
|||
}); |
|||
|
|||
// 监听headerHeight变化,重新计算contentHeight |
|||
watch(headerHeight, (newHeight) => { |
|||
if (newHeight > 0) { |
|||
const systemInfo = uni.getSystemInfoSync(); |
|||
const windowHeight = systemInfo.windowHeight; |
|||
const statusBarHeight = systemInfo.statusBarHeight || 0; |
|||
const footerHeight = 100; |
|||
|
|||
contentHeight.value = windowHeight - statusBarHeight - newHeight - footerHeight; |
|||
console.log("重新计算contentHeight:", contentHeight.value); |
|||
} |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.main { |
|||
width: 100%; |
|||
height: 100vh; |
|||
background-color: #f5f5f5; |
|||
position: relative; |
|||
} |
|||
|
|||
/* 自定义导航栏 */ |
|||
.header_fixed { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
z-index: 1000; |
|||
background-color: #ffffff; |
|||
border-bottom: 1px solid #f0f0f0; |
|||
} |
|||
|
|||
.header-content { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
height: 44px; |
|||
padding: 0 15px; |
|||
} |
|||
|
|||
.header-left, |
|||
.header-right { |
|||
width: 60px; |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
.header-left { |
|||
justify-content: flex-start; |
|||
} |
|||
|
|||
.header-right { |
|||
justify-content: flex-end; |
|||
gap: 10px; |
|||
} |
|||
|
|||
.back-text { |
|||
font-size: 24px; |
|||
color: #333333; |
|||
font-weight: 500; |
|||
line-height: 1; |
|||
} |
|||
|
|||
.header-center { |
|||
flex: 1; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.header-title { |
|||
font-size: 18px; |
|||
font-weight: 600; |
|||
color: #333333; |
|||
} |
|||
|
|||
.header-icon { |
|||
width: 20px; |
|||
height: 20px; |
|||
} |
|||
|
|||
.more-text { |
|||
font-size: 20px; |
|||
color: #666666; |
|||
font-weight: bold; |
|||
} |
|||
|
|||
/* 内容区域 */ |
|||
.content { |
|||
position: fixed; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
background-color: #ffffff; |
|||
} |
|||
|
|||
/* 表头样式 */ |
|||
.table-header { |
|||
display: flex; |
|||
padding: 12px 15px; |
|||
background-color: #f8f9fa; |
|||
border-bottom: 1px solid #e9ecef; |
|||
} |
|||
|
|||
.header-item { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.header-item.name-column { |
|||
flex: 2; |
|||
justify-content: flex-start; |
|||
} |
|||
|
|||
.header-item.price-column, |
|||
.header-item.change-column { |
|||
flex: 1; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.header-text { |
|||
font-size: 14px; |
|||
color: #666666; |
|||
font-weight: 500; |
|||
} |
|||
|
|||
.sort-icon { |
|||
margin-left: 4px; |
|||
font-size: 12px; |
|||
color: #999999; |
|||
} |
|||
|
|||
/* 股票列表 */ |
|||
.stock-list { |
|||
background-color: #ffffff; |
|||
} |
|||
|
|||
.stock-row { |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 12px 15px; |
|||
border-bottom: 1px solid #f5f5f5; |
|||
} |
|||
|
|||
.stock-row:active { |
|||
background-color: #f8f8f8; |
|||
} |
|||
|
|||
.stock-cell { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
} |
|||
|
|||
.stock-cell.name-column { |
|||
flex: 2; |
|||
align-items: flex-start; |
|||
} |
|||
|
|||
.stock-cell.price-column, |
|||
.stock-cell.change-column { |
|||
flex: 1; |
|||
align-items: center; |
|||
} |
|||
|
|||
.stock-name { |
|||
font-size: 15px; |
|||
color: #333333; |
|||
font-weight: 500; |
|||
line-height: 1.2; |
|||
margin-bottom: 2px; |
|||
} |
|||
|
|||
.stock-code { |
|||
font-size: 11px; |
|||
color: #999999; |
|||
line-height: 1.2; |
|||
} |
|||
|
|||
.stock-price { |
|||
font-size: 15px; |
|||
font-weight: 600; |
|||
line-height: 1.2; |
|||
} |
|||
|
|||
.stock-change { |
|||
font-size: 13px; |
|||
font-weight: 500; |
|||
line-height: 1.2; |
|||
} |
|||
|
|||
.rising { |
|||
color: #00c851; |
|||
} |
|||
|
|||
.falling { |
|||
color: #ff4444; |
|||
} |
|||
|
|||
/* 底部安全区域 */ |
|||
/* .bottom-safe-area { |
|||
height: 20px; |
|||
} */ |
|||
|
|||
/* 底部导航栏 */ |
|||
/* .static-footer { |
|||
position: fixed; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
z-index: 1000; |
|||
} */ |
|||
</style> |
|||
@ -1,28 +1,920 @@ |
|||
<!-- @format --> |
|||
|
|||
<template> |
|||
<view class="main"> |
|||
<!-- 顶部状态栏占位 --> |
|||
<view class="top" :style="{height:iSMT+'px'}"></view> |
|||
<view>行情</view> |
|||
<footerBar class="static-footer" :type="type"></footerBar> |
|||
</view> |
|||
<view class="main"> |
|||
<!-- 固定头部 --> |
|||
<view class="header_fixed" :style="{ top: iSMT + 'px' }"> |
|||
<view class="header_content"> |
|||
<view class="header_input_wrapper"> |
|||
<image class="search_icon" src="/static/marketSituation-image/search.png" mode="" @click="onSearchClick"></image> |
|||
<input class="header_input" type="text" placeholder="搜索" placeholder-style="color: #A6A6A6; font-size: 22rpx;" v-model="searchValue" @input="onSearchInput" @confirm="onSearchConfirm" /> |
|||
</view> |
|||
<view class="header_icons"> |
|||
<view class="header_icon" @click="selected"> |
|||
<image src="/static/marketSituation-image/mySeclected.png" mode=""></image> |
|||
</view> |
|||
<view class="header_icon" @click="history"> |
|||
<image src="/static/marketSituation-image/history.png" mode=""></image> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view class="channel_li" v-if="channelData.length > 0"> |
|||
<scroll-view class="channel_wrap" scroll-x="true" :scroll-into-view="scrollToView" :scroll-with-animation="true" show-scrollbar="false"> |
|||
<view class="channel_innerWrap"> |
|||
<view v-for="(item, index) in channelData" :key="item.id" :id="'nav' + item.id" :class="['channel_item', index === pageIndex ? 'active' : '']" @click="navClick(index)"> |
|||
<text class="channel_text">{{ item.title }}</text> |
|||
<view v-if="index === pageIndex" class="active_indicator"></view> |
|||
</view> |
|||
</view> |
|||
</scroll-view> |
|||
<view class="scroll_indicator" @click="channel_more"> |
|||
<image src="/static/marketSituation-image/menu.png" mode="aspectFit"></image> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 可滚动内容区域 --> |
|||
<scroll-view class="content_scroll" scroll-y="true" :style="{ top: contentTopPosition + 'px' }"> |
|||
<view class="content"> |
|||
<view class="map"> |
|||
<image src="/static/marketSituation-image/map.png" mode="widthFix"></image> |
|||
</view> |
|||
<view class="global_index"> |
|||
<view class="global_index_title"> |
|||
{{ $t("marketSituation.globalIndex") }} |
|||
</view> |
|||
<view class="global_index_more" @click="goToGlobalIndex"> |
|||
<text>{{ $t("marketSituation.globalIndexMore") }}</text> |
|||
<image src="/static/marketSituation-image/more.png" mode="aspectFit"></image> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 卡片网格 --> |
|||
<view class="cards_grid"> |
|||
<view v-for="(card, index) in cardData" :key="index" class="card_item"> |
|||
<IndexCard :flagIcon="card.flagIcon" :stockName="card.stockName" :currentPrice="card.currentPrice" :changeAmount="card.changeAmount" :changePercent="card.changePercent" :isRising="card.isRising" @click="viewIndexDetail(card)" /> |
|||
</view> |
|||
</view> |
|||
<view class="warn"> |
|||
<image src="/static/marketSituation-image/warn.png" mode="aspectFit"></image> |
|||
<view class="warn_text_container"> |
|||
<text :class="warnTextClass">{{ $t("marketSituation.warn") }}</text> |
|||
</view> |
|||
</view> |
|||
<!-- 底部安全区域,防止被导航栏遮挡 --> |
|||
<view class="bottom_safe_area"></view> |
|||
</view> |
|||
</scroll-view> |
|||
</view> |
|||
|
|||
<footerBar class="static-footer" :type="type"></footerBar> |
|||
|
|||
<!-- 更多tab弹窗 --> |
|||
<view v-if="showCountryModal" class="modal_overlay" @click="closeModal"> |
|||
<view class="modal_content" @click.stop> |
|||
<view class="modal_header"> |
|||
<text class="modal_title">全部栏目</text> |
|||
<view class="modal_close" @click="closeModal"> |
|||
<text>×</text> |
|||
</view> |
|||
</view> |
|||
<view class="modal_body"> |
|||
<view class="country_grid"> |
|||
<view v-for="(country, index) in countryList" :key="index" :class="['country_item', selectedCountry === country ? 'selected' : '']" @click="selectCountry(country)"> |
|||
<text class="country_text">{{ country }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref,onMounted } from 'vue' |
|||
import footerBar from '../../components/footerBar.vue' |
|||
import { ref, onMounted, watch, nextTick, computed } from "vue"; |
|||
import util from "../../common/util.js"; |
|||
import footerBar from "../../components/footerBar.vue"; |
|||
import IndexCard from "../../components/IndexCard.vue"; |
|||
|
|||
const type = ref("marketSituation"); |
|||
const iSMT = ref(0); |
|||
const searchValue = ref(""); |
|||
const contentHeight = ref(0); |
|||
const headerHeight = ref(0); // 动态计算的header高度 |
|||
const isWarnTextOverflow = ref(false); // warn文字是否溢出 |
|||
|
|||
// Tab 栏相关数据 |
|||
const channelData = ref([ |
|||
{ id: 1, title: "概况" }, |
|||
{ id: 2, title: "新加坡" }, |
|||
{ id: 3, title: "马来西亚" }, |
|||
{ id: 4, title: "印度尼西亚" }, |
|||
{ id: 5, title: "美国" }, |
|||
{ id: 6, title: "中国香港" }, |
|||
{ id: 7, title: "泰国" }, |
|||
{ id: 8, title: "中国" }, |
|||
{ id: 9, title: "加拿大" }, |
|||
{ id: 10, title: "越南" }, |
|||
{ id: 11, title: "外汇" }, |
|||
{ id: 12, title: "贵金属" }, |
|||
]); |
|||
const pageIndex = ref(0); |
|||
const scrollToView = ref(""); |
|||
|
|||
// 计算属性:精准计算content区域的top值 |
|||
const contentTopPosition = computed(() => { |
|||
const statusBarHeight = iSMT.value || 0; |
|||
const currentHeaderHeight = headerHeight.value > 0 ? headerHeight.value : 140; |
|||
return statusBarHeight + currentHeaderHeight; |
|||
}); |
|||
|
|||
// warn文字的class计算属性 |
|||
const warnTextClass = computed(() => { |
|||
return isWarnTextOverflow.value ? "warn_text scroll-active" : "warn_text"; |
|||
}); |
|||
|
|||
// 弹窗相关数据 |
|||
const showCountryModal = ref(false); |
|||
const selectedCountry = ref("概况"); |
|||
const countryList = ref(["概况", "新加坡", "马来西亚", "印度尼西亚", "美国", "中国香港", "泰国", "中国", "加拿大", "越南", "外汇", "贵金属"]); |
|||
|
|||
// 卡片数据 |
|||
const cardData = ref([ |
|||
{ |
|||
flagIcon: "🇺🇸", |
|||
stockName: "道琼斯", |
|||
stockCode: "DJIA", |
|||
currentPrice: "45757.90", |
|||
changeAmount: "-125.22", |
|||
changePercent: "-0.27%", |
|||
isRising: false, |
|||
}, |
|||
{ |
|||
flagIcon: "🇺🇸", |
|||
stockName: "纳斯达克", |
|||
stockCode: "NDX", |
|||
currentPrice: "22333.96", |
|||
changeAmount: "+125.22", |
|||
changePercent: "+0.47%", |
|||
isRising: true, |
|||
}, |
|||
{ |
|||
flagIcon: "🇺🇸", |
|||
stockName: "标普500", |
|||
stockCode: "SPX", |
|||
currentPrice: "6606.08", |
|||
changeAmount: "+125.22", |
|||
changePercent: "+0.27%", |
|||
isRising: true, |
|||
}, |
|||
{ |
|||
flagIcon: "🇨🇳", |
|||
stockName: "上证指数", |
|||
stockCode: "1A0001", |
|||
currentPrice: "3333.96", |
|||
changeAmount: "+125.22", |
|||
changePercent: "+0.27%", |
|||
isRising: true, |
|||
}, |
|||
{ |
|||
flagIcon: "🇨🇳", |
|||
stockName: "科创50", |
|||
stockCode: "1B0688", |
|||
currentPrice: "757.90", |
|||
changeAmount: "-25.22", |
|||
changePercent: "-0.27%", |
|||
isRising: false, |
|||
}, |
|||
{ |
|||
flagIcon: "🇭🇰", |
|||
stockName: "恒生指数", |
|||
stockCode: "HSI", |
|||
currentPrice: "19757.90", |
|||
changeAmount: "-125.22", |
|||
changePercent: "-0.63%", |
|||
isRising: false, |
|||
}, |
|||
{ |
|||
flagIcon: "🇸🇬", |
|||
stockName: "道琼斯", |
|||
stockCode: "DJIA", |
|||
currentPrice: "3757.90", |
|||
changeAmount: "+85.22", |
|||
changePercent: "+2.31%", |
|||
isRising: true, |
|||
}, |
|||
{ |
|||
flagIcon: "🇲🇾", |
|||
stockName: "纳斯达克", |
|||
stockCode: "NDX", |
|||
currentPrice: "1657.90", |
|||
changeAmount: "-15.22", |
|||
changePercent: "-0.91%", |
|||
isRising: false, |
|||
}, |
|||
{ |
|||
flagIcon: "🇹🇭", |
|||
stockName: "标普500", |
|||
stockCode: "SPX", |
|||
currentPrice: "1457.90", |
|||
changeAmount: "+35.22", |
|||
changePercent: "+2.48%", |
|||
isRising: true, |
|||
}, |
|||
]); |
|||
|
|||
// 搜索输入事件 |
|||
const onSearchInput = (e) => { |
|||
searchValue.value = e.detail.value; |
|||
}; |
|||
|
|||
// 搜索确认事件 |
|||
const onSearchConfirm = (e) => { |
|||
console.log("搜索内容:", e.detail.value); |
|||
// 这里可以添加搜索逻辑 |
|||
performSearch(e.detail.value); |
|||
}; |
|||
|
|||
// 搜索图标点击事件 |
|||
const onSearchClick = () => { |
|||
if (searchValue.value.trim()) { |
|||
performSearch(searchValue.value); |
|||
} |
|||
}; |
|||
|
|||
// 执行搜索 |
|||
const performSearch = (keyword) => { |
|||
if (!keyword.trim()) { |
|||
uni.showToast({ |
|||
title: "请输入搜索内容", |
|||
icon: "none", |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
uni.showToast({ |
|||
title: `搜索: ${keyword}`, |
|||
icon: "none", |
|||
}); |
|||
// 这里添加实际的搜索逻辑 |
|||
}; |
|||
|
|||
// 我的收藏点击事件 |
|||
const selected = () => { |
|||
uni.showToast({ |
|||
title: "我的收藏", |
|||
icon: "none", |
|||
}); |
|||
// 这里可以跳转到收藏页面 |
|||
}; |
|||
|
|||
// 历史记录点击事件 |
|||
const history = () => { |
|||
uni.showToast({ |
|||
title: "历史记录", |
|||
icon: "none", |
|||
}); |
|||
// 这里可以跳转到历史页面 |
|||
}; |
|||
|
|||
// Tab 栏点击事件 |
|||
const navClick = (index) => { |
|||
pageIndex.value = index; |
|||
const currentItem = channelData.value[index]; |
|||
scrollToView.value = "nav" + currentItem.id; |
|||
|
|||
// 同步更新弹窗中的选中状态 |
|||
selectedCountry.value = currentItem.title; |
|||
|
|||
const type = ref('marketSituation') |
|||
const iSMT = ref(0) |
|||
uni.showToast({ |
|||
title: `切换到: ${currentItem.title}`, |
|||
icon: "none", |
|||
}); |
|||
|
|||
// 这里可以添加切换 tab 后的数据加载逻辑 |
|||
console.log("当前选中的 tab:", currentItem); |
|||
}; |
|||
|
|||
// 更多选项点击事件 |
|||
const channel_more = () => { |
|||
showCountryModal.value = true; |
|||
}; |
|||
|
|||
// 选择国家 |
|||
const selectCountry = (country) => { |
|||
selectedCountry.value = country; |
|||
|
|||
// 查找对应的tab索引 |
|||
const targetIndex = channelData.value.findIndex((item) => item.title === country); |
|||
|
|||
if (targetIndex !== -1) { |
|||
// 同步更新页面tab |
|||
pageIndex.value = targetIndex; |
|||
const currentItem = channelData.value[targetIndex]; |
|||
scrollToView.value = "nav" + currentItem.id; |
|||
|
|||
console.log("选中了:" + country + ",同步到tab索引:" + targetIndex); |
|||
uni.showToast({ |
|||
title: "已切换到:" + country, |
|||
icon: "none", |
|||
duration: 2000, |
|||
}); |
|||
} else { |
|||
// 如果是"概况"或其他特殊选项,默认切换到第一个tab |
|||
if (country === "概况" || country === "全部") { |
|||
pageIndex.value = 0; |
|||
scrollToView.value = "nav" + channelData.value[0].id; |
|||
} |
|||
|
|||
console.log("选中了:" + country); |
|||
uni.showToast({ |
|||
title: "已选择:" + country, |
|||
icon: "none", |
|||
duration: 2000, |
|||
}); |
|||
} |
|||
|
|||
// 这里可以添加切换到对应国家/地区数据的逻辑 |
|||
// 例如:loadMarketData(country) |
|||
closeModal(); |
|||
}; |
|||
|
|||
// 关闭弹窗 |
|||
const closeModal = () => { |
|||
showCountryModal.value = false; |
|||
}; |
|||
|
|||
// 检测warn文字是否溢出 |
|||
const checkWarnTextOverflow = () => { |
|||
nextTick(() => { |
|||
setTimeout(() => { |
|||
const query = uni.createSelectorQuery(); |
|||
|
|||
// 同时查询容器和文字元素 |
|||
query.select(".warn_text_container").boundingClientRect(); |
|||
query.select(".warn_text").boundingClientRect(); |
|||
query.exec((res) => { |
|||
const containerRect = res[0]; |
|||
const textRect = res[1]; |
|||
|
|||
if (!containerRect || !textRect) { |
|||
return; |
|||
} |
|||
|
|||
// 判断文字是否超出容器(留一些余量) |
|||
const isOverflow = textRect.width > containerRect.width - 10; |
|||
|
|||
isWarnTextOverflow.value = isOverflow; |
|||
}); |
|||
}, 500); |
|||
}); |
|||
}; |
|||
|
|||
// 跳转到全球指数页面 |
|||
const goToGlobalIndex = () => { |
|||
uni.navigateTo({ |
|||
url: "/pages/home/globalIndex", |
|||
}); |
|||
}; |
|||
|
|||
// 方法:查看指数详情 |
|||
const viewIndexDetail = (item) => { |
|||
console.log("查看指数详情:", item.stockName); |
|||
// uni.showToast({ |
|||
// title: `查看 ${item.stockName} 详情`, |
|||
// icon: 'none', |
|||
// duration: 2000 |
|||
// }) |
|||
// 这里可以跳转到具体的指数详情页面 |
|||
uni.navigateTo({ |
|||
url: `/pages/home/marketCondition?stockInformation=${encodeURIComponent(JSON.stringify(item))}`, |
|||
}); |
|||
}; |
|||
|
|||
onMounted(() => { |
|||
// 状态栏高度 |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
}) |
|||
// 状态栏高度 |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
|
|||
// 初始化 tab 栏 |
|||
if (channelData.value.length > 0) { |
|||
pageIndex.value = 0; |
|||
scrollToView.value = "nav" + channelData.value[0].id; |
|||
} |
|||
|
|||
util.request( |
|||
"link/api/brain/privilege", |
|||
(res) => { |
|||
console.log(res); |
|||
}, |
|||
{ |
|||
token: "9ior41AF0xTIbIG2pRnnbZi0+fEeMx8pywnIlrmTwo5FbqJ9lWrSWOxp9MkpKiNtedtUafqvzIwpFKrwuMs", |
|||
}, |
|||
(err) => { |
|||
console.log(err); |
|||
} |
|||
); |
|||
|
|||
// 确保DOM渲染完成后再查询高度 |
|||
nextTick(() => { |
|||
// 动态计算header实际高度 |
|||
uni |
|||
.createSelectorQuery() |
|||
.select(".header_fixed") |
|||
.boundingClientRect((rect) => { |
|||
if (rect) { |
|||
headerHeight.value = rect.height; |
|||
console.log("Header实际高度:", headerHeight.value, "px"); |
|||
} |
|||
}) |
|||
.exec(); |
|||
|
|||
// 检测warn文字是否溢出 |
|||
checkWarnTextOverflow(); |
|||
}); |
|||
}); |
|||
|
|||
// 监听headerHeight变化,重新计算contentHeight |
|||
watch(headerHeight, (newHeight) => { |
|||
if (newHeight > 0) { |
|||
const systemInfo = uni.getSystemInfoSync(); |
|||
const windowHeight = systemInfo.windowHeight; |
|||
const statusBarHeight = systemInfo.statusBarHeight || 0; |
|||
const footerHeight = 100; |
|||
|
|||
contentHeight.value = windowHeight - statusBarHeight - newHeight - footerHeight; |
|||
console.log("重新计算contentHeight:", contentHeight.value); |
|||
} |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped> |
|||
/* 状态栏占位 */ |
|||
.top { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
z-index: 1001; |
|||
background-color: #ffffff; |
|||
} |
|||
|
|||
/* 固定头部样式 */ |
|||
.header_fixed { |
|||
position: fixed; |
|||
left: 0; |
|||
right: 0; |
|||
z-index: 1000; |
|||
background-color: #ffffff; |
|||
padding: 20rpx 0 0 0; |
|||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1); |
|||
} |
|||
|
|||
/* 可滚动内容区域 */ |
|||
.content_scroll { |
|||
position: fixed; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: 100rpx; |
|||
/* 底部导航栏高度 */ |
|||
overflow-y: auto; |
|||
} |
|||
|
|||
.header_content { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
height: 80rpx; |
|||
padding: 0 20rpx; |
|||
margin-bottom: 10rpx; |
|||
} |
|||
|
|||
.header_input_wrapper { |
|||
display: flex; |
|||
align-items: center; |
|||
width: 100%; |
|||
margin: 0 20rpx 0 0; |
|||
height: 70rpx; |
|||
border-radius: 35rpx; |
|||
background-color: #ffffff; |
|||
border: 1rpx solid #e9ecef; |
|||
padding: 0 80rpx 0 30rpx; |
|||
font-size: 28rpx; |
|||
color: #5c5c5c; |
|||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1); |
|||
} |
|||
|
|||
.search_icon { |
|||
width: 40rpx; |
|||
height: 40rpx; |
|||
opacity: 0.6; |
|||
} |
|||
|
|||
.header_input { |
|||
margin-left: 10rpx; |
|||
} |
|||
|
|||
.header_icons { |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 15rpx; |
|||
} |
|||
|
|||
.header_icon { |
|||
width: 40rpx; |
|||
height: 40rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.header_icon image { |
|||
width: 40rpx; |
|||
height: 40rpx; |
|||
} |
|||
|
|||
/* Tab 栏样式 */ |
|||
.channel_li { |
|||
display: flex; |
|||
align-items: center; |
|||
height: 80rpx; |
|||
background-color: #ffffff; |
|||
border-bottom: 1rpx solid #f0f0f0; |
|||
} |
|||
|
|||
.channel_wrap { |
|||
width: calc(100% - 60rpx); |
|||
height: 100%; |
|||
overflow: hidden; |
|||
flex-shrink: 0; |
|||
} |
|||
|
|||
.channel_innerWrap { |
|||
display: flex; |
|||
align-items: center; |
|||
height: 100%; |
|||
padding: 0 20rpx; |
|||
white-space: nowrap; |
|||
} |
|||
|
|||
.channel_item { |
|||
position: relative; |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
height: 60rpx; |
|||
padding: 0 20rpx; |
|||
border-radius: 30rpx; |
|||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); |
|||
cursor: pointer; |
|||
white-space: nowrap; |
|||
flex-shrink: 0; |
|||
} |
|||
|
|||
.channel_item:active { |
|||
transform: scale(0.98); |
|||
} |
|||
|
|||
.channel_item.active { |
|||
color: #333; |
|||
font-weight: bold; |
|||
} |
|||
|
|||
.channel_text { |
|||
font-size: 28rpx; |
|||
font-weight: 500; |
|||
color: #666666; |
|||
transition: color 0.3s ease; |
|||
white-space: nowrap; |
|||
} |
|||
|
|||
.channel_item.active .channel_text { |
|||
color: #333333; |
|||
font-weight: 400; |
|||
z-index: 2; |
|||
} |
|||
|
|||
.active_indicator { |
|||
position: absolute; |
|||
left: 50%; |
|||
top: 60%; |
|||
transform: translateX(-45%); |
|||
width: calc(100% - 20rpx); |
|||
min-width: 40rpx; |
|||
max-width: 120rpx; |
|||
height: 8rpx; |
|||
background-image: url("/static/marketSituation-image/bg.png"); |
|||
background-size: cover; |
|||
background-position: center; |
|||
background-repeat: no-repeat; |
|||
animation: slideIn 0.1s ease; |
|||
border-radius: 8rpx; |
|||
z-index: 1; |
|||
} |
|||
|
|||
@keyframes slideIn { |
|||
from { |
|||
width: 0; |
|||
opacity: 0; |
|||
} |
|||
|
|||
to { |
|||
width: 40rpx; |
|||
opacity: 1; |
|||
} |
|||
} |
|||
|
|||
.scroll_indicator { |
|||
border-left: 1rpx solid #b6b6b6; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
width: 60rpx; |
|||
height: 30rpx; |
|||
background-color: #ffffff; |
|||
flex-shrink: 0; |
|||
} |
|||
|
|||
.scroll_indicator image { |
|||
width: 20rpx; |
|||
height: 20rpx; |
|||
opacity: 0.5; |
|||
} |
|||
|
|||
.content { |
|||
margin-top: 20rpx; |
|||
background-color: white; |
|||
} |
|||
|
|||
.map { |
|||
width: calc(100% - 60rpx); |
|||
margin: 0 30rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
background-color: #f3f3f3; |
|||
border-radius: 30rpx; |
|||
border: 1rpx solid #e0e0e0; |
|||
padding: 30rpx 20rpx; |
|||
box-sizing: border-box; |
|||
/* 设置最小高度保护,但允许内容撑开 */ |
|||
min-height: 200rpx; |
|||
} |
|||
|
|||
.map image { |
|||
width: 100%; |
|||
height: auto; |
|||
max-width: 100%; |
|||
display: block; |
|||
/* widthFix模式下,高度会自动按比例调整 */ |
|||
/* 设置最大高度避免图片过大 */ |
|||
max-height: 60vh; |
|||
/* 添加平滑过渡效果 */ |
|||
transition: all 0.3s ease; |
|||
max-height: 60vh; |
|||
} |
|||
|
|||
/* 响应式优化 */ |
|||
@media screen and (max-width: 750rpx) { |
|||
.map { |
|||
margin: 0 20rpx; |
|||
width: calc(100% - 40rpx); |
|||
padding: 20rpx 15rpx; |
|||
} |
|||
} |
|||
|
|||
@media screen and (max-width: 480rpx) { |
|||
.map { |
|||
margin: 0 15rpx; |
|||
width: calc(100% - 30rpx); |
|||
padding: 15rpx 10rpx; |
|||
} |
|||
} |
|||
|
|||
.static-footer { |
|||
position: fixed; |
|||
bottom: 0; |
|||
position: fixed; |
|||
bottom: 0; |
|||
} |
|||
|
|||
/* 弹窗样式 */ |
|||
.modal_overlay { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
background-color: rgba(0, 0, 0, 0.5); |
|||
display: flex; |
|||
align-items: flex-end; |
|||
z-index: 1000; |
|||
} |
|||
|
|||
.modal_content { |
|||
width: 100%; |
|||
background-color: #fff; |
|||
border-radius: 20rpx 20rpx 0 0; |
|||
max-height: 80vh; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.modal_header { |
|||
position: relative; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
padding: 30rpx 40rpx; |
|||
border-bottom: 1rpx solid #f0f0f0; |
|||
} |
|||
|
|||
.modal_title { |
|||
font-size: 32rpx; |
|||
font-weight: bold; |
|||
color: #333333; |
|||
text-align: center; |
|||
} |
|||
|
|||
.modal_close { |
|||
position: absolute; |
|||
right: 40rpx; |
|||
top: 50%; |
|||
transform: translateY(-50%); |
|||
width: 60rpx; |
|||
height: 60rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
font-size: 40rpx; |
|||
color: #999; |
|||
} |
|||
|
|||
.modal_body { |
|||
padding: 40rpx; |
|||
} |
|||
|
|||
.country_grid { |
|||
display: grid; |
|||
grid-template-columns: 1fr 1fr; |
|||
gap: 20rpx; |
|||
} |
|||
|
|||
.country_item { |
|||
padding: 24rpx 30rpx; |
|||
border-radius: 12rpx; |
|||
background-color: #f8f8f8; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
transition: all 0.3s ease; |
|||
} |
|||
|
|||
.country_item.selected { |
|||
background-color: #ff4444; |
|||
color: #fff; |
|||
} |
|||
|
|||
.country_text { |
|||
font-size: 28rpx; |
|||
color: #333; |
|||
} |
|||
|
|||
.country_item.selected .country_text { |
|||
color: #fff; |
|||
} |
|||
|
|||
.global_index { |
|||
margin: 30rpx 20rpx 0 20rpx; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
} |
|||
|
|||
.global_index_title { |
|||
margin-left: 20rpx; |
|||
font-size: 40rpx; |
|||
font-weight: 100; |
|||
color: #333333; |
|||
align-items: center; |
|||
} |
|||
|
|||
.global_index_more { |
|||
display: flex; |
|||
gap: 10rpx; |
|||
font-size: 28rpx; |
|||
color: #333333; |
|||
align-items: center; |
|||
} |
|||
|
|||
.global_index_more image { |
|||
width: 40rpx; |
|||
height: 40rpx; |
|||
align-items: center; |
|||
} |
|||
|
|||
/* 卡片网格样式 */ |
|||
.cards_grid { |
|||
display: grid; |
|||
grid-template-columns: repeat(3, 1fr); |
|||
margin: 0; |
|||
box-sizing: border-box; |
|||
width: 100%; |
|||
} |
|||
|
|||
.card_item { |
|||
width: 100%; |
|||
box-sizing: border-box; |
|||
min-width: 0; |
|||
/* 防止内容溢出 */ |
|||
} |
|||
|
|||
/* 响应式布局 - 小屏幕时改为两列 */ |
|||
@media (max-width: 600rpx) { |
|||
.cards_grid { |
|||
grid-template-columns: repeat(2, 1fr); |
|||
padding: 30rpx 20rpx; |
|||
} |
|||
} |
|||
|
|||
/* 超小屏幕时改为单列 */ |
|||
@media (max-width: 400rpx) { |
|||
.cards_grid { |
|||
grid-template-columns: 1fr; |
|||
padding: 30rpx 20rpx; |
|||
} |
|||
} |
|||
|
|||
.warn { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: flex-start; |
|||
gap: 10rpx; |
|||
font-size: 28rpx; |
|||
color: #666666; |
|||
padding: 20rpx; |
|||
max-width: 100%; |
|||
overflow: hidden; |
|||
position: relative; |
|||
} |
|||
|
|||
.warn image { |
|||
width: 40rpx; |
|||
height: 40rpx; |
|||
flex-shrink: 0; |
|||
/* 防止图片被压缩 */ |
|||
position: relative; |
|||
z-index: 2; |
|||
/* 确保图片在最上层 */ |
|||
} |
|||
|
|||
.warn_text_container { |
|||
flex: 1; |
|||
overflow: hidden; |
|||
position: relative; |
|||
min-width: 0; |
|||
/* 允许容器收缩 */ |
|||
} |
|||
|
|||
.warn_text { |
|||
display: block; |
|||
white-space: nowrap; |
|||
will-change: transform; |
|||
/* 优化动画性能 */ |
|||
} |
|||
|
|||
/* 文字滚动动画 */ |
|||
@keyframes scrollText { |
|||
0% { |
|||
transform: translateX(0); |
|||
} |
|||
|
|||
20% { |
|||
transform: translateX(0); |
|||
} |
|||
|
|||
80% { |
|||
transform: translateX(-85%); |
|||
} |
|||
|
|||
100% { |
|||
transform: translateX(-85%); |
|||
} |
|||
} |
|||
|
|||
/* 当文字超长时启用滚动动画 */ |
|||
.warn_text.scroll-active { |
|||
animation: scrollText 12s linear infinite; |
|||
animation-delay: 2s; |
|||
/* 延迟2秒开始滚动,让用户先看到开头 */ |
|||
} |
|||
|
|||
/* 底部安全区域 */ |
|||
.bottom_safe_area { |
|||
height: 40rpx; |
|||
background-color: transparent; |
|||
} |
|||
|
|||
/* 主容器样式调整 */ |
|||
.main { |
|||
position: relative; |
|||
height: 100vh; |
|||
overflow: hidden; |
|||
background-color: white; |
|||
} |
|||
</style> |
|||
</style> |
|||
@ -1,28 +1,294 @@ |
|||
<template> |
|||
<view class="main"> |
|||
<!-- 顶部状态栏占位 --> |
|||
<view class="top" :style="{height:iSMT+'px'}"></view> |
|||
<view>我的</view> |
|||
<view class="top"> |
|||
<view class="bell"> |
|||
<image class="image-bell" src="/static/my/bell.png"></image> |
|||
</view> |
|||
<view class="msg"> |
|||
<view class="msg-left"> |
|||
<view class="avatar"></view> |
|||
</view> |
|||
<view class="msg-center"> |
|||
<view style="display: flex;"> |
|||
<view class="userInfo">{{ username }}</view> |
|||
<image class="image-editName" src="/static/my/editName.png"></image> |
|||
</view> |
|||
<view class="userId">ID:{{ dccode }}</view> |
|||
</view> |
|||
<view class="msg-right"> |
|||
<image class="image-attendance" src="/static/my/Check-in.png" /> |
|||
<span style="font-size:10px;">签到</span> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="settings-buttons"> |
|||
<view class="setting-btn" @click="goToMarket"> |
|||
<image src="/static/my/MarketSettings.png" class="setting-icon" /> |
|||
<text>行情设置</text> |
|||
</view> |
|||
<view class="setting-btn" @click="goToGeneral"> |
|||
<image src="/static/my/Settings.png" class="setting-icon" /> |
|||
<text>通用设置</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="share" @click="goToShare"> |
|||
<image class="img-share" src="/static/my/share.png" mode="widthFix" /> |
|||
</view> |
|||
</view> |
|||
<view class="bottom"> |
|||
<view class="list-item" @click="goToAccount"> |
|||
<image src="/static/my/security.png" class="list-icon" /> |
|||
<text>账号与安全</text> |
|||
<uni-icons type="arrowright" size="16" class="arrow" /> |
|||
</view> |
|||
<view class="list-item"> |
|||
<image src="/static/my/connection.png" class="list-icon" /> |
|||
<text>联系我们</text> |
|||
<uni-icons type="arrowright" size="16" class="arrow" /> |
|||
</view> |
|||
<view class="list-item" @click="goToNewVersion"> |
|||
<image src="/static/my/update.png" class="list-icon" /> |
|||
<text>新版本更新</text> |
|||
<view class="update-tip">有新版本可更新 |
|||
<view class="circle"></view> |
|||
</view> |
|||
<uni-icons type="arrowright" size="16" class="arrow" /> |
|||
</view> |
|||
<view class="list-item"> |
|||
<image src="/static/my/opinion.png" class="list-icon" /> |
|||
<text>意见反馈</text> |
|||
<uni-icons type="arrowright" size="16" class="arrow" /> |
|||
</view> |
|||
<view class="list-item" @click="goToAbout"> |
|||
<image src="/static/my/about.png" class="list-icon" /> |
|||
<text>关于DeepChart</text> |
|||
<uni-icons type="arrowright" size="16" class="arrow" /> |
|||
</view> |
|||
</view> |
|||
<footerBar class="static-footer" :type="type"></footerBar> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref,onMounted } from 'vue' |
|||
import footerBar from '../../components/footerBar.vue' |
|||
import { |
|||
ref, |
|||
onMounted |
|||
} from 'vue' |
|||
import { |
|||
ArrowRight |
|||
} from '@element-plus/icons-vue' |
|||
import footerBar from '../../components/footerBar.vue' |
|||
|
|||
const type = ref('member') |
|||
const iSMT = ref(0) |
|||
const type = ref('member') |
|||
const iSMT = ref(0) |
|||
const username = ref('演示机EVA') |
|||
const dccode = ref('90047681') |
|||
const goToGeneral = () => { |
|||
uni.navigateTo({ |
|||
url: '/pages/setting/general' |
|||
}) |
|||
} |
|||
|
|||
const goToMarket = () => { |
|||
uni.navigateTo({ |
|||
url: '../setting/market' |
|||
}) |
|||
} |
|||
|
|||
const goToAccount = () => { |
|||
uni.navigateTo({ |
|||
url:'../setting/account' |
|||
}) |
|||
} |
|||
|
|||
const goToNewVersion = () =>{ |
|||
uni.navigateTo({ |
|||
url:'../setting/newVersion' |
|||
}) |
|||
} |
|||
|
|||
const goToAbout = () =>{ |
|||
uni.navigateTo({ |
|||
url:'../setting/about' |
|||
}) |
|||
} |
|||
|
|||
const goToShare = () =>{ |
|||
uni.navigateTo({ |
|||
url:'../setting/share' |
|||
}) |
|||
} |
|||
|
|||
onMounted(() => { |
|||
// 状态栏高度 |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
}) |
|||
onMounted(() => { |
|||
// 状态栏高度 |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight |
|||
console.log('??????????????', iSMT.value) |
|||
}) |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.static-footer { |
|||
position: fixed; |
|||
bottom: 0; |
|||
} |
|||
.static-footer { |
|||
position: fixed; |
|||
bottom: 0; |
|||
} |
|||
|
|||
.top { |
|||
height: 47vh; |
|||
background-color: white; |
|||
} |
|||
|
|||
.bell { |
|||
height: 9.6vh; |
|||
display: flex; |
|||
align-items: flex-end; |
|||
justify-content: flex-end; |
|||
padding-right: 50rpx; |
|||
} |
|||
|
|||
.image-bell { |
|||
width: 13px; |
|||
height: 16px; |
|||
} |
|||
|
|||
.msg { |
|||
height: 10.7vh; |
|||
display: flex; |
|||
margin-top: 3vh; |
|||
margin-bottom: 3vh; |
|||
} |
|||
|
|||
.msg-left { |
|||
width: 33.6vw; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
|
|||
.avatar { |
|||
width: 175rpx; |
|||
height: 175rpx; |
|||
border-radius: 50%; |
|||
background-color: black; |
|||
} |
|||
|
|||
.msg-center { |
|||
width: 51.7vw; |
|||
padding-left: 2.5vh; |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.userInfo { |
|||
font-size: 20px; |
|||
} |
|||
|
|||
.userId { |
|||
font-size: 14px; |
|||
margin-top: 1vh; |
|||
} |
|||
|
|||
.image-editName { |
|||
width: 40rpx; |
|||
height: 40rpx; |
|||
margin-left: 2vw; |
|||
} |
|||
|
|||
.msg-right { |
|||
width: 14.7vw; |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.image-attendance { |
|||
width: 43rpx; |
|||
height: 43rpx; |
|||
} |
|||
|
|||
.settings-buttons { |
|||
display: flex; |
|||
justify-content: space-around; |
|||
} |
|||
|
|||
.setting-btn { |
|||
width: 349rpx; |
|||
height: 135rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
background-color: rgb(243, 243, 243); |
|||
border-radius: 8%; |
|||
} |
|||
|
|||
.setting-icon { |
|||
width: 64.7rpx; |
|||
height: 64.7rpx; |
|||
margin-right: 25rpx; |
|||
} |
|||
|
|||
.setting-btn text { |
|||
font-size: 28rpx; |
|||
font-weight: bold; |
|||
color: #333; |
|||
} |
|||
|
|||
.share { |
|||
height: 12.6vh; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
|
|||
.img-share { |
|||
width: 720rpx; |
|||
height: 160rpx; |
|||
} |
|||
|
|||
.bottom { |
|||
height: 44.5vh; |
|||
margin-top: 1vh; |
|||
background-color: rgb(255, 255, 255); |
|||
} |
|||
|
|||
.list-item { |
|||
width: 670rpx; |
|||
height: 7vh; |
|||
display: flex; |
|||
align-items: center; |
|||
margin: 0rpx 40rpx; |
|||
border-bottom: 1rpx solid #eee; |
|||
} |
|||
|
|||
.list-item:last-child{ |
|||
border-bottom: none; |
|||
} |
|||
|
|||
.list-icon { |
|||
width: 42rpx; |
|||
height: 42rpx; |
|||
margin-right: 18rpx; |
|||
} |
|||
|
|||
.arrow { |
|||
margin-left: auto; |
|||
} |
|||
|
|||
.update-tip { |
|||
display: flex; |
|||
color: #999; |
|||
font-size: 24rpx; |
|||
align-items: center; |
|||
margin-left: 200rpx; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.circle { |
|||
width: 10rpx; |
|||
height: 10rpx; |
|||
border-radius: 50%; |
|||
background-color: red; |
|||
margin-left: 10rpx; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,22 @@ |
|||
<template> |
|||
<view> |
|||
早盘解析页面 |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
|
|||
} |
|||
}, |
|||
methods: { |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
|
|||
</style> |
|||
@ -0,0 +1,86 @@ |
|||
<template> |
|||
<view class="main"> |
|||
<view :style="{height:iSMT+'px'}"></view> |
|||
|
|||
<view style="height:1.5vh" /> |
|||
<view class="top"> |
|||
<img src="/static/my/aboutDC.png"></img> |
|||
</view> |
|||
|
|||
<view class="bottom"> |
|||
<view class="bottom-list" @click="goToIntroduce"> |
|||
<text class="label">产品介绍</text> |
|||
<uni-icons type="arrowright" size="16" /> |
|||
</view> |
|||
<view class="bottom-list"> |
|||
<text class="label">免责声明</text> |
|||
<uni-icons type="arrowright" size="16" /> |
|||
</view> |
|||
<view class="bottom-list"> |
|||
<text class="label">隐私政策</text> |
|||
<uni-icons type="arrowright" size="16" /> |
|||
</view> |
|||
<view class="bottom-list"> |
|||
<text class="label">服务协议</text> |
|||
<uni-icons type="arrowright" size="16" /> |
|||
</view> |
|||
<view class="bottom-list"> |
|||
<text class="label">鼓励一下</text> |
|||
<uni-icons type="arrowright" size="16" /> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { |
|||
ref, |
|||
onMounted |
|||
} from 'vue' |
|||
const iSMT = ref(0) |
|||
const goToIntroduce = () =>{ |
|||
uni.navigateTo({ |
|||
url: '../setting/introduce' |
|||
}) |
|||
} |
|||
|
|||
onMounted(() => { |
|||
// 状态栏高度 |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
console.log('看看高度', iSMT.value) |
|||
}) |
|||
</script> |
|||
|
|||
<style> |
|||
.top { |
|||
height: 23vh; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
background-color: white; |
|||
} |
|||
|
|||
.bottom { |
|||
height: 35vh; |
|||
background-color: white; |
|||
} |
|||
|
|||
.bottom-list { |
|||
width: 630rpx; |
|||
height: 7vh; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
margin: 0 40rpx; |
|||
padding: 0 10rpx; |
|||
border-bottom: 1rpx solid #eee; |
|||
} |
|||
|
|||
.bottom-list:last-child { |
|||
border-bottom: none; |
|||
} |
|||
|
|||
.label{ |
|||
flex:1; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,213 @@ |
|||
<template> |
|||
<view class="main"> |
|||
<view :style="{height:iSMT+'px'}"></view> |
|||
|
|||
<view style="height:1.5vh;"></view> |
|||
|
|||
<view class="setting-list"> |
|||
<view class="setting-item"> |
|||
<text class="item-label">头像</text> |
|||
<view class="item-right"> |
|||
<image src="/static/avatar.png" class="avatar" mode="aspectFill"></image> |
|||
<uni-icons type="arrowright" size="16" class="arrow"></uni-icons> |
|||
</view> |
|||
</view> |
|||
<view class="setting-item"> |
|||
<text class="item-label">昵称</text> |
|||
<view class="item-right"> |
|||
<text class="item-text">DeepChart</text> |
|||
<uni-icons type="arrowright" size="16" class="arrow"></uni-icons> |
|||
</view> |
|||
</view> |
|||
<view class="setting-item"> |
|||
<text class="item-label">ID</text> |
|||
<view class="item-right"> |
|||
<text class="item-text">{{ jwcode }}</text> |
|||
<uni-icons type="arrowright" size="16" class="arrow"></uni-icons> |
|||
</view> |
|||
</view> |
|||
<view class="setting-item"> |
|||
<text class="item-label">密码</text> |
|||
<view class="item-right"> |
|||
<text class="item-text">qwertyuiop</text> |
|||
<uni-icons type="eye" size="16" class="eye-icon"></uni-icons> |
|||
</view> |
|||
</view> |
|||
<view class="setting-item" @click="goToPassword"> |
|||
<text class="item-label">修改密码</text> |
|||
<uni-icons type="arrowright" size="16" class="arrow"></uni-icons> |
|||
</view> |
|||
<view class="setting-item"> |
|||
<text class="item-label">注销账号</text> |
|||
<uni-icons type="arrowright" size="16" class="arrow"></uni-icons> |
|||
</view> |
|||
<view class="setting-item" @click="goToBind"> |
|||
<text class="item-label">绑定账号</text> |
|||
<uni-icons type="arrowright" size="16" class="arrow"></uni-icons> |
|||
</view> |
|||
</view> |
|||
|
|||
<view style="height:1.5vh;"></view> |
|||
|
|||
<view class="logout" @click="showLogout = true"> |
|||
<text>退出登录</text> |
|||
</view> |
|||
|
|||
<view class="logout-confirm" v-if="showLogout"> |
|||
<view class="logoutDialog"> |
|||
<view class="tips">是否退出登录</view> |
|||
<view class="tips-button"> |
|||
<button class="confirm-btn" @click="handleConfirmLogout">确认</button> |
|||
<button class="cancel-btn" @click="showLogout = false">取消</button> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
</template> |
|||
|
|||
<script setup> |
|||
import { |
|||
ref, |
|||
onMounted |
|||
} from 'vue' |
|||
const iSMT = ref(0) |
|||
const jwcode = ref('90047681') |
|||
const showLogout = ref(false) |
|||
|
|||
const handleConfirmLogout = () => { |
|||
showLogout.value = false |
|||
uni.showToast({ |
|||
title: '退出登录成功', |
|||
icon: 'none', |
|||
}) |
|||
} |
|||
|
|||
const goToBind = () =>{ |
|||
uni.navigateTo({ |
|||
url:'../setting/bind' |
|||
}) |
|||
} |
|||
|
|||
const goToPassword = () =>{ |
|||
uni.navigateTo({ |
|||
url:'../setting/password' |
|||
}) |
|||
} |
|||
|
|||
onMounted(() => { |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
}) |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.setting-list { |
|||
height: 49vh; |
|||
background-color: #fff; |
|||
} |
|||
|
|||
.setting-item { |
|||
display: flex; |
|||
align-items: center; |
|||
height: 7vh; |
|||
padding: 0 40rpx; |
|||
border-bottom: 1rpx solid #eee; |
|||
} |
|||
|
|||
.setting-item:last-child { |
|||
border-bottom: none; |
|||
} |
|||
|
|||
.item-label { |
|||
font-size: 28rpx; |
|||
flex: 1; |
|||
} |
|||
|
|||
.item-right { |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
.avatar { |
|||
width: 60rpx; |
|||
height: 60rpx; |
|||
border-radius: 50%; |
|||
margin-right: 20rpx; |
|||
background-color: #999; |
|||
} |
|||
|
|||
.item-text { |
|||
margin-right: 20rpx; |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
.arrow, |
|||
.eye-icon { |
|||
color: #999; |
|||
} |
|||
|
|||
.logout { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
height: 7vh; |
|||
font-size: 28rpx; |
|||
color: #f56c6c; |
|||
background-color: white; |
|||
} |
|||
|
|||
.logout-confirm { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
width: 100%; |
|||
height: 100%; |
|||
background-color: rgba(0, 0, 0, 0.5); |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
z-index: 999; |
|||
} |
|||
|
|||
.logoutDialog { |
|||
width: 500rpx; |
|||
background-color: #fff; |
|||
border-radius: 12rpx; |
|||
padding: 40rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
} |
|||
|
|||
.tips { |
|||
font-size: 32rpx; |
|||
margin-bottom: 40rpx; |
|||
} |
|||
|
|||
.tips-button { |
|||
display: flex; |
|||
width: 100%; |
|||
justify-content: space-between; |
|||
} |
|||
|
|||
.confirm-btn, |
|||
.cancel-btn { |
|||
width: 180rpx; |
|||
height: 60rpx; |
|||
line-height: 60rpx; |
|||
border-radius: 30rpx; |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
.confirm-btn { |
|||
background-color: #fff; |
|||
color: #000; |
|||
border: 1rpx solid #ddd; |
|||
} |
|||
|
|||
.cancel-btn { |
|||
background-color: #000; |
|||
color: #fff; |
|||
border: none; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,85 @@ |
|||
<template> |
|||
<view class="main"> |
|||
<view :style="{height:iSMT+'px'}"></view> |
|||
|
|||
<view style="height:1.5vh;" /> |
|||
|
|||
<view class="top"> |
|||
<view class="top-list" @click="goToBindPhone"> |
|||
<text class="label">手机号</text> |
|||
<view class="right"> |
|||
<text style="font-size: 28rpx;">未绑定</text> |
|||
<uni-icons type="arrowright" size="16" /> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="top-list" @click="goToBindEmail"> |
|||
<text class="label">邮箱</text> |
|||
<view class="right"> |
|||
<text style="font-size: 28rpx;">analsak@163.com</text> |
|||
<uni-icons type="arrowright" size="16" /> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { |
|||
ref, |
|||
onMounted |
|||
} from 'vue' |
|||
const iSMT = ref(0) |
|||
const goToBindPhone = () =>{ |
|||
uni.navigateTo({ |
|||
url:'../setting/phone' |
|||
}) |
|||
} |
|||
|
|||
const goToBindEmail = () =>{ |
|||
uni.navigateTo({ |
|||
url:'../setting/email' |
|||
}) |
|||
} |
|||
|
|||
onMounted(() => { |
|||
// 状态栏高度 |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
console.log('看看高度', iSMT.value) |
|||
}) |
|||
</script> |
|||
|
|||
<style> |
|||
.top { |
|||
height: 14vh; |
|||
background-color: white; |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.top-list { |
|||
width: 630rpx; |
|||
height: 7vh; |
|||
margin: 0rpx 40rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
border-bottom: 1rpx solid #eee; |
|||
} |
|||
|
|||
.top-list:last-child { |
|||
border: none; |
|||
} |
|||
|
|||
.label { |
|||
font-size: 28rpx; |
|||
flex: 1; |
|||
} |
|||
|
|||
.right{ |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,142 @@ |
|||
<template> |
|||
<view class="main"> |
|||
<view :style="{height:iSMT+'px'}"></view> |
|||
|
|||
<view style="height:1.5vh;" /> |
|||
|
|||
<view class="top"> |
|||
<view class="top-list"> |
|||
<view class="left"> |
|||
<img src="/static/my/bindedEmail.png" /> |
|||
<text class="label">已绑邮箱:{{ email }}</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="top-list"> |
|||
<view class="left"> |
|||
<img src="/static/my/changeEmail.png" /> |
|||
<text class="label">+86</text> |
|||
<input type="number" placeholder="请输入您的换绑邮箱" class="input" /> |
|||
</view> |
|||
<view class="right"> |
|||
<button class="verification" :class="{ 'disabled': gettingCode }" @click="getVerification" |
|||
:disabled="gettingCode"> |
|||
{{ gettingCode ? `重新发送 ${time}s` : '获取验证码' }} |
|||
</button> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="top-list"> |
|||
<view class="left"> |
|||
<img src="/static/my/verification.png" /> |
|||
<input type="text" placeholder="请输入验证码" class="input" /> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="bottom"> |
|||
<button class="change-btn">换绑</button> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { |
|||
ref, |
|||
onMounted |
|||
} from 'vue' |
|||
const iSMT = ref(0) |
|||
const email = ref('analsak@16.com') |
|||
const gettingCode = ref(false) |
|||
const time = ref(60) |
|||
|
|||
const getVerification = () => { |
|||
if (gettingCode.value) return |
|||
gettingCode.value = true |
|||
|
|||
time.value = 60 |
|||
const timer = setInterval(() => { |
|||
time.value-- |
|||
if (time.value <= 0) { |
|||
clearInterval(timer) |
|||
gettingCode.value = false |
|||
} |
|||
}, 1000) |
|||
} |
|||
|
|||
onMounted(() => { |
|||
// 状态栏高度 |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
console.log('看看高度', iSMT.value) |
|||
}) |
|||
</script> |
|||
|
|||
<style> |
|||
.top { |
|||
height: auto; |
|||
background-color: white; |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.top-list { |
|||
width: 630rpx; |
|||
height: 7vh; |
|||
margin: 0rpx 40rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
border-bottom: 1rpx solid #eee; |
|||
} |
|||
|
|||
.left { |
|||
flex: 1; |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
.label { |
|||
font-size: 28rpx; |
|||
margin-left: 10rpx; |
|||
} |
|||
|
|||
.right { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.input { |
|||
flex: 1; |
|||
height: 70rpx; |
|||
font-size: 29rpx; |
|||
margin-left: 20rpx; |
|||
} |
|||
|
|||
.verification { |
|||
font-size: 24rpx; |
|||
border-radius: 10rpx; |
|||
background-color: rgb(230, 230, 230); |
|||
} |
|||
|
|||
.bottom { |
|||
height: 22vh; |
|||
background-color: white; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.change-btn { |
|||
height: 85rpx; |
|||
width: 610rpx; |
|||
padding:0 20rpx; |
|||
background-color: black; |
|||
color: white; |
|||
border-radius: 40rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,68 @@ |
|||
<template> |
|||
<view class="main"> |
|||
<view :style="{height:iSMT+'px'}"></view> |
|||
<view class="top"> |
|||
<view class="top-list"> |
|||
<text>标准</text> |
|||
<radio value="0" class="radio-btn" activeBackgroundColor="red" |
|||
:checked="selectedIndex === 0" @click="selectFont(0)" /> |
|||
</view> |
|||
<view class="top-list"> |
|||
<text>中号</text> |
|||
<radio value="1" class="radio-btn" activeBackgroundColor="red" |
|||
:checked="selectedIndex === 1" @click="selectFont(1)" /> |
|||
</view> |
|||
<view class="top-list"> |
|||
<text>大号</text> |
|||
<radio value="2" class="radio-btn" activeBackgroundColor="red" |
|||
:checked="selectedIndex === 2" @click="selectFont(2)" /> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { |
|||
ref, |
|||
onMounted |
|||
} from 'vue' |
|||
const iSMT = ref(0) |
|||
const selectedIndex = ref(0) |
|||
|
|||
const selectFont = (index) => { |
|||
selectedIndex.value = index |
|||
console.log('看看选中状态',selectedIndex.value) |
|||
} |
|||
onMounted(() => { |
|||
// 状态栏高度 |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
console.log('看看高度', iSMT.value) |
|||
}) |
|||
</script> |
|||
|
|||
<style> |
|||
.top { |
|||
margin-top: 1.5vh; |
|||
height: 21vh; |
|||
background-color: white; |
|||
} |
|||
|
|||
.top-list { |
|||
width: 630rpx; |
|||
height: 7vh; |
|||
display: flex; |
|||
align-items: center; |
|||
margin: 0 40rpx; |
|||
padding:0 10rpx; |
|||
border-bottom: 1rpx solid #eee; |
|||
} |
|||
|
|||
.top-list:last-child { |
|||
border-bottom: none; |
|||
} |
|||
|
|||
.radio-btn { |
|||
margin-left: auto; |
|||
transform: scale(0.6); |
|||
} |
|||
</style> |
|||
@ -0,0 +1,165 @@ |
|||
<template> |
|||
<view class="main"> |
|||
<view :style="{height:iSMT+'px'}"></view> |
|||
<view class="top"> |
|||
<view class="top-list"> |
|||
<text>语言</text> |
|||
<text class="language">中文(简体)</text> |
|||
<uni-icons type="arrowright" size="16" class="arrow" /> |
|||
</view> |
|||
<view class="top-list" @click="goToFont"> |
|||
<text>字体大小</text> |
|||
<uni-icons type="arrowright" size="16" class="arrow" /> |
|||
</view> |
|||
<view class="top-list" @click="goToTheme"> |
|||
<text>主题切换</text> |
|||
<uni-icons type="arrowright" size="16" class="arrow" /> |
|||
</view> |
|||
</view> |
|||
|
|||
|
|||
<view class="center"> |
|||
<view class="center-list" @click="goToMessage"> |
|||
<text>消息推送</text> |
|||
<uni-icons type="arrowright" size="16" class="arrow" /> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="bottom"> |
|||
<view class="bottom-list" @click="goToServer"> |
|||
<text>切换服务器</text> |
|||
<uni-icons type="arrowright" size="16" class="arrow" /> |
|||
</view> |
|||
<view class="bottom-list" @click="clearCache"> |
|||
<text>清理缓存</text> |
|||
<text class="cache">{{ cache }}M</text> |
|||
<uni-icons type="arrowright" size="16" class="arrow" /> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { |
|||
ref, |
|||
onMounted |
|||
} from 'vue' |
|||
const iSMT = ref(0) |
|||
const cache = ref('45.5') |
|||
|
|||
const goToFont = () => { |
|||
uni.navigateTo({ |
|||
url: '/pages/setting/font' |
|||
}) |
|||
} |
|||
|
|||
const goToTheme = () => { |
|||
uni.navigateTo({ |
|||
url: '/pages/setting/theme' |
|||
}) |
|||
} |
|||
|
|||
const goToMessage = () => { |
|||
uni.navigateTo({ |
|||
url: '/pages/setting/message' |
|||
}) |
|||
} |
|||
|
|||
const goToServer = () => { |
|||
uni.navigateTo({ |
|||
url: '/pages/setting/server' |
|||
}) |
|||
} |
|||
|
|||
const clearCache = () => { |
|||
cache.value = 0 |
|||
uni.showToast({ |
|||
title: '清理成功', |
|||
icon: 'success', |
|||
duration: 1500 |
|||
}) |
|||
} |
|||
|
|||
onMounted(() => { |
|||
// 状态栏高度 |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
console.log('看看高度', iSMT.value) |
|||
}) |
|||
</script> |
|||
|
|||
<style> |
|||
.top { |
|||
margin-top: 1.5vh; |
|||
height: 21vh; |
|||
background-color: white; |
|||
} |
|||
|
|||
.top-list { |
|||
width: 630rpx; |
|||
height: 7vh; |
|||
display: flex; |
|||
align-items: center; |
|||
margin: 0 40rpx; |
|||
padding: 0 10rpx; |
|||
border-bottom: 1rpx solid #eee; |
|||
} |
|||
|
|||
.top-list:last-child { |
|||
border-bottom: none; |
|||
} |
|||
|
|||
.language { |
|||
margin-left: 55%; |
|||
font-size: 14px; |
|||
color: rgb(203, 203, 203); |
|||
} |
|||
|
|||
.arrow { |
|||
margin-left: auto; |
|||
} |
|||
|
|||
.center { |
|||
background-color: white; |
|||
height: 7vh; |
|||
display: flex; |
|||
align-items: center; |
|||
margin-top: 1vh; |
|||
} |
|||
|
|||
.center-list { |
|||
width: 630rpx; |
|||
margin: 0rpx 40rpx; |
|||
display: flex; |
|||
padding: 0 10rpx; |
|||
} |
|||
|
|||
.center-list>.arrow { |
|||
margin-right: 0; |
|||
} |
|||
|
|||
.bottom { |
|||
height: 13.5vh; |
|||
background-color: white; |
|||
margin-top: 1vh; |
|||
} |
|||
|
|||
.bottom-list { |
|||
width: 630rpx; |
|||
height: 7vh; |
|||
display: flex; |
|||
align-items: center; |
|||
margin: 0 40rpx; |
|||
padding: 0 10rpx; |
|||
border-bottom: 1rpx solid #eee; |
|||
} |
|||
|
|||
.cache { |
|||
margin-left: 55%; |
|||
font-size: 14px; |
|||
color: rgb(203, 203, 203); |
|||
} |
|||
|
|||
.bottom-list:last-child { |
|||
border-bottom: none; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,76 @@ |
|||
<template> |
|||
<view class="main"> |
|||
<view :style="{height:iSMT+'px'}"></view> |
|||
|
|||
<view style="height:1.5vh" /> |
|||
<view class="top"> |
|||
<img src="/static/my/aboutDC.png"></img> |
|||
</view> |
|||
|
|||
<view class="bottom"> |
|||
<view class="title">1.产品定位</view> |
|||
<view class="main-text">DeepChart:全球最懂机构行为的AI(你的AI投资伙伴)强化"深度分析" |
|||
的品牌标签(DeepChart=全球最懂机构行为的AI),主打"深度解读机构行为"的APP。</view> |
|||
|
|||
<view class="title">2.产品介绍</view> |
|||
<view class="main-text">DeepChart是一款以"Al智能体”为决策核心的智能投资分析平台, |
|||
专注于深度研究机构行为,专为全球散户投资者量身打造。它重新定义了人与投资工具之间的关系, |
|||
是一个真正懂投资、懂市场、更懂用户的AI投资伙伴。</view> |
|||
|
|||
<view class="title">3.产品理念</view> |
|||
<view class="main-text">从“人找信息”到“AI智能体替你思考和管理”。</view> |
|||
|
|||
<view class="title">4.功能定位——全景AI决策体系</view> |
|||
<view class="main-text">黄其振是大笨蛋</view> |
|||
<view class="main-text">李建霖是大笨蛋</view> |
|||
<view class="main-text">double是大笨蛋</view> |
|||
<view class="main-text">张鲁平是大笨蛋</view> |
|||
<view style="height:1.5vh;background-color: white;" /> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { |
|||
ref, |
|||
onMounted |
|||
} from 'vue' |
|||
const iSMT = ref(0) |
|||
|
|||
onMounted(() => { |
|||
// 状态栏高度 |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
console.log('看看高度', iSMT.value) |
|||
}) |
|||
</script> |
|||
|
|||
<style> |
|||
.top { |
|||
height: 26vh; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
background-color: white; |
|||
} |
|||
|
|||
.bottom { |
|||
height: 35vh; |
|||
padding: 0 60rpx; |
|||
background-color: white; |
|||
height: auto; |
|||
} |
|||
|
|||
.title { |
|||
font-size: 30rpx; |
|||
font-weight: bold; |
|||
margin-bottom: 20rpx; |
|||
} |
|||
|
|||
.main-text { |
|||
font-size: 27rpx; |
|||
margin-bottom: 20rpx; |
|||
color: rgb(122, 122, 122); |
|||
text-align: justify; |
|||
text-justify: inter-character;/* 两端对齐哈哈哈哈 */ |
|||
} |
|||
</style> |
|||
@ -0,0 +1,221 @@ |
|||
<template> |
|||
<view class="main"> |
|||
<view :style="{height:iSMT+'px'}"></view> |
|||
|
|||
<view class="time-share-title"> |
|||
<text>分时设计</text> |
|||
</view> |
|||
<view style="height:57.5vh;background-color: white;"> |
|||
<view class="title">A股竞价</view> |
|||
<view class="top-options"> |
|||
<view class="option-btn" :class="{ 'active': aStockBid === 0 }" @click="aStockBid = 0"> |
|||
<text>智能开启</text> |
|||
<view class="active-dot" v-if="aStockBid === 0"></view> |
|||
</view> |
|||
<view class="option-btn" :class="{ 'active': aStockBid === 1 }" @click="aStockBid = 1"> |
|||
<text>保持开启</text> |
|||
<view class="active-dot" v-if="aStockBid === 1"></view> |
|||
</view> |
|||
|
|||
<view class="option-btn" :class="{ 'active': aStockBid === 2 }" @click="aStockBid = 2"> |
|||
<text>保持关闭</text> |
|||
<view class="active-dot" v-if="aStockBid === 2"></view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="title">K线样式</view> |
|||
<view class="top-options"> |
|||
<view class="option-btn" :class="{ 'active': kStyle === 0 }" @click="kStyle = 0"> |
|||
<img src="/static/my/common.png" class="kline-icon" /> |
|||
<text>普通</text> |
|||
<view class="active-dot" v-if="kStyle === 0"></view> |
|||
</view> |
|||
<view class="option-btn" :class="{ 'active': kStyle === 1 }" @click="kStyle = 1"> |
|||
<img src="/static/my/outline.png" class="kline-icon" /> |
|||
<text>轮廓图</text> |
|||
<view class="active-dot" v-if="kStyle === 1"></view> |
|||
</view> |
|||
<view class="option-btn" :class="{ 'active': kStyle === 2 }" @click="kStyle = 2"> |
|||
<img src="/static/my/polylines.png" class="kline-icon" /> |
|||
<text>折线图</text> |
|||
<view class="active-dot" v-if="kStyle === 2"></view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="title">除权类型</view> |
|||
<view class="top-options"> |
|||
<view class="option-btn" :class="{ 'active': exRights === 0 }" @click="exRights = 0"> |
|||
<text>除权</text> |
|||
<view class="active-dot" v-if="exRights === 0"></view> |
|||
</view> |
|||
<view class="option-btn" :class="{ 'active': exRights === 1 }" @click="exRights = 1"> |
|||
<text>普通</text> |
|||
<view class="active-dot" v-if="exRights === 1"></view> |
|||
</view> |
|||
<view class="option-btn" :class="{ 'active': exRights === 2 }" @click="exRights = 2"> |
|||
<text>加权</text> |
|||
<view class="active-dot" v-if="exRights === 2"></view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="title">涨跌颜色</view> |
|||
<view class="top-options"> |
|||
<view class="option-btn" :class="{ 'active': rfColor === 0 }" @click="rfColor = 0"> |
|||
<view class="color-icon"> |
|||
<img src="/static/my/greenRise.png" class="kline-icon" /> |
|||
</view> |
|||
<text>绿涨红跌</text> |
|||
<view class="active-dot" v-if="rfColor === 0"></view> |
|||
</view> |
|||
<view class="option-btn" :class="{ 'active': rfColor === 1 }" @click="rfColor = 1"> |
|||
<view class="color-icon"> |
|||
<img src="/static/my/redRise.png" class="kline-icon" /> |
|||
</view> |
|||
<text>红涨绿跌</text> |
|||
<view class="active-dot" v-if="rfColor === 1"></view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="title">副图指标个数</view> |
|||
<view class="top-options"> |
|||
<view class="option-btn" :class="{ 'active': indexCount === 0 }" @click="indexCount = 0"> |
|||
<text>1</text> |
|||
</view> |
|||
<view class="option-btn" :class="{ 'active': indexCount === 1 }" @click="indexCount = 1"> |
|||
<text>2</text> |
|||
</view> |
|||
<view class="option-btn" :class="{ 'active': indexCount === 2 }" @click="indexCount = 2"> |
|||
<text>3</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="indicator-title"> |
|||
<text>指标设置</text> |
|||
</view> |
|||
<view class="indicator-list"> |
|||
<view class="indicator-item" v-for="(item, index) in indicatorList" :key="index"> |
|||
<text class="indicator-text">{{ item }}</text> |
|||
<view class="indicator-icons"> |
|||
<img src="/static/my/setting.png" class="icon" /> |
|||
<img src="/static/my/menu.png" class="icon" /> |
|||
</view> |
|||
</view> |
|||
<view style="height:10vh;background-color: white;"></view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { |
|||
ref, |
|||
onMounted |
|||
} from 'vue' |
|||
const iSMT = ref(0) |
|||
const aStockBid = ref(0) // 股票竞价:Stock bidding |
|||
const kStyle = ref(0) // k线样式 |
|||
const exRights = ref(0) // 除权类型 除权:Ex-rights |
|||
const rfColor = ref(0) // 涨跌颜色 rise-fall |
|||
const indexCount = ref(0) // 副图指标个数 |
|||
const indicatorList = ref(['K线', '均线', '成交量', 'KDJ', 'MACD', 'RSI']) |
|||
|
|||
onMounted(() => { |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
}) |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.time-share-title { |
|||
height: 4.5vh; |
|||
padding: 0 40rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
.title { |
|||
height: 5.5vh; |
|||
padding: 0 40rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
font-size: 26rpx; |
|||
color: #666; |
|||
} |
|||
|
|||
.top-options { |
|||
height: 5.5vh; |
|||
display: flex; |
|||
padding: 0 40rpx; |
|||
} |
|||
|
|||
.option-btn { |
|||
flex: 1; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
border: 1rpx solid #ddd; |
|||
border-radius: 8rpx; |
|||
margin: 0 10rpx; |
|||
padding: 15rpx 0; |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
.option-btn.active { |
|||
border-color: red; |
|||
} |
|||
|
|||
.active-dot { |
|||
width: 16rpx; |
|||
height: 16rpx; |
|||
background-color: red; |
|||
border-radius: 50%; |
|||
margin-left: 10rpx; |
|||
} |
|||
|
|||
.kline-icon { |
|||
margin-right: 10rpx; |
|||
font-size: 32rpx; |
|||
} |
|||
|
|||
.color-icon { |
|||
margin-right: 10rpx; |
|||
display: flex; |
|||
gap: 4rpx; |
|||
} |
|||
|
|||
.indicator-title { |
|||
height: 6vh; |
|||
padding: 0 40rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
.indicator-list { |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
padding: 0 40rpx; |
|||
background-color: white; |
|||
} |
|||
|
|||
.indicator-item { |
|||
display: flex; |
|||
align-items: center; |
|||
height: 7.5vh; |
|||
border-bottom: 1rpx solid #eee; |
|||
} |
|||
|
|||
.indicator-text { |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
.indicator-icons { |
|||
display: flex; |
|||
gap: 100rpx; |
|||
margin-left: auto; |
|||
} |
|||
|
|||
.icon { |
|||
width: 28rpx; |
|||
height: 28rpx; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,62 @@ |
|||
<template> |
|||
<view class="main"> |
|||
<view :style="{height:iSMT+'px'}"></view> |
|||
<view class="top"> |
|||
<view class="top-list" @click="goToPush"> |
|||
<text>语言</text> |
|||
<text class="message" v-if="isMessage">通知已开启</text> |
|||
<text class="message" v-if="!isMessage">通知未开启</text> |
|||
<uni-icons type="arrowright" size="16" class="arrow" /> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { |
|||
ref, |
|||
onMounted |
|||
} from 'vue' |
|||
const iSMT = ref(0) |
|||
const isMessage = ref(true) |
|||
|
|||
const goToPush = () =>{ |
|||
uni.navigateTo({ |
|||
url: '/pages/setting/push' |
|||
}) |
|||
} |
|||
|
|||
onMounted(() => { |
|||
// 状态栏高度 |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
console.log('看看高度', iSMT.value) |
|||
}) |
|||
</script> |
|||
|
|||
<style> |
|||
.top { |
|||
margin-top: 1.5vh; |
|||
height: 7vh; |
|||
background-color: white; |
|||
display: flex; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.top-list { |
|||
width: 630rpx; |
|||
height: 7vh; |
|||
display: flex; |
|||
align-items: center; |
|||
margin: 0rpx 40rpx; |
|||
} |
|||
|
|||
.message { |
|||
margin-left: 60%; |
|||
font-size: 14px; |
|||
color: rgb(203, 203, 203); |
|||
} |
|||
|
|||
.arrow { |
|||
margin-left: auto; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,82 @@ |
|||
<template> |
|||
<view class="main"> |
|||
<view :style="{height:iSMT+'px'}"></view> |
|||
<view style="height:1.5vh;" /> |
|||
<view class="top"> |
|||
<view class="top-list"> |
|||
<text v-if="hasNew === true" class="label">已有新版本</text> |
|||
<text v-if="hasNew === false" class="label">已是最新版本</text> |
|||
<view class="right"> |
|||
<text style="font-size: 28rpx;">{{ version }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view style="height:1vh;" /> |
|||
|
|||
<view class="bottom"> |
|||
<button v-if="hasNew === true" class="bottom-btn">立即更新</button> |
|||
<button v-if="hasNew === false" class="bottom-btn" disabled |
|||
style="background-color: rgb(204,204,204);color:white;">暂无更新</button> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { |
|||
ref, |
|||
onMounted |
|||
} from 'vue' |
|||
const iSMT = ref(0) |
|||
const hasNew = ref(true) |
|||
const version = ref('2.0') |
|||
|
|||
onMounted(() => { |
|||
// 状态栏高度 |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
console.log('看看高度', iSMT.value) |
|||
}) |
|||
</script> |
|||
|
|||
<style> |
|||
.top { |
|||
height: 7vh; |
|||
background-color: white; |
|||
display: flex; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.top-list { |
|||
width: 630rpx; |
|||
height: 7vh; |
|||
display: flex; |
|||
align-items: center; |
|||
margin: 0rpx 40rpx; |
|||
} |
|||
|
|||
.label { |
|||
font-size: 28rpx; |
|||
flex: 1; |
|||
} |
|||
|
|||
.bottom { |
|||
height: 11vh; |
|||
background-color: white; |
|||
padding: 0 50rpx; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
|
|||
.bottom-btn { |
|||
width: 670rpx; |
|||
height: 84rpx; |
|||
border-radius: 40rpx; |
|||
background-color: #000; |
|||
color: #fff; |
|||
font-size: 28rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,144 @@ |
|||
<template> |
|||
<view class="main"> |
|||
<view :style="{height:iSMT+'px'}"></view> |
|||
|
|||
<view style="height:1.5vh;" /> |
|||
|
|||
<view class="title"> |
|||
<text class="label">确认新密码</text> |
|||
</view> |
|||
|
|||
<view class="top"> |
|||
<view class="top-list"> |
|||
<view class="left"> |
|||
<img src="/static/my/unlock.png" /> |
|||
<input type="password" :type="pwdType" placeholder="请输入新密码" class="input" /> |
|||
<img :src="pwdType === 1 ? '/static/my/hideEye.png' : '/static/my/openEye.png'" |
|||
@click="changeEye(1)" /> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="top-list"> |
|||
<view class="left"> |
|||
<img src="/static/my/unlock.png" /> |
|||
<input type="password" :type="pwdType2" placeholder="再次确认" class="input" /> |
|||
<img :src="pwdType === 1 ? '/static/my/hideEye.png' : '/static/my/openEye.png'" |
|||
@click="changeEye(2)" /> |
|||
</view> |
|||
</view> |
|||
|
|||
<text class="tips">密码最少8位数</text> |
|||
</view> |
|||
|
|||
<view class="bottom"> |
|||
<button class="change-btn">确认</button> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { |
|||
ref, |
|||
onMounted |
|||
} from 'vue' |
|||
|
|||
const iSMT = ref(0) |
|||
const pwdType = ref('password') |
|||
const pwdType2 = ref('password') |
|||
|
|||
const changeEye = (type) => { |
|||
if (type === 1) { |
|||
pwdType.value = pwdType.value === 'password' ? 'text' : 'password' |
|||
} else { |
|||
pwdType2.value = pwdType2.value === 'password' ? 'text' : 'password' |
|||
} |
|||
} |
|||
|
|||
onMounted(() => { |
|||
// 状态栏高度 |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
console.log('看看高度', iSMT.value) |
|||
}) |
|||
</script> |
|||
|
|||
<style> |
|||
.title { |
|||
height: 8.5vh; |
|||
background-color: white; |
|||
} |
|||
|
|||
.label { |
|||
height: 8.5vh; |
|||
font-size: 40rpx; |
|||
font-weight: bold; |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 0 60rpx; |
|||
} |
|||
|
|||
.top { |
|||
height: auto; |
|||
background-color: white; |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
} |
|||
|
|||
.top-list { |
|||
width: 630rpx; |
|||
height: 7vh; |
|||
margin: 0rpx 40rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
border-bottom: 1rpx solid #eee; |
|||
} |
|||
|
|||
.left { |
|||
flex: 1; |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
.input { |
|||
flex: 1; |
|||
height: 70rpx; |
|||
font-size: 29rpx; |
|||
margin-left: 20rpx; |
|||
} |
|||
|
|||
.bottom { |
|||
height: 22vh; |
|||
background-color: white; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.change-btn { |
|||
height: 85rpx; |
|||
width: 610rpx; |
|||
padding: 0 20rpx; |
|||
background-color: black; |
|||
color: white; |
|||
border-radius: 40rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.img { |
|||
position: absolute; |
|||
right: 0; |
|||
top: 50%; |
|||
transform: translateY(-50%); |
|||
} |
|||
|
|||
.tips { |
|||
font-size: 24rpx; |
|||
color: #999; |
|||
margin-top: 20rpx; |
|||
margin-left: 60rpx; |
|||
align-self: flex-start; |
|||
/* 这是左对齐 */ |
|||
} |
|||
</style> |
|||
@ -0,0 +1,171 @@ |
|||
<template> |
|||
<view class="main"> |
|||
<view :style="{height:iSMT+'px'}"></view> |
|||
|
|||
<view class="tab"> |
|||
<view class="tab-item" :class="{active: activeTab === 'email'}" @click="activeTab = 'email'">邮箱</view> |
|||
<view class="tab-item" :class="{active: activeTab === 'phone'}" @click="activeTab = 'phone'">手机号</view> |
|||
</view> |
|||
|
|||
<view class="switch-tab"> |
|||
<view class="input-list" v-if="activeTab === 'email'"> |
|||
<image src="/static/my/changeEmail.png" mode="aspectFit"></image> |
|||
<input type="text" placeholder="请输入邮箱" class="input" /> |
|||
<button class="code-btn" :class="{disabled: gettingCode}" @click="getCode" :disabled="gettingCode"> |
|||
{{ gettingCode ? `重新发送 ${time}s` : '获取验证码' }} |
|||
</button> |
|||
</view> |
|||
|
|||
<view class="input-list" v-else> |
|||
<image src="/static/my/changeBindPhone.png" mode="aspectFit"></image> |
|||
<input type="number" placeholder="请输入手机号" class="input" /> |
|||
<button class="code-btn" :class="{disabled: gettingCode}" @click="getCode" :disabled="gettingCode"> |
|||
{{ gettingCode ? `重新发送 ${time}s` : '获取验证码' }} |
|||
</button> |
|||
</view> |
|||
|
|||
<view class="input-list"> |
|||
<image src="/static/my/verification.png" mode="aspectFit"></image> |
|||
<input type="text" placeholder="请输入验证码" class="input" /> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="btn-area"> |
|||
<button class="next-btn" @click="goToPwdNext">下一步</button> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { |
|||
ref, |
|||
onMounted |
|||
} from 'vue' |
|||
|
|||
const iSMT = ref(0) |
|||
const activeTab = ref('email') |
|||
const gettingCode = ref(false) |
|||
const time = ref(60) |
|||
|
|||
const getCode = () => { |
|||
if (gettingCode.value) return |
|||
gettingCode.value = true |
|||
|
|||
time.value = 60 |
|||
|
|||
const timer = setInterval(() => { |
|||
time.value-- |
|||
if (time.value <= 0) { |
|||
clearInterval(timer) |
|||
gettingCode.value = false |
|||
time.value = 60 |
|||
} |
|||
}, 1000) |
|||
} |
|||
|
|||
const goToPwdNext = () =>{ |
|||
uni.navigateTo({ |
|||
url:'../setting/nextPwd' |
|||
}) |
|||
} |
|||
|
|||
onMounted(() => { |
|||
// 获取状态栏高度 |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
}) |
|||
</script> |
|||
|
|||
<style> |
|||
.tab { |
|||
display: flex; |
|||
height: 8vh; |
|||
background-color: #fff; |
|||
border-bottom: 1rpx solid #eee; |
|||
} |
|||
|
|||
.tab-item { |
|||
flex: 1; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
font-size: 32rpx; |
|||
position: relative; |
|||
} |
|||
|
|||
.tab-item.active { |
|||
color: #000; |
|||
font-weight: bold; |
|||
} |
|||
|
|||
.tab-item.active::after { |
|||
content: ''; |
|||
position: absolute; |
|||
bottom: 0; |
|||
left: 50%; |
|||
transform: translateX(-50%); |
|||
width: 40rpx; |
|||
height: 6rpx; |
|||
background-color: #000;/* ????? */ |
|||
} |
|||
|
|||
.switch-tab { |
|||
background-color: #fff; |
|||
padding: 0 60rpx; |
|||
} |
|||
|
|||
.input-list { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
height: 7vh; |
|||
border-bottom: 1rpx solid #eee; |
|||
} |
|||
|
|||
.input-list image { |
|||
width: 40rpx; |
|||
height: 40rpx; |
|||
margin-right: 20rpx; |
|||
} |
|||
|
|||
.input { |
|||
flex: 1; |
|||
height: 14vh; |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
.code-btn { |
|||
width: 200rpx; |
|||
height: 60rpx; |
|||
font-size: 24rpx; |
|||
border-radius: 10rpx; |
|||
background-color: #eee; |
|||
color: #666; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.code-btn.disabled { |
|||
background-color: #ccc; |
|||
color: #999; |
|||
} |
|||
|
|||
.btn-area{ |
|||
height:8vh; |
|||
background-color: white; |
|||
padding-top: 120rpx; |
|||
} |
|||
|
|||
|
|||
.next-btn { |
|||
width: 610rpx; |
|||
height: 85rpx; |
|||
background-color: #000; |
|||
color: #fff; |
|||
font-size: 30rpx; |
|||
border-radius: 40rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,143 @@ |
|||
<template> |
|||
<view class="main"> |
|||
<view :style="{height:iSMT+'px'}"></view> |
|||
|
|||
<view style="height:1.5vh;" /> |
|||
|
|||
<view class="top"> |
|||
<view class="top-list"> |
|||
<view class="left"> |
|||
<img src="/static/my/bindedPhone.png" /> |
|||
<text class="label">已绑手机号:{{ phone }}</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="top-list"> |
|||
<view class="left"> |
|||
<img src="/static/my/changeBindPhone.png" /> |
|||
<text class="label">+86</text> |
|||
<input type="number" placeholder="请输入您的换绑手机号" class="input" /> |
|||
</view> |
|||
<view class="right"> |
|||
<button class="verification" :class="{ 'disabled': gettingCode }" @click="getVerification" |
|||
:disabled="gettingCode"> |
|||
{{ gettingCode ? `重新发送 ${time}s` : '获取验证码' }} |
|||
</button> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="top-list"> |
|||
<view class="left"> |
|||
<img src="/static/my/verification.png" /> |
|||
<input type="text" placeholder="请输入验证码" class="input" /> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="bottom"> |
|||
<button class="change-btn">换绑</button> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { |
|||
ref, |
|||
onMounted |
|||
} from 'vue' |
|||
const iSMT = ref(0) |
|||
const phone = ref('15105421566') |
|||
const gettingCode = ref(false) |
|||
const time = ref(60) |
|||
|
|||
const getVerification = () => { |
|||
if (gettingCode.value) return |
|||
gettingCode.value = true |
|||
|
|||
time.value = 60 |
|||
|
|||
const timer = setInterval(() => { |
|||
time.value-- |
|||
if (time.value <= 0) { |
|||
clearInterval(timer) |
|||
gettingCode.value = false |
|||
} |
|||
}, 1000) |
|||
} |
|||
|
|||
onMounted(() => { |
|||
// 状态栏高度 |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
console.log('看看高度', iSMT.value) |
|||
}) |
|||
</script> |
|||
|
|||
<style> |
|||
.top { |
|||
height: auto; |
|||
background-color: white; |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.top-list { |
|||
width: 630rpx; |
|||
height: 7vh; |
|||
margin: 0rpx 40rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
border-bottom: 1rpx solid #eee; |
|||
} |
|||
|
|||
.left { |
|||
flex: 1; |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
.label { |
|||
font-size: 28rpx; |
|||
margin-left: 10rpx; |
|||
} |
|||
|
|||
.right { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.input { |
|||
flex: 1; |
|||
height: 70rpx; |
|||
font-size: 29rpx; |
|||
margin-left: 20rpx; |
|||
} |
|||
|
|||
.verification { |
|||
font-size: 24rpx; |
|||
border-radius: 10rpx; |
|||
background-color: rgb(230, 230, 230); |
|||
} |
|||
|
|||
.bottom { |
|||
height: 22vh; |
|||
background-color: white; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.change-btn { |
|||
height: 85rpx; |
|||
width: 610rpx; |
|||
padding:0 20rpx; |
|||
background-color: black; |
|||
color: white; |
|||
border-radius: 40rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,108 @@ |
|||
<template> |
|||
<view class="main"> |
|||
<view :style="{height:iSMT+'px'}"></view> |
|||
<view class="top"> |
|||
<view class="top-list"> |
|||
<text style="width:180rpx;">公共消息</text> |
|||
<text class="public">重大咨询、财经要闻等系统提醒</text> |
|||
<switch class="arrow switch-btn" /> |
|||
</view> |
|||
<view class="top-list"> |
|||
<text>字体大小</text> |
|||
<switch class="arrow switch-btn" /> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="bottom"> |
|||
<view class="bottom-list"> |
|||
<text>盯盘预警</text> |
|||
<uni-icons type="arrowright" size="16" class="arrow" /> |
|||
</view> |
|||
<view class="bottom-list"> |
|||
<text>订阅服务</text> |
|||
<text class="cache">45.5M</text> |
|||
<uni-icons type="arrowright" size="16" class="arrow" /> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { |
|||
ref, |
|||
onMounted |
|||
} from 'vue' |
|||
const iSMT = ref(0) |
|||
|
|||
onMounted(() => { |
|||
// 状态栏高度 |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
console.log('看看高度', iSMT.value) |
|||
}) |
|||
</script> |
|||
|
|||
<style> |
|||
.top { |
|||
margin-top: 1.5vh; |
|||
height: 14vh; |
|||
background-color: white; |
|||
} |
|||
|
|||
.top-list { |
|||
width: 630rpx; |
|||
height: 7vh; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
margin: 0 40rpx; |
|||
padding: 0 10rpx; |
|||
border-bottom: 1rpx solid #eee; |
|||
} |
|||
|
|||
.top-list:last-child { |
|||
border-bottom: none; |
|||
} |
|||
|
|||
.switch-btn { |
|||
width: 100rpx; |
|||
transform: scale(0.6); |
|||
transform-origin: center right; |
|||
} |
|||
|
|||
.public { |
|||
width: 450rpx; |
|||
margin-left: auto; |
|||
font-size: 10px; |
|||
color: rgb(203, 203, 203); |
|||
} |
|||
|
|||
.arrow { |
|||
margin-left: auto; |
|||
} |
|||
|
|||
.bottom { |
|||
height: 13.5vh; |
|||
background-color: white; |
|||
margin-top: 1vh; |
|||
} |
|||
|
|||
.bottom-list { |
|||
width: 630rpx; |
|||
height: 7vh; |
|||
display: flex; |
|||
align-items: center; |
|||
margin: 0 40rpx; |
|||
padding: 0 10rpx; |
|||
border-bottom: 1rpx solid #eee; |
|||
} |
|||
|
|||
.cache { |
|||
margin-left: 55%; |
|||
font-size: 14px; |
|||
color: rgb(203, 203, 203); |
|||
} |
|||
|
|||
.bottom-list:last-child { |
|||
border-bottom: none; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,87 @@ |
|||
<template> |
|||
<view class="main"> |
|||
<view :style="{height:iSMT+'px'}"></view> |
|||
<view class="top"> |
|||
<view class="top-list"> |
|||
<text>自动选择</text> |
|||
<radio value="0" class="radio-btn" activeBackgroundColor="red" |
|||
:checked="selectedIndex === 0" @click="selectFont(0)" /> |
|||
</view> |
|||
<view class="top-list"> |
|||
<text>新加坡服务器</text> |
|||
<radio value="1" class="radio-btn" activeBackgroundColor="red" |
|||
:checked="selectedIndex === 1" @click="selectFont(1)" /> |
|||
</view> |
|||
<view class="top-list"> |
|||
<text>香港服务器</text> |
|||
<radio value="2" class="radio-btn" activeBackgroundColor="red" |
|||
:checked="selectedIndex === 2" @click="selectFont(2)" /> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { |
|||
ref, |
|||
onMounted |
|||
} from 'vue' |
|||
const iSMT = ref(0) |
|||
const selectedIndex = ref(0) |
|||
|
|||
const selectFont = (index) => { |
|||
selectedIndex.value = index |
|||
console.log('看看选中状态',selectedIndex.value) |
|||
} |
|||
|
|||
onMounted(() => { |
|||
// 状态栏高度 |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
console.log('看看高度', iSMT.value) |
|||
}) |
|||
</script> |
|||
|
|||
<style> |
|||
.top { |
|||
margin-top: 1.5vh; |
|||
height: 21vh; |
|||
background-color: white; |
|||
} |
|||
|
|||
.top-list { |
|||
width: 630rpx; |
|||
height: 7vh; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
margin: 0 40rpx; |
|||
padding: 0 10rpx; |
|||
border-bottom: 1rpx solid #eee; |
|||
} |
|||
|
|||
.top-list:last-child { |
|||
border-bottom: none; |
|||
} |
|||
|
|||
.switch-btn { |
|||
width: 100rpx; |
|||
transform: scale(0.6); |
|||
transform-origin: center right; |
|||
} |
|||
|
|||
.public { |
|||
width: 450rpx; |
|||
margin-left: auto; |
|||
font-size: 10px; |
|||
color: rgb(203, 203, 203); |
|||
} |
|||
|
|||
.arrow { |
|||
margin-left: auto; |
|||
} |
|||
|
|||
.radio-btn { |
|||
margin-left: auto; |
|||
transform: scale(0.6); |
|||
} |
|||
</style> |
|||
@ -0,0 +1,111 @@ |
|||
<template> |
|||
<view class="all"> |
|||
<img class="img-share" src="/static/my/shareBackground.png" /> |
|||
<img class="img-greenBack" src="/static/my/greenBackground.png" /> |
|||
<img class="img-QRcode" src="/static/my/QRcode.png" /> |
|||
<img class="img-award" src="/static/my/award.png" /> |
|||
<img class="img-myFriends" src="/static/my/myFriends.png" /> |
|||
<img class="img-friends" src="/static/my/shareFriends.png" /> |
|||
<text class="jwcode">{{ jwcode }}</text> |
|||
<button class="invite">立即邀请</button> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { |
|||
ref |
|||
} from 'vue' |
|||
|
|||
const jwcode = ref('90047681') |
|||
</script> |
|||
|
|||
<style> |
|||
.all { |
|||
position: relative; |
|||
width: 750rpx; |
|||
height: auto; |
|||
} |
|||
|
|||
.img-share { |
|||
width: 750rpx; |
|||
height: 2118rpx; |
|||
position: absolute; |
|||
top: 0; |
|||
left: 0; |
|||
z-index: 1; |
|||
} |
|||
|
|||
.img-QRcode{ |
|||
width:320rpx; |
|||
height:320rpx; |
|||
position:absolute; |
|||
top:26vh; |
|||
left:215rpx; |
|||
z-index: 3; |
|||
} |
|||
|
|||
.img-greenBack { |
|||
width: 670rpx; |
|||
height: 1740rpx; |
|||
position: absolute; |
|||
top: 16vh; |
|||
/* 为什么要用这个替代 margin-top */ |
|||
left: 40rpx; |
|||
/* 还有 padding-left */ |
|||
z-index: 2; |
|||
} |
|||
|
|||
.img-friends { |
|||
width: 602rpx; |
|||
height: 840rpx; |
|||
position: absolute; |
|||
top: 68vh; |
|||
left: 74rpx; |
|||
z-index: 3; |
|||
} |
|||
|
|||
.img-award { |
|||
width: 300rpx; |
|||
height: 120rpx; |
|||
position: absolute; |
|||
top: 61vh; |
|||
left: 75rpx; |
|||
z-index: 3; |
|||
} |
|||
|
|||
.img-myFriends { |
|||
width: 300rpx; |
|||
height: 88rpx; |
|||
position: absolute; |
|||
top: 61vh; |
|||
right: 75rpx; |
|||
z-index: 3; |
|||
} |
|||
|
|||
.jwcode { |
|||
width: 320rpx; |
|||
height: 38rpx; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
position: absolute; |
|||
top: 19vh; |
|||
left: 212rpx; |
|||
z-index: 999; |
|||
} |
|||
|
|||
.invite { |
|||
width: 320rpx; |
|||
height: 80rpx; |
|||
border-radius: 40rpx; |
|||
background-color: black; |
|||
color:white; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
position: absolute; |
|||
top: 50.7vh; |
|||
left: 212rpx; |
|||
z-index: 999; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,64 @@ |
|||
<template> |
|||
<view class="main"> |
|||
<view :style="{height:iSMT+'px'}"></view> |
|||
<view class="theme"> |
|||
<view class="left"> |
|||
<image class="img-theme" src="/static/my/whiteTheme.png" mode="widthFix" /> |
|||
<radio value="0" class="radio-btn" activeBackgroundColor="red" :checked="selectedIndex === 0" |
|||
@click="selectFont(0)" /> |
|||
</view> |
|||
<view class="left"> |
|||
<image class="img-theme" src="/static/my/blackTheme.png" mode="widthFix" /> |
|||
<radio value="1" class="radio-btn" activeBackgroundColor="red" :checked="selectedIndex === 1" |
|||
@click="selectFont(1)" /> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { |
|||
ref, |
|||
onMounted |
|||
} from 'vue' |
|||
const iSMT = ref(0) |
|||
const selectedIndex = ref(0) |
|||
|
|||
const selectFont = (index) => { |
|||
selectedIndex.value = index |
|||
console.log('看看选中状态', selectedIndex.value) |
|||
} |
|||
onMounted(() => { |
|||
// 状态栏高度 |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
console.log('看看高度', iSMT.value) |
|||
}) |
|||
</script> |
|||
|
|||
<style> |
|||
.theme { |
|||
margin-top: 1.5vh; |
|||
height: 34vh; |
|||
background-color: white; |
|||
display: flex; |
|||
justify-content: space-around; |
|||
} |
|||
|
|||
.img-theme { |
|||
width: 316rpx; |
|||
height: 362rpx; |
|||
} |
|||
|
|||
.left { |
|||
width: 350rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
|
|||
.radio-btn { |
|||
margin-top: 36rpx; |
|||
transform: scale(0.8); |
|||
} |
|||
</style> |
|||
|
After Width: 18 | Height: 32 | Size: 576 B |
|
After Width: 82 | Height: 24 | Size: 3.0 KiB |
|
After Width: 36 | Height: 33 | Size: 2.0 KiB |
|
After Width: 623 | Height: 400 | Size: 113 KiB |
|
After Width: 33 | Height: 32 | Size: 460 B |
|
After Width: 36 | Height: 36 | Size: 539 B |
|
After Width: 46 | Height: 46 | Size: 1.7 KiB |
|
After Width: 32 | Height: 32 | Size: 2.3 KiB |
|
After Width: 60 | Height: 60 | Size: 238 B |
|
After Width: 18 | Height: 32 | Size: 437 B |
|
After Width: 32 | Height: 32 | Size: 1.8 KiB |
|
After Width: 60 | Height: 60 | Size: 867 B |
|
After Width: 30 | Height: 30 | Size: 1.5 KiB |
|
After Width: 158 | Height: 181 | Size: 3.4 KiB |
|
After Width: 22 | Height: 22 | Size: 614 B |
|
After Width: 33 | Height: 33 | Size: 687 B |
|
After Width: 160 | Height: 160 | Size: 17 KiB |
|
After Width: 27 | Height: 27 | Size: 1.2 KiB |
|
After Width: 21 | Height: 19 | Size: 636 B |
|
After Width: 167 | Height: 155 | Size: 8.7 KiB |
|
After Width: 150 | Height: 60 | Size: 2.8 KiB |
|
After Width: 13 | Height: 16 | Size: 358 B |
|
After Width: 20 | Height: 20 | Size: 380 B |
|
After Width: 20 | Height: 20 | Size: 337 B |
|
After Width: 20 | Height: 20 | Size: 351 B |
|
After Width: 20 | Height: 20 | Size: 413 B |
|
After Width: 31 | Height: 23 | Size: 237 B |
|
After Width: 20 | Height: 20 | Size: 748 B |
|
After Width: 15 | Height: 15 | Size: 424 B |
|
After Width: 335 | Height: 870 | Size: 11 KiB |
|
After Width: 26 | Height: 25 | Size: 993 B |
|
After Width: 20 | Height: 9 | Size: 429 B |
|
After Width: 375 | Height: 1059 | Size: 454 KiB |
|
After Width: 14 | Height: 14 | Size: 228 B |
|
After Width: 150 | Height: 44 | Size: 2.1 KiB |
|
After Width: 20 | Height: 12 | Size: 660 B |
|
After Width: 21 | Height: 20 | Size: 551 B |
|
After Width: 31 | Height: 25 | Size: 1.3 KiB |
|
After Width: 31 | Height: 23 | Size: 1.3 KiB |
|
After Width: 26 | Height: 25 | Size: 966 B |
|
After Width: 23 | Height: 23 | Size: 669 B |
|
After Width: 28 | Height: 28 | Size: 1.4 KiB |
|
After Width: 360 | Height: 80 | Size: 28 KiB |
|
After Width: 375 | Height: 1059 | Size: 456 KiB |
|
After Width: 301 | Height: 397 | Size: 50 KiB |
|
After Width: 20 | Height: 20 | Size: 488 B |
|
After Width: 21 | Height: 17 | Size: 488 B |
|
After Width: 20 | Height: 20 | Size: 526 B |
|
After Width: 158 | Height: 181 | Size: 3.4 KiB |