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.

556 lines
12 KiB

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