diff --git a/frontend/dist-electron/main.js b/frontend/dist-electron/main.js
index 8c7c8ae..4a48150 100644
--- a/frontend/dist-electron/main.js
+++ b/frontend/dist-electron/main.js
@@ -38,8 +38,8 @@ const path = __importStar(require("path"));
let mainWindow = null;
function createWindow() {
mainWindow = new electron_1.BrowserWindow({
- width: 1200,
- height: 800,
+ width: 1600,
+ height: 900,
minWidth: 800,
minHeight: 600,
icon: path.join(__dirname, '../public/AUTO_MAA.ico'), // 设置应用图标
@@ -73,6 +73,35 @@ electron_1.ipcMain.handle('open-dev-tools', () => {
mainWindow.webContents.openDevTools({ mode: 'undocked' });
}
});
+// 处理文件夹选择请求
+electron_1.ipcMain.handle('select-folder', async () => {
+ if (!mainWindow)
+ return null;
+ const result = await electron_1.dialog.showOpenDialog(mainWindow, {
+ properties: ['openDirectory'],
+ title: '选择文件夹'
+ });
+ if (result.canceled) {
+ return null;
+ }
+ return result.filePaths[0];
+});
+// 处理文件选择请求
+electron_1.ipcMain.handle('select-file', async (event, filters = []) => {
+ if (!mainWindow)
+ return null;
+ const result = await electron_1.dialog.showOpenDialog(mainWindow, {
+ properties: ['openFile'],
+ title: '选择文件',
+ filters: filters.length > 0 ? filters : [
+ { name: '所有文件', extensions: ['*'] }
+ ]
+ });
+ if (result.canceled) {
+ return null;
+ }
+ return result.filePaths[0];
+});
electron_1.app.whenReady().then(createWindow);
electron_1.app.on('window-all-closed', () => {
if (process.platform !== 'darwin')
diff --git a/frontend/dist-electron/preload.js b/frontend/dist-electron/preload.js
index dec0df9..59fe621 100644
--- a/frontend/dist-electron/preload.js
+++ b/frontend/dist-electron/preload.js
@@ -6,5 +6,7 @@ window.addEventListener('DOMContentLoaded', () => {
});
// 暴露安全的 API 给渲染进程
electron_1.contextBridge.exposeInMainWorld('electronAPI', {
- openDevTools: () => electron_1.ipcRenderer.invoke('open-dev-tools')
+ openDevTools: () => electron_1.ipcRenderer.invoke('open-dev-tools'),
+ selectFolder: () => electron_1.ipcRenderer.invoke('select-folder'),
+ selectFile: (filters) => electron_1.ipcRenderer.invoke('select-file', filters)
});
diff --git a/frontend/electron/main.ts b/frontend/electron/main.ts
index 47e4375..9d549f8 100644
--- a/frontend/electron/main.ts
+++ b/frontend/electron/main.ts
@@ -1,12 +1,12 @@
-import { app, BrowserWindow, ipcMain } from 'electron'
+import { app, BrowserWindow, ipcMain, dialog } from 'electron'
import * as path from 'path'
let mainWindow: BrowserWindow | null = null
function createWindow() {
mainWindow = new BrowserWindow({
- width: 1200,
- height: 800,
+ width: 1600,
+ height: 900,
minWidth: 800,
minHeight: 600,
icon: path.join(__dirname, '../public/AUTO_MAA.ico'), // 设置应用图标
@@ -44,6 +44,41 @@ ipcMain.handle('open-dev-tools', () => {
}
})
+// 处理文件夹选择请求
+ipcMain.handle('select-folder', async () => {
+ if (!mainWindow) return null
+
+ const result = await dialog.showOpenDialog(mainWindow, {
+ properties: ['openDirectory'],
+ title: '选择文件夹'
+ })
+
+ if (result.canceled) {
+ return null
+ }
+
+ return result.filePaths[0]
+})
+
+// 处理文件选择请求
+ipcMain.handle('select-file', async (event, filters = []) => {
+ if (!mainWindow) return null
+
+ const result = await dialog.showOpenDialog(mainWindow, {
+ properties: ['openFile'],
+ title: '选择文件',
+ filters: filters.length > 0 ? filters : [
+ { name: '所有文件', extensions: ['*'] }
+ ]
+ })
+
+ if (result.canceled) {
+ return null
+ }
+
+ return result.filePaths[0]
+})
+
app.whenReady().then(createWindow)
app.on('window-all-closed', () => {
diff --git a/frontend/electron/preload.ts b/frontend/electron/preload.ts
index d618e0a..38bcaae 100644
--- a/frontend/electron/preload.ts
+++ b/frontend/electron/preload.ts
@@ -6,5 +6,7 @@ window.addEventListener('DOMContentLoaded', () => {
// 暴露安全的 API 给渲染进程
contextBridge.exposeInMainWorld('electronAPI', {
- openDevTools: () => ipcRenderer.invoke('open-dev-tools')
+ openDevTools: () => ipcRenderer.invoke('open-dev-tools'),
+ selectFolder: () => ipcRenderer.invoke('select-folder'),
+ selectFile: (filters?: any[]) => ipcRenderer.invoke('select-file', filters)
})
diff --git a/frontend/public/vite.svg b/frontend/public/vite.svg
deleted file mode 100644
index e7b8dfb..0000000
--- a/frontend/public/vite.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/frontend/public/AUTO_MAA.ico b/frontend/src/assets/AUTO_MAA.ico
similarity index 100%
rename from frontend/public/AUTO_MAA.ico
rename to frontend/src/assets/AUTO_MAA.ico
diff --git a/frontend/src/assets/AUTO_MAA.png b/frontend/src/assets/AUTO_MAA.png
new file mode 100644
index 0000000..669770c
Binary files /dev/null and b/frontend/src/assets/AUTO_MAA.png differ
diff --git a/frontend/src/assets/MAA.png b/frontend/src/assets/MAA.png
new file mode 100644
index 0000000..1af2759
Binary files /dev/null and b/frontend/src/assets/MAA.png differ
diff --git a/frontend/src/components/AppLayout.vue b/frontend/src/components/AppLayout.vue
index b9495f1..1504778 100644
--- a/frontend/src/components/AppLayout.vue
+++ b/frontend/src/components/AppLayout.vue
@@ -12,7 +12,7 @@
-
+
AUTO_MAA
diff --git a/frontend/src/components/ScriptEditor.vue b/frontend/src/components/ScriptEditor.vue
new file mode 100644
index 0000000..f1ba48a
--- /dev/null
+++ b/frontend/src/components/ScriptEditor.vue
@@ -0,0 +1,340 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ MAA
+ General
+
+
+
+
+
+
+
+ 基础配置
+
+
+
+
+
+
+
+
+ 运行配置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 无操作
+ 退出模拟器
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 基础配置
+
+
+
+
+
+
+
+
+ 游戏配置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 模拟器
+ 游戏
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 脚本配置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/components/ScriptTable.vue b/frontend/src/components/ScriptTable.vue
new file mode 100644
index 0000000..53e1e47
--- /dev/null
+++ b/frontend/src/components/ScriptTable.vue
@@ -0,0 +1,567 @@
+
+
+
+
+
+
+
+
+
+
+
{{ record.name }}
+
+ {{ record.type }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 编辑
+
+
+
+
+
+
+
+ 添加用户
+
+
+
+
+
+
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ user.Info.Status ? '启用' : '禁用' }}
+
+
+
+
+
+
+
+ 剿灭:
+ {{ user.Data.LastAnnihilationDate }}
+
+
+ 代理:
+ {{ user.Data.LastProxyDate }}
+
+
+
+
+
+
+ 基建
+ 作战
+ 商店
+ 任务
+ 招募
+
+
+
+
+
+
+
+
+
+
+ 编辑
+
+
+
+
+
+
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/composables/useScriptApi.ts b/frontend/src/composables/useScriptApi.ts
new file mode 100644
index 0000000..998c8fd
--- /dev/null
+++ b/frontend/src/composables/useScriptApi.ts
@@ -0,0 +1,208 @@
+import { ref } from 'vue'
+import type {
+ ScriptType,
+ AddScriptResponse,
+ MAAScriptConfig,
+ GeneralScriptConfig,
+ GetScriptsResponse,
+ ScriptDetail,
+ ScriptIndexItem
+} from '@/types/script'
+
+const API_BASE_URL = 'http://localhost:8000/api'
+
+export function useScriptApi() {
+ const loading = ref(false)
+ const error = ref
(null)
+
+ // 添加脚本
+ const addScript = async (type: ScriptType): Promise => {
+ loading.value = true
+ error.value = null
+
+ try {
+ const response = await fetch(`${API_BASE_URL}/add/scripts`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ type }),
+ })
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`)
+ }
+
+ const data: AddScriptResponse = await response.json()
+ return data
+ } catch (err) {
+ error.value = err instanceof Error ? err.message : '添加脚本失败'
+ return null
+ } finally {
+ loading.value = false
+ }
+ }
+
+ // 获取所有脚本
+ const getScripts = async (): Promise => {
+ loading.value = true
+ error.value = null
+
+ try {
+ const response = await fetch(`${API_BASE_URL}/get/scripts`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({}), // 传空对象获取全部脚本
+ })
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`)
+ }
+
+ const apiResponse: GetScriptsResponse = await response.json()
+
+ // 转换API响应为前端需要的格式
+ const scripts: ScriptDetail[] = apiResponse.index.map((item: ScriptIndexItem) => {
+ const config = apiResponse.data[item.uid]
+ const scriptType: ScriptType = item.type === 'MaaConfig' ? 'MAA' : 'General'
+
+ // 从配置中获取脚本名称
+ let name = ''
+ if (scriptType === 'MAA') {
+ name = (config as MAAScriptConfig).Info.Name || '未命名MAA脚本'
+ } else {
+ name = (config as GeneralScriptConfig).Info.Name || '未命名General脚本'
+ }
+
+ return {
+ uid: item.uid,
+ type: scriptType,
+ name,
+ config,
+ createTime: new Date().toLocaleString() // 暂时使用当前时间,后续可从API获取
+ }
+ })
+
+ return scripts
+ } catch (err) {
+ error.value = err instanceof Error ? err.message : '获取脚本列表失败'
+ return []
+ } finally {
+ loading.value = false
+ }
+ }
+
+ // 获取单个脚本
+ const getScript = async (scriptId: string): Promise => {
+ loading.value = true
+ error.value = null
+
+ try {
+ const response = await fetch(`${API_BASE_URL}/get/scripts`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ scriptId }), // 传scriptId获取单个脚本
+ })
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`)
+ }
+
+ const apiResponse: GetScriptsResponse = await response.json()
+
+ // 检查是否有数据返回
+ if (apiResponse.index.length === 0) {
+ throw new Error('脚本不存在')
+ }
+
+ const item = apiResponse.index[0]
+ const config = apiResponse.data[item.uid]
+ const scriptType: ScriptType = item.type === 'MaaConfig' ? 'MAA' : 'General'
+
+ // 从配置中获取脚本名称
+ let name = ''
+ if (scriptType === 'MAA') {
+ name = (config as MAAScriptConfig).Info.Name || '未命名MAA脚本'
+ } else {
+ name = (config as GeneralScriptConfig).Info.Name || '未命名General脚本'
+ }
+
+ return {
+ uid: item.uid,
+ type: scriptType,
+ name,
+ config,
+ createTime: new Date().toLocaleString() // 暂时使用当前时间,后续可从API获取
+ }
+ } catch (err) {
+ error.value = err instanceof Error ? err.message : '获取脚本详情失败'
+ return null
+ } finally {
+ loading.value = false
+ }
+ }
+
+ // 更新脚本(暂时模拟)
+ const updateScript = async (scriptId: string, config: MAAScriptConfig | GeneralScriptConfig) => {
+ loading.value = true
+ error.value = null
+
+ try {
+ const response = await fetch(`${API_BASE_URL}/update/scripts/${scriptId}`, {
+ method: 'PUT',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(config),
+ })
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`)
+ }
+
+ return await response.json()
+ } catch (err) {
+ error.value = err instanceof Error ? err.message : '更新脚本失败'
+ return null
+ } finally {
+ loading.value = false
+ }
+ }
+
+ // 删除脚本(暂时模拟)
+ const deleteScript = async (scriptId: string) => {
+ loading.value = true
+ error.value = null
+
+ try {
+ const response = await fetch(`${API_BASE_URL}/delete/scripts/${scriptId}`, {
+ method: 'DELETE',
+ })
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`)
+ }
+
+ return await response.json()
+ } catch (err) {
+ error.value = err instanceof Error ? err.message : '删除脚本失败'
+ return null
+ } finally {
+ loading.value = false
+ }
+ }
+
+ return {
+ loading,
+ error,
+ addScript,
+ getScripts,
+ getScript,
+ updateScript,
+ deleteScript,
+ }
+}
\ No newline at end of file
diff --git a/frontend/src/composables/useTheme.ts b/frontend/src/composables/useTheme.ts
index a7ccdc4..7801c8a 100644
--- a/frontend/src/composables/useTheme.ts
+++ b/frontend/src/composables/useTheme.ts
@@ -61,6 +61,91 @@ const updateTheme = () => {
} else {
document.documentElement.classList.remove('dark')
}
+
+ // 更新CSS变量
+ updateCSSVariables()
+}
+
+// 更新CSS变量
+const updateCSSVariables = () => {
+ const root = document.documentElement
+ const primaryColor = themeColors[themeColor.value]
+
+ if (isDark.value) {
+ // 深色模式变量
+ root.style.setProperty('--ant-color-primary', primaryColor)
+ root.style.setProperty('--ant-color-primary-hover', lightenColor(primaryColor, 10))
+ root.style.setProperty('--ant-color-primary-bg', `${primaryColor}1a`)
+ root.style.setProperty('--ant-color-text', 'rgba(255, 255, 255, 0.88)')
+ root.style.setProperty('--ant-color-text-secondary', 'rgba(255, 255, 255, 0.65)')
+ root.style.setProperty('--ant-color-text-tertiary', 'rgba(255, 255, 255, 0.45)')
+ root.style.setProperty('--ant-color-bg-container', '#141414')
+ root.style.setProperty('--ant-color-bg-layout', '#000000')
+ root.style.setProperty('--ant-color-bg-elevated', '#1f1f1f')
+ root.style.setProperty('--ant-color-border', '#424242')
+ root.style.setProperty('--ant-color-border-secondary', '#303030')
+ root.style.setProperty('--ant-color-error', '#ff4d4f')
+ root.style.setProperty('--ant-color-success', '#52c41a')
+ root.style.setProperty('--ant-color-warning', '#faad14')
+ } else {
+ // 浅色模式变量
+ root.style.setProperty('--ant-color-primary', primaryColor)
+ root.style.setProperty('--ant-color-primary-hover', darkenColor(primaryColor, 10))
+ root.style.setProperty('--ant-color-primary-bg', `${primaryColor}1a`)
+ root.style.setProperty('--ant-color-text', 'rgba(0, 0, 0, 0.88)')
+ root.style.setProperty('--ant-color-text-secondary', 'rgba(0, 0, 0, 0.65)')
+ root.style.setProperty('--ant-color-text-tertiary', 'rgba(0, 0, 0, 0.45)')
+ root.style.setProperty('--ant-color-bg-container', '#ffffff')
+ root.style.setProperty('--ant-color-bg-layout', '#f5f5f5')
+ root.style.setProperty('--ant-color-bg-elevated', '#ffffff')
+ root.style.setProperty('--ant-color-border', '#d9d9d9')
+ root.style.setProperty('--ant-color-border-secondary', '#f0f0f0')
+ root.style.setProperty('--ant-color-error', '#ff4d4f')
+ root.style.setProperty('--ant-color-success', '#52c41a')
+ root.style.setProperty('--ant-color-warning', '#faad14')
+ }
+}
+
+// 颜色工具函数
+const hexToRgb = (hex: string) => {
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
+ return result ? {
+ r: parseInt(result[1], 16),
+ g: parseInt(result[2], 16),
+ b: parseInt(result[3], 16)
+ } : null
+}
+
+const rgbToHex = (r: number, g: number, b: number) => {
+ return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)
+}
+
+const lightenColor = (hex: string, percent: number) => {
+ const rgb = hexToRgb(hex)
+ if (!rgb) return hex
+
+ const { r, g, b } = rgb
+ const amount = Math.round(2.55 * percent)
+
+ return rgbToHex(
+ Math.min(255, r + amount),
+ Math.min(255, g + amount),
+ Math.min(255, b + amount)
+ )
+}
+
+const darkenColor = (hex: string, percent: number) => {
+ const rgb = hexToRgb(hex)
+ if (!rgb) return hex
+
+ const { r, g, b } = rgb
+ const amount = Math.round(2.55 * percent)
+
+ return rgbToHex(
+ Math.max(0, r - amount),
+ Math.max(0, g - amount),
+ Math.max(0, b - amount)
+ )
}
// 监听系统主题变化
@@ -71,8 +156,9 @@ mediaQuery.addEventListener('change', () => {
}
})
-// 监听主题模式变化
+// 监听主题模式和颜色变化
watch(themeMode, updateTheme, { immediate: true })
+watch(themeColor, updateTheme)
// Ant Design 主题配置
const antdTheme = computed(() => ({
diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts
index 1b5091d..e04c5a1 100644
--- a/frontend/src/router/index.ts
+++ b/frontend/src/router/index.ts
@@ -18,6 +18,12 @@ const routes: RouteRecordRaw[] = [
component: () => import('../views/Scripts.vue'),
meta: { title: '脚本管理' },
},
+ {
+ path: '/scripts/:id/edit',
+ name: 'ScriptEdit',
+ component: () => import('../views/ScriptEdit.vue'),
+ meta: { title: '编辑脚本' },
+ },
{
path: '/plans',
name: 'Plans',
@@ -48,6 +54,12 @@ const routes: RouteRecordRaw[] = [
component: () => import('../views/Settings.vue'),
meta: { title: '设置' },
},
+ {
+ path: '/test',
+ name: 'Test',
+ component: () => import('../views/TestScript.vue'),
+ meta: { title: '测试' },
+ },
]
const router = createRouter({
diff --git a/frontend/src/style.css b/frontend/src/style.css
index f691315..e3edf68 100644
--- a/frontend/src/style.css
+++ b/frontend/src/style.css
@@ -4,76 +4,91 @@
font-weight: 400;
color-scheme: light dark;
- color: rgba(255, 255, 255, 0.87);
- background-color: #242424;
-
+
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
+
+ /* 默认浅色模式 CSS 变量 */
+ --ant-color-primary: #1677ff;
+ --ant-color-primary-hover: #4096ff;
+ --ant-color-primary-bg: #1677ff1a;
+ --ant-color-text: rgba(0, 0, 0, 0.88);
+ --ant-color-text-secondary: rgba(0, 0, 0, 0.65);
+ --ant-color-text-tertiary: rgba(0, 0, 0, 0.45);
+ --ant-color-bg-container: #ffffff;
+ --ant-color-bg-layout: #f5f5f5;
+ --ant-color-bg-elevated: #ffffff;
+ --ant-color-border: #d9d9d9;
+ --ant-color-border-secondary: #f0f0f0;
+ --ant-color-error: #ff4d4f;
+ --ant-color-success: #52c41a;
+ --ant-color-warning: #faad14;
}
-a {
- font-weight: 500;
- color: #646cff;
- text-decoration: inherit;
+/* 深色模式默认变量 */
+:root.dark {
+ --ant-color-primary: #1677ff;
+ --ant-color-primary-hover: #4096ff;
+ --ant-color-primary-bg: #1677ff1a;
+ --ant-color-text: rgba(255, 255, 255, 0.88);
+ --ant-color-text-secondary: rgba(255, 255, 255, 0.65);
+ --ant-color-text-tertiary: rgba(255, 255, 255, 0.45);
+ --ant-color-bg-container: #141414;
+ --ant-color-bg-layout: #000000;
+ --ant-color-bg-elevated: #1f1f1f;
+ --ant-color-border: #424242;
+ --ant-color-border-secondary: #303030;
+ --ant-color-error: #ff4d4f;
+ --ant-color-success: #52c41a;
+ --ant-color-warning: #faad14;
}
-a:hover {
- color: #535bf2;
+
+* {
+ box-sizing: border-box;
}
body {
margin: 0;
- display: flex;
- place-items: center;
min-width: 320px;
min-height: 100vh;
-}
-
-h1 {
- font-size: 3.2em;
- line-height: 1.1;
-}
-
-button {
- border-radius: 8px;
- border: 1px solid transparent;
- padding: 0.6em 1.2em;
- font-size: 1em;
- font-weight: 500;
- font-family: inherit;
- background-color: #1a1a1a;
- cursor: pointer;
- transition: border-color 0.25s;
-}
-button:hover {
- border-color: #646cff;
-}
-button:focus,
-button:focus-visible {
- outline: 4px auto -webkit-focus-ring-color;
-}
-
-.card {
- padding: 2em;
+ background-color: var(--ant-color-bg-layout);
+ color: var(--ant-color-text);
}
#app {
- max-width: 1280px;
- margin: 0 auto;
- padding: 2rem;
- text-align: center;
+ width: 100%;
+ height: 100vh;
+ overflow: hidden;
}
-@media (prefers-color-scheme: light) {
- :root {
- color: #213547;
- background-color: #ffffff;
- }
- a:hover {
- color: #747bff;
- }
- button {
- background-color: #f9f9f9;
- }
+/* 链接样式 */
+a {
+ color: var(--ant-color-primary);
+ text-decoration: none;
+ transition: color 0.3s ease;
+}
+
+a:hover {
+ color: var(--ant-color-primary-hover);
+}
+
+/* 滚动条样式 */
+::-webkit-scrollbar {
+ width: 6px;
+ height: 6px;
+}
+
+::-webkit-scrollbar-track {
+ background: var(--ant-color-bg-layout);
+}
+
+::-webkit-scrollbar-thumb {
+ background: var(--ant-color-border);
+ border-radius: 3px;
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background: var(--ant-color-border-secondary);
}
diff --git a/frontend/src/types/electron.ts b/frontend/src/types/electron.ts
new file mode 100644
index 0000000..eda4ab0
--- /dev/null
+++ b/frontend/src/types/electron.ts
@@ -0,0 +1,14 @@
+// Electron API 类型定义
+export interface ElectronAPI {
+ openDevTools: () => Promise
+ selectFolder: () => Promise
+ selectFile: (filters?: { name: string; extensions: string[] }[]) => Promise
+}
+
+declare global {
+ interface Window {
+ electronAPI: ElectronAPI
+ }
+}
+
+export {}
\ No newline at end of file
diff --git a/frontend/src/types/script.ts b/frontend/src/types/script.ts
new file mode 100644
index 0000000..d022e6c
--- /dev/null
+++ b/frontend/src/types/script.ts
@@ -0,0 +1,171 @@
+// 脚本类型定义
+export type ScriptType = 'MAA' | 'General'
+
+// MAA脚本配置
+export interface MAAScriptConfig {
+ Info: {
+ Name: string
+ Path: string
+ }
+ Run: {
+ ADBSearchRange: number
+ AnnihilationTimeLimit: number
+ AnnihilationWeeklyLimit: boolean
+ ProxyTimesLimit: number
+ RoutineTimeLimit: number
+ RunTimesLimit: number
+ TaskTransitionMethod: string
+ }
+ SubConfigsInfo: {
+ UserData: {
+ instances: any[]
+ }
+ }
+}
+
+// General脚本配置
+export interface GeneralScriptConfig {
+ Game: {
+ Arguments: string
+ Enabled: boolean
+ IfForceClose: boolean
+ Path: string
+ Style: string
+ WaitTime: number
+ }
+ Info: {
+ Name: string
+ RootPath: string
+ }
+ Run: {
+ ProxyTimesLimit: number
+ RunTimeLimit: number
+ RunTimesLimit: number
+ }
+ Script: {
+ Arguments: string
+ ConfigPath: string
+ ConfigPathMode: string
+ ErrorLog: string
+ IfTrackProcess: boolean
+ LogPath: string
+ LogPathFormat: string
+ LogTimeEnd: number
+ LogTimeStart: number
+ LogTimeFormat: string
+ ScriptPath: string
+ SuccessLog: string
+ UpdateConfigMode: string
+ }
+ SubConfigsInfo: {
+ UserData: {
+ instances: any[]
+ }
+ }
+}
+
+// 脚本基础信息
+export interface Script {
+ id: string
+ type: ScriptType
+ name: string
+ config: MAAScriptConfig | GeneralScriptConfig
+ users: User[]
+}
+
+// 用户配置
+export interface User {
+ id: string
+ name: string
+ Data: {
+ CustomInfrastPlanIndex: string
+ IfPassCheck: boolean
+ LastAnnihilationDate: string
+ LastProxyDate: string
+ LastSklandDate: string
+ ProxyTimes: number
+ }
+ Info: {
+ Annihilation: string
+ Id: string
+ IfSkland: boolean
+ InfrastMode: string
+ MedicineNumb: number
+ Mode: string
+ Name: string
+ Notes: string
+ Password: string
+ RemainedDay: number
+ Routine: boolean
+ SeriesNumb: string
+ Server: string
+ SklandToken: string
+ Stage: string
+ StageMode: string
+ Stage_1: string
+ Stage_2: string
+ Stage_3: string
+ Stage_Remain: string
+ Status: boolean
+ }
+ Notify: {
+ CompanyWebHookBotUrl: string
+ Enabled: boolean
+ IfCompanyWebHookBot: boolean
+ IfSendMail: boolean
+ IfSendSixStar: boolean
+ IfSendStatistic: boolean
+ IfServerChan: boolean
+ ServerChanChannel: string
+ ServerChanKey: string
+ ServerChanTag: string
+ ToAddress: string
+ }
+ Task: {
+ IfAutoRoguelike: boolean
+ IfBase: boolean
+ IfCombat: boolean
+ IfMall: boolean
+ IfMission: boolean
+ IfReclamation: boolean
+ IfRecruiting: boolean
+ IfWakeUp: boolean
+ }
+ QFluentWidgets: {
+ ThemeColor: string
+ ThemeMode: string
+ }
+}
+
+// API响应类型
+export interface AddScriptResponse {
+ code: number
+ status: string
+ message: string
+ scriptId: string
+ data: MAAScriptConfig | GeneralScriptConfig
+}
+
+// 脚本索引项
+export interface ScriptIndexItem {
+ uid: string
+ type: 'MaaConfig' | 'GeneralConfig'
+}
+
+// 获取脚本API响应
+export interface GetScriptsResponse {
+ code: number
+ status: string
+ message: string
+ index: ScriptIndexItem[]
+ data: Record
+}
+
+// 脚本详情(用于前端展示)
+export interface ScriptDetail {
+ uid: string
+ type: ScriptType
+ name: string
+ config: MAAScriptConfig | GeneralScriptConfig
+ createTime?: string
+}
\ No newline at end of file
diff --git a/frontend/src/views/ScriptEdit.vue b/frontend/src/views/ScriptEdit.vue
new file mode 100644
index 0000000..900c3b4
--- /dev/null
+++ b/frontend/src/views/ScriptEdit.vue
@@ -0,0 +1,1549 @@
+
+
+
+
+
+
+
+
+ {{ formData.type }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/views/Scripts.vue b/frontend/src/views/Scripts.vue
index 9607084..5fb3f29 100644
--- a/frontend/src/views/Scripts.vue
+++ b/frontend/src/views/Scripts.vue
@@ -1,12 +1,591 @@
-
-
脚本管理
-
这里是脚本管理内容的占位符
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
MAA脚本
+
明日方舟自动化脚本,支持日常任务、作战等功能
+
+
+
+
+
+
+
+
+
+
General脚本
+
通用自动化脚本,支持自定义游戏和脚本配置
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/views/TestScript.vue b/frontend/src/views/TestScript.vue
new file mode 100644
index 0000000..e341389
--- /dev/null
+++ b/frontend/src/views/TestScript.vue
@@ -0,0 +1,90 @@
+
+
+
脚本API测试
+
+
+ 测试添加MAA脚本
+
+
+ 测试添加General脚本
+
+
+ 前往脚本管理页面
+
+
+
+
+
API响应结果:
+
{{ JSON.stringify(result, null, 2) }}
+
+
+
+ 前往编辑页面
+
+
+
+
+
+
+
+
测试说明:
+
+ 点击"测试添加MAA脚本"或"测试添加General脚本"来测试API调用
+ 成功后会显示API返回的数据,包含scriptId和配置信息
+ 点击"前往编辑页面"可以跳转到编辑页面查看配置
+ 或者直接前往脚本管理页面测试完整流程
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/vite-env.d.ts b/frontend/src/vite-env.d.ts
index 0f54dd5..70b004c 100644
--- a/frontend/src/vite-env.d.ts
+++ b/frontend/src/vite-env.d.ts
@@ -3,7 +3,9 @@
declare global {
interface Window {
electronAPI?: {
- openDevTools: () => void
+ openDevTools: () => Promise
+ selectFolder: () => Promise
+ selectFile: (filters?: Array<{ name: string; extensions: string[] }>) => Promise
}
}
}