From 2ea85019384954d1e044c9cb8e9c8ad4a787ea7e Mon Sep 17 00:00:00 2001 From: fengsilin Date: Wed, 1 Apr 2026 14:43:15 +0800 Subject: [PATCH] =?UTF-8?q?feat(pricing):=20=E9=A6=96=E9=A1=B5=E5=AE=9A?= =?UTF-8?q?=E4=BB=B7=E6=B7=BB=E5=8A=A0=E5=88=86=E9=A1=B5=E5=B9=B6=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E6=B8=A0=E9=81=93=20ID=20=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 首页定价区域添加响应式分页(移动端6/平板8/桌面9) - 渠道列表显示 ID,支持在名称中查看 - 渠道定价卡片添加 ID 标签和使用提示 Banner - 代码示例中展示 API Key 指定渠道的格式 Co-Authored-By: Claude --- .../table/channels/ChannelsColumnDefs.jsx | 5 ++-- .../modal/components/ChannelPricingCard.jsx | 11 ++++++++- .../modal/components/ModelCodeSnippet.jsx | 22 ++++++++--------- web/src/pages/Home/HomePricingFilters.jsx | 24 +++++++++++++++++-- 4 files changed, 46 insertions(+), 16 deletions(-) diff --git a/web/src/components/table/channels/ChannelsColumnDefs.jsx b/web/src/components/table/channels/ChannelsColumnDefs.jsx index b98c3a5..4d33879 100644 --- a/web/src/components/table/channels/ChannelsColumnDefs.jsx +++ b/web/src/components/table/channels/ChannelsColumnDefs.jsx @@ -304,6 +304,7 @@ export const getChannelsColumns = ({ dataIndex: 'name', render: (text, record, index) => { const passThroughEnabled = isRequestPassThroughEnabled(record); + const nameWithId = `${record.id} - ${text}`; const nameNode = record.remark && record.remark.trim() !== '' ? ( - {text} + {nameWithId} ) : ( - {text} + {nameWithId} ); if (!passThroughEnabled) { diff --git a/web/src/components/table/model-pricing/modal/components/ChannelPricingCard.jsx b/web/src/components/table/model-pricing/modal/components/ChannelPricingCard.jsx index 97b07a5..6e19339 100644 --- a/web/src/components/table/model-pricing/modal/components/ChannelPricingCard.jsx +++ b/web/src/components/table/model-pricing/modal/components/ChannelPricingCard.jsx @@ -18,7 +18,7 @@ For commercial licensing, please contact support@quantumnous.com */ import React, { useState, useEffect, useMemo } from 'react'; -import { Card, Avatar, Typography, Table, Tag, Spin } from '@douyinfe/semi-ui'; +import { Card, Avatar, Typography, Table, Tag, Spin, Banner } from '@douyinfe/semi-ui'; import { IconServer } from '@douyinfe/semi-icons'; import { API } from '../../../../../helpers'; @@ -103,6 +103,7 @@ const ChannelPricingCard = ({ // 准备表格数据 const tableData = channelPricingData.map((item, index) => ({ key: item.channel_id || index, + channelId: item.channel_id, channelName: `渠道${['一', '二', '三', '四', '五', '六', '七', '八', '九', '十'][index] || ` ${index + 1}`}`, channelTags: item.tags || [], // 渠道定价的标签列表 channelType: item.channel_type, @@ -125,6 +126,9 @@ const ChannelPricingCard = ({ dataIndex: 'channelName', render: (text, record) => (
+ + ID: {record.channelId} + {text} @@ -237,6 +241,11 @@ const ChannelPricingCard = ({
+ ({ from openai import OpenAI client = OpenAI( - api_key="", + api_key="-", base_url="__BASE_URL__" ) @@ -66,7 +66,7 @@ print(response.choices[0].message.content) import com.openai.OpenAI; import com.openai.models.*; -OpenAI client = new OpenAI("", "__BASE_URL__"); +OpenAI client = new OpenAI("-", "__BASE_URL__"); ChatCompletionRequest request = ChatCompletionRequest.builder() .model("__MODEL_NAME__") @@ -91,37 +91,37 @@ import ( ) func main() { - client := openai.NewClient("", "__BASE_URL__") - + client := openai.NewClient("-", "__BASE_URL__") + messages := []openai.ChatMessage{ {Role: "system", Content: "You are a helpful assistant."}, {Role: "user", Content: "Hello, how are you?"}, } - + response, err := client.ChatCompletions.Create(context.Background(), openai.ChatCompletionRequest{ Model: "__MODEL_NAME__", Messages: messages, MaxTokens: 128000, Temperature: 0.7, }) - + if err != nil { panic(err) } - + fmt.Println(response.Choices[0].Message.Content) } `, shell: ` #!/bin/bash -API_KEY="" +API_KEY="-" MODEL_ID="__MODEL_NAME__" BASE_URL="__BASE_URL__" -curl -X POST "$BASE_URL/v1/chat/completions" \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer $API_KEY" \ +curl -X POST "$BASE_URL/v1/chat/completions" \\ + -H "Content-Type: application/json" \\ + -H "Authorization: Bearer $API_KEY" \\ -d '{ "model": "'$MODEL_ID'", "messages": [ diff --git a/web/src/pages/Home/HomePricingFilters.jsx b/web/src/pages/Home/HomePricingFilters.jsx index b0b954b..4f4f76d 100644 --- a/web/src/pages/Home/HomePricingFilters.jsx +++ b/web/src/pages/Home/HomePricingFilters.jsx @@ -24,6 +24,7 @@ import PricingCardView from '../../components/table/model-pricing/view/card/Pric import ModelDetailSideSheet from '../../components/table/model-pricing/modal/ModelDetailSideSheet'; import { useModelPricingData } from '../../hooks/model-pricing/useModelPricingData'; import { usePricingFilterCounts } from '../../hooks/model-pricing/usePricingFilterCounts'; +import { useIsMobile } from '../../hooks/common/useIsMobile'; import { getLobeHubIcon } from '../../helpers'; // 与 model_meta.go ModelType 常量一致:1=Chat, 2=Image, 3=Audio, 4=Video, 5=Embedding, 6=Rerank, 7=Vision, 8=Other @@ -38,9 +39,28 @@ const MODEL_TYPE_LIST = [ { value: 8, labelKey: '其他' }, ]; +// 首页定价区域分页大小配置 +// 与 gridColsClass 网格布局配合:移动端1列、平板2列、桌面3列 +const HOME_PAGE_SIZE = { + mobile: 6, // 1列 × 6行 + tablet: 8, // 2列 × 4行 + desktop: 9, // 3列 × 3行 +}; + const HomePricingFilters = ({ t }) => { const [showRatio, setShowRatio] = useState(false); + const isMobile = useIsMobile(); const pricingData = useModelPricingData(); + + // 根据屏幕尺寸动态计算分页大小 + const pageSize = useMemo(() => { + if (isMobile) return HOME_PAGE_SIZE.mobile; + // 通过窗口宽度判断平板(768px-1024px 为 md 范围) + if (typeof window !== 'undefined' && window.innerWidth < 1024) { + return HOME_PAGE_SIZE.tablet; + } + return HOME_PAGE_SIZE.desktop; + }, [isMobile]); const { vendorModels, typeModels, @@ -154,7 +174,7 @@ const HomePricingFilters = ({ t }) => { filteredModels={pricingData.filteredModels} loading={pricingData.loading} rowSelection={null} - pageSize={pricingData.pageSize} + pageSize={pageSize} setPageSize={pricingData.setPageSize} currentPage={pricingData.currentPage} setCurrentPage={pricingData.setCurrentPage} @@ -171,7 +191,7 @@ const HomePricingFilters = ({ t }) => { selectedRowKeys={[]} openModelDetail={pricingData.openModelDetail} gridColsClass='grid-cols-1 md:grid-cols-2 lg:grid-cols-3' - showPagination={false} + showPagination={true} />