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.

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