You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1043 lines
27 KiB

4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
3 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
3 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
3 weeks ago
3 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
3 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
3 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
3 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
3 weeks ago
4 weeks ago
4 weeks ago
3 weeks ago
3 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
3 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
3 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
3 weeks ago
4 weeks ago
3 weeks ago
3 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
4 weeks ago
3 weeks ago
4 weeks ago
3 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
  1. <template>
  2. <LoginPrompt ref="loginPrompt"></LoginPrompt>
  3. <view class="main">
  4. <!-- 顶部状态栏占位 -->
  5. <view class="top" :style="{height:iSMT+'px'}"></view>
  6. <deepExploration_header></deepExploration_header>
  7. <view class="search">
  8. <input v-model="searchName" class="searchInput" type="text" placeholder="请输入股票名称、股票代码"
  9. placeholder-style="color: #A6A6A6; font-size: 28rpx;" />
  10. <image @click="searchStock" class="seachIcon" src="/static/deepExploration-images/search.png"
  11. mode="aspectFill"></image>
  12. </view>
  13. <view class="content">
  14. <view class="select">
  15. <image class="img" :src="navItems[currentIndex].icon" mode=""></image>
  16. <view v-for="(item, index) in navItems" :key="index" class="selectItem"
  17. :class="{ active: currentIndex === index }" @click="handleModel(index)">
  18. <button class="btn"></button>
  19. </view>
  20. </view>
  21. <view class="graphAndTxt">
  22. <view class="graph">
  23. <view class="graph_header">
  24. <view class="left">{{stockCode}}</view>
  25. <view class="center">
  26. <text>{{stockName}}</text>
  27. </view>
  28. <view class="right">{{stockTime}}</view>
  29. </view>
  30. <view class="graph_data">
  31. <text>{{stockPrice}}</text>
  32. <text>{{stockChange}}</text>
  33. <text>{{stockAdd}}</text>
  34. </view>
  35. <view class="graph_content">
  36. <view class="loadingGraph" v-show="graphLoading">加载中...</view>
  37. <view class="charts-box" v-show="!graphLoading">
  38. <!-- uCharts 蜡烛图组件 -->
  39. <qiun-data-charts type="candle" :opts="opts" :chartData="chartData" :disableScroll="true"
  40. :ontouch="true" :onzoom="true" :key="chartKey" />
  41. </view>
  42. <!-- <image @click.stop="showFullscreenKline" src="/static/deepExploration-images/kLineAll.png"
  43. mode="aspectFill"></image> -->
  44. </view>
  45. </view>
  46. <!-- 全屏横屏弹窗 -->
  47. <view class="fullscreen-mask" v-if="isFullscreen" @click="closeFullscreen">
  48. <view class="fullscreen-container" :style="{ transform: isLandscape ? 'rotate(90deg)' : '' }">
  49. <!-- 关闭按钮 -->
  50. <view class="fullscreen-close" @click.stop="closeFullscreen">
  51. <image src="/static/icons/close.png" mode="widthFix"></image>
  52. </view>
  53. <!-- 横屏切换按钮 -->
  54. <view class="fullscreen-rotate" @click.stop="toggleOrientation">
  55. <image src="/static/icons/rotate.png" mode="widthFix"></image>
  56. </view>
  57. <!-- 全屏K线图 -->
  58. <view class="fullscreen-chart">
  59. <qiun-data-charts type="candle" :opts="fullscreenOpts" :chartData="chartData"
  60. :key="fullscreenChartKey" />
  61. </view>
  62. </view>
  63. </view>
  64. <view class="txt">
  65. <view class="txtHeader">
  66. <image src="/static/deepExploration-images/plus.png" mode="aspectFill"></image>
  67. <text>{{navItems[currentIndex].name}}</text>
  68. </view>
  69. <view class="txtContent">
  70. <view v-if="loading" class="loading">加载中...</view>
  71. <rich-text :nodes="htmlContent"></rich-text>
  72. </view>
  73. </view>
  74. </view>
  75. </view>
  76. <!-- 底部切换栏 -->
  77. <footerBar class="static-footer" :type="type"></footerBar>
  78. </view>
  79. </template>
  80. <script setup>
  81. import {
  82. ref,
  83. onMounted,
  84. watch
  85. } from 'vue'
  86. import deepExploration_header from '@/components/deepExploration_header.vue'
  87. import footerBar from '@/components/footerBar.vue'
  88. import {
  89. onLoad
  90. } from '@dcloudio/uni-app'
  91. import {
  92. getModel1First,
  93. getModel1Second,
  94. getModel2First,
  95. getModel2Second,
  96. getModel3First,
  97. getModel3Second,
  98. getModel4First,
  99. getModel4Second,
  100. getModeldefault,
  101. getData
  102. } from '/api/deepExploration/deepExploration.js'
  103. import marked from 'marked'; // 引入 marked 库
  104. import hljs from 'highlight.js';
  105. import 'highlight.js/styles/atom-one-dark.css'; // 可替换为其他主题
  106. import {
  107. useDeepExplorationStore
  108. } from '@/stores/modules/deepExploration'
  109. import {
  110. getUserInfo
  111. } from "@/api/member"
  112. import {
  113. useUserStore
  114. } from '@/stores/modules/userInfo.js'
  115. const deepExplorationStore = useDeepExplorationStore()
  116. const userInfo = getUserInfo()
  117. //历史数据
  118. const historyData = ref({})
  119. //登录弹窗提示ref
  120. const loginPrompt = ref(null)
  121. // 全屏相关状态
  122. const isFullscreen = ref(false); // 是否显示全屏弹窗
  123. const isLandscape = ref(true); // 是否横屏模式
  124. const fullscreenChartKey = ref(0); // 全屏图表重绘标识
  125. const graphLoading = ref(true)
  126. // 显示全屏K线
  127. const showFullscreenKline = () => {
  128. isFullscreen.value = true;
  129. isLandscape.value = true; // 默认横屏
  130. // 强制重绘图表
  131. setTimeout(() => {
  132. fullscreenChartKey.value++;
  133. }, 100);
  134. };
  135. // 关闭全屏
  136. const closeFullscreen = () => {
  137. isFullscreen.value = false;
  138. };
  139. // 切换横竖屏
  140. const toggleOrientation = () => {
  141. isLandscape.value = !isLandscape.value;
  142. // 旋转后重绘图表
  143. setTimeout(() => {
  144. fullscreenChartKey.value++;
  145. }, 300);
  146. };
  147. // 响应式变量定义
  148. const type = ref('deepExploration')
  149. const iSMT = ref(0)
  150. const currentIndex = ref(0)
  151. const navItems = ref([{
  152. name: '主力追踪',
  153. icon: '/static/deepExploration-images/1.png'
  154. },
  155. {
  156. name: '主力雷达',
  157. icon: '/static/deepExploration-images/2.png'
  158. },
  159. {
  160. name: '主力解码',
  161. icon: '/static/deepExploration-images/3.png'
  162. },
  163. {
  164. name: '主力资金流',
  165. icon: '/static/deepExploration-images/4.png'
  166. },
  167. ])
  168. //搜索股票
  169. const searchStock = () => {
  170. htmlContent.value = ''
  171. console.log('搜索参数:', stockName.value, currentIndex.value);
  172. if (currentIndex.value >= 0 && currentIndex.value <= 3) {
  173. handleModels()
  174. } else {
  175. uni.showToast({
  176. title: '请选择模块',
  177. icon: 'none',
  178. duration: 2000
  179. })
  180. }
  181. }
  182. //点击四大模块
  183. const handleModel = async (index) => {
  184. htmlContent.value = ''
  185. currentIndex.value = index
  186. await handleModels()
  187. // await getServerData()
  188. }
  189. const stockName = ref('Tesla Inc.')
  190. const searchName = ref('')
  191. const stockCode = ref('TSLA')
  192. const language = ref('')
  193. const recordId = ref('')
  194. const parentId = ref('')
  195. const stockId = ref('')
  196. const market = ref('usa')
  197. const stockTime = ref('2025/10/24')
  198. const loading = ref(true);
  199. const error = ref('');
  200. const htmlContent = ref('');
  201. const markdownContent = ref('');
  202. const renderer = new marked.Renderer();
  203. renderer.heading = function(text, level) {
  204. return `<p>${text}</p>`;
  205. };
  206. // 初始化 marked 配置(支持代码高亮)
  207. marked.setOptions({
  208. highlight: (code, lang) => {
  209. if (lang && hljs.getLanguage(lang)) {
  210. return hljs.highlight(code, {
  211. language: lang
  212. }).value;
  213. }
  214. return hljs.highlightAuto(code).value;
  215. },
  216. renderer,
  217. breaks: true, // 换行转<br>
  218. gfm: true, // 支持GitHub flavored Markdown
  219. sanitize: false, // 保留HTML标签(如<span style>)
  220. });
  221. //获取模型数据
  222. const handleModels = async () => {
  223. try {
  224. graphLoading.value = true
  225. if (userInfo.isVisitor) {
  226. console.log('是游客');
  227. loginPrompt.value.show()
  228. return
  229. }
  230. console.log('搜了吗');
  231. // 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 '
  232. // htmlContent.value = marked.parse(markdownContent.value);
  233. loading.value = true;
  234. if (searchName.value == '') {
  235. console.log('没有搜索', searchName.value);
  236. handleDefault()
  237. getServerData()
  238. } else {
  239. if (currentIndex.value == 0) {
  240. console.log('搜索', searchName.value);
  241. const result = await getModel1First({
  242. content: searchName.value,
  243. language: "cn",
  244. marketList: "hk,cn,usa,my,sg,vi,in,gb",
  245. model: currentIndex.value + 1
  246. })
  247. console.log('result', result);
  248. if (result.code == 200) {
  249. stockCode.value = result.data.code
  250. // stockName.value = result.data.name
  251. recordId.value = result.data.recordId
  252. parentId.value = result.data.parentId
  253. stockId.value = result.data.stockId
  254. language.value = result.data.language
  255. market.value = result.data.market
  256. const res = await getModel1Second({
  257. language: language.value,
  258. recordId: recordId.value,
  259. parentId: parentId.value,
  260. stockId: stockId.value,
  261. token: 'pCtw6AYK0EHAaIexoFHsbZjtsfEAIhcmwkCFm6uKko8VPfMvyDiODL9v9c0veic9fIpQbvT8zN4sH/Si6Q'
  262. })
  263. if (res.code == 200) {
  264. const rawMarkdown = res.data.markdown;
  265. const adaptedMarkdown = rawMarkdown.replace(/^### /gm, ''); // 全局替换行首的###
  266. markdownContent.value = adaptedMarkdown;
  267. // markdownContent.value = res.data.markdown
  268. htmlContent.value = marked.parse(markdownContent.value);
  269. await getServerData()
  270. }
  271. console.log('res', res);
  272. } else if (result.code == 400) {
  273. markdownContent.value = result.message;
  274. htmlContent.value = marked.parse(markdownContent.value);
  275. } else {
  276. return
  277. }
  278. } else if (currentIndex.value == 1) {
  279. console.log('搜索', searchName.value);
  280. const result = await getModel2First({
  281. content: searchName.value,
  282. language: "cn",
  283. marketList: "hk,cn,usa,my,sg,vi,in,gb",
  284. model: currentIndex.value + 1
  285. })
  286. console.log('result', result);
  287. if (result.code == 200) {
  288. stockCode.value = result.data.code
  289. recordId.value = result.data.recordId
  290. parentId.value = result.data.parentId
  291. stockId.value = result.data.stockId
  292. language.value = result.data.language
  293. market.value = result.data.market
  294. const res = await getModel2Second({
  295. language: language.value,
  296. recordId: recordId.value,
  297. parentId: parentId.value,
  298. stockId: stockId.value,
  299. token: 'pCtw6AYK0EHAaIexoFHsbZjtsfEAIhcmwkCFm6uKko8VPfMvyDiODL9v9c0veic9fIpQbvT8zN4sH/Si6Q'
  300. })
  301. if (res.code == 200) {
  302. const rawMarkdown = res.data.markdown;
  303. const adaptedMarkdown = rawMarkdown.replace(/^### /gm, ''); // 全局替换行首的###
  304. markdownContent.value = adaptedMarkdown;
  305. // markdownContent.value = res.data.markdown
  306. htmlContent.value = marked.parse(markdownContent.value);
  307. await getServerData()
  308. }
  309. console.log('res', res);
  310. } else if (result.code == 400) {
  311. markdownContent.value = result.message;
  312. htmlContent.value = marked.parse(markdownContent.value);
  313. } else {
  314. return
  315. }
  316. } else if (currentIndex.value == 2) {
  317. console.log('搜索', searchName.value);
  318. const result = await getModel3First({
  319. content: searchName.value,
  320. language: "cn",
  321. marketList: "hk,cn,usa,my,sg,vi,in,gb",
  322. model: currentIndex.value + 1
  323. })
  324. console.log('result', result);
  325. if (result.code == 200) {
  326. stockCode.value = result.data.code
  327. // stockName.value = result.data.name
  328. recordId.value = result.data.recordId
  329. parentId.value = result.data.parentId
  330. stockId.value = result.data.stockId
  331. language.value = result.data.language
  332. market.value = result.data.market
  333. const res = await getModel3Second({
  334. language: language.value,
  335. recordId: recordId.value,
  336. parentId: parentId.value,
  337. stockId: stockId.value,
  338. token: 'pCtw6AYK0EHAaIexoFHsbZjtsfEAIhcmwkCFm6uKko8VPfMvyDiODL9v9c0veic9fIpQbvT8zN4sH/Si6Q'
  339. })
  340. if (res.code == 200) {
  341. const rawMarkdown = res.data.markdown;
  342. const adaptedMarkdown = rawMarkdown.replace(/^### /gm, ''); // 全局替换行首的###
  343. markdownContent.value = adaptedMarkdown;
  344. // markdownContent.value = res.data.markdown
  345. htmlContent.value = marked.parse(markdownContent.value);
  346. await getServerData()
  347. }
  348. console.log('res', res);
  349. } else if (result.code == 400) {
  350. markdownContent.value = result.message;
  351. htmlContent.value = marked.parse(markdownContent.value);
  352. } else {
  353. return
  354. }
  355. } else if (currentIndex.value == 3) {
  356. console.log('搜索', searchName.value);
  357. const result = await getModel4First({
  358. content: searchName.value,
  359. language: "cn",
  360. marketList: "hk,cn,usa,my,sg,vi,in,gb",
  361. model: currentIndex.value + 1
  362. })
  363. console.log('result', result);
  364. if (result.code == 200) {
  365. stockCode.value = result.data.code
  366. // stockName.value = result.data.name
  367. recordId.value = result.data.recordId
  368. parentId.value = result.data.parentId
  369. stockId.value = result.data.stockId
  370. language.value = result.data.language
  371. market.value = result.data.market
  372. const res = await getModel4Second({
  373. language: language.value,
  374. recordId: recordId.value,
  375. parentId: parentId.value,
  376. stockId: stockId.value,
  377. token: 'pCtw6AYK0EHAaIexoFHsbZjtsfEAIhcmwkCFm6uKko8VPfMvyDiODL9v9c0veic9fIpQbvT8zN4sH/Si6Q'
  378. })
  379. if (res.code == 200) {
  380. const rawMarkdown = res.data.markdown;
  381. const adaptedMarkdown = rawMarkdown.replace(/^### /gm, ''); // 全局替换行首的###
  382. markdownContent.value = adaptedMarkdown;
  383. // markdownContent.value = res.data.markdown
  384. htmlContent.value = marked.parse(markdownContent.value);
  385. await getServerData()
  386. }
  387. console.log('res', res);
  388. } else if (result.code == 400) {
  389. markdownContent.value = result.message;
  390. htmlContent.value = marked.parse(markdownContent.value);
  391. } else {
  392. return
  393. }
  394. } else {
  395. return
  396. }
  397. }
  398. } catch (e) {
  399. error.value = e.message || '加载失败,请重试';
  400. } finally {
  401. loading.value = false;
  402. }
  403. }
  404. const handleDefault = async () => {
  405. const result = await getModeldefault({
  406. token: "pCtw6AYK0EHAaIexoFHsbZjtsfEAIhcmwkCFm6uKko8VPfMvyDiODL9v9c0veic9fIpQbvT8zN4sH/Si6Q",
  407. model: currentIndex.value + 1
  408. })
  409. if (result.code == 200) {
  410. const rawMarkdown = result.data.markdown;
  411. const adaptedMarkdown = rawMarkdown.replace(/^### /gm, ''); // 全局替换行首的###
  412. markdownContent.value = adaptedMarkdown;
  413. htmlContent.value = marked.parse(markdownContent.value);
  414. } else {
  415. }
  416. }
  417. const stockPrice = ref('435.900')
  418. const stockAdd = ref('22.410')
  419. const stockChange = ref('5.120%')
  420. const chartKey = ref(0);
  421. const getServerData = async () => {
  422. const result = await getData({
  423. market: market.value || '',
  424. code: stockCode.value || '',
  425. language: "cn",
  426. brainPrivilegeState: 1,
  427. marketList: "usa.sg.my.hk.cn.can.vi.th.in.gb"
  428. })
  429. console.log('k线数据', result);
  430. stockName.value = result.data.StockInformation.Name || 'Tesla Inc.'
  431. stockCode.value = result.data.StockInformation.Code || 'TSLA'
  432. stockTime.value = result.data.StockInformation.Time || '2025/10/29'
  433. stockChange.value = result.data.StockInformation.Zhang || '5.120%'
  434. stockAdd.value = result.data.StockInformation.ZhangFu || '22.410'
  435. stockPrice.value = result.data.StockInformation.Price || '435.900'
  436. if (result.data.chartData) {
  437. const rawData = JSON.parse(JSON.stringify(result.data.chartData));
  438. if (rawData.categories.length > 1) { // 确保至少保留一个日期
  439. rawData.categories[rawData.categories.length - 1] = ''; // 删除最后一个日期
  440. console.log('删了;');
  441. }
  442. chartData.value = {
  443. ...rawData
  444. }
  445. graphLoading.value = false
  446. chartKey.value++;
  447. console.log('chartData', chartData.value);
  448. }
  449. }
  450. // 1. K线图配置
  451. const opts = ref({
  452. rotate: false,
  453. rotateLock: false,
  454. color: ["#1890FF", "#91CB74", "#FAC858", "#EE6666", "#73C0DE", "#3CA272", "#FC8452", "#9A60B4", "#ea7ccc"],
  455. padding: [15, 30, 0, 15],
  456. dataLabel: false,
  457. enableScroll: true,
  458. enableMarkLine: false,
  459. legend: {},
  460. xAxis: {
  461. labelCount: 4,
  462. itemCount: 20,
  463. disableGrid: true,
  464. gridColor: "#CCCCCC",
  465. gridType: "solid",
  466. dashLength: 4,
  467. scrollShow: false,
  468. rotate: 45,
  469. scrollAlign: "left",
  470. scrollColor: "#A6A6A6",
  471. scrollBackgroundColor: "#EFEBEF",
  472. labelColor: "#8C8C8C",
  473. fontSize: 9,
  474. },
  475. yAxis: {
  476. labelColor: "#8C8C8C",
  477. fontSize: 9
  478. },
  479. extra: {
  480. candle: {
  481. color: {
  482. upLine: "#f04864",
  483. upFill: "#f04864",
  484. downLine: "#2fc25b",
  485. downFill: "#2fc25b"
  486. },
  487. average: {
  488. show: false,
  489. name: ["MA5", "MA10", "MA30"],
  490. day: [5, 10, 20],
  491. color: ["#1890ff", "#2fc25b", "#facc14"]
  492. }
  493. },
  494. markLine: {
  495. type: "dash",
  496. dashLength: 5,
  497. data: [{
  498. value: 2150,
  499. lineColor: "#f04864",
  500. showLabel: false
  501. },
  502. {
  503. value: 2350,
  504. lineColor: "#f04864",
  505. showLabel: false
  506. }
  507. ]
  508. },
  509. tooltip: {
  510. showCategory: true
  511. }
  512. }
  513. })
  514. // 全屏图表配置(继承原有配置并优化)
  515. const fullscreenOpts = ref({
  516. ...opts.value, // 复用原有配置
  517. padding: [30, 30, 30, 30],
  518. xAxis: {
  519. ...opts.value.xAxis,
  520. labelCount: 8, // 横屏显示更多标签
  521. fontSize: 12
  522. },
  523. yAxis: {
  524. ...opts.value.yAxis,
  525. fontSize: 12
  526. },
  527. extra: {
  528. ...opts.value.extra,
  529. candle: {
  530. ...opts.value.extra.candle,
  531. width: 12 // 横屏时K线宽度增加
  532. }
  533. }
  534. });
  535. // 2. K线图数据(响应式定义)
  536. const chartData = ref({
  537. categories: [],
  538. series: [{
  539. name: '',
  540. data: []
  541. }]
  542. })
  543. //获取K线数据函数(直接定义,无需methods)
  544. // const getServerData1 = () => {
  545. // // 模拟服务器请求延时
  546. // setTimeout(() => {
  547. // const res = {
  548. // "categories": [
  549. // "2025/10/23",
  550. // "2025/10/24",
  551. // "2025/10/27"
  552. // ],
  553. // series: [{
  554. // "name": "贵州茅台",
  555. // "data": [
  556. // [
  557. // 1455.0,
  558. // 1468.8,
  559. // 1447.2,
  560. // 1467.98
  561. // ],
  562. // [
  563. // 1467.95,
  564. // 1478.88,
  565. // 1449.34,
  566. // 1450.0
  567. // ],
  568. // [
  569. // 1440.0,
  570. // 1452.49,
  571. // 1435.99,
  572. // 1440.41
  573. // ]
  574. // ],
  575. // }]
  576. // }
  577. // // 给响应式变量赋值(需修改.value)
  578. // chartData.value = JSON.parse(JSON.stringify(res))
  579. // }, 500)
  580. // }
  581. let unwatch = null;
  582. // 生命周期钩子:组件挂载后执行(替代onReady)
  583. onMounted(async () => {
  584. iSMT.value = uni.getSystemInfoSync().statusBarHeight
  585. getUserInfo()
  586. await handleModels()
  587. unwatch = watch(
  588. () => deepExplorationStore.deepExplorationInfo, // 监听的目标值(函数返回,避免响应式丢失)
  589. (newVal, oldVal) => {
  590. console.log('deepExplorationInfo 变化了:', newVal)
  591. historyData.value = {
  592. ...newVal
  593. }
  594. console.log(historyData.value.wokeFlowData);
  595. console.log('222', historyData.value.stockData.StockInformation);
  596. //工作流数据
  597. const rawMarkdown = historyData.value.wokeFlowData.One.markdown;
  598. const adaptedMarkdown = rawMarkdown.replace(/^### /gm, ''); // 全局替换行首的###
  599. markdownContent.value = adaptedMarkdown;
  600. // markdownContent.value = res.data.markdown
  601. htmlContent.value = marked.parse(markdownContent.value);
  602. //k线
  603. if (historyData.value.stockData.chartData.categories.length > 1) { // 确保至少保留一个日期
  604. historyData.value.stockData.chartData.categories[historyData.value.stockData.chartData
  605. .categories.length - 1] = ''; // 删除最后一个日期
  606. }
  607. chartData.value = {
  608. ...JSON.parse(JSON.stringify(historyData.value.stockData.chartData))
  609. }
  610. chartKey.value++;
  611. console.log('chartData', chartData.value);
  612. stockName.value = historyData.value.stockData.StockInformation.Name || 'Tesla Inc.'
  613. stockCode.value = historyData.value.stockData.StockInformation.Code || 'TSLA'
  614. stockTime.value = historyData.value.stockData.StockInformation.Time || '2025/10/29'
  615. stockChange.value = historyData.value.stockData.StockInformation.Zhang || '5.120%'
  616. stockAdd.value = historyData.value.stockData.StockInformation.ZhangFu || '22.410'
  617. stockPrice.value = historyData.value.stockData.StockInformation.Price || '435.900'
  618. currentIndex.value = historyData.value.model - 1
  619. }, {
  620. deep: true,
  621. immediate: true
  622. } // 开启深度监听(对象内部属性变化也能触发)
  623. )
  624. })
  625. // 页面加载时执行
  626. onLoad((e) => {
  627. if (e.index) {
  628. currentIndex.value = e.index - 1
  629. console.log('模块:', currentIndex.value)
  630. }
  631. if (e.stockName) {
  632. searchName.value = e.stockName
  633. console.log('股票名称:', searchName.value)
  634. }
  635. })
  636. </script>
  637. <style scoped lang="scss">
  638. .main {
  639. width: 100%;
  640. min-height: 100vh;
  641. background-color: #fff;
  642. padding-bottom: 120rpx;
  643. .search {
  644. position: relative;
  645. display: flex;
  646. align-items: center;
  647. background-color: #F3F3F3;
  648. width: calc(100% - 60rpx);
  649. height: 80rpx;
  650. border-radius: 50rpx;
  651. box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
  652. padding: 0 40rpx;
  653. margin: 15rpx 30rpx 0 30rpx;
  654. .seachIcon {
  655. position: absolute;
  656. right: 50rpx;
  657. width: 32rpx;
  658. height: 32rpx;
  659. }
  660. .searchInput {
  661. color: #111;
  662. width: 100%;
  663. }
  664. }
  665. .content {
  666. margin-top: 30rpx;
  667. padding-top: 30rpx;
  668. background-color: rgb(248, 248, 248);
  669. .select {
  670. position: relative;
  671. margin-bottom: -5rpx;
  672. .img {
  673. width: 750rpx;
  674. height: 198rpx;
  675. }
  676. .selectItem {
  677. .btn {
  678. position: absolute;
  679. width: 120rpx;
  680. height: 150rpx;
  681. background-color: transparent;
  682. &::after {
  683. border: none;
  684. }
  685. }
  686. &:nth-of-type(1) .btn {
  687. top: 30rpx;
  688. left: 60rpx;
  689. }
  690. &:nth-of-type(2) .btn {
  691. top: 30rpx;
  692. left: 230rpx;
  693. }
  694. &:nth-of-type(3) .btn {
  695. top: 30rpx;
  696. left: 400rpx;
  697. }
  698. &:nth-of-type(4) .btn {
  699. top: 30rpx;
  700. left: 570rpx;
  701. }
  702. }
  703. }
  704. .graphAndTxt {
  705. background-color: #fff;
  706. border-radius: 50rpx 50rpx 0 0;
  707. padding: 68.6rpx 36.5rpx 0 36.5rpx;
  708. .graph {
  709. border: 1rpx solid #e2e2e2;
  710. border-radius: 30rpx 30rpx 0 0;
  711. .graph_header {
  712. padding: 32rpx 20.5rpx 0 24rpx;
  713. display: flex;
  714. align-items: center;
  715. .left {
  716. color: #333333;
  717. font-family: "PingFang SC";
  718. font-size: 15px;
  719. font-style: normal;
  720. font-weight: 400;
  721. line-height: 15px;
  722. }
  723. .center {
  724. margin-left: 155rpx;
  725. display: flex;
  726. align-items: center;
  727. text {
  728. width: 160rpx;
  729. height: 36rpx;
  730. padding-left: 10rpx;
  731. color: #000000;
  732. white-space: nowrap;
  733. overflow: hidden;
  734. text-overflow: ellipsis;
  735. text-align: center;
  736. font-family: "PingFang SC";
  737. font-size: 18px;
  738. font-style: normal;
  739. font-weight: 500;
  740. line-height: 18px;
  741. }
  742. }
  743. .right {
  744. margin-left: 50rpx;
  745. color: #6a6a6a;
  746. font-family: "PingFang SC";
  747. font-size: 13px;
  748. font-style: normal;
  749. font-weight: 400;
  750. line-height: 15px;
  751. white-space: nowrap;
  752. }
  753. }
  754. .graph_data {
  755. display: flex;
  756. padding: 48rpx 24rpx;
  757. text {
  758. display: flex;
  759. color: #25ba5d;
  760. font-family: "PingFang SC";
  761. font-size: 17px;
  762. line-height: 17px;
  763. }
  764. text:nth-child(2) {
  765. margin-left: 120rpx;
  766. }
  767. text:nth-child(3) {
  768. margin-left: 110rpx;
  769. }
  770. }
  771. .graph_content {
  772. position: relative;
  773. min-height: 500rpx;
  774. display: flex;
  775. justify-content: center;
  776. align-items: center;
  777. .loadingGraph {
  778. font-size: 35rpx;
  779. color: #6a6a6a;
  780. }
  781. image {
  782. position: absolute;
  783. bottom: 20rpx;
  784. right: 30rpx;
  785. width: 48rpx;
  786. height: 48rpx;
  787. }
  788. .charts-box {
  789. width: 100%;
  790. height: 100%;
  791. overflow: visible;
  792. }
  793. }
  794. }
  795. /* 横屏按钮样式 */
  796. .rotate-btn {
  797. background: transparent;
  798. padding: 0 10rpx;
  799. margin-left: 15rpx;
  800. .btn-icon {
  801. width: 36rpx;
  802. height: 36rpx;
  803. vertical-align: middle;
  804. }
  805. }
  806. /* 全屏遮罩 */
  807. .fullscreen-mask {
  808. position: fixed;
  809. top: 0;
  810. left: 0;
  811. width: 100vw;
  812. height: 100vh;
  813. background-color: #000;
  814. z-index: 9999;
  815. display: flex;
  816. justify-content: center;
  817. align-items: center;
  818. }
  819. /* 全屏容器 */
  820. .fullscreen-container {
  821. width: 100vh;
  822. /* 横屏时宽度等于屏幕高度 */
  823. height: 100vw;
  824. /* 横屏时高度等于屏幕宽度 */
  825. transition: transform 0.3s ease;
  826. position: relative;
  827. }
  828. /* 关闭按钮 */
  829. .fullscreen-close {
  830. position: absolute;
  831. top: 20rpx;
  832. right: 20rpx;
  833. z-index: 10;
  834. image {
  835. width: 48rpx;
  836. height: 48rpx;
  837. }
  838. }
  839. /* 旋转按钮 */
  840. .fullscreen-rotate {
  841. position: absolute;
  842. top: 20rpx;
  843. left: 20rpx;
  844. z-index: 10;
  845. image {
  846. width: 48rpx;
  847. height: 48rpx;
  848. }
  849. }
  850. /* 全屏图表容器 */
  851. .fullscreen-chart {
  852. width: 100%;
  853. height: 100%;
  854. }
  855. /* 竖屏模式适配 */
  856. :deep(.fullscreen-container:not([style*="rotate(90deg)"])) {
  857. width: 100vw;
  858. height: 100vh;
  859. }
  860. .txt {
  861. background-color: #F3F3F3;
  862. margin-top: 48rpx;
  863. border-radius: 30rpx;
  864. .txtHeader {
  865. padding: 30rpx 24rpx;
  866. image {
  867. width: 20rpx;
  868. height: 20rpx;
  869. }
  870. text {
  871. margin-left: 5rpx;
  872. background-color: #FFFFFF;
  873. color: #000000;
  874. padding: 5rpx 22rpx;
  875. border-radius: 22rpx;
  876. font-size: 28rpx;
  877. font-weight: 400;
  878. line-height: 37rpx;
  879. }
  880. }
  881. .txtContent {
  882. min-height: 300rpx;
  883. padding: 20rpx 30rpx;
  884. margin-bottom: 100rpx;
  885. ::v-deep * {
  886. box-sizing: border-box;
  887. width: 100% !important; // 强制所有解析后的标签占满容器宽度
  888. white-space: normal !important; // 取消强制不换行
  889. word-wrap: break-word !important; // 长词/长数字自动换行
  890. }
  891. // 标题样式(确保换行)
  892. ::v-deep h2 {
  893. font-size: 32rpx;
  894. color: #333;
  895. margin: 25rpx 0 15rpx;
  896. line-height: 1.5;
  897. }
  898. // 段落样式(核心换行控制)
  899. ::v-deep p {
  900. font-size: 26rpx;
  901. color: #666;
  902. margin: 15rpx 0;
  903. line-height: 1.8; // 增加行高,提升可读性
  904. text-align: justify; // 两端对齐,避免单侧参差不齐
  905. }
  906. // 列表样式(纵向排列)
  907. ::v-deep ul,
  908. ::v-deep ol {
  909. margin: 15rpx 0 15rpx 30rpx;
  910. }
  911. ::v-deep li {
  912. margin: 10rpx 0;
  913. line-height: 1.6;
  914. }
  915. // 加载状态样式
  916. .loading {
  917. text-align: center;
  918. padding: 50rpx 0;
  919. color: #666;
  920. font-size: 26rpx;
  921. }
  922. }
  923. }
  924. }
  925. }
  926. .static-footer {
  927. position: fixed;
  928. bottom: 0;
  929. width: 100%;
  930. }
  931. }
  932. * {
  933. box-sizing: border-box;
  934. }
  935. </style>