Browse Source

Merge branch 'milestone-20251031-简版功能开发' of http://39.101.133.168:8807/qimaohong/deepChartVueApp into milestone-20251031-简版功能开发

zhaowenkang/feature-20251028181547-行情页面
宋杰 4 weeks ago
parent
commit
bcb3e2d095
  1. 17
      api/deepExploration/deepExploration.js
  2. 37
      api/member.js
  3. 11
      api/setting/general.js
  4. 16
      api/setting/nextPwd.js
  5. 45
      api/setting/password.js
  6. 30
      api/start/login.js
  7. 2
      components/deepExploration_header.vue
  8. 23
      components/login-prompt.vue
  9. 12
      package-lock.json
  10. 7
      package.json
  11. 25
      pages.json
  12. 779
      pages/deepExploration/MainForceActions.vue
  13. 57
      pages/deepMate/deepMate.vue
  14. 15
      pages/home/member.vue
  15. 655
      pages/marketSituation/chartExample.vue
  16. 615
      pages/marketSituation/marketCondition.vue
  17. 15
      pages/marketSituation/marketOverview.vue
  18. 46
      pages/setting/account.vue
  19. 245
      pages/setting/createPwd.vue
  20. 57
      pages/setting/email.vue
  21. 34
      pages/setting/font.vue
  22. 51
      pages/setting/general.vue
  23. 2
      pages/setting/introduce.vue
  24. 1
      pages/setting/market.vue
  25. 9
      pages/setting/message.vue
  26. 45
      pages/setting/nextPwd.vue
  27. 88
      pages/setting/password.vue
  28. 54
      pages/setting/phone.vue
  29. 48
      pages/setting/push.vue
  30. 23
      pages/setting/server.vue
  31. 21
      pages/setting/theme.vue
  32. 3
      pages/start/Registration/Registration.vue
  33. 56
      pages/start/index/index.vue
  34. 93
      pages/start/recoverPassword/recoverPassword.vue
  35. 25
      static/language/en.js
  36. 7
      static/language/ms.js
  37. 7
      static/language/th.js
  38. 7
      static/language/vi.js
  39. 21
      static/language/zh_CN.js
  40. 21
      static/language/zh_HK.js
  41. 1
      stores/index.js
  42. 44
      stores/modules/login.js
  43. 13
      utils/http.js
  44. 14
      vue.config.js

17
api/deepExploration/deepExploration.js

