react+ts手写cron表达式转换组件

前言

最近在写的一个分布式调度系统,后端同学需要让我传入cron表达式,给调度接口传参。我去了学习了解了cron表达式的用法,发现有3个通用的表达式刚好符合我们的需求:

需求

  1. 每天 xx 的时间:

0 11 20 * * ?

上面是每天20:11的cron表达式

  1. 每周的 xxx 星期 的 xxx 时间

0 14 20 * * WED,THU

上面是 每周星期三,星期四20:14的cron表达式

  1. 每周的 xxx号 的 xxx时间

0 15 20 3,7 * ?

上面是 每月的3,7号20:15的cron表达式

这三个表达式刚好符合我们的需求,并且每个符号表达的意思也很直观。那么,话不多说,直接开写!

环境

  • react

    • 我的版本:“react”: “18.2.0”,用的函数组件+react hooks
  • moment

    • npm install moment
  • semi-design(组件库)

    • npm install semi-design
  • typescript

实现

数据

utils下创建cron.ts,对组件所用到的数据进行统一的管理:

export const dayOfTheWeekData = [{ key: 'MON', label: '星期一' },{ key: 'TUE', label: '星期二' },{ key: 'WED', label: '星期三' },{ key: 'THU', label: '星期四' },{ key: 'FRI', label: '星期五' },{ key: 'SAT', label: '星期六' },{ key: 'SUN', label: '星期天' }
];export const dayOfTheWeekOption = [{ key: '1', label: '星期一' },{ key: '2', label: '星期二' },{ key: '3', label: '星期三' },{ key: '4', label: '星期四' },{ key: '5', label: '星期五' },{ key: '6', label: '星期六' },{ key: '7', label: '星期天' }
];export const monthOption = [{ key: '1', label: '一月' },{ key: '2', label: '二月' },{ key: '3', label: '三月' },{ key: '4', label: '四月' },{ key: '5', label: '五月' },{ key: '6', label: '六月' },{ key: '7', label: '七月' },{ key: '8', label: '八月' },{ key: '9', label: '九月' },{ key: '10', label: '十月' },{ key: '11', label: '十一月' },{ key: '12', label: '十二月' }
];//获取dayOfTheMonthOption的每月对象
function getDayOfTheMonthOption() {const days = [];for (let i = 1; i < 32; i += 1) {days.push({ key: i.toString(), label: i.toString().concat('号') });}return days;
}export const dayOfTheMonthOption = getDayOfTheMonthOption();

组件

到了组件的具体实现,个人感觉我写的注释挺全的,就单挑几个核心重点讲下:

时间转换函数(handleTimeChange)

  //时间选择函数const handleTimeChange = (time: moment.Moment | null) => {setSelectTime(time);if (!time) return;const currentCron = expression ? expression.split(' ') : [];const [seconds, , , dayOfMonth, month1, dayOfWeek] = currentCron;const minutes = moment(time).minutes().toString(); //获取分钟const hours = moment(time).hours().toString(); //获取小时let result = null;if (!Number.isNaN(Number(hours)) && !Number.isNaN(Number(minutes))) {const minutesAndHour = seconds.concat(space).concat(minutes).concat(space).concat(hours).concat(space);if (defaultTimeType === 'everyDay') result = minutesAndHour.concat('* * ?');if (defaultTimeType !== 'everyDay')result = minutesAndHour.concat(dayOfMonth).concat(space).concat(month1).concat(space).concat(dayOfWeek);}if (result) onChange?.(result);setExpression(result);};
  1. 使用moment函数将time转成数字类型
    1. minutes = moment(time).minutes().toString(); //获取分钟
    2. hours = moment(time).hours().toString(); //获取小时
  2. 获取时间cron字符串minutesAndHour:
const minutesAndHour = seconds.concat(space).concat(minutes).concat(space).concat(hours).concat(space);
  1. 拼接得到完整的cron表达式:
    1. defaultTimeType === ‘everyDay’

result = minutesAndHour.concat(‘* * ?’);

  1. defaultTimeType !== ‘everyDay’
result = minutesAndHour.concat(dayOfMonth).concat(space).concat(month1).concat(space).concat(dayOfWeek);

日期转换函数(handleSelectChange)

