Files
xiaoxia-saas/apps/web/src/pages/ai-avatar/components/TitleLibraryModal.tsx
T
deploy-agent f72d640e8c
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 29s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 33s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 1m23s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 1m40s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 1m46s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m2s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m48s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m55s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 4m14s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 5m21s
AI Code Review / AI Code Review (pull_request) Successful in 6m38s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 8m15s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 10m40s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 24m23s
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 4s
CI/CD Pipeline / Canary Release to Production (pull_request) Failing after 161h48m7s
CI/CD Pipeline / Build Production Worker Image (pull_request) Failing after 161h48m10s
CI/CD Pipeline / Build Production Web Image (pull_request) Failing after 161h48m10s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Failing after 162h11m54s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 162h11m55s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 162h11m57s
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Failing after 162h11m59s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Failing after 162h12m0s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 162h12m3s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 162h12m4s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 162h12m4s
CI/CD Pipeline / Check push changed paths (pull_request) Failing after 162h12m39s
CI/CD Pipeline / Deploy Production (pull_request) Failing after 162h22m53s
CI/CD Pipeline / Build Production API Image (pull_request) Failing after 162h22m56s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 162h46m41s
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Failing after 162h46m46s
style(ai-avatar): prettier 格式化 PanelTitleConfig/TitleLibraryModal
修复 #1828 前端对接代码的 prettier check 失败,仅格式调整无逻辑改动。
2026-09-09 21:11:17 +08:00

98 lines
3.3 KiB
TypeScript

/**
* AI数字人 — 标题库选择弹窗
* 复用智能剪辑的标题库 API,选择标题后填入输入框
*/
import React, { useEffect, useState } from "react"
import { getTitles } from "@/api/titles"
import type { TitleItem } from "@/api/titles/types"
interface TitleLibraryModalProps {
open: boolean
onClose: () => void
onSelect: (title: string) => void
}
const TitleLibraryModal: React.FC<TitleLibraryModalProps> = ({ open, onClose, onSelect }) => {
const [titles, setTitles] = useState<TitleItem[]>([])
const [loading, setLoading] = useState(false)
const [search, setSearch] = useState("")
useEffect(() => {
if (!open) return
setLoading(true)
getTitles()
.then((items) => setTitles(items))
.catch(() => setTitles([]))
.finally(() => setLoading(false))
}, [open])
const filtered = titles.filter(
(t) => !search || t.content.toLowerCase().includes(search.toLowerCase()),
)
if (!open) return null
return (
<div className="aa-modal-overlay" onClick={onClose}>
<div className="aa-modal" onClick={(e) => e.stopPropagation()} style={{ maxWidth: 600 }}>
<div className="aa-modal__header">
<span className="aa-modal__title">从标题库选择</span>
<button className="aa-modal__close" onClick={onClose}></button>
</div>
<div className="aa-modal__body">
<div style={{ marginBottom: 12 }}>
<input
className="aa-input"
placeholder="搜索标题..."
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
</div>
{loading ? (
<div style={{ textAlign: "center", padding: 40, color: "#8c8ca1" }}>加载中...</div>
) : filtered.length === 0 ? (
<div style={{ textAlign: "center", padding: 40, color: "#8c8ca1" }}>
暂无标题,请先在标题库创建
</div>
) : (
<div style={{ maxHeight: 400, overflowY: "auto" }}>
{filtered.map((t) => (
<div
key={t.id}
style={{
padding: "12px 16px",
marginBottom: 8,
background: "#f8f8fc",
borderRadius: 8,
cursor: "pointer",
transition: "background 0.2s",
}}
onMouseEnter={(e) => (e.currentTarget.style.background = "#eef0ff")}
onMouseLeave={(e) => (e.currentTarget.style.background = "#f8f8fc")}
onClick={() => {
onSelect(t.content)
onClose()
}}
>
<div style={{ fontSize: 14, color: "#1a1a2e", marginBottom: 4 }}>{t.content}</div>
<div style={{ fontSize: 12, color: "#8c8ca1" }}>
{t.word_count ?? t.content.length}字 ·{" "}
{t.created_at ? new Date(t.created_at).toLocaleDateString() : ""}
</div>
</div>
))}
</div>
)}
</div>
<div className="aa-modal__footer">
<button className="aa-btn" onClick={onClose}>
取消
</button>
</div>
</div>
</div>
)
}
export default TitleLibraryModal