diff --git a/frontend/i18next-scanner.config.js b/frontend/i18next-scanner.config.js index ed5a320b..a2ad5e71 100644 --- a/frontend/i18next-scanner.config.js +++ b/frontend/i18next-scanner.config.js @@ -10,6 +10,7 @@ const systemLanguage = { }; const localesDir = 'packages/common/src/locales/scan'; const newJsonDir = 'packages/common/src/locales/scan/newJson'; +const oldJsonDir = 'packages/common/src/locales/scan/oldJson'; const keyHashFile = 'packages/common/src/locales/keyHashMap.json'; let existData = {}; let keyHashMap = {}; @@ -35,6 +36,14 @@ fs.readdirSync(localesDir).forEach(file => { const keyList = Object.keys(existData); + +// 清空 newJson 目录下的所有语言文件 +Object.values(systemLanguage).forEach(lng => { + const newJsonPath = path.join(newJsonDir, `${lng}.json`); + fs.writeFileSync(newJsonPath, JSON.stringify({})); // 清空文件 +}); + + module.exports = { input: [ 'packages/*/src/**/*.{js,jsx,tsx,ts}', @@ -110,6 +119,28 @@ module.exports = { flush: function(done) { // 将 keyHashMap 写入文件 fs.writeFileSync(keyHashFile, JSON.stringify(keyHashMap, null, 2)); + + + // 遍历每种语言,处理旧字段 + keyList.forEach((lng) => { + const localeFilePath = path.join(localesDir, `${lng}.json`); + const oldJsonPath = path.join(oldJsonDir, `${lng}.json`); + const langData = existData[lng] || {}; + + let oldJsonData = {}; + + // 将不存在于 keyHashMap 中的键移动到 oldJson 文件中 + Object.keys(langData).forEach(hashKey => { + if (!Object.values(keyHashMap).includes(hashKey)) { + oldJsonData[hashKey] = langData[hashKey]; // 将旧的 key 移到 oldJson 中 + } + }); + + // 写入 oldJson 文件 + if (Object.keys(oldJsonData).length > 0) { + fs.writeFileSync(oldJsonPath, JSON.stringify(oldJsonData, null, 2)); + } + }); done(); } }; \ No newline at end of file diff --git a/frontend/packages/common/src/contexts/GlobalStateContext.tsx b/frontend/packages/common/src/contexts/GlobalStateContext.tsx index 6cf49469..b338b76a 100644 --- a/frontend/packages/common/src/contexts/GlobalStateContext.tsx +++ b/frontend/packages/common/src/contexts/GlobalStateContext.tsx @@ -110,7 +110,7 @@ export const GlobalProvider: FC<{children:ReactNode}> = ({ children }) => { updateDate: '2024-07-01', powered:'Powered by https://apipark.com', mainPage:'/guide/page', - language:'en' + language:'en-US' }); const [accessData,setAccessData] = useState>(new Map()) const [pluginAccessDictionary, setPluginAccessDictionary] = useState<{[k:string]:string}>({}) diff --git a/frontend/packages/common/src/locales/index.ts b/frontend/packages/common/src/locales/index.ts index f83c77e2..00cb3708 100644 --- a/frontend/packages/common/src/locales/index.ts +++ b/frontend/packages/common/src/locales/index.ts @@ -6,8 +6,12 @@ import crc32 from 'crc/crc32'; // 引入需要实现国际化的简体、繁体、英文三种数据的json文件 import zhCN from 'antd/locale/zh_CN'; import enUS from 'antd/locale/en_US'; +import jaJP from 'antd/locale/ja_JP'; +import zhTW from 'antd/locale/zh_TW'; import localZh_CN from './scan/zh-CN.json'; // 本地翻译中文文件 import localEn_US from './scan/en-US.json'; // 本地翻译英文文件 +import localZh_TW from './scan/zh-TW.json'; // 本地翻译英文文件 +import localJa_JP from './scan/ja-JP.json'; // 本地翻译英文文件 // import config from '../../../../i18next-scanner.config.js'; const resources = { @@ -18,6 +22,14 @@ const resources = { 'en-US': { translation: localEn_US, ...enUS + }, + 'zh-TW': { + translation: localZh_TW, + ...zhTW + }, + 'ja-JP': { + translation: localJa_JP, + ...jaJP } }; diff --git a/frontend/packages/common/src/locales/keyHashMap.json b/frontend/packages/common/src/locales/keyHashMap.json index a745538f..4265738c 100644 --- a/frontend/packages/common/src/locales/keyHashMap.json +++ b/frontend/packages/common/src/locales/keyHashMap.json @@ -131,13 +131,13 @@ "上传 OpenAPI 文档 (.json/.yaml)": "K6206e4ad", "替换 OpenAPI 文档 (.json/.yaml)": "Kfba46e6d", "打开 OpenAPI YAML 编辑器": "Kdac8ce7e", - "无需审核:允许任何应用调用该服务": "Kf5da1284", - "人工审核:仅允许通过人工审核的应用调用该服务": "Kc59ff06d", + "无需审核:允许任何应用调用该服务": "Kffd7e274", + "人工审核:仅允许通过人工审核的应用调用该服务": "K8a8b13e4", "永久": "Kbfe02d7f", "否": "K1e9c479e", "是": "Kaddfcb6b", - "无需审核": "K6a7fa303", - "需要审核": "Kd196e8a4", + "无需审核": "K593e0c7e", + "需要审核": "Ke2d747d9", "暂无操作权限,请联系管理员分配。": "K23fda291", "微信小程序": "K4618cb0a", "获取文件,需填路径": "Ka854f511", @@ -236,7 +236,7 @@ "使用说明": "Kdefa9caa", "发布": "K36856e71", "订阅管理": "K6382bbfd", - "订阅审核": "K2eef4e4", + "订阅审核": "K31af5b99", "订阅方管理": "Ka97bd9e5", "管理": "K5974bf24", "调用拓扑图": "K3fa5c4c3", @@ -260,7 +260,7 @@ "模型供应商": "Kcf9f90b8", "模型": "Kfede1c7c", "参数": "Ke99513a0", - "审核": "K3818f03d", + "审核": "Kb595f40", "通过": "K54e27f57", "拒绝": "K8582af3f", "发布结果": "Kd568e15c", @@ -280,8 +280,8 @@ "AI 模型管理": "K7ac2be34", "配置好 AI 模型后,你可以使用对应的大模型来创建 AI 服务": "K2260837a", "同步最新模型": "K18dccc1a", - "待审核": "K6208054", - "已审核": "K74ab00a3", + "待审核": "K35612f29", + "已审核": "K47eaafde", "发布申请": "K56b4254f", "API 调用地址": "Kea2f9279", "API base URL 一般设置为API 网关的外部网络访问地址,或者是API网关绑定的域名。": "K7fc496a1", @@ -315,12 +315,12 @@ "服务内包含一组 API,并且可以发布到 API 市场被其他团队使用。": "Kd5be0cd7", "权限管理": "K62e89ee7", "订阅服务": "K8f7808e6", - "如果需要调用某个服务的 API,需要先订阅该服务,并且等待提供服务的团队审核后才可发起 API 请求。": "Kb0755523", - "审核订阅申请": "Kd28a1aa5", - "提供服务的团队可以审核来自其他团队的订阅申请,审核通过后的应用才可发起 API 请求。": "K1c15bb2e", + "如果需要调用某个服务的 API,需要先订阅该服务,并且等待提供服务的团队审核后才可发起 API 请求。": "Kf2410413", + "审核订阅申请": "K6c2e44b8", + "提供服务的团队可以审核来自其他团队的订阅申请,审核通过后的应用才可发起 API 请求。": "Ka0a8840a", "APIPark 提供详尽的 API 调用日志,帮助企业监控、分析和审计 API 的运行状况。": "K3453272", "Hello!欢迎使用 APIPark": "Kd518ba3e", - "你能通过 APIPark 快速在企业内部构建 API 开放门户/市场,享受极致的转发性能、API 可观测、服务治理、多租户管理、订阅审核流程等诸多好处。": "Ke66e4182", + "你能通过 APIPark 快速在企业内部构建 API 开放门户/市场,享受极致的转发性能、API 可观测、服务治理、多租户管理、订阅审核流程等诸多好处。": "K7e04ea16", "如果你喜欢我们的产品,欢迎给我们 Star 或提供产品反馈意见。": "Kedd41c18", "快速入门": "Kef02fd87", "我们提供了一些任务来帮你快速了解 APIPark": "K43a3b38d", @@ -542,13 +542,13 @@ "永不过期": "K9dfa2c97", "到期时间": "Kfa920c0", "订阅的服务": "Kcce1af60", - "审核详情": "Kbeb4e991", + "审核详情": "Kfefa9b58", "取消订阅": "K3118fdb0", "请确认是否取消订阅?": "Ked811bb1", "取消订阅申请": "K50c39a62", "请确认是否取消订阅申请?": "K1856c229", "搜索服务": "K66ea2f0", - "审核中": "Kfeb2559b", + "审核中": "K8adf7f8b", "添加应用": "K667bbbe7", "暂无服务描述": "Ka4b45550", "订阅的服务数量:已通过 (0) 个,申请中 (1) 个": "K3c7b175f", @@ -557,12 +557,11 @@ "服务详情": "Kf7ec36d", "申请服务": "K58ca9485", "介绍": "K59cdbec3", - "Base URL": "K1b6777bb", + "Base URL": "Kc29dabf2", "申请": "K4aa9ed2c", "服务信息": "K6c060779", "接入应用": "K8723422e", "供应方": "Kb97544cb", - "申请审核": "Kd55c6887", "分类": "Kb32f0afe", "版本": "K81634069", "更新时间": "Keefda53d", diff --git a/frontend/packages/common/src/locales/scan/en-US.json b/frontend/packages/common/src/locales/scan/en-US.json index 2c416c6b..15340da9 100644 --- a/frontend/packages/common/src/locales/scan/en-US.json +++ b/frontend/packages/common/src/locales/scan/en-US.json @@ -91,8 +91,8 @@ "K6206e4ad": "Upload OpenAPI Document (.json/.yaml)", "Kfba46e6d": "Replace OpenAPI Document (.json/.yaml)", "Kdac8ce7e": "Open OpenAPI YAML Editor", - "Kf5da1284": "No Review: All applications are allowed to subscribe to this service", - "Kc59ff06d": "Manual Review: Only reviewed and approved applications can subscribe to this service", + "Kffd7e274": "No Review: All applications are allowed to subscribe to this service", + "K8a8b13e4": "Manual Review: Only reviewed and approved applications can subscribe to this service", "Kbfe02d7f": "Permanent", "K1e9c479e": "No", "Kaddfcb6b": "Yes", @@ -194,7 +194,7 @@ "Kdefa9caa": "Usage Instructions", "K36856e71": "Publish", "K6382bbfd": "Subscription Management", - "K2eef4e4": "Subscription Review", + "K31af5b99": "Subscription Review", "Ka97bd9e5": "Subscriber Management", "K5974bf24": "Management", "K3fa5c4c3": "Call Topology", @@ -218,7 +218,7 @@ "Kcf9f90b8": "Model Provider", "Kfede1c7c": "Model", "Ke99513a0": "Parameter", - "K3818f03d": "Review", + "Kb595f40": "Review", "K54e27f57": "Approve", "K8582af3f": "Reject", "Kd568e15c": "Publish Result", @@ -238,8 +238,8 @@ "K7ac2be34": "AI Model Management", "K2260837a": "After setting up the AI model, you can use the model to create AI services", "K18dccc1a": "Sync Latest Model", - "K6208054": "Pending Review", - "K74ab00a3": "Reviewed", + "K35612f29": "Pending Review", + "K47eaafde": "Reviewed", "K56b4254f": "Publish Request", "Kea2f9279": "API Call Address", "K7fc496a1": "The API Base URL is generally set as the external network access address of the API Gateway, or the domain bound to the API Gateway.", @@ -273,12 +273,12 @@ "Kd5be0cd7": "Services include a set of APIs and can be published to the API Marketplace for use by other teams.", "K62e89ee7": "Permission Management", "K8f7808e6": "Subscribe to Services", - "Kb0755523": "To call an API from a service, you need to subscribe to that service and wait for approval from the providing team before initiating the API request.", - "Kd28a1aa5": "Review Subscription", - "K1c15bb2e": "Review subscription requests from other applications. Only approved requests can initiate API calls.", + "Kf2410413": "To call an API from a service, you need to subscribe to that service and wait for approval from the providing team before initiating the API request.", + "K6c2e44b8": "Review Subscription", + "Ka0a8840a": "Review subscription requests from other applications. Only approved requests can initiate API calls.", "K3453272": "APIPark provides detailed API call logs, helping enterprises monitor, analyze, and audit API operations.", "Kd518ba3e": "Hello! Welcome to APIPark", - "Ke66e4182": "APIPark is an open-source, all-in-one AI gateway and API developer portal, enabling enterprises and developers to quickly integrate over 100 AI models, combine AI models and prompts into new APIs, and standardize all AI request data formats, ensuring that switching AI models or adjusting prompts does not affect your APP or microservice. Additionally, APIPark’s developer portal allows you to share APIs within your team, manage applications that call your APIs, and ensure API security, while monitoring your AI API usage with clear charts.", + "K7e04ea16": "APIPark is an open-source, all-in-one AI gateway and API developer portal, enabling enterprises and developers to quickly integrate over 100 AI models, combine AI models and prompts into new APIs, and standardize all AI request data formats, ensuring that switching AI models or adjusting prompts does not affect your APP or microservice. Additionally, APIPark’s developer portal allows you to share APIs within your team, manage applications that call your APIs, and ensure API security, while monitoring your AI API usage with clear charts.", "Kedd41c18": "If you like our product, please give us a Star or provide feedback.", "Kef02fd87": "Quick Start", "K43a3b38d": "We've provided tasks to help you quickly understand APIPark", @@ -500,13 +500,13 @@ "K9dfa2c97": "Never Expires", "Kfa920c0": "Expiration Time", "Kcce1af60": "Subscribed Services", - "Kbeb4e991": "Review Details", + "Kfefa9b58": "Review Details", "K3118fdb0": "Unsubscribe", "Ked811bb1": "Are you sure you want to unsubscribe?", "K50c39a62": "Cancel Subscription Request", "K1856c229": "Are you sure you want to cancel the subscription request?", "K66ea2f0": "Search Services", - "Kfeb2559b": "Under Review", + "K8adf7f8b": "Under Review", "K667bbbe7": "Add Application", "Ka4b45550": "No Service Description", "K3c7b175f": "Number of Subscribed Services: (0) Approved, (1) Pending", @@ -521,6 +521,7 @@ "Kb97544cb": "Provider", "Kb32f0afe": "Category", "K81634069": "Version", + "K8b7c2592": "Updated By", "Keefda53d": "Last Update Time", "K96a2f1c8": "No Tags", "K72b0c0b3": "Number of APIs", @@ -571,9 +572,9 @@ "Kb3960e83": "Unpublished", "K8bd1e18": "Pending Publish", "K225a6c43": "Unit: s, Minimum: 1", - "K6a7fa303": "No Review Required", - "Kd196e8a4": "Review Required", - "K1b6777bb": "Base URL", + "K593e0c7e": "No Review Required", + "Ke2d747d9": "Review Required", + "Kc29dabf2": "Base URL", "Kd55c6887": "Review", "K300c89d4": "When creating an API, this provider is selected by default. Changing the default provider will not affect existing APIs." } diff --git a/frontend/packages/common/src/locales/scan/ja-JP.json b/frontend/packages/common/src/locales/scan/ja-JP.json index c0248eda..f28b0373 100644 --- a/frontend/packages/common/src/locales/scan/ja-JP.json +++ b/frontend/packages/common/src/locales/scan/ja-JP.json @@ -91,8 +91,8 @@ "K6206e4ad": "OpenAPI ドキュメント (.json/.yaml) をアップロード", "Kfba46e6d": "OpenAPI ドキュメント (.json/.yaml) を置き換え", "Kdac8ce7e": "OpenAPI YAML エディターを開く", - "Kf5da1284": "無審査:すべてのアプリケーションがこのサービスにサブスクライブできます", - "Kc59ff06d": "手動審査:承認されたアプリケーションのみがこのサービスにサブスクライブできます", + "Kffd7e274": "無審査:すべてのアプリケーションがこのサービスにサブスクライブできます", + "K8a8b13e4": "手動審査:承認されたアプリケーションのみがこのサービスにサブスクライブできます", "Kbfe02d7f": "永久", "K1e9c479e": "いいえ", "Kaddfcb6b": "はい", @@ -194,7 +194,7 @@ "Kdefa9caa": "説明ドキュメント", "K36856e71": "公開", "K6382bbfd": "サブスクリプション管理", - "K2eef4e4": "サブスクリプションレビュー", + "K31af5b99": "サブスクリプションレビュー", "Ka97bd9e5": "サブスクライバー管理", "K5974bf24": "管理", "K3fa5c4c3": "トポロジー図を呼び出す", @@ -218,7 +218,7 @@ "Kcf9f90b8": "モデルプロバイダー", "Kfede1c7c": "モデル", "Ke99513a0": "パラメーター", - "K3818f03d": "レビュー", + "Kb595f40": "レビュー", "K54e27f57": "承認", "K8582af3f": "拒否", "Kd568e15c": "公開結果", @@ -238,8 +238,8 @@ "K7ac2be34": "AI モデル管理", "K2260837a": "AI モデルを設定したら、そのモデルを使って AI サービスを作成できます", "K18dccc1a": "最新モデルを同期", - "K6208054": "レビュー中", - "K74ab00a3": "承認済み", + "K35612f29": "レビュー中", + "K47eaafde": "承認済み", "K56b4254f": "公開申請", "Kea2f9279": "API 呼び出し先", "K7fc496a1": "API Base URL は、通常 API ゲートウェイの外部ネットワークアクセスアドレス、または API ゲートウェイにバインドされたドメインを設定します。", @@ -273,12 +273,12 @@ "Kd5be0cd7": "サービスには一連の API が含まれており、他のチームが使用できるように API マーケットに公開できます。", "K62e89ee7": "権限管理", "K8f7808e6": "サービスのサブスクリプション", - "Kb0755523": "あるサービスの API を呼び出すには、まずそのサービスにサブスクライブし、提供チームの承認を待ってから API リクエストを発行できます。", - "Kd28a1aa5": "サブスクリプションをレビュー", - "K1c15bb2e": "他のアプリケーションのサブスクリプション申請をレビューし、承認後に API リクエストが発行できます。", + "Kf2410413": "あるサービスの API を呼び出すには、まずそのサービスにサブスクライブし、提供チームの承認を待ってから API リクエストを発行できます。", + "K6c2e44b8": "サブスクリプションをレビュー", + "Ka0a8840a": "他のアプリケーションのサブスクリプション申請をレビューし、承認後に API リクエストが発行できます。", "K3453272": "APIPark は詳細な API 呼び出しログを提供し、企業が API の運用状況を監視、分析、監査するのに役立ちます。", "Kd518ba3e": "こんにちは!APIPark へようこそ", - "Ke66e4182": "APIPark は、100 以上の AI モデルに簡単に接続できるオープンソースの AI ゲートウェイと API 開発者ポータルです。AI モデルとプロンプトを新しい API に組み合わせ、すべての AI リクエストのデータ形式を統一し、AI モデルを切り替えたりプロンプトを調整したりしても、アプリケーションやマイクロサービスに影響を与えません。また、APIPark の開発者ポータルを使用してチーム内で API を共有し、アプリケーションを管理し、API のセキュリティを確保し、AI API の使用状況を監視するための明確なグラフを提供します。", + "K7e04ea16": "APIPark は、100 以上の AI モデルに簡単に接続できるオープンソースの AI ゲートウェイと API 開発者ポータルです。AI モデルとプロンプトを新しい API に組み合わせ、すべての AI リクエストのデータ形式を統一し、AI モデルを切り替えたりプロンプトを調整したりしても、アプリケーションやマイクロサービスに影響を与えません。また、APIPark の開発者ポータルを使用してチーム内で API を共有し、アプリケーションを管理し、API のセキュリティを確保し、AI API の使用状況を監視するための明確なグラフを提供します。", "Kedd41c18": "もし私たちの製品を気に入ったら、Star を付けるか、フィードバックをお寄せください。", "Kef02fd87": "クイックスタート", "K43a3b38d": "APIPark をすばやく理解するためのいくつかのタスクを提供しています", @@ -500,13 +500,13 @@ "K9dfa2c97": "期限なし", "Kfa920c0": "有効期限", "Kcce1af60": "サブスクライブされたサービス", - "Kbeb4e991": "レビューの詳細", + "Kfefa9b58": "レビューの詳細", "K3118fdb0": "サブスクリプションをキャンセル", "Ked811bb1": "サブスクリプションをキャンセルしますか?", "K50c39a62": "サブスクリプション申請をキャンセル", "K1856c229": "サブスクリプション申請をキャンセルしますか?", "K66ea2f0": "Service を検索", - "Kfeb2559b": "レビュー中", + "K8adf7f8b": "レビュー中", "K667bbbe7": "Application を追加", "Ka4b45550": "サービス説明がありません", "K3c7b175f": "サブスクライブサービス:承認済み (0)、レビュー中 (1)", @@ -572,9 +572,9 @@ "Kb3960e83": "未公開", "K8bd1e18": "公開待ち", "K225a6c43": "単位: s、最小値: 1", - "K6a7fa303": "レビュー不要", - "Kd196e8a4": "レビュー必要", - "K1b6777bb": "Base URL", + "K593e0c7e": "レビュー不要", + "Ke2d747d9": "レビュー必要", + "Kc29dabf2": "Base URL", "Kd55c6887": "レビュー", "K300c89d4": "API 作成時にこのプロバイダーがデフォルトで選択されます。デフォルトプロバイダーを変更しても既存の API には影響しません。" } diff --git a/frontend/packages/common/src/locales/scan/newJson/en-US.json b/frontend/packages/common/src/locales/scan/newJson/en-US.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/frontend/packages/common/src/locales/scan/newJson/en-US.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/frontend/packages/common/src/locales/scan/newJson/ja-JP.json b/frontend/packages/common/src/locales/scan/newJson/ja-JP.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/frontend/packages/common/src/locales/scan/newJson/ja-JP.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/frontend/packages/common/src/locales/scan/newJson/zh-CN.json b/frontend/packages/common/src/locales/scan/newJson/zh-CN.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/frontend/packages/common/src/locales/scan/newJson/zh-CN.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/frontend/packages/common/src/locales/scan/newJson/zh-TW.json b/frontend/packages/common/src/locales/scan/newJson/zh-TW.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/frontend/packages/common/src/locales/scan/newJson/zh-TW.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/frontend/packages/common/src/locales/scan/oldJson/en-US.json b/frontend/packages/common/src/locales/scan/oldJson/en-US.json new file mode 100644 index 00000000..3ec14af5 --- /dev/null +++ b/frontend/packages/common/src/locales/scan/oldJson/en-US.json @@ -0,0 +1,3 @@ +{ + "Kd55c6887": "Review" +} \ No newline at end of file diff --git a/frontend/packages/common/src/locales/scan/oldJson/ja-JP.json b/frontend/packages/common/src/locales/scan/oldJson/ja-JP.json new file mode 100644 index 00000000..c8660395 --- /dev/null +++ b/frontend/packages/common/src/locales/scan/oldJson/ja-JP.json @@ -0,0 +1,3 @@ +{ + "Kd55c6887": "レビュー" +} \ No newline at end of file diff --git a/frontend/packages/common/src/locales/scan/oldJson/zh-CN.json b/frontend/packages/common/src/locales/scan/oldJson/zh-CN.json new file mode 100644 index 00000000..32e7815f --- /dev/null +++ b/frontend/packages/common/src/locales/scan/oldJson/zh-CN.json @@ -0,0 +1,3 @@ +{ + "Kd55c6887": "审核" +} \ No newline at end of file diff --git a/frontend/packages/common/src/locales/scan/oldJson/zh-TW.json b/frontend/packages/common/src/locales/scan/oldJson/zh-TW.json new file mode 100644 index 00000000..95a68019 --- /dev/null +++ b/frontend/packages/common/src/locales/scan/oldJson/zh-TW.json @@ -0,0 +1,3 @@ +{ + "Kd55c6887": "審核" +} \ No newline at end of file diff --git a/frontend/packages/common/src/locales/scan/zh-CN.json b/frontend/packages/common/src/locales/scan/zh-CN.json index 455b2a2f..8c75ce34 100644 --- a/frontend/packages/common/src/locales/scan/zh-CN.json +++ b/frontend/packages/common/src/locales/scan/zh-CN.json @@ -91,8 +91,8 @@ "K6206e4ad": "上传 OpenAPI 文档 (.json/.yaml)", "Kfba46e6d": "替换 OpenAPI 文档 (.json/.yaml)", "Kdac8ce7e": "打开 OpenAPI YAML 编辑器", - "Kf5da1284": "无审核:允许所有应用订阅该服务", - "Kc59ff06d": "人工审核:仅允许审核通过的应用订阅该服务", + "Kffd7e274": "无审核:允许所有应用订阅该服务", + "K8a8b13e4": "人工审核:仅允许审核通过的应用订阅该服务", "Kbfe02d7f": "永久", "K1e9c479e": "否", "Kaddfcb6b": "是", @@ -194,7 +194,7 @@ "Kdefa9caa": "说明文档", "K36856e71": "发布", "K6382bbfd": "订阅管理", - "K2eef4e4": "订阅审核", + "K31af5b99": "订阅审核", "Ka97bd9e5": "订阅方管理", "K5974bf24": "管理", "K3fa5c4c3": "调用拓扑图", @@ -218,7 +218,7 @@ "Kcf9f90b8": "模型供应商", "Kfede1c7c": "模型", "Ke99513a0": "参数", - "K3818f03d": "审核", + "Kb595f40": "审核", "K54e27f57": "通过", "K8582af3f": "拒绝", "Kd568e15c": "发布结果", @@ -238,8 +238,8 @@ "K7ac2be34": "AI 模型管理", "K2260837a": "设置好 AI 模型后,你可以使用对应的大模型来创建 AI 服务", "K18dccc1a": "同步最新模型", - "K6208054": "待审核", - "K74ab00a3": "已审核", + "K35612f29": "待审核", + "K47eaafde": "已审核", "K56b4254f": "发布申请", "Kea2f9279": "API 调用地址", "K7fc496a1": "API Base URL 一般设置为 API 网关的外部网络访问地址,或者是API网关绑定的域名。", @@ -273,12 +273,12 @@ "Kd5be0cd7": "服务内包含一组 API,并且可以发布到 API 市场被其他团队使用。", "K62e89ee7": "权限管理", "K8f7808e6": "订阅服务", - "Kb0755523": "如果需要调用某个服务的 API,需要先订阅该服务,并且等待提供服务的团队审核后才可发起 API 请求。", - "Kd28a1aa5": "审核订阅", - "K1c15bb2e": "审核其他应用的订阅申请,审核通过后的才可发起 API 请求。", + "Kf2410413": "如果需要调用某个服务的 API,需要先订阅该服务,并且等待提供服务的团队审核后才可发起 API 请求。", + "K6c2e44b8": "审核订阅", + "Ka0a8840a": "审核其他应用的订阅申请,审核通过后的才可发起 API 请求。", "K3453272": "APIPark 提供详尽的 API 调用日志,帮助企业监控、分析和审计 API 的运行状况。", "Kd518ba3e": "Hello!欢迎使用 APIPark", - "Ke66e4182": "APIPark 是开源的一站式 AI 网关和 API 开发者门户,帮助企业和开发者快速接入 100+ AI 模型,将 AI 模型和 Prompt 提示词组合成新的 API,并且统一所有 AI 的请求数据格式,避免切换 AI 模型或调整提示词时影响你的 APP 应用或者微服务。你还可以通过 APIPark 的开发者门户在团队内共享 API,管理调用的应用并保障你的 API 安全,通过清晰的图表来监控你的 AI API 使用情况。", + "K7e04ea16": "APIPark 是开源的一站式 AI 网关和 API 开发者门户,帮助企业和开发者快速接入 100+ AI 模型,将 AI 模型和 Prompt 提示词组合成新的 API,并且统一所有 AI 的请求数据格式,避免切换 AI 模型或调整提示词时影响你的 APP 应用或者微服务。你还可以通过 APIPark 的开发者门户在团队内共享 API,管理调用的应用并保障你的 API 安全,通过清晰的图表来监控你的 AI API 使用情况。", "Kedd41c18": "如果你喜欢我们的产品,欢迎给我们 Star 或提供产品反馈意见。", "Kef02fd87": "快速入门", "K43a3b38d": "我们提供了一些任务来帮你快速了解 APIPark", @@ -500,13 +500,13 @@ "K9dfa2c97": "永不过期", "Kfa920c0": "过期时间", "Kcce1af60": "订阅的服务", - "Kbeb4e991": "审核详情", + "Kfefa9b58": "审核详情", "K3118fdb0": "取消订阅", "Ked811bb1": "是否取消订阅?", "K50c39a62": "取消订阅申请", "K1856c229": "是否取消订阅申请?", "K66ea2f0": "搜索服务", - "Kfeb2559b": "审核中", + "K8adf7f8b": "审核中", "K667bbbe7": "添加应用", "Ka4b45550": "无服务描述", "K3c7b175f": "订阅服务:已通过 (0) ,审核中 (1)", @@ -572,9 +572,9 @@ "Kb3960e83": "未发布", "K8bd1e18": "待发布", "K225a6c43": "单位:s,最小值:1", - "K6a7fa303": "无需审核", - "Kd196e8a4": "需要审核", - "K1b6777bb": "Base URL", + "K593e0c7e": "无需审核", + "Ke2d747d9": "需要审核", + "Kc29dabf2": "Base URL", "Kd55c6887": "审核", "K300c89d4": "创建 API 时会默认选择该供应商,修改默认供应商不会影响现有 API" } \ No newline at end of file diff --git a/frontend/packages/common/src/locales/scan/zh-TW.json b/frontend/packages/common/src/locales/scan/zh-TW.json index 0f3b2817..7657f7db 100644 --- a/frontend/packages/common/src/locales/scan/zh-TW.json +++ b/frontend/packages/common/src/locales/scan/zh-TW.json @@ -91,8 +91,8 @@ "K6206e4ad": "上傳 OpenAPI 文檔 (.json/.yaml)", "Kfba46e6d": "替換 OpenAPI 文檔 (.json/.yaml)", "Kdac8ce7e": "打開 OpenAPI YAML 編輯器", - "Kf5da1284": "無審核:允許所有應用程式訂閱該服務", - "Kc59ff06d": "人工審核:僅允許審核通過的應用程式訂閱該服務", + "Kffd7e274": "無審核:允許所有應用程式訂閱該服務", + "K8a8b13e4": "人工審核:僅允許審核通過的應用程式訂閱該服務", "Kbfe02d7f": "永久", "K1e9c479e": "否", "Kaddfcb6b": "是", @@ -194,7 +194,7 @@ "Kdefa9caa": "說明文檔", "K36856e71": "發布", "K6382bbfd": "訂閱管理", - "K2eef4e4": "訂閱審核", + "K31af5b99": "訂閱審核", "Ka97bd9e5": "訂閱方管理", "K5974bf24": "管理", "K3fa5c4c3": "調用拓撲圖", @@ -218,7 +218,7 @@ "Kcf9f90b8": "模型供應商", "Kfede1c7c": "模型", "Ke99513a0": "參數", - "K3818f03d": "審核", + "Kb595f40": "審核", "K54e27f57": "通過", "K8582af3f": "拒絕", "Kd568e15c": "發布結果", @@ -238,8 +238,8 @@ "K7ac2be34": "AI 模型管理", "K2260837a": "設置好 AI 模型後,你可以使用對應的大模型來創建 AI 服務", "K18dccc1a": "同步最新模型", - "K6208054": "待審核", - "K74ab00a3": "已審核", + "K35612f29": "待審核", + "K47eaafde": "已審核", "K56b4254f": "發布申請", "Kea2f9279": "API 調用地址", "K7fc496a1": "API Base URL 一般設置為 API 網關的外部網絡訪問地址,或者是API網關綁定的域名。", @@ -273,12 +273,12 @@ "Kd5be0cd7": "服務內包含一組 API,並且可以發布到 API 市場被其他團隊使用。", "K62e89ee7": "權限管理", "K8f7808e6": "訂閱服務", - "Kb0755523": "如果需要調用某個服務的 API,需要先訂閱該服務,並且等待提供服務的團隊審核後才可發起 API 請求。", - "Kd28a1aa5": "審核訂閱", - "K1c15bb2e": "審核其他應用程式的訂閱申請,審核通過後的才可發起 API 請求。", + "Kf2410413": "如果需要調用某個服務的 API,需要先訂閱該服務,並且等待提供服務的團隊審核後才可發起 API 請求。", + "K6c2e44b8": "審核訂閱", + "Ka0a8840a": "審核其他應用程式的訂閱申請,審核通過後的才可發起 API 請求。", "K3453272": "APIPark 提供詳盡的 API 調用日誌,幫助企業監控、分析和審計 API 的運行狀況。", "Kd518ba3e": "Hello!歡迎使用 APIPark", - "Ke66e4182": "APIPark 是開源的一站式 AI 網關和 API 開發者門戶,幫助企業和開發者快速接入 100+ AI 模型,將 AI 模型和 Prompt 提示詞組合成新的 API,並且統一所有 AI 的請求數據格式,避免切換 AI 模型或調整提示詞時影響你的 APP 應用程式或者微服務。你還可以通過 APIPark 的開發者門戶在團隊內共享 API,管理調用的應用程式並保障你的 API 安全,通過清晰的圖表來監控你的 AI API 使用情況。", + "K7e04ea16": "APIPark 是開源的一站式 AI 網關和 API 開發者門戶,幫助企業和開發者快速接入 100+ AI 模型,將 AI 模型和 Prompt 提示詞組合成新的 API,並且統一所有 AI 的請求數據格式,避免切換 AI 模型或調整提示詞時影響你的 APP 應用程式或者微服務。你還可以通過 APIPark 的開發者門戶在團隊內共享 API,管理調用的應用程式並保障你的 API 安全,通過清晰的圖表來監控你的 AI API 使用情況。", "Kedd41c18": "如果你喜歡我們的產品,歡迎給我們 Star 或提供產品反饋意見。", "Kef02fd87": "快速入門", "K43a3b38d": "我們提供了一些任務來幫你快速了解 APIPark", @@ -500,13 +500,13 @@ "K9dfa2c97": "永不過期", "Kfa920c0": "過期時間", "Kcce1af60": "訂閱的服務", - "Kbeb4e991": "審核詳情", + "Kfefa9b58": "審核詳情", "K3118fdb0": "取消訂閱", "Ked811bb1": "是否取消訂閱?", "K50c39a62": "取消訂閱申請", "K1856c229": "是否取消訂閱申請?", "K66ea2f0": "搜索服務", - "Kfeb2559b": "審核中", + "K8adf7f8b": "審核中", "K667bbbe7": "添加應用程式", "Ka4b45550": "無服務描述", "K3c7b175f": "訂閱服務:已通過 (0) ,審核中 (1)", @@ -572,9 +572,9 @@ "Kb3960e83": "未發布", "K8bd1e18": "待發布", "K225a6c43": "單位:s,最小值:1", - "K6a7fa303": "無需審核", - "Kd196e8a4": "需要審核", - "K1b6777bb": "Base URL", + "K593e0c7e": "無需審核", + "Ke2d747d9": "需要審核", + "Kc29dabf2": "Base URL", "Kd55c6887": "審核", "K300c89d4": "創建 API 時會默認選擇該供應商,修改默認供應商不會影響現有 API" } diff --git a/frontend/packages/core/src/pages/aiService/AiServiceConfig.tsx b/frontend/packages/core/src/pages/aiService/AiServiceConfig.tsx deleted file mode 100644 index 802a0085..00000000 --- a/frontend/packages/core/src/pages/aiService/AiServiceConfig.tsx +++ /dev/null @@ -1,416 +0,0 @@ - -import { forwardRef, useEffect, useImperativeHandle, useMemo, useState } from "react"; -import { App, Button, Form, Input, Radio, Row, Select, TreeSelect, Upload } from "antd"; -import { Link, useNavigate, useParams } from "react-router-dom"; -import { RouterParams } from "@core/components/aoplatform/RenderRoutes.tsx"; -import { BasicResponse, DELETE_TIPS, PLACEHOLDER, RESPONSE_TIPS, STATUS_CODE } from "@common/const/const.tsx"; -import { useFetch} from "@common/hooks/http.ts"; -import { DefaultOptionType } from "antd/es/cascader"; -import { EntityItem, MemberItem, SimpleTeamItem } from "@common/const/type.ts"; -import { v4 as uuidv4 } from 'uuid' -import { validateUrlSlash } from "@common/utils/validate.ts"; -import { normFile } from "@common/utils/uploadPic.ts"; -import { useBreadcrumb } from "@common/contexts/BreadcrumbContext.tsx"; -import { SERVICE_VISUALIZATION_OPTIONS } from "@core/const/system/const.tsx"; -import { RcFile, UploadChangeParam, UploadFile, UploadProps } from "antd/es/upload/interface"; -import { LoadingOutlined } from "@ant-design/icons"; -import { getImgBase64 } from "@common/utils/dataTransfer.ts"; -import { CategorizesType } from "@market/const/serviceHub/type.ts"; -import WithPermission from "@common/components/aoplatform/WithPermission.tsx"; -import { Icon } from "@iconify/react/dist/iconify.js"; -import { useGlobalContext } from "@common/contexts/GlobalStateContext.tsx"; -import { $t } from "@common/locales/index.ts"; -import { AiServiceConfigHandle, AiServiceConfigFieldType } from "@core/const/ai-service/type"; -import { useAiServiceContext } from "@core/contexts/AiServiceContext"; - -type SimpleAiProviderItem = EntityItem & { - configured:boolean - logo:string -} - -const AiServiceConfig = forwardRef((_,ref) => { - const { message,modal } = App.useApp() - const { teamId, serviceId } = useParams(); - const [onEdit, setOnEdit] = useState(!!teamId) - const [form] = Form.useForm(); - const {fetchData} = useFetch() - const [teamOptionList, setTeamOptionList] = useState() - const [providerOptionList, setProviderOptionList] = useState() - const navigate = useNavigate(); - const {setBreadcrumb} = useBreadcrumb() - const { setAiServiceInfo} = useAiServiceContext() - const [showClassify, setShowClassify] = useState() - const [imageBase64, setImageBase64] = useState(null); - const [tagOptionList, setTagOptionList] = useState([]) - const [serviceClassifyOptionList, setServiceClassifyOptionList] = useState() - const [uploadLoading, setUploadLoading] = useState(false) - const {checkPermission,accessInit, getGlobalAccessData,state, aiConfigFlushed, setAiConfigFlushed} = useGlobalContext() - - useImperativeHandle(ref, () => ({ - save:onFinish - })); - - const beforeUpload = async (file: RcFile) => { - if (!['image/png', 'image/jpeg', 'image/svg+xml'].includes(file.type)) { - alert($t('只允许上传PNG、JPG或SVG格式的图片')); - return false; - } - const reader = new FileReader(); - reader.onload = (e: ProgressEvent) => { - setImageBase64(e.target?.result as string); - form.setFieldValue('logo', e.target?.result); - }; - reader.readAsDataURL(file); - // } - return false; - }; - - - const handleChange: UploadProps['onChange'] = (info: UploadChangeParam) => { - if (info.file.status === 'uploading') { - setUploadLoading(true); - return; - } - if (info.file.status === 'done') { - getImgBase64(info.file.originFileObj as RcFile, () => { - setUploadLoading(false); - }); - } - if (info.fileList.length === 0) { - form.setFieldValue( "logo", null ); - } - }; - - const uploadButton = ( -
- {uploadLoading ? : } -
- ); - - const getTagAndServiceClassifyList = ()=>{ - setTagOptionList([]) - setServiceClassifyOptionList([]) - fetchData>('catalogues',{method:'GET'}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setTagOptionList(data.tags?.map((x:EntityItem)=>{return { - label:x.name, value:x.name - }})||[]) - setServiceClassifyOptionList(data.catalogues) - - }else{ - message.error(msg || $t(RESPONSE_TIPS.error)) - } - }) - } - - - // 获取表单默认值 - const getAiServiceInfo = () => { - fetchData>('ai-service/info',{method:'GET',eoParams:{team:teamId, service:serviceId},eoTransformKeys:['team_id','service_type']}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setTimeout(()=>{ - form.setFieldsValue({ - ...data.service, - team:data.service.team.id, - catalogue:data.service.catalogue?.id, - tags:data.service.tags?.map((x:EntityItem)=>x.name), - provider:data.service.provider.id, - logoFile:[ - { - uid: '-1', // 文件唯一标识 - name: 'image.png', // 文件名 - status: 'done', // 状态有:uploading, done, error, removed - url: data.service?.logo || '', // 图片 Base64 数据 - } - ] - }) - setImageBase64(data.service.logo) - setShowClassify(data.service.serviceType === 'public') - },0) - }else{ - message.error(msg || $t(RESPONSE_TIPS.error)) - } - }) - }; - - const onFinish:()=>Promise = () => { - return form.validateFields().then((value)=>{ - return fetchData>(serviceId === undefined? 'team/ai-service':'ai-service/info',{method:serviceId === undefined? 'POST' : 'PUT',eoParams: {...(serviceId === undefined ? {team:value.team} :{service:serviceId,team:teamId})},eoBody:({...value,prefix:value.prefix?.trim()}), eoTransformKeys:['serviceType']},).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || $t(RESPONSE_TIPS.success)) - setAiServiceInfo(data.service) - return Promise.resolve(true) - }else{ - message.error(msg || $t(RESPONSE_TIPS.error)) - return Promise.reject(msg || $t(RESPONSE_TIPS.error)) - } - }).catch((errorInfo)=>{ - return Promise.reject(errorInfo) - }) - }) - }; - - const getProviderOptionList = ()=>{ - setProviderOptionList([]) - fetchData>('simple/ai/providers',{method:'GET',eoTransformKeys:[]}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setProviderOptionList(data.providers?.filter(x=>x.configured)?.map((x:SimpleAiProviderItem)=>{return {...x, - label:
, value:x.id - }})) - }else{ - message.error(msg || $t(RESPONSE_TIPS.error)) - } - }) - } - - const getTeamOptionList = ()=>{ - setTeamOptionList([]) - - fetchData>(!checkPermission('system.workspace.team.view_all') ?'simple/teams/mine' :'simple/teams',{method:'GET',eoTransformKeys:[]}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setTeamOptionList(data.teams?.map((x:MemberItem)=>{return {...x, - label:x.name, value:x.id - }})) - }else{ - message.error(msg || $t(RESPONSE_TIPS.error)) - } - }) - } - - const deleteAiService = ()=>{ - fetchData>('team/ai-service',{method:'DELETE',eoParams:{team:teamId,service:serviceId}}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || $t(RESPONSE_TIPS.success)) - navigate(`/aiservice/list`) - }else{ - message.error(msg || $t(RESPONSE_TIPS.error)) - } - }) - } - - useEffect(()=>{ - aiConfigFlushed && getProviderOptionList() - },[aiConfigFlushed]) - - useEffect(() => { - getProviderOptionList() - getTagAndServiceClassifyList() - if(accessInit){ - getTeamOptionList() - }else{ - getGlobalAccessData()?.then(()=>{ - getTeamOptionList() - }) - } - if (serviceId !== undefined) { - setOnEdit(true); - getAiServiceInfo(); - setBreadcrumb([ - { - title: {$t('服务')} - }, - { - title: $t('设置') - }]) - - } else { - setOnEdit(false); - form.setFieldValue('id',uuidv4()); - form.setFieldValue('team',teamId); - form.setFieldValue('serviceType','inner'); - } - return (form.setFieldsValue({})) - }, [serviceId]); - - - const deleteAiServiceModal = async ()=>{ - modal.confirm({ - title:$t('删除'), - content:$t(DELETE_TIPS.default), - onOk:()=> { - return deleteAiService() - }, - width:600, - okText:$t('确认'), - okButtonProps:{ - danger:true - }, - cancelText:$t('取消'), - closable:true, - icon:<> - }) - } - - const visualizationOptions = useMemo(()=>SERVICE_VISUALIZATION_OPTIONS.map((x)=>({...x, label:$t(x.label)})),[state.language]) - - return ( - <> - -
-
- - label={$t("服务名称")} - name="name" - rules={[{ required: true ,whitespace:true }]} - > - - - - - label={$t("服务ID")} - name="id" - rules={[{ required: true ,whitespace:true }]} - > - - - - - label={$t("AI 模型供应商")} - name="provider" - rules={[{ required: true }]} - >{ - (providerOptionList && providerOptionList.length >0 ) ? :

未配置任何 AI 模型供应商,setAiConfigFlushed(false)}>立即配置

- } - - - - label={$t("API 调用前缀")} - name="prefix" - extra={$t("选填,作为服务内所有API的前缀,比如host/{service_name}/{api_path},一旦保存无法修改")} - rules={[ - { - validator: validateUrlSlash, - }]} - > - - - - - label={$t("图标")} - name="logoFile" - extra={$t("仅支持 .png .jpg .jpeg .svg 格式的图片文件, 大于 1KB 的文件将被压缩")} - valuePropName="fileList" getValueFromEvent={normFile} - > - -
- {imageBase64 ? Logo : uploadButton} -
-
- - - - - label={$t("描述")} - name="description" - > - - - - - label={$t("Logo")} - name="logo" - hidden - > - - - {!onEdit && - label={$t("所属团队")} - name="team" - rules={[{ required: true }]} - > - - } - - - - label={$t("标签")} - name="tags" - > - - - - - label={$t("服务类型")} - name="serviceType" - rules={[{required: true}]} - > - {setShowClassify(e.target.value === 'public')}} /> - - - {showClassify && - - label={$t("所属服务分类")} - name="catalogue" - extra={$t("设置服务展示在服务市场中的哪个分类下")} - rules={[{required: true}]} - > - - - } - {onEdit && <> - - - - - } -
- {onEdit && <> - -
-

{$t('删除服务')}:{$t('删除操作不可恢复,请谨慎操作!')}

-
- - - -
-
-
- } -
-
- - ) -}) -export default AiServiceConfig \ No newline at end of file diff --git a/frontend/packages/core/src/pages/aiService/AiServiceInsideDocument.tsx b/frontend/packages/core/src/pages/aiService/AiServiceInsideDocument.tsx index 411f367d..3dd2ef2b 100644 --- a/frontend/packages/core/src/pages/aiService/AiServiceInsideDocument.tsx +++ b/frontend/packages/core/src/pages/aiService/AiServiceInsideDocument.tsx @@ -80,7 +80,7 @@ const ServiceInsideDocument = ()=>{ ], toolbar: 'undo redo | styles | bold italic | alignleft aligncenter alignright alignjustify | codesample |table|' + 'bullist numlist outdent indent | link image | print preview media fullscreen | ' + 'forecolor backcolor emoticons | help', - content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }', + content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px; } img { max-width: 100%; }', setup: setupEditor, codesample_languages:[ { diff --git a/frontend/packages/core/src/pages/aiService/AiServiceList.tsx b/frontend/packages/core/src/pages/aiService/AiServiceList.tsx deleted file mode 100644 index dbb3ec7b..00000000 --- a/frontend/packages/core/src/pages/aiService/AiServiceList.tsx +++ /dev/null @@ -1,159 +0,0 @@ -import PageList from "@common/components/aoplatform/PageList.tsx" -import {ActionType} from "@ant-design/pro-components"; -import {FC, useEffect, useMemo, useRef, useState} from "react"; -import {useNavigate} from "react-router-dom"; -import { App} from "antd"; -import {useBreadcrumb} from "@common/contexts/BreadcrumbContext.tsx"; -import {BasicResponse, RESPONSE_TIPS, STATUS_CODE} from "@common/const/const.tsx"; -import {useFetch} from "@common/hooks/http.ts"; -import { SimpleTeamItem ,SimpleMemberItem} from "@common/const/type.ts"; -import { DrawerWithFooter } from "@common/components/aoplatform/DrawerWithFooter.tsx"; -import AiServiceConfig from "./AiServiceConfig.tsx"; -import { useGlobalContext } from "@common/contexts/GlobalStateContext.tsx"; -import { $t } from "@common/locales/index.ts"; -import { AiServiceTableListItem, AiServiceConfigHandle } from "@core/const/ai-service/type.ts"; -import { AI_SERVICE_TABLE_COLUMNS } from "@core/const/ai-service/const.tsx"; - -const AiServiceList:FC = ()=>{ - const navigate = useNavigate(); - const [tableSearchWord, setTableSearchWord] = useState('') - const { setBreadcrumb } = useBreadcrumb() - const [teamList, setTeamList] = useState<{ [k: string]: { text: string; }; }>() - const {fetchData} = useFetch() - const [tableListDataSource, setTableListDataSource] = useState([]); - const [tableHttpReload, setTableHttpReload] = useState(true); - const { message } = App.useApp() - const pageListRef = useRef(null); - const [memberValueEnum, setMemberValueEnum] = useState<{[k:string]:{text:string}}>({}) - const [open, setOpen] = useState(false); - const drawerFormRef = useRef(null) - const {checkPermission,accessInit, getGlobalAccessData,state} = useGlobalContext() - - const getAiServiceList = ()=>{ - if(!accessInit){ - getGlobalAccessData()?.then(()=>{ - getAiServiceList() - }) - return - } - if(!tableHttpReload){ - setTableHttpReload(true) - return Promise.resolve({ - data: tableListDataSource, - success: true, - }); - } - return fetchData>(!checkPermission('system.workspace.service.view_all') ? 'my_ai_services':'ai-services',{method:'GET',eoParams:{keyword:tableSearchWord},eoTransformKeys:['api_num','can_delete','create_time']}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setTableListDataSource(data.services) - setTableHttpReload(false) - return {data:data.services, success: true} - }else{ - message.error(msg || $t(RESPONSE_TIPS.error)) - return {data:[], success:false} - } - }).catch(() => { - return {data:[], success:false} - }) - } - - const getTeamsList = ()=>{ - if(!accessInit){ - getGlobalAccessData()?.then(()=>{ - getTeamsList() - }) - return - } - fetchData>(!checkPermission('system.workspace.team.view_all') ?'simple/teams/mine' :'simple/teams',{method:'GET',eoTransformKeys:[]}).then(response=>{ - const {code,data,msg} = response - setTeamList(data.teams) - if(code === STATUS_CODE.SUCCESS){ - const tmpValueEnum:{[k:string]:{text:string}} = {} - data.teams?.forEach((x:SimpleMemberItem)=>{ - tmpValueEnum[x.name] = {text:x.name} - }) - setTeamList(tmpValueEnum) - }else{ - message.error(msg || $t(RESPONSE_TIPS.error)) - return {data:[], success:false} - } - }) - } - - const manualReloadTable = () => { - setTableHttpReload(true); // 表格数据需要从后端接口获取 - pageListRef.current?.reload() - }; - - const getMemberList = async ()=>{ - setMemberValueEnum({}) - const {code,data,msg} = await fetchData>('simple/member',{method:'GET'}) - if(code === STATUS_CODE.SUCCESS){ - const tmpValueEnum:{[k:string]:{text:string}} = {} - data.members?.forEach((x:SimpleMemberItem)=>{ - tmpValueEnum[x.name] = {text:x.name} - }) - setMemberValueEnum(tmpValueEnum) - }else{ - message.error(msg || $t(RESPONSE_TIPS.error)) - } - } - - useEffect(() => { - getTeamsList(); - getMemberList() - setBreadcrumb([ - { - title: $t('服务') - }]) - }, []); - - const onClose = () => { - setOpen(false); - }; - - const columns = useMemo(()=>{ - const res = AI_SERVICE_TABLE_COLUMNS.map(x=>{ - if(x.filters &&((x.dataIndex as string[])?.indexOf('master') !== -1 ) ){ - x.valueEnum = memberValueEnum - } - if(x.filters &&((x.dataIndex as string[])?.indexOf('team') !== -1 ) ){ - x.valueEnum = teamList - } - - return {...x,title:typeof x.title === 'string' ? $t(x.title as string) : x.title}}) - return res - },[memberValueEnum,teamList,state.language]); - - return ( -
- {/* */} - getAiServiceList()} - addNewBtnTitle={$t("添加服务")} - addNewBtnWrapperClass={'my-first-step'} - searchPlaceholder={$t("输入名称、ID、所属团队、负责人查找服务")} - onAddNewBtnClick={() => { - setOpen(true) - }} - manualReloadTable={manualReloadTable} - onChange={() => { - setTableHttpReload(false) - }} - onSearchWordChange={(e) => { - setTableSearchWord(e.target.value) - }} - onRowClick={(row:AiServiceTableListItem)=>navigate(`/aiservice/${row.team.id}/inside/${row.id}`)} - /> - drawerFormRef.current?.save()?.then((res)=>{res && manualReloadTable();return res})} > - - -
- ) - -} -export default AiServiceList \ No newline at end of file diff --git a/frontend/packages/core/src/pages/common/ApiRequestSetting.tsx b/frontend/packages/core/src/pages/common/ApiRequestSetting.tsx index 8e756927..9fd9a810 100644 --- a/frontend/packages/core/src/pages/common/ApiRequestSetting.tsx +++ b/frontend/packages/core/src/pages/common/ApiRequestSetting.tsx @@ -67,7 +67,7 @@ export default function ApiRequestSetting(){ > label={$t("API 调用地址")} - name="name" + name="invokeAddress" rules={[{ required: true,whitespace:true }]} extra={$t("API base URL 一般设置为API 网关的外部网络访问地址,或者是API网关绑定的域名。")} > diff --git a/frontend/packages/core/src/pages/member/MemberList.tsx b/frontend/packages/core/src/pages/member/MemberList.tsx index 18876ef7..48f04fce 100644 --- a/frontend/packages/core/src/pages/member/MemberList.tsx +++ b/frontend/packages/core/src/pages/member/MemberList.tsx @@ -348,7 +348,7 @@ const MemberList = ()=>{ className="w-full" mode="multiple" value={entity.roles?.map((x:EntityItem)=>x.id)} - options={roleSelectableList?.map((x:{id:string,name:string})=>({label:$t(x.name), value:x.id}))} + options={roleSelectableList?.map((x:{id:string,name:string})=>({label:(x.name), value:x.id}))} onChange={(value)=>{ changeMemberInfo(value,entity ).then((res)=>{ if(res) manualReloadTable() diff --git a/frontend/packages/core/src/pages/role/RoleConfig.tsx b/frontend/packages/core/src/pages/role/RoleConfig.tsx index 0a3e739c..153125a7 100644 --- a/frontend/packages/core/src/pages/role/RoleConfig.tsx +++ b/frontend/packages/core/src/pages/role/RoleConfig.tsx @@ -11,7 +11,6 @@ import { useGlobalContext } from "@common/contexts/GlobalStateContext"; type PermissionItem = { name:string - cname:string value:string } @@ -57,9 +56,9 @@ const PermissionContent = ({permits,onChange,value=[],id,dependenciesMap}:{permi permits.map((item:PermissionClassify)=>( <>
- {item.cname !== '' &&

{$t(item.cname)}

} + {item.name !== '' &&

{(item.name)}

}
- {item.children.map(x=> 0 && value.indexOf(x.value)>-1} onChange={onSingleCheckboxChange}>{$t(x.cname)})} + {item.children.map(x=> 0 && value.indexOf(x.value)>-1} onChange={onSingleCheckboxChange}>{(x.name)})}
@@ -76,7 +75,7 @@ const PermissionContent = ({permits,onChange,value=[],id,dependenciesMap}:{permi const items = useMemo(()=>{ const generatePermissionItem = (permissionItem:RolePermissionItem[])=> permissionItem.map((item:RolePermissionItem)=>({ key:item.name, - label:$t(item.cname), + label:(item.name), children:onChange?.(e)} id={id!} dependenciesMap={dependenciesMap!}/> })) return permissionTemplate && permissionTemplate.length > 0 ? generatePermissionItem(permissionTemplate) : [] diff --git a/frontend/packages/core/src/pages/role/RoleList.tsx b/frontend/packages/core/src/pages/role/RoleList.tsx index e6e3bc4d..9f0db1f3 100644 --- a/frontend/packages/core/src/pages/role/RoleList.tsx +++ b/frontend/packages/core/src/pages/role/RoleList.tsx @@ -45,7 +45,7 @@ const RoleList = ()=>{ return fetchData>(`${group}/roles`,{method:'GET'}).then(response=>{ const {code,data,msg} = response if(code === STATUS_CODE.SUCCESS){ - return {data:data.roles?.map((x:RoleTableListItem)=>({...x,name:$t(x.name)})), success: true} + return {data:data.roles?.map((x:RoleTableListItem)=>({...x,name:(x.name)})), success: true} }else{ message.error(msg || $t(RESPONSE_TIPS.error)) return {data:[], success:false} diff --git a/frontend/packages/core/src/pages/serviceCategory/ServiceCategory.tsx b/frontend/packages/core/src/pages/serviceCategory/ServiceCategory.tsx deleted file mode 100644 index 80579bc4..00000000 --- a/frontend/packages/core/src/pages/serviceCategory/ServiceCategory.tsx +++ /dev/null @@ -1,277 +0,0 @@ -import TreeWithMore from "@common/components/aoplatform/TreeWithMore"; -import WithPermission from "@common/components/aoplatform/WithPermission"; -import { BasicResponse, DELETE_TIPS, RESPONSE_TIPS, STATUS_CODE } from "@common/const/const"; -import { PERMISSION_DEFINITION } from "@common/const/permissions"; -import { useFetch } from "@common/hooks/http"; -import { checkAccess } from "@common/utils/permission"; -import { CategorizesType, ServiceHubCategoryConfigHandle } from "@market/const/serviceHub/type"; -import { App, Button, Spin, Tree, TreeDataNode, TreeProps } from "antd"; -import { DataNode } from "antd/es/tree"; -import { Key, useEffect, useMemo, useRef, useState } from "react"; -import { ServiceHubCategoryConfig } from "./ServiceHubCategoryConfig"; -import { useGlobalContext } from "@common/contexts/GlobalStateContext"; -import { useBreadcrumb } from "@common/contexts/BreadcrumbContext"; -import { LoadingOutlined } from "@ant-design/icons"; -import { cloneDeep } from "lodash-es"; -import { Icon } from "@iconify/react/dist/iconify.js"; -import InsidePage from "@common/components/aoplatform/InsidePage"; -import { EntityItem } from "@common/const/type"; -import { $t } from "@common/locales"; - -export default function ServiceCategory(){ - const [gData, setGData] = useState([]); - const [cateData, setCateData] = useState([]); - const [expandedKeys, setExpandedKeys] = useState([]); - const {message,modal} = App.useApp() - const {fetchData} = useFetch() - const addRef = useRef(null) - const addChildRef = useRef(null) - const renameRef = useRef(null) - const {accessData} = useGlobalContext() - const { setBreadcrumb } = useBreadcrumb() - const [loading, setLoading] = useState(false) - - const onDrop: TreeProps['onDrop'] = (info) => { - const dropKey = info.node.key; - const dragKey = info.dragNode.key; - const dropPos = info.node.pos.split('-'); - const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]); // the drop position relative to the drop node, inside 0, top -1, bottom 1 - - const loop = ( - data: TreeDataNode[], - key: React.Key, - callback: (node: TreeDataNode, i: number, data: TreeDataNode[]) => void, - ) => { - for (let i = 0; i < data.length; i++) { - if (data[i].id === key) { - return callback(data[i], i, data); - } - if (data[i].children) { - loop(data[i].children!, key, callback); - } - } - }; - const data = cloneDeep(gData); - - // Find dragObject - let dragObj: TreeDataNode; - loop(data, dragKey, (item, index, arr) => { - arr.splice(index, 1); - dragObj = item; - }); - - if (!info.dropToGap) { - // Drop on the content - loop(data, dropKey, (item) => { - item.children = item.children || []; - // where to insert. New item was inserted to the start of the array in this example, but can be anywhere - item.children.unshift(dragObj); - }); - } else { - let ar: TreeDataNode[] = []; - let i: number; - loop(data, dropKey, (_item, index, arr) => { - ar = arr; - i = index; - }); - if (dropPosition === -1) { - // Drop on the top of the drop node - ar.splice(i!, 0, dragObj!); - } else { - // Drop on the bottom of the drop node - ar.splice(i! + 1, 0, dragObj!); - } - } - - setGData(data); - sortCategories(data) - }; - - - const dropdownMenu = (entity:CategorizesType) => [ - { - key: 'addChildCate', - label: ( - - ), - }, - { - key: 'renameCate', - label: ( - - ), - }, - { - key: 'delete', - label: ( - - ), - }, - ]; - - const treeData = useMemo(() => { - setExpandedKeys([]) - const loop = (data: CategorizesType[]): DataNode[] => - data?.map((item) => { - if (item.children) { - setExpandedKeys(prev=>[...prev,item.id]) - return { - title: {item.name} , - key: item.id, children: loop(item.children) - }; - } - - return { - title: {item.name}, - key: item.id, - }; - }); - return loop(gData ?? []) - }, [gData]); - - const isActionAllowed = (type:'addCate'|'addChildCate'|'renameCate'|'delete') => { - const actionToPermissionMap = { - 'addCate': 'add', - 'addChildCate': 'add', - 'renameCate': 'edit', - 'delete': 'delete' - }; - - const action = actionToPermissionMap[type]; - const permission :keyof typeof PERMISSION_DEFINITION[0]= `system.api_market.service_classification.${action}`; - - return !checkAccess(permission, accessData); - }; - - const openModal = (type:'addCate'|'addChildCate'|'renameCate'|'delete',entity?:CategorizesType)=>{ - let title:string = '' - let content:string|React.ReactNode = '' - switch (type){ - case 'addCate': - title=$t('添加分类') - content= - break; - case 'addChildCate': - title=$t('添加子分类') - content= - break; - case 'renameCate': - title=$t('重命名分类') - content= - break; - case 'delete': - title=$t('删除') - content=$t(DELETE_TIPS.default) - break; - } - modal.confirm({ - title, - content, - onOk:()=>{ - switch (type){ - case 'addCate': - return addRef.current?.save().then((res)=>{if(res === true) getCategoryList()}) - case 'addChildCate': - return addChildRef.current?.save().then((res)=>{if(res === true) getCategoryList()}) - case 'renameCate': - return renameRef.current?.save().then((res)=>{if(res === true) getCategoryList()}) - case 'delete': - return deleteCate(entity!).then((res)=>{if(res === true) getCategoryList()}) - } - }, - width:600, - okText:$t('确认'), - okButtonProps:{ - disabled : isActionAllowed(type) - }, - cancelText:$t('取消'), - closable:true, - icon:<>, - }) - } - - const deleteCate = (entity:CategorizesType)=>{ - return new Promise((resolve, reject)=>{ - fetchData>('catalogue',{method:'DELETE',eoParams:{catalogue:entity.id},}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || $t(RESPONSE_TIPS.success)) - resolve(true) - }else{ - message.error(msg || $t(RESPONSE_TIPS.error)) - reject(msg || $t(RESPONSE_TIPS.error)) - } - }).catch((errorInfo)=> reject(errorInfo)) - }) - } - - const sortCategories = (newData:CategorizesType[])=>{ - setLoading(true) - fetchData>('catalogue/sort',{method:'PUT',eoBody:newData}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - getCategoryList() - }else{ - setGData(cateData) - message.error(msg || $t(RESPONSE_TIPS.error)) - } - }).catch(()=>{setGData(cateData)}).finally(()=>{setLoading(false)}) - } - - const getCategoryList = ()=>{ - setLoading(true) - fetchData>('catalogues',{method:'GET'}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setGData(data.catalogues) - setCateData(data.catalogues) - }else{ - message.error(msg || $t(RESPONSE_TIPS.error)) - } - }).finally(()=>{setLoading(false)}) - } - - useEffect(()=>{ - setBreadcrumb([ - { - title: $t('服务分类管理')}]) - getCategoryList() - },[]) - - return ( - -
- } spinning={loading} className=''> - {setExpandedKeys(expandedKeys as string[])}} - onDrop={onDrop} - treeData={treeData} - /> - - - - -
-
- ) -} \ No newline at end of file diff --git a/frontend/packages/core/src/pages/serviceCategory/ServiceHubCategoryConfig.tsx b/frontend/packages/core/src/pages/serviceCategory/ServiceHubCategoryConfig.tsx deleted file mode 100644 index 7add0f3c..00000000 --- a/frontend/packages/core/src/pages/serviceCategory/ServiceHubCategoryConfig.tsx +++ /dev/null @@ -1,122 +0,0 @@ -import {App, Form, Input} from "antd"; -import {forwardRef, useEffect, useImperativeHandle} from "react"; -import {BasicResponse, PLACEHOLDER, RESPONSE_TIPS, STATUS_CODE, VALIDATE_MESSAGE} from "@common/const/const.tsx"; -import {useFetch} from "@common/hooks/http.ts"; -import { ServiceHubCategoryConfigHandle, ServiceHubCategoryConfigFieldType, ServiceHubCategoryConfigProps } from "@market/const/serviceHub/type.ts" -import WithPermission from "@common/components/aoplatform/WithPermission"; -import { $t } from "@common/locales"; - -export const ServiceHubCategoryConfig = forwardRef((props,ref)=>{ - const { message } = App.useApp() - const [form] = Form.useForm(); - const {type,entity} = props - const {fetchData} = useFetch() - - const save:()=>Promise = ()=>{ - const url:string = 'catalogue' - let method:string - switch (type){ - case 'addCate': - case 'addChildCate': - method = 'POST' - break; - case 'renameCate': - method = 'PUT' - break - } - return new Promise((resolve, reject)=>{ - if(!url || !method){ - reject($t(RESPONSE_TIPS.error)) - return - } - form.validateFields().then((value)=>{ - fetchData>(url,{method,eoBody:(value), eoParams:{ ...(type === 'renameCate' ? {catalogue:value.id} :undefined)}}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || $t(RESPONSE_TIPS.success)) - resolve(true) - }else{ - message.error(msg || $t(RESPONSE_TIPS.error)) - reject(msg || $t(RESPONSE_TIPS.error)) - } - }).catch((errorInfo)=> reject(errorInfo)) - }).catch((errorInfo)=> reject(errorInfo)) - }) - } - - useImperativeHandle(ref, ()=>({ - save - }) - ) - - useEffect(() => { - - switch(type){ - case 'addCate': - form.setFieldsValue({}) - break - case 'addChildCate': - form.setFieldsValue({parent:entity!.id}) - break - case 'renameCate': - form.setFieldsValue(entity) - break - } - - }, []); - - - return ( - -
- - {type === 'renameCate' && - - label={$t("ID")} - name="id" - hidden - rules={[{ required: true,whitespace:true }]} - > - - - } - {(type === 'addCate' || type === 'renameCate') && - - label={$t("分类名称")} - name="name" - rules={[{ required: true ,whitespace:true }]} - > - - } - - {type === 'addChildCate' &&<> - - label={$t("父分类 ID")} - name="parent" - hidden - rules={[{ required: true,whitespace:true }]} - > - - - - - label={$t("子分类名称")} - name="name" - rules={[{ required: true ,whitespace:true }]} - > - - - - } - -
-) -}) \ No newline at end of file diff --git a/frontend/packages/core/src/pages/system/SystemConfig.tsx b/frontend/packages/core/src/pages/system/SystemConfig.tsx index bfd83ee3..b85e9eac 100644 --- a/frontend/packages/core/src/pages/system/SystemConfig.tsx +++ b/frontend/packages/core/src/pages/system/SystemConfig.tsx @@ -237,7 +237,7 @@ const SystemConfig = forwardRef((_,ref) => { if(accessInit){ getTeamOptionList() }else{ - getGlobalAccessData()?.then(()=>{ + getGlobalAccessData()?.then?.(()=>{ getTeamOptionList() }) } diff --git a/frontend/packages/core/src/pages/system/SystemInsideDocument.tsx b/frontend/packages/core/src/pages/system/SystemInsideDocument.tsx index 411f367d..5755ffa9 100644 --- a/frontend/packages/core/src/pages/system/SystemInsideDocument.tsx +++ b/frontend/packages/core/src/pages/system/SystemInsideDocument.tsx @@ -80,7 +80,7 @@ const ServiceInsideDocument = ()=>{ ], toolbar: 'undo redo | styles | bold italic | alignleft aligncenter alignright alignjustify | codesample |table|' + 'bullist numlist outdent indent | link image | print preview media fullscreen | ' + 'forecolor backcolor emoticons | help', - content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }', + content_style: 'body{ font-family:Helvetica,Arial,sans-serif; font-size:14px } img{ max-width: 100%; }', setup: setupEditor, codesample_languages:[ { diff --git a/frontend/packages/core/src/pages/system/SystemList.tsx b/frontend/packages/core/src/pages/system/SystemList.tsx index fe817614..5a4776ef 100644 --- a/frontend/packages/core/src/pages/system/SystemList.tsx +++ b/frontend/packages/core/src/pages/system/SystemList.tsx @@ -34,7 +34,7 @@ const SystemList:FC = ()=>{ const getSystemList = ()=>{ if(!accessInit){ - getGlobalAccessData()?.then(()=>{ + getGlobalAccessData()?.then?.(()=>{ getSystemList() }) return @@ -63,7 +63,7 @@ const SystemList:FC = ()=>{ const getTeamsList = ()=>{ if(!accessInit){ - getGlobalAccessData()?.then(()=>{ + getGlobalAccessData()?.then?.(()=>{ getTeamsList() }) return diff --git a/frontend/packages/core/src/pages/system/api/SystemInsideApiCreate.tsx b/frontend/packages/core/src/pages/system/api/SystemInsideApiCreate.tsx deleted file mode 100644 index f154021a..00000000 --- a/frontend/packages/core/src/pages/system/api/SystemInsideApiCreate.tsx +++ /dev/null @@ -1,156 +0,0 @@ -import {App, Col, Form, Input, Row, Select} from "antd"; -import {forwardRef, useEffect, useImperativeHandle, useRef} from "react"; -import EditableTableWithModal from "@common/components/aoplatform/EditableTableWithModal.tsx"; -import styles from "./SystemInsideApi.module.css" -import {BasicResponse, PLACEHOLDER, RESPONSE_TIPS, STATUS_CODE, VALIDATE_MESSAGE} from "@common/const/const.tsx"; -import {useFetch} from "@common/hooks/http.ts"; -import { HTTP_METHOD, MATCH_CONFIG } from "../../../const/system/const.tsx"; -import { SystemInsideApiCreateHandle, SystemInsideApiCreateProps, SystemApiProxyFieldType, SystemInsideApiProxyHandle } from "../../../const/system/type.ts"; -import { MatchItem } from "@common/const/type.ts"; -import { validateUrlSlash } from "@common/utils/validate.ts"; -import { $t } from "@common/locales/index.ts"; -import SystemInsideApiProxy from "@core/pages/system/api/SystemInsideApiProxy"; - -const SystemInsideApiCreate = forwardRef((props, ref) => { - const { message } = App.useApp() - const {type, entity, serviceId,teamId, modalApiPrefix:apiPrefix, modalPrefixForce:prefixForce} = props - const [form] = Form.useForm(); - const {fetchData} = useFetch() - const proxyRef = useRef(null) - - const onFinish = ()=>{ - return Promise.all([proxyRef.current?.validate?.(), form.validateFields()]).then(([,formValue])=>{ - const body = {...formValue,path:formValue.path.trim(),proxy:{...formValue.proxy,path:formValue.proxy.path ? (formValue.proxy.path.startsWith('/')? formValue.proxy.path: '/'+ formValue.proxy.path) : undefined}} - return fetchData>('service/api',{method:'POST',eoBody:(body), eoParams: {service:serviceId,team:teamId},eoTransformKeys:['matchType']}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || $t(RESPONSE_TIPS.success)) - return Promise.resolve(true) - }else{ - message.error(msg || $t(RESPONSE_TIPS.error)) - return Promise.reject(msg || $t(RESPONSE_TIPS.error)) - } - }).catch(errInfo=>Promise.reject(errInfo)) - }) - } - - const copy: ()=>Promise = ()=>{ - return new Promise((resolve, reject)=>{ - return form.validateFields().then((value)=>{ - fetchData>('service/api/copy',{method:'POST',eoParams:{service:serviceId,team:teamId, api:entity!.id},eoBody:({...value,path:value.path.trim()})}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || $t(RESPONSE_TIPS.success)) - return resolve(data.api.id) - }else{ - message.error(msg || $t(RESPONSE_TIPS.error)) - return reject(msg || $t(RESPONSE_TIPS.error)) - } - }).catch((errorInfo)=> reject(errorInfo)) - }).catch((errorInfo)=> reject(errorInfo)) - }) - } - - useImperativeHandle(ref, ()=>({ - copy, - save:onFinish - }) - ) - - useEffect(() => { - if(type === 'copy'){ - form.setFieldsValue({ - ...entity, - name:`${$t('副本')}-${entity!.name}`, - ...(prefixForce? - {prefix:apiPrefix,path: entity!.path.substring(apiPrefix?.length|| 0)}: - {}), - proxy:{timeout:10000, retry:0, ...entity?.proxy} - }); - } - else{ - form.setFieldValue('prefix',apiPrefix) - form.setFieldValue(['proxy','timeout'],10000) - form.setFieldValue(['proxy','retry'],0) - } - return (form.setFieldsValue({})) - }, []); - - return (
-
-
- {$t('API 基础信息')} - - label={$t("API 名称")} - name="name" - rules={[{ required: true ,whitespace:true }]} - > - - - - - label={$t("描述")} - name="description" - > - - - - - label={$t("请求方式")} - name="method" - rules={[{ required: true }]} - > - - - - - label={$t("请求路径")} - name="path" - rules={[{ required: true,whitespace:true }, - { - validator: validateUrlSlash, - }]} - className={styles['form-input-group']} - > - - - - - label={$t("高级匹配")} - name="match" - > - - configFields={MATCH_CONFIG} - /> - - {/* } */} - - { type !== 'copy' &&<> - - {$t('转发规则设置')} - - className="mb-0 bg-transparent border-none p-0" - name="proxy" - > - - - } -
-
-
- ) -}) -export default SystemInsideApiCreate \ No newline at end of file diff --git a/frontend/packages/core/src/pages/system/api/SystemInsideApiDetail.tsx b/frontend/packages/core/src/pages/system/api/SystemInsideApiDetail.tsx deleted file mode 100644 index 37b2af84..00000000 --- a/frontend/packages/core/src/pages/system/api/SystemInsideApiDetail.tsx +++ /dev/null @@ -1,99 +0,0 @@ - -import {useEffect, useRef, useState} from "react"; -import {BasicResponse, RESPONSE_TIPS, STATUS_CODE} from "@common/const/const.tsx"; -import {useFetch} from "@common/hooks/http.ts"; -import {App, Button, Spin} from "antd"; -import ApiBasicInfoDisplay from "@common/components/postcat/api/ApiPreview/components/ApiBasicInfoDisplay"; -import ApiPreview from "@common/components/postcat/ApiPreview.tsx"; -import ApiMatch from "@common/components/postcat/api/ApiPreview/components/ApiMatch"; -import {v4 as uuidv4} from 'uuid' -import ApiProxy from "@common/components/postcat/api/ApiPreview/components/ApiProxy"; -import { ProxyHeaderItem, SystemApiDetail, SystemInsideApiDetailProps, SystemInsideApiDocumentHandle } from "../../../const/system/type.ts"; -import { MatchItem } from "@common/const/type.ts"; -import { DrawerWithFooter } from "@common/components/aoplatform/DrawerWithFooter.tsx"; -import SystemInsideApiDocument from "./SystemInsideApiDocument.tsx"; -import ScrollableSection from "@common/components/aoplatform/ScrollableSection.tsx"; -import WithPermission from "@common/components/aoplatform/WithPermission.tsx"; -import { LoadingOutlined } from "@ant-design/icons"; -import { $t } from "@common/locales/index.ts"; - -const SystemInsideApiDetail = (props:SystemInsideApiDetailProps)=>{ - const { message } = App.useApp() - const {serviceId, teamId, apiId} = props - const {fetchData} = useFetch() - const [apiDetail, setApiDetail] = useState() - const [open, setOpen] = useState(false); - const drawerFormRef = useRef(null) - const [loading, setLoading] = useState(false) - - const getApiDetail = ()=>{ - setLoading(true) - fetchData>('service/api/detail',{method:'GET',eoParams:{service:serviceId,team:teamId, api:apiId},eoTransformKeys:['create_time','update_time','match_type','upstream_id','opt_type']}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - const newApiDetail = { - ...data.api, - match:data.api.match?.map((x:MatchItem)=>{x.id = x.id ?? uuidv4();return x}) || [], - ...data.api.proxy && {proxy:{...data.api.proxy, - headers:data.api.proxy?.headers?.map((x:ProxyHeaderItem)=>{x.id = x.id?? uuidv4();return x || [] - })} - } - } - setApiDetail(newApiDetail) - }else{ - message.error(msg || $t(RESPONSE_TIPS.error)) - } - }).finally(()=>{setLoading(false)}) - } - - const onClose = ()=>{ - setOpen(false) - } - - useEffect(() => { - getApiDetail() - }, []); - - return ( - } spinning={loading} className="h-full 1" rootClassName="h-full 2" wrapperClassName="h-full 3" > -
- -
- { - apiDetail !== undefined && <> -
- - -
-

- {$t('创建者')}:{apiDetail?.creator.name || '-'} - {$t('最后编辑人')}:{apiDetail?.updater.name || '-'}{$t('更新时间')}:{apiDetail?.updateTime || '-'}

- } -
-
- { - apiDetail?.match && apiDetail.match?.length > 0 && - - } - - { - apiDetail?.proxy && Object.keys(apiDetail?.proxy).length > 0 && - - } - - {apiDetail && } -
-
- drawerFormRef.current?.save()?.then((res)=>{res&& getApiDetail();return res})} - showLastStep={true} - > - - -
-
) -} -export default SystemInsideApiDetail \ No newline at end of file diff --git a/frontend/packages/core/src/pages/system/api/SystemInsideApiList.tsx b/frontend/packages/core/src/pages/system/api/SystemInsideApiList.tsx deleted file mode 100644 index 7fe9dadb..00000000 --- a/frontend/packages/core/src/pages/system/api/SystemInsideApiList.tsx +++ /dev/null @@ -1,251 +0,0 @@ -import PageList, { PageProColumns } from "@common/components/aoplatform/PageList.tsx" -import {ActionType} from "@ant-design/pro-components"; -import {FC, useEffect, useMemo, useRef, useState} from "react"; -import {Link, useParams} from "react-router-dom"; -import {useBreadcrumb} from "@common/contexts/BreadcrumbContext.tsx"; -import {App, Divider} from "antd"; -import {BasicResponse, COLUMNS_TITLE, DELETE_TIPS, RESPONSE_TIPS, STATUS_CODE} from "@common/const/const.tsx"; -import { SimpleMemberItem} from '@common/const/type.ts' -import {useFetch} from "@common/hooks/http.ts"; -import {RouterParams} from "@core/components/aoplatform/RenderRoutes.tsx"; -import SystemInsideApiCreate from "./SystemInsideApiCreate.tsx"; -import {useSystemContext} from "../../../contexts/SystemContext.tsx"; -import { SYSTEM_API_TABLE_COLUMNS } from "../../../const/system/const.tsx"; -import { SystemApiSimpleFieldType, SystemApiTableListItem, SystemInsideApiCreateHandle, SystemInsideApiDocumentHandle } from "../../../const/system/type.ts"; -import TableBtnWithPermission from "@common/components/aoplatform/TableBtnWithPermission.tsx"; -import { useGlobalContext } from "@common/contexts/GlobalStateContext.tsx"; -import { checkAccess } from "@common/utils/permission.ts"; -import { DrawerWithFooter } from "@common/components/aoplatform/DrawerWithFooter.tsx"; -import SystemInsideApiDetail from "./SystemInsideApiDetail.tsx"; -import SystemInsideApiDocument from "./SystemInsideApiDocument.tsx"; -import { $t } from "@common/locales/index.ts"; - -const SystemInsideApiList:FC = ()=>{ - const [searchWord, setSearchWord] = useState('') - const { setBreadcrumb } = useBreadcrumb() - const { modal,message } = App.useApp() - // const [confirmLoading, setConfirmLoading] = useState(false); - const [init, setInit] = useState(true) - const [tableListDataSource, setTableListDataSource] = useState([]); - const [tableHttpReload, setTableHttpReload] = useState(true); - const {fetchData} = useFetch() - const pageListRef = useRef(null); - const copyRef = useRef(null) - const {apiPrefix, prefixForce} = useSystemContext() - const [memberValueEnum, setMemberValueEnum] = useState([]) - const {accessData,state} = useGlobalContext() - const [drawerType,setDrawerType]= useState<'add'|'edit'|'view'|'upstream'|undefined>() - const [open, setOpen] = useState(false); - const drawerEditFormRef = useRef(null) - const drawerAddFormRef = useRef(null) - const {serviceId, teamId} = useParams() - - const [curApi, setCurApi] = useState() - - const getApiList = (): Promise<{ data: SystemApiTableListItem[], success: boolean }>=> { - //console.log(sorter, filter) - if(!tableHttpReload){ - setTableHttpReload(true) - return Promise.resolve({ - data: tableListDataSource, - success: true, - }); - } - - return fetchData>('service/apis',{method:'GET',eoParams:{service:serviceId,team:teamId, keyword:searchWord},eoTransformKeys:['request_path','create_time','update_time','can_delete']}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setTableListDataSource(data.apis) - setInit((prev)=>prev ? false : prev) - setTableHttpReload(false) - return {data:data.apis, success: true} - }else{ - message.error(msg || $t(RESPONSE_TIPS.error)) - return {data:[], success:false} - } - }).catch(() => { - return {data:[], success:false} - }) - } - - const deleteApi = (entity:SystemApiTableListItem)=>{ - return new Promise((resolve, reject)=>{ - fetchData>('service/api',{method:'DELETE',eoParams:{service:serviceId,team:teamId, api:entity!.id}}).then(response=>{ - const {code,msg} = response - if(code === STATUS_CODE.SUCCESS){ - message.success(msg || $t(RESPONSE_TIPS.success)) - resolve(true) - }else{ - message.error(msg || $t(RESPONSE_TIPS.error)) - reject(msg || $t(RESPONSE_TIPS.error)) - } - }).catch((errorInfo)=> reject(errorInfo)) - }) - } - - const openModal = async (type:'copy' | 'delete',entity:SystemApiTableListItem) =>{ - let title:string = '' - let content:string|React.ReactNode = '' - switch (type){ - case 'copy':{ - title=$t('复制 API') - message.loading($t(RESPONSE_TIPS.loading)) - const {code,data,msg} = await fetchData>('service/api/detail/simple',{method:'GET',eoParams:{service:serviceId,team:teamId, api:entity!.id}}) - message.destroy() - if(code === STATUS_CODE.SUCCESS){ - content= - }else{ - message.error(msg || $t(RESPONSE_TIPS.error)) - return - } - break;} - case 'delete': - title=$t('删除') - content=$t(DELETE_TIPS.default) - break; - } - - modal.confirm({ - title, - content, - onOk:()=> { - switch (type){ - case 'copy': - return copyRef.current?.copy().then(()=> { - manualReloadTable() - }) - case 'delete': - return deleteApi(entity).then((res)=>{if(res === true) manualReloadTable()}) - } - }, - width:type==='copy'? 900: 600, - okText:$t('确认'), - okButtonProps:{ - disabled : !checkAccess( `team.service.api.${type}`, accessData ) - }, - cancelText:$t('取消'), - closable:true, - icon:<>, - }) - } - - const operation:PageProColumns[] =[ - { - title: COLUMNS_TITLE.operate, - key: 'option', - btnNums:4, - fixed:'right', - valueType: 'option', - render: (_: React.ReactNode, entity: SystemApiTableListItem) => [ - {openDrawer('view',entity)}} btnTitle="详情"/>, - , - {openModal('copy',entity)}} btnTitle="复制"/>, - , - {openDrawer('edit',entity)}} btnTitle="编辑"/>, - entity.canDelete && , - entity.canDelete && {openModal('delete',entity)}} btnTitle="删除"/>, - ], - } - ] - - const manualReloadTable = () => { - setTableHttpReload(true); // 表格数据需要从后端接口获取 - pageListRef.current?.reload() - }; - - const getMemberList = async ()=>{ - setMemberValueEnum([]) - const {code,data,msg} = await fetchData>('simple/member',{method:'GET'}) - if(code === STATUS_CODE.SUCCESS){ - setMemberValueEnum(data.members) - }else{ - message.error(msg || $t(RESPONSE_TIPS.error)) - } - } - - const openDrawer = (type:'add'|'edit'|'view',entity?:SystemApiTableListItem)=>{ - setCurApi(entity) - setDrawerType(type) - } - - useEffect(()=>{drawerType !== undefined ? setOpen(true):setOpen(false)},[drawerType]) - - useEffect(() => { - setBreadcrumb([ - { - title:{$t('服务')} - }, - { - title:$t('API') - } - ]) - getMemberList() - manualReloadTable() - }, [serviceId]); - - const onClose = () => { - setDrawerType(undefined); - setCurApi(undefined) - }; - - const columns = useMemo(()=>{ - return [...SYSTEM_API_TABLE_COLUMNS].map(x=>{ - if(x.filters &&((x.dataIndex as string[])?.indexOf('creator') !== -1) ){ - const tmpValueEnum:{[k:string]:{text:string}} = {} - memberValueEnum?.forEach((x:SimpleMemberItem)=>{ - tmpValueEnum[x.name] = {text:x.name} - }) - x.valueEnum = tmpValueEnum - } - return {...x,title:typeof x.title === 'string' ? $t(x.title as string) : x.title}}) - },[memberValueEnum,state.language]) - - const handlerSubmit:() => Promise|undefined= ()=>{ - switch(drawerType){ - case 'add':{ - return drawerAddFormRef.current?.save()?.then((res)=>{res && manualReloadTable();return res}) - } - case 'edit':{ - return drawerEditFormRef.current?.save()?.then((res)=>{res && manualReloadTable();return res}) - } - default:return undefined - } - } - - return ( - <> - getApiList()} - dataSource={tableListDataSource} - addNewBtnTitle={$t('添加 API')} - searchPlaceholder={$t('输入名称、URL 查找 API')} - onAddNewBtnClick={()=>{openDrawer('add')}} - addNewBtnAccess="team.service.api.add" - tableClickAccess="team.service.api.view" - manualReloadTable={manualReloadTable} - onSearchWordChange={(e)=>{setSearchWord(e.target.value)}} - onChange={() => { - setTableHttpReload(false) - }} - onRowClick={(row:SystemApiTableListItem)=>openDrawer('view',row)} - tableClass="mr-PAGE_INSIDE_X " - /> - handlerSubmit()} - showOkBtn={drawerType !== 'view'} - > - {drawerType === 'add' && } - {drawerType === 'edit' && } - {drawerType === 'view' && } - - - ) - -} -export default SystemInsideApiList \ No newline at end of file diff --git a/frontend/packages/core/src/pages/team/TeamInsideMember.tsx b/frontend/packages/core/src/pages/team/TeamInsideMember.tsx index d29f95d8..221a732e 100644 --- a/frontend/packages/core/src/pages/team/TeamInsideMember.tsx +++ b/frontend/packages/core/src/pages/team/TeamInsideMember.tsx @@ -253,7 +253,7 @@ const TeamInsideMember:FC = ()=>{ className="w-full" mode="multiple" value={entity.roles?.map((x:EntityItem)=>x.id)} - options={roleList?.map((x:{id:string,name:string})=>({label:$t(x.name), value:x.id}))} + options={roleList?.map((x:{id:string,name:string})=>({label:(x.name), value:x.id}))} onChange={(value)=>{ changeMemberInfo(value,entity ).then((res)=>{ if(res) manualReloadTable() diff --git a/frontend/packages/core/src/pages/team/TeamList.tsx b/frontend/packages/core/src/pages/team/TeamList.tsx index dc1fab9e..1fba9241 100644 --- a/frontend/packages/core/src/pages/team/TeamList.tsx +++ b/frontend/packages/core/src/pages/team/TeamList.tsx @@ -35,7 +35,7 @@ const TeamList:FC = ()=>{ const getTeamList = ()=>{ if(!accessInit){ - getGlobalAccessData()?.then(()=>{getTeamList()}) + getGlobalAccessData()?.then?.(()=>{getTeamList()}) return } return fetchData>(!checkPermission('system.workspace.team.view_all') ? 'teams':'manager/teams',{method:'GET',eoParams:{keyword:searchWord},eoTransformKeys:['create_time','service_num','can_delete']}).then(response=>{ diff --git a/frontend/packages/market/src/const/serviceHub/type.ts b/frontend/packages/market/src/const/serviceHub/type.ts index 7ebbdab8..970c7fe8 100644 --- a/frontend/packages/market/src/const/serviceHub/type.ts +++ b/frontend/packages/market/src/const/serviceHub/type.ts @@ -17,6 +17,7 @@ export type ServiceBasicInfoType = { logo?:string invokeAddress:string approvalType:'auto'|'manual' + serviceType:'ai'|'rest' } export type ServiceDetailType = { diff --git a/frontend/packages/market/src/pages/serviceHub/ServiceHubDetail.tsx b/frontend/packages/market/src/pages/serviceHub/ServiceHubDetail.tsx index 6d80888d..5d72a86c 100644 --- a/frontend/packages/market/src/pages/serviceHub/ServiceHubDetail.tsx +++ b/frontend/packages/market/src/pages/serviceHub/ServiceHubDetail.tsx @@ -35,7 +35,7 @@ const ServiceHubDetail = ()=>{ const navigate = useNavigate(); const getServiceBasicInfo = ()=>{ - fetchData>('catalogue/service',{method:'GET',eoParams:{service:serviceId}, eoTransformKeys:['app_num','api_num','update_time','api_doc','invoke_address','approval_type']}).then(response=>{ + fetchData>('catalogue/service',{method:'GET',eoParams:{service:serviceId}, eoTransformKeys:['app_num','api_num','update_time','api_doc','invoke_address','approval_type','service_type']}).then(response=>{ const {code,data,msg} = response if(code === STATUS_CODE.SUCCESS){ setService(data.service) @@ -113,7 +113,7 @@ const ServiceHubDetail = ()=>{ { key: 'api-document', label: $t('API 文档'), - children:
, + children:
, icon: } ] diff --git a/frontend/packages/market/src/pages/serviceHub/ServiceHubList.tsx b/frontend/packages/market/src/pages/serviceHub/ServiceHubList.tsx index fc3c449b..1d5e3384 100644 --- a/frontend/packages/market/src/pages/serviceHub/ServiceHubList.tsx +++ b/frontend/packages/market/src/pages/serviceHub/ServiceHubList.tsx @@ -78,7 +78,7 @@ export const initialServiceHubListState = { if(!dataSet.selectedTag || dataSet.selectedTag.length === 0) return false if((!x.tags || !x.tags.length )&& dataSet.selectedTag.indexOf('empty') === -1) return false if(x.tags && x.tags.length && !x.tags.some(tag => dataSet.selectedTag.includes(tag.id))) return false; - if( dataSet.keyword && !x.name.includes(dataSet.keyword)) return false + if( dataSet.keyword && !x.name.toLocaleLowerCase().includes(dataSet.keyword.toLocaleLowerCase())) return false return true }) } diff --git a/frontend/packages/market/src/pages/serviceHub/management/ServiceHubManagement.tsx b/frontend/packages/market/src/pages/serviceHub/management/ServiceHubManagement.tsx index 10684e97..52e27669 100644 --- a/frontend/packages/market/src/pages/serviceHub/management/ServiceHubManagement.tsx +++ b/frontend/packages/market/src/pages/serviceHub/management/ServiceHubManagement.tsx @@ -33,7 +33,7 @@ export default function ServiceHubManagement() { const getServiceList = ()=>{ if(!accessInit){ - getGlobalAccessData()?.then(()=>{getServiceList()}) + getGlobalAccessData()?.then?.(()=>{getServiceList()}) return } setServiceLoading(true) @@ -56,7 +56,7 @@ const getServiceList = ()=>{ const getTeamsList = ()=>{ if(!accessInit){ - getGlobalAccessData()?.then(()=>{getTeamsList()}) + getGlobalAccessData()?.then?.(()=>{getTeamsList()}) return } setPageLoading(true)