Spaces:
Running
Running
Commit
·
d31b817
1
Parent(s):
34d2ace
try to fix data fetching issue
Browse files- package-lock.json +6 -0
- src/lib/dataService.js +35 -15
package-lock.json
CHANGED
|
@@ -488,6 +488,7 @@
|
|
| 488 |
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-7.1.0.tgz",
|
| 489 |
"integrity": "sha512-fNxRUk1KhjSbnbuBxlWSnBLKLBNun52ZBTcs22H/xEEzM6Ap81ZFTQ4bZBxVQGQgVY0xugKGoRcCbaKjLQ3XZA==",
|
| 490 |
"license": "MIT",
|
|
|
|
| 491 |
"dependencies": {
|
| 492 |
"@fortawesome/fontawesome-common-types": "7.1.0"
|
| 493 |
},
|
|
@@ -1202,6 +1203,7 @@
|
|
| 1202 |
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz",
|
| 1203 |
"integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==",
|
| 1204 |
"license": "MIT",
|
|
|
|
| 1205 |
"dependencies": {
|
| 1206 |
"@kurkle/color": "^0.3.0"
|
| 1207 |
},
|
|
@@ -1238,6 +1240,7 @@
|
|
| 1238 |
"version": "6.0.0",
|
| 1239 |
"resolved": "https://registry.npmjs.org/echarts/-/echarts-6.0.0.tgz",
|
| 1240 |
"integrity": "sha512-Tte/grDQRiETQP4xz3iZWSvoHrkCQtwqd6hs+mifXcjrCuo2iKWbajFObuLJVBlDIJlOzgQPd1hsaKt/3+OMkQ==",
|
|
|
|
| 1241 |
"dependencies": {
|
| 1242 |
"tslib": "2.3.0",
|
| 1243 |
"zrender": "6.0.0"
|
|
@@ -3565,6 +3568,7 @@
|
|
| 3565 |
"version": "4.0.3",
|
| 3566 |
"inBundle": true,
|
| 3567 |
"license": "MIT",
|
|
|
|
| 3568 |
"engines": {
|
| 3569 |
"node": ">=12"
|
| 3570 |
},
|
|
@@ -3923,6 +3927,7 @@
|
|
| 3923 |
"integrity": "sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g==",
|
| 3924 |
"dev": true,
|
| 3925 |
"license": "MIT",
|
|
|
|
| 3926 |
"dependencies": {
|
| 3927 |
"esbuild": "^0.21.3",
|
| 3928 |
"postcss": "^8.4.43",
|
|
@@ -3982,6 +3987,7 @@
|
|
| 3982 |
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.22.tgz",
|
| 3983 |
"integrity": "sha512-toaZjQ3a/G/mYaLSbV+QsQhIdMo9x5rrqIpYRObsJ6T/J+RyCSFwN2LHNVH9v8uIcljDNa3QzPVdv3Y6b9hAJQ==",
|
| 3984 |
"license": "MIT",
|
|
|
|
| 3985 |
"dependencies": {
|
| 3986 |
"@vue/compiler-dom": "3.5.22",
|
| 3987 |
"@vue/compiler-sfc": "3.5.22",
|
|
|
|
| 488 |
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-7.1.0.tgz",
|
| 489 |
"integrity": "sha512-fNxRUk1KhjSbnbuBxlWSnBLKLBNun52ZBTcs22H/xEEzM6Ap81ZFTQ4bZBxVQGQgVY0xugKGoRcCbaKjLQ3XZA==",
|
| 490 |
"license": "MIT",
|
| 491 |
+
"peer": true,
|
| 492 |
"dependencies": {
|
| 493 |
"@fortawesome/fontawesome-common-types": "7.1.0"
|
| 494 |
},
|
|
|
|
| 1203 |
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz",
|
| 1204 |
"integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==",
|
| 1205 |
"license": "MIT",
|
| 1206 |
+
"peer": true,
|
| 1207 |
"dependencies": {
|
| 1208 |
"@kurkle/color": "^0.3.0"
|
| 1209 |
},
|
|
|
|
| 1240 |
"version": "6.0.0",
|
| 1241 |
"resolved": "https://registry.npmjs.org/echarts/-/echarts-6.0.0.tgz",
|
| 1242 |
"integrity": "sha512-Tte/grDQRiETQP4xz3iZWSvoHrkCQtwqd6hs+mifXcjrCuo2iKWbajFObuLJVBlDIJlOzgQPd1hsaKt/3+OMkQ==",
|
| 1243 |
+
"peer": true,
|
| 1244 |
"dependencies": {
|
| 1245 |
"tslib": "2.3.0",
|
| 1246 |
"zrender": "6.0.0"
|
|
|
|
| 3568 |
"version": "4.0.3",
|
| 3569 |
"inBundle": true,
|
| 3570 |
"license": "MIT",
|
| 3571 |
+
"peer": true,
|
| 3572 |
"engines": {
|
| 3573 |
"node": ">=12"
|
| 3574 |
},
|
|
|
|
| 3927 |
"integrity": "sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g==",
|
| 3928 |
"dev": true,
|
| 3929 |
"license": "MIT",
|
| 3930 |
+
"peer": true,
|
| 3931 |
"dependencies": {
|
| 3932 |
"esbuild": "^0.21.3",
|
| 3933 |
"postcss": "^8.4.43",
|
|
|
|
| 3987 |
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.22.tgz",
|
| 3988 |
"integrity": "sha512-toaZjQ3a/G/mYaLSbV+QsQhIdMo9x5rrqIpYRObsJ6T/J+RyCSFwN2LHNVH9v8uIcljDNa3QzPVdv3Y6b9hAJQ==",
|
| 3989 |
"license": "MIT",
|
| 3990 |
+
"peer": true,
|
| 3991 |
"dependencies": {
|
| 3992 |
"@vue/compiler-dom": "3.5.22",
|
| 3993 |
"@vue/compiler-sfc": "3.5.22",
|
src/lib/dataService.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
import { supabase } from './supabase.js'
|
| 2 |
import { getAllDecisions, setAllDecisions, clearAllDecisions } from './dataCache.js'
|
| 3 |
-
import { writeRawDecisions, clearAllStores, readAllRawDecisions } from './idb.js'
|
| 4 |
import { filterRowsToNyseTradingDays, countNonTradingDaysBetweenForAsset, countTradingDaysBetweenForAsset } from './marketCalendar.js'
|
| 5 |
import { computeBuyHoldEquity, computeStrategyEquity, calculateMetricsFromSeries, computeWinRate } from './perf.js'
|
| 6 |
import { STRATEGIES } from './strategies.js'
|
|
@@ -435,30 +435,50 @@ class DataService {
|
|
| 435 |
}
|
| 436 |
}
|
| 437 |
|
| 438 |
-
// 检查缓存数据是否是最新的:从 Supabase
|
| 439 |
if (all && all.length > 0) {
|
| 440 |
try {
|
| 441 |
-
//
|
| 442 |
-
const
|
| 443 |
-
const cachedMaxDate = cachedDates.length > 0 ? cachedDates[cachedDates.length - 1] : null
|
| 444 |
|
| 445 |
-
// 从 Supabase
|
| 446 |
const { data: latestData, error } = await supabase
|
| 447 |
.from('trading_decisions')
|
| 448 |
-
.select('
|
| 449 |
-
.order('
|
| 450 |
.limit(1)
|
| 451 |
|
| 452 |
if (!error && latestData && latestData.length > 0) {
|
| 453 |
-
const
|
| 454 |
-
const cachedMaxDateStr = cachedMaxDate ? (typeof cachedMaxDate === 'string' ? cachedMaxDate.split('T')[0] : cachedMaxDate) : null
|
| 455 |
-
const dbMaxDateStr = typeof dbMaxDate === 'string' ? dbMaxDate.split('T')[0] : dbMaxDate
|
| 456 |
|
| 457 |
-
console.log(`[DataService] Cache check: cached max
|
| 458 |
|
| 459 |
-
//
|
| 460 |
-
|
| 461 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 462 |
await clearAllStores()
|
| 463 |
clearAllDecisions()
|
| 464 |
all = await this._fetchAllFromRemote()
|
|
|
|
| 1 |
import { supabase } from './supabase.js'
|
| 2 |
import { getAllDecisions, setAllDecisions, clearAllDecisions } from './dataCache.js'
|
| 3 |
+
import { writeRawDecisions, clearAllStores, readAllRawDecisions, readRawUpdatedAtMax } from './idb.js'
|
| 4 |
import { filterRowsToNyseTradingDays, countNonTradingDaysBetweenForAsset, countTradingDaysBetweenForAsset } from './marketCalendar.js'
|
| 5 |
import { computeBuyHoldEquity, computeStrategyEquity, calculateMetricsFromSeries, computeWinRate } from './perf.js'
|
| 6 |
import { STRATEGIES } from './strategies.js'
|
|
|
|
| 435 |
}
|
| 436 |
}
|
| 437 |
|
| 438 |
+
// 检查缓存数据是否是最新的:从 Supabase 查询最新的 updated_at,如果缓存中的 updated_at 比数据库旧,则强制刷新
|
| 439 |
if (all && all.length > 0) {
|
| 440 |
try {
|
| 441 |
+
// 获取缓存中的最大 updated_at(从 IndexedDB 读取)
|
| 442 |
+
const cachedMaxUpdatedAt = await readRawUpdatedAtMax()
|
|
|
|
| 443 |
|
| 444 |
+
// 从 Supabase 查询最新的 updated_at(只查询 updated_at,不查询所有数据)
|
| 445 |
const { data: latestData, error } = await supabase
|
| 446 |
.from('trading_decisions')
|
| 447 |
+
.select('updated_at')
|
| 448 |
+
.order('updated_at', { ascending: false })
|
| 449 |
.limit(1)
|
| 450 |
|
| 451 |
if (!error && latestData && latestData.length > 0) {
|
| 452 |
+
const dbMaxUpdatedAt = latestData[0].updated_at
|
|
|
|
|
|
|
| 453 |
|
| 454 |
+
console.log(`[DataService] Cache check: cached max updated_at = ${cachedMaxUpdatedAt}, DB max updated_at = ${dbMaxUpdatedAt}`)
|
| 455 |
|
| 456 |
+
// 使用 Date 对象比较时间,避免时区问题
|
| 457 |
+
// 将时间字符串转换为 Date 对象进行比较,确保跨时区正确
|
| 458 |
+
if (cachedMaxUpdatedAt && dbMaxUpdatedAt) {
|
| 459 |
+
const cachedDate = new Date(cachedMaxUpdatedAt)
|
| 460 |
+
const dbDate = new Date(dbMaxUpdatedAt)
|
| 461 |
+
|
| 462 |
+
// 检查日期是否有效
|
| 463 |
+
if (isNaN(cachedDate.getTime()) || isNaN(dbDate.getTime())) {
|
| 464 |
+
console.warn(`[DataService] Invalid date format detected, forcing refresh`)
|
| 465 |
+
await clearAllStores()
|
| 466 |
+
clearAllDecisions()
|
| 467 |
+
all = await this._fetchAllFromRemote()
|
| 468 |
+
setAllDecisions(all)
|
| 469 |
+
await writeRawDecisions(all)
|
| 470 |
+
} else if (dbDate > cachedDate) {
|
| 471 |
+
// 数据库中的时间更新,强制刷新
|
| 472 |
+
console.log(`[DataService] Cache is stale (${cachedMaxUpdatedAt} < ${dbMaxUpdatedAt}), fetching fresh data...`)
|
| 473 |
+
await clearAllStores()
|
| 474 |
+
clearAllDecisions()
|
| 475 |
+
all = await this._fetchAllFromRemote()
|
| 476 |
+
setAllDecisions(all)
|
| 477 |
+
await writeRawDecisions(all)
|
| 478 |
+
}
|
| 479 |
+
} else if (!cachedMaxUpdatedAt) {
|
| 480 |
+
// 如果缓存中没有 updated_at,也强制刷新
|
| 481 |
+
console.log(`[DataService] Cache missing updated_at, fetching fresh data...`)
|
| 482 |
await clearAllStores()
|
| 483 |
clearAllDecisions()
|
| 484 |
all = await this._fetchAllFromRemote()
|