diff --git a/web/src/components/common/KeyValueEditor.vue b/web/src/components/common/KeyValueEditor.vue
new file mode 100644
index 00000000..c5914d6b
--- /dev/null
+++ b/web/src/components/common/KeyValueEditor.vue
@@ -0,0 +1,118 @@
+
+
+
+
+
+ updateKey(String(key), (e.target as HTMLInputElement).value)"
+ />
+ {{ separator }}
+ updateValue(String(key), (e.target as HTMLInputElement).value)"
+ />
+
+ {{ $gettext('Remove') }}
+
+
+
+ {{ addButtonText }}
+
+
+
diff --git a/web/src/views/website/EditView.vue b/web/src/views/website/EditView.vue
index b53562d6..cfc10ae6 100644
--- a/web/src/views/website/EditView.vue
+++ b/web/src/views/website/EditView.vue
@@ -11,6 +11,7 @@ import draggable from 'vuedraggable'
import cert from '@/api/panel/cert'
import home from '@/api/panel/home'
import website from '@/api/panel/website'
+import KeyValueEditor from '@/components/common/KeyValueEditor.vue'
const { $gettext } = useGettext()
let messageReactive: MessageReactive | null = null
@@ -248,15 +249,6 @@ const removeUpstream = (index: number) => {
}
}
-// 为上游添加服务器
-const addServerToUpstream = (index: number) => {
- const upstream = setting.value.upstreams[index]
- if (!upstream.servers) {
- upstream.servers = {}
- }
- upstream.servers[`127.0.0.1:${8080 + Object.keys(upstream.servers).length}`] = ''
-}
-
// 更新上游超时时间值
const updateUpstreamTimeoutValue = (upstream: any, value: number) => {
const parsed = parseDuration(upstream.resolver_timeout)
@@ -373,61 +365,6 @@ const isCacheEnabled = (proxy: any) => {
return proxy.cache !== null && proxy.cache !== undefined
}
-// 添加缓存有效期规则
-const addCacheValidRule = (proxy: any) => {
- if (!proxy.cache) return
- if (!proxy.cache.valid) proxy.cache.valid = {}
- proxy.cache.valid[`any`] = '5m'
-}
-
-// 删除缓存有效期规则
-const removeCacheValidRule = (proxy: any, codes: string) => {
- if (proxy.cache?.valid) {
- delete proxy.cache.valid[codes]
- }
-}
-
-// 不缓存条件选项
-const noCacheConditionOptions = [
- { label: '$cookie_nocache', value: '$cookie_nocache' },
- { label: '$arg_nocache', value: '$arg_nocache' },
- { label: '$http_pragma', value: '$http_pragma' },
- { label: '$http_authorization', value: '$http_authorization' },
- { label: '$http_cache_control', value: '$http_cache_control' }
-]
-
-// 过期缓存使用策略选项
-const useStaleOptions = [
- { label: 'error', value: 'error' },
- { label: 'timeout', value: 'timeout' },
- { label: 'updating', value: 'updating' },
- { label: 'http_500', value: 'http_500' },
- { label: 'http_502', value: 'http_502' },
- { label: 'http_503', value: 'http_503' },
- { label: 'http_504', value: 'http_504' }
-]
-
-// 缓存方法选项
-const cacheMethodOptions = [
- { label: 'GET', value: 'GET' },
- { label: 'HEAD', value: 'HEAD' },
- { label: 'POST', value: 'POST' }
-]
-
-// HTTP 协议版本选项
-const httpVersionOptions = [
- { label: 'HTTP/1.0', value: '1.0' },
- { label: 'HTTP/1.1', value: '1.1' },
- { label: 'HTTP/2', value: '2' }
-]
-
-// 大小单位选项
-const sizeUnitOptions = [
- { label: 'KB', value: 'k' },
- { label: 'MB', value: 'm' },
- { label: 'GB', value: 'g' }
-]
-
// 从字节解析为 {value, unit} 格式
const parseSize = (bytes: number): { value: number; unit: string } => {
if (!bytes || bytes <= 0) return { value: 0, unit: 'm' }
@@ -459,30 +396,6 @@ const buildSize = (value: number, unit: string): number => {
}
}
-// 重试条件选项
-const retryConditionOptions = [
- { label: 'error', value: 'error' },
- { label: 'timeout', value: 'timeout' },
- { label: 'invalid_header', value: 'invalid_header' },
- { label: 'http_500', value: 'http_500' },
- { label: 'http_502', value: 'http_502' },
- { label: 'http_503', value: 'http_503' },
- { label: 'http_504', value: 'http_504' },
- { label: 'http_429', value: 'http_429' },
- { label: 'non_idempotent', value: 'non_idempotent' },
- { label: 'off', value: 'off' }
-]
-
-// 常见隐藏响应头选项
-const hideHeaderOptions = [
- { label: 'X-Powered-By', value: 'X-Powered-By' },
- { label: 'Server', value: 'Server' },
- { label: 'X-AspNet-Version', value: 'X-AspNet-Version' },
- { label: 'X-AspNetMvc-Version', value: 'X-AspNetMvc-Version' },
- { label: 'X-Runtime', value: 'X-Runtime' },
- { label: 'X-Version', value: 'X-Version' }
-]
-
// 创建默认超时配置
const createDefaultTimeoutConfig = () => ({
connect: 60 * SECOND,
@@ -601,13 +514,6 @@ const updateRetryTimeoutUnit = (proxy: any, unit: string) => {
proxy.retry.timeout = buildDuration(parsed.value, unit)
}
-// 添加响应头
-const addResponseHeader = (proxy: any) => {
- if (!proxy.response_headers) return
- if (!proxy.response_headers.add) proxy.response_headers.add = {}
- proxy.response_headers.add['X-Custom-Header'] = 'value'
-}
-
// 删除代理
const removeProxy = (index: number) => {
if (setting.value.proxies) {
@@ -781,39 +687,7 @@ const realIPEnabled = computed({
}
})
-// 真实 IP Header 选项
-const realIPHeaderOptions = [
- { label: 'X-Real-IP', value: 'X-Real-IP' },
- { label: 'X-Forwarded-For', value: 'X-Forwarded-For' },
- { label: 'CF-Connecting-IP', value: 'CF-Connecting-IP' },
- { label: 'True-Client-IP', value: 'True-Client-IP' },
- { label: 'Ali-Cdn-Real-Ip', value: 'Ali-Cdn-Real-Ip' },
- { label: 'EO-Connecting-IP', value: 'EO-Connecting-IP' }
-]
-
-// 添加基本认证用户
-const addBasicAuthUser = () => {
- if (!setting.value.basic_auth) {
- setting.value.basic_auth = {}
- }
- const index = Object.keys(setting.value.basic_auth).length + 1
- setting.value.basic_auth[`user${index}`] = ''
-}
-
-// 删除基本认证用户
-const removeBasicAuthUser = (username: string) => {
- if (setting.value.basic_auth) {
- delete setting.value.basic_auth[username]
- }
-}
-
// ========== 自定义配置相关 ==========
-// 作用域选项
-const scopeOptions = [
- { label: $gettext('This Website'), value: 'site' },
- { label: $gettext('Global'), value: 'shared' }
-]
-
// 添加自定义配置
const addCustomConfig = () => {
if (!setting.value.custom_configs) {
@@ -1007,47 +881,13 @@ const removeCustomConfig = (index: number) => {
-
-
- {
- const oldAddr = String(address)
- if (newAddr && newAddr !== oldAddr) {
- upstream.servers[newAddr] = upstream.servers[oldAddr]
- delete upstream.servers[oldAddr]
- }
- }
- "
- />
- (upstream.servers[String(address)] = v)"
- />
-
- {{ $gettext('Remove') }}
-
-
-
- {{ $gettext('Add Server') }}
-
-
+
@@ -1178,59 +1018,26 @@ const removeCustomConfig = (index: number) => {
-
-
- {
- const newCodes = (e.target as HTMLInputElement).value
- const oldCodes = String(codes)
- if (newCodes && newCodes !== oldCodes && proxy.cache?.valid) {
- proxy.cache.valid[newCodes] = proxy.cache.valid[oldCodes]
- delete proxy.cache.valid[oldCodes]
- }
- }
- "
- />
- =
- {
- if (proxy.cache?.valid) proxy.cache.valid[String(codes)] = v
- }
- "
- />
-
- {{ $gettext('Remove') }}
-
-
-
- {{ $gettext('Add Cache Valid Rule') }}
-
-
+
{
@@ -1269,7 +1084,11 @@ const removeCustomConfig = (index: number) => {
@@ -1288,58 +1107,13 @@ const removeCustomConfig = (index: number) => {
-
-
- {
- const newName = (e.target as HTMLInputElement).value
- const oldName = String(headerName)
- if (newName && newName !== oldName) {
- proxy.headers[newName] = proxy.headers[oldName]
- delete proxy.headers[oldName]
- }
- }
- "
- />
- =
- (proxy.headers[String(headerName)] = v)"
- />
-
- {{ $gettext('Remove') }}
-
-
- {
- if (!proxy.headers) proxy.headers = {}
- proxy.headers[`X-Custom-${Object.keys(proxy.headers).length}`] = ''
- }
- "
- >
- {{ $gettext('Add Request Header') }}
-
-
+
@@ -1347,58 +1121,15 @@ const removeCustomConfig = (index: number) => {
:title="$gettext('Response Content Replacement')"
name="replaces"
>
-
-
- {
- const newFrom = (e.target as HTMLInputElement).value
- const oldFrom = String(fromValue)
- if (newFrom && newFrom !== oldFrom) {
- proxy.replaces[newFrom] = proxy.replaces[oldFrom]
- delete proxy.replaces[oldFrom]
- }
- }
- "
- />
- =>
- (proxy.replaces[String(fromValue)] = v)"
- />
-
- {{ $gettext('Remove') }}
-
-
- {
- if (!proxy.replaces) proxy.replaces = {}
- proxy.replaces[`/old_${Object.keys(proxy.replaces).length}`] = '/new'
- }
- "
- >
- {{ $gettext('Add Replacement Rule') }}
-
-
+
@@ -1412,7 +1143,11 @@ const removeCustomConfig = (index: number) => {
@@ -1437,7 +1172,11 @@ const removeCustomConfig = (index: number) => {
:value="
parseSize(proxy.client_max_body_size || 1024 * 1024).unit || 'm'
"
- :options="sizeUnitOptions"
+ :options="[
+ { label: 'KB', value: 'k' },
+ { label: 'MB', value: 'm' },
+ { label: 'GB', value: 'g' }
+ ]"
style="width: 80px"
@update:value="(v: string) => updateClientMaxBodySizeUnit(proxy, v)"
/>
@@ -1558,7 +1297,18 @@ const removeCustomConfig = (index: number) => {
@@ -1629,7 +1379,14 @@ const removeCustomConfig = (index: number) => {
{
/>
-
-
- {
- const newName = (e.target as HTMLInputElement).value
- const oldName = String(headerName)
- if (newName && newName !== oldName) {
- proxy.response_headers.add[newName] =
- proxy.response_headers.add[oldName]
- delete proxy.response_headers.add[oldName]
- }
- }
- "
- />
- =
-
- (proxy.response_headers.add[String(headerName)] = v)
- "
- />
-
- {{ $gettext('Remove') }}
-
-
-
- {{ $gettext('Add Response Header') }}
-
-
+
@@ -2046,7 +1763,14 @@ const removeCustomConfig = (index: number) => {
@@ -2065,53 +1789,15 @@ const removeCustomConfig = (index: number) => {
-
-
- {
- const oldUsername = String(username)
- if (newUsername && newUsername !== oldUsername) {
- // 检查新用户名是否已存在
- if (setting.basic_auth[newUsername] !== undefined) {
- return
- }
- setting.basic_auth[newUsername] = setting.basic_auth[oldUsername]
- delete setting.basic_auth[oldUsername]
- }
- }
- "
- />
- (setting.basic_auth[String(username)] = v)"
- />
-
- {{ $gettext('Remove') }}
-
-
-
- {{ $gettext('Add User') }}
-
-
+
@@ -2156,7 +1842,13 @@ const removeCustomConfig = (index: number) => {
/>
-
+