diff --git a/app/service/key/key_manager.py b/app/service/key/key_manager.py
index 94b9ae6..73d897b 100644
--- a/app/service/key/key_manager.py
+++ b/app/service/key/key_manager.py
@@ -34,7 +34,7 @@ class KeyManager:
return next(self.key_cycle)
async def get_next_vertex_key(self) -> str:
- """获取下一个 Vertex API key"""
+ """获取下一个 Vertex Express API key"""
async with self.vertex_key_cycle_lock:
return next(self.vertex_key_cycle)
@@ -98,7 +98,7 @@ class KeyManager:
return current_key
async def get_next_working_vertex_key(self) -> str:
- """获取下一可用的 Vertex API key"""
+ """获取下一可用的 Vertex Express API key"""
initial_key = await self.get_next_vertex_key()
current_key = initial_key
@@ -124,12 +124,12 @@ class KeyManager:
return ""
async def handle_vertex_api_failure(self, api_key: str, retries: int) -> str:
- """处理 Vertex API 调用失败"""
+ """处理 Vertex Express API 调用失败"""
async with self.vertex_failure_count_lock:
self.vertex_key_failure_counts[api_key] += 1
if self.vertex_key_failure_counts[api_key] >= self.MAX_FAILURES:
logger.warning(
- f"Vertex API key {api_key} has failed {self.MAX_FAILURES} times"
+ f"Vertex Express API key {api_key} has failed {self.MAX_FAILURES} times"
)
def get_fail_count(self, key: str) -> int:
@@ -156,7 +156,7 @@ class KeyManager:
return {"valid_keys": valid_keys, "invalid_keys": invalid_keys}
async def get_vertex_keys_by_status(self) -> dict:
- """获取分类后的 Vertex API key 列表,包括失败次数"""
+ """获取分类后的 Vertex Express API key 列表,包括失败次数"""
valid_keys = {}
invalid_keys = {}
@@ -178,8 +178,7 @@ class KeyManager:
if self.api_keys:
return self.api_keys[0]
if not self.api_keys:
- logger.warning(
- "API key list is empty, cannot get first valid key.")
+ logger.warning("API key list is empty, cannot get first valid key.")
return ""
return self.api_keys[0]
@@ -214,7 +213,7 @@ async def get_key_manager_instance(
)
if vertex_api_keys is None:
raise ValueError(
- "Vertex API keys are required to initialize or re-initialize the KeyManager instance."
+ "Vertex Express API keys are required to initialize or re-initialize the KeyManager instance."
)
if not api_keys:
@@ -223,12 +222,12 @@ async def get_key_manager_instance(
)
if not vertex_api_keys:
logger.warning(
- "Initializing KeyManager with an empty list of Vertex API keys."
+ "Initializing KeyManager with an empty list of Vertex Express API keys."
)
_singleton_instance = KeyManager(api_keys, vertex_api_keys)
logger.info(
- f"KeyManager instance created/re-created with {len(api_keys)} API keys and {len(vertex_api_keys)} Vertex API keys."
+ f"KeyManager instance created/re-created with {len(api_keys)} API keys and {len(vertex_api_keys)} Vertex Express API keys."
)
# 1. 恢复失败计数
@@ -253,8 +252,7 @@ async def get_key_manager_instance(
_singleton_instance.vertex_key_failure_counts = (
current_vertex_failure_counts
)
- logger.info(
- "Inherited failure counts for applicable Vertex keys.")
+ logger.info("Inherited failure counts for applicable Vertex keys.")
_preserved_vertex_failure_counts = None
# 2. 调整 key_cycle 的起始点
@@ -351,7 +349,7 @@ async def get_key_manager_instance(
break
except ValueError:
logger.warning(
- f"Preserved next key '{_preserved_vertex_next_key_in_cycle}' not found in preserved old Vertex API keys. "
+ f"Preserved next key '{_preserved_vertex_next_key_in_cycle}' not found in preserved old Vertex Express API keys. "
"New cycle will start from the beginning of the new list."
)
except Exception as e:
@@ -372,12 +370,12 @@ async def get_key_manager_instance(
)
except ValueError:
logger.warning(
- f"Determined start key '{start_key_for_new_vertex_cycle}' not found in new Vertex API keys during cycle advancement. "
+ f"Determined start key '{start_key_for_new_vertex_cycle}' not found in new Vertex Express API keys during cycle advancement. "
"New cycle will start from the beginning."
)
except StopIteration:
logger.error(
- "StopIteration while advancing Vertex key cycle, implies empty new Vertex API key list previously missed."
+ "StopIteration while advancing Vertex key cycle, implies empty new Vertex Express API key list previously missed."
)
except Exception as e:
logger.error(
@@ -386,11 +384,11 @@ async def get_key_manager_instance(
else:
if _singleton_instance.vertex_api_keys:
logger.info(
- "New Vertex key cycle will start from the beginning of the new Vertex API key list (no specific start key determined or needed)."
+ "New Vertex key cycle will start from the beginning of the new Vertex Express API key list (no specific start key determined or needed)."
)
else:
logger.info(
- "New Vertex key cycle not applicable as the new Vertex API key list is empty."
+ "New Vertex key cycle not applicable as the new Vertex Express API key list is empty."
)
# 清理所有保存的状态
@@ -411,11 +409,15 @@ async def reset_key_manager_instance():
if _singleton_instance:
# 1. 保存失败计数
_preserved_failure_counts = _singleton_instance.key_failure_counts.copy()
- _preserved_vertex_failure_counts = _singleton_instance.vertex_key_failure_counts.copy()
+ _preserved_vertex_failure_counts = (
+ _singleton_instance.vertex_key_failure_counts.copy()
+ )
# 2. 保存旧的 API keys 列表
_preserved_old_api_keys_for_reset = _singleton_instance.api_keys.copy()
- _preserved_vertex_old_api_keys_for_reset = _singleton_instance.vertex_api_keys.copy()
+ _preserved_vertex_old_api_keys_for_reset = (
+ _singleton_instance.vertex_api_keys.copy()
+ )
# 3. 保存 key_cycle 的下一个 key 提示
try:
@@ -431,8 +433,7 @@ async def reset_key_manager_instance():
)
_preserved_next_key_in_cycle = None
except Exception as e:
- logger.error(
- f"Error preserving next key hint during reset: {e}")
+ logger.error(f"Error preserving next key hint during reset: {e}")
_preserved_next_key_in_cycle = None
# 4. 保存 vertex_key_cycle 的下一个 key 提示
@@ -449,8 +450,7 @@ async def reset_key_manager_instance():
)
_preserved_vertex_next_key_in_cycle = None
except Exception as e:
- logger.error(
- f"Error preserving next key hint during reset: {e}")
+ logger.error(f"Error preserving next key hint during reset: {e}")
_preserved_vertex_next_key_in_cycle = None
_singleton_instance = None
diff --git a/app/static/js/config_editor.js b/app/static/js/config_editor.js
index 874cf1b..8182510 100644
--- a/app/static/js/config_editor.js
+++ b/app/static/js/config_editor.js
@@ -13,7 +13,7 @@ const SHOW_CLASS = "show"; // For modals
const API_KEY_REGEX = /AIzaSy\S{33}/g;
const PROXY_REGEX =
/(?:https?|socks5):\/\/(?:[^:@\/]+(?::[^@\/]+)?@)?(?:[^:\/\s]+)(?::\d+)?/g;
-const VERTEX_API_KEY_REGEX = /AQ\.[a-zA-Z0-9_]{50}/g; // 新增 Vertex API Key 正则
+const VERTEX_API_KEY_REGEX = /AQ\.[a-zA-Z0-9_]{50}/g; // 新增 Vertex Express API Key 正则
const MASKED_VALUE = "••••••••";
// DOM Elements - Global Scope for frequently accessed elements
@@ -35,7 +35,7 @@ const bulkDeleteProxyInput = document.getElementById("bulkDeleteProxyInput");
const resetConfirmModal = document.getElementById("resetConfirmModal");
const configForm = document.getElementById("configForm"); // Added for frequent use
-// Vertex API Key Modal Elements
+// Vertex Express API Key Modal Elements
const vertexApiKeyModal = document.getElementById("vertexApiKeyModal");
const vertexApiKeyBulkInput = document.getElementById("vertexApiKeyBulkInput");
const bulkDeleteVertexApiKeyModal = document.getElementById(
@@ -394,7 +394,7 @@ document.addEventListener("DOMContentLoaded", function () {
initializeSensitiveFields(); // Initialize sensitive field handling
- // Vertex API Key Modal Elements and Events
+ // Vertex Express API Key Modal Elements and Events
const addVertexApiKeyBtn = document.getElementById("addVertexApiKeyBtn");
const closeVertexApiKeyModalBtn = document.getElementById(
"closeVertexApiKeyModalBtn"
@@ -873,9 +873,15 @@ function populateForm(config) {
}
// Populate CUSTOM_HEADERS
- const customHeadersContainer = document.getElementById("CUSTOM_HEADERS_container");
+ const customHeadersContainer = document.getElementById(
+ "CUSTOM_HEADERS_container"
+ );
let customHeadersAdded = false;
- if (customHeadersContainer && config.CUSTOM_HEADERS && typeof config.CUSTOM_HEADERS === "object") {
+ if (
+ customHeadersContainer &&
+ config.CUSTOM_HEADERS &&
+ typeof config.CUSTOM_HEADERS === "object"
+ ) {
for (const [key, value] of Object.entries(config.CUSTOM_HEADERS)) {
createAndAppendCustomHeaderItem(key, value);
customHeadersAdded = true;
@@ -883,7 +889,7 @@ function populateForm(config) {
}
if (!customHeadersAdded && customHeadersContainer) {
customHeadersContainer.innerHTML =
- '
添加自定义请求头,例如 X-Api-Key: your-key
';
+ '添加自定义请求头,例如 X-Api-Key: your-key
';
}
// 4. Populate other array fields (excluding THINKING_MODELS)
@@ -1211,17 +1217,13 @@ function handleBulkDeleteProxies() {
}
/**
- * Handles the bulk addition of Vertex API keys from the modal input.
+ * Handles the bulk addition of Vertex Express API keys from the modal input.
*/
function handleBulkAddVertexApiKeys() {
const vertexApiKeyContainer = document.getElementById(
"VERTEX_API_KEYS_container"
);
- if (
- !vertexApiKeyBulkInput ||
- !vertexApiKeyContainer ||
- !vertexApiKeyModal
- ) {
+ if (!vertexApiKeyBulkInput || !vertexApiKeyContainer || !vertexApiKeyModal) {
return;
}
@@ -1271,7 +1273,7 @@ function handleBulkAddVertexApiKeys() {
}
/**
- * Handles the bulk deletion of Vertex API keys based on input from the modal.
+ * Handles the bulk deletion of Vertex Express API keys based on input from the modal.
*/
function handleBulkDeleteVertexApiKeys() {
const vertexApiKeyContainer = document.getElementById(
@@ -1287,7 +1289,7 @@ function handleBulkDeleteVertexApiKeys() {
const bulkText = bulkDeleteVertexApiKeyInput.value;
if (!bulkText.trim()) {
- showNotification("请粘贴需要删除的 Vertex API 密钥", "warning");
+ showNotification("请粘贴需要删除的 Vertex Express API 密钥", "warning");
return;
}
@@ -1295,13 +1297,15 @@ function handleBulkDeleteVertexApiKeys() {
if (keysToDelete.size === 0) {
showNotification(
- "未在输入内容中提取到有效的 Vertex API 密钥格式",
+ "未在输入内容中提取到有效的 Vertex Express API 密钥格式",
"warning"
);
return;
}
- const keyItems = vertexApiKeyContainer.querySelectorAll(`.${ARRAY_ITEM_CLASS}`);
+ const keyItems = vertexApiKeyContainer.querySelectorAll(
+ `.${ARRAY_ITEM_CLASS}`
+ );
let deleteCount = 0;
keyItems.forEach((item) => {
@@ -1322,7 +1326,10 @@ function handleBulkDeleteVertexApiKeys() {
closeModal(bulkDeleteVertexApiKeyModal);
if (deleteCount > 0) {
- showNotification(`成功删除了 ${deleteCount} 个匹配的 Vertex 密钥`, "success");
+ showNotification(
+ `成功删除了 ${deleteCount} 个匹配的 Vertex 密钥`,
+ "success"
+ );
} else {
showNotification("列表中未找到您输入的任何 Vertex 密钥进行删除", "info");
}
@@ -1337,8 +1344,10 @@ function switchTab(tabId) {
console.log(`Switching to tab: ${tabId}`);
// 定义选中态和未选中态的样式
- const activeStyle = "background-color: #3b82f6 !important; color: #ffffff !important; border: 2px solid #2563eb !important; box-shadow: 0 4px 12px -2px rgba(59, 130, 246, 0.4), 0 2px 6px -1px rgba(59, 130, 246, 0.2) !important; transform: translateY(-2px) !important; font-weight: 600 !important;";
- const inactiveStyle = "background-color: #f8fafc !important; color: #64748b !important; border: 2px solid #e2e8f0 !important; box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1) !important; font-weight: 500 !important; transform: none !important;";
+ const activeStyle =
+ "background-color: #3b82f6 !important; color: #ffffff !important; border: 2px solid #2563eb !important; box-shadow: 0 4px 12px -2px rgba(59, 130, 246, 0.4), 0 2px 6px -1px rgba(59, 130, 246, 0.2) !important; transform: translateY(-2px) !important; font-weight: 600 !important;";
+ const inactiveStyle =
+ "background-color: #f8fafc !important; color: #64748b !important; border: 2px solid #e2e8f0 !important; box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1) !important; font-weight: 500 !important; transform: none !important;";
// 更新标签按钮状态
const tabButtons = document.querySelectorAll(".tab-btn");
@@ -1471,8 +1480,7 @@ function addArrayItemWithValue(key, value) {
const isThinkingModel = key === "THINKING_MODELS";
const isAllowedToken = key === "ALLOWED_TOKENS";
const isVertexApiKey = key === "VERTEX_API_KEYS"; // 新增判断
- const isSensitive =
- key === "API_KEYS" || isAllowedToken || isVertexApiKey; // 更新敏感判断
+ const isSensitive = key === "API_KEYS" || isAllowedToken || isVertexApiKey; // 更新敏感判断
const modelId = isThinkingModel ? generateUUID() : null;
const arrayItem = document.createElement("div");
@@ -1598,7 +1606,7 @@ function createAndAppendBudgetMapItem(mapKey, mapValue, modelId) {
* Adds a new custom header item to the DOM.
*/
function addCustomHeaderItem() {
- createAndAppendCustomHeaderItem("", "");
+ createAndAppendCustomHeaderItem("", "");
}
/**
@@ -1607,45 +1615,52 @@ function addCustomHeaderItem() {
* @param {string} value - The header value.
*/
function createAndAppendCustomHeaderItem(key, value) {
- const container = document.getElementById("CUSTOM_HEADERS_container");
- if (!container) {
- console.error("Cannot add custom header: CUSTOM_HEADERS_container not found!");
- return;
+ const container = document.getElementById("CUSTOM_HEADERS_container");
+ if (!container) {
+ console.error(
+ "Cannot add custom header: CUSTOM_HEADERS_container not found!"
+ );
+ return;
+ }
+
+ const placeholder = container.querySelector(".text-gray-500.italic");
+ if (
+ placeholder &&
+ container.children.length === 1 &&
+ container.firstChild === placeholder
+ ) {
+ container.innerHTML = "";
+ }
+
+ const headerItem = document.createElement("div");
+ headerItem.className = `${CUSTOM_HEADER_ITEM_CLASS} flex items-center mb-2 gap-2`;
+
+ const keyInput = document.createElement("input");
+ keyInput.type = "text";
+ keyInput.value = key;
+ keyInput.placeholder = "Header Name";
+ keyInput.className = `${CUSTOM_HEADER_KEY_INPUT_CLASS} flex-grow px-3 py-2 border border-gray-300 rounded-md focus:outline-none bg-gray-100 text-gray-500`;
+
+ const valueInput = document.createElement("input");
+ valueInput.type = "text";
+ valueInput.value = value;
+ valueInput.placeholder = "Header Value";
+ valueInput.className = `${CUSTOM_HEADER_VALUE_INPUT_CLASS} flex-grow px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:border-primary-500 focus:ring focus:ring-primary-200 focus:ring-opacity-50`;
+
+ const removeBtn = createRemoveButton();
+ removeBtn.addEventListener("click", () => {
+ headerItem.remove();
+ if (container.children.length === 0) {
+ container.innerHTML =
+ '添加自定义请求头,例如 X-Api-Key: your-key
';
}
+ });
- const placeholder = container.querySelector(".text-gray-500.italic");
- if (placeholder && container.children.length === 1 && container.firstChild === placeholder) {
- container.innerHTML = "";
- }
+ headerItem.appendChild(keyInput);
+ headerItem.appendChild(valueInput);
+ headerItem.appendChild(removeBtn);
- const headerItem = document.createElement("div");
- headerItem.className = `${CUSTOM_HEADER_ITEM_CLASS} flex items-center mb-2 gap-2`;
-
- const keyInput = document.createElement("input");
- keyInput.type = "text";
- keyInput.value = key;
- keyInput.placeholder = "Header Name";
- keyInput.className = `${CUSTOM_HEADER_KEY_INPUT_CLASS} flex-grow px-3 py-2 border border-gray-300 rounded-md focus:outline-none bg-gray-100 text-gray-500`;
-
- const valueInput = document.createElement("input");
- valueInput.type = "text";
- valueInput.value = value;
- valueInput.placeholder = "Header Value";
- valueInput.className = `${CUSTOM_HEADER_VALUE_INPUT_CLASS} flex-grow px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:border-primary-500 focus:ring focus:ring-primary-200 focus:ring-opacity-50`;
-
- const removeBtn = createRemoveButton();
- removeBtn.addEventListener("click", () => {
- headerItem.remove();
- if (container.children.length === 0) {
- container.innerHTML = '添加自定义请求头,例如 X-Api-Key: your-key
';
- }
- });
-
- headerItem.appendChild(keyInput);
- headerItem.appendChild(valueInput);
- headerItem.appendChild(removeBtn);
-
- container.appendChild(headerItem);
+ container.appendChild(headerItem);
}
/**
@@ -1724,15 +1739,22 @@ function collectFormData() {
});
}
- const customHeadersContainer = document.getElementById("CUSTOM_HEADERS_container");
+ const customHeadersContainer = document.getElementById(
+ "CUSTOM_HEADERS_container"
+ );
if (customHeadersContainer) {
formData["CUSTOM_HEADERS"] = {};
- const customHeaderItems = customHeadersContainer.querySelectorAll(`.${CUSTOM_HEADER_ITEM_CLASS}`);
+ const customHeaderItems = customHeadersContainer.querySelectorAll(
+ `.${CUSTOM_HEADER_ITEM_CLASS}`
+ );
customHeaderItems.forEach((item) => {
const keyInput = item.querySelector(`.${CUSTOM_HEADER_KEY_INPUT_CLASS}`);
- const valueInput = item.querySelector(`.${CUSTOM_HEADER_VALUE_INPUT_CLASS}`);
+ const valueInput = item.querySelector(
+ `.${CUSTOM_HEADER_VALUE_INPUT_CLASS}`
+ );
if (keyInput && valueInput && keyInput.value.trim() !== "") {
- formData["CUSTOM_HEADERS"][keyInput.value.trim()] = valueInput.value.trim();
+ formData["CUSTOM_HEADERS"][keyInput.value.trim()] =
+ valueInput.value.trim();
}
});
}
diff --git a/app/templates/config_editor.html b/app/templates/config_editor.html
index 5e83547..e2854e3 100644
--- a/app/templates/config_editor.html
+++ b/app/templates/config_editor.html
@@ -96,12 +96,7 @@ endblock %} {% block head_extra_styles %}
/* Theming for select fields - 改进下拉框样式 */
.form-select-themed {
- background-color: rgba(
- 255,
- 255,
- 255,
- 0.95
- ) !important; /* 白色背景 */
+ background-color: rgba(255, 255, 255, 0.95) !important; /* 白色背景 */
border: 1px solid rgba(0, 0, 0, 0.12) !important; /* 灰色边框 */
color: #374151 !important; /* gray-700 文字颜色 */
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M6 8l4 4 4-4'/%3e%3c/svg%3e") !important; /* 灰色箭头 */
@@ -124,7 +119,12 @@ endblock %} {% block head_extra_styles %}
}
.form-select-themed option {
- background-color: rgba(255, 255, 255, 0.98) !important; /* white background */
+ background-color: rgba(
+ 255,
+ 255,
+ 255,
+ 0.98
+ ) !important; /* white background */
color: #374151 !important; /* gray-700 */
padding: 8px !important;
}
@@ -141,22 +141,42 @@ endblock %} {% block head_extra_styles %}
}
#LOG_LEVEL option[value="INFO"] {
- background-color: rgba(249, 250, 251, 0.98) !important; /* gray-50 浅灰背景 */
+ background-color: rgba(
+ 249,
+ 250,
+ 251,
+ 0.98
+ ) !important; /* gray-50 浅灰背景 */
color: #374151 !important; /* gray-700 深灰色文字 */
}
#LOG_LEVEL option[value="WARNING"] {
- background-color: rgba(243, 244, 246, 0.98) !important; /* gray-100 稍深灰背景 */
+ background-color: rgba(
+ 243,
+ 244,
+ 246,
+ 0.98
+ ) !important; /* gray-100 稍深灰背景 */
color: #374151 !important; /* gray-700 深灰色文字 */
}
#LOG_LEVEL option[value="ERROR"] {
- background-color: rgba(229, 231, 235, 0.98) !important; /* gray-200 中灰背景 */
+ background-color: rgba(
+ 229,
+ 231,
+ 235,
+ 0.98
+ ) !important; /* gray-200 中灰背景 */
color: #374151 !important; /* gray-700 深灰色文字 */
}
#LOG_LEVEL option[value="CRITICAL"] {
- background-color: rgba(209, 213, 219, 0.98) !important; /* gray-300 深灰背景 */
+ background-color: rgba(
+ 209,
+ 213,
+ 219,
+ 0.98
+ ) !important; /* gray-300 深灰背景 */
color: #374151 !important; /* gray-700 深灰色文字 */
}
@@ -228,7 +248,12 @@ endblock %} {% block head_extra_styles %}
}
.generate-btn:hover {
- background-color: rgba(59, 130, 246, 0.2) !important; /* blue-500 more opaque */
+ background-color: rgba(
+ 59,
+ 130,
+ 246,
+ 0.2
+ ) !important; /* blue-500 more opaque */
color: #1d4ed8 !important; /* blue-700 */
box-shadow: 0 0 8px rgba(59, 130, 246, 0.3) !important;
}
@@ -302,36 +327,47 @@ endblock %} {% block head_extra_styles %}
}
/* Override all violet/purple buttons to light blue */
- .bg-violet-600, button.bg-violet-600 {
+ .bg-violet-600,
+ button.bg-violet-600 {
background-color: #3b82f6 !important; /* blue-500 - light blue */
}
- .bg-violet-600:hover, button.bg-violet-600:hover,
+ .bg-violet-600:hover,
+ button.bg-violet-600:hover,
.hover\\:bg-violet-700:hover {
background-color: #2563eb !important; /* blue-600 - darker light blue */
}
/* Override blue buttons to light blue */
- .bg-blue-600, button.bg-blue-600 {
+ .bg-blue-600,
+ button.bg-blue-600 {
background-color: #3b82f6 !important; /* blue-500 - light blue */
}
- .bg-blue-600:hover, button.bg-blue-600:hover,
+ .bg-blue-600:hover,
+ button.bg-blue-600:hover,
.hover\\:bg-blue-700:hover {
background-color: #2563eb !important; /* blue-600 - darker light blue */
}
/* Override red buttons to bright light red */
- .bg-red-600, button.bg-red-600,
- .bg-red-700, button.bg-red-700,
- .bg-red-800, button.bg-red-800 {
+ .bg-red-600,
+ button.bg-red-600,
+ .bg-red-700,
+ button.bg-red-700,
+ .bg-red-800,
+ button.bg-red-800 {
background-color: #f87171 !important; /* red-400 - bright light red */
}
- .bg-red-600:hover, button.bg-red-600:hover,
- .bg-red-700:hover, button.bg-red-700:hover,
- .bg-red-800:hover, button.bg-red-800:hover,
- .hover\\:bg-red-700:hover, .hover\\:bg-red-800:hover {
+ .bg-red-600:hover,
+ button.bg-red-600:hover,
+ .bg-red-700:hover,
+ button.bg-red-700:hover,
+ .bg-red-800:hover,
+ button.bg-red-800:hover,
+ .hover\\:bg-red-700:hover,
+ .hover\\:bg-red-800:hover {
background-color: #ef4444 !important; /* red-500 - darker bright light red */
}
@@ -349,7 +385,8 @@ endblock %} {% block head_extra_styles %}
button.tab-btn.active {
background-color: #3b82f6 !important; /* blue-500 */
color: #ffffff !important; /* 确保白色文字 */
- box-shadow: 0 4px 12px -2px rgba(59, 130, 246, 0.4), 0 2px 6px -1px rgba(59, 130, 246, 0.2) !important; /* 蓝色阴影 */
+ box-shadow: 0 4px 12px -2px rgba(59, 130, 246, 0.4),
+ 0 2px 6px -1px rgba(59, 130, 246, 0.2) !important; /* 蓝色阴影 */
transform: translateY(-2px) !important; /* 更明显的上移效果 */
border: 2px solid #2563eb !important; /* blue-600 边框 */
font-weight: 600 !important; /* 加粗字体 */
@@ -388,7 +425,8 @@ endblock %} {% block head_extra_styles %}
background-color: #3b82f6 !important;
color: #ffffff !important;
border: 2px solid #2563eb !important;
- box-shadow: 0 4px 12px -2px rgba(59, 130, 246, 0.4), 0 2px 6px -1px rgba(59, 130, 246, 0.2) !important;
+ box-shadow: 0 4px 12px -2px rgba(59, 130, 246, 0.4),
+ 0 2px 6px -1px rgba(59, 130, 246, 0.2) !important;
transform: translateY(-2px) !important;
font-weight: 600 !important;
}
@@ -409,7 +447,8 @@ endblock %} {% block head_extra_styles %}
background-color: rgba(255, 255, 255, 0.98) !important;
color: #374151 !important; /* gray-700 */
border-color: rgba(0, 0, 0, 0.08) !important;
- box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04) !important;
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1),
+ 0 10px 10px -5px rgba(0, 0, 0, 0.04) !important;
}
/* Fix modal titles */
@@ -428,62 +467,78 @@ endblock %} {% block head_extra_styles %}
}
/* Fix modal body text */
- .modal p, .modal label, .modal span {
+ .modal p,
+ .modal label,
+ .modal span {
color: #374151 !important; /* gray-700 */
}
/* Fix modal textarea and input styling */
- .modal textarea, .modal input {
+ .modal textarea,
+ .modal input {
background-color: rgba(255, 255, 255, 0.95) !important;
color: #374151 !important; /* gray-700 */
border: 1px solid rgba(0, 0, 0, 0.12) !important;
}
- .modal textarea:focus, .modal input:focus {
+ .modal textarea:focus,
+ .modal input:focus {
border-color: #3b82f6 !important; /* blue-500 */
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1) !important;
}
/* Fix modal button styling */
- .modal .bg-violet-600, .modal button.bg-violet-600 {
+ .modal .bg-violet-600,
+ .modal button.bg-violet-600 {
background-color: #3b82f6 !important; /* blue-500 - light blue */
color: #ffffff !important;
border: 1px solid #2563eb !important; /* blue-600 */
}
- .modal .bg-violet-600:hover, .modal button.bg-violet-600:hover {
+ .modal .bg-violet-600:hover,
+ .modal button.bg-violet-600:hover {
background-color: #2563eb !important; /* blue-600 - darker light blue */
transform: translateY(-1px) !important;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1) !important;
}
/* Fix modal blue button styling */
- .modal .bg-blue-500, .modal button.bg-blue-500,
- .modal .bg-blue-600, .modal button.bg-blue-600,
- .modal .bg-blue-700, .modal button.bg-blue-700 {
+ .modal .bg-blue-500,
+ .modal button.bg-blue-500,
+ .modal .bg-blue-600,
+ .modal button.bg-blue-600,
+ .modal .bg-blue-700,
+ .modal button.bg-blue-700 {
background-color: #3b82f6 !important; /* blue-500 - light blue */
color: #ffffff !important;
border: 1px solid #2563eb !important; /* blue-600 */
}
- .modal .bg-blue-500:hover, .modal button.bg-blue-500:hover,
- .modal .bg-blue-600:hover, .modal button.bg-blue-600:hover,
- .modal .bg-blue-700:hover, .modal button.bg-blue-700:hover {
+ .modal .bg-blue-500:hover,
+ .modal button.bg-blue-500:hover,
+ .modal .bg-blue-600:hover,
+ .modal button.bg-blue-600:hover,
+ .modal .bg-blue-700:hover,
+ .modal button.bg-blue-700:hover {
background-color: #2563eb !important; /* blue-600 - darker light blue */
transform: translateY(-1px) !important;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1) !important;
}
/* Fix modal cancel/secondary buttons */
- .modal .bg-gray-500, .modal button.bg-gray-500,
- .modal .bg-gray-600, .modal button.bg-gray-600 {
+ .modal .bg-gray-500,
+ .modal button.bg-gray-500,
+ .modal .bg-gray-600,
+ .modal button.bg-gray-600 {
background-color: #e5e7eb !important; /* gray-200 - light gray */
color: #374151 !important; /* gray-700 - dark text for contrast */
border: 1px solid #d1d5db !important; /* gray-300 */
}
- .modal .bg-gray-500:hover, .modal button.bg-gray-500:hover,
- .modal .bg-gray-600:hover, .modal button.bg-gray-600:hover {
+ .modal .bg-gray-500:hover,
+ .modal button.bg-gray-500:hover,
+ .modal .bg-gray-600:hover,
+ .modal button.bg-gray-600:hover {
background-color: #d1d5db !important; /* gray-300 - darker light gray */
color: #374151 !important; /* gray-700 - dark text for contrast */
transform: translateY(-1px) !important;
@@ -491,17 +546,23 @@ endblock %} {% block head_extra_styles %}
}
/* Fix modal red/danger buttons */
- .modal .bg-red-500, .modal button.bg-red-500,
- .modal .bg-red-600, .modal button.bg-red-600,
- .modal .bg-red-700, .modal button.bg-red-700 {
+ .modal .bg-red-500,
+ .modal button.bg-red-500,
+ .modal .bg-red-600,
+ .modal button.bg-red-600,
+ .modal .bg-red-700,
+ .modal button.bg-red-700 {
background-color: #f87171 !important; /* red-400 - bright light red */
color: #ffffff !important;
border: 1px solid #ef4444 !important; /* red-500 */
}
- .modal .bg-red-500:hover, .modal button.bg-red-500:hover,
- .modal .bg-red-600:hover, .modal button.bg-red-600:hover,
- .modal .bg-red-700:hover, .modal button.bg-red-700:hover {
+ .modal .bg-red-500:hover,
+ .modal button.bg-red-500:hover,
+ .modal .bg-red-600:hover,
+ .modal button.bg-red-600:hover,
+ .modal .bg-red-700:hover,
+ .modal button.bg-red-700:hover {
background-color: #ef4444 !important; /* red-500 - darker bright light red */
transform: translateY(-1px) !important;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1) !important;
@@ -542,27 +603,54 @@ endblock %} {% block head_extra_styles %}
}
/* Comprehensive button text color fixes */
- .bg-blue-500, .bg-blue-600, .bg-blue-700,
- .bg-red-500, .bg-red-600, .bg-red-700, .bg-red-800,
- .bg-green-500, .bg-green-600, .bg-green-700,
- .bg-sky-500, .bg-sky-600, .bg-sky-700,
- .bg-purple-500, .bg-purple-600, .bg-purple-700,
- .bg-violet-500, .bg-violet-600, .bg-violet-700 {
+ .bg-blue-500,
+ .bg-blue-600,
+ .bg-blue-700,
+ .bg-red-500,
+ .bg-red-600,
+ .bg-red-700,
+ .bg-red-800,
+ .bg-green-500,
+ .bg-green-600,
+ .bg-green-700,
+ .bg-sky-500,
+ .bg-sky-600,
+ .bg-sky-700,
+ .bg-purple-500,
+ .bg-purple-600,
+ .bg-purple-700,
+ .bg-violet-500,
+ .bg-violet-600,
+ .bg-violet-700 {
color: #ffffff !important;
}
/* Ensure button children inherit white text */
- .bg-blue-500 *, .bg-blue-600 *, .bg-blue-700 *,
- .bg-red-500 *, .bg-red-600 *, .bg-red-700 *, .bg-red-800 *,
- .bg-green-500 *, .bg-green-600 *, .bg-green-700 *,
- .bg-sky-500 *, .bg-sky-600 *, .bg-sky-700 *,
- .bg-purple-500 *, .bg-purple-600 *, .bg-purple-700 *,
- .bg-violet-500 *, .bg-violet-600 *, .bg-violet-700 * {
+ .bg-blue-500 *,
+ .bg-blue-600 *,
+ .bg-blue-700 *,
+ .bg-red-500 *,
+ .bg-red-600 *,
+ .bg-red-700 *,
+ .bg-red-800 *,
+ .bg-green-500 *,
+ .bg-green-600 *,
+ .bg-green-700 *,
+ .bg-sky-500 *,
+ .bg-sky-600 *,
+ .bg-sky-700 *,
+ .bg-purple-500 *,
+ .bg-purple-600 *,
+ .bg-purple-700 *,
+ .bg-violet-500 *,
+ .bg-violet-600 *,
+ .bg-violet-700 * {
color: inherit !important;
}
/* Fix page title gradient - comprehensive override */
- h1.text-transparent, .text-transparent.bg-clip-text,
+ h1.text-transparent,
+ .text-transparent.bg-clip-text,
.bg-gradient-to-r.from-violet-400.to-pink-400 {
background: none !important;
color: #1f2937 !important; /* gray-800 - consistent with other pages */
@@ -579,15 +667,24 @@ endblock %} {% block head_extra_styles %}
}
/* Ensure all violet/purple colors are converted to blue theme */
- .text-violet-300, .text-violet-400, .text-violet-100 {
+ .text-violet-300,
+ .text-violet-400,
+ .text-violet-100 {
color: #3b82f6 !important; /* blue-500 */
}
- .border-violet-300, .border-violet-400 {
- border-color: rgba(59, 130, 246, 0.3) !important; /* blue-500 with opacity */
+ .border-violet-300,
+ .border-violet-400 {
+ border-color: rgba(
+ 59,
+ 130,
+ 246,
+ 0.3
+ ) !important; /* blue-500 with opacity */
}
- .hover\\:text-violet-400:hover, .hover\\:text-violet-100:hover {
+ .hover\\:text-violet-400:hover,
+ .hover\\:text-violet-100:hover {
color: #2563eb !important; /* blue-600 */
}
@@ -613,7 +710,9 @@ endblock %} {% block head_extra_styles %}
}
/* Even more specific selector targeting the exact auth token wrapper */
- .mb-6 .flex.items-center div.flex.items-center.flex-grow.border.rounded-md:focus-within {
+ .mb-6
+ .flex.items-center
+ div.flex.items-center.flex-grow.border.rounded-md:focus-within {
border-color: #3b82f6 !important; /* blue-500 */
}
@@ -625,7 +724,12 @@ endblock %} {% block head_extra_styles %}
.focus\\:ring-primary-200:focus,
.focus\\:ring-primary-300:focus {
- --tw-ring-color: rgba(59, 130, 246, 0.2) !important; /* blue-500 with opacity */
+ --tw-ring-color: rgba(
+ 59,
+ 130,
+ 246,
+ 0.2
+ ) !important; /* blue-500 with opacity */
}
/* Fix select element styling */
@@ -645,15 +749,18 @@ endblock %} {% block head_extra_styles %}
}
/* Override any remaining primary colors */
- .text-primary-600, .text-primary-500 {
+ .text-primary-600,
+ .text-primary-500 {
color: #3b82f6 !important; /* blue-500 */
}
- .bg-primary-600, .bg-primary-500 {
+ .bg-primary-600,
+ .bg-primary-500 {
background-color: #3b82f6 !important; /* blue-500 */
}
- .bg-primary-700:hover, .hover\\:bg-primary-700:hover {
+ .bg-primary-700:hover,
+ .hover\\:bg-primary-700:hover {
background-color: #2563eb !important; /* blue-600 */
}
@@ -693,9 +800,7 @@ endblock %} {% block head_extra_styles %}
-