[cron]基于vue2和element的cron生成组件(同时生成中文含义)

483 阅读1分钟

效果

image.png

获取值方式

this.$refs.xxx.generateCron();

image.png

直接上代码

<!-- 
  调度策略配置组件
  用于配置 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>
          &nbsp;{{ 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>&nbsp;<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>