@ -74,7 +74,24 @@ export const getModel4Second = (data) => {
})
}
//不搜索时走这个
export const getModeldefault = (data) => {
return http({
method: 'POST',
url: '/api/coze/default',
data
})
}
//k线数据
export const getData = (data) => {
return http({
method: 'POST',
url: '/api/coze/WorkFlowData',
data
})
}
//历史记录列表
export const RecordListApi = (data) => {

37
api/member.js

@ -0,0 +1,37 @@
import util from '../common/util.js'
/*export const getUserInfo = (data = {}) => {
return util.request(
'/api/my/userInfo',
(res) => {
console.log('用户信息请求成功:', res);
},
{data},
(err) => {
console.log('用户信息请求失败:', err);
}
);
};
*/
import {
http
} from '../utils/http'
/**
* 用户信息获取接口
* @param data
* @returns {Promise<unknown>}
*/
export const getUserInfo = (data) => {
return http({
method: 'POST',
url: '/api/my/userInfo',
data: data,
header:{
token:'014de5283d2930af6481ede591afd087'
}
})
}

11
api/setting/general.js

@ -0,0 +1,11 @@
import { http } from '../../utils/http'
export const getSetting = (data) => {
return http({
method: 'POST',
url: '/api/my/getSetting',
data: data,
})
}

16
api/setting/nextPwd.js

@ -0,0 +1,16 @@
import {http} from '../../utils/http'
/**
* 修改密码
* @param data
* @returns {*}
*/
export const updatePassword = (data) => {
return http({
method: 'POST',
url: '/api/my/updatePassword',
data:
data
,
})
}

45
api/setting/password.js

@ -0,0 +1,45 @@
import {
http
} from '../../utils/http'
/**
* 验证码发送
* @param data
* @returns {*}
*/
export const sendEmail = (data) => {
return http({
method: 'POST',
url: '/UserLogin/sendEmail',
data: data,
})
}
/**
* 验证码验证
* @param data
* @returns {*}
*/
export const validateCode = (data) => {
return http({
method: 'POST',
url: '/api/my/validateCode',
data: data,
})
}
export const sendPhone = (data) => {
return http({
method: 'POST',
url: '/UserLogin/sendPhone',
data: data,
})
}
export const changeBind = (data) => {
return http({
method: 'POST',
url: '/api/my/bindEmailOrPhone',
data: data,
})
}

30
api/start/login.js

@ -67,6 +67,36 @@ export const registerApi = (data) => {
})
}
/**
* 忘记密码校验验证码
*/
export const verifyCodeApi = (data) => {
return http({
method: 'POST',
url: '/UserLogin/verifyCode',
data: data,
})
}
/**
* 忘记密码输入新的密码
*/
export const forgetApi = (data) => {
return http({
method: 'POST',
url: '/UserLogin/forget',
data: data,
})
}
/**
* 修改密码
*

2
components/deepExploration_header.vue

@ -72,6 +72,7 @@
<view class="history-main" @click="itemClick(item)">
<text class="history-query">{{ item.stockName }}</text>
<text class="history-query">{{ item.stockCode }}</text>
<text class="history-query">{{ item.stockCode }}</text>
</view>
<text class="history-time">{{
formatTimeForHistory(item.createdTime)
@ -98,6 +99,7 @@ const props = defineProps({
},
});
const showHistoryDrawer = ref(false);
const modelType = ref('');
const drawerOffsetY = ref(0);
// const handleHistory = () => {
// showHistoryDrawer.value = true;

23
components/login-prompt.vue

@ -15,19 +15,39 @@
</template>
<script setup>
import { ref, nextTick, onMounted } from "vue";
import { ref, nextTick, onMounted, watch } from "vue";
import { useUserStore } from "../stores/modules/userInfo";
import { useDeviceStore } from "../stores/modules/deviceInfo";
import { useLoginStore } from "../stores/modules/login";
import { LoginApi } from "../api/start/login";
const deviceId = ref("");
const userStore = useUserStore();
const deviceStore = useDeviceStore();
const loginStore = useLoginStore();
//
onMounted(() => {
if (!userStore.userInfo) {
show();
}
}),
// watch(
// () => loginStore.loginInfo,
// (newVal, oldVal) => {
// console.log("");
// if (newVal === "false") {
// console.log("");
// show();
// loginStore.setLoginInfo("true");
// }
// }
// );
loginStore.$subscribe(() => {
if (loginStore.loginInfo === "false") {
console.log("登录失败");
show();
}
});
//
@ -84,6 +104,7 @@ const continueAsVisitor = async () => {
if (res.code === 200) {
userStore.setUserInfo(res.data);
console.log("0loginStore.loginInfo", loginStore.loginInfo);
hide();
//

12
package-lock.json

@ -8,6 +8,7 @@
"@dcloudio/uni-ui": "^1.5.11",
"@element-plus/icons-vue": "^2.3.2",
"element-plus": "^2.11.5",
"highlight.js": "^11.11.1",
"marked": "^2.0.1",
"pinia": "^3.0.3",
"pinia-plugin-persistedstate": "^4.5.0",
@ -480,6 +481,15 @@
"license": "MIT",
"peer": true
},
"node_modules/highlight.js": {
"version": "11.11.1",
"resolved": "https://registry.npmmirror.com/highlight.js/-/highlight.js-11.11.1.tgz",
"integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/hookable": {
"version": "5.5.3",
"license": "MIT"
@ -598,6 +608,8 @@
},
"node_modules/pinia-plugin-persistedstate": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/pinia-plugin-persistedstate/-/pinia-plugin-persistedstate-4.5.0.tgz",
"integrity": "sha512-QTkP1xJVyCdr2I2p3AKUZM84/e+IS+HktRxKGAIuDzkyaKKV48mQcYkJFVVDuvTxlI5j6X3oZObpqoVB8JnWpw==",
"license": "MIT",
"dependencies": {
"deep-pick-omit": "^1.2.1",

7
package.json

@ -3,11 +3,10 @@
"@dcloudio/uni-ui": "^1.5.11",
"@element-plus/icons-vue": "^2.3.2",
"element-plus": "^2.11.5",
"vue-i18n": "^9.14.5",
"highlight.js": "^11.11.1",
"marked": "^2.0.1",
"pinia": "^3.0.3",
"pinia-plugin-persistedstate": "^4.5.0"
"pinia-plugin-persistedstate": "^4.5.0",
"vue-i18n": "^9.14.5"
}
}

25
pages.json

@ -29,16 +29,6 @@
}
},
{
"path": "pages/start/index/index",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "uni-app",
"disableSwipeBack": true,
"titleNView": false,
"bounce": false
}
},
{
"path": "pages/start/Registration/Registration",
"style": {
"navigationBarTitleText": "",
@ -107,14 +97,6 @@
}
},
{
"path": "pages/marketSituation/chartExample",
"style": {
"navigationBarTitleText": "图表示例",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black"
}
},
{
"path": "pages/marketSituation/globalIndex",
"style": {
"navigationStyle": "custom",
@ -317,6 +299,13 @@
{
"navigationBarTitleText": "选股策略"
}
},
{
"path" : "pages/setting/createPwd",
"style" :
{
"navigationBarTitleText" : "创建密码"
}
}
],
"globalStyle": {

779
pages/deepExploration/MainForceActions.vue

@ -47,9 +47,12 @@
<view class="txt">
<view class="txtHeader">
<image src="/static/deepExploration-images/plus.png" mode="aspectFill"></image>
<text>主力追踪</text>
<text>{{navItems[currentIndex].name}}</text>
</view>
<view class="txtContent">
<view v-if="loading" class="loading">加载中...</view>
<rich-text :nodes="htmlContent"></rich-text>
</view>
<view class="txtContent"></view>
</view>
</view>
</view>
@ -78,7 +81,12 @@
getModel3Second,
getModel4First,
getModel4Second,
getModeldefault,
getData
} from '/api/deepExploration/deepExploration.js'
import marked from 'marked'; // marked
import hljs from 'highlight.js';
import 'highlight.js/styles/atom-one-dark.css'; //
//
const type = ref('deepExploration')
@ -104,18 +112,11 @@
//
const searchStock = () => {
htmlContent.value = ''
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)
if (currentIndex.value ) {
handleModels()
getServerData()
} else {
uni.showToast({
title: '请选择模块',
@ -126,21 +127,10 @@
}
//
const handleModel = (index) => {
const handleModel = async(index) => {
htmlContent.value = ''
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()
}
await handleModels()
}
const stockName = ref('')
@ -150,14 +140,53 @@
const recordId = ref('')
const parentId = ref('')
const stockId = ref('')
//
const handleTrack = async () => {
const market = ref('')
const loading = ref(true);
const error = ref('');
const htmlContent = ref('');
const markdownContent = ref('');
const renderer = new marked.Renderer();
renderer.heading = function(text, level) {
return `<p>${text}</p>`;
};
// marked
marked.setOptions({
highlight: (code, lang) => {
if (lang && hljs.getLanguage(lang)) {
return hljs.highlight(code, {
language: lang
}).value;
}
return hljs.highlightAuto(code).value;
},
renderer,
breaks: true, // <br>
gfm: true, // GitHub flavored Markdown
sanitize: false, // HTML<span style>
});
//
const handleModels = async () => {
try {
// markdownContent.value = '\n## 📊 \n\n### 🕵 \n\t1. 📊 360.249 412.577 444.330\n\t2. 🔍 \n\t3. 📈 \n\n### 📊 :\n\t- 📉 : <font color=\"#13c2c2\">443.092</font> \n - 📈 : <font color=\"#ff4d4f\">466.458</font>\n\t- 📉 : <font color=\"#13c2c2\">447.354</font>\n\t- 📈 : <font color=\"#ff4d4f\">462.514</font>\n\t<font color=\"#722ed1\">AI线</font>\n\n### \n\t\t\t<font color=\"#fa8c16\">K线</font>\n\t\t\t<font color=\"#eb2f96\"></font>\n\n---\n<font color=\"#8c8c8c\">*AI*</font>\n '
// htmlContent.value = marked.parse(markdownContent.value);
loading.value = true;
if (searchName.value == '') {
console.log('没有搜索',searchName.value);
const rresult = await handleDefault()
// markdownContent.value = res.data.markdown
htmlContent.value = marked.parse(markdownContent.value);
}else{
console.log('搜索',searchName.value);
const result = await getModel1First({
content: searchName.value,
language: "cn",
marketList: "hk,cn,usa,my,sg,vi,in,gb",
model: 1
model: currentIndex.value+1
})
console.log('result', result);
if (result.code == 200) {
@ -167,36 +196,61 @@
parentId.value = result.data.parentId
stockId.value = result.data.stockId
language.value = result.data.language
market.value = result.data.market
} else {
return
}
const res = await getModel1Second({
language: language.value,
recordId: recordId.value,
parentId: parentId.value,
stockId: stockId.value
stockId: stockId.value,
token: 'pCtw6AYK0EHAaIexoFHsbZjtsfEAIhcmwkCFm6uKko8VPfMvyDiODL9v9c0veic9fIpQbvT8zN4sH/Si6Q'
})
if (res.code == 200) {
const rawMarkdown = res.data.markdown;
const adaptedMarkdown = rawMarkdown.replace(/^### /gm, ''); // ###
markdownContent.value = adaptedMarkdown;
// markdownContent.value = res.data.markdown
htmlContent.value = marked.parse(markdownContent.value);
}
console.log('res', res);
}
} catch {
} catch {
error.value = e.message || '加载失败,请重试';
} finally {
loading.value = false;
}
}
//
const handleRadar = () => {
}
//
const handleDecode = () => {
const handleDefault = async () => {
const result = await getModeldefault({
token: "pCtw6AYK0EHAaIexoFHsbZjtsfEAIhcmwkCFm6uKko8VPfMvyDiODL9v9c0veic9fIpQbvT8zN4sH/Si6Q",
model: currentIndex.value+1
})
const rawMarkdown = result.data.markdown;
const adaptedMarkdown = rawMarkdown.replace(/^### /gm, ''); // ###
markdownContent.value = adaptedMarkdown;
htmlContent.value = marked.parse(markdownContent.value);
}
//
const handleCapitalFlow = () => {
const getServerData = async() =>{
const result = await getData({
market: market.value || '',
code: searchName || '',
language: "cn",
brainPrivilegeState: 1,
marketList: "usa.sg.my.hk.cn.can.vi.th.in.gb"
})
console.log('k线数据',result);
}
// 1. K线
const opts = ref({
rotate: false,
@ -265,302 +319,302 @@
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)
}
// 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(() => {
@ -584,8 +638,9 @@
<style scoped lang="scss">
.main {
width: 100%;
height: 100vh;
min-height: 100vh;
background-color: #fff;
padding-bottom: 120rpx;
.search {
position: relative;
@ -660,7 +715,6 @@
}
.graphAndTxt {
height: 300rpx;
background-color: #fff;
border-radius: 50rpx 50rpx 0 0;
padding: 68.6rpx 36.5rpx 0 36.5rpx;
@ -783,6 +837,51 @@
.txtContent {
min-height: 200rpx;
padding: 20rpx 30rpx;
margin-bottom: 100rpx;
::v-deep * {
box-sizing: border-box;
width: 100% !important; //
white-space: normal !important; //
word-wrap: break-word !important; // /
}
//
::v-deep h2 {
font-size: 32rpx;
color: #333;
margin: 25rpx 0 15rpx;
line-height: 1.5;
}
//
::v-deep p {
font-size: 26rpx;
color: #666;
margin: 15rpx 0;
line-height: 1.8; //
text-align: justify; //
}
//
::v-deep ul,
::v-deep ol {
margin: 15rpx 0 15rpx 30rpx;
}
::v-deep li {
margin: 10rpx 0;
line-height: 1.6;
}
//
.loading {
text-align: center;
padding: 50rpx 0;
color: #666;
font-size: 26rpx;
}
}
}
}

57
pages/deepMate/deepMate.vue

@ -19,7 +19,8 @@
<image
src="https://d31zlh4on95l9h.cloudfront.net/images/d7c4e74201213a25dd9574e908233928.svg"
class="icon"
@click="goToNotice" @tap="goToNotice"
@click="goToNotice"
@tap="goToNotice"
>
</image>
<image
@ -297,6 +298,11 @@ import {
postHistory,
postHistoryDetail,
} from "../../api/deepMate/deepMate";
const renderer = new marked.Renderer();
renderer.heading = function (text, level) {
return `<p>${text}</p>`;
};
// marked
marked.setOptions({
renderer: new marked.Renderer(),
@ -621,13 +627,20 @@ const simulateBotResponse = async (userMessage) => {
isSending.value = true;
//
const res = await postIntent({
let res;
try {
res = await postIntent({
content: userMessage,
language: "cn",
marketList: "hk,cn,usa,my,sg,vi,in,gb",
token:
"pCtw6AYK0EHAaIexoFHsbZjtsfEAIhcmwkCFm6uKko8VPfMvyDiODL9v9c0veic9fIpQbvT8zN4sH/Si6Q",
});
} catch (error) {
} finally {
isSending.value = false;
}
console.log("res" + res);
@ -694,31 +707,39 @@ const simulateBotResponse = async (userMessage) => {
//
const StockInfo = await postStock({
language: 'cn',
token: 'pCtw6AYK0EHAaIexoFHsbZjtsfEAIhcmwkCFm6uKko8VPfMvyDiODL9v9c0veic9fIpQbvT8zN4sH/Si6Q',
language: "cn",
token:
"pCtw6AYK0EHAaIexoFHsbZjtsfEAIhcmwkCFm6uKko8VPfMvyDiODL9v9c0veic9fIpQbvT8zN4sH/Si6Q",
recordId: Number(recordId),
parentId: Number(parentId),
stockId: Number(stockId),
});
console.log('postStock payload', { language: 'cn', token: '790750702588f1ea79f24dc56ccd5d8a', recordId, parentId, stockId });
console.log('StockInfo', StockInfo);
console.log("postStock payload", {
language: "cn",
token: "790750702588f1ea79f24dc56ccd5d8a",
recordId,
parentId,
stockId,
});
console.log("StockInfo", StockInfo);
const cftl = StockInfo?.cftl || {};
const date = StockInfo?.date || '';
const date = StockInfo?.date || "";
if (StockInfo && StockInfo.code !== 200) {
const errMsg = `postStock失败(${StockInfo.code}): ${StockInfo.message || '未知错误'}`
console.warn(errMsg, StockInfo)
messages.value[messages.value.length - 1].isThinking = false
messages.value[messages.value.length - 1].isTyping = false
messages.value[messages.value.length - 1].content = errMsg
isSending.value = false
return
const errMsg = `postStock失败(${StockInfo.code}): ${
StockInfo.message || "未知错误"
}`;
console.warn(errMsg, StockInfo);
messages.value[messages.value.length - 1].isThinking = false;
messages.value[messages.value.length - 1].isTyping = false;
messages.value[messages.value.length - 1].content = errMsg;
isSending.value = false;
return;
}
const markdown = StockInfo?.data?.markdown || '抱歉,未找到该股票';
console.log('StockInfo', StockInfo);
const markdown = StockInfo?.data?.markdown || "抱歉,未找到该股票";
console.log("StockInfo", StockInfo);
//
// const toDataInfo = await getData();
@ -926,6 +947,8 @@ async function itemClick(item) {
isTyping: false,
isThinking: false,
};
onDrawerBackClick();
messages.value.push(botMsg);
}
}

15
pages/home/member.vue

@ -79,11 +79,22 @@
ArrowRight
} from '@element-plus/icons-vue'
import footerBar from '../../components/footerBar.vue'
import {getUserInfo} from "@/api/member"
const type = ref('member')
const iSMT = ref(0)
const username = ref('演示机EVA')
const dccode = ref('90047681')
const username = ref('')
const dccode = ref('')
const userInfoRes = ref()//
userInfoRes.value = getUserInfo()
userInfoRes.value.then(res => {
username.value = res.data.username
dccode.value = res.data.dccode
console.log('用户信息', userInfoRes.value)
})
const goToGeneral = () => {
uni.navigateTo({
url: '/pages/setting/general'

655
pages/marketSituation/chartExample.vue

@ -1,655 +0,0 @@
<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: '卖盘'
})
// 30K线 [, , , , ]
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 // RSI20-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-1010
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>

615
pages/marketSituation/marketCondition.vue

@ -145,7 +145,7 @@
</view>
</view>
<view class="stock-kline">
<view v-if="klineTab === 1 || klineTab === 2" class="time-chart-container" style="position: relative">
<view v-if="klineTab === 1 || klineTab === 2 || klineTab === 3 || klineTab === 4 || klineTab === 5 || klineTab === 6 || klineTab === 7 || klineTab === 8 || klineTab === 9" class="time-chart-container" style="position: relative">
<!-- 主图Canvas -->
<canvas
canvas-id="stockChart"
@ -195,15 +195,12 @@
></canvas>
</view>
<!-- K线图区域 -->
<view class="test" v-else-if="klineTab === 3">
<view class="test" v-else-if="klineTab === 10">
<button @click="startTcp()">接收消息</button>
<button @click="sendStopTimeData()">停止消息</button>
<button @click="sendTcpMessage('real_time')">实时行情推送</button>
<button @click="sendTcpMessage('init_real_time')">初始化获取行情历史数据</button>
<button @click="sendTcpMessage('stop_real_time')">停止实时推送</button>
<view class="tcpMsg" v-for="item in tcpMessages" :key="item">
{{ item }}
</view>
</view>
<view v-else class="kline-chart-container">
<text>K线图开发中...</text>
@ -240,21 +237,6 @@ import tcpConnection, { TCPConnection, TCP_CONFIG } from "@/api/tcpConnection.js
// TCP
const tcpConnected = ref(false);
const tcpMessages = ref([]);
const tcpStockData = ref({
count: 0,
data: {},
stock_count: 0,
timestamp: "",
type: "",
});
const currentStockInfo = ref({
stock_name: "未知股票",
current_price: "0.00",
change: "0.00%",
change_value: 0,
change_percent: 0,
});
const connectionListener = ref(null);
const messageListener = ref(null);
@ -465,11 +447,54 @@ const confirmStockColor = (price, lastDayStockClosePrice) => {
// K线
const selectKlineTab = (tabId) => {
klineTab.value = tabId;
if (klineTab.value == 1) {
if (klineTab.value) {
sendTcpMessage("stop_real_time");
}
switch (klineTab.value) {
case 1:
sendTcpMessage("init_real_time");
break;
case 2:
sendTcpMessage("daily_data");
break;
case 3:
sendTcpMessage("weekly_data");
break;
case 4:
sendTcpMessage("monthly_data");
break;
case 5:
sendTcpMessage("daily_one_minutes_data");
break;
case 6:
sendTcpMessage("daily_five_minutes_data");
break;
case 7:
sendTcpMessage("daily_fifteen_minutes_data");
break;
case 8:
sendTcpMessage("daily_thirty_minutes_data");
break;
case 9:
sendTcpMessage("daily_sixty_minutes_data");
break;
case 10:
uni.showToast({
title: "暂无季K数据",
icon: "none",
duration: 2000,
});
break;
case 11:
uni.showToast({
title: "暂无年K数据",
icon: "none",
duration: 2000,
});
break;
default:
break;
}
initCanvas();
// startAddDataTimer();
};
@ -938,6 +963,7 @@ const drawChart = () => {
return;
}
const data = klineTab.value == 1 ? timeData.value : klineData.value;
console.log("data", data);
chartRange.value = [];
//
// HCharts.setCanvasColor(ctx.value, width, height, CANVAS_BACKGROUND_COLOR);
@ -1246,6 +1272,7 @@ const touchMove = (e) => {
}
}
} else {
return;
if (klineTab.value === 2) {
// if(currentY)
if (currentX < touchState.startX) {
@ -1413,10 +1440,6 @@ const initTcpListeners = () => {
timestamp: new Date().toLocaleTimeString(),
direction: "received",
};
console.log("0000");
tcpMessages.value.push(messageObj);
// console.log('TCP:', messageObj)
console.log("home开始调用parseStockData", messageObj);
//
parseStockData(message);
@ -1469,46 +1492,62 @@ const sendTcpMessage = (command) => {
command: "stock_list",
};
break;
// 线
case "daily_data":
messageData = {
command: "daily_data",
stock_code: "GBPAUD.FXCM",
start_date: "20251001",
end_date: "20251023",
start_date: "20250801",
end_date: "20251029",
};
break;
// 线
case "weekly_data":
messageData = {
command: "weekly_data",
stock_code: "000001.SZ",
start_date: "20251001",
end_date: "20251023",
start_date: "2024912",
end_date: "20251029",
};
break;
// 线
case "monthly_data":
messageData = {
command: "monthly_data",
stock_code: "000001.SZ",
start_date: "20201130",
end_date: "20251029",
};
break;
// 1线
case "daily_one_minutes_data":
messageData = {
command: "daily_one_minutes_data",
stock_code: "000001.SZ",
};
break;
// 5线
case "daily_five_minutes_data":
messageData = {
command: "daily_five_minutes_data",
stock_code: "000001.SZ",
};
break;
// 15线
case "daily_fifteen_minutes_data":
messageData = {
command: "daily_fifteen_minutes_data",
stock_code: "000001.SZ",
};
break;
// 30线
case "daily_thirty_minutes_data":
messageData = {
command: "daily_thirty_minutes_data",
stock_code: "000001.SZ",
};
break;
// 60线
case "daily_sixty_minutes_data":
messageData = {
command: "daily_sixty_minutes_data",
@ -1531,7 +1570,7 @@ const sendTcpMessage = (command) => {
uni.showToast({
title: "命令不存在",
icon: "none",
duration: 1500,
duration: 1000,
});
return;
} else {
@ -1543,7 +1582,7 @@ const sendTcpMessage = (command) => {
uni.showToast({
title: "消息发送成功",
icon: "success",
duration: 1500,
duration: 1000,
});
}
} catch (error) {
@ -1551,34 +1590,102 @@ const sendTcpMessage = (command) => {
uni.showToast({
title: "消息发送失败",
icon: "none",
duration: 1500,
duration: 1000,
});
}
}
};
//
const clearTcpMessages = () => {
tcpMessages.value = [];
uni.showToast({
title: "消息记录已清空",
icon: "success",
duration: 1500,
});
};
// TCP
const getTcpStatus = () => {
const status = tcpConnection.getConnectionStatus();
uni.showModal({
title: "TCP连接状态",
content: `当前状态: ${status ? "已连接" : "未连接"}\n消息数量: ${tcpMessages.value.length}`,
content: `当前状态: ${status ? "已连接" : "未连接"}`,
showCancel: false,
});
};
let isMorePacket = false;
let isMorePacket = {
init_real_time: false,
daily_data: false,
weekly_data: false,
monthly_data: false,
daily_one_minutes_data: false,
daily_five_minutes_data: false,
daily_fifteen_minutes_data: false,
daily_thirty_minutes_data: false,
daily_sixty_minutes_data: false,
};
let receivedMessage;
const findJsonPacket = (message, command) => {
let jsonStartIndex = 0;
let jsonEndIndex = message.indexOf(command);
let jsonStartCount = 0;
let jsonEndCount = 0;
for (let i = 0; i < message.length - 1; ++i) {
if (message[i] == "{") {
jsonStartCount++;
if (jsonStartCount == 2) {
jsonStartIndex = i;
break;
}
}
}
for (let i = message.indexOf(command); i >= 0; --i) {
if (message[i] == "}" || i == jsonStartIndex) {
jsonEndCount++;
if (jsonEndCount == 1) {
jsonEndIndex = i;
break;
}
}
}
// JSON
if (jsonStartIndex >= jsonEndIndex) {
return { error: true };
}
return { json: JSON.parse(message.substring(jsonStartIndex, jsonEndIndex + 1)) };
};
// timeData
const generateNextTime = () => {
if (timeData.value.length === 0) {
return "09:30"; //
}
const lastTime = timeData.value[timeData.value.length - 1].time;
if (!lastTime) {
return "09:30";
}
// "HH:MM"
const [hours, minutes] = lastTime.split(":").map(Number);
//
let nextMinutes = minutes + 1;
let nextHours = hours;
//
if (nextMinutes >= 60) {
nextMinutes = 0;
nextHours += 1;
}
// 24
if (nextHours >= 24) {
nextHours = 0;
}
// "HH:MM"
const formattedHours = nextHours.toString().padStart(2, "0");
const formattedMinutes = nextMinutes.toString().padStart(2, "0");
return `${formattedHours}:${formattedMinutes}`;
};
// TCP
const parseStockData = (message) => {
try {
@ -1592,105 +1699,390 @@ const parseStockData = (message) => {
console.log("服务器命令列表,不予处理");
return;
}
if ((typeof message === "string" && message.includes("init_real_data_start")) || isMorePacket) {
if (message.includes("real_time")) {
let startIndex = 0;
let endIndex = message.length;
for (let i = 0; i < message.length - 1; ++i) {
if (message[i] == "{") {
startIndex = i;
break;
}
}
for (let i = message.length - 1; i >= 0; --i) {
if (message[i] == "}") {
endIndex = i;
break;
}
}
parsedMessage = JSON.parse(message.substring(startIndex, endIndex + 1));
console.log("实时数据解析", parsedMessage);
//
timeData.value.push({
time: generateNextTime(),
price: parsedMessage.current_price,
volume: parsedMessage.volume,
amount: parsedMessage.amount,
});
//
stockInformation.value.currentPrice = parsedMessage.current_price;
stockInformation.value.openPrice = parsedMessage.open_price;
stockInformation.value.closePrice = parsedMessage.close_price;
stockInformation.value.highPrice = parsedMessage.high_price;
stockInformation.value.lowPrice = parsedMessage.low_price;
stockInformation.value.volume = parsedMessage.volume;
stockInformation.value.amount = parsedMessage.amount;
stockInformation.value.turnoverRatio = parsedMessage.turnover_ratio;
stockInformation.value.marketValue = parsedMessage.total_market_value;
stockInformation.value.currentValue = stockInformation.value.currentPrice - stockInformation.value.lastDayStockClosePrice;
stockInformation.value.currentRatio = ((stockInformation.value.currentPrice - stockInformation.value.lastDayStockClosePrice) / stockInformation.value.lastDayStockClosePrice) * 100;
console.log("重绘画面");
drawChart();
if (timeData.value.length >= 240) {
sendTcpMessage("stop_real_time");
}
return;
} else if ((typeof message === "string" && message.includes("init_real_data_start")) || isMorePacket.init_real_time) {
if (typeof message === "string" && message.includes("init_real_data_start")) {
console.log("开始接受分包数据");
receivedMessage = "";
} else {
console.log("接收分包数据过程中");
}
isMorePacket = true;
isMorePacket.init_real_time = true;
receivedMessage += message;
// }JSON
if (receivedMessage.includes("init_real_data_complete")) {
console.log("接受分包数据结束");
isMorePacket = false;
isMorePacket.init_real_time = false;
console.log("展示数据", receivedMessage);
// JSON
let jsonStartIndex = 0;
let jsonEndIndex = receivedMessage.indexOf("init_real_data_complete");
let jsonStartCount = 0;
let jsonEndCount = 0;
for (let i = 0; i < receivedMessage.length - 1; ++i) {
if (receivedMessage[i] == "{") {
jsonStartCount++;
if (jsonStartCount == 2) {
jsonStartIndex = i;
break;
const result = findJsonPacket(receivedMessage, "init_real_data_complete");
if (result.error) {
throw new Error("解析JSON字符串失败");
} else {
parsedMessage = result.json;
console.log("JSON解析成功,解析后类型:", typeof parsedMessage, parsedMessage);
if (parsedMessage.type === "daily_data") {
timeData.value = parsedMessage.data;
stockInformation.value.lastDayStockClosePrice = parsedMessage.pre_close;
console.log("lastDayStockClosePrice", stockInformation.value.lastDayStockClosePrice);
drawChart();
sendTcpMessage("stop_real_time");
sendTcpMessage("real_time");
}
}
}
} else if ((typeof message === "string" && message.includes("daily_data_start")) || isMorePacket.daily_data) {
if (typeof message === "string" && message.includes("daily_data_start")) {
console.log("开始接受分包数据");
receivedMessage = "";
} else {
console.log("接收分包数据过程中");
}
isMorePacket.daily_data = true;
receivedMessage += message;
// }JSON
if (receivedMessage.includes("daily_data_complete")) {
console.log("接受分包数据结束");
isMorePacket.daily_data = false;
for (let i = receivedMessage.indexOf("init_real_data_complete"); i >= 0; --i) {
if (receivedMessage[i] == "}" || i == jsonStartIndex) {
jsonEndCount++;
if (jsonEndCount == 1) {
jsonEndIndex = i;
break;
console.log("展示数据", receivedMessage);
const result = findJsonPacket(receivedMessage, "daily_data_complete");
if (result.error) {
throw new Error("解析JSON字符串失败");
} else {
parsedMessage = result.json;
console.log("JSON解析成功,解析后类型:", typeof parsedMessage, parsedMessage);
if (parsedMessage.type === "daily_data") {
klineData.value = parsedMessage.data.map((item) => ({
open: item.ask_open,
close: item.ask_close,
high: item.ask_high,
low: item.ask_low,
volume: item.tick_qty,
date: item.trade_date ? `${item.trade_date.slice(0, 4)}-${item.trade_date.slice(4, 6)}-${item.trade_date.slice(6, 8)}` : item.trade_date,
}));
stockInformation.value.lastDayStockClosePrice = klineData.value[klineData.value.length - 2].close;
touchState.offset = canvasWidth.value / klineData.value.length / 2;
console.log("lastDayStockClosePrice", stockInformation.value.lastDayStockClosePrice);
drawChart();
}
}
}
// JSON
if (jsonStartIndex >= jsonEndIndex) {
throw new Error("JSON字符串格式错误");
} else if ((typeof message === "string" && message.includes("weekly_data_start")) || isMorePacket.weekly_data) {
if (typeof message === "string" && message.includes("weekly_data_start")) {
console.log("开始接受分包数据");
receivedMessage = "";
} else {
console.log("接收分包数据过程中");
}
isMorePacket.weekly_data = true;
receivedMessage += message;
// }JSON
if (receivedMessage.includes("weekly_data_complete")) {
console.log("接受分包数据结束");
isMorePacket.weekly_data = false;
console.log("展示数据", receivedMessage);
console.log("检测到JSON字符串,开始解析");
parsedMessage = JSON.parse(receivedMessage.substring(jsonStartIndex, jsonEndIndex + 1));
const result = findJsonPacket(receivedMessage, "weekly_data_complete");
if (result.error) {
throw new Error("解析JSON字符串失败");
} else {
parsedMessage = result.json;
console.log("JSON解析成功,解析后类型:", typeof parsedMessage, parsedMessage);
if (parsedMessage.type === "daily_data") {
timeData.value = parsedMessage.data;
stockInformation.value.lastDayStockClosePrice = parsedMessage.pre_close;
if (parsedMessage.type === "weekly_data") {
klineData.value = parsedMessage.data.map((item) => ({
open: item.bid_open,
close: item.bid_close,
high: item.bid_high,
low: item.bid_low,
volume: item.vol,
amount: item.amount,
date: item.trade_date ? `${item.trade_date.slice(0, 4)}-${item.trade_date.slice(4, 6)}-${item.trade_date.slice(6, 8)}` : item.trade_date,
}));
stockInformation.value.lastDayStockClosePrice = klineData.value[klineData.value.length - 2].close;
touchState.offset = canvasWidth.value / klineData.value.length / 2;
console.log("lastDayStockClosePrice", stockInformation.value.lastDayStockClosePrice);
drawChart();
}
}
// JSON
console.log("开始处理解析后的数据");
}
} else if ((typeof message === "string" && message.includes("monthly_data_start")) || isMorePacket.monthly_data) {
if (typeof message === "string" && message.includes("monthly_data_start")) {
console.log("开始接受分包数据");
receivedMessage = "";
} else {
console.log("接收分包数据过程中");
}
isMorePacket.monthly_data = true;
receivedMessage += message;
// }JSON
if (receivedMessage.includes("monthly_data_complete")) {
console.log("接受分包数据结束");
isMorePacket.monthly_data = false;
// batch_data_chunkbatch_realtime_data
if ((parsedMessage.type === "batch_data_chunk" || parsedMessage.type === "batch_realtime_data") && parsedMessage.data) {
console.log("开始更新TCP股票数据存储");
// TCP
tcpStockData.value = {
count: parsedMessage.count || 0,
data: parsedMessage.data || {},
stock_count: parsedMessage.stock_count || 0,
timestamp: parsedMessage.timestamp || "",
type: parsedMessage.type || "",
};
console.log("展示数据", receivedMessage);
const result = findJsonPacket(receivedMessage, "monthly_data_complete");
if (result.error) {
throw new Error("解析JSON字符串失败");
} else {
parsedMessage = result.json;
console.log("JSON解析成功,解析后类型:", typeof parsedMessage, parsedMessage);
if (parsedMessage.type === "monthly_data") {
klineData.value = parsedMessage.data.map((item) => ({
open: item.bid_open,
close: item.bid_close,
high: item.bid_high,
low: item.bid_low,
volume: item.vol,
amount: item.amount,
date: item.trade_date ? `${item.trade_date.slice(0, 4)}-${item.trade_date.slice(4, 6)}-${item.trade_date.slice(6, 8)}` : item.trade_date,
}));
stockInformation.value.lastDayStockClosePrice = klineData.value[klineData.value.length - 2].close;
touchState.offset = canvasWidth.value / klineData.value.length / 2;
console.log("lastDayStockClosePrice", stockInformation.value.lastDayStockClosePrice);
drawChart();
}
}
}
} else if ((typeof message === "string" && message.includes("daily_one_minutes_data_start")) || isMorePacket.daily_one_minutes_data) {
if (typeof message === "string" && message.includes("daily_one_minutes_data_start")) {
console.log("开始接受分包数据");
receivedMessage = "";
} else {
console.log("接收分包数据过程中");
}
isMorePacket.daily_one_minutes_data = true;
receivedMessage += message;
// }JSON
if (receivedMessage.includes("daily_one_minutes_data_complete")) {
console.log("接受分包数据结束");
isMorePacket.daily_one_minutes_data = false;
console.log("展示数据", receivedMessage);
const result = findJsonPacket(receivedMessage, "daily_one_minutes_data_complete");
if (result.error) {
throw new Error("解析JSON字符串失败");
} else {
parsedMessage = result.json;
console.log("JSON解析成功,解析后类型:", typeof parsedMessage, parsedMessage);
if (parsedMessage.type === "daily_one_minutes_data") {
klineData.value = parsedMessage.data.map((item) => ({
open: item.open,
close: item.close,
high: Math.max(item.low, item.high),
low: Math.min(item.low, item.high),
volume: item.volume,
amount: item.amount,
date: item.timestamp,
}));
stockInformation.value.lastDayStockClosePrice = klineData.value[klineData.value.length - 2].close;
touchState.offset = canvasWidth.value / klineData.value.length / 2;
console.log("lastDayStockClosePrice", stockInformation.value.lastDayStockClosePrice);
drawChart();
}
}
}
} else if ((typeof message === "string" && message.includes("daily_five_minutes_data_start")) || isMorePacket.daily_five_minutes_data) {
if (typeof message === "string" && message.includes("daily_five_minutes_data_start")) {
console.log("开始接受分包数据");
receivedMessage = "";
} else {
console.log("接收分包数据过程中");
}
isMorePacket.daily_five_minutes_data = true;
receivedMessage += message;
// }JSON
if (receivedMessage.includes("daily_five_minutes_data_complete")) {
console.log("接受分包数据结束");
isMorePacket.daily_five_minutes_data = false;
//
const stockCodes = Object.keys(parsedMessage.data);
if (stockCodes.length > 0) {
const firstStockCode = stockCodes[0];
console.log("展示数据", receivedMessage);
//
if (parsedMessage.data[firstStockCode] && Array.isArray(parsedMessage.data[firstStockCode]) && parsedMessage.data[firstStockCode].length > 0) {
const stockData = parsedMessage.data[firstStockCode][0]; //
const result = findJsonPacket(receivedMessage, "daily_five_minutes_data_complete");
if (result.error) {
throw new Error("解析JSON字符串失败");
} else {
parsedMessage = result.json;
console.log("JSON解析成功,解析后类型:", typeof parsedMessage, parsedMessage);
if (parsedMessage.type === "daily_five_minutes_data") {
klineData.value = parsedMessage.data.map((item) => ({
open: item.open,
close: item.close,
high: Math.max(item.low, item.high),
low: Math.min(item.low, item.high),
volume: item.volume,
amount: item.amount,
date: item.timestamp,
}));
stockInformation.value.lastDayStockClosePrice = klineData.value[klineData.value.length - 2].close;
touchState.offset = canvasWidth.value / klineData.value.length / 2;
console.log("lastDayStockClosePrice", stockInformation.value.lastDayStockClosePrice);
drawChart();
}
}
}
} else if ((typeof message === "string" && message.includes("daily_fifteen_minutes_data_start")) || isMorePacket.daily_fifteen_minutes_data) {
if (typeof message === "string" && message.includes("daily_fifteen_minutes_data_start")) {
console.log("开始接受分包数据");
receivedMessage = "";
} else {
console.log("接收分包数据过程中");
}
isMorePacket.daily_fifteen_minutes_data = true;
receivedMessage += message;
// }JSON
if (receivedMessage.includes("daily_fifteen_minutes_data_complete")) {
console.log("接受分包数据结束");
isMorePacket.daily_fifteen_minutes_data = false;
if (stockData && stockData.current_price !== undefined && stockData.pre_close !== undefined) {
//
const changeValue = stockData.current_price - stockData.pre_close;
const changePercent = ((changeValue / stockData.pre_close) * 100).toFixed(2);
const changeSign = changeValue >= 0 ? "+" : "";
console.log("展示数据", receivedMessage);
//
currentStockInfo.value = {
stock_name: stockData.stock_name || "未知股票",
current_price: stockData.current_price ? stockData.current_price.toFixed(2) : "0.00",
change: `${changeSign}${changePercent}%`,
change_value: changeValue,
change_percent: parseFloat(changePercent),
};
const result = findJsonPacket(receivedMessage, "daily_fifteen_minutes_data_complete");
if (result.error) {
throw new Error("解析JSON字符串失败");
} else {
parsedMessage = result.json;
console.log("JSON解析成功,解析后类型:", typeof parsedMessage, parsedMessage);
if (parsedMessage.type === "daily_fifteen_minutes_data") {
klineData.value = parsedMessage.data.map((item) => ({
open: item.open,
close: item.close,
high: Math.max(item.low, item.high),
low: Math.min(item.low, item.high),
volume: item.volume,
amount: item.amount,
date: item.timestamp,
}));
stockInformation.value.lastDayStockClosePrice = klineData.value[klineData.value.length - 2].close;
touchState.offset = canvasWidth.value / klineData.value.length / 2;
console.log("lastDayStockClosePrice", stockInformation.value.lastDayStockClosePrice);
drawChart();
}
}
}
} else if ((typeof message === "string" && message.includes("daily_thirty_minutes_data_start")) || isMorePacket.daily_thirty_minutes_data) {
if (typeof message === "string" && message.includes("daily_thirty_minutes_data_start")) {
console.log("开始接受分包数据");
receivedMessage = "";
} else {
console.log("接收分包数据过程中");
}
isMorePacket.daily_thirty_minutes_data = true;
receivedMessage += message;
// }JSON
if (receivedMessage.includes("daily_thirty_minutes_data_complete")) {
console.log("接受分包数据结束");
isMorePacket.daily_thirty_minutes_data = false;
console.log("股票数据更新成功:", currentStockInfo.value);
console.log("展示数据", receivedMessage);
const result = findJsonPacket(receivedMessage, "daily_thirty_minutes_data_complete");
if (result.error) {
throw new Error("解析JSON字符串失败");
} else {
parsedMessage = result.json;
console.log("JSON解析成功,解析后类型:", typeof parsedMessage, parsedMessage);
if (parsedMessage.type === "daily_thirty_minutes_data") {
klineData.value = parsedMessage.data.map((item) => ({
open: item.open,
close: item.close,
high: Math.max(item.low, item.high),
low: Math.min(item.low, item.high),
volume: item.volume,
amount: item.amount,
date: item.timestamp,
}));
stockInformation.value.lastDayStockClosePrice = klineData.value[klineData.value.length - 2].close;
touchState.offset = canvasWidth.value / klineData.value.length / 2;
console.log("lastDayStockClosePrice", stockInformation.value.lastDayStockClosePrice);
drawChart();
}
}
}
} else if ((typeof message === "string" && message.includes("daily_sixty_minutes_data_start")) || isMorePacket.daily_sixty_minutes_data) {
if (typeof message === "string" && message.includes("daily_sixty_minutes_data_start")) {
console.log("开始接受分包数据");
receivedMessage = "";
} else {
console.log("接收分包数据过程中");
}
isMorePacket.daily_sixty_minutes_data = true;
receivedMessage += message;
// }JSON
if (receivedMessage.includes("daily_sixty_minutes_data_complete")) {
console.log("接受分包数据结束");
isMorePacket.daily_sixty_minutes_data = false;
console.log("展示数据", receivedMessage);
const result = findJsonPacket(receivedMessage, "daily_sixty_minutes_data_complete");
if (result.error) {
throw new Error("解析JSON字符串失败");
} else {
console.log("不是batch_data_chunk或batch_realtime_data类型的消息,跳过处理");
parsedMessage = result.json;
console.log("JSON解析成功,解析后类型:", typeof parsedMessage, parsedMessage);
if (parsedMessage.type === "daily_sixty_minutes_data") {
klineData.value = parsedMessage.data.map((item) => ({
open: item.open,
close: item.close,
high: Math.max(item.low, item.high),
low: Math.min(item.low, item.high),
volume: item.volume,
amount: item.amount,
date: item.timestamp,
}));
stockInformation.value.lastDayStockClosePrice = klineData.value[klineData.value.length - 2].close;
touchState.offset = canvasWidth.value / klineData.value.length / 2;
console.log("lastDayStockClosePrice", stockInformation.value.lastDayStockClosePrice);
drawChart();
}
}
}
} else {
// JSON
@ -1789,7 +2181,8 @@ onLoad((options) => {
//
onUnmounted(() => {
// disconnect();
removeTcpListeners();
disconnect();
if (timer) {
console.log("卸载定时器");
clearInterval(timer);
@ -1829,7 +2222,9 @@ onMounted(async () => {
console.warn("没有时间数据,跳过股票信息计算");
}
await nextTick();
setTimeout(() => {
initCanvas();
}, 100);
console.log("所有初始化步骤完成");
} catch (error) {
console.error("初始化过程中出现错误:", error);

15
pages/marketSituation/marketOverview.vue

@ -5,7 +5,6 @@
<!-- 可滚动内容区域 -->
<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>
@ -52,13 +51,6 @@ const isWarnTextOverflow = ref(false); // warn文字是否溢出
const pageIndex = ref(0);
const scrollToView = ref("");
//
const goToChartExample = () => {
uni.navigateTo({
url: "/pages/marketSituation/chartExample",
});
};
// contenttop
const contentTopPosition = computed(() => {
const statusBarHeight = iSMT.value || 0;
@ -650,8 +642,7 @@ watch(headerHeight, (newHeight) => {
margin: 0;
box-sizing: border-box;
width: 100%;
padding: 30rpx 20rpx;
gap: 20rpx;
padding: 30rpx 0;
}
.card_item {
@ -665,7 +656,7 @@ watch(headerHeight, (newHeight) => {
@media (max-width: 600rpx) {
.cards_grid {
grid-template-columns: repeat(2, 1fr);
padding: 30rpx 20rpx;
padding: 30rpx 0;
}
}
@ -673,7 +664,7 @@ watch(headerHeight, (newHeight) => {
@media (max-width: 400rpx) {
.cards_grid {
grid-template-columns: 1fr;
padding: 30rpx 20rpx;
padding: 30rpx 0;
}
}

46
pages/setting/account.vue

@ -9,41 +9,37 @@
<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>
<uni-icons type="arrowright" size="16"></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>
<text class="item-text">{{userInfoRes.dcname}}</text>
<uni-icons type="arrowright" size="16"></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>
<text class="item-text">{{ userInfoRes.dccode }}</text>
</view>
</view>
<view class="setting-item" @click="goToPassword">
<text class="item-label">修改密码</text>
<uni-icons type="arrowright" size="16" class="arrow"></uni-icons>
<text class="item-label">
<template #default>
{{ userInfoRes.hasPwd === 0 ? '创建密码' : '修改密码' }}
</template>
</text>
<uni-icons type="arrowright" size="16"></uni-icons>
</view>
<view class="setting-item">
<text class="item-label">注销账号</text>
<uni-icons type="arrowright" size="16" class="arrow"></uni-icons>
<uni-icons type="arrowright" size="16"></uni-icons>
</view>
<view class="setting-item" @click="goToBind">
<text class="item-label">绑定账号</text>
<uni-icons type="arrowright" size="16" class="arrow"></uni-icons>
<uni-icons type="arrowright" size="16"></uni-icons>
</view>
</view>
@ -73,8 +69,12 @@
} from 'vue'
import {useUserStore} from "../../stores/modules/userInfo"
import {
getUserInfo
} from "@/api/member";
const iSMT = ref(0)
const jwcode = ref('90047681')
// const dccode = ref('')
const userInfoRes = ref({})
const showLogout = ref(false)
const userStore = useUserStore()
@ -86,6 +86,10 @@
title: '退出登录成功',
icon: 'none',
})
uni.navigateTo({
url: '/pages/start/login/login'
})
}
const goToBind = () => {
@ -95,10 +99,16 @@
}
const goToPassword = () => {
if (userInfoRes.value.hasPwd === 0) {
uni.navigateTo({
url: '../setting/createPwd'
})
} else {
uni.navigateTo({
url: '../setting/password'
})
}
}
onMounted(() => {
iSMT.value = uni.getSystemInfoSync().statusBarHeight;
@ -107,7 +117,7 @@
<style scoped>
.setting-list {
height: 49vh;
height: 42vh;
background-color: #fff;
}

245
pages/setting/createPwd.vue

@ -0,0 +1,245 @@
<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" v-model="userEmail" />
<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" v-model="userPhone" />
<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" v-model="verifyCode" />
</view>
</view>
<view class="btn-area">
<button class="next-btn" @click="goToPwdNext">下一步</button>
</view>
</view>
</template>
<script setup>
import {
ref,
onMounted
} from 'vue'
import {
sendEmail,
validateCode,
sendPhone
} from "@/api/setting/password";
const iSMT = ref(0)
const activeTab = ref('email')
const gettingCode = ref(false)
const time = ref(60)
const userEmail = ref('')
const userPhone = ref('')
const verifyCode = ref('')
const getCode = () => {
if (gettingCode.value) return
gettingCode.value = true
time.value = 2
const timer = setInterval(() => {
time.value--
if (time.value <= 0) {
clearInterval(timer)
gettingCode.value = false
time.value = 2
}
}, 1000)
if (activeTab.value === 'email') {
sendEmail({
email: userEmail.value
})
} else {
sendPhone({
phone: userPhone.value
})
}
}
const goToPwdNext = async () => {
if (!userEmail.value) {
uni.showToast({
title: '请输入邮箱',
icon: 'none'
})
return
}
if (!verifyCode.value) {
uni.showToast({
title: '请输入验证码',
icon: 'none'
})
return
}
try {
let param;
if (activeTab.value === 'email') {
param = {
loginType: 'EMAIL',
account: userEmail.value,
verifyCode: verifyCode.value
}
} else {
param = {
loginType: 'PHONE',
account: userPhone.value,
verifyCode: verifyCode.value
}
}
const res = await validateCode(param)
console.log('看看参数', param)
console.log('看看结果', res)
//
if (res.code === 200) {
uni.showToast({
title: '验证成功',
icon: 'success'
})
uni.navigateTo({
url: '../setting/nextPwd'
})
} else {
uni.showToast({
title: res.msg || '验证失败',
icon: 'none'
})
}
} catch (err) {
console.error(err)
uni.showToast({
title: '请求出错',
icon: 'none'
})
}
}
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>

57
pages/setting/email.vue

@ -15,11 +15,10 @@
<view class="top-list">
<view class="left">
<img src="/static/my/changeEmail.png" />
<text class="label">+86</text>
<input type="number" placeholder="请输入您的换绑邮箱" class="input" />
<input v-model="userEmail" placeholder="请输入您的换绑邮箱" class="input" />
</view>
<view class="right">
<button class="verification" :class="{ 'disabled': gettingCode }" @click="getVerification"
<button class="verification" :class="{ 'disabled': gettingCode }" @click="getCode"
:disabled="gettingCode">
{{ gettingCode ? `重新发送 ${time}s` : '获取验证码' }}
</button>
@ -35,7 +34,7 @@
</view>
<view class="bottom">
<button class="change-btn">换绑</button>
<button class="change-btn" @click="changeAccount">换绑</button>
</view>
</view>
</template>
@ -45,23 +44,67 @@
ref,
onMounted
} from 'vue'
import {
getUserInfo
} from "@/api/member"
import {
sendEmail,
changeBind
} from "@/api/setting/password"
const iSMT = ref(0)
const email = ref('analsak@16.com')
const email = ref('')
const gettingCode = ref(false)
const time = ref(60)
const userEmail = ref('')
const userInfoPromise = getUserInfo()
userInfoPromise.then(res => {
if (res.code === 200) {
console.log('个人信息', res.data)
email.value = res.data.email
} else {
uni.showToast({
title: '用户信息请求失败',
icon: 'none',
})
}
})
const getVerification = () => {
const changeAccount = () => {
const res = changeBind({
verificateType: 0,
account: userEmail.value
})
if(res.code === 200){
uni.showToast({
title: '绑定成功',
icon: 'none',
})
}else {
uni.showToast({
title: '用户绑定失败',
icon: 'none',
})
}
}
const getCode = () => {
if (gettingCode.value) return
gettingCode.value = true
time.value = 60
time.value = 2
const timer = setInterval(() => {
time.value--
if (time.value <= 0) {
clearInterval(timer)
gettingCode.value = false
time.value = 2
}
}, 1000)
sendEmail({
email: userEmail.value
})
}
onMounted(() => {

34
pages/setting/font.vue

@ -4,18 +4,18 @@
<view class="top">
<view class="top-list">
<text>标准</text>
<radio value="0" class="radio-btn" activeBackgroundColor="red"
:checked="selectedIndex === 0" @click="selectFont(0)" />
<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)" />
<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)" />
<radio value="2" class="radio-btn" activeBackgroundColor="red" :checked="selectedIndex === 2"
@click="selectFont(2)" />
</view>
</view>
</view>
@ -26,9 +26,30 @@
ref,
onMounted
} from 'vue'
import {
getSetting
} from "@/api/setting/general"
const iSMT = ref(0)
const selectedIndex = ref(0)
const getFont = async () => {
try {
const res = await getSetting()
if (res.code === 200) {
const fontSize = res.data.fontSize
const sizeMap = {
small: 0,
medium: 1,
large: 2
}
console.log('看看字体', res.data.fontSize)
selectedIndex.value = sizeMap[fontSize] ?? 0;
}
} catch (err) {
console.error("获取字体设置失败:", err);
}
}
const selectFont = (index) => {
selectedIndex.value = index
console.log('看看选中状态', selectedIndex.value)
@ -37,6 +58,7 @@
//
iSMT.value = uni.getSystemInfoSync().statusBarHeight;
console.log('看看高度', iSMT.value)
getFont()
})
</script>

51
pages/setting/general.vue

@ -3,37 +3,37 @@
<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" />
<text class="label">语言</text>
<text class="language">{{settingRes.language}}</text>
<uni-icons type="arrowright" size="16" />
</view>
<view class="top-list" @click="goToFont">
<text>字体大小</text>
<uni-icons type="arrowright" size="16" class="arrow" />
<text class="label">字体大小</text>
<uni-icons type="arrowright" size="16" />
</view>
<view class="top-list" @click="goToTheme">
<text>主题切换</text>
<uni-icons type="arrowright" size="16" class="arrow" />
<text class="label">主题切换</text>
<uni-icons type="arrowright" size="16" />
</view>
</view>
<view class="center">
<view class="center-list" @click="goToMessage">
<text>消息推送</text>
<uni-icons type="arrowright" size="16" class="arrow" />
<text class="label">消息推送</text>
<uni-icons type="arrowright" size="16" />
</view>
</view>
<view class="bottom">
<view class="bottom-list" @click="goToServer">
<text>切换服务器</text>
<uni-icons type="arrowright" size="16" class="arrow" />
<text class="label">切换服务器</text>
<uni-icons type="arrowright" size="16" />
</view>
<view class="bottom-list" @click="clearCache">
<text>清理缓存</text>
<text class="label">清理缓存</text>
<text class="cache">{{ cache }}M</text>
<uni-icons type="arrowright" size="16" class="arrow" />
<uni-icons type="arrowright" size="16" />
</view>
</view>
</view>
@ -44,9 +44,26 @@
ref,
onMounted
} from 'vue'
import {getUserInfo} from "@/api/member";
const iSMT = ref(0)
const cache = ref('45.5')
const settingRes = ref({})
const settingPromise = getUserInfo()
settingPromise.then(res => {
if (res.code === 200){
settingRes.value.language = res.data.language;
settingRes.value.fontSize = res.data.fontSize;
settingRes.value.theme = res.data.theme;
settingRes.value.serverSelection = res.data.serverSelection;
console.log('用户信息', res.data)
}else {
console.log('用户信息请求失败:', res.message);
}
})
const goToFont = () => {
uni.navigateTo({
url: '/pages/setting/font'
@ -109,7 +126,7 @@
}
.language {
margin-left: 55%;
margin-left: 70%;
font-size: 14px;
color: rgb(203, 203, 203);
}
@ -154,7 +171,6 @@
}
.cache {
margin-left: 55%;
font-size: 14px;
color: rgb(203, 203, 203);
}
@ -162,4 +178,9 @@
.bottom-list:last-child {
border-bottom: none;
}
.label{
flex:1;
font-size:28rpx;
}
</style>

2
pages/setting/introduce.vue

@ -13,7 +13,7 @@
的品牌标签DeepChart=全球最懂机构行为的AI主打"深度解读机构行为"的APP</view>
<view class="title">2.产品介绍</view>
<view class="main-text">DeepChart是一款以"Al智能体为决策核心的智能投资分析平台
<view class="main-text">DeepChart是一款以"Al智能体"为决策核心的智能投资分析平台
专注于深度研究机构行为专为全球散户投资者量身打造它重新定义了人与投资工具之间的关系
是一个真正懂投资懂市场更懂用户的AI投资伙伴</view>

1
pages/setting/market.vue

@ -206,6 +206,7 @@
.indicator-text {
font-size: 28rpx;
flex:1;
}
.indicator-icons {

9
pages/setting/message.vue

@ -3,10 +3,10 @@
<view :style="{height:iSMT+'px'}"></view>
<view class="top">
<view class="top-list" @click="goToPush">
<text>语言</text>
<text class="text">消息推送</text>
<text class="message" v-if="isMessage">通知已开启</text>
<text class="message" v-if="!isMessage">通知未开启</text>
<uni-icons type="arrowright" size="16" class="arrow" />
<uni-icons type="arrowright" size="16" />
</view>
</view>
</view>
@ -51,12 +51,11 @@
}
.message {
margin-left: 60%;
font-size: 14px;
color: rgb(203, 203, 203);
}
.arrow {
margin-left: auto;
.text{
flex:1;
}
</style>

45
pages/setting/nextPwd.vue

@ -9,10 +9,13 @@
</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" />
<input type="password" :type="pwdType" placeholder="请输入新密码" class="input" v-model="oldPassword"
/>
<img :src="pwdType === 1 ? '/static/my/hideEye.png' : '/static/my/openEye.png'"
@click="changeEye(1)"/>
</view>
@ -21,7 +24,7 @@
<view class="top-list">
<view class="left">
<img src="/static/my/unlock.png"/>
<input type="password" :type="pwdType2" placeholder="再次确认" class="input" />
<input type="password" :type="pwdType2" placeholder="再次确认" class="input" v-model="newPassword"/>
<img :src="pwdType === 1 ? '/static/my/hideEye.png' : '/static/my/openEye.png'"
@click="changeEye(2)"/>
</view>
@ -31,21 +34,49 @@
</view>
<view class="bottom">
<button class="change-btn">确认</button>
<button class="change-btn" @click="confirmChange">确认</button>
</view>
</view>
</template>
<script setup>
import {
ref,
onMounted
} from 'vue'
import {onMounted, ref} from 'vue'
import {updatePassword} from "@/api/setting/nextPwd";
const iSMT = ref(0)
const pwdType = ref('password')
const pwdType2 = ref('password')
//
const oldPassword = ref('')
const newPassword = ref('')
//
const confirmChange = async () => {
if (newPassword.value !== oldPassword.value) {
uni.showToast({title: '两次输入的密码不一致', icon: 'none'})
return
}
const updatePasswordPromise = updatePassword({
oldPassword: oldPassword.value,
newPassword: newPassword.value
})
updatePasswordPromise
.then(res => {
if (res.code === 200) {
uni.showToast({ title: '修改成功', icon: 'success' });
} else {
uni.showToast({ title: res.message,icon: 'none' });
}
})
.catch(err => {
console.log('修改密码失败:', err);
});
}
const changeEye = (type) => {
if (type === 1) {
pwdType.value = pwdType.value === 'password' ? 'text' : 'password'

88
pages/setting/password.vue

@ -10,7 +10,7 @@
<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" />
<input type="text" placeholder="请输入邮箱" class="input" v-model="userEmail" />
<button class="code-btn" :class="{disabled: gettingCode}" @click="getCode" :disabled="gettingCode">
{{ gettingCode ? `重新发送 ${time}s` : '获取验证码' }}
</button>
@ -18,7 +18,7 @@
<view class="input-list" v-else>
<image src="/static/my/changeBindPhone.png" mode="aspectFit"></image>
<input type="number" placeholder="请输入手机号" class="input" />
<input type="number" placeholder="请输入手机号" class="input" v-model="userPhone" />
<button class="code-btn" :class="{disabled: gettingCode}" @click="getCode" :disabled="gettingCode">
{{ gettingCode ? `重新发送 ${time}s` : '获取验证码' }}
</button>
@ -26,7 +26,7 @@
<view class="input-list">
<image src="/static/my/verification.png" mode="aspectFit"></image>
<input type="text" placeholder="请输入验证码" class="input" />
<input type="text" placeholder="请输入验证码" class="input" v-model="verifyCode" />
</view>
</view>
@ -41,34 +41,107 @@
ref,
onMounted
} from 'vue'
import {
sendEmail,
validateCode,
sendPhone
} from "@/api/setting/password";
const iSMT = ref(0)
const activeTab = ref('email')
const gettingCode = ref(false)
const time = ref(60)
const userEmail = ref('')
const userPhone = ref('')
const verifyCode = ref('')
const getCode = () => {
if (gettingCode.value) return
gettingCode.value = true
time.value = 60
time.value = 2
const timer = setInterval(() => {
time.value--
if (time.value <= 0) {
clearInterval(timer)
gettingCode.value = false
time.value = 60
time.value = 2
}
}, 1000)
if (activeTab.value === 'email') {
sendEmail({
email: userEmail.value
})
} else {
sendPhone({
phone: userPhone.value
})
}
}
const goToPwdNext = async () => {
if (!userEmail.value) {
uni.showToast({
title: '请输入邮箱',
icon: 'none'
})
return
}
if (!verifyCode.value) {
uni.showToast({
title: '请输入验证码',
icon: 'none'
})
return
}
const goToPwdNext = () =>{
try {
let param;
if (activeTab.value === 'email') {
param = {
loginType: 'EMAIL',
account: userEmail.value,
verifyCode: verifyCode.value
}
} else {
param = {
loginType: 'PHONE',
account: userPhone.value,
verifyCode: verifyCode.value
}
}
const res = await validateCode(param)
console.log('看看参数', param)
console.log('看看结果', res)
//
if (res.code === 200) {
uni.showToast({
title: '验证成功',
icon: 'success'
})
uni.navigateTo({
url: '../setting/nextPwd'
})
} else {
uni.showToast({
title: res.msg || '验证失败',
icon: 'none'
})
}
} catch (err) {
console.error(err)
uni.showToast({
title: '请求出错',
icon: 'none'
})
}
}
onMounted(() => {
//
iSMT.value = uni.getSystemInfoSync().statusBarHeight;
@ -105,7 +178,8 @@
transform: translateX(-50%);
width: 40rpx;
height: 6rpx;
background-color: #000;/* ????? */
background-color: #000;
/* ????? */
}
.switch-tab {

54
pages/setting/phone.vue

@ -11,15 +11,14 @@
<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" />
<input type="number" v-model="userPhone" placeholder="请输入您的换绑手机号" class="input" />
</view>
<view class="right">
<button class="verification" :class="{ 'disabled': gettingCode }" @click="getVerification"
<button class="verification" :class="{ 'disabled': gettingCode }" @click="getCode"
:disabled="gettingCode">
{{ gettingCode ? `重新发送 ${time}s` : '获取验证码' }}
</button>
@ -35,7 +34,7 @@
</view>
<view class="bottom">
<button class="change-btn">换绑</button>
<button class="change-btn" @click="changeAccount">换绑</button>
</view>
</view>
</template>
@ -45,12 +44,34 @@
ref,
onMounted
} from 'vue'
import {
sendPhone,
changeBind
} from "@/api/setting/password"
import {
getUserInfo
} from "@/api/member"
const iSMT = ref(0)
const phone = ref('15105421566')
const phone = ref('')
const gettingCode = ref(false)
const time = ref(60)
const userPhone = ref('')
const userInfoPromise = getUserInfo()
userInfoPromise.then(res => {
if (res.code === 200) {
console.log('个人信息', res.data)
phone.value = res.data.phone
} else {
uni.showToast({
title: '用户信息请求失败',
icon: 'none',
})
}
})
const getVerification = () => {
const getCode = () => {
if (gettingCode.value) return
gettingCode.value = true
@ -63,6 +84,27 @@
gettingCode.value = false
}
}, 1000)
sendPhone({
phone: userPhone.value
})
}
const changeAccount = () => {
const res = changeBind({
verificateType: 1,
account: userPhone.value
})
if(res.code === 200){
uni.showToast({
title: '绑定成功',
icon: 'none',
})
}else {
uni.showToast({
title: '用户绑定失败',
icon: 'none',
})
}
}
onMounted(() => {

48
pages/setting/push.vue

@ -3,25 +3,35 @@
<view :style="{height:iSMT+'px'}"></view>
<view class="top">
<view class="top-list">
<text style="width:180rpx;">公共消息</text>
<text class="label">公共消息</text>
<view class="right">
<text class="public">重大咨询财经要闻等系统提醒</text>
<switch class="arrow switch-btn" />
<switch class="switch-btn" />
</view>
</view>
<view class="top-list">
<text>字体大小</text>
<switch class="arrow switch-btn" />
<text class="label">指标消息提醒</text>
<view class="right">
<text class="public">所有指标消息的提醒</text>
<switch class="switch-btn" />
</view>
</view>
</view>
<view class="bottom">
<view class="bottom-list">
<text>盯盘预警</text>
<uni-icons type="arrowright" size="16" class="arrow" />
<text class="label">盯盘预警</text>
<view class="right">
<text class="public">自选股预警和个性化预警设置</text>
<uni-icons type="arrowright" size="16" />
</view>
</view>
<view class="bottom-list">
<text>订阅服务</text>
<text class="cache">45.5M</text>
<uni-icons type="arrowright" size="16" class="arrow" />
<text class="label">订阅服务</text>
<view class="right">
<text class="public">订阅你感兴趣的专题服务</text>
<uni-icons type="arrowright" size="16" />
</view>
</view>
</view>
</view>
@ -53,7 +63,6 @@
height: 7vh;
display: flex;
align-items: center;
justify-content: center;
margin: 0 40rpx;
padding: 0 10rpx;
border-bottom: 1rpx solid #eee;
@ -63,25 +72,24 @@
border-bottom: none;
}
.right {
display: flex;
align-items: center;
gap: 10rpx;
}
.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;
height: 14vh;
background-color: white;
margin-top: 1vh;
}
@ -105,4 +113,8 @@
.bottom-list:last-child {
border-bottom: none;
}
.label {
flex: 1;
}
</style>

