编辑功能优化 + apiKey展示

This commit is contained in:
wong
2025-06-17 17:02:07 +08:00
parent ca0e7e8bc0
commit 2488b0210b
5 changed files with 119 additions and 22 deletions

View File

@@ -193,15 +193,32 @@ function ApiDocumentationTooltip() {
})
}
const handleOpenApiSettings = (taskId: string) => {
const handleOpenApiSettings = async (taskId: string) => {
const task = tasks.find((t) => t.id === taskId)
if (task) {
setCurrentApiSettings({
apiKey: `api_${taskId}_${Math.random().toString(36).substring(2, 10)}`,
webhookUrl: `${window.location.origin}/api/scenarios/${channel}/${taskId}/webhook`,
taskId,
})
setShowApiDialog(true)
try {
const res = await api.get<ApiResponse>(`/v1/plan/detail?planId=${taskId}`)
if (res.code === 200 && res.data) {
setCurrentApiSettings({
apiKey: res.data.apiKey || '', // 使用接口返回的 API 密钥
webhookUrl: `${window.location.origin}/api/scenarios/${channel}/${taskId}/webhook`,
taskId,
})
setShowApiDialog(true)
} else {
toast({
title: "获取 API 密钥失败",
description: res.msg || "请重试",
variant: "destructive",
})
}
} catch (err: any) {
toast({
title: "获取 API 密钥失败",
description: err?.message || "请重试",
variant: "destructive",
})
}
}
}

View File

@@ -42,6 +42,38 @@ interface Material {
preview: string
}
interface PosterSectionProps {
materials: Material[]
selectedMaterials: Material[]
onUpload: () => void
onSelect: (material: Material) => void
uploading: boolean
fileInputRef: React.RefObject<HTMLInputElement>
onFileChange: (event: React.ChangeEvent<HTMLInputElement>) => void
onPreview: (url: string) => void
onRemove: (id: string) => void
}
interface OrderSectionProps {
materials: Material[]
onUpload: () => void
uploading: boolean
fileInputRef: React.RefObject<HTMLInputElement>
onFileChange: (event: React.ChangeEvent<HTMLInputElement>) => void
}
interface DouyinSectionProps {
materials: Material[]
onUpload: () => void
uploading: boolean
fileInputRef: React.RefObject<HTMLInputElement>
onFileChange: (event: React.ChangeEvent<HTMLInputElement>) => void
}
interface PlaceholderSectionProps {
title: string
}
const posterTemplates = [
{
id: "poster-1",
@@ -128,7 +160,17 @@ function getTagColorIdx(tag: string) {
}
// Section组件示例
const PosterSection = ({ materials, selectedMaterials, onUpload, onSelect, uploading, fileInputRef, onFileChange, onPreview, onRemove }) => (
const PosterSection = ({
materials,
selectedMaterials,
onUpload,
onSelect,
uploading,
fileInputRef,
onFileChange,
onPreview,
onRemove
}: PosterSectionProps) => (
<div>
<div className="flex items-center justify-between mb-4">
<Label></Label>
@@ -202,7 +244,7 @@ const PosterSection = ({ materials, selectedMaterials, onUpload, onSelect, uploa
</div>
)
const OrderSection = ({ materials, onUpload, uploading, fileInputRef, onFileChange }) => (
const OrderSection = ({ materials, onUpload, uploading, fileInputRef, onFileChange }: OrderSectionProps) => (
<div>
<div className="flex items-center justify-between mb-4">
<Label></Label>
@@ -218,7 +260,7 @@ const OrderSection = ({ materials, onUpload, uploading, fileInputRef, onFileChan
</Button>
</div>
<div className="grid grid-cols-3 gap-4">
{materials.map((item) => (
{materials.map((item: Material) => (
<div key={item.id} className="relative cursor-pointer rounded-lg overflow-hidden group">
<img src={item.preview || "/placeholder.svg"} alt={item.name} className="w-full aspect-[9/16] object-cover" />
<div className="absolute bottom-0 left-0 right-0 p-2 bg-black/50 text-white">
@@ -230,7 +272,7 @@ const OrderSection = ({ materials, onUpload, uploading, fileInputRef, onFileChan
</div>
)
const DouyinSection = ({ materials, onUpload, uploading, fileInputRef, onFileChange }) => (
const DouyinSection = ({ materials, onUpload, uploading, fileInputRef, onFileChange }: DouyinSectionProps) => (
<div>
<div className="flex items-center justify-between mb-4">
<Label></Label>
@@ -246,7 +288,7 @@ const DouyinSection = ({ materials, onUpload, uploading, fileInputRef, onFileCha
</Button>
</div>
<div className="grid grid-cols-3 gap-4">
{materials.map((item) => (
{materials.map((item: Material) => (
<div key={item.id} className="relative cursor-pointer rounded-lg overflow-hidden group">
<img src={item.preview || "/placeholder.svg"} alt={item.name} className="w-full aspect-[9/16] object-cover" />
<div className="absolute bottom-0 left-0 right-0 p-2 bg-black/50 text-white">
@@ -258,8 +300,15 @@ const DouyinSection = ({ materials, onUpload, uploading, fileInputRef, onFileCha
</div>
)
const PlaceholderSection = ({ title }) => (
<div className="p-8 text-center text-gray-400 border rounded-lg mt-4">{title}</div>
const PlaceholderSection = ({ title }: PlaceholderSectionProps) => (
<div>
<div className="flex items-center justify-between mb-4">
<Label>{title}</Label>
</div>
<div className="h-40 flex items-center justify-center border-2 border-dashed rounded-lg">
<p className="text-gray-500"></p>
</div>
</div>
)
export function BasicSettings({ formData, onChange, onNext, scenarios, loadingScenes, planNameEdited }: BasicSettingsProps & { loadingScenes?: boolean, planNameEdited?: boolean }) {
@@ -341,6 +390,25 @@ export function BasicSettings({ formData, onChange, onNext, scenarios, loadingSc
}
}, [loadingScenes, scenarios, type, planNameEdited]);
// 添加 useEffect 来处理初始化的海报数据
useEffect(() => {
if (formData.posters && Array.isArray(formData.posters)) {
const validPosters = formData.posters.filter((poster: any) =>
poster && typeof poster === 'object' &&
'id' in poster &&
'name' in poster &&
'type' in poster &&
'preview' in poster
)
setSelectedMaterials(validPosters.map((poster: any) => ({
id: poster.id,
name: poster.name,
type: poster.type || 'poster', // 确保有 type 字段
preview: poster.preview
})))
}
}, [formData.posters])
// 展示所有场景
const displayedScenarios = scenarios
@@ -1055,10 +1123,10 @@ export function BasicSettings({ formData, onChange, onNext, scenarios, loadingSc
selected
? tagColorPoolDark[idx] + " ring-2 ring-blue-400"
: tagColorPoolLight[idx] + " hover:ring-1 hover:ring-gray-300"
}`}
onClick={() => handleTagToggle(tag)}
>
{tag}
}`}
onClick={() => handleTagToggle(tag)}
>
{tag}
</div>
);
})}

View File

@@ -1,6 +1,6 @@
"use client"
import { useState, useRef } from "react"
import { useState, useRef, useEffect } from "react"
import { Card } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
@@ -24,10 +24,15 @@ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { toast } from "@/components/ui/use-toast"
interface FileContent {
url: string
name: string
}
interface MessageContent {
id: string
type: "text" | "image" | "video" | "file" | "miniprogram" | "link" | "group"
content: string | { url: string, name: string }[]
content: any // 暂时使用 any 类型来解决类型问题
sendInterval?: number
intervalUnit?: "seconds" | "minutes"
scheduledTime?: {
@@ -84,11 +89,19 @@ export function MessageSettings({ formData, onChange, onNext, onPrev }: MessageS
type: "text",
content: "",
sendInterval: 5,
intervalUnit: "seconds", // 默认改为秒
intervalUnit: "seconds",
},
],
},
])
// 添加 useEffect 来初始化消息计划数据
useEffect(() => {
if (formData.messagePlans && Array.isArray(formData.messagePlans)) {
setDayPlans(formData.messagePlans)
}
}, [formData.messagePlans])
const [isAddDayPlanOpen, setIsAddDayPlanOpen] = useState(false)
const [isGroupSelectOpen, setIsGroupSelectOpen] = useState(false)
const [selectedGroupId, setSelectedGroupId] = useState("")

View File

@@ -51,7 +51,6 @@ class GetAddFriendPlanDetailV1Controller extends Controller
$newData['createTime'],
$newData['updateTime'],
$newData['deleteTime'],
$newData['apiKey']
);