生图模型可选(火山/gpt-image)+ 模特上身图提示词强化 + 多会话等改动
本轮(生图模型选择 + 火山接入): - 工作室新增「生图模型」选择器(模特上身图/平台套图头部 chip + 图片创作底部 Pill), 默认火山 Seedream,可切 gpt-image-2;选择写入 localStorage,下次进页面读回 - 后端 resolve_image_model 解析所选模型;enqueue_standalone_images 接 image_model - worker 按模型能力分流:有 image_edit(gpt-image)走多图编辑;无(火山)走 image_generation(image=参考图);新增 _ratio_to_volcano_size 让火山按比例出图 → 内衣等敏感品类用火山可绕开 gpt-image 的 sexual 内容审核 模特上身图提示词: - 穿戴/非穿戴分流、按 index 变化动作场景镜头、负面词尾接、多图参考序号自适应 - _product_reference_urls:商品参考真实上传图优先、排除 AI 生成图、可多张 其他(并入此前各会话未提交改动): - 图片创作多会话(ImageConversation + migration 0019)、任务中心按类型过滤 - accounts/projects/assets/team/auth 等零散调整、相关测试 - 测试脚本(tryon_*.py)、测试清单(core/bug/*.xlsx)
This commit is contained in:
@@ -29,14 +29,17 @@ const SHELL_COMMANDS: Command[] = [
|
||||
{ id: "image-optimize", group: "常用动作", label: "图片创作", sub: "对话式生成、编辑、加入资产库", page: "imageOptimize", icon: "images" }
|
||||
];
|
||||
|
||||
function CommandPalette({ open, onClose, navigate }: { open: boolean; onClose: () => void; navigate: Navigate }) {
|
||||
function CommandPalette({ open, onClose, navigate, canManageBilling = true }: { open: boolean; onClose: () => void; navigate: Navigate; canManageBilling?: boolean }) {
|
||||
const [query, setQuery] = useState("");
|
||||
useBodyScrollLock(open);
|
||||
useEffect(() => { if (open) setQuery(""); }, [open]);
|
||||
const items = useMemo(() => {
|
||||
const q = query.trim().toLowerCase();
|
||||
return SHELL_COMMANDS.filter((cmd) => !q || [cmd.label, cmd.sub, cmd.group, cmd.id].join(" ").toLowerCase().includes(q));
|
||||
}, [query]);
|
||||
// 非主账号:命令面板里也不暴露「团队」「消费」(与侧栏一致,PMC#3)
|
||||
return SHELL_COMMANDS
|
||||
.filter((cmd) => canManageBilling || (cmd.page !== "team" && cmd.page !== "account"))
|
||||
.filter((cmd) => !q || [cmd.label, cmd.sub, cmd.group, cmd.id].join(" ").toLowerCase().includes(q));
|
||||
}, [query, canManageBilling]);
|
||||
const run = (cmd: Command) => { onClose(); navigate(cmd.page); };
|
||||
if (!open) return null;
|
||||
let lastGroup = "";
|
||||
@@ -109,13 +112,14 @@ const ACCOUNT_ITEMS: { act: Page; icon: string; label: string }[] = [
|
||||
{ act: "account", icon: "creditCard", label: "消费与余额" }
|
||||
];
|
||||
|
||||
function AccountMenu({ anchorRect, onClose, navigate, logout, user, team }: {
|
||||
function AccountMenu({ anchorRect, onClose, navigate, logout, user, team, canManageBilling = true }: {
|
||||
anchorRect: DOMRect;
|
||||
onClose: () => void;
|
||||
navigate: Navigate;
|
||||
logout: () => void;
|
||||
user: User;
|
||||
team: Team | null;
|
||||
canManageBilling?: boolean;
|
||||
}) {
|
||||
const menuRef = useRef<HTMLDivElement>(null);
|
||||
const [pos, setPos] = useState<{ left: number; top: number }>({ left: anchorRect.left, top: anchorRect.bottom + 8 });
|
||||
@@ -169,7 +173,7 @@ function AccountMenu({ anchorRect, onClose, navigate, logout, user, team }: {
|
||||
<span className="mail">{user.username}</span>
|
||||
</span>
|
||||
</div>
|
||||
{ACCOUNT_ITEMS.map((item) => (
|
||||
{ACCOUNT_ITEMS.filter((item) => canManageBilling || (item.act !== "team" && item.act !== "account")).map((item) => (
|
||||
<button key={item.act} type="button" role="menuitem" onClick={() => go(item.act)}>
|
||||
<IconKitSvg name={item.icon} />
|
||||
{item.label}
|
||||
@@ -222,11 +226,13 @@ const PAGE_TO_NAV: Partial<Record<Page, Page>> = {
|
||||
settingsNotify: "settings"
|
||||
};
|
||||
|
||||
export function Sidebar({ page, navigate, user, team, products, projects, productTotal, projectTotal, logout, onOpenAdmin }: {
|
||||
export function Sidebar({ page, navigate, user, team, canManageBilling = true, products, projects, productTotal, projectTotal, logout, onOpenAdmin }: {
|
||||
page: Page;
|
||||
navigate: Navigate;
|
||||
user: User;
|
||||
team: Team | null;
|
||||
// 主账号(owner=超管)才看得到「团队」「消费」入口;子账号隐藏(PMC#3)。默认 true 兼容旧调用。
|
||||
canManageBilling?: boolean;
|
||||
products: Product[];
|
||||
projects: Project[];
|
||||
productTotal?: number;
|
||||
@@ -238,6 +244,8 @@ export function Sidebar({ page, navigate, user, team, products, projects, produc
|
||||
onOpenAdmin?: () => void;
|
||||
}) {
|
||||
const activeNav = PAGE_TO_NAV[page];
|
||||
// 子账号:导航里去掉「团队」「消费」两项(命令面板、账户菜单同步过滤)。
|
||||
const navItems = NAV.filter((item) => canManageBilling || (item.page !== "team" && item.page !== "account"));
|
||||
// 徽标用后端真实总数(分页 count),不用已加载的页内条数
|
||||
const badges: Partial<Record<string, number>> = { products: productTotal ?? products.length, projects: projectTotal ?? projects.length };
|
||||
const avatar = (team?.name || user.username || "A").slice(0, 1).toUpperCase();
|
||||
@@ -320,7 +328,7 @@ export function Sidebar({ page, navigate, user, team, products, projects, produc
|
||||
</div>
|
||||
<div className="nav-section">主要</div>
|
||||
<nav>
|
||||
{NAV.map((item) => (
|
||||
{navItems.map((item) => (
|
||||
<a
|
||||
key={item.id}
|
||||
href={`/${item.id}`}
|
||||
@@ -367,7 +375,7 @@ export function Sidebar({ page, navigate, user, team, products, projects, produc
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
<CommandPalette open={paletteOpen} onClose={() => setPaletteOpen(false)} navigate={navigate} />
|
||||
<CommandPalette open={paletteOpen} onClose={() => setPaletteOpen(false)} navigate={navigate} canManageBilling={canManageBilling} />
|
||||
{accountAnchor && (
|
||||
<AccountMenu
|
||||
anchorRect={accountAnchor}
|
||||
@@ -376,6 +384,7 @@ export function Sidebar({ page, navigate, user, team, products, projects, produc
|
||||
logout={handleLogout}
|
||||
user={user}
|
||||
team={team}
|
||||
canManageBilling={canManageBilling}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user