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.

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