feat: 拆分MAAUserEdit
This commit is contained in:
@@ -362,7 +362,7 @@ const handleToggleUserStatus = (user: User) => {
|
||||
emit('toggleUserStatus', user)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
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