23
pages/setting/server.vue

@ -26,9 +26,31 @@
ref,
onMounted
} from 'vue'
import {
getSetting
} from "@/api/setting/general"
const iSMT = ref(0)
const selectedIndex = ref(0)
const getServer = async () => {
try {
const res = await getSetting()
if (res.code === 200) {
const fontSize = res.data.fontSize
const sizeMap = {
'auto': 0,
'singapore': 1,
'hongkong': 2
}
console.log('看看服务器', res.data.fontSize)
selectedIndex.value = sizeMap[fontSize] ?? 0;
}
} catch (err) {
console.error("获取服务器设置失败:", err);
}
}
const selectFont = (index) => {
selectedIndex.value = index
console.log('看看选中状态',selectedIndex.value)
@ -38,6 +60,7 @@
//
iSMT.value = uni.getSystemInfoSync().statusBarHeight;
console.log('看看高度', iSMT.value)
getServer()
})
</script>

21
pages/setting/theme.vue

@ -21,9 +21,29 @@
ref,
onMounted
} from 'vue'
import {
getSetting
} from "@/api/setting/general"
const iSMT = ref(0)
const selectedIndex = ref(0)
const getTheme = async () => {
try {
const res = await getSetting()
if (res.code === 200) {
const theme = res.data.theme
const sizeMap = {
'light': 0,
'dark': 1
}
console.log('看看主题', res.data.theme)
selectedIndex.value = sizeMap[theme] ?? 0;
}
} catch (err) {
console.error("获取主题设置失败:", err);
}
}
const selectFont = (index) => {
selectedIndex.value = index
console.log('看看选中状态', selectedIndex.value)
@ -32,6 +52,7 @@
//
iSMT.value = uni.getSystemInfoSync().statusBarHeight;
console.log('看看高度', iSMT.value)
getTheme()
})
</script>

