feat(api): 添加 OpenAPI 客户端支持

- 新增 ApiError、ApiRequestOptions、ApiResult、CancelablePromise 等核心类
- 添加多种模型类型定义,如 PlanCreateIn、QueueGetOut、ScriptCreateOut 等
- 实现请求发送、错误处理、数据解析等核心功能
- 配置 axios 客户端并集成到请求流程中
- 优化路由配置,添加用户相关路由
- 更新脚本编辑界面文案,使用更通用的描述
This commit is contained in:
2025-08-05 20:04:00 +08:00
parent c116efd6f4
commit d68e423768
59 changed files with 3274 additions and 1217 deletions

View File

@@ -281,7 +281,7 @@
</div>
</template>
<!-- General脚本配置 -->
<!-- 通用脚本配置 -->
<template v-if="formData.type === 'General'">
<!-- 基础配置 -->
<div class="form-section">
@@ -931,12 +931,12 @@ const loadScript = async () => {
}
} else {
const config = scriptData.config as GeneralScriptConfig
formData.name = config.Info.Name || '新建General脚本'
formData.name = config.Info.Name || '新建通用脚本'
Object.assign(generalConfig, config)
// 如果名称为空,设置默认名称
if (!generalConfig.Info.Name) {
generalConfig.Info.Name = '新建General脚本'
formData.name = '新建General脚本'
generalConfig.Info.Name = '新建通用脚本'
formData.name = '新建通用脚本'
}
}
} else {
@@ -1119,7 +1119,7 @@ const selectLogPath = async () => {
}
const getCardTitle = () => {
return formData.type === 'MAA' ? 'MAA脚本配置' : 'General脚本配置'
return formData.type === 'MAA' ? 'MAA脚本配置' : '通用脚本配置'
}
</script>

View File

@@ -59,7 +59,7 @@
<img src="@/assets/AUTO_MAA.png" alt="AUTO MAA" class="type-logo" />
</div>
<div class="type-info">
<div class="type-title">General脚本</div>
<div class="type-title">通用脚本</div>
<div class="type-description">通用自动化脚本支持自定义游戏和脚本配置</div>
</div>
</div>
@@ -77,9 +77,11 @@ import { PlusOutlined, ReloadOutlined } from '@ant-design/icons-vue'
import ScriptTable from '@/components/ScriptTable.vue'
import type { Script, ScriptType, User } from '@/types/script'
import { useScriptApi } from '@/composables/useScriptApi'
import { useUserApi } from '@/composables/useUserApi'
const router = useRouter()
const { addScript, deleteScript, getScripts, loading } = useScriptApi()
const { addUser, updateUser, deleteUser, loading: userLoading } = useUserApi()
const scripts = ref<Script[]>([])
const typeSelectVisible = ref(false)
@@ -95,14 +97,105 @@ const loadScripts = async () => {
const scriptDetails = await getScripts()
// 将 ScriptDetail 转换为 Script 格式(为了兼容现有的表格组件)
scripts.value = scriptDetails.map(detail => ({
id: detail.uid,
type: detail.type,
name: detail.name,
config: detail.config,
users: [], // 暂时为空后续可以从其他API获取用户数据
createTime: detail.createTime || new Date().toLocaleString(),
}))
scripts.value = scriptDetails.map(detail => {
// 从配置中提取用户数据
const users: User[] = []
// 检查配置中是否有用户数据
if (detail.config && typeof detail.config === 'object') {
const config = detail.config as any
// 检查 SubConfigsInfo.UserData.instances
if (
config.SubConfigsInfo?.UserData?.instances &&
Array.isArray(config.SubConfigsInfo.UserData.instances)
) {
config.SubConfigsInfo.UserData.instances.forEach((instance: any, index: number) => {
if (instance && typeof instance === 'object' && instance.uid) {
// 从用户数据中获取实际的用户信息
const userData = config.SubConfigsInfo.UserData[instance.uid]
if (userData) {
// 创建用户对象,使用真实的用户数据
const user: User = {
id: instance.uid, // 使用真实的用户ID
name: userData.Info?.Name || `用户${index + 1}`,
Info: {
Name: userData.Info?.Name || `用户${index + 1}`,
Id: userData.Info?.Id || '',
Password: userData.Info?.Password || '',
Server: userData.Info?.Server || '官服',
MedicineNumb: userData.Info?.MedicineNumb || 0,
RemainedDay: userData.Info?.RemainedDay || 0,
SeriesNumb: userData.Info?.SeriesNumb || '',
Notes: userData.Info?.Notes || '',
Status: userData.Info?.Status !== undefined ? userData.Info.Status : true,
Mode: userData.Info?.Mode || 'MAA',
InfrastMode: userData.Info?.InfrastMode || '默认',
Routine: userData.Info?.Routine !== undefined ? userData.Info.Routine : true,
Annihilation: userData.Info?.Annihilation || '当期',
Stage: userData.Info?.Stage || '1-7',
StageMode: userData.Info?.StageMode || '刷完即停',
Stage_1: userData.Info?.Stage_1 || '',
Stage_2: userData.Info?.Stage_2 || '',
Stage_3: userData.Info?.Stage_3 || '',
Stage_Remain: userData.Info?.Stage_Remain || '',
IfSkland: userData.Info?.IfSkland || false,
SklandToken: userData.Info?.SklandToken || '',
},
Task: {
IfBase: userData.Task?.IfBase !== undefined ? userData.Task.IfBase : true,
IfCombat: userData.Task?.IfCombat !== undefined ? userData.Task.IfCombat : true,
IfMall: userData.Task?.IfMall !== undefined ? userData.Task.IfMall : true,
IfMission:
userData.Task?.IfMission !== undefined ? userData.Task.IfMission : true,
IfRecruiting:
userData.Task?.IfRecruiting !== undefined ? userData.Task.IfRecruiting : true,
IfReclamation: userData.Task?.IfReclamation || false,
IfAutoRoguelike: userData.Task?.IfAutoRoguelike || false,
IfWakeUp: userData.Task?.IfWakeUp || false,
},
Notify: {
Enabled: userData.Notify?.Enabled || false,
ToAddress: userData.Notify?.ToAddress || '',
IfSendMail: userData.Notify?.IfSendMail || false,
IfSendSixStar: userData.Notify?.IfSendSixStar || false,
IfSendStatistic: userData.Notify?.IfSendStatistic || false,
IfServerChan: userData.Notify?.IfServerChan || false,
IfCompanyWebHookBot: userData.Notify?.IfCompanyWebHookBot || false,
ServerChanKey: userData.Notify?.ServerChanKey || '',
ServerChanChannel: userData.Notify?.ServerChanChannel || '',
ServerChanTag: userData.Notify?.ServerChanTag || '',
CompanyWebHookBotUrl: userData.Notify?.CompanyWebHookBotUrl || '',
},
Data: {
CustomInfrastPlanIndex: userData.Data?.CustomInfrastPlanIndex || '',
IfPassCheck: userData.Data?.IfPassCheck || false,
LastAnnihilationDate: userData.Data?.LastAnnihilationDate || '',
LastProxyDate: userData.Data?.LastProxyDate || '',
LastSklandDate: userData.Data?.LastSklandDate || '',
ProxyTimes: userData.Data?.ProxyTimes || 0,
},
QFluentWidgets: {
ThemeColor: userData.QFluentWidgets?.ThemeColor || 'blue',
ThemeMode: userData.QFluentWidgets?.ThemeMode || 'system',
},
}
users.push(user)
}
}
})
}
}
return {
id: detail.uid,
type: detail.type,
name: detail.name,
config: detail.config,
users,
createTime: detail.createTime || new Date().toLocaleString(),
}
})
} catch (error) {
console.error('加载脚本列表失败:', error)
message.error('加载脚本列表失败')
@@ -154,18 +247,38 @@ const handleDeleteScript = async (script: Script) => {
}
const handleAddUser = (script: Script) => {
// TODO: 实现添加用户功能
message.info('添加用户功能待实现')
// 跳转到添加用户页面
router.push(`/scripts/${script.id}/users/add`)
}
const handleEditUser = (user: User) => {
// TODO: 实现编辑用户功能
message.info('编辑用户功能待实现')
// 从用户数据中找到对应的脚本
const script = scripts.value.find(s => s.users.some(u => u.id === user.id))
if (script) {
// 跳转到编辑用户页面
router.push(`/scripts/${script.id}/users/${user.id}/edit`)
} else {
message.error('找不到对应的脚本')
}
}
const handleDeleteUser = (user: User) => {
// TODO: 实现删除用户功能
message.info('删除用户功能待实现')
const handleDeleteUser = async (user: User) => {
// 从用户数据中找到对应的脚本
const script = scripts.value.find(s => s.users.some(u => u.id === user.id))
if (!script) {
message.error('找不到对应的脚本')
return
}
const result = await deleteUser(script.id, user.id)
if (result) {
// 删除成功后,从本地数据中移除用户
const userIndex = script.users.findIndex(u => u.id === user.id)
if (userIndex > -1) {
script.users.splice(userIndex, 1)
}
message.success('用户删除成功')
}
}
const handleRefresh = () => {

View File

@@ -1,90 +0,0 @@
<template>
<div style="padding: 20px;">
<h2>脚本API测试</h2>
<a-space>
<a-button type="primary" @click="testAddMAA" :loading="loading">
测试添加MAA脚本
</a-button>
<a-button type="primary" @click="testAddGeneral" :loading="loading">
测试添加General脚本
</a-button>
<a-button @click="goToScripts">
前往脚本管理页面
</a-button>
</a-space>
<div v-if="result" style="margin-top: 20px;">
<h3>API响应结果</h3>
<pre>{{ JSON.stringify(result, null, 2) }}</pre>
<a-space style="margin-top: 10px;">
<a-button type="primary" @click="goToEdit">
前往编辑页面
</a-button>
</a-space>
</div>
<div v-if="error" style="margin-top: 20px; color: red;">
<h3>错误信息</h3>
<p>{{ error }}</p>
</div>
<div style="margin-top: 30px;">
<h3>测试说明</h3>
<ul>
<li>点击"测试添加MAA脚本""测试添加General脚本"来测试API调用</li>
<li>成功后会显示API返回的数据包含scriptId和配置信息</li>
<li>点击"前往编辑页面"可以跳转到编辑页面查看配置</li>
<li>或者直接前往脚本管理页面测试完整流程</li>
</ul>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { useScriptApi } from '@/composables/useScriptApi'
const router = useRouter()
const { addScript, loading, error } = useScriptApi()
const result = ref<any>(null)
const lastScriptType = ref<'MAA' | 'General'>('MAA')
const testAddMAA = async () => {
result.value = null
lastScriptType.value = 'MAA'
const response = await addScript('MAA')
if (response) {
result.value = response
}
}
const testAddGeneral = async () => {
result.value = null
lastScriptType.value = 'General'
const response = await addScript('General')
if (response) {
result.value = response
}
}
const goToEdit = () => {
if (result.value) {
router.push({
path: `/scripts/${result.value.scriptId}/edit`,
state: {
scriptData: {
id: result.value.scriptId,
type: lastScriptType.value,
config: result.value.data
}
}
})
}
}
const goToScripts = () => {
router.push('/scripts')
}
</script>