Files
AUTO-MAS-test/frontend/src/views/ScriptEdit.vue

1553 lines
48 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="script-edit-header">
<div class="header-nav">
<a-breadcrumb class="breadcrumb">
<a-breadcrumb-item>
<router-link to="/scripts" class="breadcrumb-link"> 脚本管理</router-link>
</a-breadcrumb-item>
<a-breadcrumb-item>
<div class="breadcrumb-current">
<img
v-if="formData.type === 'MAA'"
src="@/assets/MAA.png"
alt="MAA"
class="breadcrumb-logo"
/>
<img v-else src="@/assets/AUTO_MAA.png" alt="AUTO_MAA" class="breadcrumb-logo" />
编辑脚本
</div>
</a-breadcrumb-item>
</a-breadcrumb>
</div>
<a-space size="middle">
<a-button size="large" @click="handleCancel" class="cancel-button">
<template #icon>
<ArrowLeftOutlined />
</template>
返回
</a-button>
<!-- <a-button-->
<!-- type="primary"-->
<!-- size="large"-->
<!-- :loading="loading"-->
<!-- @click="handleSave"-->
<!-- class="save-button"-->
<!-- >-->
<!-- <template #icon>-->
<!-- <SaveOutlined />-->
<!-- </template>-->
<!-- 保存配置-->
<!-- </a-button>-->
</a-space>
</div>
<div class="script-edit-content">
<a-card :title="getCardTitle()" :loading="pageLoading" class="config-card">
<template #extra>
<a-tag :color="formData.type === 'MAA' ? 'blue' : 'green'" class="type-tag">
{{ formData.type }}
</a-tag>
</template>
<a-form ref="formRef" :model="formData" :rules="rules" layout="vertical" class="config-form">
<!-- 基本信息 -->
<div class="form-section">
<div class="section-header">
<h3>基本信息</h3>
</div>
<a-row :gutter="24">
<a-col :span="12">
<a-form-item name="name">
<template #label>
<a-tooltip title="为脚本设置一个易于识别的名称">
<span class="form-label">
脚本名称
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input
v-model:value="formData.name"
placeholder="请输入脚本名称"
size="large"
class="modern-input"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item name="type">
<template #label>
<a-tooltip title="脚本类型创建后无法修改">
<span class="form-label">
脚本类型
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-select v-model:value="formData.type" disabled size="large">
<a-select-option value="MAA">MAA脚本</a-select-option>
<a-select-option value="General">通用脚本</a-select-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
</div>
<!-- MAA脚本配置 -->
<template v-if="formData.type === 'MAA'">
<!-- 路径配置 -->
<div class="form-section">
<div class="section-header">
<h3>路径配置</h3>
</div>
<a-row :gutter="24">
<a-col :span="24">
<a-form-item name="path">
<template #label>
<a-tooltip title="选择MAA.exe所在的文件夹路径">
<span class="form-label">
MAA路径
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input-group compact class="path-input-group">
<a-input
v-model:value="maaConfig.Info.Path"
placeholder="请选择MAA.exe所在的文件夹"
size="large"
class="path-input"
readonly
/>
<a-button size="large" @click="selectMAAPath" class="path-button">
<template #icon>
<FolderOpenOutlined />
</template>
选择文件夹
</a-button>
</a-input-group>
</a-form-item>
</a-col>
</a-row>
</div>
<!-- 运行配置 -->
<div class="form-section">
<div class="section-header">
<h3>运行配置</h3>
</div>
<a-row :gutter="24">
<a-col :span="8">
<a-form-item>
<template #label>
<a-tooltip title="任务完成后的处理方式">
<span class="form-label">
任务转换方式
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-select v-model:value="maaConfig.Run.TaskTransitionMethod" size="large">
<a-select-option value="ExitEmulator">重启模拟器</a-select-option>
<a-select-option value="ExitGame">重启明日方舟</a-select-option>
<a-select-option value="NoAction">直接切换账号</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item>
<template #label>
<a-tooltip title="设置ADB设备搜索的范围可输入范围0-3">
<span class="form-label">
ADB搜索范围
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input-number
v-model:value="maaConfig.Run.ADBSearchRange"
:min="0"
:max="3"
size="large"
class="modern-number-input"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item>
<template #label>
<a-tooltip title="代理指挥作战的次数限制0表示不限制">
<span class="form-label">
代理次数限制
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input-number
v-model:value="maaConfig.Run.ProxyTimesLimit"
:min="0"
:max="999"
size="large"
class="modern-number-input"
style="width: 100%"
/>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :span="8">
<a-form-item>
<template #label>
<a-tooltip title="剿灭作战的最大执行时间,超时后会停止执行">
<span class="form-label">
剿灭时间限制(分钟)
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input-number
v-model:value="maaConfig.Run.AnnihilationTimeLimit"
:min="1"
:max="9999"
size="large"
class="modern-number-input"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item>
<template #label>
<a-tooltip title="每周剿灭达到上限后,本周剩余时间不在执行剿灭任务">
<span class="form-label">
每周剿灭达到上限后本周剩余时间不在执行剿灭任务
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-select v-model:value="maaConfig.Run.AnnihilationWeeklyLimit" size="large">
<a-select-option :value="true"></a-select-option>
<a-select-option :value="false"></a-select-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :span="8">
<a-form-item>
<template #label>
<a-tooltip title="日常任务的最大执行时间,包括基建、任务等">
<span class="form-label">
日常时间限制(分钟)
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input-number
v-model:value="maaConfig.Run.RoutineTimeLimit"
:min="1"
:max="9999"
size="large"
class="modern-number-input"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item>
<template #label>
<a-tooltip title="脚本的最大运行次数,防止无限循环">
<span class="form-label">
运行次数限制
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input-number
v-model:value="maaConfig.Run.RunTimesLimit"
:min="1"
:max="9999"
size="large"
class="modern-number-input"
style="width: 100%"
/>
</a-form-item>
</a-col>
</a-row>
</div>
</template>
<!-- 通用脚本配置 -->
<template v-if="formData.type === 'General'">
<!-- 基础配置 -->
<div class="form-section">
<div class="section-header">
<h3>脚本配置</h3>
</div>
<a-row :gutter="24">
<a-col :span="12">
<a-form-item name="rootPath">
<template #label>
<a-tooltip title="脚本的根目录路径,所有相对路径都基于此目录">
<span class="form-label">
脚本根目录
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input-group compact class="path-input-group">
<a-input
v-model:value="generalConfig.Info.RootPath"
placeholder="请选择脚本根目录"
size="large"
class="path-input"
readonly
/>
<a-button size="large" @click="selectRootPath" class="path-button">
<template #icon>
<FolderOpenOutlined />
</template>
选择文件夹
</a-button>
</a-input-group>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item>
<template #label>
<a-tooltip title="脚本文件的路径">
<span class="form-label">
脚本路径
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input-group compact class="path-input-group">
<a-input
v-model:value="generalConfig.Script.ScriptPath"
placeholder="请选择脚本文件"
size="large"
class="path-input"
readonly
/>
<a-button size="large" @click="selectScriptPath" class="path-button">
<template #icon>
<FileOutlined />
</template>
选择文件
</a-button>
</a-input-group>
</a-form-item>
</a-col>
</a-row>
</div>
<!-- 游戏配置 -->
<div class="form-section">
<a-row :gutter="24">
<a-col :span="12">
<a-form-item>
<template #label>
<a-tooltip title="脚本运行时的命令行参数">
<span class="form-label">
脚本启动参数
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input
v-model:value="generalConfig.Script.Arguments"
placeholder="请输入脚本参数"
size="large"
class="modern-input"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item>
<template #label>
<a-tooltip title="是否追踪脚本子进程的运行状态">
<span class="form-label">
追踪脚本子进程
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<!-- <a-switch-->
<!-- v-model:checked="generalConfig.Script.IfTrackProcess"-->
<!-- size="default"-->
<!-- class="modern-switch"-->
<!-- />-->
<a-select v-model:value="generalConfig.Script.IfTrackProcess" size="large">
<a-select-option :value="true"></a-select-option>
<a-select-option :value="false"></a-select-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :span="12">
<a-form-item>
<template #label>
<a-tooltip title="配置文件的路径">
<span class="form-label">
配置文件路径
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input-group compact class="path-input-group">
<a-input
v-model:value="generalConfig.Script.ConfigPath"
placeholder="请选择配置文件"
size="large"
class="path-input"
readonly
/>
<a-button size="large" @click="selectConfigPath" class="path-button">
<template #icon>
<FileOutlined />
</template>
选择文件
</a-button>
</a-input-group>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item>
<template #label>
<a-tooltip title="配置文件的更新策略">
<span class="form-label">
脚本配置文件更新时机
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-select v-model:value="generalConfig.Script.UpdateConfigMode" size="large">
<a-select-option value="Never">从不更新</a-select-option>
<a-select-option value="Success">成功时更新</a-select-option>
<a-select-option value="Failure">失败时更新</a-select-option>
<a-select-option value="Always">总是更新</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item>
<template #label>
<a-tooltip title="脚本配置文件更新范围">
<span class="form-label">
脚本配置文件更新范围
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-select v-model:value="generalConfig.Script.ConfigPathMode" size="large">
<a-select-option value="All">所有文件 (*)</a-select-option>
<a-select-option value="Folder">文件夹</a-select-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :span="12">
<a-form-item>
<template #label>
<a-tooltip title="日志文件的存储路径">
<span class="form-label">
脚本日志文件路径
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input-group compact class="path-input-group">
<a-input
v-model:value="generalConfig.Script.LogPath"
placeholder="请选择日志目录"
size="large"
class="path-input"
readonly
/>
<a-button size="large" @click="selectLogPath" class="path-button">
<template #icon>
<FolderOpenOutlined />
</template>
选择文件夹
</a-button>
</a-input-group>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item>
<template #label>
<a-tooltip title="日志文件名的格式,支持时间格式化">
<span class="form-label">
脚本日志文件名格式
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input
v-model:value="generalConfig.Script.LogPathFormat"
placeholder="日志格式"
size="large"
class="modern-input"
/>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :span="6">
<a-form-item>
<template #label>
<a-tooltip title="脚本时间戳起始位置">
<span class="form-label">
脚本时间戳起始位置
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input
v-model:value="generalConfig.Script.LogTimeStart"
placeholder="起始位置"
size="large"
class="modern-input"
/>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item>
<template #label>
<a-tooltip title="脚本时间戳结束位置">
<span class="form-label">
脚本时间戳结束位置
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input
v-model:value="generalConfig.Script.LogTimeEnd"
placeholder="结束位置"
size="large"
class="modern-input"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item>
<template #label>
<a-tooltip title="配置文件的匹配模式">
<span class="form-label">
脚本日志时间戳格式
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input
v-model:value="generalConfig.Script.LogTimeFormat"
placeholder="脚本日志时间戳格式"
size="large"
class="modern-input"
/>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :span="12">
<a-form-item>
<template #label>
<a-tooltip title="根据这个来判断执行是否成功">
<span class="form-label">
脚本成功日志 | 进行分割
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input
v-model:value="generalConfig.Script.SuccessLog"
placeholder="请输入脚本成功日志"
size="large"
class="modern-input"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item>
<template #label>
<a-tooltip title="根据这个来判断执行是否失败">
<span class="form-label">
脚本失败日志 | 进行分割
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input
v-model:value="generalConfig.Script.ErrorLog"
placeholder="请输入脚本失败日志"
size="large"
class="modern-input"
/>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="24"></a-row>
<div class="section-header">
<h3>游戏配置</h3>
</div>
<a-row :gutter="24">
<a-col :span="8">
<a-form-item>
<template #label>
<a-tooltip title="是否启用游戏/模拟器相关功能">
<span class="form-label">
启用游戏/模拟器相关功能
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<!-- <a-switch-->
<!-- v-model:checked="generalConfig.Game.Enabled"-->
<!-- size="default"-->
<!-- class="modern-switch"-->
<!-- />-->
<a-select v-model:value="generalConfig.Game.Enabled" size="large">
<a-select-option :value="true"></a-select-option>
<a-select-option :value="false"></a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item>
<template #label>
<a-tooltip title="游戏的运行方式">
<span class="form-label">
游戏平台类型
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-select v-model:value="generalConfig.Game.Style" size="large">
<a-select-option value="Emulator">安卓模拟器</a-select-option>
<a-select-option value="Client">客户端</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item>
<template #label>
<a-tooltip title="游戏可执行文件的路径">
<span class="form-label">
游戏路径
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input-group compact class="path-input-group">
<a-input
v-model:value="generalConfig.Game.Path"
placeholder="请选择脚本的可执行文件"
size="large"
class="path-input"
readonly
/>
<a-button size="large" @click="selectGamePath" class="path-button">
<template #icon>
<FileOutlined />
</template>
选择文件
</a-button>
</a-input-group>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :span="8">
<a-form-item>
<template #label>
<a-tooltip title="启动游戏时的命令行参数">
<span class="form-label">
启动参数
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input
v-model:value="generalConfig.Game.Arguments"
placeholder="请输入启动参数"
size="large"
class="modern-input"
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item>
<template #label>
<a-tooltip title="脚本结束后是否强制关闭游戏进程">
<span class="form-label">
强制关闭
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<!-- <a-switch-->
<!-- v-model:checked="generalConfig.Game.IfForceClose"-->
<!-- size="default"-->
<!-- class="modern-switch"-->
<!-- />-->
<a-select v-model:value="generalConfig.Game.IfForceClose" size="large">
<a-select-option :value="true"></a-select-option>
<a-select-option :value="false"></a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item>
<template #label>
<a-tooltip title="启动游戏后等待的时间,单位为秒">
<span class="form-label">
等待时间()
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input-number
v-model:value="generalConfig.Game.WaitTime"
:min="0"
:max="300"
size="large"
class="modern-number-input"
style="width: 100%"
/>
</a-form-item>
</a-col>
</a-row>
</div>
<!-- 运行配置 -->
<div class="form-section">
<div class="section-header">
<h3>运行配置</h3>
</div>
<a-row :gutter="24">
<a-col :span="8">
<a-form-item>
<template #label>
<a-tooltip title="代理作战的次数限制0表示不限制">
<span class="form-label">
代理次数限制
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input-number
v-model:value="generalConfig.Run.ProxyTimesLimit"
:min="0"
:max="999"
size="large"
class="modern-number-input"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item>
<template #label>
<a-tooltip title="脚本的最大运行时间,单位为分钟">
<span class="form-label">
运行时间限制(分钟)
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input-number
v-model:value="generalConfig.Run.RunTimeLimit"
:min="1"
:max="300"
size="large"
class="modern-number-input"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item>
<template #label>
<a-tooltip title="脚本的最大运行次数,防止无限循环">
<span class="form-label">
运行次数限制
<QuestionCircleOutlined class="help-icon" />
</span>
</a-tooltip>
</template>
<a-input-number
v-model:value="generalConfig.Run.RunTimesLimit"
:min="1"
:max="10"
size="large"
class="modern-number-input"
style="width: 100%"
/>
</a-form-item>
</a-col>
</a-row>
</div>
</template>
</a-form>
</a-card>
</div>
<a-float-button
type="primary"
@click="handleSave"
class="float-button"
:style="{
right: '24px',
}"
>
<template #icon>
<SaveOutlined />
</template>
</a-float-button>
</template>
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import type { FormInstance } from 'ant-design-vue'
import { message } from 'ant-design-vue'
import type { GeneralScriptConfig, MAAScriptConfig, ScriptType } from '../types/script'
import { useScriptApi } from '../composables/useScriptApi'
import {
ArrowLeftOutlined,
FileOutlined,
FolderOpenOutlined,
QuestionCircleOutlined,
SaveOutlined,
} from '@ant-design/icons-vue'
const route = useRoute()
const router = useRouter()
const { getScript, updateScript, loading } = useScriptApi()
const formRef = ref<FormInstance>()
const pageLoading = ref(false)
const scriptId = route.params.id as string
const formData = reactive({
name: '',
type: 'MAA' as ScriptType,
})
// MAA配置
const maaConfig = reactive<MAAScriptConfig>({
Info: {
Name: '',
Path: '.',
},
Run: {
ADBSearchRange: 0,
AnnihilationTimeLimit: 40,
AnnihilationWeeklyLimit: true,
ProxyTimesLimit: 0,
RoutineTimeLimit: 10,
RunTimesLimit: 3,
TaskTransitionMethod: 'ExitEmulator',
},
SubConfigsInfo: {
UserData: {
instances: [],
},
},
})
// General配置
const generalConfig = reactive<GeneralScriptConfig>({
Game: {
Arguments: '',
Enabled: false,
IfForceClose: false,
Path: '.',
Style: 'Emulator',
WaitTime: 0,
},
Info: {
Name: '',
RootPath: '.',
},
Run: {
ProxyTimesLimit: 0,
RunTimeLimit: 10,
RunTimesLimit: 3,
},
Script: {
Arguments: '',
ConfigPath: '.',
ConfigPathMode: '所有文件 (*)',
ErrorLog: '',
IfTrackProcess: false,
LogPath: '.',
LogPathFormat: '%Y-%m-%d',
LogTimeEnd: 1,
LogTimeStart: 1,
LogTimeFormat: '%Y-%m-%d %H:%M:%S',
ScriptPath: '.',
SuccessLog: '',
UpdateConfigMode: 'Never',
},
SubConfigsInfo: {
UserData: {
instances: [],
},
},
})
const rules = {
name: [{ required: true, message: '请输入脚本名称', trigger: 'blur' }],
type: [{ required: true, message: '请选择脚本类型', trigger: 'change' }],
}
onMounted(async () => {
await loadScript()
})
const loadScript = async () => {
pageLoading.value = true
try {
// 检查是否有通过路由状态传递的数据(新建脚本时)
const routeState = history.state as any
if (routeState?.scriptData) {
// 使用API返回的新建脚本数据
const scriptData = routeState.scriptData
formData.type = scriptData.type
if (scriptData.type === 'MAA') {
const config = scriptData.config as MAAScriptConfig
formData.name = config.Info.Name || '新建MAA脚本'
Object.assign(maaConfig, config)
// 如果名称为空,设置默认名称
if (!maaConfig.Info.Name) {
maaConfig.Info.Name = '新建MAA脚本'
formData.name = '新建MAA脚本'
}
} else {
const config = scriptData.config as GeneralScriptConfig
formData.name = config.Info.Name || '新建通用脚本'
Object.assign(generalConfig, config)
// 如果名称为空,设置默认名称
if (!generalConfig.Info.Name) {
generalConfig.Info.Name = '新建通用脚本'
formData.name = '新建通用脚本'
}
}
} else {
// 编辑现有脚本时从API获取数据
const scriptDetail = await getScript(scriptId)
if (!scriptDetail) {
message.error('脚本不存在或加载失败')
router.push('/scripts')
return
}
formData.type = scriptDetail.type
formData.name = scriptDetail.name
if (scriptDetail.type === 'MAA') {
Object.assign(maaConfig, scriptDetail.config as MAAScriptConfig)
} else {
Object.assign(generalConfig, scriptDetail.config as GeneralScriptConfig)
}
}
} catch (error) {
console.error('加载脚本失败:', error)
message.error('加载脚本失败')
router.push('/scripts')
} finally {
pageLoading.value = false
}
}
const handleSave = async () => {
try {
await formRef.value?.validate()
const config = formData.type === 'MAA' ? maaConfig : generalConfig
if (formData.type === 'MAA') {
maaConfig.Info.Name = formData.name
} else {
generalConfig.Info.Name = formData.name
}
const result = await updateScript(scriptId, config)
if (result) {
message.success('脚本更新成功')
router.push('/scripts')
}
} catch (error) {
console.error('保存失败:', error)
}
}
const handleCancel = () => {
router.push('/scripts')
}
// 文件选择方法
const selectMAAPath = async () => {
try {
if (!window.electronAPI) {
message.error('文件选择功能不可用,请在 Electron 环境中运行')
return
}
const path = await window.electronAPI.selectFolder()
if (path) {
maaConfig.Info.Path = path
message.success('MAA路径选择成功')
}
} catch (error) {
console.error('选择MAA路径失败:', error)
message.error('选择文件夹失败')
}
}
const selectRootPath = async () => {
try {
if (!window.electronAPI) {
message.error('文件选择功能不可用,请在 Electron 环境中运行')
return
}
const path = await window.electronAPI.selectFolder()
if (path) {
generalConfig.Info.RootPath = path
message.success('根路径选择成功')
}
} catch (error) {
console.error('选择根路径失败:', error)
message.error('选择文件夹失败')
}
}
const selectGamePath = async () => {
try {
if (!window.electronAPI) {
message.error('文件选择功能不可用,请在 Electron 环境中运行')
return
}
const path = await window.electronAPI.selectFile([
{ name: '可执行文件', extensions: ['exe'] },
{ name: '所有文件', extensions: ['*'] },
])
if (path) {
generalConfig.Game.Path = path
message.success('游戏路径选择成功')
}
} catch (error) {
console.error('选择游戏路径失败:', error)
message.error('选择文件失败')
}
}
const selectScriptPath = async () => {
try {
if (!window.electronAPI) {
message.error('文件选择功能不可用,请在 Electron 环境中运行')
return
}
const path = await window.electronAPI.selectFile([
{ name: '脚本文件', extensions: ['py', 'js', 'bat', 'sh', 'cmd'] },
{ name: 'Python 脚本', extensions: ['py'] },
{ name: 'JavaScript 脚本', extensions: ['js'] },
{ name: '批处理文件', extensions: ['bat', 'cmd'] },
{ name: 'Shell 脚本', extensions: ['sh'] },
{ name: '所有文件', extensions: ['*'] },
])
if (path) {
generalConfig.Script.ScriptPath = path
message.success('脚本路径选择成功')
}
} catch (error) {
console.error('选择脚本路径失败:', error)
message.error('选择文件失败')
}
}
const selectConfigPath = async () => {
try {
if (!window.electronAPI) {
message.error('文件选择功能不可用,请在 Electron 环境中运行')
return
}
const path = await window.electronAPI.selectFile([
{ name: '配置文件', extensions: ['json', 'yaml', 'yml', 'ini', 'conf', 'toml'] },
{ name: 'JSON 文件', extensions: ['json'] },
{ name: 'YAML 文件', extensions: ['yaml', 'yml'] },
{ name: 'INI 文件', extensions: ['ini', 'conf'] },
{ name: 'TOML 文件', extensions: ['toml'] },
{ name: '所有文件', extensions: ['*'] },
])
if (path) {
generalConfig.Script.ConfigPath = path
message.success('配置路径选择成功')
}
} catch (error) {
console.error('选择配置路径失败:', error)
message.error('选择文件失败')
}
}
const selectLogPath = async () => {
try {
if (!window.electronAPI) {
message.error('文件选择功能不可用,请在 Electron 环境中运行')
return
}
const path = await window.electronAPI.selectFolder()
if (path) {
generalConfig.Script.LogPath = path
message.success('日志路径选择成功')
}
} catch (error) {
console.error('选择日志路径失败:', error)
message.error('选择文件夹失败')
}
}
const getCardTitle = () => {
return formData.type === 'MAA' ? 'MAA脚本配置' : '通用脚本配置'
}
</script>
<style scoped>
/* 脚本编辑容器 */
.script-edit-container {
padding: 32px;
min-height: 100vh;
background: var(--ant-color-bg-layout);
display: flex;
flex-direction: column;
}
/* 头部区域 */
.script-edit-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 32px;
padding: 0 8px;
}
.header-nav {
flex: 1;
}
.breadcrumb {
margin: 0;
}
.breadcrumb-link {
align-items: center;
gap: 8px;
color: var(--ant-color-text-secondary);
text-decoration: none;
transition: color 0.3s ease;
}
.breadcrumb-current {
display: flex;
align-items: center;
gap: 8px;
color: var(--ant-color-text);
font-weight: 600;
}
.breadcrumb-logo {
width: 20px;
height: 20px;
object-fit: contain;
transition: all 0.3s ease;
}
/* 内容区域 */
.script-edit-content {
flex: 1;
}
.config-card {
border-radius: 16px;
box-shadow:
0 4px 20px rgba(0, 0, 0, 0.08),
0 1px 3px rgba(0, 0, 0, 0.1);
border: 1px solid var(--ant-color-border-secondary);
overflow: hidden;
}
.config-card :deep(.ant-card-head) {
background: var(--ant-color-bg-container);
border-bottom: 2px solid var(--ant-color-border-secondary);
padding: 24px 32px;
}
.config-card :deep(.ant-card-head-title) {
font-size: 24px;
font-weight: 700;
color: var(--ant-color-text);
}
.config-card :deep(.ant-card-body) {
padding: 32px;
background: var(--ant-color-bg-container);
}
.type-tag {
font-size: 14px;
font-weight: 600;
padding: 8px 16px;
border-radius: 8px;
border: none;
}
/* 表单样式 */
.config-form {
max-width: none;
}
.form-section {
margin-bottom: 12px;
}
.form-section:last-child {
margin-bottom: 0;
}
.section-header {
margin-bottom: 6px;
padding-bottom: 8px;
border-bottom: 2px solid var(--ant-color-border-secondary);
}
.section-header h3 {
margin: 0;
font-size: 20px;
font-weight: 700;
color: var(--ant-color-text);
display: flex;
align-items: center;
gap: 12px;
}
.section-header h3::before {
content: '';
width: 4px;
height: 24px;
background: linear-gradient(135deg, var(--ant-color-primary), var(--ant-color-primary-hover));
border-radius: 2px;
}
/* 表单标签 */
.form-label {
display: flex;
align-items: center;
gap: 8px;
font-weight: 600;
color: var(--ant-color-text);
font-size: 14px;
}
.help-icon {
color: var(--ant-color-text-tertiary);
font-size: 14px;
cursor: help;
transition: color 0.3s ease;
}
.help-icon:hover {
color: var(--ant-color-primary);
}
.modern-input {
border-radius: 8px;
border: 2px solid var(--ant-color-border);
background: var(--ant-color-bg-container);
transition: all 0.3s ease;
}
.modern-input:hover {
border-color: var(--ant-color-primary-hover);
}
.modern-input:focus,
.modern-input.ant-input-focused {
border-color: var(--ant-color-primary);
box-shadow: 0 0 0 4px rgba(24, 144, 255, 0.1);
}
.modern-select {
border-radius: 8px;
}
.modern-select :deep(.ant-select-selector) {
border: 2px solid var(--ant-color-border) !important;
border-radius: 8px !important;
background: var(--ant-color-bg-container) !important;
transition: all 0.3s ease;
}
.modern-select:hover :deep(.ant-select-selector) {
border-color: var(--ant-color-primary-hover) !important;
}
.modern-select.ant-select-focused :deep(.ant-select-selector) {
border-color: var(--ant-color-primary) !important;
box-shadow: 0 0 0 4px rgba(24, 144, 255, 0.1) !important;
}
.modern-number-input {
border-radius: 8px;
}
.modern-number-input :deep(.ant-input-number) {
border: 2px solid var(--ant-color-border);
border-radius: 8px;
background: var(--ant-color-bg-container);
transition: all 0.3s ease;
}
.modern-number-input :deep(.ant-input-number:hover) {
border-color: var(--ant-color-primary-hover);
}
.modern-number-input :deep(.ant-input-number-focused) {
border-color: var(--ant-color-primary);
box-shadow: 0 0 0 4px rgba(24, 144, 255, 0.1);
}
.modern-switch {
background: var(--ant-color-bg-layout);
}
.modern-switch.ant-switch-checked {
background: var(--ant-color-primary);
}
/* 路径输入组 */
.path-input-group {
display: flex;
border-radius: 8px;
overflow: hidden;
border: 2px solid var(--ant-color-border);
transition: all 0.3s ease;
}
.path-input-group:hover {
border-color: var(--ant-color-primary-hover);
}
.path-input-group:focus-within {
border-color: var(--ant-color-primary);
box-shadow: 0 0 0 4px rgba(24, 144, 255, 0.1);
}
.path-input {
flex: 1;
border: none !important;
border-radius: 0 !important;
background: var(--ant-color-bg-container) !important;
}
.path-input:focus {
box-shadow: none !important;
}
.path-button {
border: none;
border-radius: 0;
background: var(--ant-color-primary-bg);
color: var(--ant-color-primary);
font-weight: 600;
padding: 0 20px;
transition: all 0.3s ease;
border-left: 1px solid var(--ant-color-border-secondary);
}
.path-button:hover {
background: var(--ant-color-primary);
color: white;
transform: none;
}
/* 表单项间距 */
.config-form :deep(.ant-form-item) {
margin-bottom: 24px;
}
.config-form :deep(.ant-form-item-label) {
padding-bottom: 8px;
}
.config-form :deep(.ant-form-item-label > label) {
font-weight: 600;
color: var(--ant-color-text);
}
/* 深色模式适配 */
@media (prefers-color-scheme: dark) {
.config-card {
box-shadow:
0 4px 20px rgba(0, 0, 0, 0.3),
0 1px 3px rgba(0, 0, 0, 0.4);
}
.save-button {
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.4);
}
.save-button:hover {
box-shadow: 0 6px 16px rgba(24, 144, 255, 0.5);
}
.path-input-group:focus-within {
box-shadow: 0 0 0 4px rgba(24, 144, 255, 0.2);
}
.modern-input:focus,
.modern-input.ant-input-focused {
box-shadow: 0 0 0 4px rgba(24, 144, 255, 0.2);
}
.modern-select.ant-select-focused :deep(.ant-select-selector) {
box-shadow: 0 0 0 4px rgba(24, 144, 255, 0.2) !important;
}
.modern-number-input :deep(.ant-input-number-focused) {
box-shadow: 0 0 0 4px rgba(24, 144, 255, 0.2);
}
}
/* 响应式设计 */
@media (max-width: 1200px) {
.script-edit-container {
padding: 24px;
}
.config-card :deep(.ant-card-body) {
padding: 24px;
}
.form-section {
margin-bottom: 12px;
}
}
@media (max-width: 768px) {
.script-edit-container {
padding: 16px;
}
.script-edit-header {
flex-direction: column;
gap: 16px;
align-items: stretch;
}
.config-card :deep(.ant-card-head) {
padding: 16px 20px;
}
.config-card :deep(.ant-card-head-title) {
font-size: 20px;
}
.config-card :deep(.ant-card-body) {
padding: 20px;
}
.section-header h3 {
font-size: 18px;
}
.form-section {
margin-bottom: 12px;
}
.path-button {
padding: 0 16px;
font-size: 14px;
}
.cancel-button,
.save-button {
height: 44px;
font-size: 14px;
padding: 0 20px;
}
}
/* 动画效果 */
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.form-section {
animation: fadeInUp 0.6s ease-out;
}
.form-section:nth-child(2) {
animation-delay: 0.1s;
}
.form-section:nth-child(3) {
animation-delay: 0.2s;
}
.form-section:nth-child(4) {
animation-delay: 0.3s;
}
/* Tooltip样式优化 */
:deep(.ant-tooltip-inner) {
background: var(--ant-color-bg-elevated);
color: var(--ant-color-text);
border: 1px solid var(--ant-color-border);
border-radius: 8px;
padding: 12px 16px;
font-size: 13px;
line-height: 1.5;
max-width: 300px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
:deep(.ant-tooltip-arrow::before) {
background: var(--ant-color-bg-elevated);
border: 1px solid var(--ant-color-border);
}
.float-button {
width: 60px;
height: 60px;
}
</style>