setSelectedValue(data);
const selectValues = data.join(',');
const currentCron = expression ? expression.split(' ') : [];
const [seconds, minutes, hours, dayOfMonth, month1, dayOfWeek] = currentCron;
let result = '';
if (defaultTimeType === 'everyWeek') {result = seconds.concat(space).concat(minutes).concat(space).concat(hours).concat(space).concat(dayOfMonth).concat(space).concat(month1).concat(space).concat(selectValues);
}
if (defaultTimeType === 'everyMonth') {result = seconds.concat(space).concat(minutes).concat(space).concat(hours).concat(space).concat(data.length ? selectValues : '*').concat(space).concat(month1).concat(space).concat(dayOfWeek);
}
if (selectTime) onChange?.(result);
setExpression(result);
  1. defaultTimeType === ‘everyWeek’
result = seconds.concat(space).concat(minutes).concat(space).concat(hours).concat(space).concat(dayOfMonth).concat(space).concat(month1).concat(space).concat(selectValues);
  1. defaultTimeType === ‘everyMonth’
result = seconds.concat(space).concat(minutes).concat(space).concat(hours).concat(space).concat(data.length ? selectValues : '*').concat(space).concat(month1).concat(space).concat(dayOfWeek);

组件全部代码(CronInput)

import { ConfigProvider, TimePicker } from '@douyinfe/semi-ui';
import { Fragment, useState } from 'react';
import { Select } from '@douyinfe/semi-ui';
import moment from 'moment';
//引入数据
import { dayOfTheMonthOption, dayOfTheWeekData } from '@/utils/cron';const { Option } = Select;
const format = 'HH:mm';
const defaultCron = '0 * * * * ?';
const space = ' '; //空格
//类型选择
const timeTypes = [{ key: 'everyDay', label: '每天' },{ key: 'everyWeek', label: '每周' },{ key: 'everyMonth', label: '每月' }
];interface Props {onChange?: (cron?: string) => void;
}
const CronInput: React.FC<Props> = ({ onChange }) => {const [defaultTimeType, setDefaultTimeType] = useState(timeTypes[0].key); //选择类型const [selectedValue, setSelectedValue] = useState<[]>([]); //日期,多选数组const [selectTime, setSelectTime] = useState<any>(null); //时间const [expression, setExpression] = useState<string | null>(defaultCron); //bzd//类型选择函数const handleTimeTypeChange = (selectValue: string) => {setDefaultTimeType(selectValue);setSelectTime(null);setSelectedValue([]);setExpression(defaultCron);};//时间选择函数const handleTimeChange = (time: moment.Moment | null) => {setSelectTime(time);if (!time) return;const currentCron = expression ? expression.split(' ') : [];const [seconds, , , dayOfMonth, month1, dayOfWeek] = currentCron;const minutes = moment(time).minutes().toString(); //获取分钟const hours = moment(time).hours().toString(); //获取小时let result = null;if (!Number.isNaN(Number(hours)) && !Number.isNaN(Number(minutes))) {const minutesAndHour = seconds.concat(space).concat(minutes).concat(space).concat(hours).concat(space);if (defaultTimeType === 'everyDay') result = minutesAndHour.concat('* * ?');if (defaultTimeType !== 'everyDay')result = minutesAndHour.concat(dayOfMonth).concat(space).concat(month1).concat(space).concat(dayOfWeek);}if (result) onChange?.(result);setExpression(result);};const handleSelectChange = (data: []) => {setSelectedValue(data);const selectValues = data.join(',');const currentCron = expression ? expression.split(' ') : [];const [seconds, minutes, hours, dayOfMonth, month1, dayOfWeek] = currentCron;let result = '';if (defaultTimeType === 'everyWeek') {result = seconds.concat(space).concat(minutes).concat(space).concat(hours).concat(space).concat(dayOfMonth).concat(space).concat(month1).concat(space).concat(selectValues);}if (defaultTimeType === 'everyMonth') {result = seconds.concat(space).concat(minutes).concat(space).concat(hours).concat(space).concat(data.length ? selectValues : '*').concat(space).concat(month1).concat(space).concat(dayOfWeek);}if (selectTime) onChange?.(result);setExpression(result);};const RenderSelect = ({placeholder,data = []}: {placeholder: string;data: { key: string; label: string }[];}) => {return (<Fragment><Selectmultipleplaceholder={placeholder}onChange={(val: any) => handleSelectChange(val)}style={{ marginRight: '16px', width: 'auto' }}value={selectedValue}>{data.map((item: { key: string; label: string }) => (<Option key={item.key} value={item.key}>{item.label}</Option>))}</Select><ConfigProvider><TimePickervalue={selectTime && moment(selectTime, format).toDate()}format={format}placeholder="请选择时间"onChange={(val: any) => handleTimeChange(val)}/></ConfigProvider></Fragment>);};return (<><div className={'cron'}><Select// role="cron-type"style={{ marginRight: '16px', width: 'auto' }}placeholder="请选择类型"onChange={(val: any) => handleTimeTypeChange(val)}value={defaultTimeType}>{timeTypes.map((item) => (<Option key={item.key} value={item.key}>{' '}{item.label}</Option>))}</Select>{defaultTimeType === 'everyDay' && (<ConfigProvider><TimePickervalue={selectTime && moment(selectTime, format).toDate()}format={format}placeholder="请选择时间"onChange={(val: any) => handleTimeChange(val)}/></ConfigProvider>)}{defaultTimeType === 'everyWeek' && (<RenderSelect data={dayOfTheWeekData} placeholder="请选择星期" />)}{defaultTimeType === 'everyMonth' && (<RenderSelect data={dayOfTheMonthOption} placeholder="请选择日期" />)}</div></>);
};export default CronInput;

