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,
|
||||
|
||||
+138
-42
@@ -81,6 +81,14 @@
|
||||
}
|
||||
|
||||
function getContributionSourceLabel(currentState = getLatestState()) {
|
||||
if (getActiveFlowId(currentState) !== 'openai') {
|
||||
const rootScope = typeof window !== 'undefined' ? window : globalThis;
|
||||
const registry = rootScope.MultiPageContributionRegistry || {};
|
||||
const adapter = typeof registry.getAdapterDefinition === 'function'
|
||||
? registry.getAdapterDefinition(currentState.contributionAdapterId || '', { flowId: getActiveFlowId(currentState) })
|
||||
: null;
|
||||
return normalizeString(adapter?.label) || '账号贡献';
|
||||
}
|
||||
return getContributionSource(currentState) === CONTRIBUTION_SOURCE_SUB2API ? 'SUB2API' : 'CPA';
|
||||
}
|
||||
|
||||
@@ -88,12 +96,54 @@
|
||||
return normalizeString(currentState.activeFlowId || currentState.flowId).toLowerCase() || 'openai';
|
||||
}
|
||||
|
||||
function getActiveTargetId(currentState = getLatestState()) {
|
||||
const activeFlowId = getActiveFlowId(currentState);
|
||||
if (activeFlowId === 'kiro') {
|
||||
return normalizeString(currentState.kiroTargetId || currentState.targetId || 'kiro-rs').toLowerCase() || 'kiro-rs';
|
||||
}
|
||||
return normalizeString(currentState.openaiIntegrationTargetId || currentState.panelMode || currentState.targetId || 'cpa').toLowerCase() || 'cpa';
|
||||
}
|
||||
|
||||
function getContributionTutorialEntry(currentState = getLatestState()) {
|
||||
const rootScope = typeof window !== 'undefined' ? window : globalThis;
|
||||
const registry = rootScope.MultiPageContributionRegistry || {};
|
||||
const activeFlowId = getActiveFlowId(currentState);
|
||||
if (typeof registry.getContributionTutorialEntry === 'function') {
|
||||
return registry.getContributionTutorialEntry(activeFlowId, {
|
||||
adapterId: currentState.contributionAdapterId,
|
||||
portalBaseUrl: contributionPortalUrl,
|
||||
targetId: getActiveTargetId(currentState),
|
||||
});
|
||||
}
|
||||
return {
|
||||
flowId: activeFlowId,
|
||||
targetId: getActiveTargetId(currentState),
|
||||
contributionAdapterId: normalizeString(currentState.contributionAdapterId),
|
||||
portalUrl: normalizeString(contributionPortalUrl),
|
||||
};
|
||||
}
|
||||
|
||||
function getContributionEntryAdapterId(currentState = getLatestState()) {
|
||||
return normalizeString(getContributionTutorialEntry(currentState)?.contributionAdapterId);
|
||||
}
|
||||
|
||||
function isContributionModeAvailable(currentState = getLatestState()) {
|
||||
return getActiveFlowId(currentState) === 'openai';
|
||||
const rootScope = typeof window !== 'undefined' ? window : globalThis;
|
||||
const registry = rootScope.MultiPageFlowCapabilities?.createFlowCapabilityRegistry?.({
|
||||
defaultFlowId: 'openai',
|
||||
}) || null;
|
||||
if (registry?.resolveSidepanelCapabilities) {
|
||||
return Boolean(registry.resolveSidepanelCapabilities({
|
||||
activeFlowId: getActiveFlowId(currentState),
|
||||
panelMode: currentState?.panelMode,
|
||||
state: currentState,
|
||||
})?.canShowContributionMode);
|
||||
}
|
||||
return Boolean(currentState?.supportsAccountContribution || getActiveFlowId(currentState) === 'openai');
|
||||
}
|
||||
|
||||
function isContributionModeEnabled(currentState = getLatestState()) {
|
||||
return isContributionModeAvailable(currentState) && Boolean(currentState.contributionMode);
|
||||
return isContributionModeAvailable(currentState) && Boolean(currentState.accountContributionEnabled);
|
||||
}
|
||||
|
||||
function hasActiveContributionSession(currentState = getLatestState()) {
|
||||
@@ -127,10 +177,10 @@
|
||||
dom.btnContributionMode.title = '当前 flow 不支持贡献模式';
|
||||
return;
|
||||
}
|
||||
dom.btnContributionMode.disabled = enabled || blocked;
|
||||
dom.btnContributionMode.title = blocked
|
||||
? '当前流程运行中,暂时不能切换贡献模式'
|
||||
: (enabled ? '当前已在贡献模式' : '进入贡献模式');
|
||||
dom.btnContributionMode.disabled = actionInFlight;
|
||||
dom.btnContributionMode.title = enabled
|
||||
? '打开当前 flow 教程;当前已在贡献模式'
|
||||
: (blocked ? '打开当前 flow 教程;当前流程运行中暂时不能进入贡献模式' : '打开当前 flow 教程并进入贡献模式');
|
||||
}
|
||||
|
||||
function stopPolling() {
|
||||
@@ -163,6 +213,23 @@
|
||||
}
|
||||
|
||||
function getOauthStatusText(currentState = getLatestState()) {
|
||||
if (getActiveFlowId(currentState) !== 'openai') {
|
||||
const flowRuntime = getCurrentFlowContributionRuntime(currentState);
|
||||
const status = normalizeString(flowRuntime.status).toLowerCase();
|
||||
if (status === 'submitting') {
|
||||
return '正在提交账号产物';
|
||||
}
|
||||
if (status === 'submitted') {
|
||||
return '账号产物已提交';
|
||||
}
|
||||
if (status === 'skipped') {
|
||||
return '账号产物未就绪';
|
||||
}
|
||||
if (status === 'error') {
|
||||
return '账号产物提交失败';
|
||||
}
|
||||
return isContributionModeEnabled(currentState) ? '等待账号产物' : '未开启贡献模式';
|
||||
}
|
||||
const status = normalizeStatus(currentState.contributionStatus);
|
||||
const hasAuthUrl = Boolean(normalizeString(currentState.contributionAuthUrl));
|
||||
if (!normalizeString(currentState.contributionSessionId) || !hasAuthUrl) {
|
||||
@@ -184,6 +251,10 @@
|
||||
}
|
||||
|
||||
function getCallbackStatusText(currentState = getLatestState()) {
|
||||
if (getActiveFlowId(currentState) !== 'openai') {
|
||||
const flowRuntime = getCurrentFlowContributionRuntime(currentState);
|
||||
return normalizeString(flowRuntime.lastMessage || flowRuntime.error) || '账号产物就绪后会自动提交';
|
||||
}
|
||||
const status = normalizeCallbackStatus(currentState.contributionCallbackStatus);
|
||||
switch (status) {
|
||||
case 'captured':
|
||||
@@ -208,6 +279,9 @@
|
||||
if (statusMessage) {
|
||||
return statusMessage;
|
||||
}
|
||||
if (getActiveFlowId(currentState) !== 'openai') {
|
||||
return '当前账号将用于支持项目维护。扩展会按当前 flow 的贡献适配器收集并提交账号产物,提交过程不会依赖 OpenAI OAuth 配置。';
|
||||
}
|
||||
if (getContributionSource(currentState) === CONTRIBUTION_SOURCE_SUB2API) {
|
||||
const groupName = normalizeString(currentState.contributionTargetGroupName) || CONTRIBUTION_SUB2API_DEFAULT_GROUP_NAME;
|
||||
return `当前账号将用于支持项目维护。贡献会通过 SUB2API 完成,并固定写入 ${groupName} 分组;如检测到回调地址,扩展会自动提交并等待服务端确认。`;
|
||||
@@ -215,11 +289,24 @@
|
||||
return DEFAULT_COPY;
|
||||
}
|
||||
|
||||
function getCurrentFlowContributionRuntime(currentState = getLatestState()) {
|
||||
const runtime = currentState?.flowContributionRuntime;
|
||||
if (!runtime || typeof runtime !== 'object') {
|
||||
return {};
|
||||
}
|
||||
const flowRuntime = runtime[getActiveFlowId(currentState)];
|
||||
return flowRuntime && typeof flowRuntime === 'object' ? flowRuntime : {};
|
||||
}
|
||||
|
||||
function getContributionPortalPageUrl() {
|
||||
return normalizeString(contributionPortalUrl);
|
||||
return normalizeString(getContributionTutorialEntry()?.portalUrl || contributionPortalUrl);
|
||||
}
|
||||
|
||||
function getContributionUploadPageUrl() {
|
||||
const currentState = getLatestState();
|
||||
if (getActiveFlowId(currentState) !== 'openai') {
|
||||
return normalizeString(getContributionTutorialEntry(currentState)?.portalUrl || contributionPortalUrl);
|
||||
}
|
||||
return normalizeString(contributionUploadUrl);
|
||||
}
|
||||
|
||||
@@ -240,28 +327,27 @@
|
||||
}
|
||||
|
||||
async function syncContributionProfile(partial = {}) {
|
||||
const payload = {
|
||||
nickname: normalizeString(partial.nickname),
|
||||
qq: normalizeString(partial.qq),
|
||||
};
|
||||
const response = await runtime.sendMessage({
|
||||
type: 'SET_CONTRIBUTION_PROFILE',
|
||||
source: 'sidepanel',
|
||||
payload,
|
||||
const nickname = normalizeString(partial.nickname);
|
||||
const qq = normalizeString(partial.qq);
|
||||
if (qq && !/^\d{1,20}$/.test(qq)) {
|
||||
throw new Error('QQ 只能填写数字,且长度不能超过 20 位。');
|
||||
}
|
||||
helpers.applySettingsState?.({
|
||||
...getLatestState(),
|
||||
contributionNickname: nickname,
|
||||
contributionQq: qq,
|
||||
});
|
||||
if (response?.error) {
|
||||
throw new Error(response.error);
|
||||
}
|
||||
if (response?.state) {
|
||||
helpers.applySettingsState?.(response.state);
|
||||
}
|
||||
}
|
||||
|
||||
async function requestContributionMode(enabled) {
|
||||
const response = await runtime.sendMessage({
|
||||
type: 'SET_CONTRIBUTION_MODE',
|
||||
type: 'SET_ACCOUNT_CONTRIBUTION_MODE',
|
||||
source: 'sidepanel',
|
||||
payload: { enabled: Boolean(enabled) },
|
||||
payload: {
|
||||
enabled: Boolean(enabled),
|
||||
flowId: getActiveFlowId(),
|
||||
adapterId: getContributionEntryAdapterId(),
|
||||
},
|
||||
});
|
||||
|
||||
if (response?.error) {
|
||||
@@ -287,7 +373,7 @@
|
||||
pollInFlight = true;
|
||||
try {
|
||||
const response = await runtime.sendMessage({
|
||||
type: 'POLL_CONTRIBUTION_STATUS',
|
||||
type: 'POLL_FLOW_CONTRIBUTION_STATUS',
|
||||
source: 'sidepanel',
|
||||
payload: {
|
||||
reason: options.reason || 'sidepanel_poll',
|
||||
@@ -312,7 +398,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function startContributionFlow() {
|
||||
async function startAccountContributionFlow() {
|
||||
if (typeof helpers.startContributionAutoRun !== 'function') {
|
||||
throw new Error('贡献模式尚未接入主自动流程启动能力。');
|
||||
}
|
||||
@@ -323,7 +409,6 @@
|
||||
throw new Error('QQ 只能填写数字,且长度不能超过 20 位。');
|
||||
}
|
||||
await syncContributionProfile(profile);
|
||||
|
||||
const started = await helpers.startContributionAutoRun();
|
||||
if (!started) {
|
||||
return;
|
||||
@@ -348,28 +433,26 @@
|
||||
const currentState = getLatestState();
|
||||
const available = isContributionModeAvailable(currentState);
|
||||
const enabled = isContributionModeEnabled(currentState);
|
||||
const activeFlowId = getActiveFlowId(currentState);
|
||||
const blocked = available ? isModeSwitchBlocked() : false;
|
||||
const activeElement = typeof document !== 'undefined' ? document.activeElement : null;
|
||||
const sourceLabel = available ? getContributionSourceLabel(currentState) : '';
|
||||
|
||||
if (enabled && dom.selectPanelMode) {
|
||||
if (enabled && activeFlowId === 'openai' && dom.selectPanelMode) {
|
||||
dom.selectPanelMode.value = getContributionSource(currentState);
|
||||
}
|
||||
|
||||
helpers.updatePanelModeUI?.();
|
||||
helpers.updateAccountRunHistorySettingsUI?.();
|
||||
|
||||
if (dom.contributionModePanel) {
|
||||
dom.contributionModePanel.hidden = !available || !enabled;
|
||||
if (dom.accountContributionPanel) {
|
||||
dom.accountContributionPanel.hidden = !available || !enabled;
|
||||
}
|
||||
if (dom.contributionModeText) {
|
||||
dom.contributionModeText.textContent = getSummaryText({
|
||||
contributionSource: currentState.contributionSource,
|
||||
contributionTargetGroupName: currentState.contributionTargetGroupName,
|
||||
});
|
||||
if (dom.accountContributionText) {
|
||||
dom.accountContributionText.textContent = getSummaryText(currentState);
|
||||
}
|
||||
if (dom.contributionModeBadge) {
|
||||
dom.contributionModeBadge.textContent = enabled ? sourceLabel : '';
|
||||
if (dom.accountContributionBadge) {
|
||||
dom.accountContributionBadge.textContent = enabled ? sourceLabel : '';
|
||||
}
|
||||
if (dom.inputContributionNickname && activeElement !== dom.inputContributionNickname) {
|
||||
const nextNickname = normalizeString(currentState.contributionNickname);
|
||||
@@ -386,18 +469,24 @@
|
||||
if (dom.contributionOauthStatus) {
|
||||
dom.contributionOauthStatus.textContent = getOauthStatusText(currentState);
|
||||
}
|
||||
if (dom.contributionPrimaryStatusLabel) {
|
||||
dom.contributionPrimaryStatusLabel.textContent = activeFlowId === 'openai' ? 'OAUTH' : '账号产物';
|
||||
}
|
||||
if (dom.contributionCallbackStatus) {
|
||||
dom.contributionCallbackStatus.textContent = getCallbackStatusText(currentState);
|
||||
}
|
||||
if (dom.contributionModeSummary) {
|
||||
dom.contributionModeSummary.textContent = getSummaryText(currentState);
|
||||
if (dom.contributionSecondaryStatusLabel) {
|
||||
dom.contributionSecondaryStatusLabel.textContent = activeFlowId === 'openai' ? '回调' : '提交';
|
||||
}
|
||||
if (dom.accountContributionSummary) {
|
||||
dom.accountContributionSummary.textContent = getSummaryText(currentState);
|
||||
}
|
||||
|
||||
syncContributionRows(enabled);
|
||||
syncContributionRows(enabled && activeFlowId === 'openai');
|
||||
syncContributionButton(enabled, blocked, available);
|
||||
|
||||
if (dom.selectPanelMode) {
|
||||
dom.selectPanelMode.disabled = available && enabled;
|
||||
dom.selectPanelMode.disabled = activeFlowId === 'openai' && available && enabled;
|
||||
}
|
||||
|
||||
if (dom.btnStartContribution) {
|
||||
@@ -406,6 +495,7 @@
|
||||
|
||||
if (dom.btnOpenContributionUpload) {
|
||||
dom.btnOpenContributionUpload.disabled = !available;
|
||||
dom.btnOpenContributionUpload.textContent = activeFlowId === 'openai' ? '已有认证文件?前往上传' : '查看当前 flow 贡献说明';
|
||||
}
|
||||
|
||||
if (dom.btnExitContributionMode) {
|
||||
@@ -441,7 +531,13 @@
|
||||
}
|
||||
render();
|
||||
try {
|
||||
await enterContributionMode();
|
||||
if (isContributionModeEnabled()) {
|
||||
helpers.showToast?.('已打开当前 flow 教程。', 'info', 1800);
|
||||
} else if (isModeSwitchBlocked()) {
|
||||
helpers.showToast?.('已打开当前 flow 教程;当前流程运行中,暂时不能进入贡献模式。', 'warning', 2200);
|
||||
} else {
|
||||
await enterContributionMode();
|
||||
}
|
||||
} catch (error) {
|
||||
helpers.showToast?.(error.message, 'error');
|
||||
} finally {
|
||||
@@ -457,7 +553,7 @@
|
||||
actionInFlight = true;
|
||||
render();
|
||||
try {
|
||||
await startContributionFlow();
|
||||
await startAccountContributionFlow();
|
||||
} catch (error) {
|
||||
helpers.showToast?.(error.message, 'error');
|
||||
} finally {
|
||||
|
||||
@@ -152,11 +152,11 @@
|
||||
</div>
|
||||
<div class="contribution-mode-status-grid">
|
||||
<div class="contribution-mode-status-card">
|
||||
<span class="contribution-mode-status-label">OAUTH</span>
|
||||
<span id="contribution-primary-status-label" class="contribution-mode-status-label">OAUTH</span>
|
||||
<span id="contribution-oauth-status" class="contribution-mode-status-value">未生成登录地址</span>
|
||||
</div>
|
||||
<div class="contribution-mode-status-card">
|
||||
<span class="contribution-mode-status-label">回调</span>
|
||||
<span id="contribution-secondary-status-label" class="contribution-mode-status-label">回调</span>
|
||||
<span id="contribution-callback-status" class="contribution-mode-status-value">等待回调</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1857,6 +1857,7 @@
|
||||
<script src="../luckmail-utils.js"></script>
|
||||
<script src="../yyds-mail-utils.js"></script>
|
||||
<script src="../shared/flow-registry.js"></script>
|
||||
<script src="../shared/contribution-registry.js"></script>
|
||||
<script src="../shared/settings-schema.js"></script>
|
||||
<script src="../shared/flow-capabilities.js"></script>
|
||||
<script src="../data/step-definitions.js"></script>
|
||||
|
||||
+87
-51
@@ -36,14 +36,16 @@ const btnIgnoreRelease = document.getElementById('btn-ignore-release');
|
||||
const btnOpenRelease = document.getElementById('btn-open-release');
|
||||
const settingsCard = document.getElementById('settings-card');
|
||||
const selectFlow = document.getElementById('select-flow');
|
||||
const contributionModePanel = document.getElementById('contribution-mode-panel');
|
||||
const contributionModeBadge = document.getElementById('contribution-mode-badge');
|
||||
const contributionModeText = document.getElementById('contribution-mode-text');
|
||||
const accountContributionPanel = document.getElementById('contribution-mode-panel');
|
||||
const accountContributionBadge = document.getElementById('contribution-mode-badge');
|
||||
const accountContributionText = document.getElementById('contribution-mode-text');
|
||||
const inputContributionNickname = document.getElementById('input-contribution-nickname');
|
||||
const inputContributionQq = document.getElementById('input-contribution-qq');
|
||||
const contributionPrimaryStatusLabel = document.getElementById('contribution-primary-status-label');
|
||||
const contributionSecondaryStatusLabel = document.getElementById('contribution-secondary-status-label');
|
||||
const contributionOauthStatus = document.getElementById('contribution-oauth-status');
|
||||
const contributionCallbackStatus = document.getElementById('contribution-callback-status');
|
||||
const contributionModeSummary = document.getElementById('contribution-mode-summary');
|
||||
const accountContributionSummary = document.getElementById('contribution-mode-summary');
|
||||
const btnStartContribution = document.getElementById('btn-start-contribution');
|
||||
const btnOpenContributionUpload = document.getElementById('btn-open-contribution-upload');
|
||||
const btnExitContributionMode = document.getElementById('btn-exit-contribution-mode');
|
||||
@@ -2074,7 +2076,7 @@ function shouldPromptNewUserGuide() {
|
||||
}
|
||||
if (typeof isContributionModeActiveForFlow === 'function'
|
||||
? isContributionModeActiveForFlow(latestState)
|
||||
: Boolean(latestState?.contributionMode)) {
|
||||
: Boolean(latestState?.accountContributionEnabled)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -2084,6 +2086,18 @@ function getContributionPortalUrl() {
|
||||
return String(contributionContentService?.portalUrl || 'https://flowpilot.qlhazycoder.top').trim();
|
||||
}
|
||||
|
||||
function getContributionContentFlowId(state = latestState) {
|
||||
return String(state?.activeFlowId || state?.flowId || DEFAULT_ACTIVE_FLOW_ID).trim().toLowerCase() || DEFAULT_ACTIVE_FLOW_ID;
|
||||
}
|
||||
|
||||
function getContributionContentTargetId(state = latestState) {
|
||||
const flowId = getContributionContentFlowId(state);
|
||||
if (flowId === 'kiro') {
|
||||
return String(state?.kiroTargetId || state?.targetId || 'kiro-rs').trim().toLowerCase() || 'kiro-rs';
|
||||
}
|
||||
return String(state?.openaiIntegrationTargetId || state?.panelMode || state?.targetId || 'cpa').trim().toLowerCase() || 'cpa';
|
||||
}
|
||||
|
||||
function openNewUserGuidePrompt() {
|
||||
return openActionModal({
|
||||
title: '新手引导',
|
||||
@@ -2112,16 +2126,29 @@ async function maybeShowNewUserGuidePrompt() {
|
||||
return false;
|
||||
}
|
||||
|
||||
function getDismissedContributionContentPromptVersion() {
|
||||
return String(localStorage.getItem(CONTRIBUTION_CONTENT_PROMPT_DISMISSED_VERSION_STORAGE_KEY) || '').trim();
|
||||
function getContributionContentPromptScope(snapshot = currentContributionContentSnapshot) {
|
||||
return {
|
||||
flowId: String(snapshot?.flowId || getContributionContentFlowId()).trim().toLowerCase() || DEFAULT_ACTIVE_FLOW_ID,
|
||||
targetId: String(snapshot?.targetId || getContributionContentTargetId()).trim().toLowerCase() || 'cpa',
|
||||
};
|
||||
}
|
||||
|
||||
function setDismissedContributionContentPromptVersion(version) {
|
||||
function getContributionContentPromptDismissedStorageKey(snapshot = currentContributionContentSnapshot) {
|
||||
const scope = getContributionContentPromptScope(snapshot);
|
||||
return `${CONTRIBUTION_CONTENT_PROMPT_DISMISSED_VERSION_STORAGE_KEY}:${scope.flowId}:${scope.targetId}`;
|
||||
}
|
||||
|
||||
function getDismissedContributionContentPromptVersion(snapshot = currentContributionContentSnapshot) {
|
||||
return String(localStorage.getItem(getContributionContentPromptDismissedStorageKey(snapshot)) || '').trim();
|
||||
}
|
||||
|
||||
function setDismissedContributionContentPromptVersion(version, snapshot = currentContributionContentSnapshot) {
|
||||
const normalized = String(version || '').trim();
|
||||
const storageKey = getContributionContentPromptDismissedStorageKey(snapshot);
|
||||
if (normalized) {
|
||||
localStorage.setItem(CONTRIBUTION_CONTENT_PROMPT_DISMISSED_VERSION_STORAGE_KEY, normalized);
|
||||
localStorage.setItem(storageKey, normalized);
|
||||
} else {
|
||||
localStorage.removeItem(CONTRIBUTION_CONTENT_PROMPT_DISMISSED_VERSION_STORAGE_KEY);
|
||||
localStorage.removeItem(storageKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2301,25 +2328,25 @@ async function openAutoRunFallbackRiskConfirmModal(totalRuns) {
|
||||
|
||||
function updateConfigMenuControls() {
|
||||
const disabled = configActionInFlight || settingsSaveInFlight;
|
||||
const contributionModeEnabled = typeof isContributionModeActiveForFlow === 'function'
|
||||
const accountContributionEnabled = typeof isContributionModeActiveForFlow === 'function'
|
||||
? isContributionModeActiveForFlow(latestState)
|
||||
: Boolean(latestState?.contributionMode);
|
||||
if (contributionModeEnabled && configMenuOpen) {
|
||||
: Boolean(latestState?.accountContributionEnabled);
|
||||
if (accountContributionEnabled && configMenuOpen) {
|
||||
configMenuOpen = false;
|
||||
}
|
||||
const importLocked = disabled
|
||||
|| contributionModeEnabled
|
||||
|| accountContributionEnabled
|
||||
|| currentAutoRun.autoRunning
|
||||
|| Object.values(getStepStatuses()).some((status) => status === 'running');
|
||||
if (btnConfigMenu) {
|
||||
btnConfigMenu.disabled = disabled || contributionModeEnabled;
|
||||
btnConfigMenu.disabled = disabled || accountContributionEnabled;
|
||||
btnConfigMenu.setAttribute('aria-expanded', String(configMenuOpen));
|
||||
}
|
||||
if (configMenu) {
|
||||
configMenu.hidden = contributionModeEnabled || !configMenuOpen;
|
||||
configMenu.hidden = accountContributionEnabled || !configMenuOpen;
|
||||
}
|
||||
if (btnExportSettings) {
|
||||
btnExportSettings.disabled = disabled || contributionModeEnabled;
|
||||
btnExportSettings.disabled = disabled || accountContributionEnabled;
|
||||
}
|
||||
if (btnImportSettings) {
|
||||
btnImportSettings.disabled = importLocked;
|
||||
@@ -2776,7 +2803,10 @@ function isContributionModeActiveForFlow(state = latestState, flowId = undefined
|
||||
const normalizedFlowId = typeof normalizeFlowId === 'function'
|
||||
? normalizeFlowId(rawFlowId, DEFAULT_ACTIVE_FLOW_ID)
|
||||
: (String(rawFlowId || DEFAULT_ACTIVE_FLOW_ID).trim().toLowerCase() || DEFAULT_ACTIVE_FLOW_ID);
|
||||
return normalizedFlowId === DEFAULT_ACTIVE_FLOW_ID && Boolean(state?.contributionMode);
|
||||
const stateFlowId = typeof normalizeFlowId === 'function'
|
||||
? normalizeFlowId(state?.activeFlowId || state?.flowId || DEFAULT_ACTIVE_FLOW_ID, DEFAULT_ACTIVE_FLOW_ID)
|
||||
: (String(state?.activeFlowId || state?.flowId || DEFAULT_ACTIVE_FLOW_ID).trim().toLowerCase() || DEFAULT_ACTIVE_FLOW_ID);
|
||||
return normalizedFlowId === stateFlowId && Boolean(state?.accountContributionEnabled);
|
||||
}
|
||||
|
||||
let accountRunHistoryRefreshTimer = null;
|
||||
@@ -3775,9 +3805,9 @@ function collectSettingsPayload() {
|
||||
}
|
||||
return normalized || defaultFlowId;
|
||||
})();
|
||||
const contributionModeEnabled = typeof isContributionModeActiveForFlow === 'function'
|
||||
const accountContributionEnabled = typeof isContributionModeActiveForFlow === 'function'
|
||||
? isContributionModeActiveForFlow(latestState, activeFlowId)
|
||||
: (activeFlowId === defaultFlowId && Boolean(latestState?.contributionMode));
|
||||
: (activeFlowId === defaultFlowId && Boolean(latestState?.accountContributionEnabled));
|
||||
const icloudFetchModeRawValue = typeof selectIcloudFetchMode !== 'undefined'
|
||||
? String(selectIcloudFetchMode?.value || '')
|
||||
: '';
|
||||
@@ -4419,7 +4449,7 @@ function collectSettingsPayload() {
|
||||
: null;
|
||||
return {
|
||||
activeFlowId,
|
||||
...(contributionModeEnabled ? {} : {
|
||||
...(accountContributionEnabled ? {} : {
|
||||
...(activeFlowId === defaultFlowId ? { panelMode: effectivePanelMode } : {}),
|
||||
}),
|
||||
kiroTargetId: normalizeKiroTargetIdSafe(
|
||||
@@ -4528,7 +4558,7 @@ function collectSettingsPayload() {
|
||||
? inputGpcHelperLocalSmsUrl.value
|
||||
: (latestState?.gopayHelperLocalSmsHelperUrl || '')
|
||||
),
|
||||
...(contributionModeEnabled ? {} : {
|
||||
...(accountContributionEnabled ? {} : {
|
||||
customPassword: inputPassword.value,
|
||||
}),
|
||||
mailProvider: selectMailProvider.value,
|
||||
@@ -4548,7 +4578,7 @@ function collectSettingsPayload() {
|
||||
icloudFetchMode: (icloudFetchModeRawValue.trim().toLowerCase() === 'always_new'
|
||||
? 'always_new'
|
||||
: 'reuse_existing'),
|
||||
...(contributionModeEnabled ? {} : {
|
||||
...(accountContributionEnabled ? {} : {
|
||||
accountRunHistoryTextEnabled: true,
|
||||
accountRunHistoryHelperBaseUrl: normalizeAccountRunHistoryHelperBaseUrlValue(inputAccountRunHistoryHelperBaseUrl?.value),
|
||||
}),
|
||||
@@ -8695,9 +8725,9 @@ function canSelectPhoneSignupMethod() {
|
||||
const plusModeEnabled = typeof inputPlusModeEnabled !== 'undefined' && inputPlusModeEnabled
|
||||
? Boolean(inputPlusModeEnabled.checked)
|
||||
: Boolean(latestState?.plusModeEnabled);
|
||||
const contributionModeEnabled = typeof isContributionModeActiveForFlow === 'function'
|
||||
const accountContributionEnabled = typeof isContributionModeActiveForFlow === 'function'
|
||||
? isContributionModeActiveForFlow(latestState)
|
||||
: Boolean(latestState?.contributionMode);
|
||||
: Boolean(latestState?.accountContributionEnabled);
|
||||
const capabilityState = typeof resolveCurrentSidepanelCapabilities === 'function'
|
||||
? resolveCurrentSidepanelCapabilities({
|
||||
panelMode: typeof getSelectedPanelMode === 'function' ? getSelectedPanelMode() : latestState?.panelMode,
|
||||
@@ -8705,7 +8735,7 @@ function canSelectPhoneSignupMethod() {
|
||||
...(typeof latestState !== 'undefined' ? latestState : {}),
|
||||
phoneVerificationEnabled: phoneEnabled,
|
||||
plusModeEnabled,
|
||||
contributionMode: contributionModeEnabled,
|
||||
accountContributionEnabled,
|
||||
},
|
||||
})
|
||||
: (() => {
|
||||
@@ -8721,7 +8751,7 @@ function canSelectPhoneSignupMethod() {
|
||||
...(typeof latestState !== 'undefined' ? latestState : {}),
|
||||
phoneVerificationEnabled: phoneEnabled,
|
||||
plusModeEnabled,
|
||||
contributionMode: contributionModeEnabled,
|
||||
accountContributionEnabled,
|
||||
},
|
||||
})
|
||||
: null;
|
||||
@@ -8729,7 +8759,7 @@ function canSelectPhoneSignupMethod() {
|
||||
if (capabilityState && typeof capabilityState.canSelectPhoneSignup === 'boolean') {
|
||||
return capabilityState.canSelectPhoneSignup;
|
||||
}
|
||||
return phoneEnabled && !plusModeEnabled && !contributionModeEnabled;
|
||||
return phoneEnabled && !plusModeEnabled && !accountContributionEnabled;
|
||||
}
|
||||
|
||||
function isSignupMethodSwitchLocked() {
|
||||
@@ -8751,9 +8781,9 @@ function updateSignupMethodUI(options = {}) {
|
||||
|
||||
let selectedMethod = normalizeSignupMethod(getSelectedSignupMethod());
|
||||
const phoneSelectable = canSelectPhoneSignupMethod();
|
||||
const contributionModeEnabled = typeof isContributionModeActiveForFlow === 'function'
|
||||
const accountContributionEnabled = typeof isContributionModeActiveForFlow === 'function'
|
||||
? isContributionModeActiveForFlow(latestState)
|
||||
: Boolean(latestState?.contributionMode);
|
||||
: Boolean(latestState?.accountContributionEnabled);
|
||||
if (!phoneSelectable && selectedMethod === SIGNUP_METHOD_PHONE) {
|
||||
selectedMethod = setSignupMethod(SIGNUP_METHOD_EMAIL);
|
||||
if (options.notify && typeof showToast === 'function') {
|
||||
@@ -8773,9 +8803,9 @@ function updateSignupMethodUI(options = {}) {
|
||||
if (!Boolean(inputPhoneVerificationEnabled?.checked)) {
|
||||
button.title = '开启接码后可选择手机号注册';
|
||||
} else if (typeof inputPlusModeEnabled !== 'undefined' && inputPlusModeEnabled?.checked) {
|
||||
button.title = 'Plus 模式第一版暂不支持手机号注册';
|
||||
} else if (contributionModeEnabled) {
|
||||
button.title = '贡献模式第一版暂不支持手机号注册';
|
||||
button.title = 'Plus 模式暂不支持手机号注册';
|
||||
} else if (accountContributionEnabled) {
|
||||
button.title = '账号贡献开启时不能使用手机号注册';
|
||||
} else if (locked) {
|
||||
button.title = '自动流程运行中不能切换注册方式';
|
||||
} else {
|
||||
@@ -11392,12 +11422,12 @@ function shouldShowContributionUpdateHint(snapshot = currentContributionContentS
|
||||
if (!getContributionUpdatePromptLines(snapshot).length) {
|
||||
return false;
|
||||
}
|
||||
if (promptVersion === getDismissedContributionContentPromptVersion()) {
|
||||
if (promptVersion === getDismissedContributionContentPromptVersion(snapshot)) {
|
||||
return false;
|
||||
}
|
||||
if (typeof isContributionModeActiveForFlow === 'function'
|
||||
? isContributionModeActiveForFlow(latestState)
|
||||
: Boolean(latestState?.contributionMode)) {
|
||||
: Boolean(latestState?.accountContributionEnabled)) {
|
||||
return false;
|
||||
}
|
||||
return !btnContributionMode.disabled;
|
||||
@@ -11522,7 +11552,10 @@ async function refreshContributionContentHint() {
|
||||
return contributionContentSnapshotRequestInFlight;
|
||||
}
|
||||
|
||||
contributionContentSnapshotRequestInFlight = contributionContentService.getContentUpdateSnapshot()
|
||||
contributionContentSnapshotRequestInFlight = contributionContentService.getContentUpdateSnapshot({
|
||||
flowId: getContributionContentFlowId(),
|
||||
targetId: getContributionContentTargetId(),
|
||||
})
|
||||
.then((snapshot) => {
|
||||
currentContributionContentSnapshot = snapshot;
|
||||
renderContributionUpdateHint(snapshot);
|
||||
@@ -11543,10 +11576,10 @@ async function refreshContributionContentHint() {
|
||||
}
|
||||
|
||||
function syncPasswordField(state) {
|
||||
const contributionModeEnabled = typeof isContributionModeActiveForFlow === 'function'
|
||||
const accountContributionEnabled = typeof isContributionModeActiveForFlow === 'function'
|
||||
? isContributionModeActiveForFlow(state)
|
||||
: Boolean(state?.contributionMode);
|
||||
inputPassword.value = contributionModeEnabled ? '' : (state.customPassword || state.password || '');
|
||||
: Boolean(state?.accountContributionEnabled);
|
||||
inputPassword.value = accountContributionEnabled ? '' : (state.customPassword || state.password || '');
|
||||
}
|
||||
|
||||
function isCustomMailProvider(provider = selectMailProvider.value) {
|
||||
@@ -13518,7 +13551,7 @@ const bindAccountRecordEvents = accountRecordsManager?.bindEvents
|
||||
const closeAccountRecordsPanel = accountRecordsManager?.closePanel
|
||||
|| (() => { });
|
||||
bindAccountRecordEvents();
|
||||
const contributionModeManager = window.SidepanelContributionMode?.createContributionModeManager({
|
||||
const accountContributionManager = window.SidepanelContributionMode?.createContributionModeManager({
|
||||
state: {
|
||||
getLatestState: () => latestState,
|
||||
},
|
||||
@@ -13527,15 +13560,17 @@ const contributionModeManager = window.SidepanelContributionMode?.createContribu
|
||||
btnContributionMode,
|
||||
inputContributionNickname,
|
||||
inputContributionQq,
|
||||
contributionPrimaryStatusLabel,
|
||||
contributionSecondaryStatusLabel,
|
||||
contributionCallbackStatus,
|
||||
btnExitContributionMode,
|
||||
btnOpenAccountRecords,
|
||||
btnOpenContributionUpload,
|
||||
btnStartContribution,
|
||||
contributionModeBadge,
|
||||
contributionModePanel,
|
||||
contributionModeSummary,
|
||||
contributionModeText,
|
||||
accountContributionBadge,
|
||||
accountContributionPanel,
|
||||
accountContributionSummary,
|
||||
accountContributionText,
|
||||
contributionOauthStatus,
|
||||
rowAccountRunHistoryHelperBaseUrl,
|
||||
rowPhoneVerificationEnabled,
|
||||
@@ -13579,16 +13614,16 @@ const contributionModeManager = window.SidepanelContributionMode?.createContribu
|
||||
contributionUploadUrl: `${String(contributionContentService?.portalUrl || 'https://flowpilot.qlhazycoder.top').replace(/\/+$/, '')}/upload`,
|
||||
},
|
||||
});
|
||||
const baseRenderContributionMode = contributionModeManager?.render
|
||||
const baseRenderAccountContribution = accountContributionManager?.render
|
||||
|| (() => { });
|
||||
const renderContributionMode = () => {
|
||||
baseRenderContributionMode();
|
||||
baseRenderAccountContribution();
|
||||
renderContributionUpdateHint();
|
||||
updateSignupMethodUI({ notify: true });
|
||||
};
|
||||
const bindContributionModeEvents = contributionModeManager?.bindEvents
|
||||
const bindAccountContributionEvents = accountContributionManager?.bindEvents
|
||||
|| (() => { });
|
||||
bindContributionModeEvents();
|
||||
bindAccountContributionEvents();
|
||||
renderStepsList();
|
||||
|
||||
async function exportSettingsFile() {
|
||||
@@ -14094,7 +14129,7 @@ async function startAutoRunFromCurrentSettings() {
|
||||
plusModeEnabled: typeof inputPlusModeEnabled !== 'undefined' && inputPlusModeEnabled
|
||||
? Boolean(inputPlusModeEnabled.checked)
|
||||
: Boolean(latestState?.plusModeEnabled),
|
||||
contributionMode: Boolean(latestState?.contributionMode),
|
||||
accountContributionEnabled: Boolean(latestState?.accountContributionEnabled),
|
||||
};
|
||||
return registry.validateAutoRunStart({
|
||||
activeFlowId: validationState.activeFlowId,
|
||||
@@ -14184,7 +14219,8 @@ async function startAutoRunFromCurrentSettings() {
|
||||
activeFlowId,
|
||||
targetId,
|
||||
autoRunSkipFailures,
|
||||
contributionMode: Boolean(latestState?.contributionMode),
|
||||
accountContributionEnabled: Boolean(latestState?.accountContributionEnabled),
|
||||
contributionAdapterId: latestState?.contributionAdapterId || '',
|
||||
contributionNickname,
|
||||
contributionQq,
|
||||
mode,
|
||||
@@ -16533,7 +16569,7 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|
||||
if (
|
||||
message.payload.password !== undefined
|
||||
|| message.payload.customPassword !== undefined
|
||||
|| message.payload.contributionMode !== undefined
|
||||
|| message.payload.accountContributionEnabled !== undefined
|
||||
) {
|
||||
syncPasswordField(latestState || {});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user