import ToolBenefitOperator from '@aiComponents/BenefitOperator';
import AiToolBlockItem from '@aiComponents/BlockItem';
import { AiToolSquareCoverCard } from '@aiComponents/CardItems';
import type { DrawStepOperateLayoutPcRef } from '@aiComponents/DrawStepOperateLayout/pc';
import DrawStepOperateLayoutPC from '@aiComponents/DrawStepOperateLayout/pc';
import AiToolGenerateModal, { type AiToolGenerateModalRef } from '@aiComponents/GenerateModal';
import ToolVerticalIntroduceLayoutPC2 from '@aiComponents/IntroduceLayout/pc/vertical2';
import ToolVerticalIntroduceLayoutContent1 from '@aiComponents/IntroduceLayout/pc/vertical2/componetns/content1';
import type { MaterialIntroduceModalRef } from '@aiComponents/MaterialIntroduceModal';
import MaterialIntroduceModal from '@aiComponents/MaterialIntroduceModal';
import ToggleGenerateInfoPanelItem from '@aiComponents/ToggleInfoPanel/PanelItem.tsx';
import { QuestionCircleOutlined } from '@ant-design/icons';
import IconFont from '@components/Iconfont';
import type { ImageSelectorWrapModalRef } from '@components/ImageSelectorWrapModal';
import ImageSelectorWrapModal from '@components/ImageSelectorWrapModal';
import ProductAuth from '@components/ProductAuth';
import ThemeButton from '@components/ThemeButton';
import ThemeConfigProvider from '@components/ThemeConfigProvider';
import ThemeSegmented from '@components/ThemeSegmented';
import ThemeTextArea from '@components/ThemeTextArea';
import ToolEquityCountWrap, { type ToolEquityCountWrapRef } from '@components/ToolEquityCountWrap';
import {
requestAdvanceDrawFirstStyleCategoryList,
requestAdvanceDrawSubStyleConfigCategory,
} from '@services/advanceDraw/config.ts';
import {
requestComfyUIDrawGenerate,
type RequestComfyUIDrawParams,
} from '@services/advanceDraw/generate.ts';
import type { RequestModelRenderImageParams } from '@services/comfyUI.ts';
import { requestModelRenderImage } from '@services/comfyUI.ts';
import { getRandomNum, mergeDrawPromptStacks } from '@utils/ai.ts';
import { decodeImageUrl } from '@utils/string.ts';
import { getImageSizeInfo } from '@wander/base-utils';
import { CoolImage } from '@wander/common-components';
import { useAsyncEffect, useMount } from 'ahooks';
import { Collapse, Image, message, Typography } from 'antd';
import classNames from 'classnames/bind';
import type { CSSProperties } from 'react';
import { useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useSearchParams } from 'react-router-dom';
import type { ImageSelectorModalProps } from '@/components/ImageSelectorModal';
import type { UploadImageType } from '@/components/UploadImageCard';
import UploadImageCard, {
type UploadImageCardProps,
type UploadImageCardRef,
} from '@/components/UploadImageCard';
import { enlargeDownloadOptions } from '@/config/aiTool.ts';
import useGetConfigValue from '@/hooks/useGetConfigValue.ts';
import { ADVANCE_DRAW_DEFAULT_NEGATIVE_KEYWORDS } from '@/pages/AiTools/AdvanceDraw/constants.ts';
import type { GetAdvanceDrawLeafGenerateArgsByMidsType } from '@/pages/AiTools/AdvanceDraw/utils.ts';
import KjlResultQuickAccessBox from '@/pages/AiTools/components/KjlResultQuickAccessBox';
import ToggleGenerateInfoPopover from '@/pages/AiTools/components/ToggleInfoPanel';
import { lockingMaterialList } from '@/pages/AiTools/Draw/configs.ts';
import {
modelRenderSpeedupKey,
modelRenderToolKey,
modelRenderToolName,
TRACK_MODEL_RENDER_NAME,
} from '@/pages/AiTools/ModelRender/config.ts';
import type { ModelRenderStyleCategoryGridRef } from '@/pages/AiTools/ModelRender/Operate/components/StyleCategoryGrid';
import ModelRenderStyleCategoryGrid from '@/pages/AiTools/ModelRender/Operate/components/StyleCategoryGrid';
import { useToolRouterStore } from '@/pages/AiTools/Router/store/createStore.ts';
import { useStore } from '@/store/createStore.ts';
import type { AdvanceDrawStyleCategoryItem } from '@/types/advanceDraw.ts';
import type { AiToolProcessSuccessResponse } from '@/types/ai';
import type { LockingMaterialType } from '@/types/draw';
import { LockingMaterialTypeEnum } from '@/types/draw';
import styles from './index.module.less';
const cx = classNames.bind(styles);
const { Paragraph } = Typography;
const { Panel } = Collapse;
// 空间位置显示
type SpatialPositionListItem = {
name: string;
coverUrl: string;
// 描述
description: string;
};
const scenarioListItem = [
{
name: '建筑',
coverUrl:
'https://gd-hbimg.huaban.com/bdc46d3401c6319e58749b275b8a00f4d24716e018ed64-PyRBDr_fw1200webp',
},
{
name: '室内',
coverUrl:
'https://gd-hbimg.huaban.com/d113fdba55b570c14f9e6dd85053e20fe66e59f5cd9c6-KWo2yS_fw1200webp',
},
{
name: '景观',
coverUrl:
'https://gd-hbimg.huaban.com/c6b5104002f69d75dca57f072257f94222f688d531c69-bNzUzn_fw1200webp',
},
{
name: '规划',
coverUrl:
'https://gd-hbimg.huaban.com/31401d2c21663350a49df3181f9b34ee2dbaa6a9b8cd9-MMDggY_fw1200webp',
},
];
const ModelRenderOperatePC = () => {
const { t } = useTranslation();
const addBaseImage = useToolRouterStore((state) => state.addBaseImage);
const { productType } = useStore((state) => state.productInfo);
const [searchParams, setSearchParams] = useSearchParams();
// 介绍页显示
const [introduceLayoutShow, setIntroduceLayoutShow] = useState(
productType === 'JKJL' && !searchParams.get('url'),
);
// 步骤条ref
const drawStepOperateLayoutRef = useRef<DrawStepOperateLayoutPcRef>(null);
// 底图上传卡片ref
const baseImageCardRef = useRef<UploadImageCardRef>(null);
// 风格参考图ref
const styleImageCardRef = useRef<UploadImageCardRef>(null);
// 迁移内容的原图片效果图库
const imageSelectorWrapModalRef = useRef<ImageSelectorWrapModalRef>(null);
// 锁定材质弹窗ref
const materialIntroduceModalRef = useRef<MaterialIntroduceModalRef>(null);
// 空间位置列表
const spatialPositionConfig =
useGetConfigValue<Record<string, SpatialPositionListItem[]>>({
key: 'jzxz_model_render_spatial_config',
}) || {};
// 风格类目配置
const styleCategoryMids: string[] =
useGetConfigValue<string[][]>({
key: 'jzxz_model_render_style_categories_config',
})?.map((value) => value[0]) || [];
// 空间位置选中索引
const [selectPositionIndex, setSelectPositionIndex] = useState(0);
// 空间位置类目选中索引 (类目可以切换 然后需要分开存储)
const [spatialCategoryIndex, setSpatialCategoryIndex] = useState(0);
// 高级风格类目
const [styleCategoryList, setStyleCategoryList] = useState<AdvanceDrawStyleCategoryItem[]>([]);
// 锁定材质
const [lockingMaterialType, setLockingMaterialType] = useState<LockingMaterialType>('OFF');
// 描述词
const [description, setDescription] = useState('');
// 存储生成参数
const [generateParams, setGenerateParams] = useState({
baseImage: '',
styleImage: '',
styleAlias: [] as string[],
});
// 刷新工具次数
const refreshToolEquityUserUseInfo = useStore((state) => state.refreshToolEquityUserUseInfo);
// comfyUI 创作弹框-高级版
const generateComfyUiModalRef = useRef<AiToolGenerateModalRef<RequestComfyUIDrawParams>>(null);
// comfyUI 创作弹框- 精确渲染
const generateComfyUiPreciseRenderingModalRef =
useRef<AiToolGenerateModalRef<RequestModelRenderImageParams>>(null);
// 工具次数ref
const toolEquityCountWrapRef = useRef<ToolEquityCountWrapRef>(null);
// 类目ref
const styleCategoryGridRef = useRef<ModelRenderStyleCategoryGridRef>(null);
const [preciseRender, setPreciseRender] = useState(true);
// 建筑学长-选择模型场景index
const [modelScenarioActiveIndex, setModelScenarioActiveIndex] = useState(0);
// 图片上传成功
const onBaseImageFinish: ImageSelectorModalProps['onFinish'] = (item) => {
baseImageCardRef.current?.setUploadImage(item);
};
// 底图改变事件
const onBaseImageChange: UploadImageCardProps['onUploadImageChange'] = (uploadImage) => {
if (uploadImage) {
addBaseImage({
url: uploadImage.largeUrl,
width: uploadImage.width,
height: uploadImage.height,
});
} else {
addBaseImage(null);
}
};
// 响应-高级版
const onComfyUiGenerateSuccess = async (response: AiToolProcessSuccessResponse) => {
try {
const result = response.imageList[0];
// 刷新次数
refreshToolEquityUserUseInfo(modelRenderToolKey);
const sizeInfo = await getImageSizeInfo(result);
// 设置layout显示
drawStepOperateLayoutRef.current?.setGenerateImage({
url: result,
...sizeInfo,
});
} catch (e) {
console.error(e);
}
};
// 精确渲染
const generatePreciseRendering = () => {
const baseImage = baseImageCardRef.current?.uploadImage;
if (!baseImage) {
return;
}
const styleImage = styleImageCardRef.current?.uploadImage;
drawStepOperateLayoutRef.current?.setShowType('PREVIEW');
setGenerateParams({
baseImage: baseImage.largeUrl || '',
styleImage: styleImage?.largeUrl || '',
styleAlias: [],
});
generateComfyUiPreciseRenderingModalRef.current?.generateTask({
seed: getRandomNum(),
baseImageUrl: baseImage.largeUrl || '',
});
};
// 高级生图渲染
const generateStandardRendering = (styleArgs: GetAdvanceDrawLeafGenerateArgsByMidsType) => {
const baseImage = baseImageCardRef.current?.uploadImage;
if (!baseImage) {
return;
}
const styleImage = styleImageCardRef.current?.uploadImage;
const {
modelName = '',
loraParamses = [],
builtStyleReferImage,
exactRender,
styleAlias,
promptPrefix = '',
negativePromptPrefix = '',
samplerName = 'euler',
scheduler = 'normal',
steps = 30,
cfg = 3.5,
} = styleArgs || {};
const dealPromptsInfo = mergeDrawPromptStacks({
prompts: {
placeholder: description,
keyword: description,
},
promptsPrefix: {
placeholder: '',
keyword: `${promptPrefix},${spatialPositionConfig[styleCategoryList[spatialCategoryIndex].mid][selectPositionIndex].description},${styleAlias?.[0]}`,
},
negativePromptsPrefix: {
placeholder: '',
keyword: negativePromptPrefix,
},
defaultNegativeKeyword: ADVANCE_DRAW_DEFAULT_NEGATIVE_KEYWORDS,
});
drawStepOperateLayoutRef.current?.setShowType('PREVIEW');
setGenerateParams({
baseImage: baseImage.largeUrl || '',
styleImage: styleImage?.largeUrl || '',
styleAlias: styleAlias || [],
});
generateComfyUiModalRef.current?.generateTask({
// 精确渲染
exactRender: exactRender || false,
baseImage: {
url: baseImage.largeUrl,
width: baseImage.width,
height: baseImage.height,
guidanceStart: 0,
guidanceEnd: 1,
weight: 0.6,
model: 'XL/xinsir-controlnet-union-sdxl-1.0_promax.safetensors',
...((styleAlias || []).findIndex((value) => value.search('通用') > -1) > -1
? {
preprocessor: 'none',
controlNetKey: 'fineOutline',
}
: {
preprocessor: 'LineArtPreprocessor',
controlNetKey: 'smoothSontours',
}),
enable: true,
},
...(styleImage
? {
styleReferImage: {
url: styleImage.largeUrl,
weight: 0.6,
guidanceStart: 0,
guidanceEnd: 1,
},
}
: {}),
sizeType: 'ULTRA_2K',
seed: getRandomNum(),
builtStyleReferImage,
prompt: dealPromptsInfo.prompts.keyword,
negativePrompt: dealPromptsInfo.negativePrompts.keyword,
modelName,
loraParamses,
// 材质锁定配置项
lockingMaterialType,
enableSpatialDepth: false,
cfg,
// 迭代步数
steps,
// 采样器名称
samplerName,
// 调度器
scheduler,
imageGenerateNum: 1,
});
};
// 点击开始创作
const onStepStart = () => {
if (!toolEquityCountWrapRef.current?.verifyUseStatus()) {
return;
}
const styleArgs = styleCategoryGridRef.current?.getComfyUIDrawLeafGenerateArgsByMids?.();
if (preciseRender) {
generatePreciseRendering();
} else {
generateStandardRendering(styleArgs as GetAdvanceDrawLeafGenerateArgsByMidsType);
}
};
// 点击一级类目
useAsyncEffect(async () => {
let categoryList = await requestAdvanceDrawFirstStyleCategoryList();
categoryList = categoryList.filter((value) => styleCategoryMids.includes(value.mid));
if (categoryList[0].justCategory) {
const subCategoryList = await requestAdvanceDrawSubStyleConfigCategory(categoryList[0].mid);
// 替换当前类目下的子类目信息
categoryList.splice(0, 1, {
...categoryList[0],
children: subCategoryList,
});
}
setStyleCategoryList(categoryList);
}, []);
useMount(() => {
const url = decodeImageUrl(searchParams.get('url') || '');
const width = searchParams.get('width');
const height = searchParams.get('height');
// 工具快捷使用
if (url && height && width) {
baseImageCardRef.current?.setUploadImage({
largeUrl: url,
thumbUrl: url,
width: Number(width),
height: Number(height),
});
setSearchParams({});
}
});
// 第一步 底图的上传
const firstStepRender = (uploadImage: UploadImageType | null) => {
return (
<>
<div className={cx('first_content')}>
<UploadImageCard.Card
style={{
minHeight: '100%',
height: 'auto',
}}
ref={baseImageCardRef}
onUploadImageChange={onBaseImageChange}
enableKjlUpload
enableScreenshot={productType === 'JZXZ'}
uploadImageIcon={{
customUploadBtn: (className) => {
return (
<>
<div
className={className}
onClick={() => {
imageSelectorWrapModalRef.current?.setModalStatus('SELECT_MODAL');
}}
>
{t('HuabanUploadBtn-rWrt')}
</div>
</>
);
},
}}
onScreenshotSuccess={(value) => {
imageSelectorWrapModalRef.current?.setModalStatus('LEAFER_FRAME');
imageSelectorWrapModalRef.current?.onGenerateFrame({
width: value.width,
height: value.height,
url: value.largeUrl,
});
setTimeout(() => {
imageSelectorWrapModalRef.current?.setOperationType('CLIP_FRAME');
}, 600);
}}
hidden={!!uploadImage}
/>
<div className={cx('image_wrap')} hidden={!uploadImage}>
<CoolImage
placeholder={{ type: 'loadingIcon' }}
className={cx('image')}
style={{ objectFit: 'contain' }}
src={uploadImage?.largeUrl}
alt=""
/>
</div>
<div className={cx('operator_btn_wrap')} hidden={!uploadImage}>
<IconFont
type="micro-icon-edit"
className={cx('operator_icon')}
onClick={() => {
imageSelectorWrapModalRef.current?.setModalStatus('LEAFER_FRAME');
// 画板没有原图信息的时候 先创建画板
const originImageInfo = imageSelectorWrapModalRef.current?.getOriginalImageInfo();
if (!originImageInfo?.url && uploadImage) {
imageSelectorWrapModalRef.current?.onGenerateFrame({
url: uploadImage?.largeUrl,
width: uploadImage.width,
height: uploadImage.height,
});
}
}}
/>
<IconFont
type="micro-icon-trash-can"
className={cx('operator_icon')}
onClick={() => {
baseImageCardRef.current?.setUploadImage(null);
imageSelectorWrapModalRef.current?.clearFrame();
}}
/>
</div>
</div>
</>
);
};
// 第二步内容
const secondStepRender = (
<>
<div className={cx('first_category_wrap')}>
{styleCategoryList.map((value, index) => (
<div
key={value.mid}
className={cx('first_category_item', {
active: index === spatialCategoryIndex,
})}
onClick={async () => {
setSpatialCategoryIndex(index);
styleCategoryGridRef.current?.setFirstCategoryIndex(index);
if (!value.children && value.justCategory) {
try {
styleCategoryGridRef.current?.setSecondCategoryRequesting(true);
const subCategoryList = await requestAdvanceDrawSubStyleConfigCategory(value.mid);
// 替换当前类目下的子类目信息
setStyleCategoryList(
styleCategoryList.map((value1, index1) => {
if (index1 === index) {
return {
...value1,
children: subCategoryList,
};
}
return value1;
}),
);
styleCategoryGridRef.current?.setSecondCategoryRequesting(false);
} catch (e) {
styleCategoryGridRef.current?.setSecondCategoryRequesting(false);
console.error(e);
}
}
}}
>
{value.name}
</div>
))}
</div>
<div className={cx('spatial_position_wrap')}>
{spatialPositionConfig[styleCategoryList[spatialCategoryIndex]?.mid || '']?.map(
(value, index) => (
<div
className={cx('spatial_position_item', {
active: index === selectPositionIndex,
})}
key={index}
onClick={() => {
setSelectPositionIndex(index);
}}
>
<AiToolSquareCoverCard
coverUrl={value.coverUrl}
extra={<span className={cx('spatial_position_name')}>{value.name}</span>}
/>
</div>
),
)}
</div>
</>
);
const secondCategoryPreciseRendering = (url: string) => (
<>
{/* 二级类目前新增精确渲染 */}
<div
className={cx('second_category_item', {
active: preciseRender,
})}
onClick={() => {
setPreciseRender(true);
}}
>
<AiToolSquareCoverCard
coverUrl={url}
extra={
<>
<div className={cx('second_category_recommended')}>
<span>推荐</span>
</div>
<span className={cx('second_category_name')}>精确渲染</span>
</>
}
/>
</div>
</>
);
// 第三步内容
const thirdStepRender = (
<>
<ModelRenderStyleCategoryGrid
ref={styleCategoryGridRef}
categoryList={styleCategoryList}
onCategoryListChange={(list) => {
setStyleCategoryList(list);
}}
secondCategoryExtra={[
secondCategoryPreciseRendering(
'https://gd-hbimg.huaban.com/d113fdba55b570c14f9e6dd85053e20fe66e59f5cd9c6-KWo2yS_fw1200webp',
),
secondCategoryPreciseRendering(
'https://gd-hbimg.huaban.com/4d623892958842956954557d10427f47f7331c3bcfbdc-Xa8fgu_fw1200webp',
),
]}
hideActive={preciseRender}
onSecondCategoryChange={() => {
setPreciseRender(false);
}}
/>
{!preciseRender && (
<>
<div className={cx('step_title')} style={{ marginTop: 40 }}>
更多设置
</div>
<div className={cx('step_sub_title')}>
上传风格参考图和添加更多设置可以定制化生成对应风格,进一步加强生成图的风格准确性,此处做选填。
</div>
<Collapse ghost expandIconPosition="end">
<Panel header="上传参考图(选填)" key="reference">
<div className={cx('reference_image_wrap')}>
<UploadImageCard>
{() => <UploadImageCard.Card hideDeleteBtn={false} ref={styleImageCardRef} />}
</UploadImageCard>
</div>
</Panel>
<Panel header="更多设置(选填)" key="more">
<div className={cx('more_settings_wrap')}>
<ThemeConfigProvider
themeConfigs={{
JKJL: {
textArea: {
borderColor: '#dfdfdf',
borderWidth: '1px',
},
segmented: {
'--border-width': '1px',
'--border-color': '#dfdfdf',
} as CSSProperties,
},
}}
>
<AiToolBlockItem title="描述词">
<ThemeTextArea
placeholder="写下你的绘画想法和创意"
value={description}
onChange={(e) => {
setDescription(e.target.value);
}}
/>
</AiToolBlockItem>
<AiToolBlockItem
title={
<span>
{t('AiTools-Draw-ControlNet-BaseImage-WREs5')}
<QuestionCircleOutlined
style={{ marginLeft: 4 }}
onClick={() => {
materialIntroduceModalRef.current?.setModalStatus('INTRODUCE');
}}
/>
</span>
}
extra={
<ThemeSegmented
block
style={{ width: 180 }}
value={lockingMaterialType}
options={lockingMaterialList.map((item) => ({
label: t(item.labelKey),
value: item.value,
}))}
onChange={(item) => {
setLockingMaterialType(item.value);
}}
/>
}
/>
</ThemeConfigProvider>
</div>
</Panel>
</Collapse>
;
</>
)}
</>
);
// 生成参数弹窗
const generateParamsContent = (
<div>
<ToggleGenerateInfoPanelItem title="创意描述">
{() => {
return (
<Paragraph ellipsis={{ rows: 4 }}>
<span style={{ margin: '10px 0 0', color: 'rgb(255 255 255 / 80%)' }}>
{description || '无'}
</span>
</Paragraph>
);
}}
</ToggleGenerateInfoPanelItem>
<ToggleGenerateInfoPanelItem
title="创作类目"
description={generateParams.styleAlias?.join('/')}
/>
<ToggleGenerateInfoPanelItem
title="空间位置"
description={
spatialPositionConfig[styleCategoryList[spatialCategoryIndex]?.mid || '']?.[
selectPositionIndex
].name || ''
}
/>
<ToggleGenerateInfoPanelItem title="底图">
{(imageCardClassName) => {
return (
<div className={imageCardClassName}>
<Image
src={generateParams.baseImage}
preview
width="100%"
height={154}
style={{
objectFit: 'contain',
}}
/>
</div>
);
}}
</ToggleGenerateInfoPanelItem>
{generateParams.styleImage && (
<ToggleGenerateInfoPanelItem title="参考图">
{(imageCardClassName) => {
return (
<div className={imageCardClassName}>
<Image
src={generateParams.styleImage}
preview
width="100%"
height={154}
style={{
objectFit: 'contain',
}}
/>
</div>
);
}}
</ToggleGenerateInfoPanelItem>
)}
<ToggleGenerateInfoPanelItem
title="材质锁定"
description={t(LockingMaterialTypeEnum[lockingMaterialType || 'OFF'])}
/>
</div>
);
return (
<>
<ToolVerticalIntroduceLayoutPC2
toolName={modelRenderToolName}
description="一键AI渲染酷家乐室内设计模型,比传统渲染方式更加真实,细腻,高效~支持多种室内风格渲染!"
show={introduceLayoutShow}
onClickUseBtn={() => {
setIntroduceLayoutShow(false);
}}
content={
<>
<ToolVerticalIntroduceLayoutContent1
items={[
{
beforeUrl:
'https://gd-hbimg.huaban.com/dc74bbd45daaaf4973d71e64785ed7e2d6cb0eed5ec75-7Gc6aa',
afterUrl:
'https://gd-hbimg.huaban.com/63a044eec1c55566f7304e79d1f1c2828c51c8ba9d774-4jCT7E',
},
{
beforeUrl:
'https://gd-hbimg.huaban.com/ffefde120630092f0244bf346c1d974e51e5dd9bb5fe2-NvzNpK',
afterUrl:
'https://gd-hbimg.huaban.com/2d776cae122ab64c90697906540a706664ce21809d1e6-XyYWf1',
},
{
beforeUrl:
'https://gd-hbimg.huaban.com/6519e79f2c37ee2a1b75025376b10f6d574edfc4f0d17-8ReO7g',
afterUrl:
'https://gd-hbimg.huaban.com/82c0c13e8abcb63243697acde385fc569b9b3fd5ba214-nh471F',
},
]}
/>
</>
}
/>
<UploadImageCard>
{(uploadImage) => (
<>
<ProductAuth productTypes={['JKJL']}>
<DrawStepOperateLayoutPC
trackToolName={TRACK_MODEL_RENDER_NAME}
ref={drawStepOperateLayoutRef}
downloadConfig={{
enlargeDownloadOptions,
}}
items={[
{
title: '上传模型底图',
subTitle: '大师级渲染,从上传底图开始!',
content: firstStepRender(uploadImage),
beforeNextStep: async () => {
if (!baseImageCardRef.current?.uploadImage) {
message.warn('请先上传底图');
return false;
}
return true;
},
},
{
title: '选择空间位置',
subTitle: '选择正确的位置可以确保生成图更准确。',
content: secondStepRender,
},
{
title: '选择渲染风格',
subTitle: '选择想要生成的风格大模型,可以让生成结果更偏向自己的喜好。',
content: thirdStepRender,
},
]}
onStepStart={onStepStart}
uploadImage={uploadImage}
resultExtra={
<>
{/* 快捷使用 */}
<KjlResultQuickAccessBox
className={cx('quick_access_box')}
extraBottomItems={[
{
title: '迭代渲染',
iconKey: 'micro-icon-iterative-render',
onClick: () => {
const generateImage = drawStepOperateLayoutRef.current?.generateImage;
if (generateImage) {
drawStepOperateLayoutRef.current.setShowType('STEP');
drawStepOperateLayoutRef.current.setCurrent(0);
baseImageCardRef.current?.setUploadImage({
thumbUrl: generateImage.url,
largeUrl: generateImage.url,
width: generateImage.width,
height: generateImage.height,
});
}
},
},
]}
/>
{/* 参数明细 */}
<ToggleGenerateInfoPopover
placement="leftTop"
className={cx('generate_params_wrap')}
content={generateParamsContent}
>
{(open) => {
return <IconFont type={open ? 'micro-icon-close' : 'micro-icon-tip'} />;
}}
</ToggleGenerateInfoPopover>
</>
}
stepFooterExtra={
<ToolEquityCountWrap
toolKey={modelRenderToolKey}
showToolName={modelRenderToolName}
trackToolName={TRACK_MODEL_RENDER_NAME}
ref={toolEquityCountWrapRef}
>
<ToolBenefitOperator
style={{
marginTop: 8,
}}
toolKey={modelRenderToolKey}
trackToolName={TRACK_MODEL_RENDER_NAME}
showToolEquityInfo={() => {
toolEquityCountWrapRef.current?.showToolEquityInfo();
}}
showToolCountUsageIntro={() => {
toolEquityCountWrapRef.current?.showToolCountUsageIntro();
}}
showToolBuyCount={() => {
toolEquityCountWrapRef.current?.showToolBuyCount();
}}
/>
</ToolEquityCountWrap>
}
/>
</ProductAuth>
<ProductAuth productTypes={['JZXZ']}>
<DrawStepOperateLayoutPC
trackToolName={TRACK_MODEL_RENDER_NAME}
ref={drawStepOperateLayoutRef}
downloadConfig={{
enlargeDownloadOptions,
}}
items={[
{
title: '选择模型场景',
subTitle: '请根据实际情况选择合适的渲染场景',
content: (
<>
<div className={cx('scenario_wrap')}>
{scenarioListItem.map((item, index) => (
<div
key={index}
className={cx('scenario_item', {
active: modelScenarioActiveIndex === index,
})}
onClick={() => {
setModelScenarioActiveIndex(index);
}}
>
<div className={cx('scenario_item_image')}>
<img
src={item.coverUrl}
alt={item.name}
className={cx('scenario_image')}
/>
</div>
<ThemeButton
size="large"
shape="circle"
className={cx('start_btn', {
no_active: modelScenarioActiveIndex !== index,
})}
>
{item.name}
</ThemeButton>
</div>
))}
</div>
</>
),
},
{
title: '上传模型底图',
subTitle: '大师级渲染,从上传底图开始!',
content: firstStepRender(uploadImage),
beforeNextStep: async () => {
if (!baseImageCardRef.current?.uploadImage) {
message.warn('请先上传底图');
return false;
}
return true;
},
},
{
title: '选择空间位置',
subTitle: '选择正确的位置可以确保生成图更准确。',
content: secondStepRender,
},
{
title: '选择渲染风格',
subTitle: '选择想要生成的风格大模型,可以让生成结果更偏向自己的喜好。',
content: thirdStepRender,
},
]}
onStepStart={onStepStart}
uploadImage={uploadImage}
resultExtra={
<>
{/* 快捷使用 */}
<KjlResultQuickAccessBox
className={cx('quick_access_box')}
extraBottomItems={[
{
title: '迭代渲染',
iconKey: 'micro-icon-iterative-render',
onClick: () => {
const generateImage = drawStepOperateLayoutRef.current?.generateImage;
if (generateImage) {
drawStepOperateLayoutRef.current.setShowType('STEP');
drawStepOperateLayoutRef.current.setCurrent(0);
baseImageCardRef.current?.setUploadImage({
thumbUrl: generateImage.url,
largeUrl: generateImage.url,
width: generateImage.width,
height: generateImage.height,
});
}
},
},
]}
/>
{/* 参数明细 */}
<ToggleGenerateInfoPopover
placement="leftTop"
className={cx('generate_params_wrap')}
content={generateParamsContent}
>
{(open) => {
return <IconFont type={open ? 'micro-icon-close' : 'micro-icon-tip'} />;
}}
</ToggleGenerateInfoPopover>
</>
}
stepFooterExtra={
<ToolEquityCountWrap
toolKey={modelRenderToolKey}
showToolName={modelRenderToolName}
trackToolName={TRACK_MODEL_RENDER_NAME}
ref={toolEquityCountWrapRef}
>
<ToolBenefitOperator
style={{
marginTop: 8,
}}
toolKey={modelRenderToolKey}
trackToolName={TRACK_MODEL_RENDER_NAME}
showToolEquityInfo={() => {
toolEquityCountWrapRef.current?.showToolEquityInfo();
}}
showToolCountUsageIntro={() => {
toolEquityCountWrapRef.current?.showToolCountUsageIntro();
}}
showToolBuyCount={() => {
toolEquityCountWrapRef.current?.showToolBuyCount();
}}
/>
</ToolEquityCountWrap>
}
/>
</ProductAuth>
</>
)}
</UploadImageCard>
{/* 迁移内容的原图片效果图库 */}
<ImageSelectorWrapModal
ref={imageSelectorWrapModalRef}
queryTagImages={{
categoryList: [
{
name: '室内',
tag: '室内底图',
sourceType: 'JZXZ',
},
],
introduce: t('AiTools-DecorationDesign-Operate-pc-f4eJ'),
modalTitle: t('AiTools-Draw-ControlNet-BaseImage-b2tNh'),
iconClassName: cx('style_refer_image'),
}}
onFinish={onBaseImageFinish}
hideDiyDraw
/>
<AiToolGenerateModal
displayType="MASK"
className={cx('generate_mask_container')}
customerRef={generateComfyUiModalRef}
toolKey={modelRenderToolKey}
trackToolName={TRACK_MODEL_RENDER_NAME}
request={requestComfyUIDrawGenerate}
speedupKey={modelRenderSpeedupKey}
pollingConfig={{
processingType: 'COMFYUI_COMPOSE',
imageDetectMode: 'NONE',
}}
onGenerateSuccess={onComfyUiGenerateSuccess}
onCancel={() => {
// 蒙层关闭 回到进度展示
drawStepOperateLayoutRef.current?.setShowType('STEP');
}}
/>
{/* 精确渲染 */}
<AiToolGenerateModal
displayType="MASK"
className={cx('generate_mask_container')}
customerRef={generateComfyUiPreciseRenderingModalRef}
toolKey={modelRenderToolKey}
trackToolName={TRACK_MODEL_RENDER_NAME}
request={requestModelRenderImage}
speedupKey={modelRenderSpeedupKey}
pollingConfig={{
processingType: 'COMFYUI_COMPOSE',
imageDetectMode: 'NONE',
}}
onGenerateSuccess={onComfyUiGenerateSuccess}
onCancel={() => {
// 蒙层关闭 回到进度展示
drawStepOperateLayoutRef.current?.setShowType('STEP');
}}
/>
<MaterialIntroduceModal ref={materialIntroduceModalRef} />
</>
);
};
export default ModelRenderOperatePC;
步骤一直显示的是4步 ,只是 modelScenarioActiveIndex !== 1 跳过第三步直接到第四步
最新发布