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.

582 lines
13 KiB

4 weeks ago
3 weeks ago
4 weeks ago
4 weeks ago
3 weeks ago
4 weeks ago
3 weeks ago
3 weeks ago
4 weeks ago
  1. <template>
  2. <view class="titleContent">
  3. <view class="left">
  4. <uni-icons
  5. @click="handleBack"
  6. type="back"
  7. size="23"
  8. color="#111"
  9. ></uni-icons>
  10. </view>
  11. <view class="title">深度探索</view>
  12. <view class="right">
  13. <image
  14. class="notice"
  15. src="/static/deepExploration-images/notice.png"
  16. mode="aspectFill"
  17. ></image>
  18. <image
  19. @click="openHistoryDrawer"
  20. class="history"
  21. src="/static/deepExploration-images/history.png"
  22. mode="aspectFill"
  23. ></image>
  24. </view>
  25. </view>
  26. <view class="drawer-overlay" v-show="showHistoryDrawer"></view>
  27. <view
  28. class="drawer-panel"
  29. v-show="showHistoryDrawer"
  30. @click.stop
  31. @touchmove.stop.prevent
  32. :style="{ transform: 'translateY(' + drawerOffsetY + 'px)' }"
  33. >
  34. <view class="drawer-header">
  35. <text class="drawer-title">历史对话</text>
  36. <view class="drawer-actions">
  37. <view class="delete-all-container">
  38. <image
  39. class="delete-icon"
  40. src="/static/icons/Group_48095481.svg"
  41. ></image>
  42. <text class="delete-all" @click="clearAllHistory">删除全部</text>
  43. </view>
  44. <view class="drawer-close" @click="onDrawerBackClick"
  45. ><text class="drawer-close-icon"></text
  46. ></view>
  47. </view>
  48. </view>
  49. <scroll-view scroll-y="true" class="drawer-content">
  50. <view class="drawer-inner">
  51. <view v-if="groupedHistory.length === 0" class="empty-history">
  52. <text>暂无历史记录</text>
  53. </view>
  54. <view
  55. v-for="(section, sIdx) in groupedHistory"
  56. :key="sIdx"
  57. class="history-section"
  58. >
  59. <text class="section-title">{{ section.title }}</text>
  60. <view
  61. v-for="(item, idx) in section.items"
  62. :key="idx"
  63. class="history-item"
  64. >
  65. <view class="history-left">
  66. <view class="flag-circle">
  67. <image
  68. class="icon-stock-model"
  69. :src="modelImage(item.model)"
  70. mode="scaleToFill"
  71. /></view>
  72. </view>
  73. <view class="history-left">
  74. <view class="flag-circle">
  75. <image
  76. class="icon-stock"
  77. :src="stockImage(item.stockMarket)"
  78. mode="scaleToFill"
  79. /></view>
  80. </view>
  81. <view class="history-main" @click="itemClick(item)">
  82. <text class="history-query">{{ item.stockName }}</text>
  83. <text class="history-query">{{ item.stockCode }}</text>
  84. </view>
  85. <text class="history-time">{{
  86. formatTimeForHistory(item.createdTime)
  87. }}</text>
  88. </view>
  89. </view>
  90. </view>
  91. </scroll-view>
  92. </view>
  93. </template>
  94. <script setup>
  95. import {
  96. RecordListApi,
  97. RecordInfoApi,
  98. RecordListDeleteApi
  99. } from "../api/deepExploration/deepExploration";
  100. import { ref, onMounted, computed } from "vue";
  101. import { useDeepExplorationStore } from "../stores/modules/deepExploration";
  102. const props = defineProps({
  103. name: {
  104. type: String,
  105. default: "",
  106. },
  107. });
  108. const showHistoryDrawer = ref(false);
  109. const drawerOffsetY = ref(0);
  110. // const handleHistory = () => {
  111. // showHistoryDrawer.value = true;
  112. // };
  113. function modelType(model) {
  114. switch (model) {
  115. case 1:
  116. return "主力追踪";
  117. case 2:
  118. return "主力雷达";
  119. case 3:
  120. return "主力解码";
  121. case 4:
  122. return "主力资金流";
  123. }
  124. }
  125. // 历史记录
  126. const openHistoryDrawer = async () => {
  127. const res = await RecordListApi({
  128. model: 1,
  129. });
  130. if (res.code === 200) {
  131. historyList.value = res.data;
  132. }
  133. console.log("historyList.value", historyList.value);
  134. const hideDistance = uni.upx2px(900);
  135. drawerOffsetY.value = hideDistance;
  136. showHistoryDrawer.value = true;
  137. setTimeout(() => {
  138. drawerOffsetY.value = 0;
  139. }, 10);
  140. };
  141. const clearAllHistory = () => {
  142. historyList.value = [];
  143. RecordListDeleteApi({
  144. })
  145. // uni.setStorageSync("search_history", []);
  146. };
  147. //返回上一页
  148. const handleBack = () => {
  149. uni.navigateBack();
  150. };
  151. const closeHistoryDrawer = () => {
  152. showHistoryDrawer.value = false;
  153. };
  154. const onDrawerBackClick = () => {
  155. const hideDistance = uni.upx2px(900);
  156. drawerOffsetY.value = hideDistance;
  157. setTimeout(() => {
  158. closeHistoryDrawer();
  159. drawerOffsetY.value = 0;
  160. }, 180);
  161. };
  162. // 历史记录国家图像
  163. function modelImage(model) {
  164. switch (model) {
  165. case 1:
  166. return "../../static/icons/tracking.png";
  167. case 2:
  168. return "../../static/icons/radar.png";
  169. case 3:
  170. return "../../static/icons/decoding.png";
  171. case 4:
  172. return "../../static/icons/funds.png";
  173. }
  174. }
  175. // 历史记录国家图像
  176. function stockImage(Market) {
  177. switch (Market) {
  178. case "usa":
  179. return "../../static/marketSituation-image/country-flag/us.png";
  180. case "can":
  181. return "../../static/marketSituation-image/country-flag/can.png";
  182. case "vi":
  183. return "../../static/marketSituation-image/country-flag/vi.png";
  184. case "th":
  185. return "../../static/marketSituation-image/country-flag/th.png";
  186. case "my":
  187. return "../../static/marketSituation-image/country-flag/my.png";
  188. case "sg":
  189. return "../../static/marketSituation-image/country-flag/sg.png";
  190. case "hk":
  191. return "../../static/marketSituation-image/country-flag/hk.png";
  192. case "cn":
  193. return "../../static/marketSituation-image/country-flag/cn.png";
  194. }
  195. }
  196. // 历史记录详情
  197. async function itemClick(item) {
  198. const res = await RecordInfoApi({
  199. recordId: item.id,
  200. parentId: item.parentId,
  201. model: 5,
  202. });
  203. if (res.code == 200) {
  204. const message = res.data;
  205. const deepExplorationStore = useDeepExplorationStore();
  206. deepExplorationStore.setDeepExplorationInfo(message);
  207. console.log("点击了历史数据", deepExplorationStore.deepExplorationInfo);
  208. onDrawerBackClick();
  209. setTimeout(() => {
  210. uni.navigateTo({
  211. url: "/pages/deepExploration/MainForceActions",
  212. });
  213. }, 200);
  214. }
  215. }
  216. const historyList = ref([]);
  217. // 为历史记录格式化时间:YYYY-MM-DD HH:mm
  218. const formatTimeForHistory = (timeString) => {
  219. // 假设 timeString 格式为 "YYYY-MM-DD HH:mm:ss"
  220. const parts = timeString.split(" ");
  221. if (parts.length >= 2) {
  222. const datePart = parts[0];
  223. const timePart = parts[1];
  224. const timeParts = timePart.split(":");
  225. if (timeParts.length >= 2) {
  226. return `${datePart} ${timeParts[0]}:${timeParts[1]}`;
  227. }
  228. }
  229. return timeString;
  230. };
  231. // 历史分组(今天/昨天/近一周/按月)
  232. const groupedHistory = computed(() => {
  233. const sections = [];
  234. // 从缓存获取今天日期,如果没有则使用当前日期
  235. const now = new Date();
  236. const startOfDay = (d) =>
  237. new Date(d.getFullYear(), d.getMonth(), d.getDate());
  238. const isSameDay = (a, b) =>
  239. startOfDay(a).getTime() === startOfDay(b).getTime();
  240. const isYesterday = (d) => {
  241. const y = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1);
  242. return isSameDay(d, y);
  243. };
  244. const isToday = (d) => isSameDay(d, now);
  245. const withinLast7Days = (d) => {
  246. const seven = new Date(
  247. now.getFullYear(),
  248. now.getMonth(),
  249. now.getDate() - 7
  250. );
  251. return d >= seven && !isToday(d) && !isYesterday(d);
  252. };
  253. const monthLabel = (d) => `${d.getMonth() + 1}`;
  254. const today = [];
  255. const yesterday = [];
  256. const last7 = [];
  257. const byMonth = new Map();
  258. // 使用 historyList.value 替代 searchHistory.value
  259. historyList.value.forEach((item) => {
  260. // 根据你的数据结构,使用 createdTime 字段
  261. const dt = new Date(item.createdTime);
  262. if (isToday(dt)) {
  263. today.push(item);
  264. } else if (isYesterday(dt)) {
  265. yesterday.push(item);
  266. } else if (withinLast7Days(dt)) {
  267. last7.push(item);
  268. } else {
  269. const year = dt.getFullYear();
  270. const month = dt.getMonth() + 1;
  271. const key = `${year}-${month}`;
  272. if (!byMonth.has(key))
  273. byMonth.set(key, {
  274. title: `${year}${month}`,
  275. year,
  276. month,
  277. items: [],
  278. });
  279. byMonth.get(key).items.push(item);
  280. }
  281. });
  282. if (today.length) sections.push({ title: "今天", items: today });
  283. if (yesterday.length) sections.push({ title: "昨天", items: yesterday });
  284. if (last7.length) sections.push({ title: "近一周", items: last7 });
  285. const monthSections = Array.from(byMonth.values()).sort((a, b) => {
  286. if (a.year !== b.year) return b.year - a.year;
  287. return b.month - a.month; // 月份倒序,如 10月 在 9月 之前
  288. });
  289. sections.push(...monthSections);
  290. return sections;
  291. });
  292. onMounted(() => {});
  293. </script>
  294. <style scoped lang="scss">
  295. * {
  296. box-sizing: border-box;
  297. }
  298. .titleContent {
  299. display: flex;
  300. align-items: center;
  301. justify-content: space-between;
  302. padding: 30rpx 60rpx 40rpx 35rpx;
  303. box-shadow: 2rpx 2rpx 8rpx rgba(0, 0, 0, 0.1);
  304. .left {
  305. display: flex;
  306. align-items: center;
  307. width: 36rpx;
  308. height: 36rpx;
  309. }
  310. .title {
  311. position: absolute;
  312. left: 50%;
  313. transform: translateX(-50%);
  314. color: #000000;
  315. font-family: "PingFang SC";
  316. font-size: 19px;
  317. font-style: normal;
  318. font-weight: 400;
  319. line-height: 25px;
  320. }
  321. .right {
  322. display: flex;
  323. align-items: center;
  324. gap: 20rpx;
  325. .notice {
  326. width: 35rpx;
  327. height: 35rpx;
  328. gap: 20rpx;
  329. }
  330. .history {
  331. width: 32rpx;
  332. height: 32rpx;
  333. align-items: center;
  334. }
  335. }
  336. }
  337. /* 搜索历史侧拉框样式 */
  338. .drawer-overlay {
  339. position: fixed;
  340. left: 0;
  341. top: 0;
  342. right: 0;
  343. bottom: 0;
  344. background-color: rgba(0, 0, 0, 0.35);
  345. z-index: 900;
  346. }
  347. .drawer-panel {
  348. position: fixed;
  349. left: 0;
  350. right: 0;
  351. bottom: 0;
  352. height: 75vh;
  353. max-height: 80vh;
  354. width: 100%;
  355. background: #ffffff;
  356. box-shadow: 0 -8rpx 20rpx rgba(0, 0, 0, 0.06);
  357. z-index: 1000;
  358. display: flex;
  359. flex-direction: column;
  360. border-top-left-radius: 20rpx;
  361. border-top-right-radius: 20rpx;
  362. transition: transform 0.22s ease;
  363. }
  364. .drawer-back {
  365. position: absolute;
  366. left: 50%;
  367. top: -14px;
  368. transform: translateX(-50%);
  369. width: 28px;
  370. height: 48px;
  371. border-radius: 12px;
  372. background: #fff;
  373. box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
  374. display: flex;
  375. align-items: center;
  376. justify-content: center;
  377. }
  378. .drawer-back-icon {
  379. font-size: 16px;
  380. color: #8a8a8a;
  381. }
  382. .drawer-actions {
  383. display: flex;
  384. align-items: center;
  385. gap: 40rpx;
  386. }
  387. .delete-all-container {
  388. display: flex;
  389. align-items: center;
  390. gap: 14rpx;
  391. }
  392. .delete-icon {
  393. width: 28rpx;
  394. height: 32rpx;
  395. }
  396. .delete-all {
  397. font-size: 28rpx;
  398. }
  399. .drawer-close {
  400. background: url("../static/icons/close-two.svg");
  401. width: 48rpx;
  402. height: 48rpx;
  403. border-radius: 24rpx;
  404. /* background: #f5f5f5; */
  405. /* box-shadow: 0 2px 8px rgba(0,0,0,0.08); */
  406. display: flex;
  407. align-items: center;
  408. justify-content: center;
  409. image {
  410. width: 100%;
  411. height: 100%;
  412. }
  413. }
  414. .drawer-header {
  415. display: flex;
  416. align-items: center;
  417. justify-content: space-between;
  418. padding: 52rpx 28rpx 0rpx 28rpx;
  419. /* border-bottom: 2rpx solid #f0f0f0; */
  420. }
  421. .drawer-title {
  422. font-size: 32rpx;
  423. font-weight: 600;
  424. color: #333333;
  425. }
  426. .drawer-content {
  427. flex: 1;
  428. min-height: 0;
  429. /* 让 flex 子元素可在容器内收缩以启用滚动 */
  430. height: 100%;
  431. overscroll-behavior-y: contain;
  432. /* 防止滚动串联到页面 */
  433. -webkit-overflow-scrolling: touch;
  434. /* iOS 惯性滚动 */
  435. touch-action: pan-y;
  436. /* 优化触控滚动,仅垂直 */
  437. }
  438. .drawer-inner {
  439. padding: 20rpx 24rpx 20rpx 24rpx;
  440. }
  441. .history-section {
  442. margin-bottom: 20rpx;
  443. /* margin: 0 24rpx; */
  444. }
  445. .section-title {
  446. font-size: 26rpx;
  447. color: #888;
  448. margin: 10rpx 6rpx 16rpx;
  449. }
  450. .history-item {
  451. display: flex;
  452. align-items: center;
  453. padding: 19rpx 18rpx;
  454. background-color: #f6f7f9;
  455. border-radius: 12rpx;
  456. margin-bottom: 12rpx;
  457. }
  458. .history-left {
  459. margin-right: 20rpx;
  460. width: 50rpx;
  461. height: 50rpx;
  462. }
  463. .icon-stock-model {
  464. width: 45rpx;
  465. height: 45rpx;
  466. }
  467. .icon-stock {
  468. width: 36rpx;
  469. height: 36rpx;
  470. }
  471. .flag-circle {
  472. width: 50rpx;
  473. height: 50rpx;
  474. border-radius: 50%;
  475. background: #fff;
  476. border: 2rpx solid #eee;
  477. display: flex;
  478. align-items: center;
  479. justify-content: center;
  480. // image {
  481. // width: 50rpx;
  482. // height: 50rpx;
  483. // border-radius: 50%;
  484. // }
  485. }
  486. .history-main {
  487. flex: 1;
  488. }
  489. .history-query {
  490. color: #000000;
  491. text-align: center;
  492. font-size: 24rpx;
  493. font-weight: 400;
  494. line-height: 40rpx;
  495. }
  496. .history-time {
  497. font-size: 22rpx;
  498. color: #999;
  499. }
  500. .history-card {
  501. background-color: #fff;
  502. border: 2rpx solid #f2f2f2;
  503. border-left: 8rpx solid rgb(220, 31, 29);
  504. border-radius: 12rpx;
  505. padding: 18rpx 20rpx;
  506. margin-bottom: 16rpx;
  507. box-shadow: 0 4rpx 10rpx rgba(0, 0, 0, 0.03);
  508. }
  509. .history-query {
  510. font-size: 28rpx;
  511. color: #333333;
  512. font-weight: 500;
  513. }
  514. .history-time {
  515. margin-top: 8rpx;
  516. font-size: 22rpx;
  517. color: #888888;
  518. }
  519. .empty-history {
  520. padding: 40rpx;
  521. color: #999999;
  522. text-align: center;
  523. }
  524. </style>