feat: 拆分MAAUserEdit
This commit is contained in:
@@ -362,7 +362,7 @@ const handleToggleUserStatus = (user: User) => {
|
|||||||
emit('toggleUserStatus', user)
|
emit('toggleUserStatus', user)
|
||||||
}
|
}
|
||||||
const truncateText = (text: string, maxLength: number = 10): string => {
|
const truncateText = (text: string, maxLength: number = 10): string => {
|
||||||
if (!text) return ''
|
if (!text || text.length === 0) return '无'
|
||||||
return text.length > maxLength ? text.substring(0, maxLength) + '...' : text
|
return text.length > maxLength ? text.substring(0, maxLength) + '...' : text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
325
frontend/src/views/MAAUserEdit/BasicInfoSection.vue
Normal file
325
frontend/src/views/MAAUserEdit/BasicInfoSection.vue
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
<template>
|
||||||
|
<div class="form-section">
|
||||||
|
<div class="section-header">
|
||||||
|
<h3>基本信息</h3>
|
||||||
|
</div>
|
||||||
|
<a-row :gutter="24">
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item name="userName" required>
|
||||||
|
<template #label>
|
||||||
|
<a-tooltip title="用于区分用户的名称,相同名称的用户将被视为同一用户进行统计">
|
||||||
|
<span class="form-label">
|
||||||
|
用户名
|
||||||
|
<QuestionCircleOutlined class="help-icon" />
|
||||||
|
</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<a-input
|
||||||
|
v-model:value="formData.userName"
|
||||||
|
placeholder="请输入用户名"
|
||||||
|
:disabled="loading"
|
||||||
|
size="large"
|
||||||
|
class="modern-input"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item name="userId">
|
||||||
|
<template #label>
|
||||||
|
<a-tooltip title="用于切换账号,官服输入手机号,B服输入B站ID,无需切换则留空">
|
||||||
|
<span class="form-label">
|
||||||
|
账号ID
|
||||||
|
<QuestionCircleOutlined class="help-icon" />
|
||||||
|
</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<a-input
|
||||||
|
v-model:value="formData.userId"
|
||||||
|
placeholder="请输入账号ID"
|
||||||
|
:disabled="loading"
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<a-row :gutter="24">
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item name="status">
|
||||||
|
<template #label>
|
||||||
|
<a-tooltip title="是否启用该用户">
|
||||||
|
<span class="form-label">
|
||||||
|
启用状态
|
||||||
|
<QuestionCircleOutlined class="help-icon" />
|
||||||
|
</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<a-select v-model:value="formData.Info.Status" 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="12">
|
||||||
|
<a-form-item :name="['Info', 'Password']">
|
||||||
|
<template #label>
|
||||||
|
<a-tooltip title="用户密码,仅用于存储以防遗忘,此外无任何作用">
|
||||||
|
<span class="form-label">
|
||||||
|
密码
|
||||||
|
<QuestionCircleOutlined class="help-icon" />
|
||||||
|
</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<a-input-password
|
||||||
|
v-model:value="formData.Info.Password"
|
||||||
|
placeholder="密码仅用于储存以防遗忘,此外无任何作用"
|
||||||
|
:disabled="loading"
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<a-row :gutter="24">
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item name="server">
|
||||||
|
<template #label>
|
||||||
|
<a-tooltip title="选择用户所在的游戏服务器">
|
||||||
|
<span class="form-label">
|
||||||
|
服务器
|
||||||
|
<QuestionCircleOutlined class="help-icon" />
|
||||||
|
</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<a-select
|
||||||
|
v-model:value="formData.Info.Server"
|
||||||
|
placeholder="请选择服务器"
|
||||||
|
:disabled="loading"
|
||||||
|
:options="serverOptions"
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item name="remainedDay">
|
||||||
|
<template #label>
|
||||||
|
<a-tooltip title="账号剩余的有效天数,「-1」表示无限">
|
||||||
|
<span class="form-label">
|
||||||
|
剩余天数
|
||||||
|
<QuestionCircleOutlined class="help-icon" />
|
||||||
|
</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<a-input-number
|
||||||
|
v-model:value="formData.Info.RemainedDay"
|
||||||
|
:min="-1"
|
||||||
|
:max="9999"
|
||||||
|
placeholder="0"
|
||||||
|
:disabled="loading"
|
||||||
|
size="large"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<a-row :gutter="24">
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item name="mode">
|
||||||
|
<template #label>
|
||||||
|
<a-tooltip title="简洁模式下配置沿用脚本全局配置,详细模式下沿用用户自定义配置">
|
||||||
|
<span class="form-label">
|
||||||
|
用户配置模式
|
||||||
|
<QuestionCircleOutlined class="help-icon" />
|
||||||
|
</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<a-select
|
||||||
|
v-model:value="formData.Info.Mode"
|
||||||
|
:options="[
|
||||||
|
{ label: '简洁', value: '简洁' },
|
||||||
|
{ label: '详细', value: '详细' },
|
||||||
|
]"
|
||||||
|
:disabled="loading"
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item name="mode">
|
||||||
|
<template #label>
|
||||||
|
<a-tooltip title="选择基建模式,自定义基建模式需要自行选择自定义基建配置文件">
|
||||||
|
<span class="form-label">
|
||||||
|
基建模式
|
||||||
|
<QuestionCircleOutlined class="help-icon" />
|
||||||
|
</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<a-select
|
||||||
|
v-model:value="formData.Info.InfrastMode"
|
||||||
|
:options="[
|
||||||
|
{ label: '常规模式', value: 'Normal' },
|
||||||
|
{ label: '一键轮休', value: 'Rotation' },
|
||||||
|
{ label: '自定义基建', value: 'Custom' },
|
||||||
|
]"
|
||||||
|
:disabled="loading"
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<!-- 自定义基建配置文件选择 -->
|
||||||
|
<a-row :gutter="24" v-if="formData.Info.InfrastMode === 'Custom'">
|
||||||
|
<a-col :span="24">
|
||||||
|
<a-form-item name="infrastructureConfigFile">
|
||||||
|
<template #label>
|
||||||
|
<a-tooltip title="选择自定义基建配置JSON文件">
|
||||||
|
<span class="form-label">
|
||||||
|
基建配置文件
|
||||||
|
<QuestionCircleOutlined class="help-icon" />
|
||||||
|
</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<div style="display: flex; gap: 12px; align-items: center">
|
||||||
|
<a-input
|
||||||
|
v-model:value="formData.Info.InfrastPath"
|
||||||
|
placeholder="请选择基建配置JSON文件"
|
||||||
|
readonly
|
||||||
|
size="large"
|
||||||
|
style="flex: 1"
|
||||||
|
/>
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
ghost
|
||||||
|
@click="$emit('selectInfrastructureConfig')"
|
||||||
|
:disabled="loading"
|
||||||
|
size="large"
|
||||||
|
>
|
||||||
|
选择文件
|
||||||
|
</a-button>
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
@click="$emit('importInfrastructureConfig')"
|
||||||
|
:disabled="loading || !infrastructureConfigPath || !isEdit"
|
||||||
|
:loading="infrastructureImporting"
|
||||||
|
size="large"
|
||||||
|
>
|
||||||
|
导入配置
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
<div style="color: #999; font-size: 12px; margin-top: 4px">
|
||||||
|
请选择有效的基建配置JSON文件,点击「导入配置」按钮将其应用到当前用户。如果已经导入,可以忽略此选择框。
|
||||||
|
</div>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<a-form-item name="notes">
|
||||||
|
<template #label>
|
||||||
|
<a-tooltip title="为用户添加备注信息">
|
||||||
|
<span class="form-label">
|
||||||
|
备注
|
||||||
|
<QuestionCircleOutlined class="help-icon" />
|
||||||
|
</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<a-textarea
|
||||||
|
v-model:value="formData.Info.Notes"
|
||||||
|
placeholder="请输入备注信息"
|
||||||
|
:rows="4"
|
||||||
|
:disabled="loading"
|
||||||
|
class="modern-input"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { QuestionCircleOutlined } from '@ant-design/icons-vue'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
formData: any
|
||||||
|
loading: boolean
|
||||||
|
serverOptions: any[]
|
||||||
|
infrastructureConfigPath: string
|
||||||
|
infrastructureImporting: boolean
|
||||||
|
isEdit: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
|
defineEmits<{
|
||||||
|
selectInfrastructureConfig: []
|
||||||
|
importInfrastructureConfig: []
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.form-section {
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
border-bottom: 2px solid var(--ant-color-border-secondary);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
.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);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
119
frontend/src/views/MAAUserEdit/MAAUserEditHeader.vue
Normal file
119
frontend/src/views/MAAUserEdit/MAAUserEditHeader.vue
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
<template>
|
||||||
|
<div class="user-edit-header">
|
||||||
|
<div class="header-nav">
|
||||||
|
<a-breadcrumb class="breadcrumb">
|
||||||
|
<a-breadcrumb-item>
|
||||||
|
<router-link to="/scripts">脚本管理</router-link>
|
||||||
|
</a-breadcrumb-item>
|
||||||
|
<a-breadcrumb-item>
|
||||||
|
<router-link :to="`/scripts/${scriptId}/edit`" class="breadcrumb-link">
|
||||||
|
{{ scriptName }}
|
||||||
|
</router-link>
|
||||||
|
</a-breadcrumb-item>
|
||||||
|
<a-breadcrumb-item>
|
||||||
|
{{ isEdit ? '编辑用户' : '添加用户' }}
|
||||||
|
</a-breadcrumb-item>
|
||||||
|
</a-breadcrumb>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-space size="middle">
|
||||||
|
<a-button
|
||||||
|
v-if="userMode !== '简洁'"
|
||||||
|
type="primary"
|
||||||
|
ghost
|
||||||
|
size="large"
|
||||||
|
@click="$emit('handleMAAConfig')"
|
||||||
|
:loading="maaConfigLoading"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<SettingOutlined />
|
||||||
|
</template>
|
||||||
|
MAA配置
|
||||||
|
</a-button>
|
||||||
|
<a-button size="large" @click="$emit('handleCancel')" class="cancel-button">
|
||||||
|
<template #icon>
|
||||||
|
<ArrowLeftOutlined />
|
||||||
|
</template>
|
||||||
|
返回
|
||||||
|
</a-button>
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
size="large"
|
||||||
|
@click="$emit('handleSubmit')"
|
||||||
|
:loading="loading"
|
||||||
|
class="save-button"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<SaveOutlined />
|
||||||
|
</template>
|
||||||
|
{{ isEdit ? '保存修改' : '创建用户' }}
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ArrowLeftOutlined, SaveOutlined, SettingOutlined } from '@ant-design/icons-vue'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
scriptId: string
|
||||||
|
scriptName: string
|
||||||
|
isEdit: boolean
|
||||||
|
userMode: string
|
||||||
|
maaConfigLoading: boolean
|
||||||
|
loading: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
|
defineEmits<{
|
||||||
|
handleMAAConfig: []
|
||||||
|
handleCancel: []
|
||||||
|
handleSubmit: []
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.user-edit-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-nav {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-button {
|
||||||
|
border: 1px solid var(--ant-color-border);
|
||||||
|
background: var(--ant-color-bg-container);
|
||||||
|
color: var(--ant-color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-button:hover {
|
||||||
|
border-color: var(--ant-color-primary);
|
||||||
|
color: var(--ant-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-button {
|
||||||
|
background: var(--ant-color-primary);
|
||||||
|
border-color: var(--ant-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-button:hover {
|
||||||
|
background: var(--ant-color-primary-hover);
|
||||||
|
border-color: var(--ant-color-primary-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.user-edit-header {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
160
frontend/src/views/MAAUserEdit/NotifyConfigSection.vue
Normal file
160
frontend/src/views/MAAUserEdit/NotifyConfigSection.vue
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
<template>
|
||||||
|
<div class="form-section">
|
||||||
|
<div class="section-header">
|
||||||
|
<h3>通知配置</h3>
|
||||||
|
</div>
|
||||||
|
<a-row :gutter="24" align="middle">
|
||||||
|
<a-col :span="6">
|
||||||
|
<span style="font-weight: 500">启用通知</span>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="18">
|
||||||
|
<a-switch v-model:checked="formData.Notify.Enabled" :disabled="loading" />
|
||||||
|
<span class="switch-description">启用后将发送此用户的任务通知到选中的渠道</span>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
<!-- 发送统计/六星等可选通知 -->
|
||||||
|
<a-row :gutter="24" style="margin-top: 16px">
|
||||||
|
<a-col :span="6">
|
||||||
|
<span style="font-weight: 500">通知内容</span>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="18" style="display: flex; gap: 32px">
|
||||||
|
<a-checkbox
|
||||||
|
v-model:checked="formData.Notify.IfSendStatistic"
|
||||||
|
:disabled="loading || !formData.Notify.Enabled"
|
||||||
|
>统计信息
|
||||||
|
</a-checkbox>
|
||||||
|
<a-checkbox
|
||||||
|
v-model:checked="formData.Notify.IfSendSixStar"
|
||||||
|
:disabled="loading || !formData.Notify.Enabled"
|
||||||
|
>公开招募高资喜报
|
||||||
|
</a-checkbox>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<!-- 邮件通知 -->
|
||||||
|
<a-row :gutter="24" style="margin-top: 16px">
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-checkbox
|
||||||
|
v-model:checked="formData.Notify.IfSendMail"
|
||||||
|
:disabled="loading || !formData.Notify.Enabled"
|
||||||
|
>邮件通知
|
||||||
|
</a-checkbox>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="18">
|
||||||
|
<a-input
|
||||||
|
v-model:value="formData.Notify.ToAddress"
|
||||||
|
placeholder="请输入收件人邮箱地址"
|
||||||
|
:disabled="loading || !formData.Notify.Enabled || !formData.Notify.IfSendMail"
|
||||||
|
size="large"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<!-- Server酱通知 -->
|
||||||
|
<a-row :gutter="24" style="margin-top: 16px">
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-checkbox
|
||||||
|
v-model:checked="formData.Notify.IfServerChan"
|
||||||
|
:disabled="loading || !formData.Notify.Enabled"
|
||||||
|
>Server酱
|
||||||
|
</a-checkbox>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="18" style="display: flex; gap: 8px">
|
||||||
|
<a-input
|
||||||
|
v-model:value="formData.Notify.ServerChanKey"
|
||||||
|
placeholder="请输入SENDKEY"
|
||||||
|
:disabled="loading || !formData.Notify.Enabled || !formData.Notify.IfServerChan"
|
||||||
|
size="large"
|
||||||
|
style="flex: 2"
|
||||||
|
/>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<!-- 企业微信群机器人通知 -->
|
||||||
|
<a-row :gutter="24" style="margin-top: 16px">
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-checkbox
|
||||||
|
v-model:checked="formData.Notify.IfCompanyWebHookBot"
|
||||||
|
:disabled="loading || !formData.Notify.Enabled"
|
||||||
|
>企业微信群机器人
|
||||||
|
</a-checkbox>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="18">
|
||||||
|
<a-input
|
||||||
|
v-model:value="formData.Notify.CompanyWebHookBotUrl"
|
||||||
|
placeholder="请输入机器人Webhook地址"
|
||||||
|
:disabled="
|
||||||
|
loading || !formData.Notify.Enabled || !formData.Notify.IfCompanyWebHookBot
|
||||||
|
"
|
||||||
|
size="large"
|
||||||
|
style="width: 100%"
|
||||||
|
class="modern-input"
|
||||||
|
/>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
defineProps<{
|
||||||
|
formData: any
|
||||||
|
loading: boolean
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.form-section {
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
border-bottom: 2px solid var(--ant-color-border-secondary);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch-description {
|
||||||
|
margin-left: 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--ant-color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.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);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
104
frontend/src/views/MAAUserEdit/SkylandConfigSection.vue
Normal file
104
frontend/src/views/MAAUserEdit/SkylandConfigSection.vue
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
<template>
|
||||||
|
<div class="form-section">
|
||||||
|
<div class="section-header">
|
||||||
|
<h3>森空岛配置</h3>
|
||||||
|
<a
|
||||||
|
href="https://doc.auto-mas.top/docs/advanced-features.html#%E8%8E%B7%E5%8F%96%E9%B9%B0%E8%A7%92%E7%BD%91%E7%BB%9C%E9%80%9A%E8%A1%8C%E8%AF%81%E7%99%BB%E5%BD%95%E5%87%AD%E8%AF%81"
|
||||||
|
target="_blank"
|
||||||
|
class="section-doc-link"
|
||||||
|
title="查看森空岛签到配置文档"
|
||||||
|
>
|
||||||
|
文档
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<a-row :gutter="24" align="middle">
|
||||||
|
<a-col :span="6">
|
||||||
|
<span style="font-weight: 500">森空岛签到</span>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="18">
|
||||||
|
<a-switch v-model:checked="formData.Info.IfSkland" :disabled="loading" />
|
||||||
|
<span class="switch-description">开启后将启用森空岛签到功能</span>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
<a-row :gutter="24" style="margin-top: 16px">
|
||||||
|
<a-col :span="24">
|
||||||
|
<span style="font-weight: 500">森空岛Token</span>
|
||||||
|
<a-input-password
|
||||||
|
v-model:value="formData.Info.SklandToken"
|
||||||
|
:disabled="loading || !formData.Info.IfSkland"
|
||||||
|
placeholder="请输入森空岛Token"
|
||||||
|
size="large"
|
||||||
|
style="margin-top: 8px; width: 100%"
|
||||||
|
allow-clear
|
||||||
|
/>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
defineProps<{
|
||||||
|
formData: any
|
||||||
|
loading: boolean
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.form-section {
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
border-bottom: 2px solid var(--ant-color-border-secondary);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-doc-link {
|
||||||
|
color: var(--ant-color-primary) !important;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
padding: 4px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid var(--ant-color-primary);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-doc-link:hover {
|
||||||
|
color: var(--ant-color-primary-hover) !important;
|
||||||
|
background-color: var(--ant-color-primary-bg);
|
||||||
|
border-color: var(--ant-color-primary-hover);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch-description {
|
||||||
|
margin-left: 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--ant-color-text-secondary);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
482
frontend/src/views/MAAUserEdit/StageConfigSection.vue
Normal file
482
frontend/src/views/MAAUserEdit/StageConfigSection.vue
Normal file
@@ -0,0 +1,482 @@
|
|||||||
|
<template>
|
||||||
|
<div class="form-section">
|
||||||
|
<div class="section-header">
|
||||||
|
<h3>关卡配置</h3>
|
||||||
|
</div>
|
||||||
|
<a-row :gutter="24">
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item name="mode">
|
||||||
|
<template #label>
|
||||||
|
<a-tooltip title="剿灭代理关卡选择">
|
||||||
|
<span class="form-label">
|
||||||
|
剿灭代理
|
||||||
|
<QuestionCircleOutlined class="help-icon" />
|
||||||
|
</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<a-select
|
||||||
|
v-model:value="formData.Info.Annihilation"
|
||||||
|
:options="[
|
||||||
|
{ label: '关闭', value: 'Close' },
|
||||||
|
{ label: '当期剿灭', value: 'Annihilation' },
|
||||||
|
{ label: '切尔诺伯格', value: 'Chernobog@Annihilation' },
|
||||||
|
{ label: '龙门外环', value: 'LungmenOutskirts@Annihilation' },
|
||||||
|
{ label: '龙门市区', value: 'LungmenDowntown@Annihilation' },
|
||||||
|
]"
|
||||||
|
:disabled="loading"
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item name="mode">
|
||||||
|
<template #label>
|
||||||
|
<a-tooltip title="可选择「固定」或「计划表」">
|
||||||
|
<span class="form-label">
|
||||||
|
关卡配置模式
|
||||||
|
<QuestionCircleOutlined class="help-icon" />
|
||||||
|
</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<a-select
|
||||||
|
v-model:value="formData.Info.StageMode"
|
||||||
|
:options="stageModeOptions"
|
||||||
|
:disabled="loading"
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
<a-row :gutter="24">
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item name="medicineNumb">
|
||||||
|
<template #label>
|
||||||
|
<a-tooltip title="吃理智药数量">
|
||||||
|
<span class="form-label">
|
||||||
|
吃理智药数量
|
||||||
|
<QuestionCircleOutlined class="help-icon" />
|
||||||
|
</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<!-- 计划模式:显示只读文本 -->
|
||||||
|
<div v-if="isPlanMode" class="plan-mode-display">
|
||||||
|
<div class="plan-value">{{ displayMedicineNumb }}</div>
|
||||||
|
<a-tooltip>
|
||||||
|
<template #title>
|
||||||
|
<div class="plan-tooltip" v-html="formatTooltip(medicineNumbTooltip)"></div>
|
||||||
|
</template>
|
||||||
|
<div class="plan-source">来自计划表</div>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
<!-- 固定模式:显示输入框 -->
|
||||||
|
<a-input-number
|
||||||
|
v-else
|
||||||
|
:value="displayMedicineNumb"
|
||||||
|
@update:value="$emit('update-medicine-numb', $event)"
|
||||||
|
:min="0"
|
||||||
|
:max="9999"
|
||||||
|
placeholder="0"
|
||||||
|
:disabled="loading"
|
||||||
|
size="large"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item name="mode">
|
||||||
|
<template #label>
|
||||||
|
<a-tooltip
|
||||||
|
title="AUTO:自动识别关卡最大代理倍率,保持最大代理倍率且使用理智药后理智不溢出;数值(1~6):按设定倍率执行代理;不切换:不调整游戏内代理倍率设定"
|
||||||
|
>
|
||||||
|
<span class="form-label">
|
||||||
|
连战次数
|
||||||
|
<QuestionCircleOutlined class="help-icon" />
|
||||||
|
</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<!-- 计划模式:显示只读文本 -->
|
||||||
|
<div v-if="isPlanMode" class="plan-mode-display">
|
||||||
|
<div class="plan-value">
|
||||||
|
{{
|
||||||
|
displaySeriesNumb === '0'
|
||||||
|
? 'AUTO'
|
||||||
|
: displaySeriesNumb === '-1'
|
||||||
|
? '不切换'
|
||||||
|
: displaySeriesNumb
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
<a-tooltip>
|
||||||
|
<template #title>
|
||||||
|
<div class="plan-tooltip" v-html="formatTooltip(seriesNumbTooltip)"></div>
|
||||||
|
</template>
|
||||||
|
<div class="plan-source">来自计划表</div>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
<!-- 固定模式:显示选择框 -->
|
||||||
|
<a-select
|
||||||
|
v-else
|
||||||
|
:value="displaySeriesNumb"
|
||||||
|
@update:value="$emit('update-series-numb', $event)"
|
||||||
|
:options="[
|
||||||
|
{ label: 'AUTO', value: '0' },
|
||||||
|
{ label: '1', value: '1' },
|
||||||
|
{ label: '2', value: '2' },
|
||||||
|
{ label: '3', value: '3' },
|
||||||
|
{ label: '4', value: '4' },
|
||||||
|
{ label: '5', value: '5' },
|
||||||
|
{ label: '6', value: '6' },
|
||||||
|
{ label: '不切换', value: '-1' },
|
||||||
|
]"
|
||||||
|
:disabled="loading"
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item name="mode">
|
||||||
|
<template #label>
|
||||||
|
<a-tooltip title="关卡选择">
|
||||||
|
<span class="form-label">
|
||||||
|
关卡选择
|
||||||
|
<QuestionCircleOutlined class="help-icon" />
|
||||||
|
</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<!-- 计划模式:显示只读文本 -->
|
||||||
|
<div v-if="isPlanMode" class="plan-mode-display">
|
||||||
|
<div class="plan-value">
|
||||||
|
{{ displayStage === '-' ? '当前/上次' : displayStage || '不选择' }}
|
||||||
|
</div>
|
||||||
|
<a-tooltip>
|
||||||
|
<template #title>
|
||||||
|
<div class="plan-tooltip" v-html="formatTooltip(stageTooltip)"></div>
|
||||||
|
</template>
|
||||||
|
<div class="plan-source">来自计划表</div>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
<!-- 固定模式:显示选择框 -->
|
||||||
|
<StageSelector
|
||||||
|
v-else
|
||||||
|
:value="displayStage"
|
||||||
|
@update:value="$emit('update-stage', $event)"
|
||||||
|
:options="stageOptions"
|
||||||
|
:loading="loading"
|
||||||
|
placeholder="选择或输入自定义关卡"
|
||||||
|
@add-custom-stage="handleAddCustomStage"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
<a-row :gutter="24">
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item name="mode">
|
||||||
|
<template #label>
|
||||||
|
<a-tooltip
|
||||||
|
title="备选关卡-1,所有备选关卡均选择「当前/上次」时视为不使用备选关卡"
|
||||||
|
>
|
||||||
|
<span class="form-label">
|
||||||
|
备选关卡-1
|
||||||
|
<QuestionCircleOutlined class="help-icon" />
|
||||||
|
</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<!-- 计划模式:显示只读文本 -->
|
||||||
|
<div v-if="isPlanMode" class="plan-mode-display">
|
||||||
|
<div class="plan-value">
|
||||||
|
{{ displayStage1 === '-' ? '当前/上次' : displayStage1 || '不选择' }}
|
||||||
|
</div>
|
||||||
|
<a-tooltip>
|
||||||
|
<template #title>
|
||||||
|
<div class="plan-tooltip" v-html="formatTooltip(stage1Tooltip)"></div>
|
||||||
|
</template>
|
||||||
|
<div class="plan-source">来自计划表</div>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
<!-- 固定模式:显示选择框 -->
|
||||||
|
<StageSelector
|
||||||
|
v-else
|
||||||
|
:value="displayStage1"
|
||||||
|
@update:value="$emit('update-stage1', $event)"
|
||||||
|
:options="stageOptions"
|
||||||
|
:loading="loading"
|
||||||
|
placeholder="选择或输入自定义关卡"
|
||||||
|
@add-custom-stage="handleAddCustomStage1"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item name="mode">
|
||||||
|
<template #label>
|
||||||
|
<a-tooltip
|
||||||
|
title="备选关卡-2,所有备选关卡均选择「当前/上次」时视为不使用备选关卡"
|
||||||
|
>
|
||||||
|
<span class="form-label">
|
||||||
|
备选关卡-2
|
||||||
|
<QuestionCircleOutlined class="help-icon" />
|
||||||
|
</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<!-- 计划模式:显示只读文本 -->
|
||||||
|
<div v-if="isPlanMode" class="plan-mode-display">
|
||||||
|
<div class="plan-value">
|
||||||
|
{{ displayStage2 === '-' ? '当前/上次' : displayStage2 || '不选择' }}
|
||||||
|
</div>
|
||||||
|
<a-tooltip>
|
||||||
|
<template #title>
|
||||||
|
<div class="plan-tooltip" v-html="formatTooltip(stage2Tooltip)"></div>
|
||||||
|
</template>
|
||||||
|
<div class="plan-source">来自计划表</div>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
<!-- 固定模式:显示选择框 -->
|
||||||
|
<StageSelector
|
||||||
|
v-else
|
||||||
|
:value="displayStage2"
|
||||||
|
@update:value="$emit('update-stage2', $event)"
|
||||||
|
:options="stageOptions"
|
||||||
|
:loading="loading"
|
||||||
|
placeholder="选择或输入自定义关卡"
|
||||||
|
@add-custom-stage="handleAddCustomStage2"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item name="mode">
|
||||||
|
<template #label>
|
||||||
|
<a-tooltip
|
||||||
|
title="备选关卡-3,所有备选关卡均选择「当前/上次」时视为不使用备选关卡"
|
||||||
|
>
|
||||||
|
<span class="form-label">
|
||||||
|
备选关卡-3
|
||||||
|
<QuestionCircleOutlined class="help-icon" />
|
||||||
|
</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<!-- 计划模式:显示只读文本 -->
|
||||||
|
<div v-if="isPlanMode" class="plan-mode-display">
|
||||||
|
<div class="plan-value">
|
||||||
|
{{ displayStage3 === '-' ? '当前/上次' : displayStage3 || '不选择' }}
|
||||||
|
</div>
|
||||||
|
<a-tooltip>
|
||||||
|
<template #title>
|
||||||
|
<div class="plan-tooltip" v-html="formatTooltip(stage3Tooltip)"></div>
|
||||||
|
</template>
|
||||||
|
<div class="plan-source">来自计划表</div>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
<!-- 固定模式:显示选择框 -->
|
||||||
|
<StageSelector
|
||||||
|
v-else
|
||||||
|
:value="displayStage3"
|
||||||
|
@update:value="$emit('update-stage3', $event)"
|
||||||
|
:options="stageOptions"
|
||||||
|
:loading="loading"
|
||||||
|
placeholder="选择或输入自定义关卡"
|
||||||
|
@add-custom-stage="handleAddCustomStage3"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item name="mode">
|
||||||
|
<template #label>
|
||||||
|
<a-tooltip title="剩余理智关卡,选择「不选择」时视为不使用剩余理智关卡">
|
||||||
|
<span class="form-label">
|
||||||
|
剩余理智关卡
|
||||||
|
<QuestionCircleOutlined class="help-icon" />
|
||||||
|
</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<!-- 计划模式:显示只读文本 -->
|
||||||
|
<div v-if="isPlanMode" class="plan-mode-display">
|
||||||
|
<div class="plan-value">
|
||||||
|
{{ displayStageRemain === '-' ? '不选择' : displayStageRemain || '不选择' }}
|
||||||
|
</div>
|
||||||
|
<a-tooltip>
|
||||||
|
<template #title>
|
||||||
|
<div class="plan-tooltip" v-html="formatTooltip(stageRemainTooltip)"></div>
|
||||||
|
</template>
|
||||||
|
<div class="plan-source">来自计划表</div>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
<!-- 固定模式:显示选择框 -->
|
||||||
|
<StageSelector
|
||||||
|
v-else
|
||||||
|
:value="displayStageRemain"
|
||||||
|
@update:value="$emit('update-stage-remain', $event)"
|
||||||
|
:options="stageRemainOptions"
|
||||||
|
:loading="loading"
|
||||||
|
placeholder="选择或输入自定义关卡"
|
||||||
|
@add-custom-stage="handleAddCustomStageRemain"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { QuestionCircleOutlined } from '@ant-design/icons-vue'
|
||||||
|
import StageSelector from './StageSelector.vue'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
formData: any
|
||||||
|
loading: boolean
|
||||||
|
stageModeOptions: any[]
|
||||||
|
stageOptions: any[]
|
||||||
|
stageRemainOptions: any[]
|
||||||
|
isPlanMode: boolean
|
||||||
|
displayMedicineNumb: number
|
||||||
|
displaySeriesNumb: string
|
||||||
|
displayStage: string
|
||||||
|
displayStage1: string
|
||||||
|
displayStage2: string
|
||||||
|
displayStage3: string
|
||||||
|
displayStageRemain: string
|
||||||
|
medicineNumbTooltip: string
|
||||||
|
seriesNumbTooltip: string
|
||||||
|
stageTooltip: string
|
||||||
|
stage1Tooltip: string
|
||||||
|
stage2Tooltip: string
|
||||||
|
stage3Tooltip: string
|
||||||
|
stageRemainTooltip: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
'update-medicine-numb': [value: number]
|
||||||
|
'update-series-numb': [value: string]
|
||||||
|
'update-stage': [value: string]
|
||||||
|
'update-stage1': [value: string]
|
||||||
|
'update-stage2': [value: string]
|
||||||
|
'update-stage3': [value: string]
|
||||||
|
'update-stage-remain': [value: string]
|
||||||
|
'handle-add-custom-stage': [stageName: string]
|
||||||
|
'handle-add-custom-stage1': [stageName: string]
|
||||||
|
'handle-add-custom-stage2': [stageName: string]
|
||||||
|
'handle-add-custom-stage3': [stageName: string]
|
||||||
|
'handle-add-custom-stage-remain': [stageName: string]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
// 事件处理函数
|
||||||
|
const handleAddCustomStage = (stageName: string) => {
|
||||||
|
emit('handle-add-custom-stage', stageName)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAddCustomStage1 = (stageName: string) => {
|
||||||
|
emit('handle-add-custom-stage1', stageName)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAddCustomStage2 = (stageName: string) => {
|
||||||
|
emit('handle-add-custom-stage2', stageName)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAddCustomStage3 = (stageName: string) => {
|
||||||
|
emit('handle-add-custom-stage3', stageName)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAddCustomStageRemain = (stageName: string) => {
|
||||||
|
emit('handle-add-custom-stage-remain', stageName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式化 tooltip
|
||||||
|
const escapeHtml = (text: string) =>
|
||||||
|
text
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/'/g, ''')
|
||||||
|
|
||||||
|
const formatTooltip = (text: string) => {
|
||||||
|
if (!text) return ''
|
||||||
|
return escapeHtml(text).replace(/\n/g, '<br/>')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.form-section {
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
border-bottom: 2px solid var(--ant-color-border-secondary);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
.plan-mode-display {
|
||||||
|
min-height: 40px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border: 1px solid var(--ant-color-border);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: var(--ant-color-bg-container);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plan-value {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--ant-color-text);
|
||||||
|
font-weight: 500;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plan-source {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--ant-color-primary);
|
||||||
|
font-weight: 500;
|
||||||
|
padding: 2px 8px;
|
||||||
|
background: var(--ant-color-primary-bg);
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid var(--ant-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.plan-tooltip {
|
||||||
|
white-space: normal;
|
||||||
|
line-height: 1.5;
|
||||||
|
max-width: 320px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
122
frontend/src/views/MAAUserEdit/StageSelector.vue
Normal file
122
frontend/src/views/MAAUserEdit/StageSelector.vue
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
<template>
|
||||||
|
<a-select
|
||||||
|
:value="value"
|
||||||
|
@update:value="$emit('update:value', $event)"
|
||||||
|
:disabled="loading"
|
||||||
|
size="large"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
>
|
||||||
|
<template #dropdownRender="{ menuNode: menu }">
|
||||||
|
<v-nodes :vnodes="menu" />
|
||||||
|
<a-divider style="margin: 4px 0" />
|
||||||
|
<a-space style="padding: 4px 8px" size="small">
|
||||||
|
<a-input
|
||||||
|
ref="inputRef"
|
||||||
|
v-model:value="customStageName"
|
||||||
|
placeholder="输入自定义关卡,如: 11-8"
|
||||||
|
style="flex: 1"
|
||||||
|
size="small"
|
||||||
|
@keyup.enter="addCustomStage"
|
||||||
|
/>
|
||||||
|
<a-button type="text" size="small" @click="addCustomStage">
|
||||||
|
<template #icon>
|
||||||
|
<PlusOutlined />
|
||||||
|
</template>
|
||||||
|
添加关卡
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
<a-select-option
|
||||||
|
v-for="option in options"
|
||||||
|
:key="option.value"
|
||||||
|
:value="option.value"
|
||||||
|
>
|
||||||
|
<template v-if="option.label.includes('|')">
|
||||||
|
<span>{{ option.label.split('|')[0] }}</span>
|
||||||
|
<a-tag color="green" size="small" style="margin-left: 8px">
|
||||||
|
{{ option.label.split('|')[1] }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
{{ option.label }}
|
||||||
|
<a-tag
|
||||||
|
v-if="isCustomStage(option.value)"
|
||||||
|
color="blue"
|
||||||
|
size="small"
|
||||||
|
style="margin-left: 8px"
|
||||||
|
>
|
||||||
|
自定义
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, defineComponent } from 'vue'
|
||||||
|
import { PlusOutlined } from '@ant-design/icons-vue'
|
||||||
|
import { message } from 'ant-design-vue'
|
||||||
|
|
||||||
|
// VNodes 组件定义
|
||||||
|
const VNodes = defineComponent({
|
||||||
|
props: { vnodes: { type: Object, required: true } },
|
||||||
|
setup(props) {
|
||||||
|
return () => props.vnodes as any
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
value: string
|
||||||
|
options: any[]
|
||||||
|
loading: boolean
|
||||||
|
placeholder?: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
'update:value': [value: string]
|
||||||
|
'add-custom-stage': [stageName: string]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const customStageName = ref('')
|
||||||
|
const inputRef = ref()
|
||||||
|
|
||||||
|
// 判断值是否为自定义关卡
|
||||||
|
const isCustomStage = (value: string) => {
|
||||||
|
if (!value || value === '' || value === '-') return false
|
||||||
|
// 检查是否在从API加载的关卡列表中
|
||||||
|
const predefinedStage = props.options.find(
|
||||||
|
option => option.value === value && !option.isCustom
|
||||||
|
)
|
||||||
|
return !predefinedStage
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证关卡名称格式
|
||||||
|
const validateStageName = (stageName: string): boolean => {
|
||||||
|
if (!stageName || !stageName.trim()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// 简单的关卡名称验证
|
||||||
|
const stagePattern = /^[a-zA-Z0-9\-_\u4e00-\u9fa5]+$/
|
||||||
|
return stagePattern.test(stageName.trim())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加自定义关卡
|
||||||
|
const addCustomStage = () => {
|
||||||
|
if (!validateStageName(customStageName.value)) {
|
||||||
|
message.error('请输入有效的关卡名称')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const trimmedName = customStageName.value.trim()
|
||||||
|
|
||||||
|
// 检查是否已存在
|
||||||
|
const exists = props.options.find((option: any) => option.value === trimmedName)
|
||||||
|
if (exists) {
|
||||||
|
message.warning(`关卡 "${trimmedName}" 已存在`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
emit('add-custom-stage', trimmedName)
|
||||||
|
customStageName.value = ''
|
||||||
|
}
|
||||||
|
</script>
|
||||||
116
frontend/src/views/MAAUserEdit/TaskConfigSection.vue
Normal file
116
frontend/src/views/MAAUserEdit/TaskConfigSection.vue
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
<template>
|
||||||
|
<div class="form-section">
|
||||||
|
<div class="section-header">
|
||||||
|
<h3>任务配置</h3>
|
||||||
|
</div>
|
||||||
|
<a-row :gutter="24">
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item name="ifWakeUp" label="开始唤醒">
|
||||||
|
<a-switch v-model:checked="formData.Task.IfWakeUp" :disabled="loading" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item name="ifRecruiting" label="自动公招">
|
||||||
|
<a-switch v-model:checked="formData.Task.IfRecruiting" :disabled="loading" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item name="ifBase" label="基建换班">
|
||||||
|
<a-switch v-model:checked="formData.Task.IfBase" :disabled="loading" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item name="ifCombat" label="刷理智">
|
||||||
|
<a-switch v-model:checked="formData.Task.IfCombat" :disabled="loading" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
<a-row :gutter="24">
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item name="ifMall" label="获取信用及购物">
|
||||||
|
<a-switch v-model:checked="formData.Task.IfMall" :disabled="loading" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item name="ifMission" label="领取奖励">
|
||||||
|
<a-switch v-model:checked="formData.Task.IfMission" :disabled="loading" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item name="ifAutoRoguelike">
|
||||||
|
<template #label>
|
||||||
|
<a-tooltip title="未完全适配,请谨慎使用">
|
||||||
|
<span>自动肉鸽 </span>
|
||||||
|
<QuestionCircleOutlined class="help-icon" />
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<a-switch v-model:checked="formData.Task.IfAutoRoguelike" :disabled="true" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item name="ifReclamation">
|
||||||
|
<template #label>
|
||||||
|
<a-tooltip title="暂不支持,等待适配中~">
|
||||||
|
<span>生息演算 </span>
|
||||||
|
<QuestionCircleOutlined class="help-icon" />
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<a-switch v-model:checked="formData.Task.IfReclamation" :disabled="true" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { QuestionCircleOutlined } from '@ant-design/icons-vue'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
formData: any
|
||||||
|
loading: boolean
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.form-section {
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
border-bottom: 2px solid var(--ant-color-border-secondary);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user