Merge branch 'refs/heads/dev_1.0.0_beta2' into dev
This commit is contained in:
commit
980be3e2ac
2
.env
2
.env
@ -2,7 +2,7 @@ VITE_APP_TITLE=Snail Job
|
||||
|
||||
VITE_APP_DESC=A flexible, reliable, and fast platform for distributed task retry and distributed task scheduling.
|
||||
|
||||
VITE_APP_VERSION=3.1.0
|
||||
VITE_APP_VERSION=1.0.0-beta2
|
||||
|
||||
# the prefix of the icon name
|
||||
VITE_ICON_PREFIX=icon
|
||||
|
61
README.md
Normal file
61
README.md
Normal file
@ -0,0 +1,61 @@
|
||||
<p align="center">
|
||||
<a href="https://snailjob.opensnail.com">
|
||||
<img alt="snail-job-Logo" src="public/favicon.svg" width="200px">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
🔥🔥🔥 灵活,可靠和快速的分布式任务重试和分布式任务调度平台<br> <br/>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
|
||||
> ✅️ 可重放,可管控、为提高分布式业务系统一致性的分布式任务重试平台 <br/>
|
||||
> ✅️ 支持秒级、可中断、可编排的高性能分布式任务调度平台
|
||||
>
|
||||
</p>
|
||||
|
||||
# 简介
|
||||
|
||||
> SnailJob 是一个灵活、可靠且高效的分布式任务重试和任务调度平台。其核心采用分区模式实现,具备高度可伸缩性和容错性的分布式系统。拥有完善的权限管理、强大的告警监控功能和友好的界面交互。欢迎大家接入并使用。
|
||||
|
||||
# 开源地址
|
||||
- [snail-job](https://gitee.com/aizuda/snail-job.git)
|
||||
- [snail-job-demo](https://gitee.com/opensnail/snail-job-demo.git)
|
||||
|
||||
# 预览地址
|
||||
https://snailjob.opensnail.com/docs/preview.html
|
||||
|
||||
## 特别用户
|
||||
<a href="http://aizuda.com/?from=mp" >
|
||||
<img alt="snail-job-Logo" src="public/aizuda.png" width="200px">
|
||||
</a>
|
||||
<a href="https://plus-doc.dromara.org/#/">
|
||||
<img alt="snail-job-Logo" src="public/ryp.png" width="300px" height="71">
|
||||
</a>
|
||||
|
||||
## 相关链接
|
||||
|
||||
- [字节跳动: 如何优雅地重试](https://juejin.cn/post/6914091859463634951)
|
||||
- [这款分布式重试组件,治好了我的重试强迫症!](https://juejin.cn/post/7249607108043145274)
|
||||
- [系统简介](https://snailjob.opensnail.com/docs/introduce/preface.html)
|
||||
|
||||
## 快速入门
|
||||
|
||||
- [服务部署](https://snailjob.opensnail.com/docs/guide/service_deployment.html)
|
||||
- [HelloWorld](https://snailjob.opensnail.com/docs/guide/hello_world.html)
|
||||
|
||||
## 期望
|
||||
|
||||
欢迎提出更好的意见,帮助完善 snail-job
|
||||
|
||||
## 版权
|
||||
|
||||
Aizuda/SnailJob 采用[APACHE LICENSE 2.0](https://gitee.com/aizuda/snail-job/blob/master/LICENSE)
|
||||
开源协议,您在使用过程中,需要注意以下几点:
|
||||
|
||||
1. 不得修改产品相关代码的源码头注释和出处;
|
||||
2. 不得进行简单修改包装声称是自己的产品;
|
||||
3. 不得应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法目的;
|
||||
|
||||
|
@ -113,5 +113,5 @@
|
||||
"*": "eslint --fix"
|
||||
},
|
||||
"officialWebsite": "https://snailjob.opensnail.com",
|
||||
"website": "https://snailjob.opensnail.com/pages/78ba75/"
|
||||
"website": "https://snailjob.opensnail.com/docs/preview.html"
|
||||
}
|
||||
|
BIN
public/aizuda.png
Normal file
BIN
public/aizuda.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
BIN
public/ryp.png
Normal file
BIN
public/ryp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 52 KiB |
@ -22,8 +22,6 @@ const interval = ref<number>(props.backOff === 2 || props.backOff === 4 ? Number
|
||||
/** 保存 `CRON表达式` 类型的 表达式 */
|
||||
const cron = ref<string>(props.backOff === 3 ? model.value! : '* * * * * ?');
|
||||
|
||||
const delayLevelDesc = ref('10s,15s,30s,35s,40s,50s,1m,2m,4m,6m,8m,10m,20m,40m,1h,2h,3h,4h,5h,6h,7h,8h,9h,10h,11h,12h');
|
||||
|
||||
/** 监视 触发间隔 变化 */
|
||||
watch(
|
||||
interval,
|
||||
@ -70,7 +68,6 @@ watch(
|
||||
:placeholder="$t('page.retryScene.form.triggerInterval')"
|
||||
clearable
|
||||
/>
|
||||
<NInput v-else v-model:value="delayLevelDesc" type="textarea" :autosize="{ minRows: 1, maxRows: 3 }" readonly />
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
|
@ -213,6 +213,15 @@ export const taskBatchStatusRecord: Record<Api.Common.TaskBatchStatus, App.I18n.
|
||||
};
|
||||
export const taskBatchStatusRecordOptions = transformRecordToNumberOption(taskBatchStatusRecord);
|
||||
|
||||
export const taskStatusRecord: Record<Api.Common.TaskStatus, App.I18n.I18nKey> = {
|
||||
2: 'common.taskStatus.items.running',
|
||||
3: 'common.taskStatus.items.success',
|
||||
4: 'common.taskStatus.items.fail',
|
||||
5: 'common.taskStatus.items.stop',
|
||||
6: 'common.taskStatus.items.cancel'
|
||||
};
|
||||
export const taskStatusRecordOptions = transformRecordToNumberOption(taskStatusRecord);
|
||||
|
||||
export const operationReasonRecord: Record<Api.Common.OperationReason, App.I18n.I18nKey> = {
|
||||
0: 'common.jobOperationReason.items.none',
|
||||
1: 'common.jobOperationReason.items.taskExecutionTimeout',
|
||||
|
@ -133,6 +133,17 @@ const local: App.I18n.Schema = {
|
||||
cancel: 'Cancel'
|
||||
}
|
||||
},
|
||||
taskStatus: {
|
||||
label: 'Task status',
|
||||
form: 'Please enter task status',
|
||||
items: {
|
||||
running: 'Running',
|
||||
success: 'Success',
|
||||
fail: 'Fail',
|
||||
stop: 'Stop',
|
||||
cancel: 'Cancel'
|
||||
}
|
||||
},
|
||||
jobOperationReason: {
|
||||
label: 'Job operation reason',
|
||||
form: 'Please enter job operation reason',
|
||||
@ -513,7 +524,9 @@ const local: App.I18n.Schema = {
|
||||
groupPartition: 'Please select Group partition',
|
||||
initScene: 'Initialized scene',
|
||||
collapseCommon: 'Common config',
|
||||
collapseRetry: 'Retry config'
|
||||
collapseRetry: 'Retry config',
|
||||
groupNameRule:
|
||||
'Group name: Must be between 1 and 64 characters in length. Format: numbers, letters, underscores, or hyphens.'
|
||||
},
|
||||
idMode: {
|
||||
idWorker: 'Id Workder',
|
||||
@ -866,7 +879,7 @@ const local: App.I18n.Schema = {
|
||||
deadlineRequest: 'Please enter Call chain timeout(ms)',
|
||||
routeKey: 'Please enter Routing strategy',
|
||||
backOff: 'Please enter Backoff strategy',
|
||||
sceneName2: 'Scene name: 1~64 characters. allowing: digit, letters and underscore.'
|
||||
sceneName2: 'Scene name: 1~64 characters. allowing: digit, letters, underscore or hyphens..'
|
||||
},
|
||||
addScene: 'Add Scenes',
|
||||
editScene: 'Add Scenes',
|
||||
@ -1004,6 +1017,7 @@ const local: App.I18n.Schema = {
|
||||
title: 'Job task list',
|
||||
id: 'ID',
|
||||
groupName: 'Group name',
|
||||
taskStatus: 'Status',
|
||||
clientInfo: 'Client address',
|
||||
argsStr: 'Argument string',
|
||||
resultMessage: 'Result message',
|
||||
|
@ -133,6 +133,17 @@ const local: App.I18n.Schema = {
|
||||
cancel: '取消'
|
||||
}
|
||||
},
|
||||
taskStatus: {
|
||||
label: '状态',
|
||||
form: '请选择状态',
|
||||
items: {
|
||||
running: '运行中',
|
||||
success: '处理成功',
|
||||
fail: '处理失败',
|
||||
stop: '任务停止',
|
||||
cancel: '取消'
|
||||
}
|
||||
},
|
||||
jobOperationReason: {
|
||||
label: '操作原因',
|
||||
form: '请选择执行状态',
|
||||
@ -521,7 +532,8 @@ const local: App.I18n.Schema = {
|
||||
groupPartition: '分区',
|
||||
initScene: '初始化场景',
|
||||
collapseCommon: '通用配置',
|
||||
collapseRetry: '重试配置'
|
||||
collapseRetry: '重试配置',
|
||||
groupNameRule: '组名称: 仅支持长度为:1~64位字符.格式为:数字、字母、下划线、短横线。'
|
||||
},
|
||||
idMode: {
|
||||
idWorker: '雪花算法',
|
||||
@ -874,7 +886,7 @@ const local: App.I18n.Schema = {
|
||||
deadlineRequest: '请输入调用链超时时间(毫秒)',
|
||||
routeKey: '请输入路由策略',
|
||||
backOff: '请输入退避策略',
|
||||
sceneName2: '场景名称: 仅支持长度为:1~64位字符.格式为:数字、字母、下划线。'
|
||||
sceneName2: '场景名称: 仅支持长度为:1~64位字符.格式为:数字、字母、下划线和中横线。'
|
||||
},
|
||||
addScene: '新增场景',
|
||||
editScene: '编辑场景',
|
||||
@ -1011,6 +1023,7 @@ const local: App.I18n.Schema = {
|
||||
title: 'JobTask 列表',
|
||||
id: 'ID',
|
||||
groupName: '组名称',
|
||||
taskStatus: '状态',
|
||||
clientInfo: '地址',
|
||||
argsStr: '参数',
|
||||
resultMessage: '结果',
|
||||
|
@ -170,8 +170,10 @@ async function initRoute(to: RouteLocationNormalized): Promise<RouteLocationRaw
|
||||
const authStore = useAuthStore();
|
||||
await authStore.getInfo();
|
||||
const { data, error } = await fetchVersion();
|
||||
if (!error) {
|
||||
if (!error && data) {
|
||||
localStg.set('version', data!);
|
||||
} else {
|
||||
localStg.remove('version');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
15
src/typings/api.d.ts
vendored
15
src/typings/api.d.ts
vendored
@ -88,6 +88,9 @@ declare namespace Api {
|
||||
/** 1、待处理 2、运行中 3、成功 4、失败 5、停止 6、取消 */
|
||||
type TaskBatchStatus = 1 | 2 | 3 | 4 | 5 | 6;
|
||||
|
||||
/** 2、处理中 3、处理成功 4、处理失败、5、任务停止 6、取消 */
|
||||
type TaskStatus = 2 | 3 | 4 | 5 | 6;
|
||||
|
||||
/**
|
||||
* 1、任务执行超时 2、无客户端节点 3、JOB已关闭 4、任务丢弃 5、任务被覆盖 6、无可执行任务项 7、任务执行期间发生非预期异常 8、手动停止 9、条件节点执行异常 10、任务中断 11、回调节点执行异常 12、无需处理
|
||||
* 13、节点关闭跳过执行 14、判定未通过
|
||||
@ -197,10 +200,10 @@ declare namespace Api {
|
||||
type DashboardLine = {
|
||||
taskList: TaskList;
|
||||
rankList: RankList[];
|
||||
dashboardLineResponseDOList: DashboardLineResponseDOList[];
|
||||
dashboardLineResponseDOList: DashboardLineResponseDO[];
|
||||
};
|
||||
|
||||
type DashboardLineResponseDOList = {
|
||||
type DashboardLineResponseDO = {
|
||||
createDt: string;
|
||||
total: number;
|
||||
} & DashboardLineJob &
|
||||
@ -209,7 +212,7 @@ declare namespace Api {
|
||||
type DashboardLineJob = {
|
||||
createDt: string;
|
||||
total: number;
|
||||
fail: number;
|
||||
failNum: number;
|
||||
stop: number;
|
||||
cancel: number;
|
||||
success: number;
|
||||
@ -262,6 +265,8 @@ declare namespace Api {
|
||||
*/
|
||||
type DashboardLineMode = 'JOB' | 'WORKFLOW';
|
||||
|
||||
type TaskType = 'JOB' | 'RETRY' | 'WORKFLOW';
|
||||
|
||||
type DashboardLineParams = {
|
||||
groupName?: string;
|
||||
type: DashboardLineType;
|
||||
@ -541,7 +546,7 @@ declare namespace Api {
|
||||
/** notify-config */
|
||||
type NotifyConfig = Common.CommonRecord<{
|
||||
/** 组名称 */
|
||||
groupName: string;
|
||||
groupName: string | null;
|
||||
/** 业务ID */
|
||||
businessId: string | null;
|
||||
/** 通知人id */
|
||||
@ -995,6 +1000,8 @@ declare namespace Api {
|
||||
createDt: string;
|
||||
/** 任务批次 ID */
|
||||
taskBatchId: string;
|
||||
/** 任务状态 ID */
|
||||
taskStatus: Common.TaskStatus;
|
||||
}>;
|
||||
|
||||
/** jobTask search params */
|
||||
|
13
src/typings/app.d.ts
vendored
13
src/typings/app.d.ts
vendored
@ -383,6 +383,17 @@ declare namespace App {
|
||||
cancel: string;
|
||||
};
|
||||
};
|
||||
taskStatus: {
|
||||
label: string;
|
||||
form: string;
|
||||
items: {
|
||||
running: string;
|
||||
success: string;
|
||||
fail: string;
|
||||
stop: string;
|
||||
cancel: string;
|
||||
};
|
||||
};
|
||||
jobOperationReason: {
|
||||
label: string;
|
||||
form: string;
|
||||
@ -660,6 +671,7 @@ declare namespace App {
|
||||
initScene: string;
|
||||
collapseCommon: string;
|
||||
collapseRetry: string;
|
||||
groupNameRule: string;
|
||||
};
|
||||
idMode: {
|
||||
idWorker: string;
|
||||
@ -1149,6 +1161,7 @@ declare namespace App {
|
||||
title: string;
|
||||
id: string;
|
||||
groupName: string;
|
||||
taskStatus: string;
|
||||
clientInfo: string;
|
||||
argsStr: string;
|
||||
resultMessage: string;
|
||||
|
@ -27,10 +27,12 @@ const version = ref<string>(`v${localStg.get('version') || VITE_APP_VERSION}`);
|
||||
|
||||
const getVersion = async () => {
|
||||
const { data, error } = await fetchVersion();
|
||||
if (!error) {
|
||||
if (!error && data) {
|
||||
version.value = data;
|
||||
localStg.set('version', data);
|
||||
return;
|
||||
}
|
||||
localStg.remove('version');
|
||||
};
|
||||
|
||||
getVersion();
|
||||
|
@ -1,41 +1,44 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { $t } from '@/locales';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import pkg from '~/package.json';
|
||||
import { localStg } from '@/utils/storage';
|
||||
|
||||
const appStore = useAppStore();
|
||||
|
||||
const column = computed(() => (appStore.isMobile ? 1 : 2));
|
||||
|
||||
interface PkgJson {
|
||||
name: string;
|
||||
version: string;
|
||||
dependencies: PkgVersionInfo[];
|
||||
devDependencies: PkgVersionInfo[];
|
||||
}
|
||||
// interface PkgJson {
|
||||
// name: string;
|
||||
// dependencies: PkgVersionInfo[];
|
||||
// devDependencies: PkgVersionInfo[];
|
||||
// }
|
||||
|
||||
interface PkgVersionInfo {
|
||||
name: string;
|
||||
version: string;
|
||||
}
|
||||
// interface PkgVersionInfo {
|
||||
// name: string;
|
||||
// version: string;
|
||||
// }
|
||||
|
||||
const { name, version, dependencies, devDependencies } = pkg;
|
||||
const { VITE_APP_VERSION } = import.meta.env;
|
||||
|
||||
function transformVersionData(tuple: [string, string]): PkgVersionInfo {
|
||||
const [$name, $version] = tuple;
|
||||
return {
|
||||
name: $name,
|
||||
version: $version
|
||||
};
|
||||
}
|
||||
// const { name, dependencies, devDependencies } = pkg;
|
||||
//
|
||||
// function transformVersionData(tuple: [string, string]): PkgVersionInfo {
|
||||
// const [$name, $version] = tuple;
|
||||
// return {
|
||||
// name: $name,
|
||||
// version: $version
|
||||
// };
|
||||
// }
|
||||
|
||||
const pkgJson: PkgJson = {
|
||||
name,
|
||||
version,
|
||||
dependencies: Object.entries(dependencies).map(item => transformVersionData(item)),
|
||||
devDependencies: Object.entries(devDependencies).map(item => transformVersionData(item))
|
||||
};
|
||||
const version = ref<string>(`${localStg.get('version') || VITE_APP_VERSION}`);
|
||||
|
||||
// const pkgJson: PkgJson = {
|
||||
// name,
|
||||
// dependencies: Object.entries(dependencies).map(item => transformVersionData(item)),
|
||||
// devDependencies: Object.entries(devDependencies).map(item => transformVersionData(item))
|
||||
// };
|
||||
|
||||
const latestBuildTime = BUILD_TIME;
|
||||
</script>
|
||||
@ -53,7 +56,7 @@ const latestBuildTime = BUILD_TIME;
|
||||
</a>
|
||||
</NDescriptionsItem>
|
||||
<NDescriptionsItem :label="$t('page.about.projectInfo.version')">
|
||||
<NTag type="primary">{{ pkgJson.version }}</NTag>
|
||||
<NTag type="primary">{{ version }}</NTag>
|
||||
</NDescriptionsItem>
|
||||
<NDescriptionsItem :label="$t('page.about.projectInfo.githubLink')">
|
||||
<a class="text-primary" :href="pkg.repository.githubUrl" target="_blank" rel="noopener noreferrer">
|
||||
|
@ -66,14 +66,31 @@ type RuleKey = Extract<
|
||||
'groupName' | 'token' | 'groupStatus' | 'idGeneratorMode' | 'initScene' | 'groupPartition'
|
||||
>;
|
||||
|
||||
const rules: Record<RuleKey, App.Global.FormRule> = {
|
||||
groupName: defaultRequiredRule,
|
||||
token: defaultRequiredRule,
|
||||
groupStatus: defaultRequiredRule,
|
||||
idGeneratorMode: defaultRequiredRule,
|
||||
initScene: defaultRequiredRule,
|
||||
groupPartition: defaultRequiredRule
|
||||
};
|
||||
// const rules: Record<RuleKey, App.Global.FormRule> = {
|
||||
// groupName: defaultRequiredRule,
|
||||
// token: defaultRequiredRule,
|
||||
// groupStatus: defaultRequiredRule,
|
||||
// idGeneratorMode: defaultRequiredRule,
|
||||
// initScene: defaultRequiredRule,
|
||||
// groupPartition: defaultRequiredRule
|
||||
// };
|
||||
|
||||
const rules = {
|
||||
groupName: [
|
||||
defaultRequiredRule,
|
||||
{
|
||||
required: true,
|
||||
pattern: /^[A-Za-z0-9_-]{1,64}$/,
|
||||
trigger: 'change',
|
||||
message: $t('page.groupConfig.form.groupNameRule')
|
||||
}
|
||||
],
|
||||
token: [defaultRequiredRule],
|
||||
groupStatus: [defaultRequiredRule],
|
||||
idGeneratorMode: [defaultRequiredRule],
|
||||
initScene: [defaultRequiredRule],
|
||||
groupPartition: [defaultRequiredRule]
|
||||
} satisfies Record<RuleKey, App.Global.FormRule[]>;
|
||||
|
||||
function handleUpdateModelWhenEdit() {
|
||||
if (props.operateType === 'add') {
|
||||
|
@ -2,7 +2,7 @@
|
||||
import { ref } from 'vue';
|
||||
import { fetchCardCount } from '@/service/api';
|
||||
import CardData from './modules/card-data.vue';
|
||||
import RetryTab from './modules/retry-tab.vue';
|
||||
import TaskTab from './modules/task-tab.vue';
|
||||
|
||||
const cardCount = ref<Api.Dashboard.CardCount>();
|
||||
|
||||
@ -20,7 +20,7 @@ getCardData();
|
||||
<NSpace vertical :size="16">
|
||||
<CardData v-model="cardCount!" />
|
||||
<NCard :bordered="false" class="card-wrapper p-t-136px 2xl:p-t-0 lg:p-t-36px md:p-t-90px">
|
||||
<RetryTab v-model="cardCount!" />
|
||||
<TaskTab v-model="cardCount!" />
|
||||
</NCard>
|
||||
</NSpace>
|
||||
</template>
|
||||
|
@ -91,6 +91,35 @@ interface CardData {
|
||||
|
||||
// eslint-disable-next-line complexity
|
||||
const cardData = computed<CardData[]>(() => [
|
||||
{
|
||||
key: 'jobTask',
|
||||
title: $t('page.home.jobTask'),
|
||||
tip: $t('page.home.jobTaskTip'),
|
||||
value: props.modelValue?.jobTask.totalNum ?? 0,
|
||||
color: {
|
||||
start: '#f5b386',
|
||||
end: '#FFD6BA'
|
||||
},
|
||||
icon: 'ant-design:profile-outlined',
|
||||
bottom: [
|
||||
{
|
||||
label: $t('common.success'),
|
||||
value: props.modelValue?.jobTask.successNum ?? 0
|
||||
},
|
||||
{
|
||||
label: $t('common.fail'),
|
||||
value: props.modelValue?.jobTask.failNum ?? 0
|
||||
},
|
||||
{
|
||||
label: $t('common.stop'),
|
||||
value: props.modelValue?.jobTask.stopNum ?? 0
|
||||
},
|
||||
{
|
||||
label: $t('common.cancel'),
|
||||
value: props.modelValue?.jobTask.cancelNum ?? 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'retryTask',
|
||||
title: $t('page.home.retryTask'),
|
||||
@ -121,35 +150,6 @@ const cardData = computed<CardData[]>(() => [
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'jobTask',
|
||||
title: $t('page.home.jobTask'),
|
||||
tip: $t('page.home.jobTaskTip'),
|
||||
value: props.modelValue?.jobTask.totalNum ?? 0,
|
||||
color: {
|
||||
start: '#f5b386',
|
||||
end: '#FFD6BA'
|
||||
},
|
||||
icon: 'ant-design:profile-outlined',
|
||||
bottom: [
|
||||
{
|
||||
label: $t('common.success'),
|
||||
value: props.modelValue?.jobTask.successNum ?? 0
|
||||
},
|
||||
{
|
||||
label: $t('common.fail'),
|
||||
value: props.modelValue?.jobTask.failNum ?? 0
|
||||
},
|
||||
{
|
||||
label: $t('common.stop'),
|
||||
value: props.modelValue?.jobTask.stopNum ?? 0
|
||||
},
|
||||
{
|
||||
label: $t('common.cancel'),
|
||||
value: props.modelValue?.jobTask.cancelNum ?? 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'workflow',
|
||||
title: $t('page.home.workflow'),
|
||||
@ -268,7 +268,7 @@ function getGradientColor(color: CardData['color']) {
|
||||
type="line"
|
||||
color="#728bf9"
|
||||
rail-color="#ebebeb"
|
||||
:percentage="12.58 ?? 0"
|
||||
:percentage="props.modelValue?.workFlowTask.successRate ?? 0"
|
||||
indicator-text-color="#fff"
|
||||
/>
|
||||
<DardRetryChart v-else-if="item.key === 'retryTask'" :model-value="props.modelValue?.retryTaskBarList" />
|
||||
@ -296,6 +296,6 @@ function getGradientColor(color: CardData['color']) {
|
||||
}
|
||||
|
||||
:deep(.n-progress-icon--as-text) {
|
||||
width: 53px !important;
|
||||
width: 60px !important;
|
||||
}
|
||||
</style>
|
||||
|
@ -55,7 +55,7 @@ const { domRef, updateOptions } = useEcharts(() => ({
|
||||
|
||||
const getData = async () => {
|
||||
await new Promise(resolve => {
|
||||
setTimeout(resolve, 1);
|
||||
setTimeout(resolve, 100);
|
||||
});
|
||||
|
||||
if (!props.modelValue) {
|
||||
|
@ -5,16 +5,16 @@ import { useAppStore } from '@/store/modules/app';
|
||||
import { useEcharts } from '@/hooks/common/echarts';
|
||||
|
||||
defineOptions({
|
||||
name: 'LineRetryChart'
|
||||
name: 'TaskLineChart'
|
||||
});
|
||||
|
||||
interface Props {
|
||||
type?: number;
|
||||
type?: Api.Dashboard.TaskType;
|
||||
modelValue: Api.Dashboard.DashboardLine;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
type: 0
|
||||
type: 'JOB'
|
||||
});
|
||||
|
||||
const appStore = useAppStore();
|
||||
@ -32,7 +32,7 @@ const { domRef, updateOptions } = useEcharts(() => ({
|
||||
},
|
||||
legend: {
|
||||
data:
|
||||
props.type === 0
|
||||
props.type === 'RETRY'
|
||||
? [
|
||||
$t('common.success'),
|
||||
$t('common.running'),
|
||||
@ -88,7 +88,7 @@ const { domRef, updateOptions } = useEcharts(() => ({
|
||||
},
|
||||
{
|
||||
color: '#40e9c5',
|
||||
name: props.type === 0 ? $t('common.running') : $t('common.fail'),
|
||||
name: props.type === 'RETRY' ? $t('common.running') : $t('common.fail'),
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
stack: 'Total',
|
||||
@ -118,7 +118,7 @@ const { domRef, updateOptions } = useEcharts(() => ({
|
||||
},
|
||||
{
|
||||
color: '#b686d4',
|
||||
name: props.type === 0 ? $t('page.manage.retryTask.status.maxRetryTimes') : $t('common.stop'),
|
||||
name: props.type === 'RETRY' ? $t('page.manage.retryTask.status.maxRetryTimes') : $t('common.stop'),
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
stack: 'Total',
|
||||
@ -148,7 +148,7 @@ const { domRef, updateOptions } = useEcharts(() => ({
|
||||
},
|
||||
{
|
||||
color: '#ec6f6f',
|
||||
name: props.type === 0 ? $t('page.manage.retryTask.status.pauseRetry') : $t('common.cancel'),
|
||||
name: props.type === 'RETRY' ? $t('page.manage.retryTask.status.pauseRetry') : $t('common.cancel'),
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
stack: 'Total',
|
||||
@ -190,37 +190,23 @@ const getData = () => {
|
||||
|
||||
opts.xAxis.data = props.modelValue?.dashboardLineResponseDOList.map(x => x.createDt);
|
||||
opts.series[0].data = props.modelValue?.dashboardLineResponseDOList.map(x =>
|
||||
opts.tabIndex === 0 ? x.successNum : x.success
|
||||
opts.tabIndex === 'RETRY' ? x.successNum : x.success
|
||||
);
|
||||
opts.series[1].data = props.modelValue?.dashboardLineResponseDOList.map(x =>
|
||||
opts.tabIndex === 0 ? x.runningNum : x.fail
|
||||
opts.tabIndex === 'RETRY' ? x.runningNum : x.failNum
|
||||
);
|
||||
opts.series[2].data = props.modelValue?.dashboardLineResponseDOList.map(x =>
|
||||
opts.tabIndex === 0 ? x.maxCountNum : x.stop
|
||||
opts.tabIndex === 'RETRY' ? x.maxCountNum : x.stop
|
||||
);
|
||||
opts.series[3].data = props.modelValue?.dashboardLineResponseDOList.map(x =>
|
||||
opts.tabIndex === 0 ? x.suspendNum : x.cancel
|
||||
opts.tabIndex === 'RETRY' ? x.suspendNum : x.cancel
|
||||
);
|
||||
return opts;
|
||||
});
|
||||
};
|
||||
|
||||
watch(
|
||||
() => appStore.locale,
|
||||
() => {
|
||||
getData();
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
() => {
|
||||
getData();
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.type,
|
||||
[() => appStore.locale, props],
|
||||
() => {
|
||||
getData();
|
||||
},
|
@ -7,16 +7,16 @@ import { useEcharts } from '@/hooks/common/echarts';
|
||||
import { useThemeStore } from '@/store/modules/theme';
|
||||
|
||||
defineOptions({
|
||||
name: 'PieRetryChart'
|
||||
name: 'TaskPieChart'
|
||||
});
|
||||
|
||||
interface Props {
|
||||
type?: number;
|
||||
type?: Api.Dashboard.TaskType;
|
||||
modelValue: Api.Dashboard.CardCount;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
type: 0
|
||||
type: 'JOB'
|
||||
});
|
||||
|
||||
const appStore = useAppStore();
|
||||
@ -94,16 +94,7 @@ function updateLocale() {
|
||||
opts.tooltip.textStyle.color = originOpts.tooltip.textStyle.color;
|
||||
opts.tooltip.backgroundColor = originOpts.tooltip.backgroundColor;
|
||||
|
||||
if (props.type === 0) {
|
||||
const retryTask = props.modelValue.retryTask;
|
||||
opts.series[0].data = [
|
||||
{ name: $t('common.success'), value: retryTask.finishNum / retryTask.totalNum },
|
||||
{ name: $t('common.running'), value: retryTask.runningNum / retryTask.totalNum },
|
||||
{ name: $t('page.manage.retryTask.status.maxRetryTimes'), value: retryTask.maxCountNum / retryTask.totalNum },
|
||||
{ name: $t('page.manage.retryTask.status.pauseRetry'), value: retryTask.suspendNum / retryTask.totalNum }
|
||||
];
|
||||
}
|
||||
if (props.type === 1) {
|
||||
if (props.type === 'JOB') {
|
||||
const jobTask = props.modelValue.jobTask;
|
||||
opts.series[0].data = [
|
||||
{ name: $t('common.success'), value: jobTask.successNum / jobTask.totalNum },
|
||||
@ -112,7 +103,18 @@ function updateLocale() {
|
||||
{ name: $t('common.cancel'), value: jobTask.cancelNum / jobTask.totalNum }
|
||||
];
|
||||
}
|
||||
if (props.type === 2) {
|
||||
|
||||
if (props.type === 'RETRY') {
|
||||
const retryTask = props.modelValue.retryTask;
|
||||
opts.series[0].data = [
|
||||
{ name: $t('common.success'), value: retryTask.finishNum / retryTask.totalNum },
|
||||
{ name: $t('common.running'), value: retryTask.runningNum / retryTask.totalNum },
|
||||
{ name: $t('page.manage.retryTask.status.maxRetryTimes'), value: retryTask.maxCountNum / retryTask.totalNum },
|
||||
{ name: $t('page.manage.retryTask.status.pauseRetry'), value: retryTask.suspendNum / retryTask.totalNum }
|
||||
];
|
||||
}
|
||||
|
||||
if (props.type === 'WORKFLOW') {
|
||||
const workFlowTask = props.modelValue.workFlowTask;
|
||||
opts.series[0].data = [
|
||||
{ name: $t('common.success'), value: workFlowTask.successNum / workFlowTask.totalNum },
|
@ -4,11 +4,11 @@ import type { DataTableColumns } from 'naive-ui';
|
||||
import { $t } from '@/locales';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { fetchAllGroupName, fetchJobLine, fetchRetryLine } from '@/service/api';
|
||||
import LineRetryChart from './line-retry-chart.vue';
|
||||
import PieRetryChart from './pie-retry-chart.vue';
|
||||
import TaskLineChart from './task-line-chart.vue';
|
||||
import TaskPieChart from './task-pie-chart.vue';
|
||||
|
||||
defineOptions({
|
||||
name: 'RetryTab'
|
||||
name: 'TaskTab'
|
||||
});
|
||||
|
||||
interface Props {
|
||||
@ -17,7 +17,7 @@ interface Props {
|
||||
|
||||
defineProps<Props>();
|
||||
|
||||
const type = ref(0);
|
||||
const taskType = ref<Api.Dashboard.TaskType>('JOB');
|
||||
const appStore = useAppStore();
|
||||
const gap = computed(() => (appStore.isMobile ? 0 : 16));
|
||||
const data = ref<Api.Dashboard.DashboardLine>();
|
||||
@ -25,7 +25,8 @@ const groupOptions = ref();
|
||||
const tabParams = ref<Api.Dashboard.DashboardLineParams>({
|
||||
type: 'WEEK',
|
||||
page: 1,
|
||||
size: 6
|
||||
size: 6,
|
||||
mode: 'JOB'
|
||||
});
|
||||
const dateRange = ref<[number, number] | null>();
|
||||
const formattedValue = ref<[string, string] | null>(
|
||||
@ -34,15 +35,13 @@ const formattedValue = ref<[string, string] | null>(
|
||||
|
||||
const getData = async () => {
|
||||
const { data: lineData, error } =
|
||||
type.value === 0 ? await fetchRetryLine(tabParams.value) : await fetchJobLine(tabParams.value);
|
||||
taskType.value === 'RETRY' ? await fetchRetryLine(tabParams.value) : await fetchJobLine(tabParams.value);
|
||||
|
||||
if (!error) {
|
||||
data.value = lineData;
|
||||
}
|
||||
};
|
||||
|
||||
getData();
|
||||
|
||||
const getGroupNames = async () => {
|
||||
const { data: groupNames, error } = await fetchAllGroupName();
|
||||
|
||||
@ -53,27 +52,17 @@ const getGroupNames = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
getGroupNames();
|
||||
|
||||
watch(
|
||||
() => tabParams.value,
|
||||
() => {
|
||||
getData();
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
const onUpdateTab = (value: string) => {
|
||||
if (value === 'retryTask') {
|
||||
type.value = 0;
|
||||
tabParams.value.mode = undefined;
|
||||
}
|
||||
if (value === 'jobTask') {
|
||||
type.value = 1;
|
||||
taskType.value = 'JOB';
|
||||
tabParams.value.mode = 'JOB';
|
||||
}
|
||||
if (value === 'retryTask') {
|
||||
taskType.value = 'RETRY';
|
||||
tabParams.value.mode = undefined;
|
||||
}
|
||||
if (value === 'workflow') {
|
||||
type.value = 2;
|
||||
taskType.value = 'WORKFLOW';
|
||||
tabParams.value.mode = 'WORKFLOW';
|
||||
}
|
||||
};
|
||||
@ -108,14 +97,14 @@ const pagination = ref({
|
||||
});
|
||||
|
||||
const createPanels = () => [
|
||||
{
|
||||
name: 'retryTask',
|
||||
tab: $t('page.home.retryTask')
|
||||
},
|
||||
{
|
||||
name: 'jobTask',
|
||||
tab: $t('page.home.jobTask')
|
||||
},
|
||||
{
|
||||
name: 'retryTask',
|
||||
tab: $t('page.home.retryTask')
|
||||
},
|
||||
{
|
||||
name: 'workflow',
|
||||
tab: $t('page.home.workflow')
|
||||
@ -133,13 +122,13 @@ const createColumns = (): DataTableColumns<Api.Dashboard.Task> => [
|
||||
title: $t('page.home.retryTab.task.run'),
|
||||
key: 'run',
|
||||
align: 'center',
|
||||
render: row => <span class="retry-table-number">{row.run}</span>
|
||||
render: row => <span class="task-table-number">{row.run}</span>
|
||||
},
|
||||
{
|
||||
title: $t('page.home.retryTab.task.total'),
|
||||
key: 'total',
|
||||
align: 'center',
|
||||
render: row => <span class="retry-table-number">{row.total}</span>
|
||||
render: row => <span class="task-table-number">{row.total}</span>
|
||||
}
|
||||
];
|
||||
|
||||
@ -152,6 +141,17 @@ watch(
|
||||
columns.value = createColumns();
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => tabParams.value,
|
||||
() => {
|
||||
getData();
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
getData();
|
||||
getGroupNames();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -160,20 +160,20 @@ watch(
|
||||
<NTabPane v-for="panel in panels" :key="panel.name" :tab="panel.tab" :name="panel.name">
|
||||
<NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive>
|
||||
<NGi span="24 s:24 m:16">
|
||||
<LineRetryChart v-model="data!" :type="type"></LineRetryChart>
|
||||
<TaskLineChart v-model="data!" :type="taskType" />
|
||||
</NGi>
|
||||
<NGi span="24 s:24 m:8">
|
||||
<div class="retry-tab-rank">
|
||||
<h4 class="retry-tab-title">{{ $t('page.home.retryTab.rank.title') }}</h4>
|
||||
<ul class="retry-tab-rank__list">
|
||||
<li v-for="(item, index) in data?.rankList" :key="index" class="retry-tab-rank__list--item">
|
||||
<div class="task-tab-rank">
|
||||
<h4 class="task-tab-title">{{ $t('page.home.retryTab.rank.title') }}</h4>
|
||||
<ul class="task-tab-rank__list">
|
||||
<li v-for="(item, index) in data?.rankList" :key="index" class="task-tab-rank__list--item">
|
||||
<span>
|
||||
<span class="retry-tab-rank__list--index">
|
||||
<span class="task-tab-rank__list--index">
|
||||
{{ index + 1 }}
|
||||
</span>
|
||||
<span>{{ item.name }}</span>
|
||||
</span>
|
||||
<span class="retry-tab-badge">{{ item.total }}</span>
|
||||
<span class="task-tab-badge">{{ item.total }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@ -181,7 +181,7 @@ watch(
|
||||
</NGrid>
|
||||
<NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive class="p-t-16px">
|
||||
<NGi span="24 s:24 m:16">
|
||||
<h4 class="retry-tab-title">{{ $t('page.home.retryTab.task.title') }}</h4>
|
||||
<h4 class="task-tab-title">{{ $t('page.home.retryTab.task.title') }}</h4>
|
||||
<NDivider />
|
||||
<NDataTable
|
||||
min-height="300px"
|
||||
@ -193,9 +193,9 @@ watch(
|
||||
/>
|
||||
</NGi>
|
||||
<NGi span="24 s:24 m:8">
|
||||
<h4 class="retry-tab-title">{{ $t('page.home.retryTab.pie.title') }}</h4>
|
||||
<h4 class="task-tab-title">{{ $t('page.home.retryTab.pie.title') }}</h4>
|
||||
<NDivider />
|
||||
<PieRetryChart v-model="modelValue!" :type="type" />
|
||||
<TaskPieChart v-model="modelValue!" :type="taskType" />
|
||||
</NGi>
|
||||
</NGrid>
|
||||
</NTabPane>
|
||||
@ -225,7 +225,7 @@ watch(
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.retry-table-number {
|
||||
.task-table-number {
|
||||
padding: 3px 7px;
|
||||
background-color: #f4f4f4;
|
||||
color: #555;
|
||||
@ -234,19 +234,19 @@ watch(
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.dark .retry-table-number {
|
||||
.dark .task-table-number {
|
||||
background: #2c2c2c;
|
||||
color: #d6d6d6;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.retry-tab-title {
|
||||
.task-tab-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.retry-tab-badge {
|
||||
.task-tab-badge {
|
||||
float: right;
|
||||
padding: 3px 7px;
|
||||
background-color: #f4f4f4;
|
||||
@ -256,7 +256,7 @@ watch(
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.retry-tab-rank {
|
||||
.task-tab-rank {
|
||||
height: 360px;
|
||||
overflow: hidden;
|
||||
|
||||
@ -303,12 +303,12 @@ watch(
|
||||
}
|
||||
|
||||
.dark {
|
||||
.retry-tab-badge {
|
||||
.task-tab-badge {
|
||||
background: #2c2c2c;
|
||||
color: #d6d6d6;
|
||||
}
|
||||
|
||||
.retry-tab-rank {
|
||||
.task-tab-rank {
|
||||
&__list {
|
||||
&--index {
|
||||
color: #d6d6d6;
|
@ -34,7 +34,7 @@ const { columnChecks, columns, data, getData, loading, mobilePagination, searchP
|
||||
key: 'id',
|
||||
title: $t('common.index'),
|
||||
align: 'center',
|
||||
width: 64,
|
||||
width: 120,
|
||||
render: row => {
|
||||
function showDetailDrawer() {
|
||||
detailData.value = row;
|
||||
|
@ -1,9 +1,13 @@
|
||||
<script setup lang="tsx">
|
||||
import { NButton } from 'naive-ui';
|
||||
import { NButton, NTag } from 'naive-ui';
|
||||
import { onBeforeUnmount, ref } from 'vue';
|
||||
import { executorTypeRecord, operationReasonRecord, taskBatchStatusRecord } from '@/constants/business';
|
||||
import {
|
||||
executorTypeRecord,
|
||||
operationReasonRecord,
|
||||
taskBatchStatusRecord,
|
||||
taskStatusRecord
|
||||
} from '@/constants/business';
|
||||
import { $t } from '@/locales';
|
||||
// import { fetchGetJobBatchDetail } from '@/service/api';
|
||||
import { tagColor } from '@/utils/common';
|
||||
import { useTable } from '@/hooks/common/table';
|
||||
import { fetchGetJobTaskList } from '@/service/api';
|
||||
@ -71,6 +75,27 @@ const { columns, data, loading, mobilePagination } = useTable({
|
||||
align: 'left',
|
||||
minWidth: 120
|
||||
},
|
||||
{
|
||||
key: 'taskStatus',
|
||||
title: $t('page.jobBatch.jobTask.taskStatus'),
|
||||
align: 'left',
|
||||
minWidth: 80,
|
||||
render: row => {
|
||||
if (row.taskStatus === null) {
|
||||
return null;
|
||||
}
|
||||
const label = $t(taskStatusRecord[row.taskStatus!]);
|
||||
const tagMap: Record<number, NaiveUI.ThemeColor> = {
|
||||
1: 'info',
|
||||
2: 'info',
|
||||
3: 'info',
|
||||
4: 'error',
|
||||
5: 'error',
|
||||
6: 'error'
|
||||
};
|
||||
return <NTag type={tagMap[row.taskStatus!]}>{label}</NTag>;
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'clientInfo',
|
||||
title: $t('page.jobBatch.jobTask.clientInfo'),
|
||||
|
@ -37,7 +37,7 @@ const { columnChecks, columns, data, getData, loading, mobilePagination, searchP
|
||||
key: 'index',
|
||||
title: $t('common.index'),
|
||||
align: 'center',
|
||||
width: 40
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
key: 'jobName',
|
||||
|
@ -281,39 +281,27 @@ watch(visible, () => {
|
||||
:placeholder="$t('page.jobTask.form.jobName')"
|
||||
/>
|
||||
</NFormItem>
|
||||
<NGrid cols="2 s:1 m:2" responsive="screen" x-gap="20">
|
||||
<NGi>
|
||||
<NFormItem :label="$t('page.jobTask.groupName')" path="groupName">
|
||||
<SelectGroup v-model:value="model.groupName" />
|
||||
</NFormItem>
|
||||
</NGi>
|
||||
<NGi>
|
||||
<NFormItem :label="$t('page.jobTask.jobStatus')" path="jobStatus">
|
||||
<NRadioGroup v-model:value="model.jobStatus" name="jobStatus">
|
||||
<NSpace>
|
||||
<NRadio
|
||||
v-for="item in enableStatusNumberOptions"
|
||||
:key="item.value"
|
||||
:value="item.value"
|
||||
:label="$t(item.label)"
|
||||
/>
|
||||
</NSpace>
|
||||
</NRadioGroup>
|
||||
</NFormItem>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
<NGrid cols="2 s:1 m:2" responsive="screen" x-gap="20">
|
||||
<NGi>
|
||||
<NFormItem :label="$t('page.jobTask.executorType')" path="executorType">
|
||||
<ExecutorType v-model:value="model.executorType" />
|
||||
</NFormItem>
|
||||
</NGi>
|
||||
<NGi>
|
||||
<NFormItem :label="$t('page.jobTask.executorInfo')" path="executorInfo">
|
||||
<NInput v-model:value="model.executorInfo" :placeholder="$t('page.jobTask.form.executorInfo')" />
|
||||
</NFormItem>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
<NFormItem :label="$t('page.jobTask.groupName')" path="groupName">
|
||||
<SelectGroup v-model:value="model.groupName" />
|
||||
</NFormItem>
|
||||
<NFormItem :label="$t('page.jobTask.jobStatus')" path="jobStatus">
|
||||
<NRadioGroup v-model:value="model.jobStatus" name="jobStatus">
|
||||
<NSpace>
|
||||
<NRadio
|
||||
v-for="item in enableStatusNumberOptions"
|
||||
:key="item.value"
|
||||
:value="item.value"
|
||||
:label="$t(item.label)"
|
||||
/>
|
||||
</NSpace>
|
||||
</NRadioGroup>
|
||||
</NFormItem>
|
||||
<NFormItem :label="$t('page.jobTask.executorType')" path="executorType">
|
||||
<ExecutorType v-model:value="model.executorType" />
|
||||
</NFormItem>
|
||||
<NFormItem :label="$t('page.jobTask.executorInfo')" path="executorInfo">
|
||||
<NInput v-model:value="model.executorInfo" :placeholder="$t('page.jobTask.form.executorInfo')" />
|
||||
</NFormItem>
|
||||
<NFormItem :label="$t('page.jobTask.taskType')" path="taskType">
|
||||
<TaskType v-model:value="model.taskType" :placeholder="$t('page.jobTask.form.taskType')" />
|
||||
</NFormItem>
|
||||
|
@ -108,7 +108,7 @@ watch(visible, () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<OperateDrawer v-model="visible" :title="title">
|
||||
<OperateDrawer v-model="visible" :min-size="480" :title="title">
|
||||
<NTabs v-model:value="notifyTabPane" type="segment" animated>
|
||||
<NTabPane :name="1" tab="钉钉" :disabled="notifyTabPane !== 1 && props.operateType === 'edit'">
|
||||
<DingDingForm ref="formRef" v-model:value="model" />
|
||||
|
@ -100,7 +100,7 @@ const model: Model = reactive(createDefaultModel());
|
||||
|
||||
function createDefaultModel(): Model {
|
||||
return {
|
||||
groupName: '',
|
||||
groupName: null,
|
||||
businessId: '',
|
||||
recipientIds: [],
|
||||
systemTaskType: null,
|
||||
@ -267,23 +267,11 @@ watch(visible, () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<OperateDrawer v-model="visible" :title="title" @handle-submit="handleSubmit">
|
||||
<OperateDrawer v-model="visible" :title="title" :min-size="480" @handle-submit="handleSubmit">
|
||||
<NForm ref="formRef" :model="model" :rules="rules">
|
||||
<NFormItem :label="$t('page.notifyConfig.groupName')" path="groupName">
|
||||
<SelectGroup v-model:modelValue="model.groupName" @update:model-value="groupNameUpdate" />
|
||||
</NFormItem>
|
||||
<NFormItem :label="$t('page.notifyConfig.notifyStatus')" path="notifyStatus">
|
||||
<NRadioGroup v-model:value="model.notifyStatus" name="notifyStatus">
|
||||
<NSpace>
|
||||
<NRadio
|
||||
v-for="item in enableStatusNumberOptions"
|
||||
:key="item.value"
|
||||
:value="item.value"
|
||||
:label="$t(item.label)"
|
||||
/>
|
||||
</NSpace>
|
||||
</NRadioGroup>
|
||||
</NFormItem>
|
||||
<NFormItem :label="$t('page.notifyConfig.systemTaskType')" path="systemTaskType">
|
||||
<NSelect
|
||||
v-model:value="model.systemTaskType"
|
||||
@ -341,34 +329,58 @@ watch(visible, () => {
|
||||
multiple
|
||||
/>
|
||||
</NFormItem>
|
||||
<NFormItem :label="$t('page.notifyConfig.rateLimiterStatus')" path="rateLimiterStatus">
|
||||
<NRadioGroup v-model:value="model.rateLimiterStatus" name="rateLimiterStatus" :disabled="retrySceneDisable">
|
||||
<NSpace>
|
||||
<NRadio
|
||||
v-for="item in enableStatusNumberOptions"
|
||||
:key="item.value"
|
||||
:value="item.value"
|
||||
:label="$t(item.label)"
|
||||
<NGrid cols="2 s:1 m:2" responsive="screen" x-gap="20">
|
||||
<NGi>
|
||||
<NFormItem :label="$t('page.notifyConfig.notifyStatus')" path="notifyStatus">
|
||||
<NRadioGroup v-model:value="model.notifyStatus" name="notifyStatus">
|
||||
<NSpace>
|
||||
<NRadio
|
||||
v-for="item in enableStatusNumberOptions"
|
||||
:key="item.value"
|
||||
:value="item.value"
|
||||
:label="$t(item.label)"
|
||||
/>
|
||||
</NSpace>
|
||||
</NRadioGroup>
|
||||
</NFormItem>
|
||||
</NGi>
|
||||
<NGi>
|
||||
<NFormItem :label="$t('page.notifyConfig.notifyThreshold')" path="notifyThreshold">
|
||||
<NInputNumber
|
||||
v-model:value="model.notifyThreshold"
|
||||
:min="1"
|
||||
:placeholder="$t('page.notifyConfig.form.notifyThreshold')"
|
||||
:disabled="retrySceneDisable"
|
||||
/>
|
||||
</NSpace>
|
||||
</NRadioGroup>
|
||||
</NFormItem>
|
||||
<NFormItem :label="$t('page.notifyConfig.rateLimiterThreshold')" path="notifyThreshold">
|
||||
<NInputNumber
|
||||
v-model:value="model.rateLimiterThreshold"
|
||||
:min="1"
|
||||
:placeholder="$t('page.notifyConfig.form.notifyThreshold')"
|
||||
:disabled="retrySceneDisable"
|
||||
/>
|
||||
</NFormItem>
|
||||
<NFormItem :label="$t('page.notifyConfig.notifyThreshold')" path="notifyThreshold">
|
||||
<NInputNumber
|
||||
v-model:value="model.notifyThreshold"
|
||||
:min="1"
|
||||
:placeholder="$t('page.notifyConfig.form.notifyThreshold')"
|
||||
:disabled="retrySceneDisable"
|
||||
/>
|
||||
</NFormItem>
|
||||
</NFormItem>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
<NGrid cols="2 s:1 m:2" responsive="screen" x-gap="20">
|
||||
<NGi>
|
||||
<NFormItem :label="$t('page.notifyConfig.rateLimiterStatus')" path="rateLimiterStatus">
|
||||
<NRadioGroup v-model:value="model.rateLimiterStatus" name="rateLimiterStatus" :disabled="retrySceneDisable">
|
||||
<NSpace>
|
||||
<NRadio
|
||||
v-for="item in enableStatusNumberOptions"
|
||||
:key="item.value"
|
||||
:value="item.value"
|
||||
:label="$t(item.label)"
|
||||
/>
|
||||
</NSpace>
|
||||
</NRadioGroup>
|
||||
</NFormItem>
|
||||
</NGi>
|
||||
<NGi>
|
||||
<NFormItem :label="$t('page.notifyConfig.rateLimiterThreshold')" path="notifyThreshold">
|
||||
<NInputNumber
|
||||
v-model:value="model.rateLimiterThreshold"
|
||||
:min="1"
|
||||
:placeholder="$t('page.notifyConfig.form.notifyThreshold')"
|
||||
:disabled="retrySceneDisable"
|
||||
/>
|
||||
</NFormItem>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
<NFormItem :label="$t('page.notifyConfig.description')" path="description">
|
||||
<NInput
|
||||
v-model:value="model.description"
|
||||
|
@ -107,7 +107,7 @@ const rules = {
|
||||
defaultRequiredRule,
|
||||
{
|
||||
required: true,
|
||||
pattern: /^[A-Za-z0-9_]{1,64}$/,
|
||||
pattern: /^[A-Za-z0-9_-]{1,64}$/,
|
||||
trigger: 'change',
|
||||
message: $t('page.retryScene.form.sceneName2')
|
||||
}
|
||||
@ -202,17 +202,6 @@ async function handleSubmit() {
|
||||
emit('submitted');
|
||||
}
|
||||
|
||||
function maxRetryCountUpdate(maxRetryCount: number) {
|
||||
if (model.backOff !== 1) {
|
||||
return;
|
||||
}
|
||||
let desc = '';
|
||||
for (let i = 1; i <= maxRetryCount; i += 1) {
|
||||
desc += `,${DelayLevel[i as keyof typeof DelayLevel]}`;
|
||||
}
|
||||
delayLevelDesc.value = desc.substring(1, desc.length);
|
||||
}
|
||||
|
||||
watch(visible, () => {
|
||||
if (visible.value) {
|
||||
handleUpdateModelWhenEdit();
|
||||
@ -220,10 +209,19 @@ watch(visible, () => {
|
||||
}
|
||||
});
|
||||
|
||||
watch(
|
||||
() => model.backOff,
|
||||
backOff => {
|
||||
if (backOff === 1 && model.maxRetryCount > 26) {
|
||||
model.maxRetryCount = 1;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => model.maxRetryCount,
|
||||
() => {
|
||||
maxRetryCountUpdate(model.maxRetryCount);
|
||||
delayLevelDesc.value = Object.values(DelayLevel).slice(0, model.maxRetryCount).join(',');
|
||||
}
|
||||
);
|
||||
</script>
|
||||
@ -240,34 +238,27 @@ watch(
|
||||
:placeholder="$t('page.retryScene.form.sceneName')"
|
||||
/>
|
||||
</NFormItem>
|
||||
<NGrid cols="2 s:1 m:2" responsive="screen" x-gap="20">
|
||||
<NGi>
|
||||
<NFormItem :label="$t('page.retryScene.groupName')" path="groupName">
|
||||
<NSelect
|
||||
v-model:value="model.groupName"
|
||||
:disabled="props.operateType === 'edit'"
|
||||
:placeholder="$t('page.retryScene.form.groupName')"
|
||||
:options="translateOptions2(groupNameList)"
|
||||
clearable
|
||||
<NFormItem :label="$t('page.retryScene.groupName')" path="groupName">
|
||||
<NSelect
|
||||
v-model:value="model.groupName"
|
||||
:disabled="props.operateType === 'edit'"
|
||||
:placeholder="$t('page.retryScene.form.groupName')"
|
||||
:options="translateOptions2(groupNameList)"
|
||||
clearable
|
||||
/>
|
||||
</NFormItem>
|
||||
<NFormItem :label="$t('page.retryScene.sceneStatus')" path="sceneStatus">
|
||||
<NRadioGroup v-model:value="model.sceneStatus" name="sceneStatus">
|
||||
<NSpace>
|
||||
<NRadio
|
||||
v-for="item in enableStatusNumberOptions"
|
||||
:key="item.value"
|
||||
:value="item.value"
|
||||
:label="$t(item.label)"
|
||||
/>
|
||||
</NFormItem>
|
||||
</NGi>
|
||||
<NGi>
|
||||
<NFormItem :label="$t('page.retryScene.sceneStatus')" path="sceneStatus">
|
||||
<NRadioGroup v-model:value="model.sceneStatus" name="sceneStatus">
|
||||
<NSpace>
|
||||
<NRadio
|
||||
v-for="item in enableStatusNumberOptions"
|
||||
:key="item.value"
|
||||
:value="item.value"
|
||||
:label="$t(item.label)"
|
||||
/>
|
||||
</NSpace>
|
||||
</NRadioGroup>
|
||||
</NFormItem>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
|
||||
</NSpace>
|
||||
</NRadioGroup>
|
||||
</NFormItem>
|
||||
<NGrid cols="2 s:1 m:2" responsive="screen" x-gap="20">
|
||||
<NGi>
|
||||
<NFormItem :label="$t('common.routeKey.routeLabel')" path="routeKey">
|
||||
@ -299,7 +290,18 @@ watch(
|
||||
</NGi>
|
||||
<NGi>
|
||||
<NFormItem path="triggerInterval">
|
||||
<SceneTriggerInterval v-model="model.triggerInterval" :back-off="model.backOff" />
|
||||
<SceneTriggerInterval
|
||||
v-if="model.backOff !== 1"
|
||||
v-model="model.triggerInterval"
|
||||
:back-off="model.backOff"
|
||||
/>
|
||||
<NInput
|
||||
v-else
|
||||
v-model:value="delayLevelDesc"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 1, maxRows: 3 }"
|
||||
readonly
|
||||
/>
|
||||
<template #label>
|
||||
<div class="flex-center">
|
||||
{{ $t('page.retryScene.triggerInterval') }}
|
||||
|
@ -37,7 +37,7 @@ const { columns, columnChecks, data, getData, loading, mobilePagination, searchP
|
||||
key: 'index',
|
||||
title: $t('common.index'),
|
||||
align: 'center',
|
||||
width: 64
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
key: 'workflowName',
|
||||
@ -131,7 +131,6 @@ const { columns, columnChecks, data, getData, loading, mobilePagination, searchP
|
||||
});
|
||||
|
||||
const {
|
||||
handleAdd,
|
||||
checkedRowKeys,
|
||||
onBatchDeleted
|
||||
// closeDrawer
|
||||
@ -172,8 +171,8 @@ function detail(id: string) {
|
||||
v-model:columns="columnChecks"
|
||||
:disabled-delete="checkedRowKeys.length === 0"
|
||||
:loading="loading"
|
||||
:show-add="false"
|
||||
:show-delete="false"
|
||||
@add="handleAdd"
|
||||
@delete="handleBatchDelete"
|
||||
@refresh="getData"
|
||||
/>
|
||||
|
@ -41,7 +41,7 @@ const { columns, columnChecks, data, getData, loading, mobilePagination, searchP
|
||||
key: 'index',
|
||||
title: $t('common.index'),
|
||||
align: 'center',
|
||||
width: 64
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
key: 'workflowName',
|
||||
|
Loading…
Reference in New Issue
Block a user