diff --git a/himarket-web/himarket-frontend/src/components/ProductHeader.tsx b/himarket-web/himarket-frontend/src/components/ProductHeader.tsx index de32525b3..d2142ddb7 100644 --- a/himarket-web/himarket-frontend/src/components/ProductHeader.tsx +++ b/himarket-web/himarket-frontend/src/components/ProductHeader.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from "react"; +import React, { useState, useEffect, useImperativeHandle, forwardRef } from "react"; import { Typography, Button, Modal, Select, message, Popconfirm, Input, Pagination, Spin } from "antd"; import { ApiOutlined, CheckCircleFilled, ClockCircleFilled, ExclamationCircleFilled, PlusOutlined, RobotOutlined, BulbOutlined } from "@ant-design/icons"; import { useParams } from "react-router-dom"; @@ -10,6 +10,10 @@ import APIs, { getProductSubscriptionStatus, type ISubscription } from "../lib/a const { Title, Paragraph } = Typography; const { Search } = Input; +export interface ProductHeaderHandle { + showManageModal: () => void; +} + interface ProductHeaderProps { name: string; description: string; @@ -19,6 +23,7 @@ interface ProductHeaderProps { agentConfig?: IAgentConfig; updatedAt?: string; productType?: 'REST_API' | 'MCP_SERVER' | 'AGENT_API' | 'MODEL_API' | 'AGENT_SKILL'; + onSubscriptionStatusChange?: (hasSubscription: boolean) => void; } type UnwrapPromise = T extends Promise ? U : T; @@ -42,7 +47,7 @@ const getIconUrl = (icon?: IProductIcon, defaultIcon?: string): string => { } }; -export const ProductHeader: React.FC = ({ +export const ProductHeader = forwardRef(({ name, description, icon, @@ -51,7 +56,8 @@ export const ProductHeader: React.FC = ({ agentConfig, updatedAt, productType, -}) => { + onSubscriptionStatusChange, +}, ref) => { const { apiProductId, mcpProductId, @@ -122,6 +128,18 @@ export const ProductHeader: React.FC = ({ } }, [productId, shouldShowSubscribeButton]); + // 暴露给父组件的方法 + useImperativeHandle(ref, () => ({ + showManageModal, + })); + + // 订阅状态变化时通知父组件 + useEffect(() => { + if (subscriptionStatus !== undefined && onSubscriptionStatusChange) { + onSubscriptionStatusChange(subscriptionStatus.hasSubscription); + } + }, [subscriptionStatus, onSubscriptionStatusChange]); + // 获取订阅详情(用于管理弹窗) const fetchSubscriptionDetails = async (page: number = 1, search: string = ''): Promise => { if (!productId) return Promise.resolve(); @@ -589,4 +607,4 @@ export const ProductHeader: React.FC = ({ ); -}; \ No newline at end of file +}); \ No newline at end of file diff --git a/himarket-web/himarket-frontend/src/pages/ModelDetail.tsx b/himarket-web/himarket-frontend/src/pages/ModelDetail.tsx index b733aa29c..b597d2b7a 100644 --- a/himarket-web/himarket-frontend/src/pages/ModelDetail.tsx +++ b/himarket-web/himarket-frontend/src/pages/ModelDetail.tsx @@ -1,7 +1,8 @@ -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState, useCallback } from "react"; import { useParams, useNavigate } from "react-router-dom"; import { Layout } from "../components/Layout"; import { ProductHeader } from "../components/ProductHeader"; +import type { ProductHeaderHandle } from "../components/ProductHeader"; import { Alert, Button, @@ -29,6 +30,12 @@ function ModelDetail() { const [data, setData] = useState(); const [modelConfig, setModelConfig] = useState(); const [selectedModelDomainIndex, setSelectedModelDomainIndex] = useState(0); + const [hasSubscription, setHasSubscription] = useState(false); + const headerRef = useRef(null); + + const handleSubscriptionStatusChange = useCallback((subscribed: boolean) => { + setHasSubscription(subscribed); + }, []); useEffect(() => { @@ -260,11 +267,13 @@ function ModelDetail() { @@ -510,10 +519,15 @@ function ModelDetail() { icon={} className="rounded-lg mt-4" onClick={() => { - navigate("/chat", { state: { selectedProduct: data } }); + if (hasSubscription) { + navigate("/chat", { state: { selectedProduct: data } }); + } else { + message.warning('请先订阅该产品后再进行对话测试'); + headerRef.current?.showManageModal(); + } }} > - 开始对话测试 + {hasSubscription ? '开始对话测试' : '订阅并开始对话'} ),