feat(core/frontend): pipeline stage editor (burn-in controls) + double-submit guard & button greying
Pipeline (脚本→资产→故事板→视频→拼接): - Stage1 render real script shots + wire 确认脚本→adopt (advance stage) - Stage2 add person/scene AI-生成 buttons + clickable category tabs - Stage4 auto-poll videos to completion + per-segment upload + real frame thumbnails + download - Stage5 real timeline editor: clips undo/redo/split/copy/delete/drag-reorder/zoom, subtitle style + per-clip text editor, transition select (xfade preview), BGM upload + volume, save draft, export-with-save → shows/download final MP4 - embedded asset URLs everywhere (beat assets pagination) UX: re-entry guard in action() (no double-submit anywhere) + greyed :disabled styles for btn-aigen/chat-mode/pill-cta/tl-action so generate buttons visibly disable while generating. Also includes prior uncommitted frontend work: settings preferences/sessions/avatar, asset delete, account/team/products pages, fonts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useState } from "react";
|
||||
import { CircleDollarSign, KeyRound, UserPlus } from "lucide-react";
|
||||
import type { BillingSummary, Team, TeamMember, User } from "../types";
|
||||
import type { BillingSummary, Notification, Team, TeamMember, User } from "../types";
|
||||
import type { Page } from "./route-config";
|
||||
import { money } from "./stage-config";
|
||||
import { ConfirmModal, TeamModal } from "../components/overlays";
|
||||
@@ -24,11 +24,12 @@ const PERM_ROWS: Array<{ cap: string; cells: [string, string, string]; last?: bo
|
||||
{ cap: "创建项目 / 用 AI 流程", cells: ["✓", "✓", "✓"], last: true }
|
||||
];
|
||||
|
||||
export function TeamPage({ team, user, members, billing, navigate, onCreateMember, onUpdateMember, onRemoveMember, onResetPassword, onRecharge }: {
|
||||
export function TeamPage({ team, user, members, billing, notifications = [], navigate, onCreateMember, onUpdateMember, onRemoveMember, onResetPassword, onRecharge }: {
|
||||
team: Team;
|
||||
user: User;
|
||||
members: TeamMember[];
|
||||
billing: BillingSummary | null;
|
||||
notifications?: Notification[];
|
||||
navigate: (page: Page) => void;
|
||||
onCreateMember: (payload: { username: string; password: string; name?: string; role?: string; monthly_credit_limit?: number }) => void | Promise<unknown>;
|
||||
onUpdateMember: (id: string, payload: { role?: string; monthly_credit_limit?: number }) => void | Promise<unknown>;
|
||||
@@ -72,6 +73,11 @@ export function TeamPage({ team, user, members, billing, navigate, onCreateMembe
|
||||
const left = Math.max(0, limit - used);
|
||||
const pct = limit > 0 ? Math.min(100, (used / limit) * 100) : 0;
|
||||
|
||||
// 团队动态:取最近 6 条真实通知
|
||||
const feedItems = [...notifications]
|
||||
.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())
|
||||
.slice(0, 6);
|
||||
|
||||
const needle = search.trim().toLowerCase();
|
||||
const list = rows.filter((member) => {
|
||||
const name = member.user.username || "";
|
||||
@@ -190,21 +196,37 @@ export function TeamPage({ team, user, members, billing, navigate, onCreateMembe
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 团队动态(banner 右栏)· 对齐 api-bridge renderLiveTeamActivity 的真实状态占位 */}
|
||||
{/* 团队动态(banner 右栏)· 接真实 ops/notifications 事件流 */}
|
||||
<div className="team-feed">
|
||||
<div className="h">
|
||||
<h3>团队动态</h3>
|
||||
<span className="ct">// 真实动态接口待接入</span>
|
||||
<span className="ct">// 最近 {Math.min(feedItems.length, 6)} 条 · 共 {notifications.length}</span>
|
||||
<a className="more" id="open-feed-all" role="button" tabIndex={0} onClick={() => navigate("messages")}>全部 →</a>
|
||||
</div>
|
||||
<div className="feed-list">
|
||||
<div className="feed-item">
|
||||
<div className="av">Q</div>
|
||||
<div>
|
||||
<div className="txt"><span className="who">真实团队表</span><span className="act">已同步</span><span className="obj">{rows.length} 名成员</span></div>
|
||||
<div className="ts">local cache</div>
|
||||
{feedItems.length === 0 ? (
|
||||
<div className="feed-item">
|
||||
<div className="av">{(team.name || "T").slice(0, 1).toUpperCase()}</div>
|
||||
<div>
|
||||
<div className="txt"><span className="who">{team.name}</span><span className="act">已同步</span><span className="obj">{rows.length} 名成员</span></div>
|
||||
<div className="ts">// 暂无团队动态</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
feedItems.map((n) => (
|
||||
<div className="feed-item" key={n.id}>
|
||||
<div className="av">{(n.owner_label || n.source || team.name || "·").slice(0, 1).toUpperCase()}</div>
|
||||
<div>
|
||||
<div className="txt">
|
||||
<span className="who">{n.owner_label || n.source || "系统"}</span>
|
||||
<span className="act">{n.title}</span>
|
||||
{n.project_name && <span className="obj">{n.project_name}</span>}
|
||||
</div>
|
||||
<div className="ts">{n.created_at ? new Date(n.created_at).toLocaleString("zh-CN") : n.brief}</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user