使用与效果

使用

使用方法很简单,接收onChange传来的cron表达式即可:

const App: FC<IProps> = (props) => {const { datas = [] } = props;let [value, setValue] = useState<string>();return (<div><CronInput onChange={(cron) => setValue(cron)} /><div>{value}</div></div>);
};

效果

  1. 每天

image.png

  1. 每周

image.png

  1. 每月

image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/163221.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Kotlin中的算数运算符

在Kotlin中&#xff0c;我们可以使用各种算术运算符来进行数值计算和操作。下面对这些运算符进行详细描述&#xff0c;并提供示例代码。 正号&#xff08;正数&#xff09;和负号&#xff08;负数&#xff09;&#xff1a; 正号用于表示一个正数&#xff0c;不对数值进行任何…

东方通部署vue项目

在东方通中部署vue项目需要以war 的形式进行部署具体操作步骤如下 1. 正常打包完vue 项目 在其项目目录下创建WEB-INF 文件夹&#xff0c;同时在里面新建一个 rewrite.config 的文件文件具体内容如下&#xff1a; RewriteRule ^/index\.html$ - [L]RewriteCond …

PyQt 问题记录

1.现成的组件不一定线程安全&#xff0c;&#xff08;包括且不限于数据的修改竞争,和一些组件的崩溃 ) 对于PyQt 的线程使用&#xff0c;可能还需要更谨慎些 保存逻辑 QuestionBox("保存/Save")def Save(self):okFlagFalseerrFlagFalseWriteCmd{}for it in self.Mode…

易点易动上线招标管理模块:提升企业高效招标管理的解决方案

在当今竞争激烈的商业环境下&#xff0c;招标管理对于企业的成功至关重要。为了帮助企业实现高效的招标管理&#xff0c;易点易动固定资产管理系统上线了全新的招标管理模块。该模块涵盖了供应商资质审核、采购询价单、重新报价单、招标结果单、招标作废单等功能&#xff0c;为…

vue源码笔记之——响应系统

vue是一种声明式范式编程&#xff0c;使用vue者只需要告诉其想要什么结果&#xff0c;无需关心具体实现&#xff08;vue内部做了&#xff0c;底层是利用命令式范式&#xff09; 1. reactive为什么只能操作对象&#xff0c;对于基本数据类型&#xff0c;需要用ref&#xff1f; …

ATE测试工程师的前景待遇如何?薪资天花板有多高?

在芯片行业&#xff0c;ATE测试工程师扮演着至关重要的角色。 他们不仅需要理解电路和芯片内部的工作原理&#xff0c;还需要利用各种测试工具和方法对芯片进行精确的测试和分析。那么ATE测试工程师前景如何&#xff1f;需要具备哪些技能要求呢&#xff1f; 首先来了解什么是…

计算机基础知识33

进程基础(操作系统中的概念) 进程它是操作系统总最重要的概念&#xff0c;线程也是 进程和线程都是有操作系统来调度使用的&#xff0c;我们程序员是不能控制的 # 进程和程序是两码事、完全不一样 程序&#xff1a;其实一个死的东西、一堆代码就是程序&#xff0c;它也没有生命…

通信管理机在变电站监控系统中的应用-安科瑞黄安南

随着通信管理机在我国历经多年的发展&#xff0c;随着技术的不断创新和完善&#xff0c;越来越多的变电站认可和接受并且正在使用着通信管理机。 1通信管理机的功能特点 通讯管理机一般运用于变电所、调度站&#xff0c;通讯管理机通过控制平台控制下行的RRtu设备&#xff0c…

