diff --git a/apps/admin/app/dashboard/subscribe/protocol-form.tsx b/apps/admin/app/dashboard/subscribe/protocol-form.tsx index ce58f7c..f407bf7 100644 --- a/apps/admin/app/dashboard/subscribe/protocol-form.tsx +++ b/apps/admin/app/dashboard/subscribe/protocol-form.tsx @@ -56,8 +56,8 @@ import { useRef, useState } from 'react'; import { useForm } from 'react-hook-form'; import { toast } from 'sonner'; import { z } from 'zod'; +import { TemplatePreview } from './template-preview'; -// 表单验证规则 - 基于 API.CreateSubscribeApplicationRequest const createClientFormSchema = (t: any) => z.object({ name: z.string().min(1, t('form.validation.nameRequired')), @@ -83,6 +83,8 @@ export function ProtocolForm() { const t = useTranslations('subscribe'); const [loading, setLoading] = useState(false); const [open, setOpen] = useState(false); + const [previewOpen, setPreviewOpen] = useState(false); + const [previewApplicationId, setPreviewApplicationId] = useState(null); const [editingClient, setEditingClient] = useState(null); const tableRef = useRef(null); @@ -136,6 +138,7 @@ export function ProtocolForm() { onCheckedChange={async (checked) => { await updateSubscribeApplication({ ...row.original, + proxy_template: '', is_default: checked, }); tableRef.current?.refresh(); @@ -294,7 +297,6 @@ export function ProtocolForm() { } else { await createSubscribeApplication({ ...data, - proxy_template: '', is_default: false, }); toast.success(t('actions.createSuccess')); @@ -310,6 +312,11 @@ export function ProtocolForm() { } }; + const handlePreview = (application: API.SubscribeApplication) => { + setPreviewApplicationId(application.id); + setPreviewOpen(true); + }; + return ( <> > @@ -322,6 +329,11 @@ export function ProtocolForm() { }} actions={{ render: (row) => [ + , + + + + {t('title')} + + {isLoading ? ( +
+ + {t('loading')} +
+ ) : ( +
+ {getDisplayContent()} +
+ )} +
+
+ + ); +} diff --git a/apps/admin/locales/cs-CZ/subscribe.json b/apps/admin/locales/cs-CZ/subscribe.json index 06931cf..d484814 100644 --- a/apps/admin/locales/cs-CZ/subscribe.json +++ b/apps/admin/locales/cs-CZ/subscribe.json @@ -117,5 +117,16 @@ "outputFormat": "Formát výstupu", "supportedPlatforms": "Podporované platformy" } + }, + "templatePreview": { + "base64": { + "decodeError": "Dekódování selhalo: Obsah není platný formát Base64", + "decodedContent": "Dekódovaný obsah", + "originalContent": "Původní obsah (Base64)" + }, + "failed": "Náhled selhal", + "loading": "Načítání...", + "preview": "Náhled", + "title": "Náhled šablony" } } diff --git a/apps/admin/locales/de-DE/subscribe.json b/apps/admin/locales/de-DE/subscribe.json index ee8a3d2..82f02eb 100644 --- a/apps/admin/locales/de-DE/subscribe.json +++ b/apps/admin/locales/de-DE/subscribe.json @@ -117,5 +117,16 @@ "outputFormat": "Ausgabeformat", "supportedPlatforms": "Unterstützte Plattformen" } + }, + "templatePreview": { + "base64": { + "decodeError": "Dekodierung fehlgeschlagen: Inhalt ist kein gültiges Base64-Format", + "decodedContent": "Dekodierter Inhalt", + "originalContent": "Ursprünglicher Inhalt (Base64)" + }, + "failed": "Vorschau fehlgeschlagen", + "loading": "Wird geladen...", + "preview": "Vorschau", + "title": "Vorlagenvorschau" } } diff --git a/apps/admin/locales/en-US/subscribe.json b/apps/admin/locales/en-US/subscribe.json index ea4ed96..b68ce1b 100644 --- a/apps/admin/locales/en-US/subscribe.json +++ b/apps/admin/locales/en-US/subscribe.json @@ -117,5 +117,16 @@ "outputFormat": "Output Format", "supportedPlatforms": "Supported Platforms" } + }, + "templatePreview": { + "title": "Template Preview", + "preview": "Preview", + "loading": "Loading...", + "failed": "Preview failed", + "base64": { + "originalContent": "Original Content (Base64)", + "decodedContent": "Decoded Content", + "decodeError": "Decode failed: Content is not valid Base64 format" + } } } diff --git a/apps/admin/locales/es-ES/subscribe.json b/apps/admin/locales/es-ES/subscribe.json index af4d6f5..4e10c3f 100644 --- a/apps/admin/locales/es-ES/subscribe.json +++ b/apps/admin/locales/es-ES/subscribe.json @@ -117,5 +117,16 @@ "outputFormat": "Formato de Salida", "supportedPlatforms": "Plataformas Soportadas" } + }, + "templatePreview": { + "base64": { + "decodeError": "Error de decodificación: El contenido no es un formato Base64 válido", + "decodedContent": "Contenido decodificado", + "originalContent": "Contenido original (Base64)" + }, + "failed": "La vista previa ha fallado", + "loading": "Cargando...", + "preview": "Vista previa", + "title": "Vista previa de la plantilla" } } diff --git a/apps/admin/locales/es-MX/subscribe.json b/apps/admin/locales/es-MX/subscribe.json index 3e45777..fa16377 100644 --- a/apps/admin/locales/es-MX/subscribe.json +++ b/apps/admin/locales/es-MX/subscribe.json @@ -117,5 +117,16 @@ "outputFormat": "Formato de Salida", "supportedPlatforms": "Plataformas Soportadas" } + }, + "templatePreview": { + "base64": { + "decodeError": "Error de decodificación: El contenido no es un formato Base64 válido", + "decodedContent": "Contenido decodificado", + "originalContent": "Contenido original (Base64)" + }, + "failed": "La vista previa falló", + "loading": "Cargando...", + "preview": "Vista previa", + "title": "Vista previa de la plantilla" } } diff --git a/apps/admin/locales/fa-IR/subscribe.json b/apps/admin/locales/fa-IR/subscribe.json index 08a6242..1d5da2f 100644 --- a/apps/admin/locales/fa-IR/subscribe.json +++ b/apps/admin/locales/fa-IR/subscribe.json @@ -117,5 +117,16 @@ "outputFormat": "فرمت خروجی", "supportedPlatforms": "پلتفرم‌های پشتیبانی شده" } + }, + "templatePreview": { + "base64": { + "decodeError": "خطا در رمزگشایی: محتوا فرمت Base64 معتبر نیست", + "decodedContent": "محتوای رمزگشایی شده", + "originalContent": "محتوای اصلی (Base64)" + }, + "failed": "پیش‌نمایش ناموفق بود", + "loading": "در حال بارگذاری...", + "preview": "پیش‌نمایش", + "title": "پیش‌نمایش الگو" } } diff --git a/apps/admin/locales/fi-FI/subscribe.json b/apps/admin/locales/fi-FI/subscribe.json index 3c40a7d..1909d7d 100644 --- a/apps/admin/locales/fi-FI/subscribe.json +++ b/apps/admin/locales/fi-FI/subscribe.json @@ -117,5 +117,16 @@ "outputFormat": "Tulostusmuoto", "supportedPlatforms": "Tuetut alustat" } + }, + "templatePreview": { + "base64": { + "decodeError": "Dekoodaus epäonnistui: Sisältö ei ole voimassa olevaa Base64-muotoa", + "decodedContent": "Dekoodattu sisältö", + "originalContent": "Alkuperäinen sisältö (Base64)" + }, + "failed": "Esikatselu epäonnistui", + "loading": "Ladataan...", + "preview": "Esikatselu", + "title": "Mallin esikatselu" } } diff --git a/apps/admin/locales/fr-FR/subscribe.json b/apps/admin/locales/fr-FR/subscribe.json index 9c4f878..dc326ef 100644 --- a/apps/admin/locales/fr-FR/subscribe.json +++ b/apps/admin/locales/fr-FR/subscribe.json @@ -117,5 +117,16 @@ "outputFormat": "Format de sortie", "supportedPlatforms": "Plateformes prises en charge" } + }, + "templatePreview": { + "base64": { + "decodeError": "Échec du décodage : le contenu n'est pas au format Base64 valide", + "decodedContent": "Contenu décodé", + "originalContent": "Contenu original (Base64)" + }, + "failed": "Échec de l'aperçu", + "loading": "Chargement...", + "preview": "Aperçu", + "title": "Aperçu du modèle" } } diff --git a/apps/admin/locales/hi-IN/subscribe.json b/apps/admin/locales/hi-IN/subscribe.json index b8fbf51..c152d53 100644 --- a/apps/admin/locales/hi-IN/subscribe.json +++ b/apps/admin/locales/hi-IN/subscribe.json @@ -117,5 +117,16 @@ "outputFormat": "आउटपुट प्रारूप", "supportedPlatforms": "समर्थित प्लेटफ़ॉर्म" } + }, + "templatePreview": { + "base64": { + "decodeError": "डिकोड विफल: सामग्री मान्य Base64 प्रारूप नहीं है", + "decodedContent": "डिकोड की गई सामग्री", + "originalContent": "मूल सामग्री (Base64)" + }, + "failed": "पूर्वावलोकन विफल", + "loading": "लोड हो रहा है...", + "preview": "पूर्वावलोकन", + "title": "टेम्पलेट पूर्वावलोकन" } } diff --git a/apps/admin/locales/hu-HU/subscribe.json b/apps/admin/locales/hu-HU/subscribe.json index 7d8faaa..ce6b274 100644 --- a/apps/admin/locales/hu-HU/subscribe.json +++ b/apps/admin/locales/hu-HU/subscribe.json @@ -117,5 +117,16 @@ "outputFormat": "Kimeneti Formátum", "supportedPlatforms": "Támogatott Platformok" } + }, + "templatePreview": { + "base64": { + "decodeError": "Dekódolás sikertelen: A tartalom nem érvényes Base64 formátum", + "decodedContent": "Dekódolt Tartalom", + "originalContent": "Eredeti Tartalom (Base64)" + }, + "failed": "Az előnézet nem sikerült", + "loading": "Betöltés...", + "preview": "Előnézet", + "title": "Sablon Előnézet" } } diff --git a/apps/admin/locales/ja-JP/subscribe.json b/apps/admin/locales/ja-JP/subscribe.json index 390688f..07e0e50 100644 --- a/apps/admin/locales/ja-JP/subscribe.json +++ b/apps/admin/locales/ja-JP/subscribe.json @@ -117,5 +117,16 @@ "outputFormat": "出力形式", "supportedPlatforms": "サポートされているプラットフォーム" } + }, + "templatePreview": { + "base64": { + "decodeError": "デコードに失敗しました:コンテンツが有効なBase64形式ではありません", + "decodedContent": "デコードされたコンテンツ", + "originalContent": "オリジナルコンテンツ(Base64)" + }, + "failed": "プレビューに失敗しました", + "loading": "読み込み中...", + "preview": "プレビュー", + "title": "テンプレートプレビュー" } } diff --git a/apps/admin/locales/ko-KR/subscribe.json b/apps/admin/locales/ko-KR/subscribe.json index 5d3ce7c..c32c7fc 100644 --- a/apps/admin/locales/ko-KR/subscribe.json +++ b/apps/admin/locales/ko-KR/subscribe.json @@ -117,5 +117,16 @@ "outputFormat": "출력 형식", "supportedPlatforms": "지원되는 플랫폼" } + }, + "templatePreview": { + "base64": { + "decodeError": "디코드 실패: 콘텐츠가 유효한 Base64 형식이 아닙니다", + "decodedContent": "디코딩된 콘텐츠", + "originalContent": "원본 콘텐츠 (Base64)" + }, + "failed": "미리보기가 실패했습니다", + "loading": "로딩 중...", + "preview": "미리보기", + "title": "템플릿 미리보기" } } diff --git a/apps/admin/locales/no-NO/subscribe.json b/apps/admin/locales/no-NO/subscribe.json index 604c832..11e943e 100644 --- a/apps/admin/locales/no-NO/subscribe.json +++ b/apps/admin/locales/no-NO/subscribe.json @@ -117,5 +117,16 @@ "outputFormat": "Utdataformat", "supportedPlatforms": "Støttede plattformer" } + }, + "templatePreview": { + "base64": { + "decodeError": "Dekoding feilet: Innholdet er ikke i gyldig Base64-format", + "decodedContent": "Dekodet innhold", + "originalContent": "Opprinnelig innhold (Base64)" + }, + "failed": "Forhåndsvisning feilet", + "loading": "Laster...", + "preview": "Forhåndsvisning", + "title": "Malemal" } } diff --git a/apps/admin/locales/pl-PL/subscribe.json b/apps/admin/locales/pl-PL/subscribe.json index ac4552b..843aa16 100644 --- a/apps/admin/locales/pl-PL/subscribe.json +++ b/apps/admin/locales/pl-PL/subscribe.json @@ -117,5 +117,16 @@ "outputFormat": "Format wyjściowy", "supportedPlatforms": "Obsługiwane platformy" } + }, + "templatePreview": { + "base64": { + "decodeError": "Dekodowanie nie powiodło się: Zawartość nie jest w prawidłowym formacie Base64", + "decodedContent": "Zdekodowana zawartość", + "originalContent": "Oryginalna zawartość (Base64)" + }, + "failed": "Nie udało się załadować podglądu", + "loading": "Ładowanie...", + "preview": "Podgląd", + "title": "Podgląd szablonu" } } diff --git a/apps/admin/locales/pt-BR/subscribe.json b/apps/admin/locales/pt-BR/subscribe.json index 4d5d1ee..d9ea2ea 100644 --- a/apps/admin/locales/pt-BR/subscribe.json +++ b/apps/admin/locales/pt-BR/subscribe.json @@ -117,5 +117,16 @@ "outputFormat": "Formato de Saída", "supportedPlatforms": "Plataformas Suportadas" } + }, + "templatePreview": { + "base64": { + "decodeError": "Falha na decodificação: O conteúdo não é um formato Base64 válido", + "decodedContent": "Conteúdo Decodificado", + "originalContent": "Conteúdo Original (Base64)" + }, + "failed": "Falha na prévia", + "loading": "Carregando...", + "preview": "Prévia", + "title": "Prévia do Modelo" } } diff --git a/apps/admin/locales/ro-RO/subscribe.json b/apps/admin/locales/ro-RO/subscribe.json index b39b1f7..b2402a0 100644 --- a/apps/admin/locales/ro-RO/subscribe.json +++ b/apps/admin/locales/ro-RO/subscribe.json @@ -117,5 +117,16 @@ "outputFormat": "Format de Ieșire", "supportedPlatforms": "Platforme Suportate" } + }, + "templatePreview": { + "base64": { + "decodeError": "Decodarea a eșuat: Conținutul nu este un format Base64 valid", + "decodedContent": "Conținut Decodat", + "originalContent": "Conținut Original (Base64)" + }, + "failed": "Previzualizarea a eșuat", + "loading": "Se încarcă...", + "preview": "Previzualizare", + "title": "Previzualizare Șablon" } } diff --git a/apps/admin/locales/ru-RU/subscribe.json b/apps/admin/locales/ru-RU/subscribe.json index 39cc163..3b94b53 100644 --- a/apps/admin/locales/ru-RU/subscribe.json +++ b/apps/admin/locales/ru-RU/subscribe.json @@ -117,5 +117,16 @@ "outputFormat": "Формат вывода", "supportedPlatforms": "Поддерживаемые платформы" } + }, + "templatePreview": { + "base64": { + "decodeError": "Ошибка декодирования: Содержимое не является допустимым форматом Base64", + "decodedContent": "Декодированное содержимое", + "originalContent": "Исходное содержимое (Base64)" + }, + "failed": "Не удалось загрузить предварительный просмотр", + "loading": "Загрузка...", + "preview": "Предварительный просмотр", + "title": "Предварительный просмотр шаблона" } } diff --git a/apps/admin/locales/th-TH/subscribe.json b/apps/admin/locales/th-TH/subscribe.json index 1e296b6..a42b8bd 100644 --- a/apps/admin/locales/th-TH/subscribe.json +++ b/apps/admin/locales/th-TH/subscribe.json @@ -117,5 +117,16 @@ "outputFormat": "รูปแบบผลลัพธ์", "supportedPlatforms": "แพลตฟอร์มที่รองรับ" } + }, + "templatePreview": { + "base64": { + "decodeError": "การถอดรหัสล้มเหลว: เนื้อหาไม่ใช่รูปแบบ Base64 ที่ถูกต้อง", + "decodedContent": "เนื้อหาที่ถอดรหัสแล้ว", + "originalContent": "เนื้อหาต้นฉบับ (Base64)" + }, + "failed": "การดูตัวอย่างล้มเหลว", + "loading": "กำลังโหลด...", + "preview": "ดูตัวอย่าง", + "title": "ตัวอย่างแม่แบบ" } } diff --git a/apps/admin/locales/tr-TR/subscribe.json b/apps/admin/locales/tr-TR/subscribe.json index cbe708d..50236c7 100644 --- a/apps/admin/locales/tr-TR/subscribe.json +++ b/apps/admin/locales/tr-TR/subscribe.json @@ -117,5 +117,16 @@ "outputFormat": "Çıktı Formatı", "supportedPlatforms": "Desteklenen Platformlar" } + }, + "templatePreview": { + "base64": { + "decodeError": "Çözme başarısız oldu: İçerik geçerli bir Base64 formatında değil", + "decodedContent": "Çözülmüş İçerik", + "originalContent": "Orijinal İçerik (Base64)" + }, + "failed": "Önizleme başarısız oldu", + "loading": "Yükleniyor...", + "preview": "Önizleme", + "title": "Şablon Önizlemesi" } } diff --git a/apps/admin/locales/uk-UA/subscribe.json b/apps/admin/locales/uk-UA/subscribe.json index 82c212b..f8cf135 100644 --- a/apps/admin/locales/uk-UA/subscribe.json +++ b/apps/admin/locales/uk-UA/subscribe.json @@ -117,5 +117,16 @@ "outputFormat": "Формат виходу", "supportedPlatforms": "Підтримувані платформи" } + }, + "templatePreview": { + "base64": { + "decodeError": "Не вдалося декодувати: вміст не є дійсним форматом Base64", + "decodedContent": "Декодований вміст", + "originalContent": "Оригінальний вміст (Base64)" + }, + "failed": "Не вдалося відобразити попередній перегляд", + "loading": "Завантаження...", + "preview": "Перегляд", + "title": "Попередній перегляд шаблону" } } diff --git a/apps/admin/locales/vi-VN/subscribe.json b/apps/admin/locales/vi-VN/subscribe.json index f57e08a..44de401 100644 --- a/apps/admin/locales/vi-VN/subscribe.json +++ b/apps/admin/locales/vi-VN/subscribe.json @@ -117,5 +117,16 @@ "outputFormat": "Định dạng Đầu ra", "supportedPlatforms": "Nền tảng Hỗ trợ" } + }, + "templatePreview": { + "base64": { + "decodeError": "Giải mã không thành công: Nội dung không phải định dạng Base64 hợp lệ", + "decodedContent": "Nội dung đã giải mã", + "originalContent": "Nội dung gốc (Base64)" + }, + "failed": "Xem trước không thành công", + "loading": "Đang tải...", + "preview": "Xem trước", + "title": "Xem trước mẫu" } } diff --git a/apps/admin/locales/zh-CN/subscribe.json b/apps/admin/locales/zh-CN/subscribe.json index a5a4390..24a951d 100644 --- a/apps/admin/locales/zh-CN/subscribe.json +++ b/apps/admin/locales/zh-CN/subscribe.json @@ -117,5 +117,16 @@ "outputFormat": "输出格式", "supportedPlatforms": "支持的平台" } + }, + "templatePreview": { + "title": "模板预览", + "preview": "预览", + "loading": "加载中...", + "failed": "预览失败", + "base64": { + "originalContent": "原始内容 (Base64)", + "decodedContent": "解码后内容", + "decodeError": "解码失败:内容不是有效的Base64格式" + } } } diff --git a/apps/admin/locales/zh-HK/subscribe.json b/apps/admin/locales/zh-HK/subscribe.json index b4b371b..29b54e1 100644 --- a/apps/admin/locales/zh-HK/subscribe.json +++ b/apps/admin/locales/zh-HK/subscribe.json @@ -117,5 +117,16 @@ "outputFormat": "輸出格式", "supportedPlatforms": "支持的平台" } + }, + "templatePreview": { + "base64": { + "decodeError": "解碼失敗:內容不是有效的 Base64 格式", + "decodedContent": "解碼內容", + "originalContent": "原始內容(Base64)" + }, + "failed": "預覽失敗", + "loading": "加載中...", + "preview": "預覽", + "title": "範本預覽" } } diff --git a/apps/admin/services/admin/application.ts b/apps/admin/services/admin/application.ts index 194f29c..0ff2011 100644 --- a/apps/admin/services/admin/application.ts +++ b/apps/admin/services/admin/application.ts @@ -17,6 +17,24 @@ export async function createSubscribeApplication( }); } +/** Preview Template GET /v1/admin/application/preview */ +export async function previewSubscribeTemplate( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.PreviewSubscribeTemplateParams, + options?: { [key: string]: any }, +) { + return request( + '/v1/admin/application/preview', + { + method: 'GET', + params: { + ...params, + }, + ...(options || {}), + }, + ); +} + /** Update subscribe application PUT /v1/admin/application/subscribe_application */ export async function updateSubscribeApplication( body: API.UpdateSubscribeApplicationRequest, diff --git a/apps/admin/services/admin/index.ts b/apps/admin/services/admin/index.ts index 4ebecd4..bdf189b 100644 --- a/apps/admin/services/admin/index.ts +++ b/apps/admin/services/admin/index.ts @@ -1,5 +1,5 @@ // @ts-ignore - + // API 更新时间: // API 唯一标识: import * as ads from './ads'; diff --git a/apps/admin/services/admin/typings.d.ts b/apps/admin/services/admin/typings.d.ts index 06c1dc5..c779294 100644 --- a/apps/admin/services/admin/typings.d.ts +++ b/apps/admin/services/admin/typings.d.ts @@ -342,7 +342,6 @@ declare namespace API { scheme?: string; user_agent: string; is_default: boolean; - proxy_template: string; template: string; output_format: string; download_link: DownloadLink; @@ -1213,6 +1212,19 @@ declare namespace API { orderNo: string; }; + type PreviewSubscribeTemplateParams = { + id: number; + }; + + type PreviewSubscribeTemplateRequest = { + id: number; + }; + + type PreviewSubscribeTemplateResponse = { + /** 预览的模板内容 */ + template: string; + }; + type PrivacyPolicyConfig = { privacy_policy: string; }; @@ -1505,7 +1517,6 @@ declare namespace API { scheme?: string; user_agent: string; is_default: boolean; - proxy_template: string; template: string; output_format: string; download_link?: DownloadLink; diff --git a/apps/admin/services/common/common.ts b/apps/admin/services/common/common.ts index 7c81712..fbf90bd 100644 --- a/apps/admin/services/common/common.ts +++ b/apps/admin/services/common/common.ts @@ -1,5 +1,5 @@ // @ts-ignore - +/* eslint-disable */ import request from '@/utils/request'; /** Get Ads GET /v1/common/ads */ @@ -45,13 +45,10 @@ export async function checkVerificationCode( /** Get Client GET /v1/common/client */ export async function getClient(options?: { [key: string]: any }) { - return request( - '/v1/common/client', - { - method: 'GET', - ...(options || {}), - }, - ); + return request('/v1/common/client', { + method: 'GET', + ...(options || {}), + }); } /** Get verification code POST /v1/common/send_code */ diff --git a/apps/admin/services/common/index.ts b/apps/admin/services/common/index.ts index 73b3bda..61ba129 100644 --- a/apps/admin/services/common/index.ts +++ b/apps/admin/services/common/index.ts @@ -1,5 +1,5 @@ // @ts-ignore - + // API 更新时间: // API 唯一标识: import * as auth from './auth'; diff --git a/apps/admin/services/common/typings.d.ts b/apps/admin/services/common/typings.d.ts index e871f67..1012fcd 100644 --- a/apps/admin/services/common/typings.d.ts +++ b/apps/admin/services/common/typings.d.ts @@ -293,9 +293,9 @@ declare namespace API { protocol: string[]; }; - type GetSubscribeApplicationListResponse = { + type GetSubscribeClientResponse = { total: number; - list: SubscribeApplication[]; + list: SubscribeClient[]; }; type GetTosResponse = { @@ -779,20 +779,14 @@ declare namespace API { updated_at: number; }; - type SubscribeApplication = { + type SubscribeClient = { id: number; name: string; description?: string; icon?: string; scheme?: string; - user_agent: string; is_default: boolean; - proxy_template: string; - template: string; - output_format: string; download_link?: DownloadLink; - created_at: number; - updated_at: number; }; type SubscribeConfig = { diff --git a/apps/user/services/common/common.ts b/apps/user/services/common/common.ts index 7c81712..fbf90bd 100644 --- a/apps/user/services/common/common.ts +++ b/apps/user/services/common/common.ts @@ -1,5 +1,5 @@ // @ts-ignore - +/* eslint-disable */ import request from '@/utils/request'; /** Get Ads GET /v1/common/ads */ @@ -45,13 +45,10 @@ export async function checkVerificationCode( /** Get Client GET /v1/common/client */ export async function getClient(options?: { [key: string]: any }) { - return request( - '/v1/common/client', - { - method: 'GET', - ...(options || {}), - }, - ); + return request('/v1/common/client', { + method: 'GET', + ...(options || {}), + }); } /** Get verification code POST /v1/common/send_code */ diff --git a/apps/user/services/common/index.ts b/apps/user/services/common/index.ts index 73b3bda..61ba129 100644 --- a/apps/user/services/common/index.ts +++ b/apps/user/services/common/index.ts @@ -1,5 +1,5 @@ // @ts-ignore - + // API 更新时间: // API 唯一标识: import * as auth from './auth'; diff --git a/apps/user/services/common/typings.d.ts b/apps/user/services/common/typings.d.ts index e871f67..1012fcd 100644 --- a/apps/user/services/common/typings.d.ts +++ b/apps/user/services/common/typings.d.ts @@ -293,9 +293,9 @@ declare namespace API { protocol: string[]; }; - type GetSubscribeApplicationListResponse = { + type GetSubscribeClientResponse = { total: number; - list: SubscribeApplication[]; + list: SubscribeClient[]; }; type GetTosResponse = { @@ -779,20 +779,14 @@ declare namespace API { updated_at: number; }; - type SubscribeApplication = { + type SubscribeClient = { id: number; name: string; description?: string; icon?: string; scheme?: string; - user_agent: string; is_default: boolean; - proxy_template: string; - template: string; - output_format: string; download_link?: DownloadLink; - created_at: number; - updated_at: number; }; type SubscribeConfig = { diff --git a/apps/user/services/user/index.ts b/apps/user/services/user/index.ts index f988131..12fe8d0 100644 --- a/apps/user/services/user/index.ts +++ b/apps/user/services/user/index.ts @@ -1,5 +1,5 @@ // @ts-ignore - + // API 更新时间: // API 唯一标识: import * as announcement from './announcement'; diff --git a/apps/user/services/user/typings.d.ts b/apps/user/services/user/typings.d.ts index 7312230..d2e86c0 100644 --- a/apps/user/services/user/typings.d.ts +++ b/apps/user/services/user/typings.d.ts @@ -275,11 +275,6 @@ declare namespace API { methods: UserAuthMethod[]; }; - type GetSubscribeApplicationListResponse = { - total: number; - list: SubscribeApplication[]; - }; - type GetSubscribeLogParams = { page: number; size: number; @@ -877,22 +872,6 @@ declare namespace API { updated_at: number; }; - type SubscribeApplication = { - id: number; - name: string; - description?: string; - icon?: string; - scheme?: string; - user_agent: string; - is_default: boolean; - proxy_template: string; - template: string; - output_format: string; - download_link?: DownloadLink; - created_at: number; - updated_at: number; - }; - type SubscribeConfig = { single_model: boolean; subscribe_path: string; diff --git a/packages/ui/src/custom-components/editor/go-template.tsx b/packages/ui/src/custom-components/editor/go-template.tsx index 721a7d6..48d6d4f 100644 --- a/packages/ui/src/custom-components/editor/go-template.tsx +++ b/packages/ui/src/custom-components/editor/go-template.tsx @@ -66,6 +66,7 @@ const REGEX_PATTERNS = { FIELD_PATH: /^(\.\w+(?:\.\w+)*)$/, NESTED_DOT: /(\.\w+(?:\.\w+)*)\./, NESTED_VAR: /(\$\w+\.\w+(?:\.\w+)*)\.$/, + VAR_DOT: /(\$\w+)\.$/, NESTED_GENERAL: /([\w.]+)\.$/, WORD_WITH_SPACES: /(\s*)(\S*)$/, LEADING_SPACES: /^(\s+)/, @@ -694,6 +695,33 @@ export function GoTemplateEditor({ schema, enableSprig = true, ...props }: GoTem }); } }); + } else if ( + isSchemaProperty(currentSchema) && + currentSchema.type === 'array' && + currentSchema.items && + currentSchema.items.type === 'object' && + currentSchema.items.properties + ) { + Object.keys(currentSchema.items.properties).forEach((key) => { + const prop = currentSchema.items!.properties![key]; + if (isSchemaProperty(prop)) { + items.push({ + label: key, + kind: COMPLETION_KINDS.PROPERTY, + insertText: key, + documentation: `${prop.description || key} (${prop.type}) - from array item`, + sortText: `${SORT_PREFIXES.NESTED}${key}`, + }); + } else { + items.push({ + label: key, + kind: COMPLETION_KINDS.PROPERTY, + insertText: key, + documentation: `Field: ${key} - from array item`, + sortText: `${SORT_PREFIXES.NESTED}${key}`, + }); + } + }); } return items; @@ -848,24 +876,67 @@ export function GoTemplateEditor({ schema, enableSprig = true, ...props }: GoTem Math.max(templateStartNormal, templateStartTrim) + (templateStartTrim > templateStartNormal ? 3 : 2); const actualStart = Math.max(wordStart, templateStart); - const currentWord = textUntilPosition.substring(actualStart).trim(); + const currentWord = textUntilPosition.substring(actualStart); + const currentWordTrimmed = currentWord.trim(); - let dotMatches = currentWord.match(REGEX_PATTERNS.NESTED_DOT); + let dotMatches = currentWordTrimmed.match(REGEX_PATTERNS.NESTED_DOT); if (!dotMatches) { const beforeCursor = textUntilPosition.substring(Math.max(templateStart, 0)); dotMatches = beforeCursor.match(REGEX_PATTERNS.NESTED_DOT) || beforeCursor.match(REGEX_PATTERNS.NESTED_VAR) || + beforeCursor.match(REGEX_PATTERNS.VAR_DOT) || beforeCursor.match(REGEX_PATTERNS.NESTED_GENERAL); } - const isNestedField = dotMatches && textUntilPosition.endsWith('.') && schema; - const justTypedDot = currentWord.endsWith('.') || textUntilPosition.endsWith('.'); + const varDotMatch = textUntilPosition.match(REGEX_PATTERNS.VAR_DOT); + const isVarDot = + varDotMatch && + textUntilPosition.endsWith('.') && + schema && + activeRangeField && + rangeVariable; + + const isNestedField = + (dotMatches && textUntilPosition.endsWith('.') && schema) || isVarDot; + + const justTypedDot = + currentWordTrimmed.endsWith('.') || textUntilPosition.endsWith('.'); const justTypedSpace = textUntilPosition.endsWith(' '); - const wordForFiltering = justTypedDot ? currentWord.slice(0, -1) : currentWord; + let wordForFiltering = currentWordTrimmed; + if (justTypedDot) { + wordForFiltering = currentWordTrimmed.slice(0, -1); + } + + if ((justTypedDot && activeRangeField) || isVarDot) { + console.log('Go Template Debug:', { + justTypedDot, + isVarDot, + varDotMatch, + activeRangeField, + rangeVariable, + currentWord, + currentWordTrimmed, + wordForFiltering, + textUntilPosition, + allCompletionsCount: allCompletions.length, + }); + } + + if (isNestedField && schema) { + let fieldPath = ''; + + if (isVarDot && varDotMatch) { + // 处理变量后跟点的情况 ($n.) + const variableName = varDotMatch[1]; + if (variableName === rangeVariable && activeRangeField) { + // 使用activeRangeField作为字段路径 + fieldPath = activeRangeField; + } + } else if (dotMatches && dotMatches[1]) { + fieldPath = dotMatches[1]; + } - if (isNestedField && schema && dotMatches) { - const fieldPath = dotMatches[1]; if (fieldPath) { const nestedCompletions = getNestedFieldCompletions( schema, @@ -889,26 +960,45 @@ export function GoTemplateEditor({ schema, enableSprig = true, ...props }: GoTem ); }; - const isRangeContextItem = (item: CompletionItem): boolean => { - return ( - isVariableOrFieldItem(item) || - item.sortText?.startsWith(SORT_PREFIXES.ROOT_IN_RANGE) - ); - }; - const filteredCompletions = allCompletions.filter((item) => { if (isNestedField) { return item.sortText?.startsWith(SORT_PREFIXES.NESTED); } + if (justTypedDot && activeRangeField) { + return ( + item.label.startsWith('.') || + item.label.startsWith('$') || + item.sortText?.startsWith(SORT_PREFIXES.RANGE_VAR) || + item.sortText?.startsWith(SORT_PREFIXES.VAR_FIELD) || + item.sortText?.startsWith(SORT_PREFIXES.CURRENT) || + item.sortText?.startsWith(SORT_PREFIXES.ROOT_FIELD) || + item.sortText?.startsWith(SORT_PREFIXES.ROOT_IN_RANGE) + ); + } + if (justTypedDot) { - return activeRangeField ? isRangeContextItem(item) : isVariableOrFieldItem(item); + return isVariableOrFieldItem(item); } if (justTypedSpace) { return true; } + if ( + activeRangeField && + (item.sortText?.startsWith(SORT_PREFIXES.RANGE_VAR) || + item.sortText?.startsWith(SORT_PREFIXES.VAR_FIELD) || + item.sortText?.startsWith(SORT_PREFIXES.CURRENT)) + ) { + if (!wordForFiltering) { + return true; + } + const label = item.label.toLowerCase(); + const word = wordForFiltering.toLowerCase(); + return label.includes(word) || label.startsWith(word) || word === ''; + } + if (!wordForFiltering) { return true; } @@ -1006,18 +1096,11 @@ export function GoTemplateEditor({ schema, enableSprig = true, ...props }: GoTem const wordMatch = templateContent.match(REGEX_PATTERNS.WORD_WITH_SPACES); if (wordMatch) { const [, leadingSpaces, currentWordInTemplate] = wordMatch; - if (leadingSpaces && currentWordInTemplate) { + if (currentWordInTemplate) { startColumn = templateStart + templateContent.length - currentWordInTemplate.length; - } else { - const spaceMatch = templateContent.match(REGEX_PATTERNS.LEADING_SPACES); - if ( - spaceMatch && - spaceMatch[1] && - templateContent.trim() === currentWordInTemplate - ) { - startColumn = templateStart + spaceMatch[1].length; - } + } else if (leadingSpaces) { + startColumn = position.column; } } } diff --git a/packages/ui/src/custom-components/editor/monaco-editor.tsx b/packages/ui/src/custom-components/editor/monaco-editor.tsx index aa78a28..de485b4 100644 --- a/packages/ui/src/custom-components/editor/monaco-editor.tsx +++ b/packages/ui/src/custom-components/editor/monaco-editor.tsx @@ -20,6 +20,7 @@ export interface MonacoEditorProps { beforeMount?: (monaco: Monaco) => void; language?: string; className?: string; + showLineNumbers?: boolean; } // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -43,6 +44,7 @@ export function MonacoEditor({ beforeMount, language = 'markdown', className, + showLineNumbers = false, }: MonacoEditorProps) { const [internalValue, setInternalValue] = useState(propValue); const [isFullscreen, setIsFullscreen] = useState(false); @@ -133,7 +135,7 @@ export function MonacoEditor({ formatOnPaste: true, formatOnType: true, glyphMargin: false, - lineNumbers: 'off', + lineNumbers: showLineNumbers ? 'on' : 'off', minimap: { enabled: false }, overviewRulerLanes: 0, renderLineHighlight: 'none',