feat: upgrade multi-flow account contributions
This commit is contained in:
@@ -1,9 +1,31 @@
|
||||
(() => {
|
||||
const PORTAL_BASE_URL = 'https://flowpilot.qlhazycoder.top';
|
||||
const CONTENT_SUMMARY_API_URL = `${PORTAL_BASE_URL}/api/content-summary`;
|
||||
const CACHE_KEY = 'multipage-contribution-content-summary-v1';
|
||||
const CACHE_KEY_PREFIX = 'multipage-contribution-content-summary-v2';
|
||||
const FETCH_TIMEOUT_MS = 6000;
|
||||
|
||||
function normalizeScopeId(value = '', fallback = '') {
|
||||
return String(value || '').trim().toLowerCase().replace(/[^a-z0-9_-]+/g, '-') || fallback;
|
||||
}
|
||||
|
||||
function normalizeScope(options = {}) {
|
||||
const flowId = normalizeScopeId(options.flowId || options.flow || options.activeFlowId, 'openai');
|
||||
const targetFallback = flowId === 'kiro' ? 'kiro-rs' : 'cpa';
|
||||
const targetId = normalizeScopeId(options.targetId || options.target || options.activeTargetId, targetFallback);
|
||||
return { flowId, targetId };
|
||||
}
|
||||
|
||||
function getCacheKey(scope = normalizeScope()) {
|
||||
return `${CACHE_KEY_PREFIX}:${scope.flowId}:${scope.targetId}`;
|
||||
}
|
||||
|
||||
function buildSummaryApiUrl(scope = normalizeScope()) {
|
||||
const url = new URL(CONTENT_SUMMARY_API_URL);
|
||||
url.searchParams.set('flow', scope.flowId);
|
||||
url.searchParams.set('target', scope.targetId);
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
function sanitizeItem(item = {}) {
|
||||
return {
|
||||
slug: String(item?.slug || '').trim(),
|
||||
@@ -14,13 +36,20 @@
|
||||
isVisible: Boolean(item?.is_visible ?? item?.isVisible),
|
||||
updatedAt: String(item?.updated_at ?? item?.updatedAt ?? '').trim(),
|
||||
updatedAtDisplay: String(item?.updated_at_display ?? item?.updatedAtDisplay ?? '').trim(),
|
||||
flowId: normalizeScopeId(item?.flow_id ?? item?.flowId, ''),
|
||||
targetId: normalizeScopeId(item?.target_id ?? item?.targetId, ''),
|
||||
scope: String(item?.scope || '').trim(),
|
||||
};
|
||||
}
|
||||
|
||||
function buildSnapshot(payload = {}) {
|
||||
function buildSnapshot(payload = {}, scope = normalizeScope()) {
|
||||
const items = Array.isArray(payload?.items)
|
||||
? payload.items.map(sanitizeItem).filter((item) => item.slug)
|
||||
: [];
|
||||
const responseScope = normalizeScope({
|
||||
flowId: payload?.flow_id || payload?.flowId || scope.flowId,
|
||||
targetId: payload?.target_id || payload?.targetId || scope.targetId,
|
||||
});
|
||||
const promptVersion = String(payload?.prompt_version || '').trim();
|
||||
const latestUpdatedAt = String(payload?.latest_updated_at || '').trim();
|
||||
const latestUpdatedAtDisplay = String(payload?.latest_updated_at_display || '').trim();
|
||||
@@ -33,15 +62,17 @@
|
||||
latestUpdatedAt,
|
||||
latestUpdatedAtDisplay,
|
||||
items,
|
||||
flowId: responseScope.flowId,
|
||||
targetId: responseScope.targetId,
|
||||
portalUrl: PORTAL_BASE_URL,
|
||||
apiUrl: CONTENT_SUMMARY_API_URL,
|
||||
apiUrl: buildSummaryApiUrl(responseScope),
|
||||
checkedAt: Date.now(),
|
||||
};
|
||||
}
|
||||
|
||||
function readCache() {
|
||||
function readCache(scope = normalizeScope()) {
|
||||
try {
|
||||
const raw = localStorage.getItem(CACHE_KEY);
|
||||
const raw = localStorage.getItem(getCacheKey(scope));
|
||||
if (!raw) {
|
||||
return null;
|
||||
}
|
||||
@@ -57,7 +88,9 @@
|
||||
has_visible_updates: parsed.hasVisibleUpdates,
|
||||
latest_updated_at: parsed.latestUpdatedAt,
|
||||
latest_updated_at_display: parsed.latestUpdatedAtDisplay,
|
||||
});
|
||||
flow_id: parsed.flowId,
|
||||
target_id: parsed.targetId,
|
||||
}, scope);
|
||||
if (!Number.isFinite(parsed.checkedAt)) {
|
||||
return snapshot;
|
||||
}
|
||||
@@ -68,20 +101,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
function writeCache(snapshot) {
|
||||
function writeCache(snapshot, scope = normalizeScope(snapshot)) {
|
||||
try {
|
||||
localStorage.setItem(CACHE_KEY, JSON.stringify(snapshot));
|
||||
localStorage.setItem(getCacheKey(scope), JSON.stringify(snapshot));
|
||||
} catch (error) {
|
||||
// Ignore cache write failures.
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchContentSummary() {
|
||||
async function fetchContentSummary(options = {}) {
|
||||
const scope = normalizeScope(options);
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
||||
|
||||
try {
|
||||
const response = await fetch(CONTENT_SUMMARY_API_URL, {
|
||||
const response = await fetch(buildSummaryApiUrl(scope), {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
@@ -99,8 +133,8 @@
|
||||
throw new Error('内容摘要返回格式异常');
|
||||
}
|
||||
|
||||
const snapshot = buildSnapshot(payload);
|
||||
writeCache(snapshot);
|
||||
const snapshot = buildSnapshot(payload, scope);
|
||||
writeCache(snapshot, scope);
|
||||
return snapshot;
|
||||
} catch (error) {
|
||||
if (error?.name === 'AbortError') {
|
||||
@@ -112,11 +146,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function getContentUpdateSnapshot() {
|
||||
async function getContentUpdateSnapshot(options = {}) {
|
||||
const scope = normalizeScope(options);
|
||||
try {
|
||||
return await fetchContentSummary();
|
||||
return await fetchContentSummary(scope);
|
||||
} catch (error) {
|
||||
const cached = readCache();
|
||||
const cached = readCache(scope);
|
||||
if (cached) {
|
||||
return {
|
||||
...cached,
|
||||
@@ -132,8 +167,10 @@
|
||||
latestUpdatedAt: '',
|
||||
latestUpdatedAtDisplay: '',
|
||||
items: [],
|
||||
flowId: scope.flowId,
|
||||
targetId: scope.targetId,
|
||||
portalUrl: PORTAL_BASE_URL,
|
||||
apiUrl: CONTENT_SUMMARY_API_URL,
|
||||
apiUrl: buildSummaryApiUrl(scope),
|
||||
checkedAt: Date.now(),
|
||||
errorMessage: error?.message || '内容摘要获取失败',
|
||||
};
|
||||
@@ -141,6 +178,7 @@
|
||||
}
|
||||
|
||||
window.SidepanelContributionContentService = {
|
||||
buildSummaryApiUrl,
|
||||
getContentUpdateSnapshot,
|
||||
portalUrl: PORTAL_BASE_URL,
|
||||
apiUrl: CONTENT_SUMMARY_API_URL,
|
||||
|
||||
Reference in New Issue
Block a user