3
pages/start/Registration/Registration.vue

@ -198,6 +198,7 @@ import {
SendPhoneCodeApi,
} from "../../../api/start/login";
import { useDeviceStore} from "../../../stores/modules/deviceInfo"
import { useUserStore} from "../../../stores/modules/userInfo"
const type = ref("");
const email = ref("");
@ -246,7 +247,7 @@ function showCountryPicker() {
function goToIndex() {
//
uni.navigateTo({
url: "/pages/start/index/index",
url: "/pages/start/login/login",
});
}

56
pages/start/index/index.vue

@ -1,56 +0,0 @@
<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>

93
pages/start/recoverPassword/recoverPassword.vue

@ -209,9 +209,9 @@
</text>
<!-- 或者 -->
<text class="or-text" @click="goToLogin">已有账号
<text class="link">登录
</text>
<text class="or-text" @click="goToLogin"
>已有账号
<text class="link">登录 </text>
</text>
<!-- 同意弹窗 -->
@ -235,7 +235,12 @@ import countryList from "../login/list";
import footerBar from "../../../components/footerBar";
import uniPopup from "../../../uni_modules/uni-popup/components/uni-popup/uni-popup.vue";
import { verificationPhone, verificationEmail } from "../login/verification";
import { SendEmailCodeApi, SendPhoneCodeApi } from "../../../api/start/login";
import {
SendEmailCodeApi,
SendPhoneCodeApi,
verifyCodeApi,
forgetApi,
} from "../../../api/start/login";
const type = ref("");
const email = ref("");
@ -254,6 +259,7 @@ const verifyCode = ref("");
const isRecovering = ref(false);
const newPasswordLookFirst = ref(false);
const newPasswordLookSecond = ref(false);
const account = ref("");
// 使list.js
const countries = ref(
@ -301,7 +307,7 @@ function switchPhone() {
verifyCode.value = "";
}
function register() {
async function register() {
if (isRecovering.value) {
if (!newPasswordFirst.value || !newPasswordSecond.value) {
uni.showToast({
@ -319,6 +325,32 @@ function register() {
return;
}
const account = changeAccount();
const res = await forgetApi({
account: account,
password: newPasswordSecond.value,
});
console.log("res", res);
if (res.code !== 200) {
uni.showToast({
title: res.message,
icon: "none",
});
return;
}
uni.showToast({
title: res.message,
icon: "none",
});
uni.navigateTo({
url: "/pages/start/login/login",
});
//
return;
}
@ -384,13 +416,54 @@ function register() {
console.log("登录:", email.value);
}
const account = changeAccount();
const loginType = changeLoginType();
const res = await verifyCodeApi({
loginType: loginType, //EMAIL,PHONE
account: account, // /
verifyCode: verifyCode.value,
});
if (res.code !== 200) {
uni.showToast({
title: res.message,
icon: "none",
});
return;
}
isRecovering.value = !isRecovering.value;
}
//
function changeAccount() {
if (switchType.value === "User") {
account.value = deepChartID.value;
}
if (switchType.value === "Phone") {
account.value = `${country.value}${phone.value}`;
}
if (switchType.value === "Email") {
account.value = email.value;
}
//
// uni.showToast({
// title: "",
// icon: "success",
// });
return account.value;
}
// type
function changeLoginType() {
if (switchType.value === "User") {
return "DCCODE";
}
if (switchType.value === "Phone") {
return "PHONE";
}
if (switchType.value === "Email") {
return "EMAIL";
}
}
function goToLogin() {

25
static/language/en.js

@ -1,14 +1,21 @@
/** @format */
export default {
language: {
"name": "Simplified Chinese"
name: "Simplified Chinese",
},
components: {
footerBar: {
homepage: '首页',
marketSituation: '行情',
deepMate: 'DeepMate',
deepExploration: '深度探索',
member: '我的',
},
}
}
homepage: "首页",
marketSituation: "行情",
deepMate: "DeepMate",
deepExploration: "深度探索",
member: "我的",
},
},
marketSituation: {
globalIndex: "全球指数",
globalIndexMore:'查看更多',
warn:'全球指数为试运行,免费开放,有诸多不足请见谅'
},
};

7
static/language/ms.js

@ -10,5 +10,10 @@ export default {
deepExploration: '深度探索',
member: '我的',
},
}
},
marketSituation: {
globalIndex: "全球指数",
globalIndexMore:'查看更多',
warn:'全球指数为试运行,免费开放,有诸多不足请见谅'
},
}

7
static/language/th.js

@ -10,5 +10,10 @@ export default {
deepExploration: '深度探索',
member: '我的',
},
}
},
marketSituation: {
globalIndex: "全球指数",
globalIndexMore:'查看更多',
warn:'全球指数为试运行,免费开放,有诸多不足请见谅'
},
}

