效果
获取值方式
this.$refs.xxx.generateCron();
直接上代码
<!--
调度策略配置组件
用于配置 Cron 表达式的界面组件,支持秒、分、时、天、月、周、年的配置
提供四种配置方式:
1. 每一个时间单位执行
2. 从指定值开始每隔特定间隔执行
3. 选择具体时间点执行
4. 设置时间周期执行
-->
<template>
<div style="box-sizing: border-box; padding: 16px; font-size: 14px">
<!-- 使用选项卡展示不同时间单位的配置 -->
<el-tabs type="border-card" v-model="activeName" @tab-click="handleClick">
<el-tab-pane v-for="item in tabPanes" :key="item.code" :name="item.code">
<!-- 自定义选项卡标签,包含日历图标 -->
<div slot="label" style="display: flex; align-items: center">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" width="16"
height="18" viewBox="0 0 16 16">
<g>
<g>
<path
d="M6,1.75L6,3.25L10,3.25L10,1.75L11,1.75L11,3.25L13,3.25C13.5523,3.25,14,3.69772,14,4.25L14,13.25C14,13.8023,13.5523,14.25,13,14.25L3,14.25C2.447715,14.25,2,13.8023,2,13.25L2,4.25C2,3.69771,2.447715,3.25,3,3.25L5,3.25L5,1.75L6,1.75ZM5,4.25L3,4.25L3,6.25L13,6.25L13,4.25L11,4.25L11,5.25L10,5.25L10,4.25L6,4.25L6,5.25L5,5.25L5,4.25ZM3,13.25L13,13.25L13,7.25L3,7.25L3,13.25Z"
fill-rule="evenodd" :fill="activeName === item.code ? ' #1D68D0' : '#000000'" fill-opacity="1" />
</g>
</g>
</svg>
{{ item.name }}
</div>
<div>
<!-- 配置选项一:每一个时间单位执行 -->
<div style="line-height: 32px; margin-bottom: 16px">
<el-radio v-model="item.configurationSelection" label="every">每一{{ item.text }}</el-radio>
</div>
<!-- 配置选项二:从特定值开始间隔执行 -->
<div style="margin-bottom: 16px">
<el-radio v-model="item.configurationSelection" label="across">
<span> 从<el-input-number :style="numberInputStyle" :size="formComSize"
v-model="item.configurationSelectionData.across[0]" controls-position="right" :min="1"
:max="numberInputMax"></el-input-number>{{ item.text }}开始</span>,
<span>每隔<el-input-number :style="numberInputStyle" :size="formComSize"
v-model="item.configurationSelectionData.across[1]" controls-position="right" :min="1"
:max="numberInputMax"></el-input-number>{{ item.text }}执行</span>
</el-radio>
</div>
<!-- 配置选项三:选择具体时间点 -->
<div style="margin-bottom: 16px">
<el-radio v-model="item.configurationSelection" label="concreteness">
具体{{ item.text }}数(可多选)
<el-select v-model="item.configurationSelectionData.concreteness" multiple placeholder="请选择"
style="margin: 0 2px 0 0">
<el-option v-for="item in item.configurationSelectionData
.concretenessOptions" :key="item.value" :size="formComSize" :label="item.name" :value="item.value">
</el-option>
</el-select>
{{ item.text }}开始
</el-radio>
</div>
<!-- 配置选项四:设置执行周期 -->
<div style="margin-bottom: 16px">
<el-radio v-model="item.configurationSelection" label="cycle">
周期从
<el-input-number :style="numberInputStyle" :size="formComSize"
v-model="item.configurationSelectionData.cycle[0]" controls-position="right" :min="0"
:max="numberInputMax"></el-input-number>
到
<el-input-number :style="numberInputStyle" :size="formComSize"
v-model="item.configurationSelectionData.cycle[1]" controls-position="right" :min="0"
:max="numberInputMax"></el-input-number>
{{ item.text }}
</el-radio>
</div>
</div>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
/**
* 生成基础配置数据
* @returns {Array} 包含秒、分、时、天、月、周、年的配置数组
*/
const CronConfig = () => {
// 定义基础时间单位配置
const d = [
{
name: "秒", // 显示名称
code: "second", // 标识符
text: "秒", // 单位文本
max: 59, // 最大值
},
{
name: "分", // 显示名称
code: "minute", // 标识符
text: "分钟", // 单位文本
max: 59, // 最大值
},
{
name: "时", // 显示名称
code: "hour", // 标识符
text: "小时", // 单位文本
max: 23, // 最大值
},
{
name: "天", // 显示名称
code: "day", // 标识符
text: "天", // 单位文本
max: 31, // 最大值
},
{
name: "月", // 显示名称
code: "month", // 标识符
text: "月", // 单位文本
max: 12, // 最大值
},
{
name: "周", // 显示名称
code: "week", // 标识符
text: "周", // 单位文本
max: 7, // 最大值
},
{
name: '年', // 显示名称
code: 'year', // 标识符
text: '年', // 单位文本
max: 9999, // 最大值
}
];
// 为每个时间单位添加配置选项
d.forEach((e) => {
// 生成具体数值选项
const concretenessOptions = [];
for (let i = 0; i <= e.max; i++) {
concretenessOptions.push({
name: i,
value: i,
});
}
// 为每个时间单位添加配置数据结构
e = Object.assign(e, {
configurationSelection: "every", // 默认选择"每一"配置
configurationSelectionData: {
every: "*", // 通配符,表示每一个时间单位
across: [0, 0], // 间隔执行的起始值和间隔值
concreteness: [], // 具体时间点数组
cycle: [0, 0], // 周期的起始值和结束值
concretenessOptions: concretenessOptions, // 可选的具体时间点
},
});
});
return d;
};
export default {
data() {
return {
numberInputStyle: { width: "100px", margin: "0 4px" }, // 数字输入框统一样式
formComSize: "small", // 表单组件统一大小
numberInputMax: 59, // 数字输入框最大值(随时间单位动态变化)
tabPanes: CronConfig(), // 初始化配置面板数据
activeName: "second", // 默认选中"秒"配置
};
},
methods: {
/**
* 处理标签页切换事件
* 更新当前输入框最大值限制
*/
handleClick() {
const c = this.tabPanes.find((e) => e.code === this.activeName);
this.numberInputMax = c.max;
const { configurationSelection } = this.$options.data();
this.configurationSelection = configurationSelection;
},
/**
* 生成 Cron 表达式和对应的中文描述
* @returns {Object} 包含 cron 表达式和中文描述的对象
*/
generateCron() {
let cron = this.tabPanes.map((e) => {
const { configurationSelection, configurationSelectionData } = e;
switch (configurationSelection) {
case "every":
return `${configurationSelectionData.every}`;
case "across":
return `${configurationSelectionData.across[0]}/${configurationSelectionData.across[1]}`;
case "concreteness":
return `${configurationSelectionData.concreteness.join(",")}`;
case "cycle":
return `${configurationSelectionData.cycle[0]}-${configurationSelectionData.cycle[1]}`;
default:
}
return "";
});
cron = cron.join(" ");
return {
cron: cron,
chinese: this.cronToChina(cron),
};
},
/**
* 将 Cron 表达式转换为可读的中文描述
* @param {string} cron Cron 表达式
* @returns {string} 中文描述
*/
cronToChina(cron) {
const texts = CronConfig().map((e) => e.text);
cron = cron.split(" ");
for (let i = 0; i < cron.length; i++) {
if (cron[i] === "*" || cron[i] === "?") {
cron[i] = ``;
}
if (cron[i].includes("/")) {
cron[i] = cron[i].split("/");
if (String(cron[i][0]) === String(0)) {
cron[i] = `每隔${cron[i][1]}${texts[i]}`;
} else {
cron[
i
] = `从${cron[i][0]}${texts[i]}开始每隔${cron[i][1]}${texts[i]}`;
}
}
if (cron[i].includes("-")) {
cron[i] = cron[i].split("-");
cron[i] = `周期从${cron[i][0]}到${cron[i][1]}${texts[i]}`;
}
if (cron[i] === "0") {
cron[i] = "";
}
if (String(cron[i]).length === 1 || cron[i].includes(",")) {
cron[i] = `具体${cron[i]}${texts[i]}`;
}
}
return (
cron
.reverse()
.filter((e) => e !== "")
.join(",") + "触发"
);
},
},
};
</script>
<style scoped></style>