Merge branch 'milestone-20251031-简版功能开发' into maziyang/feature-20251025172218-智能客服中台
zhaowenkang/feature-20251028181547-行情页面
-
6.hbuilderx/launch.json
-
88api/deepExploration/deepExploration.js
-
0api/deepMate.js
-
68api/deepMate/deepMate.js
-
116api/start/login.js
-
260api/tcpConnection.js
-
392common/canvasMethod.js
-
354common/stockTimeInformation.js
-
123common/util.js
-
42components/DeepMate.vue
-
4components/IndexCard.vue
-
58components/MarketOverview.vue
-
536components/deepExploration_header.vue
-
49components/footerBar.vue
-
183components/login-prompt.vue
-
54main.js
-
38manifest.json
-
469package-lock.json
-
10package.json
-
274pages.json
-
100pages/blank/institutionalTrendsBriefing.vue
-
100pages/blank/notice.vue
-
801pages/deepExploration/MainForceActions.vue
-
427pages/deepExploration/deepExploration.vue
-
354pages/deepExploration/stockSelectDetail.vue
-
1733pages/deepMate/deepMate.vue
-
28pages/home/deepExploration.vue
-
1214pages/home/home.vue
-
296pages/home/member.vue
-
655pages/marketSituation/chartExample.vue
-
493pages/marketSituation/countryMarket.vue
-
301pages/marketSituation/forexMetals.vue
-
62pages/marketSituation/globalIndex.vue
-
2258pages/marketSituation/marketCondition.vue
-
82pages/marketSituation/marketDetail.vue
-
757pages/marketSituation/marketOverview.vue
-
473pages/marketSituation/marketSituation.vue
-
86pages/setting/about.vue
-
218pages/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
-
1054pages/start/Registration/Registration.vue
-
1341pages/start/Registration/list.js
-
13pages/start/agreement/agreement.vue
-
56pages/start/index/index.vue
-
1341pages/start/login/list.js
-
1190pages/start/login/login.vue
-
69pages/start/login/verification.js
-
13pages/start/privacy/privacy.vue
-
1012pages/start/recoverPassword/recoverPassword.vue
-
170pages/start/select/select.vue
-
73pages/start/startup/startup.vue
-
138server/login.json
-
BINstatic/deepExploration-images/1.png
-
BINstatic/deepExploration-images/2.png
-
BINstatic/deepExploration-images/3.png
-
BINstatic/deepExploration-images/4.png
-
BINstatic/deepExploration-images/ASC.png
-
BINstatic/deepExploration-images/Americle.png
-
BINstatic/deepExploration-images/DESC.png
-
BINstatic/deepExploration-images/all.png
-
BINstatic/deepExploration-images/close.png
-
BINstatic/deepExploration-images/delete.png
-
BINstatic/deepExploration-images/history.png
-
BINstatic/deepExploration-images/icon1.png
-
BINstatic/deepExploration-images/icon2.png
-
BINstatic/deepExploration-images/icon3.png
-
BINstatic/deepExploration-images/icon4.png
-
BINstatic/deepExploration-images/last.png
-
BINstatic/deepExploration-images/next.png
-
BINstatic/deepExploration-images/notice.png
-
BINstatic/deepExploration-images/plus.png
-
BINstatic/deepExploration-images/search.png
-
BINstatic/deepExploration-images/showAll.png
-
BINstatic/flag/ad.png
-
BINstatic/flag/ae.png
-
BINstatic/flag/af.png
-
BINstatic/flag/ag.png
-
BINstatic/flag/ai.png
-
BINstatic/flag/al.png
-
BINstatic/flag/am.png
-
BINstatic/flag/an.png
-
BINstatic/flag/ao.png
-
BINstatic/flag/aq.png
-
BINstatic/flag/ar.png
-
BINstatic/flag/as.png
-
BINstatic/flag/at.png
@ -0,0 +1,88 @@ |
|||
import { http } from '@/utils/http.js' |
|||
|
|||
|
|||
//主力追踪意图
|
|||
export const getModel1First = (data) => { |
|||
return http({ |
|||
method: 'POST', |
|||
url: '/api/coze/trackingFirst', |
|||
data |
|||
}) |
|||
} |
|||
|
|||
//主力追踪意图
|
|||
export const getModel1Second = (data) => { |
|||
return http({ |
|||
method: 'POST', |
|||
url: '/api/coze/trackingSecond', |
|||
data |
|||
}) |
|||
} |
|||
|
|||
|
|||
//主力追踪意图
|
|||
export const getModel2First = (data) => { |
|||
return http({ |
|||
method: 'POST', |
|||
url: '/api/coze/radarFirst', |
|||
data |
|||
}) |
|||
} |
|||
|
|||
//主力追踪意图
|
|||
export const getModel2Second = (data) => { |
|||
return http({ |
|||
method: 'POST', |
|||
url: '/api/coze/radarSecond', |
|||
data |
|||
}) |
|||
} |
|||
|
|||
//主力追踪意图
|
|||
export const getModel3First = (data) => { |
|||
return http({ |
|||
method: 'POST', |
|||
url: '/api/coze/decodingFirst', |
|||
data |
|||
}) |
|||
} |
|||
|
|||
//主力追踪意图
|
|||
export const getModel3Second = (data) => { |
|||
return http({ |
|||
method: 'POST', |
|||
url: '/api/coze/decodingSecond', |
|||
data |
|||
}) |
|||
} |
|||
|
|||
//主力追踪意图
|
|||
export const getModel4First = (data) => { |
|||
return http({ |
|||
method: 'POST', |
|||
url: '/api/coze/fundsFirst', |
|||
data |
|||
}) |
|||
} |
|||
|
|||
//主力追踪意图
|
|||
export const getModel4Second = (data) => { |
|||
return http({ |
|||
method: 'POST', |
|||
url: '/api/coze/fundsSecond', |
|||
data |
|||
}) |
|||
} |
|||
|
|||
|
|||
|
|||
//历史记录列表
|
|||
export const RecordListApi = (data) => { |
|||
return http({ |
|||
method: 'POST', |
|||
url: '/api/coze/mainForceList', |
|||
data:data |
|||
}) |
|||
} |
|||
|
|||
|
|||
@ -0,0 +1,68 @@ |
|||
import { http } from '../../utils/http' |
|||
|
|||
|
|||
|
|||
export const getData = () => { |
|||
return http({ |
|||
method: 'GET', |
|||
url: '/ka', |
|||
}) |
|||
} |
|||
|
|||
|
|||
|
|||
/** |
|||
* 意图识别 |
|||
* POST /api/deepMate/dmFirst |
|||
* headers: token, content-type: application/json, contentType: application/json, version, client |
|||
* body: { content, language, marketList } |
|||
*/ |
|||
export const postIntent = (data) => { |
|||
return http({ |
|||
method: 'POST', |
|||
url: '/api/deepMate/dmFirst', |
|||
data |
|||
}) |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 获取股票信息 |
|||
* headers: token, content-type: application/json, contentType: application/json, version, client |
|||
* body: { language, token, recordId, parentId, stockId } |
|||
*/ |
|||
export const postStock = (data) => { |
|||
return http({ |
|||
method: 'POST', |
|||
url: '/api/deepMate/dmSecond', |
|||
data |
|||
}) |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 获取历史记录 |
|||
*/ |
|||
|
|||
export const postHistory = (data) => { |
|||
return http({ |
|||
method: 'POST', |
|||
url: '/api/deepMate/dmList', |
|||
data |
|||
}) |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 历史记录详情 |
|||
*/ |
|||
|
|||
export const postHistoryDetail = (data) => { |
|||
return http({ |
|||
method: 'POST', |
|||
url: '/api/deepMate/clickRecord', |
|||
data |
|||
}) |
|||
} |
|||
|
|||
|
|||
@ -0,0 +1,116 @@ |
|||
import { http } from '../../utils/http' |
|||
|
|||
|
|||
/** |
|||
* |
|||
* @param data 模拟手机号码 |
|||
* { |
|||
"loginType":"EMAIL", //登录方式
|
|||
"account":"q614588746@163.com" , //登陆账号 手机号/邮箱/dccode
|
|||
"verifyCode":"837012", //验证码
|
|||
"password":"", //密码
|
|||
"useCode":"true", //是否使用验证码 true/false
|
|||
"idToken":"", //第三方登录idToken
|
|||
} |
|||
*/ |
|||
export const LoginApi = (data) => { |
|||
return http({ |
|||
method: 'POST', |
|||
url: '/UserLogin/login', |
|||
data: |
|||
data |
|||
, |
|||
}) |
|||
} |
|||
|
|||
|
|||
|
|||
/** |
|||
* 发送邮箱验证码 |
|||
* @param {*} email |
|||
* @returns |
|||
*/ |
|||
export const SendEmailCodeApi = (data) => { |
|||
return http({ |
|||
method: 'POST', |
|||
url: '/UserLogin/sendEmail', |
|||
data: data |
|||
}) |
|||
} |
|||
|
|||
|
|||
|
|||
/** |
|||
* 发送手机验证码 |
|||
* @param {*} email |
|||
* @returns |
|||
*/ |
|||
export const SendPhoneCodeApi = (data) => { |
|||
return http({ |
|||
method: 'POST', |
|||
url: '/UserLogin/sendPhone', |
|||
data:data |
|||
}) |
|||
} |
|||
|
|||
|
|||
|
|||
/** |
|||
* 注册 |
|||
*/ |
|||
|
|||
export const registerApi = (data) => { |
|||
return http({ |
|||
method: 'POST', |
|||
url: '/UserLogin/register', |
|||
data: data, |
|||
}) |
|||
} |
|||
|
|||
/** |
|||
* 修改密码 |
|||
* |
|||
*/ |
|||
|
|||
export const updatePassword = (data) => { |
|||
return http({ |
|||
method: 'GET', |
|||
url: '/updatePassword', |
|||
data: { |
|||
data |
|||
}, |
|||
}) |
|||
} |
|||
|
|||
|
|||
|
|||
/** |
|||
* 通过苹果登录 |
|||
*/ |
|||
|
|||
export const postLoginAppleSimpleAPI = (phoneNumber) => { |
|||
return http({ |
|||
method: 'POST', |
|||
url: '/login', |
|||
data: { |
|||
phoneNumber, |
|||
}, |
|||
}) |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 通过谷歌登录 |
|||
*/ |
|||
|
|||
export const postLoginGoogleSimpleAPI = (phoneNumber) => { |
|||
return http({ |
|||
method: 'POST', |
|||
url: '/login/wxMin/simple', |
|||
data: { |
|||
phoneNumber, |
|||
}, |
|||
}) |
|||
} |
|||
|
|||
|
|||
@ -0,0 +1,260 @@ |
|||
/** |
|||
* TCP连接工具类 |
|||
* 用于处理TCP连接、发送消息和断开连接 |
|||
* |
|||
* @format |
|||
*/ |
|||
|
|||
// 引用TCP插件
|
|||
// const TCPSocket = uni.requireNativePlugin('Aimer-TCPPlugin');
|
|||
// 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.channelConnections = new Map(); // 存储每个channel的连接状态
|
|||
this.connectionCallbacks = []; |
|||
this.messageCallbacks = []; |
|||
} |
|||
|
|||
/** |
|||
* TCP初始化连接 |
|||
* @param {Object} config - 连接配置 {ip, port, channel, charsetname} |
|||
* @param {Function} callback - 连接状态回调函数 |
|||
*/ |
|||
connect(config = {}, callback = null) { |
|||
const channel = config.channel || TCP_CONFIG.channel; |
|||
|
|||
// 如果该channel已经连接,先断开现有连接
|
|||
if (this.channelConnections.get(channel)) { |
|||
console.log(`检测到channel ${channel}现有TCP连接,先断开...`); |
|||
this.disconnect(config); |
|||
// 等待断开完成后再连接
|
|||
setTimeout(() => { |
|||
this._performConnect(config, callback); |
|||
}, 300); |
|||
} else { |
|||
// 直接连接
|
|||
this._performConnect(config, callback); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 执行TCP连接 |
|||
* @param {Object} config - 连接配置 |
|||
* @param {Function} callback - 连接状态回调函数 |
|||
*/ |
|||
_performConnect(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; |
|||
} |
|||
|
|||
console.log('开始建立TCP连接:', connectionConfig); |
|||
TCPSocket.connect( |
|||
connectionConfig, |
|||
result => { |
|||
/** |
|||
* status : 0 连接成功 |
|||
* status : 1 断开连接 |
|||
* receivedMsg : 服务器返回字符串(普通的字符串交互) |
|||
* receivedHexMsg : 服务器返回字节数组(单片机、智能家居等硬件数据交互) |
|||
*/ |
|||
if (result.status == '0') { |
|||
// TCP连接成功
|
|||
this.channelConnections.set(connectionConfig.channel, true); |
|||
console.log(`TCP连接成功 - Channel ${connectionConfig.channel}`); |
|||
this._notifyConnectionCallbacks('connected', result, connectionConfig.channel); |
|||
} else if (result.status == '1') { |
|||
// TCP断开连接
|
|||
this.channelConnections.set(connectionConfig.channel, false); |
|||
console.log(`TCP断开连接 - Channel ${connectionConfig.channel}`); |
|||
this._notifyConnectionCallbacks('disconnected', result, connectionConfig.channel); |
|||
} |
|||
|
|||
if (result.receivedMsg) { |
|||
// 服务器返回字符串
|
|||
console.log('收到字符串消息:', result.receivedMsg); |
|||
this._notifyMessageCallbacks('string', result.receivedMsg, null, connectionConfig.channel); |
|||
} |
|||
|
|||
// 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 = {}) { |
|||
const channel = config.channel || '1'; |
|||
|
|||
if (!this.channelConnections.get(channel)) { |
|||
console.warn(`TCP Channel ${channel}未连接,无法发送消息`); |
|||
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 channel = config.channel || TCP_CONFIG.channel; |
|||
const disconnectConfig = { |
|||
channel: channel |
|||
}; |
|||
|
|||
TCPSocket.disconnect(disconnectConfig); |
|||
this.channelConnections.set(channel, false); |
|||
console.log(`TCP连接已断开 - Channel ${channel}`, 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); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 获取连接状态 |
|||
* @param {String} channel - 要检查的channel,如果不指定则返回所有channel的连接状态 |
|||
* @returns {Boolean|Object} 连接状态 |
|||
*/ |
|||
getConnectionStatus(channel = null) { |
|||
if (channel) { |
|||
return this.channelConnections.get(channel) || false; |
|||
} |
|||
// 返回所有channel的连接状态
|
|||
const allConnections = {}; |
|||
for (const [ch, status] of this.channelConnections) { |
|||
allConnections[ch] = status; |
|||
} |
|||
return allConnections; |
|||
} |
|||
|
|||
/** |
|||
* 通知连接状态回调 |
|||
* @private |
|||
*/ |
|||
_notifyConnectionCallbacks(status, result, channel) { |
|||
this.connectionCallbacks.forEach(callback => { |
|||
try { |
|||
callback(status, result, channel); |
|||
} catch (error) { |
|||
console.error('连接状态回调执行错误:', error); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 通知消息回调 |
|||
* @private |
|||
*/ |
|||
_notifyMessageCallbacks(type, message, parsedArray = null, channel = null) { |
|||
this.messageCallbacks.forEach(callback => { |
|||
try { |
|||
callback(type, message, parsedArray, channel); |
|||
} 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,536 @@ |
|||
<template> |
|||
<view class="titleContent"> |
|||
<view class="left"> |
|||
<uni-icons |
|||
@click="handleBack" |
|||
type="back" |
|||
size="23" |
|||
color="#111" |
|||
></uni-icons> |
|||
</view> |
|||
<view class="title">深度探索</view> |
|||
<view class="right"> |
|||
<image |
|||
class="notice" |
|||
src="/static/deepExploration-images/notice.png" |
|||
mode="aspectFill" |
|||
></image> |
|||
<image |
|||
@click="openHistoryDrawer" |
|||
class="history" |
|||
src="/static/deepExploration-images/history.png" |
|||
mode="aspectFill" |
|||
></image> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="drawer-overlay" v-show="showHistoryDrawer"></view> |
|||
|
|||
<view |
|||
class="drawer-panel" |
|||
v-show="showHistoryDrawer" |
|||
@click.stop |
|||
@touchmove.stop.prevent |
|||
:style="{ transform: 'translateY(' + drawerOffsetY + 'px)' }" |
|||
> |
|||
<view class="drawer-header"> |
|||
<text class="drawer-title">历史对话</text> |
|||
<view class="drawer-actions"> |
|||
<view class="delete-all-container"> |
|||
<image |
|||
class="delete-icon" |
|||
src="/static/icons/Group_48095481.svg" |
|||
></image> |
|||
<text class="delete-all" @click="clearAllHistory">删除全部</text> |
|||
</view> |
|||
<view class="drawer-close" @click="onDrawerBackClick" |
|||
><text class="drawer-close-icon"></text |
|||
></view> |
|||
</view> |
|||
</view> |
|||
<scroll-view scroll-y="true" class="drawer-content"> |
|||
<view class="drawer-inner"> |
|||
<view v-if="groupedHistory.length === 0" class="empty-history"> |
|||
<text>暂无历史记录</text> |
|||
</view> |
|||
<view |
|||
v-for="(section, sIdx) in groupedHistory" |
|||
:key="sIdx" |
|||
class="history-section" |
|||
> |
|||
<text class="section-title">{{ section.title }}</text> |
|||
<view |
|||
v-for="(item, idx) in section.items" |
|||
:key="idx" |
|||
class="history-item" |
|||
> |
|||
<view class="history-left"> |
|||
<view class="flag-circle" |
|||
><text class="flag-emoji">🇺🇸</text></view |
|||
> |
|||
</view> |
|||
<view class="history-main" @click="itemClick(item)"> |
|||
<text class="history-query">{{ item.stockName }}</text> |
|||
<text class="history-query">({{ item.stockCode }})</text> |
|||
</view> |
|||
<text class="history-time">{{ |
|||
formatTimeForHistory(item.createdTime) |
|||
}}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</scroll-view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { RecordListApi } from "../api/deepExploration/deepExploration"; |
|||
import { ref, onMounted, computed } from "vue"; |
|||
|
|||
const props = defineProps({ |
|||
name: { |
|||
type: String, |
|||
default: "", |
|||
}, |
|||
}); |
|||
const showHistoryDrawer = ref(false); |
|||
const drawerOffsetY = ref(0); |
|||
// const handleHistory = () => { |
|||
// showHistoryDrawer.value = true; |
|||
// }; |
|||
|
|||
// 历史记录 |
|||
const openHistoryDrawer = async () => { |
|||
const res = await RecordListApi({ |
|||
model: 1, |
|||
}); |
|||
|
|||
if (res.code === 200) { |
|||
historyList.value = res.data; |
|||
} |
|||
|
|||
console.log("historyList.value", historyList.value); |
|||
|
|||
const hideDistance = uni.upx2px(900); |
|||
drawerOffsetY.value = hideDistance; |
|||
showHistoryDrawer.value = true; |
|||
setTimeout(() => { |
|||
drawerOffsetY.value = 0; |
|||
}, 10); |
|||
}; |
|||
|
|||
const clearAllHistory = () => { |
|||
searchHistory.value = []; |
|||
|
|||
// uni.setStorageSync("search_history", []); |
|||
}; |
|||
|
|||
//返回上一页 |
|||
const handleBack = () => { |
|||
uni.navigateBack(); |
|||
}; |
|||
|
|||
const closeHistoryDrawer = () => { |
|||
showHistoryDrawer.value = false; |
|||
}; |
|||
const onDrawerBackClick = () => { |
|||
const hideDistance = uni.upx2px(900); |
|||
drawerOffsetY.value = hideDistance; |
|||
setTimeout(() => { |
|||
closeHistoryDrawer(); |
|||
drawerOffsetY.value = 0; |
|||
}, 180); |
|||
}; |
|||
|
|||
// 历史记录详情 |
|||
async function itemClick(item) { |
|||
// const res = await postHistoryDetail({ |
|||
// recordId: item.id, |
|||
// parentId: item.parentId, |
|||
// model: 5, |
|||
// }); |
|||
// if (res.code == 200) { |
|||
// const message = res.data.wokeFlowData.One.markdown; |
|||
// messages.value = []; |
|||
// const botMsg = { |
|||
// content: message, |
|||
// isUser: false, |
|||
// isTyping: false, |
|||
// isThinking: false, |
|||
// }; |
|||
// messages.value.push(botMsg); |
|||
// } |
|||
} |
|||
const historyList = ref([ |
|||
{ |
|||
title: "今天", // 分组标题(如“今天”“昨天”“更早”) |
|||
items: [ |
|||
{ |
|||
icon: "/static/deepExploration-images/Americle.png", |
|||
stockName: "TechCore", // 股票名称 |
|||
stockCode: "600001", // 6位数字股票代码 |
|||
createdTime: "14:35", // 时间格式(时:分) |
|||
}, |
|||
{ |
|||
icon: "/static/deepExploration-images/Americle.png", |
|||
stockName: "MediaLink", |
|||
stockCode: "600002", |
|||
createdTime: "10:12", |
|||
}, |
|||
], |
|||
}, |
|||
{ |
|||
title: "昨天", |
|||
items: [ |
|||
{ |
|||
icon: "/static/deepExploration-images/Americle.png", |
|||
stockName: "FinServ", |
|||
stockCode: "600003", |
|||
createdTime: "09:48", |
|||
}, |
|||
], |
|||
}, |
|||
]); |
|||
|
|||
// 为历史记录格式化时间:YYYY-MM-DD HH:mm |
|||
const formatTimeForHistory = (timeString) => { |
|||
// 假设 timeString 格式为 "YYYY-MM-DD HH:mm:ss" |
|||
const parts = timeString.split(" "); |
|||
if (parts.length >= 2) { |
|||
const datePart = parts[0]; |
|||
const timePart = parts[1]; |
|||
const timeParts = timePart.split(":"); |
|||
if (timeParts.length >= 2) { |
|||
return `${datePart} ${timeParts[0]}:${timeParts[1]}`; |
|||
} |
|||
} |
|||
return timeString; |
|||
}; |
|||
|
|||
// 历史分组(今天/昨天/近一周/按月) |
|||
const groupedHistory = computed(() => { |
|||
const sections = []; |
|||
|
|||
// 从缓存获取今天日期,如果没有则使用当前日期 |
|||
const now = new Date(); |
|||
|
|||
const startOfDay = (d) => |
|||
new Date(d.getFullYear(), d.getMonth(), d.getDate()); |
|||
const isSameDay = (a, b) => |
|||
startOfDay(a).getTime() === startOfDay(b).getTime(); |
|||
const isYesterday = (d) => { |
|||
const y = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1); |
|||
return isSameDay(d, y); |
|||
}; |
|||
const isToday = (d) => isSameDay(d, now); |
|||
const withinLast7Days = (d) => { |
|||
const seven = new Date( |
|||
now.getFullYear(), |
|||
now.getMonth(), |
|||
now.getDate() - 7 |
|||
); |
|||
return d >= seven && !isToday(d) && !isYesterday(d); |
|||
}; |
|||
const monthLabel = (d) => `${d.getMonth() + 1}月`; |
|||
|
|||
const today = []; |
|||
const yesterday = []; |
|||
const last7 = []; |
|||
const byMonth = new Map(); |
|||
|
|||
// 使用 historyList.value 替代 searchHistory.value |
|||
historyList.value.forEach((item) => { |
|||
// 根据你的数据结构,使用 createdTime 字段 |
|||
const dt = new Date(item.createdTime); |
|||
if (isToday(dt)) { |
|||
today.push(item); |
|||
} else if (isYesterday(dt)) { |
|||
yesterday.push(item); |
|||
} else if (withinLast7Days(dt)) { |
|||
last7.push(item); |
|||
} else { |
|||
const year = dt.getFullYear(); |
|||
const month = dt.getMonth() + 1; |
|||
const key = `${year}-${month}`; |
|||
if (!byMonth.has(key)) |
|||
byMonth.set(key, { |
|||
title: `${year}年${month}月`, |
|||
year, |
|||
month, |
|||
items: [], |
|||
}); |
|||
byMonth.get(key).items.push(item); |
|||
} |
|||
}); |
|||
|
|||
if (today.length) sections.push({ title: "今天", items: today }); |
|||
if (yesterday.length) sections.push({ title: "昨天", items: yesterday }); |
|||
if (last7.length) sections.push({ title: "近一周", items: last7 }); |
|||
|
|||
const monthSections = Array.from(byMonth.values()).sort((a, b) => { |
|||
if (a.year !== b.year) return b.year - a.year; |
|||
return b.month - a.month; // 月份倒序,如 10月 在 9月 之前 |
|||
}); |
|||
sections.push(...monthSections); |
|||
|
|||
return sections; |
|||
}); |
|||
|
|||
onMounted(() => {}); |
|||
</script> |
|||
|
|||
<style scoped lang="scss"> |
|||
* { |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
.titleContent { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
padding: 30rpx 60rpx 40rpx 35rpx; |
|||
box-shadow: 2rpx 2rpx 8rpx rgba(0, 0, 0, 0.1); |
|||
|
|||
.left { |
|||
display: flex; |
|||
align-items: center; |
|||
width: 36rpx; |
|||
height: 36rpx; |
|||
} |
|||
|
|||
.title { |
|||
position: absolute; |
|||
left: 50%; |
|||
transform: translateX(-50%); |
|||
color: #000000; |
|||
font-family: "PingFang SC"; |
|||
font-size: 19px; |
|||
font-style: normal; |
|||
font-weight: 400; |
|||
line-height: 25px; |
|||
} |
|||
|
|||
.right { |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 20rpx; |
|||
|
|||
.notice { |
|||
width: 35rpx; |
|||
height: 35rpx; |
|||
gap: 20rpx; |
|||
} |
|||
|
|||
.history { |
|||
width: 32rpx; |
|||
height: 32rpx; |
|||
align-items: center; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/* 搜索历史侧拉框样式 */ |
|||
.drawer-overlay { |
|||
position: fixed; |
|||
left: 0; |
|||
top: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
background-color: rgba(0, 0, 0, 0.35); |
|||
z-index: 900; |
|||
} |
|||
|
|||
.drawer-panel { |
|||
position: fixed; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
height: 75vh; |
|||
max-height: 80vh; |
|||
width: 100%; |
|||
background: #ffffff; |
|||
box-shadow: 0 -8rpx 20rpx rgba(0, 0, 0, 0.06); |
|||
z-index: 1000; |
|||
display: flex; |
|||
flex-direction: column; |
|||
border-top-left-radius: 20rpx; |
|||
border-top-right-radius: 20rpx; |
|||
transition: transform 0.22s ease; |
|||
} |
|||
|
|||
.drawer-back { |
|||
position: absolute; |
|||
left: 50%; |
|||
top: -14px; |
|||
transform: translateX(-50%); |
|||
width: 28px; |
|||
height: 48px; |
|||
border-radius: 12px; |
|||
background: #fff; |
|||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08); |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.drawer-back-icon { |
|||
font-size: 16px; |
|||
color: #8a8a8a; |
|||
} |
|||
|
|||
.drawer-actions { |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 40rpx; |
|||
} |
|||
|
|||
.delete-all-container { |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 14rpx; |
|||
} |
|||
|
|||
.delete-icon { |
|||
width: 28rpx; |
|||
height: 32rpx; |
|||
} |
|||
|
|||
.delete-all { |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
.drawer-close { |
|||
background: url("../static/icons/关闭2.svg"); |
|||
width: 48rpx; |
|||
height: 48rpx; |
|||
border-radius: 24rpx; |
|||
/* background: #f5f5f5; */ |
|||
/* box-shadow: 0 2px 8px rgba(0,0,0,0.08); */ |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
|
|||
image { |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
} |
|||
|
|||
.drawer-header { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
padding: 52rpx 28rpx 0rpx 28rpx; |
|||
/* border-bottom: 2rpx solid #f0f0f0; */ |
|||
} |
|||
|
|||
.drawer-title { |
|||
font-size: 32rpx; |
|||
font-weight: 600; |
|||
color: #333333; |
|||
} |
|||
|
|||
.drawer-content { |
|||
flex: 1; |
|||
min-height: 0; |
|||
/* 让 flex 子元素可在容器内收缩以启用滚动 */ |
|||
height: 100%; |
|||
overscroll-behavior-y: contain; |
|||
/* 防止滚动串联到页面 */ |
|||
-webkit-overflow-scrolling: touch; |
|||
/* iOS 惯性滚动 */ |
|||
touch-action: pan-y; |
|||
/* 优化触控滚动,仅垂直 */ |
|||
} |
|||
|
|||
.drawer-inner { |
|||
padding: 20rpx 24rpx 20rpx 24rpx; |
|||
} |
|||
|
|||
.history-section { |
|||
margin-bottom: 20rpx; |
|||
/* margin: 0 24rpx; */ |
|||
} |
|||
|
|||
.section-title { |
|||
font-size: 26rpx; |
|||
color: #888; |
|||
margin: 10rpx 6rpx 16rpx; |
|||
} |
|||
|
|||
.history-item { |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 19rpx 18rpx; |
|||
background-color: #f6f7f9; |
|||
border-radius: 12rpx; |
|||
margin-bottom: 12rpx; |
|||
} |
|||
|
|||
.history-left { |
|||
margin-right: 20rpx; |
|||
width: 50rpx; |
|||
height: 50rpx; |
|||
} |
|||
|
|||
.flag-circle { |
|||
width: 50rpx; |
|||
height: 50rpx; |
|||
border-radius: 50%; |
|||
background: #fff; |
|||
border: 2rpx solid #eee; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
image { |
|||
width: 50rpx; |
|||
height: 50rpx; |
|||
border-radius: 50%; |
|||
} |
|||
} |
|||
|
|||
.history-main { |
|||
flex: 1; |
|||
} |
|||
|
|||
.history-query { |
|||
color: #000000; |
|||
text-align: center; |
|||
font-size: 24rpx; |
|||
font-weight: 400; |
|||
line-height: 40rpx; |
|||
} |
|||
|
|||
.history-time { |
|||
font-size: 22rpx; |
|||
color: #999; |
|||
} |
|||
|
|||
.history-card { |
|||
background-color: #fff; |
|||
border: 2rpx solid #f2f2f2; |
|||
border-left: 8rpx solid rgb(220, 31, 29); |
|||
border-radius: 12rpx; |
|||
padding: 18rpx 20rpx; |
|||
margin-bottom: 16rpx; |
|||
box-shadow: 0 4rpx 10rpx rgba(0, 0, 0, 0.03); |
|||
} |
|||
|
|||
.history-query { |
|||
font-size: 28rpx; |
|||
color: #333333; |
|||
font-weight: 500; |
|||
} |
|||
|
|||
.history-time { |
|||
margin-top: 8rpx; |
|||
font-size: 22rpx; |
|||
color: #888888; |
|||
} |
|||
|
|||
.empty-history { |
|||
padding: 40rpx; |
|||
color: #999999; |
|||
text-align: center; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,183 @@ |
|||
<template> |
|||
<view class="login-prompt" v-if="showPrompt"> |
|||
<view class="mask" :class="{ 'mask-show': showAnimation }"></view> |
|||
<view class="prompt-content" :class="{ 'slide-up': showAnimation }"> |
|||
<text class="prompt-title">登录以获得更好的体验</text> |
|||
<button class="login-btn" @click="goLogin">登录</button> |
|||
<button class="visitor-btn" @click="continueAsVisitor"> |
|||
以访客身份继续 |
|||
</button> |
|||
<text class="prompt-title-small" @click="goRegister" |
|||
>如果您还没有账号,点击注册</text |
|||
> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, nextTick, onMounted } from "vue"; |
|||
import { useUserStore } from "../stores/modules/userInfo"; |
|||
import { useDeviceStore } from "../stores/modules/deviceInfo"; |
|||
import { LoginApi } from "../api/start/login"; |
|||
const deviceId = ref(""); |
|||
|
|||
const userStore = useUserStore(); |
|||
const deviceStore = useDeviceStore(); |
|||
// 初始化 |
|||
onMounted(() => { |
|||
if (!userStore.userInfo) { |
|||
show(); |
|||
} |
|||
}); |
|||
|
|||
// 定义响应式数据 |
|||
const showPrompt = ref(false); |
|||
const showAnimation = ref(false); |
|||
|
|||
// 显示弹窗 |
|||
const show = () => { |
|||
showPrompt.value = true; |
|||
// 在下一帧触发动画 |
|||
nextTick(() => { |
|||
setTimeout(() => { |
|||
showAnimation.value = true; |
|||
}, 10); |
|||
}); |
|||
}; |
|||
|
|||
// 隐藏弹窗 |
|||
const hide = () => { |
|||
showAnimation.value = false; |
|||
// 等待动画结束后再隐藏 |
|||
setTimeout(() => { |
|||
showPrompt.value = false; |
|||
}, 300); |
|||
}; |
|||
|
|||
// 跳转到登录页面 |
|||
const goLogin = () => { |
|||
uni.navigateTo({ |
|||
url: "/pages/start/login/login", |
|||
}); |
|||
hide(); |
|||
}; |
|||
// 跳转到登录页面 |
|||
const goRegister = () => { |
|||
uni.navigateTo({ |
|||
url: "/pages/start/Registration/Registration", |
|||
}); |
|||
hide(); |
|||
}; |
|||
|
|||
// 以访客身份继续 |
|||
const continueAsVisitor = async () => { |
|||
// 设置访客模式 |
|||
const res = await LoginApi({ |
|||
loginType: "VISITOR", //登录方式EMAIL,PHONE,DCCODE,APPLE,GOOGLE,VISITOR |
|||
account: "", //登陆账号 手机号/邮箱/dccode |
|||
verifyCode: "", //验证码 |
|||
password: "", //密码 |
|||
useCode: "", //是否使用验证码 true/false |
|||
idToken: "", //第三方登录idToken |
|||
deviceId: deviceStore.deviceInfo.deviceId, |
|||
}); |
|||
|
|||
if (res.code === 200) { |
|||
userStore.setUserInfo(res.data); |
|||
hide(); |
|||
} |
|||
}; |
|||
|
|||
// 暴露方法给外部使用 |
|||
defineExpose({ |
|||
show, |
|||
hide, |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.login-prompt { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
z-index: 999; |
|||
} |
|||
|
|||
.mask { |
|||
position: absolute; |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
background-color: rgba(0, 0, 0, 0.8); |
|||
opacity: 0; |
|||
transition: opacity 0.3s ease; |
|||
} |
|||
|
|||
.mask.mask-show { |
|||
opacity: 1; |
|||
} |
|||
|
|||
.prompt-content { |
|||
position: absolute; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
height: 400rpx; |
|||
border-radius: 20rpx 20rpx 0 0; |
|||
background-color: white; |
|||
padding: 20rpx 70rpx; |
|||
transform: translateY(100%); |
|||
transition: transform 0.3s ease; |
|||
box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.3); |
|||
} |
|||
|
|||
.prompt-content.slide-up { |
|||
transform: translateY(0); |
|||
} |
|||
|
|||
.prompt-title { |
|||
display: block; |
|||
text-align: center; |
|||
font-size: 40rpx; |
|||
font-weight: 700; |
|||
color: #000000; |
|||
margin-top: 30rpx; |
|||
margin-bottom: 40rpx; |
|||
} |
|||
|
|||
.login-btn { |
|||
width: 100%; |
|||
height: 80rpx; |
|||
background-color: rgb(0, 0, 0); |
|||
color: white; |
|||
font-size: 32rpx; |
|||
line-height: 80rpx; |
|||
border-radius: 40rpx; |
|||
margin-bottom: 20rpx; |
|||
} |
|||
|
|||
.visitor-btn { |
|||
width: 100%; |
|||
height: 80rpx; |
|||
background-color: #f5f5f5; |
|||
color: #333; |
|||
font-size: 32rpx; |
|||
line-height: 80rpx; |
|||
border-radius: 40rpx; |
|||
} |
|||
.prompt-title-small { |
|||
display: block; |
|||
text-align: center; |
|||
font-size: 24rpx; |
|||
color: #6a6a6a; |
|||
margin-top: 30rpx; |
|||
margin-bottom: 40rpx; |
|||
line-height: 15.5px; |
|||
letter-spacing: 0.3px; |
|||
font-style: normal; |
|||
font-family: "PingFang SC"; |
|||
} |
|||
</style> |
|||
@ -1,5 +1,13 @@ |
|||
{ |
|||
"dependencies": { |
|||
"vue-i18n": "^9.14.5" |
|||
"@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" |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,100 @@ |
|||
<template> |
|||
|
|||
<view class="blank-page"> |
|||
<view class="header" :style="{ paddingTop: safeAreaInsets?.top + 'px' }"> |
|||
<!-- 返回按钮 --> |
|||
<view class="head-left"> |
|||
<image class="back-button" @click="goBack" src="/static/icons/Left_(左).png"> |
|||
|
|||
|
|||
<!-- <text class="tip">当前特斯拉该如何布局?</text> --> |
|||
</image> |
|||
</view> |
|||
<view class="header-center"> |
|||
<text class="title" :style="{ paddingTop: safeAreaInsets?.top + 'px' }" |
|||
>机构动向解析</text |
|||
> |
|||
</view> |
|||
</view> |
|||
<image class="picture" src="/static/images/缺省.png" /> |
|||
<text class="tip">暂无内容~</text> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
// 返回到 deepMate 页面 |
|||
const goBack = () => { |
|||
uni.navigateTo({ |
|||
url: '/pages/deepMate/deepMate' |
|||
}); |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.blank-page { |
|||
display: flex; |
|||
flex-direction: column; |
|||
position: fixed; |
|||
/* 充满视口,彻底禁用页面滚动 */ |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
height: 100vh; |
|||
overflow: hidden; |
|||
/* 锁定页面滚动 */ |
|||
background-color: #ffffff; |
|||
padding: 20rpx 0rpx; |
|||
} |
|||
.header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 20rpx 30rpx; |
|||
background-color: #ffffff; |
|||
box-shadow: 0 2rpx rgba(0, 0, 0, 0.1); |
|||
} |
|||
.head-left { |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
.back-button { |
|||
width: 40rpx; |
|||
height: 40rpx; |
|||
} |
|||
.header-center .title { |
|||
position: fixed; |
|||
top: 25rpx; |
|||
left: 50%; |
|||
transform: translateX(-50%); |
|||
font-size: 36rpx; |
|||
font-weight: bold; |
|||
color: #333333; |
|||
} |
|||
.back-button:hover { |
|||
background-color: #e0e0e0; |
|||
} |
|||
|
|||
.back-button:active { |
|||
transform: scale(0.95); |
|||
} |
|||
|
|||
.back-icon { |
|||
font-size: 32rpx; |
|||
color: #333333; |
|||
margin-right: 10rpx; |
|||
} |
|||
|
|||
.picture { |
|||
display: block; |
|||
margin: 200rpx auto 0; /* 图片水平居中 */ |
|||
width: 60%; |
|||
height: 600rpx; |
|||
} |
|||
.tip { |
|||
color: #999999; |
|||
font-size: 28rpx; |
|||
text-align: center; |
|||
margin-top: 20rpx; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,100 @@ |
|||
<template> |
|||
|
|||
<view class="blank-page"> |
|||
<view class="header" :style="{ paddingTop: safeAreaInsets?.top + 'px' }"> |
|||
<!-- 返回按钮 --> |
|||
<view class="head-left"> |
|||
<image class="back-button" @click="goBack" src="/static/icons/Left_(左).png"> |
|||
|
|||
|
|||
<!-- <text class="tip">当前特斯拉该如何布局?</text> --> |
|||
</image> |
|||
</view> |
|||
<view class="header-center"> |
|||
<text class="title" :style="{ paddingTop: safeAreaInsets?.top + 'px' }" |
|||
>消息推送通知</text |
|||
> |
|||
</view> |
|||
</view> |
|||
<image class="picture" src="/static/images/缺省.png" /> |
|||
<text class="tip">暂无内容~</text> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
// 返回到 deepMate 页面 |
|||
const goBack = () => { |
|||
uni.navigateTo({ |
|||
url: '/pages/deepMate/deepMate' |
|||
}); |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.blank-page { |
|||
display: flex; |
|||
flex-direction: column; |
|||
position: fixed; |
|||
/* 充满视口,彻底禁用页面滚动 */ |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
height: 100vh; |
|||
overflow: hidden; |
|||
/* 锁定页面滚动 */ |
|||
background-color: #ffffff; |
|||
padding: 20rpx 0rpx; |
|||
} |
|||
.header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 20rpx 30rpx; |
|||
background-color: #ffffff; |
|||
box-shadow: 0 2rpx rgba(0, 0, 0, 0.1); |
|||
} |
|||
.head-left { |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
.back-button { |
|||
width: 40rpx; |
|||
height: 40rpx; |
|||
} |
|||
.header-center .title { |
|||
position: fixed; |
|||
top: 25rpx; |
|||
left: 50%; |
|||
transform: translateX(-50%); |
|||
font-size: 36rpx; |
|||
font-weight: bold; |
|||
color: #333333; |
|||
} |
|||
.back-button:hover { |
|||
background-color: #e0e0e0; |
|||
} |
|||
|
|||
.back-button:active { |
|||
transform: scale(0.95); |
|||
} |
|||
|
|||
.back-icon { |
|||
font-size: 32rpx; |
|||
color: #333333; |
|||
margin-right: 10rpx; |
|||
} |
|||
|
|||
.picture { |
|||
display: block; |
|||
margin: 200rpx auto 0; /* 图片水平居中 */ |
|||
width: 60%; |
|||
height: 600rpx; |
|||
} |
|||
.tip { |
|||
color: #999999; |
|||
font-size: 28rpx; |
|||
text-align: center; |
|||
margin-top: 20rpx; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,801 @@ |
|||
<template> |
|||
<view class="main"> |
|||
<!-- 顶部状态栏占位 --> |
|||
<view class="top" :style="{height:iSMT+'px'}"></view> |
|||
<deepExploration_header></deepExploration_header> |
|||
|
|||
<view class="search"> |
|||
<input v-model="searchName" class="searchInput" type="text" placeholder="请输入股票名称、股票代码" |
|||
placeholder-style="color: #A6A6A6; font-size: 22rpx;" /> |
|||
<image @click="searchStock" class="seachIcon" src="/static/deepExploration-images/search.png" |
|||
mode="aspectFill"></image> |
|||
</view> |
|||
|
|||
<view class="content"> |
|||
<view class="select"> |
|||
<image class="img" :src="navItems[currentIndex].icon" mode=""></image> |
|||
<view v-for="(item, index) in navItems" :key="index" class="selectItem" |
|||
:class="{ active: currentIndex === index }" @click="handleModel(index)"> |
|||
<button class="btn"></button> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="graphAndTxt"> |
|||
<view class="graph"> |
|||
<view class="graph_header"> |
|||
<view class="left">TESA</view> |
|||
<view class="center"> |
|||
<image class="last" src="/static/deepExploration-images/last.png" mode="aspectFill"></image> |
|||
<text>Taewlkj.sejssssssssf</text> |
|||
<image class="next" src="/static/deepExploration-images/next.png" mode="aspectFill"></image> |
|||
</view> |
|||
<view class="right">2025/10/26</view> |
|||
</view> |
|||
<view class="graph_data"> |
|||
<text>435.900</text> |
|||
<text>22.410</text> |
|||
<text>5.120%</text> |
|||
</view> |
|||
<view class="graph_content"> |
|||
<view class="charts-box"> |
|||
<!-- uCharts 蜡烛图组件 --> |
|||
<qiun-data-charts type="candle" :opts="opts" :chartData="chartData" :disableScroll="true" |
|||
:ontouch="true" :onzoom="true" /> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view class="txt"> |
|||
<view class="txtHeader"> |
|||
<image src="/static/deepExploration-images/plus.png" mode="aspectFill"></image> |
|||
<text>主力追踪</text> |
|||
</view> |
|||
<view class="txtContent"></view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 底部切换栏 --> |
|||
<footerBar class="static-footer" :type="type"></footerBar> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { |
|||
ref, |
|||
onMounted |
|||
} from 'vue' |
|||
import deepExploration_header from '@/components/deepExploration_header.vue' |
|||
import footerBar from '@/components/footerBar.vue' |
|||
import { |
|||
onLoad |
|||
} from '@dcloudio/uni-app' |
|||
import { |
|||
getModel1First, |
|||
getModel1Second, |
|||
getModel2First, |
|||
getModel2Second, |
|||
getModel3First, |
|||
getModel3Second, |
|||
getModel4First, |
|||
getModel4Second, |
|||
} from '/api/deepExploration/deepExploration.js' |
|||
|
|||
// 响应式变量定义 |
|||
const type = ref('deepExploration') |
|||
const iSMT = ref(0) |
|||
const currentIndex = ref(0) |
|||
const navItems = ref([{ |
|||
name: '主力追踪', |
|||
icon: '/static/deepExploration-images/1.png' |
|||
}, |
|||
{ |
|||
name: '主力雷达', |
|||
icon: '/static/deepExploration-images/2.png' |
|||
}, |
|||
{ |
|||
name: '主力解码', |
|||
icon: '/static/deepExploration-images/3.png' |
|||
}, |
|||
{ |
|||
name: '主力资金流', |
|||
icon: '/static/deepExploration-images/4.png' |
|||
}, |
|||
]) |
|||
|
|||
//搜索股票 |
|||
const searchStock = () => { |
|||
console.log('搜索参数:', stockName.value); |
|||
if (currentIndex.value == 0) { |
|||
handleModel(0) |
|||
} else if (currentIndex.value == 1) { |
|||
console.log(index); |
|||
handleModel(1) |
|||
} else if (currentIndex.value == 2) { |
|||
console.log(index); |
|||
handleModel(2) |
|||
} else if (currentIndex.value == 3) { |
|||
console.log(index); |
|||
handleModel(3) |
|||
}else{ |
|||
uni.showToast({ |
|||
title: '请选择模块', |
|||
icon: 'none', |
|||
duration: 2000 |
|||
}) |
|||
} |
|||
|
|||
} |
|||
//点击四大模块 |
|||
const handleModel = (index) => { |
|||
currentIndex.value = index |
|||
if (currentIndex.value == 0) { |
|||
console.log(index); |
|||
handleTrack() |
|||
} else if (currentIndex.value == 1) { |
|||
console.log(index); |
|||
handleRadar() |
|||
} else if (currentIndex.value == 2) { |
|||
console.log(index); |
|||
handleDecode() |
|||
} else if (currentIndex.value == 3) { |
|||
console.log(index); |
|||
handleCapitalFlow() |
|||
} |
|||
} |
|||
|
|||
const stockName = ref('') |
|||
const searchName = ref('') |
|||
const stockCode = ref('') |
|||
const language = ref('') |
|||
const recordId = ref('') |
|||
const parentId = ref('') |
|||
const stockId = ref('') |
|||
//点击主力追踪 |
|||
const handleTrack = async () => { |
|||
try { |
|||
const result = await getModel1First({ |
|||
content: searchName.value, |
|||
language: "cn", |
|||
marketList: "hk,cn,usa,my,sg,vi,in,gb", |
|||
model: 1 |
|||
}) |
|||
console.log('result', result); |
|||
if (result.code == 200) { |
|||
stockCode.value = result.data.code |
|||
stockName.value = result.data.name |
|||
recordId.value = result.data.recordId |
|||
parentId.value = result.data.parentId |
|||
stockId.value = result.data.stockId |
|||
language.value = result.data.language |
|||
const res = await getModel1Second({ |
|||
language: language.value, |
|||
recordId: recordId.value, |
|||
parentId: parentId.value, |
|||
stockId: stockId.value |
|||
}) |
|||
console.log('res', res); |
|||
} |
|||
|
|||
} catch { |
|||
|
|||
} |
|||
} |
|||
|
|||
//点击主力雷达 |
|||
const handleRadar = () => { |
|||
|
|||
} |
|||
|
|||
//点击主力解码 |
|||
const handleDecode = () => { |
|||
|
|||
} |
|||
|
|||
//点击主力资金流 |
|||
const handleCapitalFlow = () => { |
|||
|
|||
} |
|||
|
|||
|
|||
// 1. K线图配置 |
|||
const opts = ref({ |
|||
rotate: false, |
|||
rotateLock: false, |
|||
color: ["#1890FF", "#91CB74", "#FAC858", "#EE6666", "#73C0DE", "#3CA272", "#FC8452", "#9A60B4", "#ea7ccc"], |
|||
padding: [15, 15, 0, 15], |
|||
dataLabel: false, |
|||
enableScroll: true, |
|||
enableMarkLine: false, |
|||
legend: {}, |
|||
xAxis: { |
|||
labelCount: 4, |
|||
itemCount: 30, |
|||
disableGrid: true, |
|||
gridColor: "#CCCCCC", |
|||
gridType: "solid", |
|||
dashLength: 4, |
|||
scrollShow: false, |
|||
scrollAlign: "left", |
|||
scrollColor: "#A6A6A6", |
|||
scrollBackgroundColor: "#EFEBEF", |
|||
labelColor: "#8C8C8C", |
|||
fontSize: 9 |
|||
}, |
|||
yAxis: { |
|||
labelColor: "#8C8C8C", |
|||
fontSize: 9 |
|||
}, |
|||
extra: { |
|||
candle: { |
|||
color: { |
|||
upLine: "#f04864", |
|||
upFill: "#f04864", |
|||
downLine: "#2fc25b", |
|||
downFill: "#2fc25b" |
|||
}, |
|||
average: { |
|||
show: false, |
|||
name: ["MA5", "MA10", "MA30"], |
|||
day: [5, 10, 20], |
|||
color: ["#1890ff", "#2fc25b", "#facc14"] |
|||
} |
|||
}, |
|||
markLine: { |
|||
type: "dash", |
|||
dashLength: 5, |
|||
data: [{ |
|||
value: 2150, |
|||
lineColor: "#f04864", |
|||
showLabel: false |
|||
}, |
|||
{ |
|||
value: 2350, |
|||
lineColor: "#f04864", |
|||
showLabel: false |
|||
} |
|||
] |
|||
}, |
|||
tooltip: { |
|||
showCategory: true |
|||
} |
|||
} |
|||
}) |
|||
|
|||
// 2. K线图数据(响应式定义) |
|||
const chartData = ref({}) |
|||
|
|||
// 获取K线数据函数(直接定义,无需methods) |
|||
const getServerData = () => { |
|||
// 模拟服务器请求延时 |
|||
setTimeout(() => { |
|||
const res = { |
|||
"categories": [ |
|||
"2025/08/25", |
|||
"2025/08/26", |
|||
"2025/08/27", |
|||
"2025/08/28", |
|||
"2025/08/29", |
|||
"2025/09/01", |
|||
"2025/09/02", |
|||
"2025/09/03", |
|||
"2025/09/04", |
|||
"2025/09/05", |
|||
"2025/09/08", |
|||
"2025/09/09", |
|||
"2025/09/10", |
|||
"2025/09/11", |
|||
"2025/09/12", |
|||
"2025/09/15", |
|||
"2025/09/16", |
|||
"2025/09/17", |
|||
"2025/09/18", |
|||
"2025/09/19", |
|||
"2025/09/22", |
|||
"2025/09/23", |
|||
"2025/09/24", |
|||
"2025/09/25", |
|||
"2025/09/26", |
|||
"2025/09/29", |
|||
"2025/09/30", |
|||
"2025/10/09", |
|||
"2025/10/10", |
|||
"2025/10/13", |
|||
"2025/10/14", |
|||
"2025/10/15", |
|||
"2025/10/16", |
|||
"2025/10/17", |
|||
"2025/10/20", |
|||
"2025/10/21", |
|||
"2025/10/22", |
|||
"2025/10/23", |
|||
"2025/10/24", |
|||
"2025/10/27" |
|||
], |
|||
series: [{ |
|||
"name": "贵州茅台", |
|||
"data": [ |
|||
[ |
|||
1470.01, |
|||
1496.0, |
|||
1466.0, |
|||
1499.33 |
|||
], |
|||
[ |
|||
1490.32, |
|||
1474.23, |
|||
1480.01, |
|||
1481.61 |
|||
], |
|||
[ |
|||
1481.88, |
|||
1484.93, |
|||
1448.0, |
|||
1448.0 |
|||
], |
|||
[ |
|||
1447.97, |
|||
1456.1, |
|||
1438.77, |
|||
1446.1 |
|||
], |
|||
[ |
|||
1453.0, |
|||
1482.58, |
|||
1452.0, |
|||
1480.0 |
|||
], |
|||
[ |
|||
1482.2, |
|||
1488.0, |
|||
1465.7, |
|||
1476.1 |
|||
], |
|||
[ |
|||
1478.66, |
|||
1509.0, |
|||
1478.0, |
|||
1491.3 |
|||
], |
|||
[ |
|||
1491.0, |
|||
1503.5, |
|||
1466.0, |
|||
1480.55 |
|||
], |
|||
[ |
|||
1472.0, |
|||
1479.3, |
|||
1460.47, |
|||
1480.66 |
|||
], |
|||
[ |
|||
1471.0, |
|||
1486.97, |
|||
1464.0, |
|||
1483.0 |
|||
], |
|||
[ |
|||
1483.0, |
|||
1506.44, |
|||
1477.5, |
|||
1501.23 |
|||
], |
|||
[ |
|||
1505.0, |
|||
1509.95, |
|||
1493.42, |
|||
1505.0 |
|||
], |
|||
[ |
|||
1506.66, |
|||
1529.95, |
|||
1496.0, |
|||
1522.01 |
|||
], |
|||
[ |
|||
1522.01, |
|||
1526.02, |
|||
1508.5, |
|||
1523.5 |
|||
], |
|||
[ |
|||
1526.0, |
|||
1538.02, |
|||
1510.53, |
|||
1516.0 |
|||
], |
|||
[ |
|||
1515.87, |
|||
1517.48, |
|||
1501.5, |
|||
1515.1 |
|||
], |
|||
[ |
|||
1515.1, |
|||
1520.99, |
|||
1496.21, |
|||
1499.98 |
|||
], |
|||
[ |
|||
1499.99, |
|||
1510.28, |
|||
1490.01, |
|||
1493.0 |
|||
], |
|||
[ |
|||
1492.0, |
|||
1497.8, |
|||
1463.5, |
|||
1467.96 |
|||
], |
|||
[ |
|||
1467.99, |
|||
1475.5, |
|||
1457.01, |
|||
1467.97 |
|||
], |
|||
[ |
|||
1465.09, |
|||
1467.97, |
|||
1450.01, |
|||
1453.35 |
|||
], |
|||
[ |
|||
1450.5, |
|||
1457.5, |
|||
1440.0, |
|||
1447.42 |
|||
], |
|||
[ |
|||
1434.07, |
|||
1456.78, |
|||
1434.07, |
|||
1442.0 |
|||
], |
|||
[ |
|||
1442.83, |
|||
1445.21, |
|||
1436.0, |
|||
1439.0 |
|||
], |
|||
[ |
|||
1441.18, |
|||
1447.11, |
|||
1428.01, |
|||
1435.0 |
|||
], |
|||
[ |
|||
1439.38, |
|||
1469.99, |
|||
1435.0, |
|||
1460.86 |
|||
], |
|||
[ |
|||
1460.0, |
|||
1460.76, |
|||
1440.0, |
|||
1443.99 |
|||
], |
|||
[ |
|||
1436.0, |
|||
1439.38, |
|||
1420.0, |
|||
1436.78 |
|||
], |
|||
[ |
|||
1437.6, |
|||
1439.94, |
|||
1427.5, |
|||
1430.0 |
|||
], |
|||
[ |
|||
1415.7, |
|||
1422.85, |
|||
1415.12, |
|||
1419.2 |
|||
], |
|||
[ |
|||
1429.99, |
|||
1464.0, |
|||
1429.99, |
|||
1451.02 |
|||
], |
|||
[ |
|||
1450.98, |
|||
1463.0, |
|||
1445.08, |
|||
1462.0 |
|||
], |
|||
[ |
|||
1461.92, |
|||
1484.95, |
|||
1458.88, |
|||
1484.91 |
|||
], |
|||
[ |
|||
1483.1, |
|||
1488.0, |
|||
1454.03, |
|||
1455.0 |
|||
], |
|||
[ |
|||
1455.0, |
|||
1469.5, |
|||
1454.88, |
|||
1457.93 |
|||
], |
|||
[ |
|||
1459.0, |
|||
1469.94, |
|||
1455.5, |
|||
1462.26 |
|||
], |
|||
[ |
|||
1462.08, |
|||
1465.73, |
|||
1456.0, |
|||
1458.7 |
|||
], |
|||
[ |
|||
1455.0, |
|||
1468.8, |
|||
1447.2, |
|||
1467.98 |
|||
], |
|||
[ |
|||
1467.95, |
|||
1478.88, |
|||
1449.34, |
|||
1450.0 |
|||
], |
|||
[ |
|||
1440.0, |
|||
1452.49, |
|||
1435.99, |
|||
1440.41 |
|||
] |
|||
], |
|||
}] |
|||
} |
|||
// 给响应式变量赋值(需修改.value) |
|||
chartData.value = JSON.parse(JSON.stringify(res)) |
|||
}, 500) |
|||
} |
|||
|
|||
// 生命周期钩子:组件挂载后执行(替代onReady) |
|||
onMounted(() => { |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight |
|||
getServerData() // 调用数据获取函数 |
|||
}) |
|||
|
|||
// 页面加载时执行 |
|||
onLoad((e) => { |
|||
if (e.index) { |
|||
currentIndex.value = e.index - 1 |
|||
console.log('模块:', currentIndex.value) |
|||
} |
|||
if (e.stockName) { |
|||
stockName.value = e.stockName |
|||
console.log('股票名称:', stockName.value) |
|||
} |
|||
}) |
|||
</script> |
|||
|
|||
<style scoped lang="scss"> |
|||
.main { |
|||
width: 100%; |
|||
height: 100vh; |
|||
background-color: #fff; |
|||
|
|||
.search { |
|||
position: relative; |
|||
display: flex; |
|||
align-items: center; |
|||
background-color: #F3F3F3; |
|||
width: calc(100% - 60rpx); |
|||
height: 80rpx; |
|||
border-radius: 50rpx; |
|||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1); |
|||
padding: 0 40rpx; |
|||
margin: 15rpx 30rpx 0 30rpx; |
|||
|
|||
.seachIcon { |
|||
position: absolute; |
|||
right: 50rpx; |
|||
width: 32rpx; |
|||
height: 32rpx; |
|||
} |
|||
|
|||
.searchInput { |
|||
color: #111; |
|||
} |
|||
} |
|||
|
|||
.content { |
|||
margin-top: 30rpx; |
|||
padding-top: 30rpx; |
|||
background-color: rgb(248, 248, 248); |
|||
|
|||
.select { |
|||
position: relative; |
|||
margin-bottom: -5rpx; |
|||
|
|||
.img { |
|||
width: 750rpx; |
|||
height: 198rpx; |
|||
} |
|||
|
|||
.selectItem { |
|||
.btn { |
|||
position: absolute; |
|||
width: 120rpx; |
|||
height: 150rpx; |
|||
background-color: transparent; |
|||
|
|||
&::after { |
|||
border: none; |
|||
} |
|||
} |
|||
|
|||
&:nth-of-type(1) .btn { |
|||
top: 30rpx; |
|||
left: 60rpx; |
|||
} |
|||
|
|||
&:nth-of-type(2) .btn { |
|||
top: 30rpx; |
|||
left: 230rpx; |
|||
} |
|||
|
|||
&:nth-of-type(3) .btn { |
|||
top: 30rpx; |
|||
left: 400rpx; |
|||
} |
|||
|
|||
&:nth-of-type(4) .btn { |
|||
top: 30rpx; |
|||
left: 570rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.graphAndTxt { |
|||
height: 300rpx; |
|||
background-color: #fff; |
|||
border-radius: 50rpx 50rpx 0 0; |
|||
padding: 68.6rpx 36.5rpx 0 36.5rpx; |
|||
|
|||
.graph { |
|||
border: 1rpx solid #e2e2e2; |
|||
border-radius: 30rpx 30rpx 0 0; |
|||
|
|||
.graph_header { |
|||
padding: 32rpx 20.5rpx 0 24rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
|
|||
.left { |
|||
color: #333333; |
|||
font-family: "PingFang SC"; |
|||
font-size: 15px; |
|||
font-style: normal; |
|||
font-weight: 400; |
|||
line-height: 15px; |
|||
} |
|||
|
|||
.center { |
|||
margin-left: 105rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
|
|||
text { |
|||
width: 160rpx; |
|||
height: 36rpx; |
|||
padding-left: 10rpx; |
|||
color: #000000; |
|||
white-space: nowrap; |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
text-align: center; |
|||
font-family: "PingFang SC"; |
|||
font-size: 18px; |
|||
font-style: normal; |
|||
font-weight: 500; |
|||
line-height: 18px; |
|||
} |
|||
|
|||
.last { |
|||
width: 15rpx; |
|||
height: 20rpx; |
|||
margin-right: 30rpx; |
|||
} |
|||
|
|||
.next { |
|||
width: 15rpx; |
|||
height: 20rpx; |
|||
margin-left: 30rpx; |
|||
} |
|||
} |
|||
|
|||
.right { |
|||
margin-left: 50rpx; |
|||
color: #6a6a6a; |
|||
font-family: "PingFang SC"; |
|||
font-size: 13px; |
|||
font-style: normal; |
|||
font-weight: 400; |
|||
line-height: 15px; |
|||
} |
|||
} |
|||
|
|||
.graph_data { |
|||
display: flex; |
|||
padding: 48rpx 24rpx; |
|||
|
|||
text { |
|||
display: flex; |
|||
color: #25ba5d; |
|||
font-family: "PingFang SC"; |
|||
font-size: 17px; |
|||
line-height: 17px; |
|||
} |
|||
|
|||
text:nth-child(2) { |
|||
margin-left: 120rpx; |
|||
} |
|||
|
|||
text:nth-child(3) { |
|||
margin-left: 150rpx; |
|||
} |
|||
} |
|||
|
|||
.graph_content { |
|||
.charts-box { |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.txt { |
|||
background-color: #F3F3F3; |
|||
margin-top: 48rpx; |
|||
border-radius: 30rpx; |
|||
|
|||
.txtHeader { |
|||
padding: 30rpx 24rpx; |
|||
|
|||
image { |
|||
width: 20rpx; |
|||
height: 20rpx; |
|||
} |
|||
|
|||
text { |
|||
background-color: #FFFFFF; |
|||
color: #000000; |
|||
padding: 0 22rpx; |
|||
border-radius: 22rpx; |
|||
font-size: 28rpx; |
|||
font-weight: 400; |
|||
line-height: 37rpx; |
|||
} |
|||
} |
|||
|
|||
.txtContent { |
|||
min-height: 200rpx; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.static-footer { |
|||
position: fixed; |
|||
bottom: 0; |
|||
width: 100%; |
|||
} |
|||
} |
|||
|
|||
* { |
|||
box-sizing: border-box; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,427 @@ |
|||
<template> |
|||
<view class="main"> |
|||
<!-- 顶部状态栏占位 --> |
|||
<view class="top" :style="{height:iSMT+'px'}"></view> |
|||
<!-- 标题图标部分 --> |
|||
<deepExploration_header></deepExploration_header> |
|||
<view class="search"> |
|||
<input v-model="stockName" class="searchInput" type="text" placeholder="请输入股票名称、股票代码" |
|||
placeholder-style="color: #A6A6A6; font-size: 22rpx;" /> |
|||
<image @click="searchStock" class="seachIcon" src="/static/deepExploration-images/search.png" |
|||
mode="aspectFill"></image> |
|||
</view> |
|||
|
|||
<!-- 四大功能模块 --> |
|||
<view class="select"> |
|||
<view class="selectItem" @click="toMain('主力追踪')"> |
|||
<image class="img" src="/static/deepExploration-images/icon3.png" mode="aspectFill"></image> |
|||
<view class="txt">主力追踪</view> |
|||
</view> |
|||
<view class="selectItem" @click="toMain('主力雷达')"> |
|||
<image class="img" src="/static/deepExploration-images/icon2.png" mode="aspectFill"></image> |
|||
<view class="txt">主力雷达</view> |
|||
</view> |
|||
<view class="selectItem" @click="toMain('主力解码')"> |
|||
<image class="img" src="/static/deepExploration-images/icon1.png" mode="aspectFill"></image> |
|||
<view class="txt">主力解码</view> |
|||
</view> |
|||
<view class="selectItem" @click="toMain('主力资金流')"> |
|||
<image class="img" src="/static/deepExploration-images/icon4.png" mode="aspectFill"></image> |
|||
<view class="txt">主力资金流</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 灰色间隔 --> |
|||
<view class="gap"></view> |
|||
<!-- 选股策略 --> |
|||
<view class="stockSelection"> |
|||
<view class="stockSelection_top"> |
|||
<view class="txt"> |
|||
<text>选股策略</text> |
|||
</view> |
|||
<view class="viewAll" @click='viewAll'> |
|||
<text>查看全部</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="stockSelection_content"> |
|||
<view class="selectionItem"> |
|||
<view class="header"> |
|||
<view class="left"> |
|||
<image src="/static/deepExploration-images/plus.png" mode="aspectFill"></image> |
|||
<text>抄底卖顶</text> |
|||
</view> |
|||
<view class="right"> |
|||
<image src="/static/deepExploration-images/Americle.png" mode="aspectFill"></image> |
|||
<text>美股</text> |
|||
</view> |
|||
|
|||
</view> |
|||
<view class="content"> |
|||
<view class="contentTitle"> |
|||
<view class="contentTitle_name">股票名称</view> |
|||
<view class="contentTitle_close">最新收盘价</view> |
|||
<view class="contentTitle_price">选股价格</view> |
|||
</view> |
|||
<view class="contentItem"> |
|||
<view class="row" v-for="(item,index) in stockData" :key="index"> |
|||
<view class="nameItem">{{item.name}}</view> |
|||
<view class="closeItem">{{item.close}}</view> |
|||
<view class="priceItem">{{item.select}}</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="stockSelection_content"> |
|||
<view class="selectionItem"> |
|||
<view class="header"> |
|||
<view class="left"> |
|||
<image src="/static/deepExploration-images/plus.png" mode="aspectFill"></image> |
|||
<text>抄底卖顶</text> |
|||
</view> |
|||
<view class="right"> |
|||
<image src="/static/deepExploration-images/Americle.png" mode="aspectFill"></image> |
|||
<text>美股</text> |
|||
</view> |
|||
</view> |
|||
<view class="content"> |
|||
<view class="contentTitle"> |
|||
<view class="contentTitle_name">股票名称</view> |
|||
<view class="contentTitle_close">最新收盘价</view> |
|||
<view class="contentTitle_price">选股价格</view> |
|||
</view> |
|||
<view class="contentItem"> |
|||
<view class="row" v-for="(item,index) in stockData" :key="index"> |
|||
<view class="nameItem">{{item.name}}</view> |
|||
<view class="closeItem">{{item.close}}</view> |
|||
<view class="priceItem">{{item.select}}</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</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 deepExploration_header from '@/components/deepExploration_header.vue' |
|||
|
|||
const type = ref('deepExploration') |
|||
const iSMT = ref(0) |
|||
|
|||
//查看全部选股策略 |
|||
const toMain = (val) => { |
|||
if (val == '主力追踪') { |
|||
uni.navigateTo({ |
|||
url: '/pages/deepExploration/MainForceActions?index=1' |
|||
}) |
|||
} else if (val == '主力雷达') { |
|||
uni.navigateTo({ |
|||
url: '/pages/deepExploration/MainForceActions?index=2' |
|||
}) |
|||
} else if (val == '主力解码') { |
|||
uni.navigateTo({ |
|||
url: '/pages/deepExploration/MainForceActions?index=3' |
|||
}) |
|||
} else if (val == '主力资金流') { |
|||
uni.navigateTo({ |
|||
url: '/pages/deepExploration/MainForceActions?index=4' |
|||
}) |
|||
} |
|||
|
|||
} |
|||
|
|||
const stockName = ref('') |
|||
//搜索股票 |
|||
const searchStock = () => { |
|||
console.log('搜索参数:', stockName.value); |
|||
uni.navigateTo({ |
|||
url: `/pages/deepExploration/MainForceActions?stockName=${stockName.value}` |
|||
}) |
|||
} |
|||
|
|||
//查看全部选股策略 |
|||
const viewAll = () => { |
|||
uni.navigateTo({ |
|||
url: '/pages/deepExploration/stockSelectDetail' |
|||
}) |
|||
} |
|||
//选股策略数据 |
|||
const stockData = [{ |
|||
name: "(MKTW)MarketWise Inc", |
|||
close: "$14.190", |
|||
select: "$13.180" |
|||
}, |
|||
{ |
|||
name: "(MTCH)Match Group Inc", |
|||
close: "$32.120", |
|||
select: "$28.120" |
|||
}, |
|||
{ |
|||
name: "(MKTW)MarketWise Inc", |
|||
close: "$14.190", |
|||
select: "$13.180" |
|||
} |
|||
]; |
|||
onMounted(() => { |
|||
// 状态栏高度 |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
}) |
|||
</script> |
|||
|
|||
<style scoped lang="scss"> |
|||
.main { |
|||
width: 100%; |
|||
height: 100vh; |
|||
background-color: #fff; |
|||
|
|||
.search { |
|||
position: relative; |
|||
display: flex; |
|||
align-items: center; |
|||
background-color: #F3F3F3; |
|||
width: calc(100% - 60rpx); |
|||
height: 80rpx; |
|||
border-radius: 50rpx; |
|||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1); |
|||
padding: 0 40rpx; |
|||
margin: 15rpx 30rpx 0 30rpx; |
|||
|
|||
.seachIcon { |
|||
position: absolute; |
|||
right: 50rpx; |
|||
width: 32rpx; |
|||
height: 32rpx; |
|||
} |
|||
|
|||
.searchInput { |
|||
color: #111; |
|||
} |
|||
} |
|||
|
|||
.select { |
|||
display: flex; |
|||
padding: 60rpx 10rpx 30rpx 30rpx; |
|||
gap: 70rpx; |
|||
align-items: center; |
|||
justify-content: center; |
|||
|
|||
.selectItem { |
|||
.img { |
|||
width: 80rpx; |
|||
height: 80rpx; |
|||
display: block; |
|||
margin: 0 auto; |
|||
} |
|||
|
|||
.txt { |
|||
color: #6a6a6a; |
|||
font-family: "PingFang SC"; |
|||
font-size: 11px; |
|||
font-style: normal; |
|||
font-weight: 400; |
|||
line-height: 14.5px; |
|||
margin-top: 13rpx; |
|||
white-space: nowrap; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.gap { |
|||
width: 100%; |
|||
height: 15rpx; |
|||
background-color: #F3F3F3; |
|||
} |
|||
|
|||
.stockSelection { |
|||
width: 100%; |
|||
padding: 32rpx 15rpx; |
|||
|
|||
.stockSelection_top { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
|
|||
.txt { |
|||
color: #000000; |
|||
font-family: "PingFang SC"; |
|||
font-size: 38rpx; |
|||
font-style: normal; |
|||
font-weight: 400; |
|||
line-height: 50rpx; |
|||
} |
|||
|
|||
.viewAll { |
|||
background-color: #000000; |
|||
border-radius: 10rpx; |
|||
padding: 6rpx 20rpx; |
|||
color: #ffffff; |
|||
font-family: "PingFang SC"; |
|||
font-size: 10rpx; |
|||
font-style: normal; |
|||
font-weight: 100; |
|||
line-height: 29rpx; |
|||
height: 40rpx; |
|||
} |
|||
} |
|||
|
|||
.stockSelection_content { |
|||
.selectionItem { |
|||
background-color: #F3F3F3; |
|||
padding: 30rpx 15rpx 17rpx 30rpx; |
|||
border-radius: 30rpx; |
|||
margin-top: 30rpx; |
|||
|
|||
.header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
|
|||
.left { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
|
|||
image { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
width: 15rpx; |
|||
height: 15rpx; |
|||
} |
|||
|
|||
text { |
|||
margin-left: 15rpx; |
|||
color: #000000; |
|||
font-family: "PingFang SC"; |
|||
font-size: 28rpx; |
|||
font-style: normal; |
|||
font-weight: 400; |
|||
line-height: 18.5px; |
|||
} |
|||
} |
|||
|
|||
.right { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
border-radius: 15rpx; |
|||
background-color: #FFFFFF; |
|||
padding: 6rpx 20rpx; |
|||
|
|||
image { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
width: 40rpx; |
|||
height: 26.5rpx; |
|||
} |
|||
|
|||
text { |
|||
margin-left: 10rpx; |
|||
color: #6a6a6a; |
|||
font-family: "PingFang SC"; |
|||
font-size: 18rpx; |
|||
font-style: normal; |
|||
font-weight: 400; |
|||
line-height: 24rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.content { |
|||
.contentTitle { |
|||
display: flex; |
|||
color: #6a6a6a; |
|||
font-family: "PingFang SC"; |
|||
font-size: 11px; |
|||
font-style: normal; |
|||
font-weight: 400; |
|||
line-height: 14.5px; |
|||
margin-top: 24rpx; |
|||
margin-bottom: 20rpx; |
|||
|
|||
.contentTitle_name { |
|||
width: 100rpx; |
|||
} |
|||
|
|||
.contentTitle_close { |
|||
width: 130rpx; |
|||
margin-left: 260rpx; |
|||
} |
|||
|
|||
.contentTitle_price { |
|||
width: 120rpx; |
|||
margin-left: 60rpx; |
|||
} |
|||
|
|||
} |
|||
|
|||
.contentItem { |
|||
.row { |
|||
display: flex; |
|||
box-shadow: 0 -2rpx 5rpx rgba(0, 0, 0, 0.05); |
|||
padding: 10rpx 0; |
|||
margin-bottom: 10rpx; |
|||
|
|||
.nameItem { |
|||
width: 260rpx; |
|||
white-space: nowrap; |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
color: #000000; |
|||
font-family: "PingFang SC"; |
|||
font-size: 13px; |
|||
font-style: normal; |
|||
font-weight: 400; |
|||
line-height: 17.5px; |
|||
} |
|||
|
|||
.closeItem { |
|||
width: 120rpx; |
|||
margin-left: 100rpx; |
|||
color: #25ba5d; |
|||
font-family: "PingFang SC"; |
|||
font-size: 13px; |
|||
font-style: normal; |
|||
font-weight: 400; |
|||
line-height: 17.5px; |
|||
} |
|||
|
|||
.priceItem { |
|||
width: 120rpx; |
|||
margin-left: 73rpx; |
|||
color: #25ba5d; |
|||
font-family: "PingFang SC"; |
|||
font-size: 13px; |
|||
font-style: normal; |
|||
font-weight: 400; |
|||
line-height: 17.5px; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
.static-footer { |
|||
position: fixed; |
|||
bottom: 0; |
|||
} |
|||
} |
|||
|
|||
* { |
|||
box-sizing: border-box; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,354 @@ |
|||
<template> |
|||
<view class="main"> |
|||
<view class="table"> |
|||
<view class="tableHeader"> |
|||
<scroll-view class="tabs" scroll-x="true"> |
|||
<view v-for="(item,index) in tabsData" :key="index" class="tabItem" @click="handleTab(item)"> |
|||
{{item}} |
|||
</view> |
|||
</scroll-view> |
|||
</view> |
|||
<view class="tableContent"> |
|||
<image class="showAll" src="/static/deepExploration-images/showAll.png" mode="aspectFill"></image> |
|||
<scroll-view scroll-x="true" show-scrollbar="false"> |
|||
<view class="tableBox"> |
|||
<view class="box_header"> |
|||
<view class="name">名称</view> |
|||
<view class="other" v-for="(item,index) in tableContentHeaderData" :key="index"> |
|||
<text>{{item}}</text> |
|||
<image v-show="ifASC" src="/static/deepExploration-images/ASC.png" mode="aspectFill"> |
|||
</image> |
|||
<image v-show="!ifASC" src="/static/deepExploration-images/DESC.png" mode="aspectFill"> |
|||
</image> |
|||
</view> |
|||
</view> |
|||
<view class="box_content"> |
|||
<view class="row" v-for="(item,index) in fakeData" :key="index" :class="{ 'increase-positive': item.increase.startsWith('+'), |
|||
'increase-negative': item.increase.startsWith('-')}"> |
|||
<view class="name_colum"> |
|||
<text class="stockName">{{item.name}}</text> |
|||
<text class="stockCode">{{item.stockCode}}</text> |
|||
</view> |
|||
<view class="other_colum">{{item.latest}}</view> |
|||
<view class="other_colum">{{item.increase}}</view> |
|||
<view class="other_colum">{{item.decrease}}</view> |
|||
<view class="other_colum">{{item.previousClose}}</view> |
|||
<view class="other_colum">{{item.volume}}</view> |
|||
<view class="other_colum">{{item.turnover}}</view> |
|||
<view class="other_colum">{{item.openingPrice}}</view> |
|||
<view class="other_colum">{{item.highestPrice}}</view> |
|||
<view class="other_colum">{{item.lowestPrice}}</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</scroll-view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { |
|||
ref |
|||
} from 'vue' |
|||
|
|||
const tabsData = ref(['全部', '抄底卖顶', '波段行情', '价值投资', '资金及仓位管理', '价值投资', '价值投资', '价值投资', ]) |
|||
const handleTab = (item) => { |
|||
uni.showToast({ |
|||
title: `查看 ${item} 详情`, |
|||
icon: 'none', |
|||
duration: 2000 |
|||
}) |
|||
} |
|||
//表头是否升序 |
|||
const ifASC = ref(true) |
|||
//表头数据 |
|||
const tableContentHeaderData = ref(['最新', '涨幅', '跌幅', '昨收', '成交量', '成交额', '开盘价', '最高价', '最低价']) |
|||
const fakeData = [{ |
|||
name: "TechCore", |
|||
stockCode: "600001", |
|||
latest: 1315.00, |
|||
increase: "+5.2%", |
|||
decrease: "+5.2%", |
|||
previousClose: 1250.00, |
|||
volume: 12000, |
|||
turnover: "15780K", |
|||
openingPrice: 1237.50, |
|||
highestPrice: 1320.00, |
|||
lowestPrice: 1230.00 |
|||
}, |
|||
{ |
|||
name: "MediaLink", |
|||
stockCode: "600002", |
|||
latest: 1138.70, |
|||
increase: "-3.5%", |
|||
decrease: "-3.5%", |
|||
previousClose: 1180.00, |
|||
volume: 8500, |
|||
turnover: "967.9K", |
|||
openingPrice: 1191.80, |
|||
highestPrice: 1195.00, |
|||
lowestPrice: 1130.00 |
|||
}, |
|||
{ |
|||
name: "FinServ", |
|||
stockCode: "600003", |
|||
latest: 1413.72, |
|||
increase: "+7.1%", |
|||
decrease: "+7.1%", |
|||
previousClose: 1320.00, |
|||
volume: 15000, |
|||
turnover: "2120.6K", |
|||
openingPrice: 1293.60, |
|||
highestPrice: 1420.00, |
|||
lowestPrice: 1290.00 |
|||
}, |
|||
{ |
|||
name: "AutoDrive", |
|||
stockCode: "600004", |
|||
latest: 1080.40, |
|||
increase: "+2.8%", |
|||
decrease: "+2.8%", |
|||
previousClose: 1050.00, |
|||
volume: 9000, |
|||
turnover: "972.4K", |
|||
openingPrice: 1055.25, |
|||
highestPrice: 1085.00, |
|||
lowestPrice: 1050.00 |
|||
}, |
|||
{ |
|||
name: "EduSmart", |
|||
stockCode: "600005", |
|||
latest: 968.24, |
|||
increase: "-1.2%", |
|||
decrease: "-1.2%", |
|||
previousClose: 980.00, |
|||
volume: 7000, |
|||
turnover: "677.8K", |
|||
openingPrice: 975.10, |
|||
highestPrice: 978.00, |
|||
lowestPrice: 965.00 |
|||
}, |
|||
{ |
|||
name: "HealthPlusqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", |
|||
stockCode: "600006", |
|||
latest: 1463.00, |
|||
increase: "+4.5%", |
|||
decrease: "+4.5%", |
|||
previousClose: 1400.00, |
|||
volume: 13000, |
|||
turnover: "1901.9K", |
|||
openingPrice: 1393.00, |
|||
highestPrice: 1470.00, |
|||
lowestPrice: 1385.00 |
|||
}, |
|||
{ |
|||
name: "AgriTech", |
|||
stockCode: "600007", |
|||
latest: 1038.36, |
|||
increase: "+1.8%", |
|||
decrease: "+1.8%", |
|||
previousClose: 1020.00, |
|||
volume: 6500, |
|||
turnover: "674.9K", |
|||
openingPrice: 1028.16, |
|||
highestPrice: 1040.00, |
|||
lowestPrice: 1025.00 |
|||
}, |
|||
{ |
|||
name: "LogiFlow", |
|||
stockCode: "600008", |
|||
latest: 1094.24, |
|||
increase: "-2.3%", |
|||
decrease: "-2.3%", |
|||
previousClose: 1120.00, |
|||
volume: 8000, |
|||
turnover: "875.4K", |
|||
openingPrice: 1122.24, |
|||
highestPrice: 1125.00, |
|||
lowestPrice: 1090.00 |
|||
}, |
|||
{ |
|||
name: "EnergySol", |
|||
stockCode: "600009", |
|||
latest: 1435.05, |
|||
increase: "+6.3%", |
|||
decrease: "+6.3%", |
|||
previousClose: 1350.00, |
|||
volume: 14000, |
|||
turnover: "2009.1K", |
|||
openingPrice: 1339.75, |
|||
highestPrice: 1440.00, |
|||
lowestPrice: 1335.00 |
|||
}, |
|||
{ |
|||
name: "RealEstate", |
|||
stockCode: "600010", |
|||
latest: 995.00, |
|||
increase: "-0.5%", |
|||
decrease: "-0.5%", |
|||
previousClose: 1000.00, |
|||
volume: 7500, |
|||
turnover: "746.3K", |
|||
openingPrice: 1003.00, |
|||
highestPrice: 1005.00, |
|||
lowestPrice: 990.00 |
|||
} |
|||
]; |
|||
</script> |
|||
|
|||
<style scoped lang="scss"> |
|||
.main { |
|||
width: 100%; |
|||
height: 100vh; |
|||
background-color: #fff; |
|||
|
|||
|
|||
.table { |
|||
margin-top: 10rpx; |
|||
box-shadow: 0 -2rpx 3rpx -1rpx rgba(0, 0, 0, 0.5); |
|||
|
|||
.tableHeader { |
|||
.tabs { |
|||
white-space: nowrap; |
|||
padding-top: 20rpx; |
|||
padding-left: 40rpx; |
|||
|
|||
::-webkit-scrollbar { |
|||
//隐藏 滚动条 |
|||
display: none; |
|||
} |
|||
|
|||
.tabItem { |
|||
display: inline-block; |
|||
color: rgb(175, 175, 175); |
|||
border-radius: 10rpx; |
|||
padding: 5rpx 30rpx; |
|||
margin-right: 20rpx; |
|||
font-size: 28rpx; |
|||
background-color: rgb(243, 243, 243); |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
.tableContent { |
|||
width: 100%; |
|||
|
|||
position: relative; |
|||
|
|||
.showAll { |
|||
position: absolute; |
|||
top: 35rpx; |
|||
right: 20rpx; |
|||
width: 40rpx; |
|||
height: 40rpx; |
|||
z-index: 100; |
|||
} |
|||
|
|||
scroll-view { |
|||
width: 100%; |
|||
white-space: nowrap; |
|||
|
|||
::-webkit-scrollbar { |
|||
//隐藏 滚动条 |
|||
display: none; |
|||
} |
|||
|
|||
} |
|||
|
|||
.tableBox { |
|||
padding-left: 40rpx; |
|||
|
|||
.box_header { |
|||
margin-bottom: 19rpx; |
|||
display: flex; |
|||
width: max-content; |
|||
margin-top: 40rpx; |
|||
color: rgb(109, 109, 109); |
|||
border-radius: 10rpx; |
|||
margin-right: 20rpx; |
|||
font-size: 23rpx; |
|||
|
|||
|
|||
.name { |
|||
flex: 0 0 375rpx; |
|||
} |
|||
|
|||
.other { |
|||
flex: 0 0 195rpx; |
|||
|
|||
text { |
|||
margin-right: 5rpx; |
|||
} |
|||
|
|||
image { |
|||
width: 20rpx; |
|||
height: 20rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.box_content { |
|||
width: max-content; |
|||
|
|||
.row { |
|||
padding: 5rpx; |
|||
display: flex; |
|||
border-top: 1rpx dashed #eee; |
|||
width: 210%; |
|||
|
|||
&.increase-positive { |
|||
.other_colum { |
|||
color: #2DD357; |
|||
font-weight: 200; |
|||
} |
|||
} |
|||
|
|||
&.increase-negative { |
|||
.other_colum { |
|||
color: #FF4150; |
|||
font-weight: 200; |
|||
} |
|||
} |
|||
|
|||
.name_colum { |
|||
flex: 0 0 375rpx; |
|||
|
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 4rpx; |
|||
|
|||
.stockName { |
|||
color: #333333; |
|||
width: 100%; |
|||
max-width: 305rpx; |
|||
font-size: 28rpx; |
|||
font-weight: 400; |
|||
line-height: 36rpx; |
|||
white-space: nowrap; |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
} |
|||
|
|||
.stockCode { |
|||
color: #c5c5c5; |
|||
; |
|||
font-size: 24rpx; |
|||
font-weight: 400; |
|||
line-height: 30rpx; |
|||
} |
|||
} |
|||
|
|||
.other_colum { |
|||
flex: 0 0 195rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
1733
pages/deepMate/deepMate.vue
File diff suppressed because it is too large
View File
@ -1,28 +0,0 @@ |
|||
<template> |
|||
<view class="main"> |
|||
<!-- 顶部状态栏占位 --> |
|||
<view class="top" :style="{height:iSMT+'px'}"></view> |
|||
<view>深度探索</view> |
|||
<footerBar class="static-footer" :type="type"></footerBar> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref,onMounted } from 'vue' |
|||
import footerBar from '../../components/footerBar.vue' |
|||
|
|||
const type = ref('deepExploration') |
|||
const iSMT = ref(0) |
|||
|
|||
onMounted(() => { |
|||
// 状态栏高度 |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
}) |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.static-footer { |
|||
position: fixed; |
|||
bottom: 0; |
|||
} |
|||
</style> |
|||
1214
pages/home/home.vue
File diff suppressed because it is too large
View File
@ -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 username = ref('演示机EVA') |
|||
const dccode = ref('90047681') |
|||
const goToGeneral = () => { |
|||
uni.navigateTo({ |
|||
url: '/pages/setting/general' |
|||
}) |
|||
} |
|||
|
|||
const goToMarket = () => { |
|||
uni.navigateTo({ |
|||
url: '../setting/market' |
|||
}) |
|||
} |
|||
|
|||
const type = ref('member') |
|||
const iSMT = ref(0) |
|||
const goToAccount = () => { |
|||
uni.navigateTo({ |
|||
url:'../setting/account' |
|||
}) |
|||
} |
|||
|
|||
onMounted(() => { |
|||
// 状态栏高度 |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
}) |
|||
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 |
|||
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,655 @@ |
|||
<template> |
|||
<view style="width: 750rpx; height: 750rpx;"> |
|||
<l-echart ref="chartRef" @finished="initChart"></l-echart> |
|||
</view> |
|||
</template> |
|||
<script setup> |
|||
import { ref, computed, onMounted } from 'vue'; |
|||
|
|||
const chartRef = ref(null) |
|||
// 获取系统信息,替代 window.innerWidth |
|||
const systemInfo = uni.getSystemInfoSync() |
|||
const screenWidth = ref(systemInfo.screenWidth || 375) // 默认值 375px |
|||
|
|||
// 生成30天的交易信号数据 |
|||
const generateAIGoldBullData = () => { |
|||
const data = [] |
|||
|
|||
for (let i = 0; i < 30; i++) { |
|||
// 模拟交易信号 [索引, 买入信号, 卖出信号, 持有信号, 强度, 成交量] |
|||
const buySignal = Math.random() > 0.7 ? 1 : 0 // 30%概率买入信号 |
|||
const sellSignal = Math.random() > 0.8 ? 1 : 0 // 20%概率卖出信号 |
|||
const holdSignal = Math.random() > 0.5 ? 1 : 0 // 50%概率持有信号 |
|||
const strength = Math.floor(Math.random() * 3) + 1 // 信号强度1-3 |
|||
const volume = Math.floor(Math.random() * 2000) + 500 // 成交量500-2500 |
|||
|
|||
data.push([i, buySignal, sellSignal, holdSignal, strength, volume]) |
|||
} |
|||
return data |
|||
} |
|||
|
|||
// 添加缺失的变量定义 |
|||
var option |
|||
const AIGoldBull = ref({ |
|||
JN: generateAIGoldBullData() |
|||
}) |
|||
|
|||
// 模拟多语言数据 |
|||
const t = ref({ |
|||
suoxie: 'zh', |
|||
tianxian: '天线', |
|||
feixian: '飞线', |
|||
zhoongxian: '中线', |
|||
liuxian: '流线', |
|||
Klinetext_5: 'K线5', |
|||
Klinetext_6: 'K线6', |
|||
maipan: '买盘', |
|||
maipan1: '卖盘' |
|||
}) |
|||
|
|||
// 生成30天的模拟K线数据 [日期, 开盘, 最高, 最低, 收盘] |
|||
const generateKLineData = () => { |
|||
const data = [] |
|||
let basePrice = 2450 // 黄金基础价格 |
|||
|
|||
for (let i = 0; i < 30; i++) { |
|||
const date = new Date(2024, 0, i + 1).toISOString().split('T')[0] |
|||
|
|||
// 模拟价格波动 |
|||
const volatility = (Math.random() - 0.5) * 50 // ±25的波动 |
|||
const open = basePrice + volatility |
|||
|
|||
const highVolatility = Math.random() * 30 + 10 // 10-40的向上波动 |
|||
const lowVolatility = Math.random() * 30 + 10 // 10-40的向下波动 |
|||
|
|||
const high = Math.max(open, open + highVolatility) |
|||
const low = Math.min(open, open - lowVolatility) |
|||
|
|||
const closeVolatility = (Math.random() - 0.5) * 20 |
|||
const close = Math.max(low, Math.min(high, open + closeVolatility)) |
|||
|
|||
data.push([date, |
|||
Math.round(open * 100) / 100, |
|||
Math.round(high * 100) / 100, |
|||
Math.round(low * 100) / 100, |
|||
Math.round(close * 100) / 100 |
|||
]) |
|||
|
|||
basePrice = close // 下一天的基础价格 |
|||
} |
|||
return data |
|||
} |
|||
|
|||
// 生成30天的成交量和技术指标数据 [日期, 成交量1, 成交量2, 指标1, 指标2, 指标3] |
|||
const generateWaveVolData = () => { |
|||
const data = [] |
|||
|
|||
for (let i = 0; i < 30; i++) { |
|||
const date = new Date(2024, 0, i + 1).toISOString().split('T')[0] |
|||
|
|||
// 模拟成交量数据 |
|||
const vol1 = Math.floor(Math.random() * 2000) + 800 // 800-2800 |
|||
const vol2 = Math.floor(Math.random() * 1500) + 600 // 600-2100 |
|||
|
|||
// 模拟技术指标 |
|||
const indicator1 = Math.floor(Math.random() * 30) + 40 // 40-70 |
|||
const indicator2 = Math.floor(Math.random() * 40) + 50 // 50-90 |
|||
const indicator3 = Math.floor(Math.random() * 35) + 60 // 60-95 |
|||
|
|||
data.push([date, vol1, vol2, indicator1, indicator2, indicator3]) |
|||
} |
|||
return data |
|||
} |
|||
|
|||
// 生成30天的移动平均线数据 [MA5, MA10, MA20, MA30] |
|||
const generateFTLineData = () => { |
|||
const data = [] |
|||
let ma5Base = 2450 |
|||
let ma10Base = 2445 |
|||
let ma20Base = 2440 |
|||
let ma30Base = 2435 |
|||
|
|||
for (let i = 0; i < 30; i++) { |
|||
// 模拟移动平均线的平滑变化 |
|||
ma5Base += (Math.random() - 0.5) * 10 |
|||
ma10Base += (Math.random() - 0.5) * 8 |
|||
ma20Base += (Math.random() - 0.5) * 6 |
|||
ma30Base += (Math.random() - 0.5) * 4 |
|||
|
|||
data.push([ |
|||
Math.round(ma5Base * 100) / 100, |
|||
Math.round(ma10Base * 100) / 100, |
|||
Math.round(ma20Base * 100) / 100, |
|||
Math.round(ma30Base * 100) / 100 |
|||
]) |
|||
} |
|||
return data |
|||
} |
|||
|
|||
// 生成模拟数据 |
|||
const mockKLineData = generateKLineData() |
|||
const mockWaveVolData = generateWaveVolData() |
|||
const mockFTLineData = generateFTLineData() |
|||
|
|||
// 生成RSI指标数据 (相对强弱指数) |
|||
const generateRSIData = () => { |
|||
const data = [] |
|||
for (let i = 0; i < 30; i++) { |
|||
const rsi = Math.random() * 60 + 20 // RSI值在20-80之间 |
|||
data.push(Math.round(rsi * 100) / 100) |
|||
} |
|||
return data |
|||
} |
|||
|
|||
// 生成MACD指标数据 |
|||
const generateMACDData = () => { |
|||
const data = [] |
|||
for (let i = 0; i < 30; i++) { |
|||
const macd = (Math.random() - 0.5) * 20 // MACD值在-10到10之间 |
|||
const signal = (Math.random() - 0.5) * 15 // 信号线 |
|||
const histogram = macd - signal // 柱状图 |
|||
|
|||
data.push([ |
|||
Math.round(macd * 100) / 100, |
|||
Math.round(signal * 100) / 100, |
|||
Math.round(histogram * 100) / 100 |
|||
]) |
|||
} |
|||
return data |
|||
} |
|||
|
|||
// 生成布林带数据 |
|||
const generateBollingerData = () => { |
|||
const data = [] |
|||
let middleLine = 2450 |
|||
|
|||
for (let i = 0; i < 30; i++) { |
|||
middleLine += (Math.random() - 0.5) * 10 |
|||
const upperBand = middleLine + Math.random() * 30 + 20 // 上轨 |
|||
const lowerBand = middleLine - Math.random() * 30 - 20 // 下轨 |
|||
|
|||
data.push([ |
|||
Math.round(upperBand * 100) / 100, |
|||
Math.round(middleLine * 100) / 100, |
|||
Math.round(lowerBand * 100) / 100 |
|||
]) |
|||
} |
|||
return data |
|||
} |
|||
|
|||
// 生成成交量分析数据 |
|||
const generateVolumeAnalysisData = () => { |
|||
const data = [] |
|||
for (let i = 0; i < 30; i++) { |
|||
const buyVolume = Math.floor(Math.random() * 1500) + 500 // 买入量 |
|||
const sellVolume = Math.floor(Math.random() * 1500) + 500 // 卖出量 |
|||
const netVolume = buyVolume - sellVolume // 净买入量 |
|||
|
|||
data.push([buyVolume, sellVolume, netVolume]) |
|||
} |
|||
return data |
|||
} |
|||
|
|||
// 生成市场情绪数据 |
|||
const generateMarketSentimentData = () => { |
|||
const sentiments = ['极度恐慌', '恐慌', '中性', '贪婪', '极度贪婪'] |
|||
const data = [] |
|||
|
|||
for (let i = 0; i < 30; i++) { |
|||
const sentimentIndex = Math.floor(Math.random() * 100) // 0-100的情绪指数 |
|||
const sentimentLabel = sentiments[Math.floor(sentimentIndex / 20)] |
|||
|
|||
data.push({ |
|||
date: new Date(2024, 0, i + 1).toISOString().split('T')[0], |
|||
index: sentimentIndex, |
|||
label: sentimentLabel, |
|||
fearGreedRatio: Math.random() * 100 |
|||
}) |
|||
} |
|||
return data |
|||
} |
|||
|
|||
// 生成重要新闻事件数据 |
|||
const generateNewsEventsData = () => { |
|||
const events = [ |
|||
'美联储利率决议', |
|||
'非农就业数据发布', |
|||
'通胀数据公布', |
|||
'地缘政治紧张', |
|||
'央行政策变化', |
|||
'经济数据超预期', |
|||
'市场技术突破', |
|||
'大宗商品价格波动' |
|||
] |
|||
|
|||
const data = [] |
|||
for (let i = 0; i < 10; i++) { // 生成10个随机事件 |
|||
const randomDay = Math.floor(Math.random() * 30) + 1 |
|||
const event = events[Math.floor(Math.random() * events.length)] |
|||
const impact = Math.floor(Math.random() * 5) + 1 // 影响力1-5 |
|||
|
|||
data.push({ |
|||
date: new Date(2024, 0, randomDay).toISOString().split('T')[0], |
|||
event: event, |
|||
impact: impact, |
|||
type: Math.random() > 0.5 ? 'positive' : 'negative' |
|||
}) |
|||
} |
|||
return data.sort((a, b) => new Date(a.date) - new Date(b.date)) |
|||
} |
|||
|
|||
// 生成价格预测数据 |
|||
const generatePricePredictionData = () => { |
|||
const data = [] |
|||
let currentPrice = 2450 |
|||
|
|||
for (let i = 0; i < 7; i++) { // 未来7天预测 |
|||
const date = new Date(2024, 1, i + 1).toISOString().split('T')[0] // 2月份 |
|||
|
|||
// 模拟AI预测的价格区间 |
|||
const prediction = currentPrice + (Math.random() - 0.5) * 100 |
|||
const confidence = Math.random() * 40 + 60 // 60-100%的置信度 |
|||
const upperBound = prediction + Math.random() * 50 |
|||
const lowerBound = prediction - Math.random() * 50 |
|||
|
|||
data.push({ |
|||
date: date, |
|||
predicted_price: Math.round(prediction * 100) / 100, |
|||
confidence: Math.round(confidence), |
|||
upper_bound: Math.round(upperBound * 100) / 100, |
|||
lower_bound: Math.round(lowerBound * 100) / 100 |
|||
}) |
|||
|
|||
currentPrice = prediction |
|||
} |
|||
return data |
|||
} |
|||
|
|||
// 模拟提取的绘图数据 |
|||
const extractedDrawData = { |
|||
KLine20: mockKLineData, |
|||
WAVEVOL: mockWaveVolData, |
|||
FTLINE: mockFTLineData, |
|||
RSI: generateRSIData(), |
|||
MACD: generateMACDData(), |
|||
BOLLINGER: generateBollingerData(), |
|||
VOLUME_ANALYSIS: generateVolumeAnalysisData(), |
|||
MARKET_SENTIMENT: generateMarketSentimentData(), |
|||
NEWS_EVENTS: generateNewsEventsData(), |
|||
PRICE_PREDICTION: generatePricePredictionData() |
|||
} |
|||
|
|||
const fnShowEcharts4 = (extractedDrawData) => { |
|||
const splitData = (b) => { |
|||
const a = JSON.parse(JSON.stringify(b)) |
|||
let categoryData = [] |
|||
let values = [] |
|||
for (let i = 0; i < a.length; i++) { |
|||
categoryData.push(a[i].splice(0, 1)[0]) |
|||
values.push(a[i]) |
|||
} |
|||
return { |
|||
categoryData, |
|||
values |
|||
} |
|||
} |
|||
var bodongliang = splitData(extractedDrawData.WAVEVOL) |
|||
function bodongliangData(values, i) { |
|||
return values.map((subArray) => subArray[i]) |
|||
} |
|||
function calculateMA(index, data) { |
|||
let result = [] |
|||
if (data.FTLINE) { |
|||
data.FTLINE.forEach((item) => { |
|||
result.push(item[index]) |
|||
}) |
|||
} |
|||
return result |
|||
} |
|||
function vwToPx(vw) { |
|||
return (screenWidth.value * vw) / 100 |
|||
} |
|||
var dealData = splitData(extractedDrawData.KLine20) |
|||
var dealGnBullData = AIGoldBull.value.JN |
|||
const textEcharts = t.value |
|||
const firstLegend = computed(() => { |
|||
if (screenWidth.value < 768) { |
|||
if (textEcharts.suoxie === 'en' || textEcharts.suoxie === 'th') { |
|||
return '2%' |
|||
} else if (textEcharts.suoxie === 'kr') { |
|||
return '2%' |
|||
} else { |
|||
return '2%' |
|||
} |
|||
} else { |
|||
return textEcharts.suoxie === 'en' || |
|||
textEcharts.suoxie === 'th' || |
|||
textEcharts.suoxie === 'kr' |
|||
? '9%' |
|||
: '9%' |
|||
} |
|||
}) |
|||
const processBarData = (data) => { |
|||
const barData = [] |
|||
data.forEach((item) => { |
|||
let color |
|||
switch (item[4]) { |
|||
case 1: |
|||
color = '#13E113' |
|||
break |
|||
case 2: |
|||
color = '#FF0E00' |
|||
break |
|||
case 3: |
|||
color = '#0000FE' |
|||
break |
|||
case 4: |
|||
color = '#1397FF' |
|||
break |
|||
} |
|||
barData.push({ |
|||
value: item[5], |
|||
itemStyle: { |
|||
normal: { |
|||
color: color |
|||
} |
|||
} |
|||
}) |
|||
}) |
|||
return { barData } |
|||
} |
|||
const { barData } = processBarData(dealGnBullData) |
|||
option = { |
|||
tooltip: { |
|||
trigger: 'axis', |
|||
axisPointer: { |
|||
type: 'cross' |
|||
}, |
|||
backgroundColor: 'rgba(119, 120, 125, 0.6)', |
|||
borderWidth: 1, |
|||
borderColor: '#77787D', |
|||
padding: 10, |
|||
textStyle: { |
|||
color: '#fff' |
|||
} |
|||
}, |
|||
axisPointer: { |
|||
link: [ |
|||
{ |
|||
xAxisIndex: 'all' |
|||
} |
|||
], |
|||
label: { |
|||
backgroundColor: '#77787D' |
|||
} |
|||
}, |
|||
toolbox: { |
|||
show: false |
|||
}, |
|||
grid: [ |
|||
{ |
|||
left: screenWidth.value > 768 ? '10%' : '12%', |
|||
right: screenWidth.value > 768 ? '4%' : '6%', |
|||
top: screenWidth.value > 768 ? '10%' : '12%', |
|||
height: screenWidth.value > 768 ? '35%' : '34%', |
|||
containLabel: false |
|||
}, |
|||
{ |
|||
left: screenWidth.value > 768 ? '10%' : '12%', |
|||
right: screenWidth.value > 768 ? '4%' : '6%', |
|||
top: screenWidth.value > 768 ? '48%' : '48%', |
|||
height: screenWidth.value > 768 ? '19%' : '21%', |
|||
containLabel: false |
|||
}, |
|||
{ |
|||
left: screenWidth.value > 768 ? '10%' : '12%', |
|||
right: screenWidth.value > 768 ? '4%' : '6%', |
|||
top: screenWidth.value > 768 ? '70%' : '71%', |
|||
height: screenWidth.value > 768 ? '19%' : '21%', |
|||
containLabel: false |
|||
} |
|||
], |
|||
xAxis: [ |
|||
{ |
|||
type: 'category', |
|||
data: dealData.categoryData, |
|||
boundaryGap: true, |
|||
axisLine: { onZero: false }, |
|||
splitLine: { show: false }, |
|||
min: 'dataMin', |
|||
max: 'dataMax', |
|||
axisPointer: { |
|||
z: 100, |
|||
label: { |
|||
show: false // 不显示标签 |
|||
} |
|||
}, |
|||
axisLine: { |
|||
lineStyle: { |
|||
color: 'black' |
|||
} |
|||
}, // |
|||
axisLabel: { show: false }, |
|||
axisTick: { show: false } |
|||
}, |
|||
{ |
|||
type: 'category', |
|||
gridIndex: 1, |
|||
data: dealData.categoryData, |
|||
boundaryGap: true, |
|||
axisPointer: { |
|||
z: 100, |
|||
label: { |
|||
show: false // 不显示标签 |
|||
} |
|||
}, |
|||
axisLine: { lineStyle: { color: 'black' } }, |
|||
axisLabel: { |
|||
show: false, |
|||
interval: 'auto' |
|||
}, |
|||
axisTick: { show: false } |
|||
}, |
|||
{ |
|||
type: 'category', |
|||
gridIndex: 2, |
|||
data: dealData.categoryData, |
|||
boundaryGap: true, |
|||
axisLine: { lineStyle: { color: 'black' } }, |
|||
axisLabel: { |
|||
show: true, |
|||
interval: 'auto', |
|||
fontSize: screenWidth.value > 768 ? 15 : 9 |
|||
}, |
|||
axisTick: { show: false } |
|||
} |
|||
], |
|||
yAxis: [ |
|||
{ |
|||
scale: true, |
|||
gridIndex: 0, |
|||
position: 'left', |
|||
axisLabel: { |
|||
inside: false, |
|||
align: 'right', |
|||
fontSize: screenWidth.value > 768 ? 15 : 9 |
|||
}, |
|||
axisLine: { |
|||
show: true, |
|||
lineStyle: { |
|||
fontSize: '', |
|||
color: 'black' |
|||
} |
|||
}, |
|||
axisTick: { show: false }, |
|||
splitLine: { show: false } |
|||
}, |
|||
{ |
|||
scale: true, |
|||
gridIndex: 1, |
|||
splitNumber: 4, |
|||
min: 0, |
|||
minInterval: 1, |
|||
axisLabel: { |
|||
show: true, |
|||
fontSize: screenWidth.value > 768 ? 15 : 9, |
|||
margin: 8, |
|||
}, |
|||
axisLine: { show: true, lineStyle: { color: 'black' } }, |
|||
axisTick: { show: false }, |
|||
splitLine: { show: true, lineStyle: { type: 'dashed' } }, |
|||
boundaryGap: ['20%', '20%'] |
|||
}, |
|||
{ |
|||
scale: true, |
|||
gridIndex: 2, |
|||
splitNumber: 2, |
|||
axisLabel: { |
|||
show: true, |
|||
fontSize: screenWidth.value > 768 ? 15 : 9 |
|||
}, |
|||
axisLine: { show: true, lineStyle: { color: 'black' } }, |
|||
axisTick: { show: false }, |
|||
splitLine: { show: false } |
|||
} |
|||
], |
|||
dataZoom: [ |
|||
{ |
|||
type: 'inside', |
|||
xAxisIndex: [0, 1, 2], |
|||
start: 50, |
|||
end: 100 |
|||
}, |
|||
{ |
|||
show: true, |
|||
xAxisIndex: [0, 1, 2], |
|||
type: 'slider', |
|||
start: 50, |
|||
end: 100 |
|||
} |
|||
], |
|||
series: [ |
|||
{ |
|||
type: 'candlestick', |
|||
name: '日K', |
|||
xAxisIndex: 0, |
|||
yAxisIndex: 0, |
|||
data: dealData.values, |
|||
itemStyle: { |
|||
normal: { |
|||
color0: 'red', |
|||
color: 'green', |
|||
borderColor0: 'red', |
|||
borderColor: 'green' |
|||
} |
|||
}, |
|||
gridIndex: 1 |
|||
}, |
|||
{ |
|||
name: '成交量', |
|||
type: 'bar', |
|||
barWidth: '70%', |
|||
xAxisIndex: 1, |
|||
yAxisIndex: 1, |
|||
data: barData, |
|||
}, |
|||
// { |
|||
// name: textEcharts.feixian, |
|||
// type: 'line', |
|||
// data: calculateMA(1, extractedDrawData), |
|||
// smooth: true, |
|||
// symbol: 'none', |
|||
// xAxisIndex: 2, |
|||
// yAxisIndex: 2, |
|||
// itemStyle: { |
|||
// normal: { |
|||
// color: '#00a32e', |
|||
// lineStyle: { |
|||
// color: '#00a32e', |
|||
// width: 2, |
|||
// type: 'solid' |
|||
// } |
|||
// } |
|||
// } |
|||
// }, |
|||
// { |
|||
// name: textEcharts.zhoongxian, |
|||
// type: 'line', |
|||
// data: calculateMA(2, extractedDrawData), |
|||
// smooth: true, |
|||
// symbol: 'none', |
|||
// xAxisIndex: 2, |
|||
// yAxisIndex: 2, |
|||
// itemStyle: { |
|||
// normal: { |
|||
// color: '#de0000', |
|||
// lineStyle: { |
|||
// color: '#de0000', |
|||
// width: 2, |
|||
// type: 'solid' |
|||
// } |
|||
// } |
|||
// } |
|||
// }, |
|||
// { |
|||
// name: textEcharts.tianxian, |
|||
// type: 'line', |
|||
// data: calculateMA(3, extractedDrawData), |
|||
// smooth: true, |
|||
// symbol: 'none', |
|||
// xAxisIndex: 2, |
|||
// yAxisIndex: 2, |
|||
// itemStyle: { |
|||
// normal: { |
|||
// color: '#ffb300', |
|||
// lineStyle: { |
|||
// color: '#ffb300', |
|||
// width: 2, |
|||
// type: 'solid' |
|||
// } |
|||
// } |
|||
// } |
|||
// }, |
|||
// { |
|||
// name: textEcharts.liuxian, |
|||
// type: 'line', |
|||
// data: calculateMA(4, extractedDrawData), |
|||
// smooth: true, |
|||
// symbol: 'none', |
|||
// xAxisIndex: 2, |
|||
// yAxisIndex: 2, |
|||
// itemStyle: { |
|||
// normal: { |
|||
// color: '#00c8ff', |
|||
// lineStyle: { |
|||
// color: '#00c8ff', |
|||
// width: 2, |
|||
// type: 'solid' |
|||
// } |
|||
// } |
|||
// } |
|||
// }, |
|||
] |
|||
} |
|||
initChart() |
|||
} |
|||
|
|||
// 组件挂载时初始化图表 |
|||
onMounted(() => { |
|||
// 调用图表初始化函数 |
|||
fnShowEcharts4(extractedDrawData) |
|||
}) |
|||
|
|||
|
|||
// 初始化图表 |
|||
const initChart = async () => { |
|||
if (!chartRef.value) return |
|||
|
|||
try { |
|||
const chart = await chartRef.value.init(echarts) |
|||
chart.setOption(option) |
|||
} catch (error) { |
|||
console.error('图表初始化失败:', error) |
|||
} |
|||
} |
|||
</script> |
|||
@ -0,0 +1,493 @@ |
|||
<template> |
|||
<view class="content"> |
|||
<!-- 市场子Tab --> |
|||
<view class="sub_tabs"> |
|||
<view v-for="(tab, i) in marketTabs" :key="tab" :class="['tab_item', i === activeTabIndex ? 'active' : '']" |
|||
@click="switchTab(i)"> |
|||
<text>{{ tab }}</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 大盘指数 --> |
|||
<view class="section"> |
|||
<view class="section_header"> |
|||
<text class="section_title">大盘指数</text> |
|||
<text class="section_action" @click="viewMore('indices')">查看更多 ></text> |
|||
</view> |
|||
<view class="indices_grid"> |
|||
<view v-for="(index, i) in countryInfo.mainIndices" :key="i" class="index_item"> |
|||
<IndexCard :flagIcon="countryInfo.flag" :indexName="index.name" :currentPrice="index.price" |
|||
:changeAmount="index.change" :changePercent="index.changePercent" :isRising="index.isRising" /> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 今日市场情绪温度 --> |
|||
<view class="sentiment"> |
|||
<view class="section_subtitle"> |
|||
<text>今日市场情绪温度</text> |
|||
</view> |
|||
<view class="meters"> |
|||
<view class="meter_item" v-for="(m, i) in sentimentMeters" :key="i"> |
|||
<image class="meter_icon" :class="m.theme" :src="selectIcons[m.theme]" mode="aspectFit"></image> |
|||
<view class="meter_info"> |
|||
<text class="meter_value" :class="m.theme">{{ m.value }}°C</text> |
|||
<text class="meter_label" :class="m.theme">{{ m.label }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 板块 --> |
|||
<view class="section"> |
|||
<view class="section_header"> |
|||
<text class="section_title">板块</text> |
|||
<text class="section_action" @click="viewMore('sectors')">查看更多 ></text> |
|||
</view> |
|||
<view class="sectors_grid"> |
|||
<view v-for="(sec, i) in sectors" :key="i" class="sector_item"> |
|||
<view class="sector_header"> |
|||
<text class="sector_name">{{ sec.name }}</text> |
|||
<text :class="['sector_change', sec.isRising ? 'rising' : 'falling']"> |
|||
{{ sec.change }} |
|||
</text> |
|||
</view> |
|||
<view class="sector_price">{{ sec.price }}</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 股票 --> |
|||
<view class="section"> |
|||
<view class="section_header"> |
|||
<text class="section_title">股票</text> |
|||
<text class="section_action" @click="viewMore('stocks')">查看更多 ></text> |
|||
</view> |
|||
<view class="table"> |
|||
<view class="table_header"> |
|||
<text class="cell name">名称</text> |
|||
<text class="cell price">最新</text> |
|||
<text class="cell change">涨幅</text> |
|||
</view> |
|||
<view class="table_row" v-for="(stk, i) in stocks" :key="i"> |
|||
<view class="cell name"> |
|||
<text class="stk_name">{{ stk.name }}</text> |
|||
<text class="stk_code">{{ stk.code }}</text> |
|||
</view> |
|||
<view class="cell price"> |
|||
<text class="stk_price">{{ stk.price }}</text> |
|||
</view> |
|||
<view class="cell change"> |
|||
<text :class="['stk_change', stk.isRising ? 'rising' : 'falling']"> |
|||
{{ stk.change }} |
|||
</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 底部安全区域 --> |
|||
<view class="bottom_safe_area"></view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, computed, onMounted } from 'vue' |
|||
import IndexCard from '../../components/IndexCard.vue' |
|||
|
|||
// 子Tab与操作 |
|||
const marketTabs = ['全部', '美股', '纽交所', '纳斯达克'] |
|||
const activeTabIndex = ref(0) |
|||
const switchTab = (i) => { |
|||
activeTabIndex.value = i |
|||
} |
|||
|
|||
// 今日情绪温度示例数据 |
|||
const sentimentMeters = [ |
|||
{ value: 90, label: '道琼斯', theme: 'hot' }, |
|||
{ value: 60, label: '纳斯达克', theme: 'warm' }, |
|||
{ value: 20, label: '标普500', theme: 'cool' } |
|||
] |
|||
|
|||
// 图标映射 |
|||
const selectIcons = { |
|||
hot: '/static/marketSituation-image/hot.png', |
|||
warm: '/static/marketSituation-image/warm.png', |
|||
cool: '/static/marketSituation-image/cool.png' |
|||
} |
|||
|
|||
// Props |
|||
const props = defineProps({ |
|||
countryId: { |
|||
type: Number, |
|||
required: true |
|||
} |
|||
}) |
|||
|
|||
// 国家/地区信息映射 |
|||
const countryInfoMap = { |
|||
2: { // 新加坡 |
|||
name: '新加坡', |
|||
flag: '🇸🇬', |
|||
isMarketOpen: true, |
|||
mainIndices: [ |
|||
{ name: '海峡时报指数', price: '3,234.56', change: '+12.34', changePercent: '+0.38%', isRising: true }, |
|||
{ name: 'FTSE ST Mid Cap', price: '1,234.56', change: '-5.67', changePercent: '-0.46%', isRising: false } |
|||
], |
|||
hotStocks: [ |
|||
{ name: '星展银行', code: 'D05.SI', price: '35.20', change: '+0.15', isRising: true }, |
|||
{ name: '华侨银行', code: 'O39.SI', price: '13.45', change: '-0.05', isRising: false } |
|||
] |
|||
}, |
|||
3: { // 马来西亚 |
|||
name: '马来西亚', |
|||
flag: '🇲🇾', |
|||
isMarketOpen: false, |
|||
mainIndices: [ |
|||
{ name: '富时大马KLCI指数', price: '1,567.89', change: '+8.90', changePercent: '+0.57%', isRising: true } |
|||
], |
|||
hotStocks: [ |
|||
{ name: '马来亚银行', code: '1155.KL', price: '9.85', change: '+0.10', isRising: true }, |
|||
{ name: '大众银行', code: '1295.KL', price: '4.32', change: '-0.02', isRising: false } |
|||
] |
|||
}, |
|||
4: { // 印度尼西亚 |
|||
name: '印度尼西亚', |
|||
flag: '🇮🇩', |
|||
isMarketOpen: true, |
|||
mainIndices: [ |
|||
{ name: '雅加达综合指数', price: '7,234.56', change: '+45.67', changePercent: '+0.63%', isRising: true } |
|||
], |
|||
hotStocks: [] |
|||
}, |
|||
5: { // 美国 |
|||
name: '美国', |
|||
flag: '🇺🇸', |
|||
isMarketOpen: false, |
|||
mainIndices: [ |
|||
{ name: '道琼斯', price: '45,757.90', change: '-125.22', changePercent: '-0.27%', isRising: false }, |
|||
{ name: '纳斯达克', price: '22,333.96', change: '+125.22', changePercent: '+0.47%', isRising: true }, |
|||
{ name: '标普500', price: '6,606.08', change: '+125.22', changePercent: '+0.27%', isRising: true } |
|||
], |
|||
hotStocks: [ |
|||
{ name: '苹果', code: 'AAPL', price: '195.89', change: '+2.34', isRising: true }, |
|||
{ name: '微软', code: 'MSFT', price: '378.85', change: '-1.23', isRising: false } |
|||
] |
|||
} |
|||
} |
|||
|
|||
// 计算当前国家信息 |
|||
const countryInfo = computed(() => { |
|||
return countryInfoMap[props.countryId] || { |
|||
name: '未知地区', |
|||
flag: '🌍', |
|||
isMarketOpen: false, |
|||
mainIndices: [], |
|||
hotStocks: [] |
|||
} |
|||
}) |
|||
|
|||
// 计算当前国家的板块与股票 |
|||
const sectors = computed(() => { |
|||
return countryInfoMap[props.countryId]?.sectors || [] |
|||
}) |
|||
const stocks = computed(() => { |
|||
return countryInfoMap[props.countryId]?.stocks || [] |
|||
}) |
|||
|
|||
// 查看更多占位 |
|||
const viewMore = (type) => { |
|||
// 可根据 type 跳转到相应页面或加载更多 |
|||
// 例如:indices/sectors/stocks |
|||
// uni.navigateTo({ url: `/pages/marketSituation/${type}List` }) |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.content { |
|||
padding: 0 20rpx 20rpx 20rpx; |
|||
} |
|||
|
|||
/* 子Tab */ |
|||
.sub_tabs { |
|||
display: flex; |
|||
gap: 16rpx; |
|||
padding: 0 20rpx 20rpx 20rpx; |
|||
} |
|||
|
|||
.tab_item { |
|||
padding: 6rpx 20rpx; |
|||
border-radius: 5rpx; |
|||
background: #f5f5f5; |
|||
color: #666; |
|||
font-size: 24rpx; |
|||
} |
|||
|
|||
.tab_item.active { |
|||
background: #ff4444; |
|||
color: #fff; |
|||
} |
|||
|
|||
.section { |
|||
padding: 20rpx; |
|||
border-radius: 16rpx; |
|||
} |
|||
|
|||
.section_header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-bottom: 16rpx; |
|||
} |
|||
|
|||
.section_title { |
|||
font-size: 28rpx; |
|||
font-weight: bold; |
|||
color: #333; |
|||
} |
|||
|
|||
.section_action { |
|||
font-size: 24rpx; |
|||
color: #999; |
|||
} |
|||
|
|||
.indices_grid { |
|||
padding: 20rpx; |
|||
display: grid; |
|||
grid-template-columns: repeat(3, 1fr); |
|||
gap: 20rpx; |
|||
background-color: #F6F6F6; |
|||
} |
|||
|
|||
/* 情绪温度 */ |
|||
.sentiment { |
|||
background-color: #F6F6F6; |
|||
padding: 0 20rpx 20rpx 20rpx; |
|||
} |
|||
|
|||
.section_subtitle { |
|||
font-size: 24rpx; |
|||
color: #000000; |
|||
padding: 20rpx 0; |
|||
} |
|||
|
|||
.meters { |
|||
display: grid; |
|||
grid-template-columns: repeat(3, 1fr); |
|||
gap: 16rpx; |
|||
} |
|||
|
|||
.meter_item { |
|||
display: flex; |
|||
align-items: center; |
|||
/* padding: 10rpx; */ |
|||
background: #ffffff; |
|||
border-radius: 12rpx; |
|||
} |
|||
|
|||
.meter_item image { |
|||
width: 100rpx; |
|||
height: 100rpx; |
|||
} |
|||
|
|||
.meter_info { |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
.meter_value { |
|||
font-size: 36rpx; |
|||
} |
|||
|
|||
.meter_value.hot { |
|||
color: #ff6b6b; |
|||
} |
|||
|
|||
.meter_value.warm { |
|||
color: #ffd166; |
|||
} |
|||
|
|||
.meter_value.cool { |
|||
color: #60a5fa; |
|||
} |
|||
|
|||
.meter_label { |
|||
font-size: 22rpx; |
|||
} |
|||
|
|||
.meter_label.hot { |
|||
color: #ff6b6b; |
|||
} |
|||
|
|||
.meter_label.warm { |
|||
color: #ffd166; |
|||
} |
|||
|
|||
.meter_label.cool { |
|||
color: #60a5fa; |
|||
} |
|||
|
|||
/* 板块 */ |
|||
.sectors_grid { |
|||
display: grid; |
|||
grid-template-columns: repeat(3, 1fr); |
|||
gap: 16rpx; |
|||
} |
|||
|
|||
.sector_item { |
|||
background: #fafafa; |
|||
border-radius: 12rpx; |
|||
padding: 16rpx; |
|||
} |
|||
|
|||
.sector_header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-bottom: 12rpx; |
|||
} |
|||
|
|||
.sector_name { |
|||
font-size: 24rpx; |
|||
color: #333; |
|||
} |
|||
|
|||
.sector_change { |
|||
font-size: 22rpx; |
|||
} |
|||
|
|||
.sector_change.rising { |
|||
color: #e74c3c; |
|||
} |
|||
|
|||
.sector_change.falling { |
|||
color: #27ae60; |
|||
} |
|||
|
|||
.sector_price { |
|||
font-size: 24rpx; |
|||
color: #666; |
|||
} |
|||
|
|||
/* 股票表 */ |
|||
.table { |
|||
background: #fff; |
|||
border-radius: 12rpx; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.table_header, |
|||
.table_row { |
|||
display: grid; |
|||
grid-template-columns: 2fr 1fr 1fr; |
|||
padding: 18rpx 20rpx; |
|||
border-bottom: 1rpx solid #f0f0f0; |
|||
} |
|||
|
|||
.table_header { |
|||
background: #fafafa; |
|||
} |
|||
|
|||
.cell.name { |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
.stk_name { |
|||
font-size: 26rpx; |
|||
color: #333; |
|||
} |
|||
|
|||
.stk_code { |
|||
font-size: 22rpx; |
|||
color: #999; |
|||
} |
|||
|
|||
.stk_price { |
|||
font-size: 26rpx; |
|||
color: #333; |
|||
} |
|||
|
|||
.stk_change { |
|||
font-size: 24rpx; |
|||
} |
|||
|
|||
.stk_change.rising { |
|||
color: #e74c3c; |
|||
} |
|||
|
|||
.stk_change.falling { |
|||
color: #27ae60; |
|||
} |
|||
|
|||
.index_item { |
|||
background: #fff; |
|||
border-radius: 12rpx; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.hot_stocks { |
|||
margin-bottom: 30rpx; |
|||
} |
|||
|
|||
.stocks_list { |
|||
background: #fff; |
|||
border-radius: 12rpx; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.stock_item { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 24rpx 20rpx; |
|||
border-bottom: 1rpx solid #f0f0f0; |
|||
} |
|||
|
|||
.stock_item:last-child { |
|||
border-bottom: none; |
|||
} |
|||
|
|||
.stock_info { |
|||
flex: 1; |
|||
} |
|||
|
|||
.stock_name { |
|||
font-size: 28rpx; |
|||
color: #333; |
|||
display: block; |
|||
margin-bottom: 8rpx; |
|||
} |
|||
|
|||
.stock_code { |
|||
font-size: 24rpx; |
|||
color: #999; |
|||
} |
|||
|
|||
.stock_price { |
|||
text-align: right; |
|||
} |
|||
|
|||
.price { |
|||
font-size: 28rpx; |
|||
color: #333; |
|||
display: block; |
|||
margin-bottom: 8rpx; |
|||
} |
|||
|
|||
.change { |
|||
font-size: 24rpx; |
|||
} |
|||
|
|||
.change.rising { |
|||
color: #e74c3c; |
|||
} |
|||
|
|||
.change.falling { |
|||
color: #27ae60; |
|||
} |
|||
|
|||
.bottom_safe_area { |
|||
height: 120rpx; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,301 @@ |
|||
<template> |
|||
<view class="content"> |
|||
<view class="section" v-if="type === 'forex'"> |
|||
<view class="section_title"> |
|||
<text class="title_icon">💱</text> |
|||
<text>外汇市场</text> |
|||
</view> |
|||
<view class="forex_grid"> |
|||
<view v-for="(item, index) in forexData" :key="index" class="forex_item"> |
|||
<view class="forex_pair"> |
|||
<text class="base_currency">{{ item.base }}</text> |
|||
<text class="separator">/</text> |
|||
<text class="quote_currency">{{ item.quote }}</text> |
|||
</view> |
|||
<view class="forex_price"> |
|||
<text class="price">{{ item.price }}</text> |
|||
<text :class="['change', item.isRising ? 'rising' : 'falling']"> |
|||
{{ item.change }} |
|||
</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="section" v-if="type === 'metals'"> |
|||
<view class="section_title"> |
|||
<text class="title_icon">🥇</text> |
|||
<text>贵金属</text> |
|||
</view> |
|||
<view class="metals_grid"> |
|||
<view v-for="(item, index) in metalsData" :key="index" class="metal_item"> |
|||
<view class="metal_info"> |
|||
<text class="metal_icon">{{ item.icon }}</text> |
|||
<text class="metal_name">{{ item.name }}</text> |
|||
</view> |
|||
<view class="metal_price"> |
|||
<text class="price">{{ item.price }}</text> |
|||
<text class="unit">{{ item.unit }}</text> |
|||
<text :class="['change', item.isRising ? 'rising' : 'falling']"> |
|||
{{ item.change }} |
|||
</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 市场动态 --> |
|||
<view class="market_news"> |
|||
<view class="section_title"> |
|||
<text class="title_icon">📰</text> |
|||
<text>市场动态</text> |
|||
</view> |
|||
<view class="news_list"> |
|||
<view v-for="(news, index) in newsData" :key="index" class="news_item"> |
|||
<view class="news_content"> |
|||
<text class="news_title">{{ news.title }}</text> |
|||
<text class="news_time">{{ news.time }}</text> |
|||
</view> |
|||
<view class="news_impact" :class="news.impact"> |
|||
<text>{{ news.impactText }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 底部安全区域 --> |
|||
<view class="bottom_safe_area"></view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, computed } from 'vue' |
|||
|
|||
// Props |
|||
const props = defineProps({ |
|||
countryId: { |
|||
type: Number, |
|||
required: true |
|||
} |
|||
}) |
|||
|
|||
// 判断类型 |
|||
const type = computed(() => { |
|||
return props.countryId === 11 ? 'forex' : 'metals' |
|||
}) |
|||
|
|||
// 外汇数据 |
|||
const forexData = ref([ |
|||
{ base: 'USD', quote: 'CNY', price: '7.2456', change: '+0.0123', isRising: true }, |
|||
{ base: 'EUR', quote: 'USD', price: '1.0876', change: '-0.0034', isRising: false }, |
|||
{ base: 'GBP', quote: 'USD', price: '1.2654', change: '+0.0087', isRising: true }, |
|||
{ base: 'USD', quote: 'JPY', price: '149.87', change: '+0.45', isRising: true }, |
|||
{ base: 'AUD', quote: 'USD', price: '0.6543', change: '-0.0021', isRising: false }, |
|||
{ base: 'USD', quote: 'SGD', price: '1.3456', change: '+0.0012', isRising: true } |
|||
]) |
|||
|
|||
// 贵金属数据 |
|||
const metalsData = ref([ |
|||
{ icon: '🥇', name: '黄金', price: '2,034.56', unit: 'USD/盎司', change: '+12.34', isRising: true }, |
|||
{ icon: '🥈', name: '白银', price: '24.87', unit: 'USD/盎司', change: '-0.23', isRising: false }, |
|||
{ icon: '⚪', name: '铂金', price: '987.65', unit: 'USD/盎司', change: '+5.67', isRising: true }, |
|||
{ icon: '⚫', name: '钯金', price: '1,234.56', unit: 'USD/盎司', change: '-8.90', isRising: false } |
|||
]) |
|||
|
|||
// 新闻数据 |
|||
const newsData = ref([ |
|||
{ |
|||
title: '美联储暗示可能暂停加息', |
|||
time: '2小时前', |
|||
impact: 'high', |
|||
impactText: '高影响' |
|||
}, |
|||
{ |
|||
title: '欧洲央行维持利率不变', |
|||
time: '4小时前', |
|||
impact: 'medium', |
|||
impactText: '中影响' |
|||
}, |
|||
{ |
|||
title: '黄金价格创新高', |
|||
time: '6小时前', |
|||
impact: 'medium', |
|||
impactText: '中影响' |
|||
}, |
|||
{ |
|||
title: '美元指数小幅下跌', |
|||
time: '8小时前', |
|||
impact: 'low', |
|||
impactText: '低影响' |
|||
} |
|||
]) |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.content { |
|||
padding: 20rpx; |
|||
} |
|||
|
|||
.section { |
|||
margin-bottom: 40rpx; |
|||
} |
|||
|
|||
.section_title { |
|||
display: flex; |
|||
align-items: center; |
|||
font-size: 28rpx; |
|||
font-weight: bold; |
|||
color: #333; |
|||
margin-bottom: 20rpx; |
|||
} |
|||
|
|||
.title_icon { |
|||
font-size: 32rpx; |
|||
margin-right: 12rpx; |
|||
} |
|||
|
|||
.forex_grid, .metals_grid { |
|||
background: #fff; |
|||
border-radius: 12rpx; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.forex_item, .metal_item { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 24rpx 20rpx; |
|||
border-bottom: 1rpx solid #f0f0f0; |
|||
} |
|||
|
|||
.forex_item:last-child, .metal_item:last-child { |
|||
border-bottom: none; |
|||
} |
|||
|
|||
.forex_pair { |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
.base_currency { |
|||
font-size: 28rpx; |
|||
font-weight: bold; |
|||
color: #333; |
|||
} |
|||
|
|||
.separator { |
|||
font-size: 24rpx; |
|||
color: #999; |
|||
margin: 0 8rpx; |
|||
} |
|||
|
|||
.quote_currency { |
|||
font-size: 28rpx; |
|||
color: #666; |
|||
} |
|||
|
|||
.forex_price, .metal_price { |
|||
text-align: right; |
|||
} |
|||
|
|||
.price { |
|||
font-size: 28rpx; |
|||
color: #333; |
|||
display: block; |
|||
margin-bottom: 8rpx; |
|||
} |
|||
|
|||
.unit { |
|||
font-size: 20rpx; |
|||
color: #999; |
|||
margin-left: 8rpx; |
|||
} |
|||
|
|||
.change { |
|||
font-size: 24rpx; |
|||
} |
|||
|
|||
.change.rising { |
|||
color: #e74c3c; |
|||
} |
|||
|
|||
.change.falling { |
|||
color: #27ae60; |
|||
} |
|||
|
|||
.metal_info { |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
.metal_icon { |
|||
font-size: 32rpx; |
|||
margin-right: 16rpx; |
|||
} |
|||
|
|||
.metal_name { |
|||
font-size: 28rpx; |
|||
color: #333; |
|||
} |
|||
|
|||
.market_news { |
|||
margin-bottom: 30rpx; |
|||
} |
|||
|
|||
.news_list { |
|||
background: #fff; |
|||
border-radius: 12rpx; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.news_item { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 24rpx 20rpx; |
|||
border-bottom: 1rpx solid #f0f0f0; |
|||
} |
|||
|
|||
.news_item:last-child { |
|||
border-bottom: none; |
|||
} |
|||
|
|||
.news_content { |
|||
flex: 1; |
|||
} |
|||
|
|||
.news_title { |
|||
font-size: 28rpx; |
|||
color: #333; |
|||
display: block; |
|||
margin-bottom: 8rpx; |
|||
} |
|||
|
|||
.news_time { |
|||
font-size: 24rpx; |
|||
color: #999; |
|||
} |
|||
|
|||
.news_impact { |
|||
padding: 6rpx 12rpx; |
|||
border-radius: 16rpx; |
|||
font-size: 20rpx; |
|||
color: #fff; |
|||
} |
|||
|
|||
.news_impact.high { |
|||
background: #e74c3c; |
|||
} |
|||
|
|||
.news_impact.medium { |
|||
background: #f39c12; |
|||
} |
|||
|
|||
.news_impact.low { |
|||
background: #95a5a6; |
|||
} |
|||
|
|||
.bottom_safe_area { |
|||
height: 120rpx; |
|||
} |
|||
</style> |
|||
2258
pages/marketSituation/marketCondition.vue
File diff suppressed because it is too large
View File
@ -0,0 +1,757 @@ |
|||
<!-- @format --> |
|||
|
|||
<template> |
|||
<view class="main"> |
|||
<!-- 可滚动内容区域 --> |
|||
<scroll-view class="content_scroll" scroll-y="true" :style="{ top: contentTopPosition + 'px' }"> |
|||
<view class="content"> |
|||
<button @click="goToChartExample">图表</button> |
|||
<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> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, onMounted, watch, nextTick, computed } from "vue"; |
|||
import util from "../../common/util.js"; |
|||
import IndexCard from "../../components/IndexCard.vue"; |
|||
|
|||
const iSMT = ref(0); |
|||
const searchValue = ref(""); |
|||
const contentHeight = ref(0); |
|||
const headerHeight = ref(0); // 动态计算的header高度 |
|||
const isWarnTextOverflow = ref(false); // warn文字是否溢出 |
|||
|
|||
const pageIndex = ref(0); |
|||
const scrollToView = ref(""); |
|||
|
|||
// 跳转图表示例页面 |
|||
const goToChartExample = () => { |
|||
uni.navigateTo({ |
|||
url: "/pages/marketSituation/chartExample", |
|||
}); |
|||
}; |
|||
|
|||
// 计算属性:精准计算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: "noCode", |
|||
currentPrice: "45757.90", |
|||
changeAmount: "-125.22", |
|||
changePercent: "-0.27%", |
|||
isRising: false, |
|||
}, |
|||
{ |
|||
flagIcon: "🇺🇸", |
|||
stockName: "纳斯达克", |
|||
stockCode: "noCode", |
|||
currentPrice: "22333.96", |
|||
changeAmount: "+125.22", |
|||
changePercent: "+0.47%", |
|||
isRising: true, |
|||
}, |
|||
{ |
|||
flagIcon: "🇺🇸", |
|||
stockName: "标普500", |
|||
stockCode: "noCode", |
|||
currentPrice: "6606.08", |
|||
changeAmount: "+125.22", |
|||
changePercent: "+0.27%", |
|||
isRising: true, |
|||
}, |
|||
{ |
|||
flagIcon: "🇨🇳", |
|||
stockName: "上证指数", |
|||
stockCode: "noCode", |
|||
currentPrice: "3333.96", |
|||
changeAmount: "+125.22", |
|||
changePercent: "+0.27%", |
|||
isRising: true, |
|||
}, |
|||
{ |
|||
flagIcon: "🇨🇳", |
|||
stockName: "科创50", |
|||
stockCode: "noCode", |
|||
currentPrice: "757.90", |
|||
changeAmount: "-25.22", |
|||
changePercent: "-0.27%", |
|||
isRising: false, |
|||
}, |
|||
{ |
|||
flagIcon: "🇭🇰", |
|||
stockName: "恒生指数", |
|||
stockCode: "noCode", |
|||
currentPrice: "19757.90", |
|||
changeAmount: "-125.22", |
|||
changePercent: "-0.63%", |
|||
isRising: false, |
|||
}, |
|||
{ |
|||
flagIcon: "🇸🇬", |
|||
stockName: "道琼斯", |
|||
stockCode: "noCode", |
|||
currentPrice: "3757.90", |
|||
changeAmount: "+85.22", |
|||
changePercent: "+2.31%", |
|||
isRising: true, |
|||
}, |
|||
{ |
|||
flagIcon: "🇲🇾", |
|||
stockName: "纳斯达克", |
|||
stockCode: "noCode", |
|||
currentPrice: "1657.90", |
|||
changeAmount: "-15.22", |
|||
changePercent: "-0.91%", |
|||
isRising: false, |
|||
}, |
|||
{ |
|||
flagIcon: "🇹🇭", |
|||
stockName: "标普500", |
|||
stockCode: "noCode", |
|||
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", |
|||
}); |
|||
// 这里添加实际的搜索逻辑 |
|||
}; |
|||
|
|||
// 检测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 viewIndexDetail = (item) => { |
|||
console.log("查看指数详情:", item.stockName); |
|||
// uni.showToast({ |
|||
// title: `查看 ${item.stockName} 详情`, |
|||
// icon: 'none', |
|||
// duration: 2000 |
|||
// }) |
|||
// 这里可以跳转到具体的指数详情页面 |
|||
uni.navigateTo({ |
|||
url: `/pages/marketSituation/marketCondition?stockInformation=${encodeURIComponent(JSON.stringify(item))}`, |
|||
}); |
|||
}; |
|||
|
|||
// 跳转到全球指数页面 |
|||
const goToGlobalIndex = () => { |
|||
uni.navigateTo({ |
|||
url: "/pages/marketSituation/globalIndex", |
|||
}); |
|||
}; |
|||
|
|||
onMounted(() => { |
|||
// 状态栏高度 |
|||
iSMT.value = uni.getSystemInfoSync().statusBarHeight; |
|||
|
|||
// 确保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; |
|||
} |
|||
|
|||
/* 弹窗样式 */ |
|||
.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%; |
|||
padding: 30rpx 20rpx; |
|||
gap: 20rpx; |
|||
} |
|||
|
|||
.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> |
|||
@ -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,218 @@ |
|||
<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' |
|||
|
|||
import {useUserStore} from "../../stores/modules/userInfo" |
|||
const iSMT = ref(0) |
|||
const jwcode = ref('90047681') |
|||
const showLogout = ref(false) |
|||
const userStore = useUserStore() |
|||
|
|||
const handleConfirmLogout = () => { |
|||
|
|||
userStore.clearUserInfo() |
|||
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> |
|||
1054
pages/start/Registration/Registration.vue
File diff suppressed because it is too large
View File
1341
pages/start/Registration/list.js
File diff suppressed because it is too large
View File
@ -0,0 +1,13 @@ |
|||
<template> |
|||
<view> |
|||
用户协议 |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
|
|||
</script> |
|||
|
|||
<style> |
|||
|
|||
</style> |
|||
@ -0,0 +1,56 @@ |
|||
<template> |
|||
<view class="content"> |
|||
<image class="logo" src="/static/logo.png"></image> |
|||
<view class="text-area"> |
|||
<text class="title" @click="showLoginPrompt">{{ title }}</text> |
|||
</view> |
|||
<LoginPrompt ref="loginPrompt"></LoginPrompt> |
|||
<button @click="toDeepMate">deepMate</button> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref } from "vue"; |
|||
import { useUserStore } from "../../../stores/modules/userInfo"; |
|||
const title = ref("请先登录"); |
|||
const loginPrompt = ref(null); |
|||
|
|||
const userStore = useUserStore(); |
|||
function showLoginPrompt() { |
|||
userStore.clearUserInfo(); |
|||
} |
|||
|
|||
function toDeepMate() { |
|||
uni.navigateTo({ |
|||
url: "/pages/deepMate/deepMate", |
|||
}); |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
.content { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.logo { |
|||
height: 200rpx; |
|||
width: 200rpx; |
|||
margin-top: 200rpx; |
|||
margin-left: auto; |
|||
margin-right: auto; |
|||
margin-bottom: 50rpx; |
|||
} |
|||
|
|||
.text-area { |
|||
display: flex; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.title { |
|||
font-size: 36rpx; |
|||
color: #8f8f94; |
|||
} |
|||
</style> |
|||
1341
pages/start/login/list.js
File diff suppressed because it is too large
View File
1190
pages/start/login/login.vue
File diff suppressed because it is too large
View File
@ -0,0 +1,69 @@ |
|||
|
|||
function verificationPhone(countryCode,phoneNumber) { |
|||
switch (countryCode) { |
|||
case '+86': |
|||
return verificationChina(phoneNumber); |
|||
case '+1': |
|||
return verificationAmerica(phoneNumber); |
|||
case '+65': |
|||
return verificationSingapore(phoneNumber); |
|||
case '+60': |
|||
return verificationMalaysia(phoneNumber); |
|||
case '+66': |
|||
return verificationThailand(phoneNumber); |
|||
case '+852': |
|||
return verificationHongKong(phoneNumber); |
|||
case '+84': |
|||
return verificationVietnam(phoneNumber); |
|||
default: |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
|
|||
function verificationChina(phoneNumber){ |
|||
const phoneRegex = /^1[3-9]\d{9}$/; |
|||
return phoneRegex.test(phoneNumber); |
|||
} |
|||
|
|||
|
|||
function verificationAmerica(phoneNumber){ |
|||
const phoneRegex = /^[2-9]\d{2}[- ]?\d{4}$/; |
|||
return phoneRegex.test(phoneNumber); |
|||
} |
|||
function verificationSingapore(phoneNumber){ |
|||
const phoneRegex = /^[89]\d{7}$/; |
|||
return phoneRegex.test(phoneNumber); |
|||
} |
|||
function verificationMalaysia(phoneNumber){ |
|||
const phoneRegex = /^01\d{8}$/; |
|||
return phoneRegex.test(phoneNumber); |
|||
} |
|||
|
|||
function verificationHongKong(phoneNumber){ |
|||
const phoneRegex = /^0[896]\d{8}$/; |
|||
return phoneRegex.test(phoneNumber); |
|||
} |
|||
|
|||
|
|||
function verificationThailand(phoneNumber){ |
|||
const phoneRegex = /^[5-9]\d{7}$/; |
|||
return phoneRegex.test(phoneNumber); |
|||
} |
|||
|
|||
|
|||
|
|||
function verificationVietnam(phoneNumber){ |
|||
const phoneRegex = /^(0)?[3-9]\d{8}$/; |
|||
return phoneRegex.test(phoneNumber); |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
function verificationEmail(email) { |
|||
const emailRegex = /^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/; |
|||
return emailRegex.test(email); |
|||
} |
|||
|
|||
export {verificationPhone,verificationEmail} |
|||
@ -0,0 +1,13 @@ |
|||
<template> |
|||
<view> |
|||
隐私政策 |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
|
|||
</script> |
|||
|
|||
<style> |
|||
|
|||
</style> |
|||
1012
pages/start/recoverPassword/recoverPassword.vue
File diff suppressed because it is too large
View File
@ -0,0 +1,170 @@ |
|||
<template> |
|||
<view class="login-container"> |
|||
<!-- 顶部标题 --> |
|||
<view class="title-section"> |
|||
<text class="main-title">DeepChart</text> |
|||
</view> |
|||
<view class="subtitle-section"> |
|||
<text class="subtitle">您的股市随身顾问</text> |
|||
</view> |
|||
|
|||
<!-- 手机卡片样式 --> |
|||
<view class="phone-card"> </view> |
|||
|
|||
<!-- 登录注册按钮 --> |
|||
<view class="button-group"> |
|||
<button class="login-button" @click="toLogin">登录</button> |
|||
<button class="register-button" @click="toRegistration">注册</button> |
|||
</view> |
|||
|
|||
<footerBar class="static-footer" :type="type"></footerBar> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import footerBar from "../../../components/footerBar"; |
|||
import { ref, reactive, toRefs, watch } from "vue"; |
|||
|
|||
|
|||
const type = ref(""); |
|||
|
|||
function toRegistration() { |
|||
uni.redirectTo({ |
|||
url: "/pages/start/Registration/Registration", |
|||
}); |
|||
} |
|||
|
|||
function toLogin() { |
|||
uni.redirectTo({ |
|||
url: "/pages/start/login/login", |
|||
}); |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.login-container { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
/* justify-content: space-between; */ |
|||
padding: 40rpx; |
|||
height: 90vh; |
|||
background-color: #ffffff; |
|||
overflow: hidden; |
|||
max-height: 100vh; |
|||
-webkit-overflow-scrolling: none; |
|||
} |
|||
|
|||
.title-section { |
|||
text-align: center; |
|||
margin-top: 120rpx; |
|||
|
|||
margin-bottom: 20rpx; |
|||
} |
|||
|
|||
.main-title { |
|||
text-align: center; |
|||
font-size: 64rpx; |
|||
font-weight: 300; |
|||
color: #000000; |
|||
margin-bottom: 10rpx; |
|||
} |
|||
.subtitle-section { |
|||
margin-bottom: 80rpx; |
|||
} |
|||
.subtitle { |
|||
/* font-weight: bold; */ |
|||
font-size: 32rpx; |
|||
color: #333333; |
|||
} |
|||
|
|||
.phone-card { |
|||
background-image: url("/static/select.png"); |
|||
background-repeat: no-repeat; |
|||
background-size: contain; |
|||
background-position: center; |
|||
/* background-position: center; */ |
|||
/* min-width: 300rpx; */ |
|||
|
|||
width: 420rpx; |
|||
height: 786rpx; |
|||
border-radius: 50rpx; |
|||
padding: 40rpx; |
|||
/* box-shadow: 0 20rpx 40rpx rgba(0, 0, 0, 0.3); */ |
|||
position: relative; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.button-group { |
|||
display: flex; |
|||
gap: 40rpx; |
|||
margin: 80rpx 0; |
|||
width: 100%; |
|||
max-width: 600rpx; |
|||
} |
|||
|
|||
.login-button { |
|||
flex: 1; |
|||
background-color: #f5f5f5; |
|||
color: #000000; |
|||
border-radius: 60rpx; |
|||
font-size: 32rpx; |
|||
padding: 20rpx; |
|||
} |
|||
|
|||
.register-button { |
|||
flex: 1; |
|||
background-color: #000000; |
|||
color: #ffffff; |
|||
border-radius: 60rpx; |
|||
font-size: 32rpx; |
|||
padding: 20rpx; |
|||
} |
|||
|
|||
.bottom-nav { |
|||
display: flex; |
|||
justify-content: space-around; |
|||
align-items: center; |
|||
width: 100%; |
|||
height: 100rpx; |
|||
background-color: #ffffff; |
|||
position: fixed; |
|||
bottom: 0; |
|||
left: 0; |
|||
border-top: 1rpx solid #e5e5e5; |
|||
} |
|||
|
|||
.nav-item { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
padding: 10rpx; |
|||
} |
|||
|
|||
.nav-item.active .nav-icon { |
|||
transform: scale(1.2); |
|||
} |
|||
|
|||
.nav-icon { |
|||
width: 40rpx; |
|||
height: 40rpx; |
|||
margin-bottom: 10rpx; |
|||
} |
|||
|
|||
.nav-text { |
|||
font-size: 24rpx; |
|||
color: #666666; |
|||
} |
|||
|
|||
.nav-item.active .nav-text { |
|||
color: #000000; |
|||
} |
|||
|
|||
.static-footer { |
|||
position: fixed; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,73 @@ |
|||
<template> |
|||
<view class="background"> |
|||
<image |
|||
class="logo" |
|||
src="../../../static/icons/start-logo.png" |
|||
mode="scaleToFill" |
|||
/> |
|||
<view class="logo-text"> DeepChart </view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { onShow } from "@dcloudio/uni-app"; |
|||
import { useUserStore } from "../../../stores/modules/userInfo"; |
|||
import { useDeviceStore } from "../../../stores/modules/deviceInfo"; |
|||
|
|||
onShow(() => { |
|||
const deviceInfo = useDeviceStore(); |
|||
// 获取设备ID |
|||
uni.getSystemInfo({ |
|||
success: (res) => { |
|||
deviceInfo.setDeviceInfo(res) |
|||
}, |
|||
}); |
|||
|
|||
setTimeout(() => { |
|||
const userStore = useUserStore(); |
|||
if (!userStore.userInfo) |
|||
uni.redirectTo({ |
|||
url: "/pages/start/select/select", |
|||
animationType: "slide-in-right", |
|||
animationDuration: 1000, |
|||
}); |
|||
else { |
|||
uni.redirectTo({ |
|||
url: "/pages/home/home", |
|||
animationType: "slide-in-right", |
|||
animationDuration: 1000, |
|||
}); |
|||
} |
|||
}, 1500); |
|||
}); |
|||
</script> |
|||
|
|||
<style> |
|||
.background { |
|||
background: linear-gradient(180deg, #fb6967, #fb6967); |
|||
width: 100vw; |
|||
height: 100vh; |
|||
} |
|||
|
|||
.logo-text { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
color: white; |
|||
font-weight: bold; |
|||
font-size: 24px; |
|||
position: absolute; |
|||
bottom: 5%; |
|||
left: 50%; |
|||
transform: translateX(-50%); |
|||
} |
|||
|
|||
.logo { |
|||
width: 320rpx; |
|||
height: 200rpx; |
|||
position: absolute; |
|||
top: 30%; |
|||
left: 50%; |
|||
transform: translate(-50%, -50%); |
|||
} |
|||
</style> |
|||
@ -0,0 +1,138 @@ |
|||
{ |
|||
"loginSuccessByEmail": { |
|||
"code": 200, |
|||
"message": "c3e9ed50ad72073b94dfb04860562b58", |
|||
"data": { |
|||
"loginType": null, |
|||
"device": "unknown", |
|||
"dccode": "90047686", |
|||
"account": null, |
|||
"password": null, |
|||
"verifyCode": null, |
|||
"useCode": false, |
|||
"idToken": null, |
|||
"token": "c3e9ed50ad72073b94dfb04860562b58", |
|||
"market": "新加坡", |
|||
"phone": "17861484516", |
|||
"email": "q614588746@163.com", |
|||
"language": "中文", |
|||
"avatar": "123" |
|||
} |
|||
}, |
|||
"loginFailureEmailNotFound": { |
|||
"code": 404, |
|||
"message": "账号不存在", |
|||
"interface": "login" |
|||
}, |
|||
"loginFailureWrongCode": { |
|||
"code": 400, |
|||
"message": "验证码错误", |
|||
"interface": "login" |
|||
}, |
|||
"loginSuccessByPhone": { |
|||
"code": 200, |
|||
"message": "登录成功", |
|||
"interface": "login", |
|||
"data": { |
|||
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", |
|||
"userInfo": { |
|||
"id": "987654321", |
|||
"username": "13800138000", |
|||
"phone": "13800138000" |
|||
} |
|||
} |
|||
}, |
|||
"loginSuccessByPassword": { |
|||
"code": 200, |
|||
"message": "登录成功", |
|||
"interface": "login", |
|||
"data": { |
|||
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", |
|||
"userInfo": { |
|||
"id": "556677889", |
|||
"username": "testuser" |
|||
} |
|||
} |
|||
}, |
|||
"sendCodeSuccess": { |
|||
"code": 200, |
|||
"message": "验证码发送成功", |
|||
"interface": "sendCode", |
|||
"data": { |
|||
"expireTime": 180 |
|||
} |
|||
}, |
|||
"sendCodeFailureInvalidFormat": { |
|||
"code": 400, |
|||
"message": "手机号格式错误", |
|||
"interface": "sendCode" |
|||
}, |
|||
"sendCodeFailureTooFrequent": { |
|||
"code": 429, |
|||
"message": "发送频率过高,请稍后再试", |
|||
"interface": "sendCode" |
|||
}, |
|||
"registerSuccess": { |
|||
"code": 200, |
|||
"message": "注册成功", |
|||
"interface": "register", |
|||
"data": { |
|||
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", |
|||
"userInfo": { |
|||
"id": "112233445", |
|||
"username": "newuser", |
|||
"email": "newuser@example.com" |
|||
} |
|||
} |
|||
}, |
|||
"registerFailureEmailExist": { |
|||
"code": 400, |
|||
"message": "邮箱已被注册", |
|||
"interface": "register" |
|||
}, |
|||
"registerFailurePhoneExist": { |
|||
"code": 400, |
|||
"message": "手机号已被注册", |
|||
"interface": "register" |
|||
}, |
|||
"registerFailureWrongCode": { |
|||
"code": 400, |
|||
"message": "验证码错误", |
|||
"interface": "register" |
|||
}, |
|||
"updatePasswordSuccess": { |
|||
"code": 200, |
|||
"message": "密码修改成功", |
|||
"interface": "updatePassword" |
|||
}, |
|||
"updatePasswordFailureWrongOldPassword": { |
|||
"code": 400, |
|||
"message": "旧密码错误", |
|||
"interface": "updatePassword" |
|||
}, |
|||
"updatePasswordFailureWrongCode": { |
|||
"code": 400, |
|||
"message": "验证码错误", |
|||
"interface": "updatePassword" |
|||
}, |
|||
"forgotPasswordSuccessByEmail": { |
|||
"code": 200, |
|||
"message": "密码重置成功,新密码已发送至邮箱", |
|||
"interface": "forgotPassword" |
|||
}, |
|||
"forgotPasswordSuccessByPhone": { |
|||
"code": 200, |
|||
"message": "密码重置成功,新密码已发送至手机", |
|||
"interface": "forgotPassword" |
|||
}, |
|||
"forgotPasswordFailureAccountNotFound": { |
|||
"code": 404, |
|||
"message": "账号不存在", |
|||
"interface": "forgotPassword" |
|||
}, |
|||
"forgotPasswordFailureWrongCode": { |
|||
"code": 400, |
|||
"message": "验证码错误", |
|||
"interface": "forgotPassword" |
|||
} |
|||
} |
|||
|
After Width: 750 | Height: 198 | Size: 35 KiB |
|
After Width: 750 | Height: 198 | Size: 36 KiB |
|
After Width: 750 | Height: 198 | Size: 37 KiB |
|
After Width: 750 | Height: 198 | Size: 35 KiB |
|
After Width: 200 | Height: 200 | Size: 4.8 KiB |
|
After Width: 305 | Height: 200 | Size: 7.9 KiB |
|
After Width: 200 | Height: 200 | Size: 4.8 KiB |
|
After Width: 48 | Height: 48 | Size: 1.6 KiB |
|
After Width: 24 | Height: 24 | Size: 232 B |
|
After Width: 28 | Height: 31 | Size: 894 B |
|
After Width: 16 | Height: 15 | Size: 797 B |
|
After Width: 40 | Height: 40 | Size: 1.9 KiB |
|
After Width: 40 | Height: 40 | Size: 2.6 KiB |
|
After Width: 40 | Height: 40 | Size: 1.7 KiB |
|
After Width: 40 | Height: 40 | Size: 1.5 KiB |
|
After Width: 200 | Height: 200 | Size: 3.1 KiB |
|
After Width: 200 | Height: 200 | Size: 4.4 KiB |
|
After Width: 18 | Height: 18 | Size: 523 B |
|
After Width: 9 | Height: 9 | Size: 274 B |
|
After Width: 16 | Height: 16 | Size: 522 B |
|
After Width: 34 | Height: 34 | Size: 292 B |
|
After Width: 100 | Height: 70 | Size: 2.1 KiB |
|
After Width: 100 | Height: 50 | Size: 170 B |
|
After Width: 100 | Height: 67 | Size: 2.6 KiB |
|
After Width: 100 | Height: 67 | Size: 2.0 KiB |
|
After Width: 100 | Height: 50 | Size: 1.3 KiB |
|
After Width: 100 | Height: 71 | Size: 1.7 KiB |
|
After Width: 100 | Height: 50 | Size: 122 B |
|
After Width: 100 | Height: 67 | Size: 610 B |
|
After Width: 100 | Height: 67 | Size: 1.4 KiB |
|
After Width: 100 | Height: 100 | Size: 6.0 KiB |
|
After Width: 100 | Height: 63 | Size: 991 B |
|
After Width: 100 | Height: 50 | Size: 2.0 KiB |
|
After Width: 100 | Height: 67 | Size: 133 B |