feat: 编辑任务对话框使用 Tab 分类重构
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
1. 使用 Tabs 分类组织内容: - 基本信息:名称、租户、类型、调度 - 脚本配置:脚本内容、参数 - 通知与高级:通知渠道、重试、告警 2. 固定对话框高度,内部滚动,避免整体滚动体验差
This commit is contained in:
@@ -561,203 +561,218 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 编辑对话框 -->
|
<!-- 编辑对话框 -->
|
||||||
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="900px" top="5vh">
|
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="900px" top="5vh" class="task-dialog">
|
||||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
|
||||||
<el-row :gutter="20">
|
<el-tabs type="border-card">
|
||||||
<el-col :span="12">
|
<!-- Tab 1: 基本信息 -->
|
||||||
<el-form-item label="任务名称" prop="task_name">
|
<el-tab-pane label="基本信息">
|
||||||
<el-input v-model="form.task_name" placeholder="如: 每日销售播报" />
|
<div class="tab-content">
|
||||||
</el-form-item>
|
<el-row :gutter="20">
|
||||||
</el-col>
|
<el-col :span="12">
|
||||||
<el-col :span="12">
|
<el-form-item label="任务名称" prop="task_name">
|
||||||
<el-form-item label="所属租户">
|
<el-input v-model="form.task_name" placeholder="如: 每日销售播报" />
|
||||||
<el-select v-model="form.tenant_id" placeholder="全局任务" clearable style="width: 100%">
|
</el-form-item>
|
||||||
<el-option label="全局任务" value="" />
|
</el-col>
|
||||||
<el-option v-for="t in tenants" :key="t.code" :label="t.name" :value="t.code" />
|
<el-col :span="12">
|
||||||
</el-select>
|
<el-form-item label="所属租户">
|
||||||
</el-form-item>
|
<el-select v-model="form.tenant_id" placeholder="全局任务" clearable style="width: 100%">
|
||||||
</el-col>
|
<el-option label="全局任务" value="" />
|
||||||
</el-row>
|
<el-option v-for="t in tenants" :key="t.code" :label="t.name" :value="t.code" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="任务类型">
|
<el-form-item label="任务类型">
|
||||||
<el-radio-group v-model="form.task_type">
|
<el-radio-group v-model="form.task_type">
|
||||||
<el-radio value="script">Python 脚本</el-radio>
|
<el-radio value="script">Python 脚本</el-radio>
|
||||||
<el-radio value="webhook">Webhook</el-radio>
|
<el-radio value="webhook">Webhook</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="调度方式">
|
<el-form-item label="调度方式">
|
||||||
<el-radio-group v-model="form.schedule_type">
|
<el-radio-group v-model="form.schedule_type">
|
||||||
<el-radio value="simple">指定时间点</el-radio>
|
<el-radio value="simple">指定时间点</el-radio>
|
||||||
<el-radio value="cron">CRON 表达式</el-radio>
|
<el-radio value="cron">CRON 表达式</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<!-- 调度配置 -->
|
<!-- 调度配置 -->
|
||||||
<el-form-item v-if="form.schedule_type === 'simple'" label="执行时间">
|
<el-form-item v-if="form.schedule_type === 'simple'" label="执行时间">
|
||||||
<div class="time-points-container">
|
<div class="time-points-container">
|
||||||
<div class="time-points-list">
|
<div class="time-points-list">
|
||||||
<el-tag
|
<el-tag
|
||||||
v-for="(tp, idx) in form.time_points"
|
v-for="(tp, idx) in form.time_points"
|
||||||
:key="idx"
|
:key="idx"
|
||||||
closable
|
closable
|
||||||
@close="removeTimePoint(idx)"
|
@close="removeTimePoint(idx)"
|
||||||
style="margin-right: 8px; margin-bottom: 8px"
|
style="margin-right: 8px; margin-bottom: 8px"
|
||||||
>
|
>
|
||||||
{{ tp }}
|
{{ tp }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
|
</div>
|
||||||
|
<div class="time-points-add">
|
||||||
|
<el-time-select
|
||||||
|
v-model="newTimePoint"
|
||||||
|
start="00:00"
|
||||||
|
step="00:30"
|
||||||
|
end="23:30"
|
||||||
|
placeholder="选择时间"
|
||||||
|
style="width: 120px"
|
||||||
|
/>
|
||||||
|
<el-button type="primary" size="small" @click="addTimePoint">添加</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-tip">点击添加按钮增加执行时间点</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-else label="CRON表达式">
|
||||||
|
<el-input v-model="form.cron_expression" placeholder="0 9 * * *" style="width: 300px" />
|
||||||
|
<div class="form-tip">格式: 分 时 日 月 周,如: 0 9 * * * (每天9点)</div>
|
||||||
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
<div class="time-points-add">
|
</el-tab-pane>
|
||||||
<el-time-select
|
|
||||||
v-model="newTimePoint"
|
<!-- Tab 2: 执行配置 -->
|
||||||
start="00:00"
|
<el-tab-pane :label="form.task_type === 'script' ? '脚本配置' : 'Webhook配置'">
|
||||||
step="00:30"
|
<div class="tab-content">
|
||||||
end="23:30"
|
<!-- Webhook 配置 -->
|
||||||
placeholder="选择时间"
|
<template v-if="form.task_type === 'webhook'">
|
||||||
style="width: 120px"
|
<el-form-item label="Webhook URL">
|
||||||
/>
|
<el-input v-model="form.webhook_url" placeholder="https://example.com/webhook" />
|
||||||
<el-button type="primary" size="small" @click="addTimePoint">添加</el-button>
|
</el-form-item>
|
||||||
|
<el-form-item label="请求方法">
|
||||||
|
<el-select v-model="form.webhook_method" style="width: 120px">
|
||||||
|
<el-option value="GET" />
|
||||||
|
<el-option value="POST" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 脚本配置 -->
|
||||||
|
<template v-if="form.task_type === 'script'">
|
||||||
|
<el-form-item label="脚本内容">
|
||||||
|
<div class="script-editor-container">
|
||||||
|
<div class="script-toolbar">
|
||||||
|
<el-button size="small" @click="handleShowSdkDocs">SDK 文档</el-button>
|
||||||
|
<el-button size="small" @click="showScriptDialog">
|
||||||
|
<el-icon><FullScreen /></el-icon>
|
||||||
|
全屏编辑
|
||||||
|
</el-button>
|
||||||
|
<el-button size="small" type="primary" @click="showTestDialog">测试运行</el-button>
|
||||||
|
</div>
|
||||||
|
<el-input
|
||||||
|
v-model="form.script_content"
|
||||||
|
type="textarea"
|
||||||
|
:rows="14"
|
||||||
|
placeholder="Python 脚本"
|
||||||
|
class="script-textarea"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 任务参数 -->
|
||||||
|
<el-form-item label="任务参数">
|
||||||
|
<div class="params-preview">
|
||||||
|
<div v-if="Object.keys(form.input_params || {}).length === 0" style="color: #999">
|
||||||
|
暂无参数
|
||||||
|
</div>
|
||||||
|
<div v-else class="params-tags">
|
||||||
|
<el-tag v-for="(val, key) in form.input_params" :key="key" style="margin-right: 8px">
|
||||||
|
{{ key }}: {{ String(val).substring(0, 20) }}{{ String(val).length > 20 ? '...' : '' }}
|
||||||
|
</el-tag>
|
||||||
|
</div>
|
||||||
|
<el-button size="small" type="primary" @click="showParamsDialog">编辑参数</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="form-tip">脚本中使用 get_param('key') 获取</div>
|
||||||
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</el-tab-pane>
|
||||||
<div class="form-tip">点击添加按钮增加执行时间点</div>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item v-else label="CRON表达式">
|
|
||||||
<el-input v-model="form.cron_expression" placeholder="0 9 * * *" />
|
|
||||||
<div class="form-tip">格式: 分 时 日 月 周,如: 0 9 * * * (每天9点)</div>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<!-- Webhook 配置 -->
|
<!-- Tab 3: 通知与高级 -->
|
||||||
<template v-if="form.task_type === 'webhook'">
|
<el-tab-pane label="通知与高级">
|
||||||
<el-form-item label="Webhook URL">
|
<div class="tab-content">
|
||||||
<el-input v-model="form.webhook_url" placeholder="https://example.com/webhook" />
|
<div class="section-title">通知配置</div>
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="请求方法">
|
|
||||||
<el-select v-model="form.webhook_method" style="width: 120px">
|
|
||||||
<el-option value="GET" />
|
|
||||||
<el-option value="POST" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- 脚本配置 -->
|
<el-form-item label="通知渠道">
|
||||||
<template v-if="form.task_type === 'script'">
|
<div v-if="!form.tenant_id" class="form-tip" style="color: #e6a23c">
|
||||||
<el-form-item label="脚本内容">
|
请先在「基本信息」选择租户,再配置通知渠道
|
||||||
<div class="script-editor-container">
|
</div>
|
||||||
<div class="script-toolbar">
|
<template v-else>
|
||||||
<el-button size="small" @click="handleShowSdkDocs">SDK 文档</el-button>
|
<el-select
|
||||||
<el-button size="small" @click="showScriptDialog">
|
v-model="form.notify_channels"
|
||||||
<el-icon><FullScreen /></el-icon>
|
multiple
|
||||||
全屏编辑
|
placeholder="选择通知渠道(可多选)"
|
||||||
</el-button>
|
style="width: 100%"
|
||||||
<el-button size="small" type="primary" @click="showTestDialog">测试运行</el-button>
|
@focus="fetchNotifyChannels(form.tenant_id)"
|
||||||
</div>
|
>
|
||||||
<el-input
|
<el-option
|
||||||
v-model="form.script_content"
|
v-for="ch in notifyChannels"
|
||||||
type="textarea"
|
:key="ch.id"
|
||||||
:rows="12"
|
:label="`${ch.channel_name} (${ch.channel_type === 'dingtalk_bot' ? '钉钉' : '企微'})`"
|
||||||
placeholder="Python 脚本"
|
:value="ch.id"
|
||||||
class="script-textarea"
|
/>
|
||||||
/>
|
</el-select>
|
||||||
|
<div class="form-tip">
|
||||||
|
脚本中设置 <code>result = {'content': '内容', 'title': '标题'}</code> 变量,执行后自动发送
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="企微应用">
|
||||||
|
<div v-if="!form.tenant_id" class="form-tip" style="color: #e6a23c">
|
||||||
|
请先选择租户
|
||||||
|
</div>
|
||||||
|
<template v-else>
|
||||||
|
<el-select
|
||||||
|
v-model="form.notify_wecom_app_id"
|
||||||
|
placeholder="选择企微应用(可选)"
|
||||||
|
clearable
|
||||||
|
style="width: 100%"
|
||||||
|
@focus="fetchWecomApps(form.tenant_id)"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="app in wecomApps"
|
||||||
|
:key="app.id"
|
||||||
|
:label="app.app_name"
|
||||||
|
:value="app.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
<div class="form-tip">发送到企微应用的全员消息</div>
|
||||||
|
</template>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<div class="section-title" style="margin-top: 24px">高级配置</div>
|
||||||
|
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="失败重试">
|
||||||
|
<el-input-number v-model="form.retry_count" :min="0" :max="10" />
|
||||||
|
<span style="margin-left: 8px; color: #999">次</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="重试间隔">
|
||||||
|
<el-input-number v-model="form.retry_interval" :min="10" :max="3600" />
|
||||||
|
<span style="margin-left: 8px; color: #999">秒</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-form-item label="失败告警">
|
||||||
|
<el-switch v-model="form.alert_on_failure" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="form.alert_on_failure" label="告警地址">
|
||||||
|
<el-input v-model="form.alert_webhook" placeholder="钉钉/企微机器人 Webhook 地址" />
|
||||||
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-tab-pane>
|
||||||
</template>
|
</el-tabs>
|
||||||
|
|
||||||
<!-- 任务参数 -->
|
|
||||||
<el-form-item label="任务参数">
|
|
||||||
<div class="params-preview">
|
|
||||||
<div v-if="Object.keys(form.input_params || {}).length === 0" style="color: #999">
|
|
||||||
暂无参数
|
|
||||||
</div>
|
|
||||||
<div v-else class="params-tags">
|
|
||||||
<el-tag v-for="(val, key) in form.input_params" :key="key" style="margin-right: 8px">
|
|
||||||
{{ key }}: {{ String(val).substring(0, 20) }}{{ String(val).length > 20 ? '...' : '' }}
|
|
||||||
</el-tag>
|
|
||||||
</div>
|
|
||||||
<el-button size="small" type="primary" @click="showParamsDialog">编辑参数</el-button>
|
|
||||||
</div>
|
|
||||||
<div class="form-tip">脚本中使用 get_param('key') 获取</div>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<!-- 高级配置 -->
|
|
||||||
<el-divider>高级配置</el-divider>
|
|
||||||
|
|
||||||
<el-row :gutter="20">
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="失败重试">
|
|
||||||
<el-input-number v-model="form.retry_count" :min="0" :max="10" />
|
|
||||||
<span style="margin-left: 8px; color: #999">次</span>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="重试间隔">
|
|
||||||
<el-input-number v-model="form.retry_interval" :min="10" :max="3600" />
|
|
||||||
<span style="margin-left: 8px; color: #999">秒</span>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
|
|
||||||
<el-form-item label="失败告警">
|
|
||||||
<el-switch v-model="form.alert_on_failure" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item v-if="form.alert_on_failure" label="告警地址">
|
|
||||||
<el-input v-model="form.alert_webhook" placeholder="钉钉/企微机器人 Webhook 地址" />
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<!-- 通知配置 -->
|
|
||||||
<el-divider>通知配置(脚本设置 result 变量后自动发送)</el-divider>
|
|
||||||
|
|
||||||
<el-form-item label="通知渠道">
|
|
||||||
<div v-if="!form.tenant_id" class="form-tip" style="color: #e6a23c">
|
|
||||||
请先选择租户,再配置通知渠道
|
|
||||||
</div>
|
|
||||||
<template v-else>
|
|
||||||
<el-select
|
|
||||||
v-model="form.notify_channels"
|
|
||||||
multiple
|
|
||||||
placeholder="选择通知渠道(可多选)"
|
|
||||||
style="width: 100%"
|
|
||||||
@focus="fetchNotifyChannels(form.tenant_id)"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="ch in notifyChannels"
|
|
||||||
:key="ch.id"
|
|
||||||
:label="`${ch.channel_name} (${ch.channel_type === 'dingtalk_bot' ? '钉钉' : '企微'})`"
|
|
||||||
:value="ch.id"
|
|
||||||
/>
|
|
||||||
</el-select>
|
|
||||||
<div class="form-tip">
|
|
||||||
脚本中设置 <code>result = {'content': '内容', 'title': '标题'}</code> 变量,执行后自动发送
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item label="企微应用">
|
|
||||||
<div v-if="!form.tenant_id" class="form-tip" style="color: #e6a23c">
|
|
||||||
请先选择租户
|
|
||||||
</div>
|
|
||||||
<template v-else>
|
|
||||||
<el-select
|
|
||||||
v-model="form.notify_wecom_app_id"
|
|
||||||
placeholder="选择企微应用(可选)"
|
|
||||||
clearable
|
|
||||||
style="width: 100%"
|
|
||||||
@focus="fetchWecomApps(form.tenant_id)"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="app in wecomApps"
|
|
||||||
:key="app.id"
|
|
||||||
:label="app.app_name"
|
|
||||||
:value="app.id"
|
|
||||||
/>
|
|
||||||
</el-select>
|
|
||||||
<div class="form-tip">发送到企微应用的全员消息</div>
|
|
||||||
</template>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@@ -1041,6 +1056,33 @@ onMounted(() => {
|
|||||||
min-height: 200px;
|
min-height: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 编辑对话框样式 */
|
||||||
|
.task-dialog :deep(.el-dialog__body) {
|
||||||
|
padding: 10px 20px;
|
||||||
|
max-height: 65vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-dialog :deep(.el-tabs__content) {
|
||||||
|
height: calc(65vh - 100px);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content {
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.output-preview, .error-preview {
|
.output-preview, .error-preview {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|||||||
Reference in New Issue
Block a user