diff --git a/android-webview-app/APP_CHANGELOG.md b/android-webview-app/APP_CHANGELOG.md
index 02d59ff..a91583f 100644
--- a/android-webview-app/APP_CHANGELOG.md
+++ b/android-webview-app/APP_CHANGELOG.md
@@ -1,5 +1,10 @@
# App 更新说明
+# 1.0.17
+- 登录/注册页改为 Vue 实现,统一前端技术栈
+- 登录/注册页接入主题变量体系,自动跟随已保存主题(Claude / 浅色 / 深色)
+- 移除登录/注册页独立主题切换控件,主题入口统一由主界面个人空间管理
+
# 1.0.16
- 工作区顶部品牌图标改为内联 SVG 渲染(不再依赖静态路径加载)
- 修复深色/浅色主题下 logo 颜色适配问题,跟随主题文本色显示
diff --git a/android-webview-app/app/build.gradle.kts b/android-webview-app/app/build.gradle.kts
index 009dbbd..d2dc829 100644
--- a/android-webview-app/app/build.gradle.kts
+++ b/android-webview-app/app/build.gradle.kts
@@ -16,8 +16,8 @@ android {
applicationId = "com.cyjai.agent"
minSdk = 24
targetSdk = 35
- versionCode = 18
- versionName = "1.0.16"
+ versionCode = 19
+ versionName = "1.0.17"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
diff --git a/static/login.html b/static/login.html
index 9ef434b..5c42d21 100644
--- a/static/login.html
+++ b/static/login.html
@@ -1,207 +1,26 @@
-
+
-
-
-
+
+
+
登录 - AI Agent
-
-
-
-
-
AI Agent 登录
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/static/register.html b/static/register.html
index e3029c8..85e684f 100644
--- a/static/register.html
+++ b/static/register.html
@@ -1,156 +1,26 @@
-
+
-
-
-
+
+
+
注册 - AI Agent
-
-
-
-
-
创建账号
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/static/src/auth/LoginApp.vue b/static/src/auth/LoginApp.vue
new file mode 100644
index 0000000..05c68d2
--- /dev/null
+++ b/static/src/auth/LoginApp.vue
@@ -0,0 +1,143 @@
+
+
+
+
+
+
+
diff --git a/static/src/auth/RegisterApp.vue b/static/src/auth/RegisterApp.vue
new file mode 100644
index 0000000..5a95e43
--- /dev/null
+++ b/static/src/auth/RegisterApp.vue
@@ -0,0 +1,125 @@
+
+
+
+
+
+
+
diff --git a/static/src/auth/auth.scss b/static/src/auth/auth.scss
new file mode 100644
index 0000000..81bd3ba
--- /dev/null
+++ b/static/src/auth/auth.scss
@@ -0,0 +1,133 @@
+@use '../styles/base/tokens';
+
+:root,
+body {
+ margin: 0;
+ min-height: 100%;
+}
+
+body {
+ min-height: 100vh;
+ font-family:
+ -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', sans-serif;
+ background: var(--claude-bg);
+ color: var(--claude-text);
+}
+
+.auth-page {
+ min-height: 100vh;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 24px;
+ box-sizing: border-box;
+}
+
+.auth-card {
+ width: min(100%, 390px);
+ padding: 30px;
+ border-radius: 18px;
+ background: var(--theme-surface-soft);
+ border: 1px solid var(--theme-control-border, var(--claude-border));
+ box-shadow: var(--theme-shadow-mid, var(--claude-shadow));
+ backdrop-filter: blur(8px);
+}
+
+.auth-title {
+ margin: 0;
+ font-size: 1.4rem;
+}
+
+.auth-subtitle {
+ margin-top: 8px;
+ margin-bottom: 0;
+ font-size: 0.9rem;
+ color: var(--claude-text-secondary);
+}
+
+.auth-form-group {
+ margin-top: 14px;
+}
+
+.auth-label {
+ display: block;
+ margin-bottom: 6px;
+ font-size: 0.86rem;
+ color: var(--claude-text-secondary);
+}
+
+.auth-input {
+ width: 100%;
+ min-height: 46px;
+ box-sizing: border-box;
+ border-radius: 12px;
+ border: 1px solid var(--theme-control-border, var(--claude-border));
+ background: var(--theme-surface-strong);
+ color: var(--claude-text);
+ padding: 11px 12px;
+ font-size: 0.95rem;
+ transition:
+ border-color 0.2s ease,
+ box-shadow 0.2s ease;
+}
+
+.auth-input:focus {
+ outline: none;
+ border-color: var(--claude-accent-strong);
+ box-shadow: 0 0 0 3px var(--claude-highlight);
+}
+
+.auth-button {
+ width: 100%;
+ margin-top: 18px;
+ border: none;
+ border-radius: 999px;
+ min-height: 44px;
+ font-size: 0.95rem;
+ cursor: pointer;
+ background: linear-gradient(135deg, var(--claude-accent), var(--claude-accent-strong));
+ color: #fff;
+ transition:
+ transform 0.15s ease,
+ filter 0.15s ease;
+}
+
+.auth-button:hover:not(:disabled) {
+ transform: translateY(-1px);
+ filter: brightness(1.02);
+}
+
+.auth-button:disabled,
+.auth-secondary-button:disabled {
+ opacity: 0.65;
+ cursor: not-allowed;
+}
+
+.auth-secondary-button {
+ width: 100%;
+ margin-top: 10px;
+ border-radius: 999px;
+ min-height: 42px;
+ border: 1px solid var(--claude-accent-strong);
+ background: var(--theme-surface-strong);
+ color: var(--claude-accent-strong);
+ cursor: pointer;
+}
+
+.auth-error {
+ min-height: 1.2em;
+ margin-top: 12px;
+ color: #e85b57;
+ font-size: 0.86rem;
+}
+
+.auth-link {
+ margin-top: 16px;
+ font-size: 0.86rem;
+ color: var(--claude-text-secondary);
+}
+
+.auth-link a {
+ color: var(--claude-accent-strong);
+ text-decoration: none;
+}
diff --git a/static/src/auth/loginMain.ts b/static/src/auth/loginMain.ts
new file mode 100644
index 0000000..0619556
--- /dev/null
+++ b/static/src/auth/loginMain.ts
@@ -0,0 +1,5 @@
+import { createApp } from 'vue';
+import LoginApp from './LoginApp.vue';
+import './auth.scss';
+
+createApp(LoginApp).mount('#auth-app');
diff --git a/static/src/auth/registerMain.ts b/static/src/auth/registerMain.ts
new file mode 100644
index 0000000..a3f0535
--- /dev/null
+++ b/static/src/auth/registerMain.ts
@@ -0,0 +1,5 @@
+import { createApp } from 'vue';
+import RegisterApp from './RegisterApp.vue';
+import './auth.scss';
+
+createApp(RegisterApp).mount('#auth-app');
diff --git a/static/src/auth/theme.ts b/static/src/auth/theme.ts
new file mode 100644
index 0000000..1a7d5c5
--- /dev/null
+++ b/static/src/auth/theme.ts
@@ -0,0 +1,25 @@
+export type ThemeKey = 'claude' | 'light' | 'dark';
+
+const THEME_STORAGE_KEY = 'agents_ui_theme';
+
+export const isThemeKey = (value: unknown): value is ThemeKey =>
+ value === 'claude' || value === 'light' || value === 'dark';
+
+export const loadTheme = (): ThemeKey => {
+ if (typeof window === 'undefined') return 'claude';
+ const saved = window.localStorage.getItem(THEME_STORAGE_KEY);
+ return isThemeKey(saved) ? saved : 'claude';
+};
+
+export const applyTheme = (theme: ThemeKey) => {
+ const root = document.documentElement;
+ root.setAttribute('data-theme', theme);
+ document.body.setAttribute('data-theme', theme);
+};
+
+export const setTheme = (theme: ThemeKey) => {
+ if (typeof window !== 'undefined') {
+ window.localStorage.setItem(THEME_STORAGE_KEY, theme);
+ }
+ applyTheme(theme);
+};
diff --git a/vite.config.ts b/vite.config.ts
index d39eabf..44138b6 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -4,10 +4,18 @@ import vue from '@vitejs/plugin-vue';
const entry = fileURLToPath(new URL('./static/src/main.ts', import.meta.url));
const adminEntry = fileURLToPath(new URL('./static/src/admin/main.ts', import.meta.url));
-const adminPolicyEntry = fileURLToPath(new URL('./static/src/admin/policyMain.ts', import.meta.url));
-const adminCustomToolsEntry = fileURLToPath(new URL('./static/src/admin/customToolsMain.ts', import.meta.url));
-const adminCustomToolsGuideEntry = fileURLToPath(new URL('./static/src/admin/customToolsGuideMain.ts', import.meta.url));
+const adminPolicyEntry = fileURLToPath(
+ new URL('./static/src/admin/policyMain.ts', import.meta.url)
+);
+const adminCustomToolsEntry = fileURLToPath(
+ new URL('./static/src/admin/customToolsMain.ts', import.meta.url)
+);
+const adminCustomToolsGuideEntry = fileURLToPath(
+ new URL('./static/src/admin/customToolsGuideMain.ts', import.meta.url)
+);
const adminApiEntry = fileURLToPath(new URL('./static/src/admin/apiMain.ts', import.meta.url));
+const loginEntry = fileURLToPath(new URL('./static/src/auth/loginMain.ts', import.meta.url));
+const registerEntry = fileURLToPath(new URL('./static/src/auth/registerMain.ts', import.meta.url));
export default defineConfig({
plugins: [vue()],
@@ -21,7 +29,9 @@ export default defineConfig({
adminPolicy: adminPolicyEntry,
adminCustomTools: adminCustomToolsEntry,
adminCustomToolsGuide: adminCustomToolsGuideEntry,
- adminApi: adminApiEntry
+ adminApi: adminApiEntry,
+ login: loginEntry,
+ register: registerEntry
},
output: {
entryFileNames: 'assets/[name].js',