1. 前端CRON表达式编辑器组件
CronExpressionEditor.vue
组件是系统中用于创建和编辑CRON表达式的核心UI组件,它提供了直观的界面来生成复杂的定时任务表达式。
1.1 组件结构与状态管理
// 核心状态变量
const second = ref<string>('0');
const minute = ref<string>('0');
const hour = ref<string>('*');
const day = ref<string>('*');
const month = ref<string>('*');
const week = ref<string>('?');
const year = ref<string>('');
// 选择模式
const secondMode = ref('specific');
const minuteMode = ref('specific');
const hourMode = ref('every');
const dayMode = ref('every');
const monthMode = ref('every');
const weekMode = ref('notSpecified');
const yearMode = ref('notSpecified');
组件使用Vue 3的Composition API管理复杂状态,每个CRON时间单位(秒、分、时、日、月、周、年)都有对应的:
- 值状态(value):存储实际CRON表达式部分
- 模式状态(mode):决定用户如何设置此字段(具体值、每一个、周期范围、间隔等)
1.2 值更新与表达式生成
组件通过一系列的响应式函数处理用户交互,核心是updateFieldValue
函数:
const updateFieldValue = (field: string) => {
switch (field) {
case 'minute':
if (minuteMode.value === 'every') {
minute.value = '*';
} else if (minuteMode.value === 'specific') {
minute.value = specificMinutes.value.length > 0
? specificMinutes.value.join(',')
: '0';
} else if (minuteMode.value === 'cycle') {
minute.value = `${minuteCycleStart.value}-${minuteCycleEnd.value}`;
} else if (minuteMode.value === 'interval') {
minute.value = `${minuteIntervalStart.value}/${minuteIntervalStep.value}`;
}
break;
// 其他字段处理...
}
};
当用户更改任何设置时,这个函数会更新对应的CRON表达式部分,然后调用updateCronExpression
生成完整表达式。
1.3 PostgreSQL适配处理
组件特别增加了对PostgreSQL pg_cron的兼容转换:
const convertToPgCronFormat = (expression: string): string => {
// 1. 移除秒字段,pg_cron只支持5段式表达式
const parts = expression.split(' ');
if (parts.length >= 6) {
parts.shift();
}
// 2. 处理特殊步长格式 0/10 转为 */10
const convertedParts = parts.map(part => {
if (part.match(/^0\/\d+$/)) {
return part.replace('0/', '*/');
}
return part;
});
return convertedParts.join(' ');
};
这确保生成的CRON表达式能够在PostgreSQL的pg_cron扩展中正确执行。
1.4 人性化表达与预览
组件使用cronstrue
库将技术性的CRON表达式转换为自然语言描述:
const cronDescription = computed(() => {
try {
if (!cronExpression.value) return '请输入有效的Cron表达式';
// 使用cronstrue库解析cron表达式为中文
const description = cronstrue.toString(cronExpression.value, { locale: 'zh_CN' });
// 向父组件发送当前表达式的描述
emit('update:description', description);
return description;
} catch (e) {
console.error('解析错误:', e);
emit('update:description', '无效的Cron表达式');
return '无效的Cron表达式';
}
});
同时提供未来几次执行时间的预览:
const nextExecutionTimes = computed(() => {
try {
if (!cronExpression.value) return [];
const interval = parseCronExpression(cronExpression.value);
if (!interval) return [];
const times = [];
for (let i = 0; i < 5; i++) {
try {
const next = interval.next();
times.push(dayjs(next.toDate()).format('YYYY-MM-DD HH:mm:ss'));
} catch (e) {
break;
}
}
return times;
} catch (e) {
console.error('计算下次执行时间错误:', e);
return [];
}
});
2. 分析计划编辑器与CRON集成
AnalysisPlanEditor.vue
是创建和编辑分析计划的主界面,它集成了CRON表达式编辑器。
2.1 表单与CRON表达式关联
const formState = reactive({
// ...其他字段
cronExpression: '0 9 * * *', // 默认每天上午9点
cronDescription: '', // 表达式的描述字段
// ...其他字段
});
2.2 CRON表达式验证
编辑器实现了表单验证,确保CRON表达式有效:
const rules: Record<string, Rule[]> = {
// ...其他字段验证
cronExpression: [
{ required: true, message: '请输入CRON表达式', trigger: 'blur', type: 'string' },
{
validator: (_: Rule, value: string) => {
// 简单验证CRON表达式是否有效
const parts = value.trim().split(/\s+/);
if (parts.length < 5 || parts.length > 7) {
return Promise.reject('无效的CRON表达式');
}
return Promise.resolve();
},
trigger: 'blur',
type: 'string'
}
],
// ...其他字段验证
};
2.3 提交计划与CRON存储
当保存分析计划时,CRON表达式会被存储到execution_frequency
字段:
const handleSubmit = async () => {
try {
await formRef.value.validate();
// 构建计划数据
const planData = {
// ...其他字段
execution_frequency: {
cron_expression: formState.cronExpression,
description: formState.cronDescription
},
// ...其他字段
};
// 发送到后端
// ...提交逻辑
} catch (error) {
// ...错误处理
}
};
3. 前端CRON工具函数
cronUtils.ts
文件提供了前端使用的CRON表达式处理工具函数:
3.1 CRON表达式转换
export function convertToPgCronFormat(cronExpression: string): string {
try {
if (!cronExpression) return '';
// 分割表达式
const parts = cronExpression.trim().split(/\s+/);
// 处理6段式表达式 (带秒的格式)
if (parts.length === 6) {
// 移除秒字段
return parts.slice(1).join(' ');
}
// 处理7段式表达式 (带秒和年的格式)
if (parts.length === 7) {
// 移除秒和年字段
return parts.slice(1, 6).join(' ');
}
// 处理特殊格式:0/10 这种步长表达式在pg_cron中应写为 */10
const result = parts.map(part => {
if (part.match(/^0\/\d+$/)) {
return part.replace('0/', '*/');
}
return part;
}).join(' ');
return result;
} catch (error) {
console.error('转换CRON表达式出错:', error);
return cronExpression; // 转换失败时返回原表达式
}
}
3.2 CRON表达式描述生成
export function formatCronToText(cronExpression: string): string {
try {
if (!cronExpression) return '无效的表达式';
// 解析cron表达式部分
const parts = cronExpression.trim().split(/\s+/);
if (parts.length < 5 || parts.length > 7) {
return '无效的CRON表达式';
}
// ...复杂的解析逻辑
return description;
} catch (error) {
console.error('解析CRON表达式出错:', error);
return '无法解析的CRON表达式';
}
}
3.3 预设模板
系统提供了常用的CRON表达式模板,便于用户快速选择:
export const cronTemplates = [
{ label: '每分钟', value: '* * * * *' },
{ label: '每5分钟', value: '*/5 * * * *' },
{ label: '每小时', value: '0 * * * *' },
{ label: '每天午夜', value: '0 0 * * *' },
{ label: '每天上午9点', value: '0 9 * * *' },
{ label: '每周一上午9点', value: '0 9 * * 1' },
{ label: '每月1号午夜', value: '0 0 1 * *' },
{ label: '工作日上午9点', value: '0 9 * * 1-5' }
];
4. 前后端交互流程
4.1 创建/编辑分析计划
- 用户通过
AnalysisPlanEditor.vue
设置计划参数,包括使用CronExpressionEditor.vue
设置CRON表达式 - 表单验证确保CRON表达式格式正确
- 提交时,将CRON表达式转换为pg_cron兼容格式,并存储在
execution_frequency
字段
// 保存分析计划
const savePlan = async (formData) => {
try {
// 确保CRON表达式格式正确
const pgCompatibleCron = convertToPgCronFormat(formData.cronExpression);
const planData = {
// ...其他字段
execution_frequency: {
cron_expression: pgCompatibleCron,
description: formData.cronDescription
},
// ...其他字段
};
// 创建或更新
if (isEditMode.value) {
await analysisPlanApi.updateAnalysisPlan(planId.value, planData);
} else {
await analysisPlanApi.createAnalysisPlan(planData);
}
message.success(`分析计划${isEditMode.value ? '更新' : '创建'}成功`);
router.push('/desktop/quality_management/analysis_plans');
} catch (error) {
message.error(`操作失败: ${error.message}`);
}
};
4.2 前端时间处理
前端使用dayjs
库处理日期时间,确保与后端时区一致:
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';
// 启用dayjs插件
dayjs.extend(isSameOrBefore);
dayjs.locale('zh-cn');
5. 技术实现要点
5.1 CRON表达式编辑器的核心特性
模块化设计:
- 将CRON表达式编辑功能封装为独立组件
- 实现与父组件的双向绑定(v-model)
- 提供表达式描述的辅助输出
用户友好界面:
- 将复杂的CRON语法转换为直观的界面控件
- 提供多种设置模式:specific、every、cycle、interval
- 实时预览未来执行时间
格式兼容性:
- 支持标准6段式和7段式CRON表达式
- 自动转换为PostgreSQL pg_cron兼容的5段式
- 处理特殊语法格式
5.2 前端工具函数设计
清晰的职责划分:
- 将CRON相关逻辑抽取到独立的
cronUtils.ts
- 提供统一的格式转换和描述生成API
- 将CRON相关逻辑抽取到独立的
错误处理与降级:
- 所有工具函数都有完善的错误捕获
- 解析失败时提供友好的降级显示
5.3 前后端协同
统一格式约定:
- 前端将CRON表达式转换为后端兼容格式
- JSON结构化存储表达式与描述信息
双重验证:
- 前端提供基本的格式验证
- 后端在创建pg_cron作业时再次验证和转换
6. 数据流图
7. 最佳实践与注意事项
CRON表达式注意事项:
- 使用预设模板可以避免常见错误
- PostgreSQL pg_cron仅支持5段式表达式(分 时 日 月 周)
- 避免使用过于复杂的表达式
前端开发建议:
- 充分利用
cronstrue
库提供人性化描述 - 使用计算属性显示未来执行时间
- 在保存前进行充分验证
- 充分利用
与后端集成:
- 确保时区设置一致(前端与数据库)
- 理解pg_cron的限制和特性
- 正确处理特殊语法(如
0/10
到*/10
的转换)
通过这种设计,系统实现了用户友好的定时任务设置界面,同时确保生成的CRON表达式能够在PostgreSQL后端正确执行,为分析计划的自动执行提供了强大支持。