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.

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