QT学习笔记-QT程序执行Linux Shell命令实现动态添加路由

QT学习笔记-QT程序执行Linux Shell命令实现动态添加路由 背景关键代码程序界面 背景 在使用QT进行Linux下应用程序开发时&#xff0c;在特定业务需求下&#xff0c;需要在程序中执行Linux的Shell命令。QT中执行Linux命令可以通过QProcess类和system来实现&#xff0c;如果需要…

美芯片禁令再次扩大,波及英伟达、AMD以及intel等科技公司 | 百能云芯

拜登政府17日宣布&#xff0c;计划停止英伟达&#xff08;Nvidia&#xff09;、超微半导体以及英特尔等科技公司设计的先进AI芯片输出中国大陆&#xff0c;英伟达&#xff08;Nvidia&#xff09;昨日股价重挫4.68%至每股439.38美元&#xff1b;天风国际证券分析师郭明錤表示&am…

flask实战(问答平台)

课程链接 问答平台项目结构搭建 先创建一个配置文件config.py&#xff0c;后面有些配置写在这里 #app.py from flask import Flask import configapp Flask(__name__) #绑定配置文件 app.config.from_object(config)app.route(/) def hello_world(): # put applications …

嵌入式行业是否会面临中年危机?

今日话题&#xff1a;嵌入式行业是否会面临中年危机&#xff1f;事实上&#xff0c;无论你在哪个行业工作&#xff0c;都可能面临下岗风险。因此&#xff0c;我的建议是选择一个有前景、发展空间大的行业和方向&#xff0c;并不断提升自己的技能价值。为了帮助你在嵌入式领域取…

实测文心一言4.0,真的比GPT-4毫不逊色吗?

10月17日&#xff0c;李彦宏在百度世界2023上表示。当天&#xff0c;李彦宏以《手把手教你做AI原生应用》为主题发表演讲&#xff0c;发布文心大模型4.0版本。 今天&#xff0c;咱们就开门见山啊。这一回要测一测&#xff0c;昨天才发布的文心一言大模型 4.0。 之所以要测它&…

JVM(Java Virtual Machine)内存模型篇

前言 本文是JVM系列的内存模型篇&#xff0c;参考资料为《深入理解Java虚拟机》&#xff0c;本文章将会以HotSpot 虚拟机为介绍基础。 1.JVM简单介绍 Java Virtual Machine是运行Java程序的基础&#xff0c;JVM基于C、C实现&#xff0c;JVM有很多种类&#xff0c;但是这些虚…

扬帆起航:许战海方法论日文版正式发布

近日&#xff0c;中国头部战略咨询机构‘许战海咨询’最新研究成果《中国汽车行业新能源转型战略》行业白皮书日文版&#xff0c;即将在日本发布。同时发布的日文版核心方法论白皮书还有《主品牌进化战略》、《第二招牌增长战略》、《链主品牌&#xff1a;制造业的竞争之王》等…

关于代理服务器那点事

问题&#xff1a;我们有时候会遇到&#xff0c;后端再本地服务器开发&#xff0c;不是测试服上&#xff0c;这时候我们就需要代码几个baseurl 答&#xff1a;一个axios只能代理一个baseurl axios 库本身只能代理一个 baseURL。在一个 axios 实例中&#xff0c;只能指定一个基…

Spring framework day 01:spring 整合数据源(连接池)

前言 在现代的企业应用开发中&#xff0c;数据库是不可或缺的一部分。而对于大部分的应用程序来说&#xff0c;与数据库的交互涉及到频繁的连接、查询和事务操作。为了提高应用程序的性能和可扩展性&#xff0c;使用连接池来管理数据库连接是一个不错的选择。而 Spring 框架提…

Spring事件ApplicationEvent源码浅读

文章目录 demo应用实现基于注解事件过滤异步事件监听 源码解读总结 ApplicationContext 中的事件处理是通过 ApplicationEvent 类和 ApplicationListener 接口提供的。如果将实现了 ApplicationListener 接口的 bean 部署到容器中&#xff0c;则每次将 ApplicationEvent 发布到…

为什么Redis集群的最大槽数是16384个?

对于客户端请求的key&#xff0c;根据公式HASH_SLOTCRC16(key) mod 16384&#xff0c;计算出映射到哪个分片上&#xff0c;然后Redis会去相应的节点进行操作&#xff01; 为什么有16384个槽&#xff1f; Redis集群并没有使用一致性hash而是引入了哈希槽的概念。Redis 集群有1…