This commit is contained in:
Ivan Neplokhov 2026-01-15 19:05:37 +04:00
parent 217b6398e6
commit 3329b91c3f
6 changed files with 62 additions and 6 deletions

View File

@ -13,7 +13,7 @@
"build:win:x64": "vite build && electron-builder --win --x64", "build:win:x64": "vite build && electron-builder --win --x64",
"build:win:x64:installer": "vite build && electron-builder --win --x64 --config.win.target=nsis", "build:win:x64:installer": "vite build && electron-builder --win --x64 --config.win.target=nsis",
"build:win:x64:portable": "vite build && electron-builder --win --x64 --config.win.target=portable", "build:win:x64:portable": "vite build && electron-builder --win --x64 --config.win.target=portable",
"build:win:x64:portable:zip": "npm run build:win:x64:portable && powershell -Command \"Compress-Archive -Force -Path dist/release/*portable*.exe -DestinationPath dist/release/Telegram-Invite-Automation-win-portable-x64.zip\"", "build:win:x64:portable:zip": "npm run build:win:x64:portable && zip -j -o dist/release/Telegram-Invite-Automation-win-portable-x64.zip dist/release/Telegram-Invite-Automation-win-x64-*.exe",
"build:mac": "vite build && electron-builder --mac", "build:mac": "vite build && electron-builder --mac",
"build:all": "vite build && electron-builder --win --mac", "build:all": "vite build && electron-builder --win --mac",
"build:linux": "vite build && electron-builder --linux", "build:linux": "vite build && electron-builder --linux",

Binary file not shown.

View File

@ -459,15 +459,16 @@ function initStore(userDataPath) {
.run(now, queueId); .run(now, queueId);
} }
function recordInvite(taskId, userId, username, accountId, accountPhone, sourceChat, status, error, skippedReason, action) { function recordInvite(taskId, userId, username, accountId, accountPhone, sourceChat, status, error, skippedReason, action, userAccessHash) {
const now = dayjs().toISOString(); const now = dayjs().toISOString();
db.prepare(` db.prepare(`
INSERT INTO invites (task_id, user_id, username, account_id, account_phone, source_chat, action, skipped_reason, invited_at, status, error) INSERT INTO invites (task_id, user_id, username, user_access_hash, account_id, account_phone, source_chat, action, skipped_reason, invited_at, status, error)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`).run( `).run(
taskId || 0, taskId || 0,
userId, userId,
username || "", username || "",
userAccessHash || "",
accountId || 0, accountId || 0,
accountPhone || "", accountPhone || "",
sourceChat || "", sourceChat || "",
@ -564,6 +565,7 @@ function initStore(userDataPath) {
taskId: row.task_id || 0, taskId: row.task_id || 0,
userId: row.user_id, userId: row.user_id,
username: row.username || "", username: row.username || "",
userAccessHash: row.user_access_hash || "",
accountId: row.account_id || 0, accountId: row.account_id || 0,
accountPhone: row.account_phone || "", accountPhone: row.account_phone || "",
sourceChat: row.source_chat || "", sourceChat: row.source_chat || "",

View File

@ -105,7 +105,8 @@ class TaskRunner {
"success", "success",
"", "",
"", "",
"invite" "invite",
item.user_access_hash
); );
} else { } else {
errors.push(`${item.user_id}: ${result.error}`); errors.push(`${item.user_id}: ${result.error}`);
@ -125,7 +126,8 @@ class TaskRunner {
"failed", "failed",
result.error || "", result.error || "",
result.error || "", result.error || "",
"invite" "invite",
item.user_access_hash
); );
} }
} }

View File

@ -114,6 +114,7 @@ export default function App() {
const [inviteFilter, setInviteFilter] = useState("all"); const [inviteFilter, setInviteFilter] = useState("all");
const [taskSort, setTaskSort] = useState("activity"); const [taskSort, setTaskSort] = useState("activity");
const [sidebarExpanded, setSidebarExpanded] = useState(false); const [sidebarExpanded, setSidebarExpanded] = useState(false);
const [expandedInviteId, setExpandedInviteId] = useState(null);
const bellRef = useRef(null); const bellRef = useRef(null);
const competitorGroups = useMemo(() => { const competitorGroups = useMemo(() => {
@ -362,6 +363,23 @@ export default function App() {
return date.toLocaleString("ru-RU"); return date.toLocaleString("ru-RU");
}; };
const explainInviteError = (error) => {
if (!error) return "";
if (error === "USER_ID_INVALID") {
return "Чаще всего нет access_hash (пользователь скрыт/удален/анонимный).";
}
if (error === "CHAT_WRITE_FORBIDDEN") {
return "Аккаунт не может приглашать: нет прав или он не участник группы.";
}
if (error === "AUTH_KEY_DUPLICATED") {
return "Сессия используется в другом месте, Telegram отозвал ключ.";
}
if (error.includes("FLOOD") || error.includes("PEER_FLOOD")) {
return "Ограничение Telegram по частоте действий.";
}
return "";
};
const showNotification = (text, tone) => { const showNotification = (text, tone) => {
if (tone === "success") return; if (tone === "success") return;
const entry = { text, tone, id: Date.now() }; const entry = { text, tone, id: Date.now() };
@ -2026,6 +2044,29 @@ export default function App() {
{invite.error && invite.error !== "" && ( {invite.error && invite.error !== "" && (
<div className="log-errors">Причина: {invite.error}</div> <div className="log-errors">Причина: {invite.error}</div>
)} )}
{invite.error && explainInviteError(invite.error) && (
<div className="log-users">Вероятная причина: {explainInviteError(invite.error)}</div>
)}
<button
type="button"
className="ghost"
onClick={() => setExpandedInviteId(expandedInviteId === invite.id ? null : invite.id)}
>
{expandedInviteId === invite.id ? "Скрыть детали" : "Подробнее"}
</button>
{expandedInviteId === invite.id && (
<div className="invite-details">
<div>Задача: {invite.taskId}</div>
<div>Аккаунт ID: {invite.accountId || "—"}</div>
<div>Действие: {invite.action || "invite"}</div>
<div>Статус: {invite.status}</div>
<div>Пропуск: {invite.skippedReason || "—"}</div>
<div>Ошибка: {invite.error || "—"}</div>
<div>Вероятная причина: {explainInviteError(invite.error) || "—"}</div>
<div>Access Hash: {invite.userAccessHash || "—"}</div>
<div>Время: {formatTimestamp(invite.invitedAt)}</div>
</div>
)}
</div> </div>
</div> </div>
))} ))}

View File

@ -883,6 +883,17 @@ button.danger {
color: #475569; color: #475569;
} }
.invite-details {
margin-top: 10px;
padding: 10px 12px;
border-radius: 10px;
background: #f1f5f9;
color: #334155;
font-size: 12px;
display: grid;
gap: 4px;
}
.wrap { .wrap {
word-break: break-all; word-break: break-all;
} }