f0dce3d41d
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4m1s
CI/CD Pipeline / Build Staging API Image (push) Successful in 4m58s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 5m2s
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 4m25s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 5m50s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 5m53s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 7m14s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m15s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m54s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 48s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m42s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 10m31s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 10m39s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m3s
AI Code Review / AI Code Review (pull_request) Successful in 7m44s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 12m8s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 12m54s
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
- useStep2Materials 在调用 /clips/from-assets 后获取服务端 clips 并通过回调解构 - GeneratePage 将 serverClips 传递给 FrontendPreviewPlayer - buildPlaybackSegments 优先使用服务端 clips 的 start_time/duration,无 clips 时 fallback 到本地构建 - 确保预览与最终生成结果一致(片段数量、起始时间随机)
102 lines
3.2 KiB
TypeScript
102 lines
3.2 KiB
TypeScript
/**
|
||
* Step 2 素材选择组件
|
||
*/
|
||
import React from "react"
|
||
import type { TemplateSegment } from "@/api/templates/types"
|
||
import type { EditPlanClip } from "@/api/template-editor"
|
||
import { useStep2Materials } from "../hooks/useStep2Materials"
|
||
import MaterialModeTabs from "./material/MaterialModeTabs"
|
||
import ManualMaterialList from "./material/ManualMaterialList"
|
||
import SmartMatchInput from "./material/SmartMatchInput"
|
||
import SmartMatchResults from "./material/SmartMatchResults"
|
||
|
||
interface Step2MaterialSelectProps {
|
||
materialMode: "manual" | "auto"
|
||
onMaterialModeChange: (mode: "manual" | "auto") => void
|
||
selectedMaterials: string[]
|
||
onSelectedMaterialsChange: (ids: string[]) => void
|
||
smartSelectedIds: string[]
|
||
onSmartSelectedIdsChange: (ids: string[]) => void
|
||
/** 当前选中的模板/草稿 ID,用于自动保存 */
|
||
selectedTemplate?: string
|
||
/** 当前模板的 segments(用于构建 clips duration) */
|
||
templateSegments?: TemplateSegment[]
|
||
/** 服务端 clips 创建成功后的回调 */
|
||
onServerClipsChange?: (clips: EditPlanClip[]) => void
|
||
}
|
||
|
||
const Step2MaterialSelect: React.FC<Step2MaterialSelectProps> = (props) => {
|
||
const m = useStep2Materials(props)
|
||
|
||
return (
|
||
<div className="xx-form-section">
|
||
<h3>📦 选择素材</h3>
|
||
|
||
<MaterialModeTabs mode={m.materialMode} onModeChange={m.onMaterialModeChange} />
|
||
|
||
<div className="xx-form-field" style={{ marginTop: 12 }}>
|
||
<label>选择视频库</label>
|
||
<select
|
||
value={m.selectedLibraryId}
|
||
onChange={(e) => m.setSelectedLibraryId(e.target.value)}
|
||
>
|
||
{m.libraries.map((lib) => (
|
||
<option key={lib.id} value={lib.id}>
|
||
{lib.name}
|
||
</option>
|
||
))}
|
||
</select>
|
||
</div>
|
||
|
||
{m.materialMode === "manual" && (
|
||
<>
|
||
<div
|
||
style={{
|
||
marginTop: 14,
|
||
display: "flex",
|
||
alignItems: "center",
|
||
gap: 10,
|
||
}}
|
||
>
|
||
<span className="xx-pill xx-pill-ok">已选 {m.selectedMaterials.length} 个素材</span>
|
||
</div>
|
||
|
||
<ManualMaterialList
|
||
materials={m.materials}
|
||
materialsLoading={m.materialsLoading}
|
||
selectedMaterials={m.selectedMaterials}
|
||
onToggle={m.handleToggleMaterial}
|
||
/>
|
||
</>
|
||
)}
|
||
|
||
{m.materialMode === "auto" && (
|
||
<div className="xx-smart-match-section">
|
||
<SmartMatchInput
|
||
matching={m.smartMatching}
|
||
onMatch={m.handleSmartMatch}
|
||
hasMatched={m.hasMatched}
|
||
onRefresh={m.handleRefreshMatch}
|
||
materialsCount={m.materials.items.length}
|
||
loading={m.materialsLoading}
|
||
/>
|
||
|
||
<SmartMatchResults
|
||
matchedAssets={m.smartMatchedResults}
|
||
selectedIds={m.smartSelectedIds}
|
||
matching={m.smartMatching}
|
||
hasMatched={m.hasMatched}
|
||
onToggle={m.handleToggleSmartSelect}
|
||
onSelectAll={m.handleSelectAllMatched}
|
||
onClear={m.handleClearSmartSelect}
|
||
formatDuration={m.formatDuration}
|
||
selectedTotalDuration={m.smartSelectedTotalDuration}
|
||
/>
|
||
</div>
|
||
)}
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export default Step2MaterialSelect
|