11
This commit is contained in:
@@ -96,13 +96,23 @@ pub async fn publish_login(
|
|||||||
params: PublishLoginParams,
|
params: PublishLoginParams,
|
||||||
) -> Result<Value, String> {
|
) -> Result<Value, String> {
|
||||||
let _ = app_config;
|
let _ = app_config;
|
||||||
|
let platform = params.platform.trim().to_string();
|
||||||
|
if platform.is_empty() {
|
||||||
|
return Err("platform 不能为空".to_string());
|
||||||
|
}
|
||||||
|
// 对齐 Electron:先创建账号槽位,再走扫码登录,保证每个账号独立 userDataDir。
|
||||||
|
let (effective_account_id, created_slot) = if let Some(id) = params.account_id {
|
||||||
|
(id, false)
|
||||||
|
} else {
|
||||||
|
(store.create_account_slot(platform.clone()).await?.id, true)
|
||||||
|
};
|
||||||
let result = run_publish_script(
|
let result = run_publish_script(
|
||||||
app,
|
app,
|
||||||
window,
|
window,
|
||||||
"publish_login.js",
|
"publish_login.js",
|
||||||
json!({
|
json!({
|
||||||
"platform": params.platform,
|
"platform": platform,
|
||||||
"accountId": params.account_id,
|
"accountId": effective_account_id,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
@@ -118,17 +128,23 @@ pub async fn publish_login(
|
|||||||
.and_then(|v| v.as_str())
|
.and_then(|v| v.as_str())
|
||||||
.unwrap_or("")
|
.unwrap_or("")
|
||||||
.to_string();
|
.to_string();
|
||||||
|
let avatar = result
|
||||||
|
.get("avatar")
|
||||||
|
.and_then(|v| v.as_str())
|
||||||
|
.unwrap_or("")
|
||||||
|
.to_string();
|
||||||
let cookies = result
|
let cookies = result
|
||||||
.get("cookies")
|
.get("cookies")
|
||||||
.map(|v| serde_json::to_string(v).unwrap_or_else(|_| "[]".to_string()))
|
.map(|v| serde_json::to_string(v).unwrap_or_else(|_| "[]".to_string()))
|
||||||
.unwrap_or_else(|| "[]".to_string());
|
.unwrap_or_else(|| "[]".to_string());
|
||||||
let rec = store
|
let rec = store
|
||||||
.upsert_login(
|
.upsert_login(
|
||||||
params.platform.clone(),
|
platform,
|
||||||
nickname,
|
nickname,
|
||||||
uid,
|
uid,
|
||||||
|
avatar,
|
||||||
cookies,
|
cookies,
|
||||||
params.account_id,
|
Some(effective_account_id),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(json!({
|
return Ok(json!({
|
||||||
@@ -138,6 +154,9 @@ pub async fn publish_login(
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if created_slot {
|
||||||
|
let _ = store.delete(effective_account_id).await;
|
||||||
|
}
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -138,6 +138,7 @@ impl PublishDb {
|
|||||||
platform: &str,
|
platform: &str,
|
||||||
nickname: &str,
|
nickname: &str,
|
||||||
uid: &str,
|
uid: &str,
|
||||||
|
avatar: &str,
|
||||||
cookies_json: &str,
|
cookies_json: &str,
|
||||||
account_id: Option<i64>,
|
account_id: Option<i64>,
|
||||||
) -> Result<PlatformAccountRecord, PublishDbError> {
|
) -> Result<PlatformAccountRecord, PublishDbError> {
|
||||||
@@ -149,9 +150,9 @@ impl PublishDb {
|
|||||||
|
|
||||||
if let Some(id) = account_id {
|
if let Some(id) = account_id {
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"UPDATE platform_accounts SET nickname = ?1, uid = ?2, cookies = ?3,
|
"UPDATE platform_accounts SET nickname = ?1, uid = ?2, avatar = ?3, cookies = ?4,
|
||||||
login_status = 'active', expires_at = ?4, updated_at = ?5 WHERE id = ?6",
|
login_status = 'active', expires_at = ?5, updated_at = ?6 WHERE id = ?7",
|
||||||
params![nickname, uid, cookies_json, expires, now, id],
|
params![nickname, uid, avatar, cookies_json, expires, now, id],
|
||||||
)?;
|
)?;
|
||||||
return self
|
return self
|
||||||
.get(id)?
|
.get(id)?
|
||||||
@@ -159,11 +160,30 @@ impl PublishDb {
|
|||||||
.ok_or_else(|| PublishDbError::Message("更新账号失败".into()));
|
.ok_or_else(|| PublishDbError::Message("更新账号失败".into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !uid.trim().is_empty() {
|
||||||
|
let mut stmt = conn.prepare(
|
||||||
|
"SELECT id FROM platform_accounts WHERE platform = ?1 AND uid = ?2 LIMIT 1",
|
||||||
|
)?;
|
||||||
|
let mut rows = stmt.query(params![platform, uid])?;
|
||||||
|
if let Some(row) = rows.next()? {
|
||||||
|
let existing_id: i64 = row.get(0)?;
|
||||||
|
conn.execute(
|
||||||
|
"UPDATE platform_accounts SET nickname = ?1, avatar = ?2, cookies = ?3,
|
||||||
|
login_status = 'active', expires_at = ?4, updated_at = ?5 WHERE id = ?6",
|
||||||
|
params![nickname, avatar, cookies_json, expires, now, existing_id],
|
||||||
|
)?;
|
||||||
|
return self
|
||||||
|
.get(existing_id)?
|
||||||
|
.map(|(r, _)| r)
|
||||||
|
.ok_or_else(|| PublishDbError::Message("更新账号失败".into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"INSERT INTO platform_accounts (platform, nickname, uid, avatar, cookies, tokens,
|
"INSERT INTO platform_accounts (platform, nickname, uid, avatar, cookies, tokens,
|
||||||
login_status, expires_at, created_at, updated_at)
|
login_status, expires_at, created_at, updated_at)
|
||||||
VALUES (?1, ?2, ?3, '', ?4, '', 'active', ?5, ?6, ?6)",
|
VALUES (?1, ?2, ?3, ?4, ?5, '', 'active', ?6, ?7, ?7)",
|
||||||
params![platform, nickname, uid, cookies_json, expires, now],
|
params![platform, nickname, uid, avatar, cookies_json, expires, now],
|
||||||
)?;
|
)?;
|
||||||
let id = conn.last_insert_rowid();
|
let id = conn.last_insert_rowid();
|
||||||
self.get(id)?
|
self.get(id)?
|
||||||
@@ -171,6 +191,23 @@ impl PublishDb {
|
|||||||
.ok_or_else(|| PublishDbError::Message("插入账号失败".into()))
|
.ok_or_else(|| PublishDbError::Message("插入账号失败".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_account_slot(&self, platform: &str) -> Result<PlatformAccountRecord, PublishDbError> {
|
||||||
|
let conn = self.conn.lock().map_err(|_| {
|
||||||
|
PublishDbError::Message("数据库锁异常".into())
|
||||||
|
})?;
|
||||||
|
let now = chrono::Utc::now().timestamp_millis();
|
||||||
|
conn.execute(
|
||||||
|
"INSERT INTO platform_accounts (platform, nickname, uid, avatar, cookies, tokens,
|
||||||
|
login_status, expires_at, created_at, updated_at)
|
||||||
|
VALUES (?1, '', '', '', '[]', '', 'inactive', NULL, ?2, ?2)",
|
||||||
|
params![platform, now],
|
||||||
|
)?;
|
||||||
|
let id = conn.last_insert_rowid();
|
||||||
|
self.get(id)?
|
||||||
|
.map(|(r, _)| r)
|
||||||
|
.ok_or_else(|| PublishDbError::Message("创建账号槽位失败".into()))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_login_status(&self, id: i64, status: &str) -> Result<(), PublishDbError> {
|
pub fn set_login_status(&self, id: i64, status: &str) -> Result<(), PublishDbError> {
|
||||||
let conn = self.conn.lock().map_err(|_| {
|
let conn = self.conn.lock().map_err(|_| {
|
||||||
PublishDbError::Message("数据库锁异常".into())
|
PublishDbError::Message("数据库锁异常".into())
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ impl PublishStore {
|
|||||||
platform: String,
|
platform: String,
|
||||||
nickname: String,
|
nickname: String,
|
||||||
uid: String,
|
uid: String,
|
||||||
|
avatar: String,
|
||||||
cookies_json: String,
|
cookies_json: String,
|
||||||
account_id: Option<i64>,
|
account_id: Option<i64>,
|
||||||
) -> Result<PlatformAccountRecord, String> {
|
) -> Result<PlatformAccountRecord, String> {
|
||||||
@@ -72,6 +73,7 @@ impl PublishStore {
|
|||||||
&platform,
|
&platform,
|
||||||
&nickname,
|
&nickname,
|
||||||
&uid,
|
&uid,
|
||||||
|
&avatar,
|
||||||
&cookies_json,
|
&cookies_json,
|
||||||
account_id,
|
account_id,
|
||||||
)
|
)
|
||||||
@@ -80,6 +82,11 @@ impl PublishStore {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn create_account_slot(&self, platform: String) -> Result<PlatformAccountRecord, String> {
|
||||||
|
self.with_db(move |db| db.create_account_slot(&platform).map_err(|e| e.to_string()))
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn set_login_status(&self, id: i64, status: String) -> Result<(), String> {
|
pub async fn set_login_status(&self, id: i64, status: String) -> Result<(), String> {
|
||||||
self.with_db(move |db| db.set_login_status(id, &status).map_err(|e| e.to_string()))
|
self.with_db(move |db| db.set_login_status(id, &status).map_err(|e| e.to_string()))
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ const {
|
|||||||
const feedback = ref({ severity: "", message: "" });
|
const feedback = ref({ severity: "", message: "" });
|
||||||
const scheduleDialogVisible = ref(false);
|
const scheduleDialogVisible = ref(false);
|
||||||
const scheduleDate = ref(null);
|
const scheduleDate = ref(null);
|
||||||
|
const accountDialogVisible = ref(false);
|
||||||
|
const activePlatformKey = ref("douyin");
|
||||||
|
|
||||||
const hasVideo = computed(
|
const hasVideo = computed(
|
||||||
() => Boolean(processedVideoPath.value || generatedVideoPath.value),
|
() => Boolean(processedVideoPath.value || generatedVideoPath.value),
|
||||||
@@ -40,6 +42,20 @@ const accountOptions = (platform) =>
|
|||||||
value: a.id,
|
value: a.id,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const platformIcons = {
|
||||||
|
douyin: "📱",
|
||||||
|
kuaishou: "🎬",
|
||||||
|
shipin: "📺",
|
||||||
|
xiaohongshu: "📕",
|
||||||
|
};
|
||||||
|
|
||||||
|
const activePlatform = computed(
|
||||||
|
() =>
|
||||||
|
publishPlatforms.value.find((p) => p.key === activePlatformKey.value) ||
|
||||||
|
publishPlatforms.value[0] ||
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
function showFeedback(result) {
|
function showFeedback(result) {
|
||||||
if (!result?.message) return;
|
if (!result?.message) return;
|
||||||
feedback.value = {
|
feedback.value = {
|
||||||
@@ -52,6 +68,17 @@ onMounted(async () => {
|
|||||||
await workflow.refreshPublishAccounts();
|
await workflow.refreshPublishAccounts();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function openAccountManager() {
|
||||||
|
if (publishPlatforms.value.length && !activePlatform.value) {
|
||||||
|
activePlatformKey.value = publishPlatforms.value[0].key;
|
||||||
|
}
|
||||||
|
accountDialogVisible.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectPlatform(platformKey) {
|
||||||
|
activePlatformKey.value = platformKey;
|
||||||
|
}
|
||||||
|
|
||||||
async function onPublish() {
|
async function onPublish() {
|
||||||
feedback.value = { severity: "", message: "" };
|
feedback.value = { severity: "", message: "" };
|
||||||
showFeedback(await workflow.publishVideo({ autoPublish: true }));
|
showFeedback(await workflow.publishVideo({ autoPublish: true }));
|
||||||
@@ -85,22 +112,77 @@ function cancelSchedule() {
|
|||||||
feedback.value = { severity: "success", message: "已取消定时发布" };
|
feedback.value = { severity: "success", message: "已取消定时发布" };
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onLogin(platform) {
|
async function onLogin(platform, accountId = undefined) {
|
||||||
feedback.value = { severity: "", message: "" };
|
feedback.value = { severity: "", message: "" };
|
||||||
showFeedback(await workflow.loginPublishPlatform(platform.key));
|
showFeedback(await workflow.loginPublishPlatform(platform.key, accountId));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onLoginAccount(platform, account) {
|
||||||
|
await onLogin(platform, account.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onAddAccount(platform) {
|
||||||
|
await onLogin(platform, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDeleteAccount(platform, account) {
|
||||||
|
platform.accounts = (platform.accounts || []).filter((a) => a.id !== account.id);
|
||||||
|
if (platform.accountId === account.id) {
|
||||||
|
platform.accountId = null;
|
||||||
|
}
|
||||||
|
if (!platform.accounts.length) {
|
||||||
|
platform.loggedIn = false;
|
||||||
|
platform.nickname = "";
|
||||||
|
}
|
||||||
|
feedback.value = { severity: "success", message: "已从本地列表移除账号,刷新后可重新获取" };
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatAccountStatus(account) {
|
||||||
|
if (account?.loginStatus === "active" && account?.hasCookies) {
|
||||||
|
return { dot: "🟢", text: "已登录", color: "#4ade80" };
|
||||||
|
}
|
||||||
|
if (account?.loginStatus === "expired") {
|
||||||
|
return { dot: "🟠", text: "登录过期", color: "#f59e0b" };
|
||||||
|
}
|
||||||
|
return { dot: "⚪", text: "未登录", color: "#999999" };
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatUpdateTime(account) {
|
||||||
|
const raw = account?.updatedAt || account?.lastLoginAt || account?.createdAt;
|
||||||
|
if (!raw) return "";
|
||||||
|
const d = new Date(raw);
|
||||||
|
if (Number.isNaN(d.getTime())) return "";
|
||||||
|
return d.toLocaleString("zh-CN", {
|
||||||
|
month: "numeric",
|
||||||
|
day: "numeric",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
hour12: false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<DashboardCard title="视频发布" step="07" :grow="true">
|
<DashboardCard title="视频发布" step="07" :grow="true">
|
||||||
|
<div class="mb-2 flex justify-end">
|
||||||
|
<Button
|
||||||
|
label="账号管理"
|
||||||
|
icon="pi pi-users"
|
||||||
|
size="small"
|
||||||
|
text
|
||||||
|
class="text-gray-400 hover:text-blue-400"
|
||||||
|
@click="openAccountManager"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-for="platform in publishPlatforms"
|
v-for="platform in publishPlatforms"
|
||||||
:key="platform.key"
|
:key="platform.key"
|
||||||
class="dashboard-platform-row mb-2"
|
class="publish-platform-row mb-2 flex items-center justify-between gap-2 rounded border border-white/5 bg-white/5 p-2 hover:bg-white/10"
|
||||||
>
|
>
|
||||||
<label class="flex shrink-0 items-center gap-2 text-sm" style="min-width: 86px">
|
<label class="flex shrink-0 items-center text-sm" style="min-width: 86px">
|
||||||
<Checkbox v-model="platform.checked" binary />
|
<Checkbox v-model="platform.checked" binary />
|
||||||
<span>{{ platform.label }}</span>
|
<span class="ml-1">{{ platform.label }}</span>
|
||||||
<span
|
<span
|
||||||
v-if="platform.loggedIn"
|
v-if="platform.loggedIn"
|
||||||
class="text-xs text-emerald-400"
|
class="text-xs text-emerald-400"
|
||||||
@@ -116,16 +198,9 @@ async function onLogin(platform) {
|
|||||||
option-value="value"
|
option-value="value"
|
||||||
placeholder="选择账号"
|
placeholder="选择账号"
|
||||||
size="small"
|
size="small"
|
||||||
class="min-w-0 flex-1"
|
class="min-w-0 max-w-[200px] flex-1"
|
||||||
:disabled="!accountOptions(platform).length"
|
:disabled="!accountOptions(platform).length"
|
||||||
/>
|
/>
|
||||||
<Button
|
|
||||||
label="登录"
|
|
||||||
size="small"
|
|
||||||
text
|
|
||||||
:loading="publishLoggingIn === platform.key"
|
|
||||||
@click="onLogin(platform)"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p v-if="!hasVideo" class="mt-1 text-xs text-amber-400/90">
|
<p v-if="!hasVideo" class="mt-1 text-xs text-amber-400/90">
|
||||||
@@ -196,6 +271,94 @@ async function onLogin(platform) {
|
|||||||
首次发布:请手动关闭浏览器内出现的任何弹窗提示(说明等),防止干扰脚本,下次即可流畅运行
|
首次发布:请手动关闭浏览器内出现的任何弹窗提示(说明等),防止干扰脚本,下次即可流畅运行
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<Dialog
|
||||||
|
v-model:visible="accountDialogVisible"
|
||||||
|
header="平台账号管理"
|
||||||
|
modal
|
||||||
|
:style="{ width: '640px' }"
|
||||||
|
>
|
||||||
|
<div class="account-manager">
|
||||||
|
<div class="platform-tabs">
|
||||||
|
<div
|
||||||
|
v-for="platform in publishPlatforms"
|
||||||
|
:key="platform.key"
|
||||||
|
class="platform-tab"
|
||||||
|
:class="{ active: activePlatform?.key === platform.key }"
|
||||||
|
@click="selectPlatform(platform.key)"
|
||||||
|
>
|
||||||
|
<span class="tab-icon">{{ platformIcons[platform.key] || "📌" }}</span>
|
||||||
|
<span class="tab-name">{{ platform.label }}</span>
|
||||||
|
<span v-if="platform.accounts?.length" class="tab-count">{{ platform.accounts.length }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="account-list">
|
||||||
|
<div
|
||||||
|
v-for="account in activePlatform?.accounts || []"
|
||||||
|
:key="`${activePlatform.key}_${account.id}`"
|
||||||
|
class="account-card"
|
||||||
|
>
|
||||||
|
<div class="account-info">
|
||||||
|
<span class="status-dot">{{ formatAccountStatus(account).dot }}</span>
|
||||||
|
<div class="account-detail">
|
||||||
|
<div class="account-nickname">{{ account.nickname || "未登录" }}</div>
|
||||||
|
<div class="account-meta">
|
||||||
|
<span class="status-text" :style="{ color: formatAccountStatus(account).color }">
|
||||||
|
{{ formatAccountStatus(account).text }}
|
||||||
|
</span>
|
||||||
|
<span v-if="formatUpdateTime(account)" class="update-time">
|
||||||
|
· {{ formatUpdateTime(account) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="account-actions">
|
||||||
|
<Button
|
||||||
|
label="扫码登录"
|
||||||
|
size="small"
|
||||||
|
severity="secondary"
|
||||||
|
:loading="publishLoggingIn === activePlatform.key"
|
||||||
|
@click="onLoginAccount(activePlatform, account)"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
label="删除"
|
||||||
|
size="small"
|
||||||
|
severity="danger"
|
||||||
|
outlined
|
||||||
|
@click="onDeleteAccount(activePlatform, account)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="!(activePlatform?.accounts || []).length" class="account-card">
|
||||||
|
<div class="account-info">
|
||||||
|
<span class="status-dot">⚪</span>
|
||||||
|
<div class="account-detail">
|
||||||
|
<div class="account-nickname">未登录</div>
|
||||||
|
<div class="account-meta">
|
||||||
|
<span class="status-text" style="color: #999999">未登录</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="account-actions">
|
||||||
|
<Button
|
||||||
|
label="扫码登录"
|
||||||
|
size="small"
|
||||||
|
severity="secondary"
|
||||||
|
:loading="publishLoggingIn === activePlatform?.key"
|
||||||
|
@click="onAddAccount(activePlatform)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="add-account-btn" @click="onAddAccount(activePlatform)">
|
||||||
|
<span class="add-icon">+</span>
|
||||||
|
<span>添加{{ activePlatform?.label || "" }}账号</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
<Dialog
|
<Dialog
|
||||||
v-model:visible="scheduleDialogVisible"
|
v-model:visible="scheduleDialogVisible"
|
||||||
header="定时发布"
|
header="定时发布"
|
||||||
@@ -217,3 +380,118 @@ async function onLogin(platform) {
|
|||||||
</Dialog>
|
</Dialog>
|
||||||
</DashboardCard>
|
</DashboardCard>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.account-manager {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-tab {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border: 1px solid #333333;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #1c1c1c;
|
||||||
|
color: #d1d5db;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-tab.active {
|
||||||
|
border-color: #2563eb;
|
||||||
|
background: rgba(37, 99, 235, 0.15);
|
||||||
|
color: #e2e8f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-count {
|
||||||
|
min-width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
padding: 0 5px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(37, 99, 235, 0.25);
|
||||||
|
color: #bfdbfe;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 18px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-card {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
border: 1px solid #333333;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-detail {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-nickname {
|
||||||
|
color: #e5e7eb;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-meta {
|
||||||
|
margin-top: 3px;
|
||||||
|
color: #9ca3af;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-account-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
border: 1px dashed #3f3f46;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
color: #cbd5e1;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-account-btn:hover {
|
||||||
|
border-color: #2563eb;
|
||||||
|
color: #dbeafe;
|
||||||
|
background: rgba(37, 99, 235, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-icon {
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -54,15 +54,17 @@ export async function refreshPublishAccounts(store) {
|
|||||||
* @param {ReturnType<typeof import('../stores/workflow.js').useWorkflowStore>} store
|
* @param {ReturnType<typeof import('../stores/workflow.js').useWorkflowStore>} store
|
||||||
* @param {string} platformKey
|
* @param {string} platformKey
|
||||||
*/
|
*/
|
||||||
export async function loginPublishPlatform(store, platformKey) {
|
export async function loginPublishPlatform(store, platformKey, accountId = undefined) {
|
||||||
const row = store.publishPlatforms.find((p) => p.key === platformKey);
|
const row = store.publishPlatforms.find((p) => p.key === platformKey);
|
||||||
if (!row) return { ok: false, message: "未知平台" };
|
if (!row) return { ok: false, message: "未知平台" };
|
||||||
|
|
||||||
store.publishLoggingIn = platformKey;
|
store.publishLoggingIn = platformKey;
|
||||||
try {
|
try {
|
||||||
const result = await invoke("publish_login", {
|
const result = await invoke("publish_login", {
|
||||||
|
params: {
|
||||||
platform: platformKey,
|
platform: platformKey,
|
||||||
accountId: row.accountId || null,
|
accountId: accountId === undefined ? row.accountId || null : accountId,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
if (!result?.success) {
|
if (!result?.success) {
|
||||||
return {
|
return {
|
||||||
@@ -116,9 +118,11 @@ export async function executePublishVideo(store, { autoPublish = true } = {}) {
|
|||||||
|
|
||||||
for (const row of selected) {
|
for (const row of selected) {
|
||||||
const check = await invoke("publish_check_login", {
|
const check = await invoke("publish_check_login", {
|
||||||
|
params: {
|
||||||
platform: row.key,
|
platform: row.key,
|
||||||
accountId: row.accountId || null,
|
accountId: row.accountId || null,
|
||||||
checkBrowser: false,
|
checkBrowser: false,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
if (!check?.isLoggedIn) {
|
if (!check?.isLoggedIn) {
|
||||||
const label = row.label || row.key;
|
const label = row.label || row.key;
|
||||||
@@ -142,6 +146,7 @@ export async function executePublishVideo(store, { autoPublish = true } = {}) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await invoke("publish_execute", {
|
const result = await invoke("publish_execute", {
|
||||||
|
params: {
|
||||||
platforms: selected.map((p) => ({
|
platforms: selected.map((p) => ({
|
||||||
platform: p.key,
|
platform: p.key,
|
||||||
accountId: p.accountId || null,
|
accountId: p.accountId || null,
|
||||||
@@ -152,6 +157,7 @@ export async function executePublishVideo(store, { autoPublish = true } = {}) {
|
|||||||
description,
|
description,
|
||||||
tags,
|
tags,
|
||||||
autoPublish,
|
autoPublish,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
store.publishResults = Array.isArray(result?.results) ? result.results : [];
|
store.publishResults = Array.isArray(result?.results) ? result.results : [];
|
||||||
|
|||||||
@@ -685,8 +685,8 @@ export const useWorkflowStore = defineStore("workflow", {
|
|||||||
return refreshPublishAccounts(this);
|
return refreshPublishAccounts(this);
|
||||||
},
|
},
|
||||||
|
|
||||||
async loginPublishPlatform(platformKey) {
|
async loginPublishPlatform(platformKey, accountId = undefined) {
|
||||||
return loginPublishPlatform(this, platformKey);
|
return loginPublishPlatform(this, platformKey, accountId);
|
||||||
},
|
},
|
||||||
|
|
||||||
async publishVideo(options) {
|
async publishVideo(options) {
|
||||||
|
|||||||
Reference in New Issue
Block a user