feat(desktop): drop parked review flow, add publish management

SaaS 侧人工审核后才创建 publish job,desktop 不再做二次审核:移除
manual/waiting_user/parked/from_parked 状态机与 LeaseFromParked 查询,
desktop client 只执行发布并新增"发布管理"页(待发布队列 / 历史 / 再次
发送)。同时抽离 @geo/publisher-platforms 共享适配器包、新增 Redis-based
desktop_presence 与 publish_record_support,刷新 admin-web 发布弹窗与
媒体库;plan A / spec 文档同步口径。
This commit is contained in:
2026-04-20 09:52:48 +08:00
parent b16e9f0bd1
commit a617d39a4a
93 changed files with 5519 additions and 3594 deletions
@@ -27,6 +27,7 @@ interface DesktopSession {
const sessionStorageKey = "geo.desktop.session.v1";
const apiBaseURLStorageKey = "geo.desktop.api-base-url";
const clientRegistrationStoragePrefix = "geo.desktop.client-registration.v1";
const session = shallowRef<DesktopSession | null>(readStoredSession());
const apiBaseURL = shallowRef(readStoredApiBaseURL());
@@ -125,8 +126,50 @@ function createAuthenticatedClient() {
});
}
function registerPayload(): DesktopClientRegisterRequest {
function clientRegistrationStorageKey(user: UserInfo): string {
return `${clientRegistrationStoragePrefix}:${user.primary_workspace_id}:${user.id}`;
}
function readStoredClientRegistrationID(user: UserInfo): string | null {
if (typeof window === "undefined") {
return null;
}
return window.localStorage.getItem(clientRegistrationStorageKey(user));
}
function persistClientRegistrationID(user: UserInfo, clientID: string): void {
if (typeof window === "undefined") {
return;
}
window.localStorage.setItem(clientRegistrationStorageKey(user), clientID);
}
function generateUUID(): string {
if (globalThis.crypto?.randomUUID) {
return globalThis.crypto.randomUUID();
}
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (char) => {
const random = Math.floor(Math.random() * 16);
const value = char === "x" ? random : (random & 0x3) | 0x8;
return value.toString(16);
});
}
function getOrCreateClientRegistrationID(user: UserInfo): string {
const existing = readStoredClientRegistrationID(user)?.trim();
if (existing) {
return existing;
}
const generated = generateUUID();
persistClientRegistrationID(user, generated);
return generated;
}
function registerPayload(user: UserInfo): DesktopClientRegisterRequest {
return {
client_id: getOrCreateClientRegistrationID(user),
device_name: `Desktop ${navigator.platform || "unknown"}`,
os: navigator.platform || "unknown",
cpu_arch: "renderer-preview",
@@ -217,7 +260,9 @@ async function login(payload: LoginRequest): Promise<void> {
const registered = await createAuthenticatedClient().post<
DesktopClientRegisterResponse,
DesktopClientRegisterRequest
>("/api/desktop/clients/register", registerPayload());
>("/api/desktop/clients/register", registerPayload(authData.user));
persistClientRegistrationID(authData.user, registered.client.id);
persistSession({
mode: "authenticated",
@@ -250,8 +295,24 @@ function enterPreview(): void {
});
}
function logout(): void {
async function logout(): Promise<void> {
error.value = null;
const current = session.value;
if (current?.mode === "authenticated") {
try {
await window.desktopBridge?.app?.releaseRuntimeSession?.(true);
} catch (err) {
console.warn("[desktop-session] releaseRuntimeSession failed", err);
}
try {
await createAuthenticatedClient().post<null, Record<string, never>>("/api/auth/logout", {});
} catch (err) {
console.warn("[desktop-session] auth logout failed", err);
}
}
persistSession(null);
}