7
static/language/vi.js

@ -10,5 +10,10 @@ export default {
deepExploration: '深度探索',
member: '我的',
},
}
},
marketSituation: {
globalIndex: "全球指数",
globalIndexMore:'查看更多',
warn:'全球指数为试运行,免费开放,有诸多不足请见谅'
},
}

21
static/language/zh_CN.js

@ -1,15 +1,22 @@
/** @format */
// 中文简体
export default {
language: {
name: '中文简体'
name: "中文简体",
},
components: {
footerBar: {
homepage: '首页',
marketSituation: '行情',
deepMate: 'DeepMate',
deepExploration: '深度探索',
member: '我的',
homepage: "首页",
marketSituation: "行情",
deepMate: "DeepMate",
deepExploration: "深度探索",
member: "我的",
},
},
}
marketSituation: {
globalIndex: "全球指数",
globalIndexMore:'查看更多',
warn:'全球指数为试运行,免费开放,有诸多不足请见谅'
},
};

21
static/language/zh_HK.js

@ -1,15 +1,22 @@
/** @format */
// 中文繁体
export default {
language: {
name: "中文繁体"
name: "中文繁体",
},
components: {
footerBar: {
homepage: '首页',
marketSituation: '行情',
deepMate: 'DeepMate',
deepExploration: '深度探索',
member: '我的',
homepage: "首页",
marketSituation: "行情",
deepMate: "DeepMate",
deepExploration: "深度探索",
member: "我的",
},
},
}
marketSituation: {
globalIndex: "全球指数",
globalIndexMore:'查看更多',
warn:'全球指数为试运行,免费开放,有诸多不足请见谅'
},
};

