封装request
This commit is contained in:
16
package-lock.json
generated
16
package-lock.json
generated
@@ -3812,7 +3812,6 @@
|
|||||||
"version": "2.5.1",
|
"version": "2.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz",
|
||||||
"integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==",
|
"integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==",
|
||||||
"dev": true,
|
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
@@ -3852,7 +3851,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -3873,7 +3871,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -3894,7 +3891,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -3915,7 +3911,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -3936,7 +3931,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -3957,7 +3951,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -3978,7 +3971,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -3999,7 +3991,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -4020,7 +4011,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -4041,7 +4031,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -4062,7 +4051,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -4083,7 +4071,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -4104,7 +4091,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -6100,7 +6086,6 @@
|
|||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
||||||
"integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
|
"integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -8812,7 +8797,6 @@
|
|||||||
"version": "7.1.1",
|
"version": "7.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
|
||||||
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
|
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
|||||||
51
src/api/login.js
Normal file
51
src/api/login.js
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
|
||||||
|
import { request } from '../utils/request'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户登录
|
||||||
|
* @param {Object} data - 登录数据 {username, password}
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
export function login(data) {
|
||||||
|
return request({
|
||||||
|
url: '/user/login',
|
||||||
|
method: 'POST',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户信息
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
export function getUserInfo() {
|
||||||
|
return request({
|
||||||
|
url: '/user/info',
|
||||||
|
method: 'GET'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新用户信息
|
||||||
|
* @param {Object} data - 用户信息
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
export function updateUserInfo(data) {
|
||||||
|
return request({
|
||||||
|
url: '/user/info',
|
||||||
|
method: 'PUT',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户注销
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
export function logout() {
|
||||||
|
return request({
|
||||||
|
url: '/user/logout',
|
||||||
|
method: 'POST'
|
||||||
|
})
|
||||||
|
}
|
||||||
49
src/main.js
49
src/main.js
@@ -1,46 +1,47 @@
|
|||||||
import { createSSRApp } from 'vue'
|
import { createSSRApp } from 'vue'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import { createI18n } from 'vue-i18n'
|
import { createI18n } from 'vue-i18n'
|
||||||
// 导入语言包
|
import { request, http } from '@/utils/request' // 引入封装的request
|
||||||
import en from './static/lang/enUS.json'
|
import en from './static/lang/enUS.json'
|
||||||
import cn from './static/lang/zh_CN.json'
|
import zh from './static/lang/zh_CN.json'
|
||||||
|
|
||||||
export function createApp() {
|
export function createApp() {
|
||||||
const app = createSSRApp(App)
|
const app = createSSRApp(App)
|
||||||
|
|
||||||
// 获取系统语言(适配uni-app环境)
|
// 1. 获取系统语言
|
||||||
const systemInfo = uni.getSystemInfoSync() || {};
|
const systemInfo = uni.getSystemInfoSync() || {}
|
||||||
const systemLanguage = systemInfo.language || 'zh-CN';
|
const systemLanguage = systemInfo.language || 'zh-CN'
|
||||||
let curLang = 'cn';
|
let curLang = 'zh'
|
||||||
|
|
||||||
// 语言判断(转换为小写处理)
|
|
||||||
switch (systemLanguage.toLowerCase()) {
|
switch (systemLanguage.toLowerCase()) {
|
||||||
case 'en':
|
case 'en':
|
||||||
case 'en-us':
|
case 'en-us':
|
||||||
curLang = 'en';
|
curLang = 'en'
|
||||||
break;
|
break
|
||||||
case 'zh':
|
case 'zh':
|
||||||
case 'zh-cn':
|
case 'zh-cn':
|
||||||
case 'zh-hans':
|
case 'zh-hans':
|
||||||
curLang = 'cn';
|
curLang = 'zh'
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// 配置i18n
|
// 2. 配置i18n
|
||||||
const i18n = createI18n({
|
const i18n = createI18n({
|
||||||
legacy: false,
|
legacy: false,
|
||||||
locale: curLang, // 使用检测到的系统语言
|
locale: curLang,
|
||||||
fallbackLocale: 'en',
|
fallbackLocale: 'en',
|
||||||
messages: {
|
messages: { en, zh },
|
||||||
en, // 英文语言包
|
|
||||||
cn // 中文语言包
|
|
||||||
},
|
|
||||||
missing: (locale, key) => {
|
missing: (locale, key) => {
|
||||||
console.error(`[i18n] 缺失: '${key}' 在 '${locale}' 语言包中不存在`);
|
console.error(`[i18n] 缺失: '${key}' 在 '${locale}' 语言包中不存在`)
|
||||||
return process.env.NODE_ENV === 'development' ? `[缺失: ${key}]` : '';
|
return process.env.NODE_ENV === 'development' ? `[缺失: ${key}]` : ''
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 3. 挂载request到全局
|
||||||
|
app.config.globalProperties.$request = request
|
||||||
|
app.config.globalProperties.$http = http
|
||||||
|
|
||||||
|
// 4. 使用i18n插件
|
||||||
app.use(i18n)
|
app.use(i18n)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -52,5 +53,15 @@ export function createApp() {
|
|||||||
// 非SSR模式下挂载应用
|
// 非SSR模式下挂载应用
|
||||||
if (!globalThis.__IS_SSR__) {
|
if (!globalThis.__IS_SSR__) {
|
||||||
const { app } = createApp()
|
const { app } = createApp()
|
||||||
|
|
||||||
|
// 全局错误处理
|
||||||
|
app.config.errorHandler = (err) => {
|
||||||
|
console.error('全局错误:', err)
|
||||||
|
uni.showToast({
|
||||||
|
title: '发生错误,请重试',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
app.mount('#app')
|
app.mount('#app')
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,12 @@
|
|||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": ""
|
"navigationBarTitleText": ""
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/home/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"globalStyle": {
|
"globalStyle": {
|
||||||
|
|||||||
372
src/pages/home/index.vue
Normal file
372
src/pages/home/index.vue
Normal file
@@ -0,0 +1,372 @@
|
|||||||
|
<template>
|
||||||
|
<view class="stock-home-container">
|
||||||
|
<!-- 顶部用户信息栏 -->
|
||||||
|
<view class="user-header">
|
||||||
|
<view class="user-info">
|
||||||
|
<image class="avatar" src="/static/images/avatar.png" mode="aspectFill"></image>
|
||||||
|
<view class="user-details">
|
||||||
|
<text class="username">Welcome, {{userName}}</text>
|
||||||
|
<text class="account-id">Account ID: {{accountId}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="account-summary">
|
||||||
|
<text class="total-assets">${{formatNumber(totalAssets)}}</text>
|
||||||
|
<text class="asset-change" :class="{'positive': dailyChange >= 0, 'negative': dailyChange < 0}">
|
||||||
|
{{dailyChange >= 0 ? '+' : ''}}{{formatNumber(dailyChange)}} ({{dailyChangePercent >= 0 ? '+' : ''}}{{dailyChangePercent}}%)
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 主要功能入口 -->
|
||||||
|
<view class="quick-actions">
|
||||||
|
<view class="action-item" @click="navigateTo('trade')">
|
||||||
|
<image src="/static/icons/trade.png"></image>
|
||||||
|
<text>Trade</text>
|
||||||
|
</view>
|
||||||
|
<view class="action-item" @click="navigateTo('deposit')">
|
||||||
|
<image src="/static/icons/deposit.png"></image>
|
||||||
|
<text>Deposit</text>
|
||||||
|
</view>
|
||||||
|
<view class="action-item" @click="navigateTo('withdraw')">
|
||||||
|
<image src="/static/icons/withdraw.png"></image>
|
||||||
|
<text>Withdraw</text>
|
||||||
|
</view>
|
||||||
|
<view class="action-item" @click="navigateTo('transfer')">
|
||||||
|
<image src="/static/icons/transfer.png"></image>
|
||||||
|
<text>Transfer</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 自选股票列表 -->
|
||||||
|
<view class="watchlist-section">
|
||||||
|
<view class="section-header">
|
||||||
|
<text class="section-title">Watchlist</text>
|
||||||
|
<text class="section-more" @click="navigateTo('watchlist')">More ></text>
|
||||||
|
</view>
|
||||||
|
<scroll-view scroll-x class="stock-scroll">
|
||||||
|
<view class="stock-card" v-for="(stock, index) in watchlist" :key="index" @click="viewStockDetail(stock)">
|
||||||
|
<text class="stock-symbol">{{stock.symbol}}</text>
|
||||||
|
<text class="stock-name">{{stock.name}}</text>
|
||||||
|
<text class="stock-price">${{stock.price}}</text>
|
||||||
|
<text class="stock-change" :class="{'positive': stock.change >= 0, 'negative': stock.change < 0}">
|
||||||
|
{{stock.change >= 0 ? '+' : ''}}{{stock.change}}%
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 市场指数 -->
|
||||||
|
<view class="market-indices">
|
||||||
|
<view class="section-header">
|
||||||
|
<text class="section-title">Market Indices</text>
|
||||||
|
<text class="section-more" @click="navigateTo('markets')">More ></text>
|
||||||
|
</view>
|
||||||
|
<view class="indices-container">
|
||||||
|
<view class="index-item" v-for="(index, i) in marketIndices" :key="i">
|
||||||
|
<text class="index-name">{{index.name}}</text>
|
||||||
|
<text class="index-value">{{index.value}}</text>
|
||||||
|
<text class="index-change" :class="{'positive': index.change >= 0, 'negative': index.change < 0}">
|
||||||
|
{{index.change >= 0 ? '+' : ''}}{{index.change}}%
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 新闻资讯 -->
|
||||||
|
<view class="news-section">
|
||||||
|
<view class="section-header">
|
||||||
|
<text class="section-title">Market News</text>
|
||||||
|
<text class="section-more" @click="navigateTo('news')">More ></text>
|
||||||
|
</view>
|
||||||
|
<view class="news-list">
|
||||||
|
<view class="news-item" v-for="(news, idx) in marketNews" :key="idx" @click="viewNewsDetail(news)">
|
||||||
|
<image class="news-image" :src="news.imageUrl" mode="aspectFill"></image>
|
||||||
|
<view class="news-content">
|
||||||
|
<text class="news-title">{{news.title}}</text>
|
||||||
|
<text class="news-time">{{formatTime(news.time)}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
userName: "John Doe",
|
||||||
|
accountId: "EU20230001",
|
||||||
|
totalAssets: 125430.56,
|
||||||
|
dailyChange: 1254.32,
|
||||||
|
dailyChangePercent: 1.01,
|
||||||
|
watchlist: [
|
||||||
|
{ symbol: "AAPL", name: "Apple Inc.", price: 175.34, change: 1.23 },
|
||||||
|
{ symbol: "MSFT", name: "Microsoft", price: 328.39, change: 0.56 },
|
||||||
|
{ symbol: "TSLA", name: "Tesla", price: 260.54, change: -2.34 },
|
||||||
|
{ symbol: "AMZN", name: "Amazon", price: 134.56, change: 0.89 },
|
||||||
|
{ symbol: "GOOGL", name: "Alphabet", price: 125.67, change: -0.45 }
|
||||||
|
],
|
||||||
|
marketIndices: [
|
||||||
|
{ name: "S&P 500", value: 4524.09, change: 0.42 },
|
||||||
|
{ name: "NASDAQ", value: 14019.31, change: 0.85 },
|
||||||
|
{ name: "Dow 30", value: 34721.12, change: -0.12 },
|
||||||
|
{ name: "FTSE 100", value: 7527.53, change: 0.23 }
|
||||||
|
],
|
||||||
|
marketNews: [
|
||||||
|
{
|
||||||
|
title: "Fed signals more rate hikes to combat inflation",
|
||||||
|
imageUrl: "/static/images/news1.jpg",
|
||||||
|
time: "2023-06-15T09:30:00Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Tech stocks rally as AI boom continues",
|
||||||
|
imageUrl: "/static/images/news2.jpg",
|
||||||
|
time: "2023-06-15T08:45:00Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "European markets open higher amid positive earnings",
|
||||||
|
imageUrl: "/static/images/news3.jpg",
|
||||||
|
time: "2023-06-15T07:15:00Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// formatNumber(num) {
|
||||||
|
// return num.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
||||||
|
// },
|
||||||
|
// formatTime(timeString) {
|
||||||
|
// const date = new Date(timeString);
|
||||||
|
// return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
||||||
|
// },
|
||||||
|
// navigateTo(page) {
|
||||||
|
// uni.navigateTo({
|
||||||
|
// url: `/pages/${page}/${page}`
|
||||||
|
// });
|
||||||
|
// },
|
||||||
|
// viewStockDetail(stock) {
|
||||||
|
// uni.navigateTo({
|
||||||
|
// url: `/pages/stock/detail?symbol=${stock.symbol}`
|
||||||
|
// });
|
||||||
|
// },
|
||||||
|
// viewNewsDetail(news) {
|
||||||
|
// uni.navigateTo({
|
||||||
|
// url: `/pages/news/detail?title=${encodeURIComponent(news.title)}`
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.stock-home-container {
|
||||||
|
padding: 20rpx;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
min-height: 100vh;
|
||||||
|
padding-bottom: 120rpx; /* 给底部导航留空间 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-header {
|
||||||
|
background: linear-gradient(135deg, #1976D2, #2196F3);
|
||||||
|
border-radius: 16rpx;
|
||||||
|
padding: 30rpx;
|
||||||
|
color: white;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 100rpx;
|
||||||
|
height: 100rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-details {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-id {
|
||||||
|
font-size: 24rpx;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-summary {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.total-assets {
|
||||||
|
font-size: 48rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.asset-change {
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.positive {
|
||||||
|
color: #4CAF50;
|
||||||
|
}
|
||||||
|
|
||||||
|
.negative {
|
||||||
|
color: #F44336;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
padding: 20rpx;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-item image {
|
||||||
|
width: 60rpx;
|
||||||
|
height: 60rpx;
|
||||||
|
margin-bottom: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-item text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin: 30rpx 0 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-more {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #1976D2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-scroll {
|
||||||
|
white-space: nowrap;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-card {
|
||||||
|
display: inline-block;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
padding: 20rpx;
|
||||||
|
margin-right: 20rpx;
|
||||||
|
width: 200rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-symbol {
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-name {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #666;
|
||||||
|
display: block;
|
||||||
|
margin: 10rpx 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-price {
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-change {
|
||||||
|
font-size: 24rpx;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indices-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.index-item {
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
padding: 20rpx;
|
||||||
|
width: 48%;
|
||||||
|
margin-bottom: 15rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.index-name {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.index-value {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 10rpx 0;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-list {
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-item {
|
||||||
|
display: flex;
|
||||||
|
padding: 20rpx;
|
||||||
|
border-bottom: 1rpx solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-image {
|
||||||
|
width: 160rpx;
|
||||||
|
height: 120rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
margin-right: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-content {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-title {
|
||||||
|
font-size: 28rpx;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-time {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -140,6 +140,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// import {
|
||||||
|
// login,
|
||||||
|
// getUserInfo,
|
||||||
|
// } from '@/api/login'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -158,6 +163,7 @@ export default {
|
|||||||
onLoad() {
|
onLoad() {
|
||||||
this.currentLang = this.$i18n.locale
|
this.currentLang = this.$i18n.locale
|
||||||
this.loadRememberedAccount()
|
this.loadRememberedAccount()
|
||||||
|
// console.log(login(1))
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
togglePasswordVisibility() {
|
togglePasswordVisibility() {
|
||||||
@@ -194,37 +200,38 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleLogin() {
|
handleLogin() {
|
||||||
if (!this.agreeTerms) {
|
// if (!this.agreeTerms) {
|
||||||
this.showError = true
|
// this.showError = true
|
||||||
this.errorMessage = this.$t('login.errors.agreeTermsFirst')
|
// this.errorMessage = this.$t('login.errors.agreeTermsFirst')
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (!this.username) {
|
// if (!this.username) {
|
||||||
this.showError = true
|
// this.showError = true
|
||||||
this.errorMessage = this.$t('login.errors.emptyUsername')
|
// this.errorMessage = this.$t('login.errors.emptyUsername')
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (this.username.length !== 6 || !/^\d{6}$/.test(this.username)) {
|
// if (this.username.length !== 6 || !/^\d{6}$/.test(this.username)) {
|
||||||
this.showError = true
|
// this.showError = true
|
||||||
this.errorMessage = this.$t('login.errors.invalidIdCard')
|
// this.errorMessage = this.$t('login.errors.invalidIdCard')
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (!this.password) {
|
// if (!this.password) {
|
||||||
this.showError = true
|
// this.showError = true
|
||||||
this.errorMessage = this.$t('login.errors.emptyPassword')
|
// this.errorMessage = this.$t('login.errors.emptyPassword')
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
this.isLoading = true
|
// this.isLoading = true
|
||||||
this.showError = false
|
// this.showError = false
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
console.log('登录信息:', { username: this.username, password: this.password })
|
console.log('登录信息:', { username: this.username, password: this.password })
|
||||||
this.saveRememberedAccount()
|
this.saveRememberedAccount()
|
||||||
uni.navigateTo({ url: '/pages/index/index' })
|
uni.redirectTo({ url: '/pages/home/index' })
|
||||||
|
console.log('登录成功')
|
||||||
this.isLoading = false
|
this.isLoading = false
|
||||||
}, 1500)
|
}, 1500)
|
||||||
},
|
},
|
||||||
@@ -246,18 +253,19 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
handleForgotPassword() {
|
//修改密码的js实现方法
|
||||||
uni.showModal({
|
// handleForgotPassword() {
|
||||||
title: this.$t('login.forgotPassword'),
|
// uni.showModal({
|
||||||
content: this.$t('login.forgotPasswordDesc'),
|
// title: this.$t('login.forgotPassword'),
|
||||||
confirmText: this.$t('login.resetPassword'),
|
// content: this.$t('login.forgotPasswordDesc'),
|
||||||
success: (res) => {
|
// confirmText: this.$t('login.resetPassword'),
|
||||||
if (res.confirm) {
|
// success: (res) => {
|
||||||
uni.navigateTo({ url: '/pages/reset-password/reset-password' })
|
// if (res.confirm) {
|
||||||
}
|
// uni.navigateTo({ url: '/pages/reset-password/reset-password' })
|
||||||
}
|
// }
|
||||||
})
|
// }
|
||||||
}
|
// })
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,5 +1,45 @@
|
|||||||
{
|
{
|
||||||
"index.Loading": "Loading",
|
"index.Loading": "Loading...",
|
||||||
"index.errMsg": "Error"
|
"index.errMsg": "Failed to load",
|
||||||
|
"login.loginButton": "Login",
|
||||||
|
"login.usernamePlaceholder": "Please enter username",
|
||||||
|
"login.idCardLabel": "Last 6 digits of ID card",
|
||||||
|
"login.passwordPlaceholder": "Please enter password",
|
||||||
|
"login.passwordLabel": "Password",
|
||||||
|
"login.appTitle": "European Stock Software",
|
||||||
|
"login.rememberPassword": "Remember password",
|
||||||
|
"login.forgotPassword": "Forgot password",
|
||||||
|
"login.agreeTermsPrefix": "I have read and agree to",
|
||||||
|
"login.agreeTermsSuffix": "User Agreement",
|
||||||
|
"login.userAgreement": "User Agreement",
|
||||||
|
"login.and": "and",
|
||||||
|
"login.privacyPolicy": "Privacy Policy",
|
||||||
|
"login.registerButton": "Register",
|
||||||
|
"login.noAccount": "No account?",
|
||||||
|
"login.languagechangeclose": "Done",
|
||||||
|
"login.chooseLanguage": "Select Language",
|
||||||
|
"login.changelanguage": "Change Language",
|
||||||
|
|
||||||
|
"register.chooseLanguage": "Select Language",
|
||||||
|
"register.languagechangeclose": "Done",
|
||||||
|
"register.appTitle": "European & American Stock Software",
|
||||||
|
"register.registerDesc": "Create an account to continue",
|
||||||
|
"register.idCardLabel": "Last 6 digits of ID card",
|
||||||
|
"register.idCardPlaceholder": "Please enter last 6 digits of ID card",
|
||||||
|
"register.passwordLabel": "Password",
|
||||||
|
"register.passwordPlaceholder": "Please enter password",
|
||||||
|
"register.confirmPasswordLabel": "Confirm Password",
|
||||||
|
"register.confirmPasswordPlaceholder": "Please confirm password again",
|
||||||
|
"register.inviteCodeLabel": "Invitation Code",
|
||||||
|
"register.inviteCodePlaceholder": "Please enter invitation code",
|
||||||
|
"register.emailLabel": "Email",
|
||||||
|
"register.emailPlaceholder": "Please enter email",
|
||||||
|
"register.agreeTermsPrefix": "I have read and agree to",
|
||||||
|
"register.userAgreement": "User Agreement",
|
||||||
|
"register.and": "and",
|
||||||
|
"register.privacyPolicy": "Privacy Policy",
|
||||||
|
"register.registerButton": "Register",
|
||||||
|
"register.hasAccount": "Already have an account?",
|
||||||
|
"register.loginNow": "Login now",
|
||||||
|
"register.registerSuccess": "Registration successful"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,10 @@
|
|||||||
"login.languagechangeclose": "完成",
|
"login.languagechangeclose": "完成",
|
||||||
"login.chooseLanguage": "选择语言",
|
"login.chooseLanguage": "选择语言",
|
||||||
"login.changelanguage": "切换语言",
|
"login.changelanguage": "切换语言",
|
||||||
|
"login.errors.agreeTermsFirst": "请先同意用户协议和隐私政策",
|
||||||
|
"login.errors.emptyUsername": "请输入用户名",
|
||||||
|
"login.errors.invalidIdCard": "请输入正确身份证号码的后六位",
|
||||||
|
"login.errors.emptyPassword": "请输入密码",
|
||||||
|
|
||||||
|
|
||||||
"register.chooseLanguage": "选择语言",
|
"register.chooseLanguage": "选择语言",
|
||||||
|
|||||||
134
src/utils/request.js
Normal file
134
src/utils/request.js
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
// utils/request.js
|
||||||
|
|
||||||
|
const BASE_URL = process.env.VUE_APP_API_BASE_URL || '/api'
|
||||||
|
const TOKEN_KEY = 'auth_token'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基础请求方法
|
||||||
|
*/
|
||||||
|
export function request(options) {
|
||||||
|
// 默认配置
|
||||||
|
const defaultOptions = {
|
||||||
|
url: '',
|
||||||
|
method: 'GET',
|
||||||
|
data: {},
|
||||||
|
header: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
timeout: 10000,
|
||||||
|
showLoading: false,
|
||||||
|
loadingText: '加载中...',
|
||||||
|
checkAuth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 合并配置
|
||||||
|
options = { ...defaultOptions, ...options }
|
||||||
|
|
||||||
|
// 请求拦截 - 处理URL
|
||||||
|
if (!options.url.startsWith('http')) {
|
||||||
|
options.url = BASE_URL + options.url
|
||||||
|
}
|
||||||
|
|
||||||
|
// 请求拦截 - 添加token
|
||||||
|
if (options.checkAuth) {
|
||||||
|
const token = uni.getStorageSync(TOKEN_KEY)
|
||||||
|
if (token) {
|
||||||
|
options.header.Authorization = `Bearer ${token}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示加载提示
|
||||||
|
if (options.showLoading) {
|
||||||
|
uni.showLoading({
|
||||||
|
title: options.loadingText,
|
||||||
|
mask: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
uni.request({
|
||||||
|
...options,
|
||||||
|
success: (res) => {
|
||||||
|
handleResponse(res, resolve, reject)
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
handleError(err, reject)
|
||||||
|
},
|
||||||
|
complete: () => {
|
||||||
|
if (options.showLoading) {
|
||||||
|
uni.hideLoading()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 响应处理函数
|
||||||
|
function handleResponse(res, resolve, reject) {
|
||||||
|
if (res.statusCode === 200) {
|
||||||
|
resolve(res.data)
|
||||||
|
} else if (res.statusCode === 401) {
|
||||||
|
handleUnauthorized()
|
||||||
|
reject(new Error('未授权'))
|
||||||
|
} else {
|
||||||
|
handleHttpError(res.statusCode)
|
||||||
|
reject(new Error(`HTTP错误: ${res.statusCode}`))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 错误处理函数
|
||||||
|
function handleError(err, reject) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '网络连接错误',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000
|
||||||
|
})
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTP错误处理
|
||||||
|
function handleHttpError(statusCode) {
|
||||||
|
const errorMap = {
|
||||||
|
400: '请求参数错误',
|
||||||
|
403: '拒绝访问',
|
||||||
|
404: '资源不存在',
|
||||||
|
500: '服务器错误'
|
||||||
|
}
|
||||||
|
uni.showToast({
|
||||||
|
title: errorMap[statusCode] || `请求错误: ${statusCode}`,
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 未授权处理
|
||||||
|
function handleUnauthorized() {
|
||||||
|
uni.removeStorageSync(TOKEN_KEY)
|
||||||
|
uni.showToast({
|
||||||
|
title: '登录已过期',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 1500
|
||||||
|
})
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/login/login'
|
||||||
|
})
|
||||||
|
}, 1500)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 快捷方法
|
||||||
|
*/
|
||||||
|
export const http = {
|
||||||
|
get: (url, params, options) =>
|
||||||
|
request({ url, params, method: 'GET', ...options }),
|
||||||
|
|
||||||
|
post: (url, data, options) =>
|
||||||
|
request({ url, data, method: 'POST', ...options }),
|
||||||
|
|
||||||
|
put: (url, data, options) =>
|
||||||
|
request({ url, data, method: 'PUT', ...options }),
|
||||||
|
|
||||||
|
delete: (url, data, options) =>
|
||||||
|
request({ url, data, method: 'DELETE', ...options })
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user