fix: Optimized proxy configure drawer content (#10097)

* fix: Update proxy settings interface, add tabs and optimize style

* fix: update i18n text

* fix: reset modified data

* fix: Optimize proxy settings interface, remove unnecessary options and adjust SNI settings display logic

* fix: Optimize proxy settings interface, replace custom style tag to tailwind.css class

* fix: Update i18n text
This commit is contained in:
KOMATA 2025-08-22 15:46:49 +08:00 committed by GitHub
parent 89491eac56
commit b6fbacc992
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 261 additions and 100 deletions

View file

@ -2254,6 +2254,10 @@ const message = {
null: 'none',
nginxConfig: 'Nginx configuration',
websiteConfig: 'Website settings',
proxySettings: 'Proxy Settings',
advancedSettings: 'Advanced Settings',
cacheSettings: 'Cache Settings',
sniSettings: 'SNI Settings',
basic: 'Basic',
source: 'Configuration',
security: 'Security',
@ -2381,11 +2385,15 @@ const message = {
modifierHelper:
'Example: "=" is exact match, "~" is regular match, "^~" matches the beginning of the path, etc.',
replace: 'Text replacements',
replaceHelper:
'The nginx text replacement feature allows for string substitution in the response content during reverse proxying. It is commonly used to modify links, API addresses, etc., in HTML, CSS, JavaScript, and other files returned by the backend. It supports regular expression matching for complex content replacement needs.',
addReplace: 'Add',
replaced: 'Search String (cannot be empty)',
replaceText: 'Replace with string',
replacedErr: 'The Search String cannot be empty',
replacedErr2: 'The Search String cannot be repeated',
replacedListEmpty: 'No text replacement rules',
proxySslName: 'Proxy SNI Name',
basicAuth: 'Basic authentication',
editBasicAuthHelper:
'The password is asymmetrically encrypted and cannot be echoed. Editing needs to reset the password',

View file

@ -2169,6 +2169,10 @@ const message = {
null: 'なし',
nginxConfig: 'nginx構成',
websiteConfig: 'ウェブサイトの設定',
proxySettings: 'プロキシ設定',
advancedSettings: '詳細設定',
cacheSettings: 'キャッシュ設定',
sniSettings: 'SNI設定',
basic: '基本',
source: '構成',
security: '安全',
@ -2295,11 +2299,15 @@ const message = {
modifier: '一致するルール',
modifierHelper: ': "="は正確な一致 "〜"は通常の一致^はパスの始まりなどと一致します',
replace: 'テキスト置換',
replaceHelper:
'nginxのテキスト置換機能はリバースプロキシ時にレスポンス内容の文字列を置換することができますバックエンドから返されるHTMLCSSJavaScriptなどのファイル内のリンクアドレスAPIアドレスなどを変更するためによく使用されます正規表現マッチングをサポートしており複雑なコンテンツ置換のニーズに対応できます',
addReplace: '追加',
replaced: '検索文字列空にすることはできません',
replaceText: '文字列に置き換えます',
replacedErr: '検索文字列を空にすることはできません',
replacedErr2: '検索文字列を繰り返すことはできません',
replacedListEmpty: 'テキスト置換ルールがありません',
proxySslName: 'プロキシSNI名',
basicAuth: '基本認証',
editBasicAuthHelper:
'パスワードは非対称的に暗号化されており反響することはできません編集はパスワードをリセットする必要があります',

View file

@ -2131,6 +2131,10 @@ const message = {
null: '없음',
nginxConfig: 'Nginx 설정',
websiteConfig: '웹사이트 설정',
proxySettings: '프록시 설정',
advancedSettings: '고급 설정',
cacheSettings: '캐시 설정',
sniSettings: 'SNI 설정',
basic: '기본',
source: '구성',
security: '보안',
@ -2254,11 +2258,15 @@ const message = {
modifier: '매칭 규칙',
modifierHelper: ': = 정확히 일치, ~ 정규식 일치, ^~ 경로 시작 부분 일치 등을 나타냅니다.',
replace: '텍스트 교체',
replaceHelper:
'nginx 텍스트 교체 기능은 리버스 프록시 응답 내용의 문자열을 대체할 있습니다. 백엔드에서 반환된 HTML, CSS, JavaScript 기타 파일의 링크, API 주소 등을 수정하는 일반적으로 사용됩니다. 복잡한 콘텐츠 교체 요구 사항에 대해 정규식 일치를 지원합니다.',
addReplace: '추가',
replaced: '검색 문자열 (비울 없음)',
replaceText: '교체할 문자열',
replacedErr: '검색 문자열은 비워둘 없습니다',
replacedErr2: '검색 문자열은 중복될 없습니다',
replacedListEmpty: '텍스트 교체 규칙 없음',
proxySslName: '프록시 SNI 이름',
basicAuth: '기본 인증',
editBasicAuthHelper:
'비밀번호는 비대칭으로 암호화되어 표시할 없습니다. 수정하려면 비밀번호를 재설정해야 합니다.',

View file

@ -2223,6 +2223,10 @@ const message = {
null: 'tiada',
nginxConfig: 'Konfigurasi Nginx',
websiteConfig: 'Tetapan Laman Web',
proxySettings: 'Tetapan Proksi',
advancedSettings: 'Tetapan Lanjutan',
cacheSettings: 'Tetapan Cache',
sniSettings: 'Tetapan SNI',
basic: 'Asas',
source: 'Konfigurasi',
security: 'Keselamatan',
@ -2349,11 +2353,15 @@ const message = {
modifierHelper:
'Contoh: "=" adalah padanan tepat, "~" adalah padanan biasa, "^~" memadankan permulaan laluan, dan sebagainya.',
replace: 'Penggantian Teks',
replaceHelper:
'Ciri penggantian teks nginx membenarkan penggantian rentetan dalam kandungan respons semasa proksi terbalik. Ia biasanya digunakan untuk mengubah suai pautan, alamat API, dll., dalam HTML, CSS, JavaScript, dan fail lain yang dikembalikan oleh backend. Ia menyokong padanan ungkapan biasa untuk keperluan penggantian kandungan yang kompleks.',
addReplace: 'Tambah',
replaced: 'String Carian (tidak boleh kosong)',
replaceText: 'Ganti dengan string',
replacedErr: 'String Carian tidak boleh kosong',
replacedErr2: 'String Carian tidak boleh berulang',
replacedListEmpty: 'Tiada peraturan penggantian teks',
proxySslName: 'Nama SNI Proksi',
basicAuth: 'Pengesahan Asas',
editBasicAuthHelper:
'Kata laluan disulitkan secara tidak simetri dan tidak dapat dipaparkan. Penyuntingan perlu menetapkan semula kata laluan',

View file

@ -2220,6 +2220,10 @@ const message = {
null: 'nenhum',
nginxConfig: 'Configuração Nginx',
websiteConfig: 'Configurações do site',
proxySettings: 'Configurações de Proxy',
advancedSettings: 'Configurações Avançadas',
cacheSettings: 'Configurações de Cache',
sniSettings: 'Configurações de SNI',
basic: 'Básico',
source: 'Configuração',
security: 'Segurança',
@ -2347,11 +2351,15 @@ const message = {
modifierHelper:
'Exemplo: "=" é correspondência exata, "~" é correspondência regular, "^~" corresponde ao início do caminho, etc.',
replace: 'Substituições de texto',
replaceHelper:
'O recurso de substituição de texto do nginx permite a substituição de strings no conteúdo da resposta durante o proxy reverso. É comumente usado para modificar links, endereços de API, etc., em arquivos HTML, CSS, JavaScript e outros retornados pelo backend. Suporta correspondência de expressão regular para necessidades complexas de substituição de conteúdo.',
addReplace: 'Adicionar',
replaced: 'String de busca (não pode estar vazia)',
replaceText: 'Substituir por string',
replacedErr: 'A string de busca não pode estar vazia',
replacedErr2: 'A string de busca não pode ser repetida',
replacedListEmpty: 'Nenhuma regra de substituição de texto',
proxySslName: 'Nome SNI do Proxy',
basicAuth: 'Autenticação básica',
editBasicAuthHelper:
'A senha é criptografada de forma assimétrica e não pode ser exibida. A edição requer a redefinição da senha',

View file

@ -2216,6 +2216,10 @@ const message = {
null: 'нет',
nginxConfig: 'Конфигурация Nginx',
websiteConfig: 'Настройки веб-сайта',
proxySettings: 'Proxy Ayarları',
advancedSettings: 'Gelişmiş Ayarlar',
cacheSettings: 'Önbellek Ayarları',
sniSettings: 'SNI Ayarları',
basic: 'Основные',
source: 'Конфигурация',
security: 'Безопасность',
@ -2345,11 +2349,15 @@ const message = {
modifier: 'Правила сопоставления',
modifierHelper: 'Пример: "=" точное совпадение, "~" регулярное совпадение, "^~" совпадение начала пути и т.д.',
replace: 'Замены текста',
replaceHelper:
'Функция замены текста в nginx позволяет заменять строки в содержимом ответа при обратном проксировании. Она обычно используется для изменения ссылок, адресов API и т.д. в файлах HTML, CSS, JavaScript и других, возвращаемых бэкендом. Поддерживает сопоставление с регулярными выражениями для сложных потребностей в замене содержимого.',
addReplace: 'Добавить',
replaced: 'Искомая строка (не может быть пустой)',
replaceText: 'Заменить на строку',
replacedErr: 'Искомая строка не может быть пустой',
replacedErr2: 'Искомая строка не может повторяться',
replacedListEmpty: 'Нет правил замены текста',
proxySslName: 'Имя прокси SNI',
basicAuth: 'Базовая аутентификация',
editBasicAuthHelper:
'Пароль асимметрично зашифрован и не может быть показан. При редактировании нужно сбросить пароль',

View file

@ -2281,6 +2281,10 @@ const message = {
null: 'hiçbiri',
nginxConfig: 'Nginx yapılandırması',
websiteConfig: 'Web sitesi ayarları',
proxySettings: 'Proxy Ayarları',
advancedSettings: 'Gelişmiş Ayarlar',
cacheSettings: 'Önbellek Ayarları',
sniSettings: 'SNI Ayarları',
basic: 'Temel',
source: 'Yapılandırma',
security: 'Güvenlik',
@ -2409,11 +2413,15 @@ const message = {
modifier: 'Eşleştirme kuralları',
modifierHelper: 'Örnek: "=" tam eşleşme, "~" düzenli eşleşme, "^~" yolun başlangıcıyla eşleşme vb.',
replace: 'Metin değiştirmeleri',
replaceHelper:
'Nginx metin değiştirme özelliği, ters proxy sırasında yanıt içeriğindeki dizelerin değiştirilmesine olanak tanır. Genellikle arka tarafından döndürülen HTML, CSS, JavaScript ve diğer dosyalardaki bağlantıları, API adreslerini vb. değiştirmek için kullanılır. Karmaşık içerik değiştirme ihtiyaçları için normal ifade eşleştirmeyi destekler.',
addReplace: 'Ekle',
replaced: 'Arama Dizisi (boş olamaz)',
replaceText: 'Şununla değiştir',
replacedErr: 'Arama Dizisi boş olamaz',
replacedErr2: 'Arama Dizisi tekrarlanamaz',
replacedListEmpty: 'Metin değiştirme kuralı yok',
proxySslName: 'Proxy SNI Adı',
basicAuth: 'Temel kimlik doğrulama',
editBasicAuthHelper:
'Şifre asimetrik olarak şifrelenir ve geri alınamaz. Düzenleme, şifrenin sıfırlanmasını gerektirir',

View file

@ -2103,6 +2103,10 @@ const message = {
null: '無',
nginxConfig: 'Nginx配置',
websiteConfig: '網站設置',
proxySettings: '代理設定',
advancedSettings: '進階設定',
cacheSettings: '快取設定',
sniSettings: 'SNI 設定',
basic: '基本',
source: '配置文件',
security: '安全',
@ -2222,11 +2226,15 @@ const message = {
modifier: '匹配規則',
modifierHelper: '= 精確匹配~ 正則匹配^~ 匹配路徑開頭 ',
replace: '文本替換',
replaceHelper:
'nginx文本替換功能可以在反向代理時對響應內容進行字符串替換常用於修改代理後端返回的HTMLCSSJavaScript等文件中的鏈接地址API接口地址等支持正則表達式匹配可實現複雜的內容替換需求',
addReplace: '添加文本替換',
replaced: '搜索字符串不能為空',
replaceText: '替換為字符串',
replacedErr: '搜索字符串不能為空',
replacedErr2: '搜索字符串不能重復',
replacedListEmpty: '無文本替換規則',
proxySslName: '代理 SNI 名稱',
basicAuth: '密碼訪問',
editBasicAuthHelper: '密碼為非對稱加密無法回顯編輯需要重新設置密碼',
antiLeech: '防盜鏈',

View file

@ -2093,6 +2093,10 @@ const message = {
null: '无',
nginxConfig: 'Nginx配置',
websiteConfig: '网站设置',
proxySettings: '代理设置',
advancedSettings: '高级设置',
cacheSettings: '缓存设置',
sniSettings: 'SNI 设置',
basic: '基本',
source: '配置文件',
security: '安全',
@ -2212,11 +2216,15 @@ const message = {
modifier: '匹配规则',
modifierHelper: '= 精确匹配~ 正则匹配^~ 匹配路径开头 ',
replace: '文本替换',
replaceHelper:
'nginx文本替换功能可以在反向代理时对响应内容进行字符串替换常用于修改代理后端返回的HTMLCSSJavaScript等文件中的链接地址API接口地址等支持正则表达式匹配可实现复杂的内容替换需求',
addReplace: '添加文本替换',
replaced: '搜索字符串不能为空',
replaceText: '替换为字符串',
replacedErr: '搜索字符串不能为空',
replacedErr2: '搜索字符串不能重复',
replacedListEmpty: '无文本替换规则',
proxySslName: '代理 SNI 名称',
basicAuth: '密码访问',
editBasicAuthHelper: '密码为非对称加密无法回显编辑需要重新设置密码',
antiLeech: '防盗链',

View file

@ -1,110 +1,197 @@
<template>
<DrawerPro v-model="open" :header="$t('commons.button.' + proxy.operate)" @close="handleClose" size="normal">
<el-form ref="proxyForm" label-position="top" :model="proxy" :rules="rules" v-loading="loading">
<el-form-item :label="$t('commons.table.name')" prop="name">
<el-input v-model.trim="proxy.name" :disabled="proxy.operate === 'edit'"></el-input>
</el-form-item>
<el-form-item :label="$t('website.modifier')" prop="modifier">
<el-input v-model.trim="proxy.modifier"></el-input>
<div>
<span class="input-help">{{ $t('website.modifierHelper') }}</span>
</div>
</el-form-item>
<el-form-item :label="$t('website.proxyPath')" prop="match">
<el-input v-model.trim="proxy.match"></el-input>
</el-form-item>
<el-form-item :label="$t('website.enableCache')" prop="cache">
<el-switch v-model="proxy.cache" @change="changeCache(proxy.cache)"></el-switch>
</el-form-item>
<el-form-item :label="$t('website.browserCacheTime')" prop="cacheTime" v-if="proxy.cache">
<el-input v-model.number="proxy.cacheTime" maxlength="15">
<template #append>
<el-select v-model="proxy.cacheUnit" class="p-w-100">
<el-option
v-for="(unit, index) in Units"
:key="index"
:label="unit.label"
:value="unit.value"
></el-option>
</el-select>
</template>
</el-input>
<span class="input-help">{{ $t('website.browserCacheTimeHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('website.serverCacheTime')" prop="cacheTime" v-if="proxy.cache">
<el-input v-model.number="proxy.serverCacheTime" maxlength="15">
<template #append>
<el-select v-model="proxy.serverCacheUnit" class="p-w-100">
<el-option
v-for="(unit, index) in Units"
:key="index"
:label="unit.label"
:value="unit.value"
></el-option>
</el-select>
</template>
</el-input>
<span class="input-help">{{ $t('website.serverCacheTimeHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('website.sni')" prop="sni">
<el-switch v-model="proxy.sni"></el-switch>
<span class="input-help">{{ $t('website.sniHelper') }}</span>
</el-form-item>
<el-form-item label="proxy_ssl_name" prop="proxySSLName" v-if="proxy.sni">
<el-input v-model.trim="proxy.proxySSLName"></el-input>
</el-form-item>
<el-row :gutter="10">
<el-col :span="12">
<el-form-item :label="$t('website.proxyPass')" prop="proxyAddress">
<el-input
v-model.trim="proxy.proxyAddress"
:placeholder="$t('website.proxyHelper')"
@blur="getProxyHost"
>
<template #prepend>
<el-select v-model="proxy.proxyProtocol" class="pre-select">
<el-option label="http" value="http://" />
<el-option label="https" value="https://" />
<el-option :label="$t('website.other')" value="" />
</el-select>
</template>
</el-input>
<div>
<span class="input-help">{{ $t('website.proxyPassHelper') }}</span>
</div>
<el-tabs v-model="activeTab" type="border-card">
<el-tab-pane :label="$t('website.proxySettings')" name="basic">
<el-divider content-position="left">{{ $t('website.proxy') }}</el-divider>
<el-form-item :label="$t('commons.table.name')" prop="name">
<el-input v-model.trim="proxy.name" :disabled="proxy.operate === 'edit'" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="$t('website.proxyHost')" prop="proxyHost">
<el-input v-model.trim="proxy.proxyHost"></el-input>
<div>
<span class="input-help">{{ $t('website.proxyHostHelper') }}</span>
</div>
</el-form-item>
</el-col>
</el-row>
<el-form-item :label="$t('website.replace')">
<div style="width: 100%" v-for="(replace, index) in replaces" :key="index">
<el-row :gutter="10">
<el-col :span="10">
<el-input v-model.trim="replace.key" :placeholder="$t('website.replaced')"></el-input>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item :label="$t('website.modifier')" prop="modifier">
<el-input v-model.trim="proxy.modifier" />
<div class="flex items-center gap-1 mt-1 text-xs">
<el-icon class="text-sm"><QuestionFilled /></el-icon>
<span>{{ $t('website.modifierHelper') }}</span>
</div>
</el-form-item>
</el-col>
<el-col :span="10">
<el-input v-model.trim="replace.value" :placeholder="$t('website.replaceText')"></el-input>
</el-col>
<el-col :span="2">
<el-button link @click="removeReplace(index)" type="danger">
{{ $t('commons.button.delete') }}
</el-button>
<el-col :span="12">
<el-form-item :label="$t('website.proxyPath')" prop="match">
<el-input v-model.trim="proxy.match" />
</el-form-item>
</el-col>
</el-row>
</div>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="addReplaces">
{{ $t('website.addReplace') }}
</el-button>
</el-form-item>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item :label="$t('website.proxyPass')" prop="proxyAddress">
<el-input
v-model.trim="proxy.proxyAddress"
:placeholder="$t('website.proxyHelper')"
@blur="getProxyHost"
>
<template #prepend>
<el-select v-model="proxy.proxyProtocol" class="!w-24">
<el-option label="http" value="http://" />
<el-option label="https" value="https://" />
</el-select>
</template>
</el-input>
<div class="flex items-center gap-1 mt-1 text-xs">
<el-icon class="text-sm"><QuestionFilled /></el-icon>
<span>{{ $t('website.proxyPassHelper') }}</span>
</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="$t('website.proxyHost')" prop="proxyHost">
<el-input v-model.trim="proxy.proxyHost" />
<div class="flex items-center gap-1 mt-1 text-xs">
<el-icon class="text-sm"><QuestionFilled /></el-icon>
<span>{{ $t('website.proxyHostHelper') }}</span>
</div>
</el-form-item>
</el-col>
</el-row>
<template v-if="proxy.proxyProtocol === 'https://'">
<el-divider content-position="left">{{ $t('website.sniSettings') }}</el-divider>
<div class="flex justify-between items-center py-3">
<div class="flex flex-col gap-1">
<span class="font-medium">{{ $t('website.sni') }}</span>
<div class="flex items-center gap-1 mt-1 text-xs">
<el-icon class="text-sm"><QuestionFilled /></el-icon>
<span>{{ $t('website.sniHelper') }}</span>
</div>
</div>
<el-switch v-model="proxy.sni" size="large" />
</div>
<el-form-item
:label="$t('website.proxySslName')"
prop="proxySSLName"
v-if="proxy.sni"
class="mt-4"
>
<el-input v-model.trim="proxy.proxySSLName" />
</el-form-item>
</template>
</el-tab-pane>
<el-tab-pane :label="$t('website.advancedSettings')" name="advanced">
<el-divider content-position="left">{{ $t('website.cacheSettings') }}</el-divider>
<div class="flex justify-between items-center py-3">
<div class="flex flex-col gap-1">
<span class="font-medium">{{ $t('website.enableCache') }}</span>
</div>
<el-switch v-model="proxy.cache" @change="changeCache(proxy.cache)" size="large" />
</div>
<el-collapse-transition>
<div v-if="proxy.cache" class="mt-4">
<el-row :gutter="16">
<el-col :span="12">
<el-form-item :label="$t('website.browserCacheTime')" prop="cacheTime">
<el-input v-model.number="proxy.cacheTime" maxlength="15">
<template #append>
<el-select v-model="proxy.cacheUnit" class="!w-24">
<el-option
v-for="(unit, index) in Units"
:key="index"
:label="unit.label"
:value="unit.value"
/>
</el-select>
</template>
</el-input>
<div class="flex items-center gap-1 mt-1 text-xs">
<el-icon class="text-sm"><QuestionFilled /></el-icon>
<span>{{ $t('website.browserCacheTimeHelper') }}</span>
</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="$t('website.serverCacheTime')" prop="serverCacheTime">
<el-input v-model.number="proxy.serverCacheTime" maxlength="15">
<template #append>
<el-select v-model="proxy.serverCacheUnit" class="!w-24">
<el-option
v-for="(unit, index) in Units"
:key="index"
:label="unit.label"
:value="unit.value"
/>
</el-select>
</template>
</el-input>
<div class="flex items-center gap-1 mt-1 text-xs">
<el-icon class="text-sm"><QuestionFilled /></el-icon>
<span>{{ $t('website.serverCacheTimeHelper') }}</span>
</div>
</el-form-item>
</el-col>
</el-row>
</div>
</el-collapse-transition>
<el-divider content-position="left">{{ $t('website.replace') }}</el-divider>
<div class="replace-section">
<div v-if="replaces.length === 0" class="empty-state">
<el-empty :image-size="60" :description="$t('website.replacedListEmpty')" />
</div>
<div v-else class="replace-list">
<div v-for="(replace, index) in replaces" :key="index" class="mb-3">
<div class="flex justify-between items-center mb-3">
<span class="text-sm font-medium">Rule {{ index + 1 }}</span>
<el-button @click="removeReplace(index)" type="danger" link size="small">
<el-icon><Delete /></el-icon>
{{ $t('commons.button.delete') }}
</el-button>
</div>
<el-row :gutter="16">
<el-col :span="11">
<el-input
v-model.trim="replace.key"
:placeholder="$t('website.replaced')"
size="default"
>
<template #prepend>Search</template>
</el-input>
</el-col>
<el-col :span="2" class="flex items-center justify-center">
<el-icon size="16"><ArrowRight /></el-icon>
</el-col>
<el-col :span="11">
<el-input
v-model.trim="replace.value"
:placeholder="$t('website.replaceText')"
size="default"
>
<template #prepend>Replace</template>
</el-input>
</el-col>
</el-row>
</div>
</div>
<div class="text-center mt-4">
<el-button type="primary" @click="addReplaces" :icon="Plus">
{{ $t('website.addReplace') }}
</el-button>
</div>
<div class="flex items-center gap-1 mt-1 text-xs">
<el-icon class="text-sm"><QuestionFilled /></el-icon>
<span>{{ $t('website.replaceHelper') }}</span>
</div>
</div>
</el-tab-pane>
</el-tabs>
</el-form>
<template #footer>
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
@ -125,6 +212,7 @@ import { MsgError, MsgSuccess } from '@/utils/message';
import { Website } from '@/api/interface/website';
import { Units } from '@/global/mimetype';
import { isDomain } from '@/utils/util';
import { QuestionFilled, Delete, Plus, ArrowRight } from '@element-plus/icons-vue';
const proxyForm = ref<FormInstance>();
const rules = ref({
@ -137,6 +225,7 @@ const rules = ref({
});
const open = ref(false);
const loading = ref(false);
const activeTab = ref('basic');
const initData = (): Website.ProxyConfig => ({
id: 0,