1
stores/index.js

@ -10,5 +10,6 @@ pinia.use(persist)
export * from './modules/userInfo'
export * from './modules/deviceInfo'
export * from './modules/deepExploration'
export * from './modules/login'
// 默认导出,给 main.js 使用
export default pinia

44
stores/modules/login.js

@ -0,0 +1,44 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
// 定义 Store
export const useLoginStore = defineStore(
'login',
() => {
// 会员信息
const loginInfo = ref("true")
// 保存会员信息,登录时使用
const setLoginInfo = (val) => {
loginInfo.value = val
}
// 清理会员信息,退出时使用
const clearLoginInfo = () => {
loginInfo.value = undefined
}
// 记得 return
return {
loginInfo,
setLoginInfo,
clearLoginInfo,
}
},
// TODO: 持久化
{
// 网页端持久化
// persist: true,
// 小程序端持久化
persist: {
storage: {
getItem(key) {
return uni.getStorageSync(key)
},
setItem(key, value) {
uni.setStorageSync(key, value)
},
},
},
},
)

13
utils/http.js

@ -1,5 +1,6 @@
import { useUserStore } from "../stores/modules/userInfo"
import { useDeviceStore } from "../stores/modules/deviceInfo"
import { useLoginStore } from "../stores/modules/login"
const baseURL = "https://dbqb.nfdxy.net/testApi"
@ -22,7 +23,7 @@ const httpInterceptor = {
// 打印最终请求地址
console.log('HTTP(finalUrl)=', options.url)
// 2.请求超时,默认60s
options.timeout = 60000
options.timeout = 10000
console.log(options)
//3 添加小程序端请求头
const sys = uni.getSystemInfoSync();
@ -66,6 +67,14 @@ export const http = (options) => {
success: (result) => {
if (result.statusCode >= 200 && result.statusCode < 300) {
if (result.data.code === 401) {
const loginStore = useLoginStore()
loginStore.setLoginInfo("true")
console.log("1loginStore.loginInfo", loginStore.loginInfo);
loginStore.setLoginInfo("false")
console.log("2loginStore.loginInfo", loginStore.loginInfo);
uni.showToast({
title: '请先登录',
icon: 'none'
@ -93,7 +102,7 @@ export const http = (options) => {
fail: (err) => {
reject(err)
uni.showToast({
title: '网络错误',
title: '请求超时',
icon: 'none'
})
}

14
vue.config.js

@ -1,12 +1,22 @@
module.exports = {
devServer: {
proxy: {
/* proxy: {
'/api': { // 你的目标服务器的请求路径前缀
target: 'https://hwjb.homilychart.com', // 目标服务器的地址
changeOrigin: true, // 是否跨域
secure: false, // 如果是https接口,需要配置这个参数
pathRewrite: {
'^/': '/testApi' // 将 /api 替换为 /testApi,以便正确请求目标服务器的资源
'^/api': '' // 将 /api 替换为 /testApi,以便正确请求目标服务器的资源
}
}
} */
proxy: {
'/api': { // 你的目标服务器的请求路径前缀
target: 'http://192.168.40.8:9000', // 目标服务器的地址
changeOrigin: true, // 是否跨域
secure: false, // 如果是https接口,需要配置这个参数
pathRewrite: {
'^/api': '' // 将 /api 替换为 /testApi,以便正确请求目标服务器的资源
}
}
}

Loading…
Cancel
Save