基于vue3的cron表达式生成组件

依赖 :

  • vue: 3.3.7
  • element-plus: 2.4.2
参考no-vue3-cron
  • 代码目录:

代码目录

  • language/cn.js
export default {
  Seconds: {
    name: "秒",
    every: "每一秒钟",
    interval: ["每隔", "秒执行 从", "秒开始"],
    specific: "具体秒数(可多选)",
    cycle: ["周期从", "到", "秒"],
  },
  Minutes: {
    name: "分",
    every: "每一分钟",
    interval: ["每隔", "分执行 从", "分开始"],
    specific: "具体分钟数(可多选)",
    cycle: ["周期从", "到", "分"],
  },
  Hours: {
    name: "时",
    every: "每一小时",
    interval: ["每隔", "小时执行 从", "小时开始"],
    specific: "具体小时数(可多选)",
    cycle: ["周期从", "到", "小时"],
  },
  Day: {
    name: "天",
    every: "每一天",
    intervalWeek: ["每隔", "周执行 从", "开始"],
    intervalDay: ["每隔", "天执行 从", "天开始"],
    specificWeek: "具体星期几(可多选)",
    specificDay: "具体天数(可多选)",
    lastDay: "在这个月的最后一天",
    lastWeekday: "在这个月的最后一个工作日",
    lastWeek: ["在这个月的最后一个"],
    beforeEndMonth: ["在本月底前", "天"],
    nearestWeekday: ["最近的工作日(周一至周五)至本月", "日"],
    someWeekday: ["在这个月的第", "个"],
  },
  Week: ["天", "一", "二", "三", "四", "五", "六"].map((val) => "星期" + val),
  Month: {
    name: "月",
    every: "每一月",
    interval: ["每隔", "月执行 从", "月开始"],
    specific: "具体月数(可多选)",
    cycle: ["从", "到", "月之间的每个月"],
  },
  Year: {
    name: "年",
    every: "每一年",
    interval: ["每隔", "年执行 从", "年开始"],
    specific: "具体年份(可多选)",
    cycle: ["从", "到", "年之间的每一年"],
  },
  Save: "保存",
  Close: "关闭",
};

  • language/index.js
import en from "./en";
import cn from "./cn";

export default {
  en,
  cn,
};

  • TestComp/index.vue
<style lang="scss">
.no-vue3-cron-div {
  .language {
    position: absolute;
    right: 25px;
    z-index: 1;
  }

  .el-tabs {
    box-shadow: none;
  }

  .tabBody {
    overflow: auto;

    .el-row {
      margin: 20px 0;

      .long {
        .el-select {
          width: 200px;
        }
      }

      .el-input-number {
        width: 120px;
      }
    }
  }

  .myScroller {
    &::-webkit-scrollbar {
      /*滚动条整体样式*/
      width: 5px;
      /*高宽分别对应横竖滚动条的尺寸*/
      height: 1px;
    }

    &::-webkit-scrollbar-thumb {
      /*滚动条里面小方块*/
      border-radius: 10px;
      background-color: skyblue;
      background-image: -webkit-linear-gradient(45deg,
          rgba(255, 255, 255, 0.2) 25%,
          transparent 25%,
          transparent 50%,
          rgba(255, 255, 255, 0.2) 50%,
          rgba(255, 255, 255, 0.2) 75%,
          transparent 75%,
          transparent);
    }

    &::-webkit-scrollbar-track {
      /*滚动条里面轨道*/
      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
      background: #ededed;
      border-radius: 10px;
    }
  }

  .bottom {
    width: 100%;
    margin-top: 5px;
    display: flex;
    align-items: center;
    justify-content: space-around;

    .value {
      float: left;
      font-size: 14px;
      vertical-align: middle;

      span:nth-child(1) {
        color: red
      }
    }
  }
}
</style>
<template>
    <div class="no-vue3-cron-div">
        <el-button
          class="language"
          text
          @click="state.language = state.language === 'en' ? 'cn' : 'en'"
          >{{ state.language === 'en' ? 'cn' : 'en' }}</el-button
        >
        <el-tabs type="border-card">
            <el-tab-pane>
                <template #label>
                    <span><i class="el-icon-date"></i> {{ state.text.Seconds.name }}</span>
                </template>
                <div class="tabBody myScroller" :style="{ 'max-height': maxHeight }">
                    <el-row>
                        <el-radio v-model="state.second.cronEvery" label="1">{{
                          state.text.Seconds.every
                        }}
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio v-model="state.second.cronEvery" label="2"
                        >{{ state.text.Seconds.interval[0] }}
                            <el-input-number
                                v-model="state.second.incrementIncrement"
                                :min="1"
                                :max="60"
                            ></el-input-number>
                            {{ state.text.Seconds.interval[1] || "" }}
                            <el-input-number

                                v-model="state.second.incrementStart"
                                :min="0"
                                :max="59"
                            ></el-input-number>
                            {{ state.text.Seconds.interval[2] || "" }}
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio class="long" v-model="state.second.cronEvery" label="3"
                        >{{ state.text.Seconds.specific }}
                            <el-select

                                multiple
                                v-model="state.second.specificSpecific"
                                @click.prevent
                            >
                                <el-option
                                    v-for="(val, index) in 60"
                                    :key="index"
                                    :value="val - 1"
                                >{{ val - 1 }}
                                </el-option
                                >
                            </el-select>
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio v-model="state.second.cronEvery" label="4"
                        >{{ state.text.Seconds.cycle[0] }}
                            <el-input-number

                                v-model="state.second.rangeStart"
                                :min="1"
                                :max="60"
                            ></el-input-number>
                            {{ state.text.Seconds.cycle[1] || "" }}
                            <el-input-number

                                v-model="state.second.rangeEnd"
                                :min="0"
                                :max="59"
                            ></el-input-number>
                            {{ state.text.Seconds.cycle[2] || "" }}
                        </el-radio>
                    </el-row>
                </div>
            </el-tab-pane>
            <el-tab-pane>
                <template #label>
                    <span><i class="el-icon-date"></i> {{ state.text.Minutes.name }}</span>
                </template>
                <div class="tabBody myScroller" :style="{ 'max-height': maxHeight }">
                    <el-row>
                        <el-radio v-model="state.minute.cronEvery" label="1">{{
                          state.text.Minutes.every
                        }}
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio v-model="state.minute.cronEvery" label="2"
                        >{{ state.text.Minutes.interval[0] }}
                            <el-input-number

                                v-model="state.minute.incrementIncrement"
                                :min="1"
                                :max="60"
                            ></el-input-number>
                            {{ state.text.Minutes.interval[1] }}
                            <el-input-number

                                v-model="state.minute.incrementStart"
                                :min="0"
                                :max="59"
                            ></el-input-number>
                            {{ state.text.Minutes.interval[2] || "" }}
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio class="long" v-model="state.minute.cronEvery" label="3"
                        >{{ state.text.Minutes.specific }}
                            <el-select
                                multiple
                                v-model="state.minute.specificSpecific"
                                @click.prevent
                            >
                                <el-option
                                    v-for="(val, index) in 60"
                                    :key="index"
                                    :value="val - 1"
                                >{{ val - 1 }}
                                </el-option
                                >
                            </el-select>
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio v-model="state.minute.cronEvery" label="4"
                        >{{ state.text.Minutes.cycle[0] }}
                            <el-input-number

                                v-model="state.minute.rangeStart"
                                :min="1"
                                :max="60"
                            ></el-input-number>
                            {{ state.text.Minutes.cycle[1] }}
                            <el-input-number

                                v-model="state.minute.rangeEnd"
                                :min="0"
                                :max="59"
                            ></el-input-number>
                            {{ state.text.Minutes.cycle[2] }}
                        </el-radio>
                    </el-row>
                </div>
            </el-tab-pane>
            <el-tab-pane>
                <template #label>
                    <span><i class="el-icon-date"></i> {{ state.text.Hours.name }}</span>
                </template>
                <div class="tabBody myScroller" :style="{ 'max-height': maxHeight }">
                    <el-row>
                        <el-radio v-model="state.hour.cronEvery" label="1">{{
                          state.text.Hours.every
                        }}
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio v-model="state.hour.cronEvery" label="2"
                        >{{ state.text.Hours.interval[0] }}
                            <el-input-number

                                v-model="state.hour.incrementIncrement"
                                :min="0"
                                :max="23"
                            ></el-input-number>
                            {{ state.text.Hours.interval[1] }}
                            <el-input-number

                                v-model="state.hour.incrementStart"
                                :min="0"
                                :max="23"
                            ></el-input-number>
                            {{ state.text.Hours.interval[2] }}
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio class="long" v-model="state.hour.cronEvery" label="3"
                        >{{ state.text.Hours.specific }}
                            <el-select multiple v-model="state.hour.specificSpecific" @click.prevent>
                                <el-option
                                    v-for="(val, index) in 24"
                                    :key="index"
                                    :value="val - 1"
                                >{{ val - 1 }}
                                </el-option
                                >
                            </el-select>
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio v-model="state.hour.cronEvery" label="4"
                        >{{ state.text.Hours.cycle[0] }}
                            <el-input-number

                                v-model="state.hour.rangeStart"
                                :min="0"
                                :max="23"
                            ></el-input-number>
                            {{ state.text.Hours.cycle[1] }}
                            <el-input-number

                                v-model="state.hour.rangeEnd"
                                :min="0"
                                :max="23"
                            ></el-input-number>
                            {{ state.text.Hours.cycle[2] }}
                        </el-radio>
                    </el-row>
                </div>
            </el-tab-pane>
            <el-tab-pane>
                <template #label>
                    <span><i class="el-icon-date"></i> {{ state.text.Day.name }}</span>
                </template>
                <div class="tabBody myScroller" :style="{ 'max-height': maxHeight }">
                    <el-row>
                        <el-radio v-model="state.day.cronEvery" label="1">{{
                          state.text.Day.every
                        }}
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio v-model="state.day.cronEvery" label="2"
                        >{{ state.text.Day.intervalWeek[0] }}
                            <el-input-number

                                v-model="state.week.incrementIncrement"
                                :min="1"
                                :max="7"
                            ></el-input-number>
                            {{ state.text.Day.intervalWeek[1] }}
                            <el-select v-model="state.week.incrementStart" @click.prevent>
                                <el-option
                                    v-for="(val, index) in 7"
                                    :key="index"
                                    :label="state.text.Week[val - 1]"
                                    :value="val"
                                ></el-option>
                            </el-select>
                            {{ state.text.Day.intervalWeek[2] }}
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio v-model="state.day.cronEvery" label="3"
                        >{{ state.text.Day.intervalDay[0] }}
                            <el-input-number

                                v-model="state.day.incrementIncrement"
                                :min="1"
                                :max="31"
                            ></el-input-number>
                            {{ state.text.Day.intervalDay[1] }}
                            <el-input-number

                                v-model="state.day.incrementStart"
                                :min="1"
                                :max="31"
                            ></el-input-number>
                            {{ state.text.Day.intervalDay[2] }}
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio class="long" v-model="state.day.cronEvery" label="4"
                        >{{ state.text.Day.specificWeek }}
                            <el-select multiple v-model="state.week.specificSpecific" @click.prevent>
                                <el-option
                                    v-for="(val, index) in 7"
                                    :key="index"
                                    :label="state.text.Week[val - 1]"
                                    :value="['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'][val - 1]
                                      "
                                ></el-option>
                            </el-select>
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio class="long" v-model="state.day.cronEvery" label="5"
                        >{{ state.text.Day.specificDay }}
                            <el-select multiple v-model="state.day.specificSpecific" @click.prevent>
                                <el-option
                                    v-for="(val, index) in 31"
                                    :key="index"
                                    :value="val"
                                >{{ val }}
                                </el-option
                                >
                            </el-select>
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio v-model="state.day.cronEvery" label="6">{{
                          state.text.Day.lastDay
                        }}
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio v-model="state.day.cronEvery" label="7">{{
                          state.text.Day.lastWeekday
                        }}
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio v-model="state.day.cronEvery" label="8"
                        >{{ state.text.Day.lastWeek[0] }}
                            <el-select v-model="state.week.cronLastSpecificDomDay" @click.prevent>
                                <el-option
                                    v-for="(val, index) in 7"
                                    :key="index"
                                    :label="state.text.Week[val - 1]"
                                    :value="val"
                                ></el-option>
                            </el-select>
                            {{ state.text.Day.lastWeek[1] || "" }}
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio v-model="state.day.cronEvery" label="9">
                            <el-input-number

                                v-model="state.day.cronDaysBeforeEomMinus"
                                :min="1"
                                :max="31"
                            ></el-input-number>
                            {{ state.text.Day.beforeEndMonth[0] }}
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio v-model="state.day.cronEvery" label="10"
                        >{{ state.text.Day.nearestWeekday[0] }}
                            <el-input-number

                                v-model="state.day.cronDaysNearestWeekday"
                                :min="1"
                                :max="31"
                            ></el-input-number>
                            {{ state.text.Day.nearestWeekday[1] }}
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio v-model="state.day.cronEvery" label="11"
                        >{{ state.text.Day.someWeekday[0] }}
                            <el-input-number

                                v-model="state.week.cronNthDayNth"
                                :min="1"
                                :max="5"
                            ></el-input-number>
                            <el-select v-model="state.week.cronNthDayDay" @click.prevent>
                                <el-option
                                    v-for="(val, index) in 7"
                                    :key="index"
                                    :label="state.text.Week[val - 1]"
                                    :value="val"
                                ></el-option>
                            </el-select>
                            {{ state.text.Day.someWeekday[1] }}
                        </el-radio>
                    </el-row>
                </div>
            </el-tab-pane>
            <el-tab-pane>
                <template #label>
                    <span><i class="el-icon-date"></i> {{ state.text.Month.name }}</span>
                </template>
                <div class="tabBody myScroller" :style="{ 'max-height': maxHeight }">
                    <el-row>
                        <el-radio v-model="state.month.cronEvery" label="1">{{
                          state.text.Month.every
                        }}
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio v-model="state.month.cronEvery" label="2"
                        >{{ state.text.Month.interval[0] }}
                            <el-input-number

                                v-model="state.month.incrementIncrement"
                                :min="0"
                                :max="12"
                            ></el-input-number>
                            {{ state.text.Month.interval[1] }}
                            <el-input-number

                                v-model="state.month.incrementStart"
                                :min="0"
                                :max="12"
                            ></el-input-number>
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio class="long" v-model="state.month.cronEvery" label="3"
                        >{{ state.text.Month.specific }}
                            <el-select multiple v-model="state.month.specificSpecific" @click.prevent>
                                <el-option
                                    v-for="(val, index) in 12"
                                    :key="index"
                                    :label="val"
                                    :value="val"
                                ></el-option>
                            </el-select>
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio v-model="state.month.cronEvery" label="4"
                        >{{ state.text.Month.cycle[0] }}
                            <el-input-number

                                v-model="state.month.rangeStart"
                                :min="1"
                                :max="12"
                            ></el-input-number>
                            {{ state.text.Month.cycle[1] }}
                            <el-input-number

                                v-model="state.month.rangeEnd"
                                :min="1"
                                :max="12"
                            ></el-input-number>
                        </el-radio>
                    </el-row>
                </div>
            </el-tab-pane>
            <el-tab-pane>
                <template #label>
                    <span><i class="el-icon-date"></i> {{ state.text.Year.name }}</span>
                </template>
                <div class="tabBody myScroller" :style="{ 'max-height': maxHeight }">
                    <el-row>
                        <el-radio v-model="state.year.cronEvery" label="1">{{
                          state.text.Year.every
                        }}
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio v-model="state.year.cronEvery" label="2"
                        >{{ state.text.Year.interval[0] }}
                            <el-input-number

                                v-model="state.year.incrementIncrement"
                                :min="1"
                                :max="99"
                            ></el-input-number>
                            {{ state.text.Year.interval[1] }}
                            <el-input-number

                                v-model="state.year.incrementStart"
                                :min="2018"
                                :max="2118"
                            ></el-input-number>
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio class="long" v-model="state.year.cronEvery" label="3"
                        >{{ state.text.Year.specific }}
                            <el-select
                                filterable
                                multiple
                                v-model="state.year.specificSpecific"
                                @click.prevent
                            >
                                <el-option
                                    v-for="(val, index) in 100"
                                    :key="index"
                                    :label="2017 + val"
                                    :value="2017 + val"
                                ></el-option>
                            </el-select>
                        </el-radio>
                    </el-row>
                    <el-row>
                        <el-radio v-model="state.year.cronEvery" label="4"
                        >{{ state.text.Year.cycle[0] }}
                            <el-input-number
                                v-model="state.year.rangeStart"
                                :min="2018"
                                :max="2118"
                            ></el-input-number>
                            {{ state.text.Year.cycle[1] }}
                            <el-input-number
                                v-model="state.year.rangeEnd"
                                :min="2018"
                                :max="2118"
                            ></el-input-number>
                        </el-radio>
                    </el-row>
                </div>
            </el-tab-pane>
        </el-tabs>
        <!-- <div class="bottom">
          <div class="value">
            <span>
              cron预览:
            </span>
            <el-tag>
                {{ state.cron }}
            </el-tag>
          </div>
          <div class="buttonDiv">
              <el-button type="primary" size="small" @click.stop="handleChange">{{ state.text.Save }}</el-button>
              <el-button type="primary" size="small" @click="close">{{ state.text.Close }}</el-button>
          </div>
        </div> -->
    </div>
</template>
<script setup>
import Language from "./language";
import { watch, reactive, computed, toRefs } from "vue";

const props = defineProps({
  cronValue: {
    type: String
  },
  i18n: {
    type: String
  },
  maxHeight: {
    type: String
  }
})
const emit = defineEmits(['close', 'change'])

const { i18n } = toRefs(props)
const state = reactive({
  language: i18n.value,
  second: {
    cronEvery: "1",
    incrementStart: 3,
    incrementIncrement: 5,
    rangeStart: 0,
    rangeEnd: 0,
    specificSpecific: [],
  },
  minute: {
    cronEvery: "1",
    incrementStart: 3,
    incrementIncrement: 5,
    rangeStart: 0,
    rangeEnd: 0,
    specificSpecific: [],
  },
  hour: {
    cronEvery: "1",
    incrementStart: 3,
    incrementIncrement: 5,
    rangeStart: 0,
    rangeEnd: 0,
    specificSpecific: [],
  },
  day: {
    cronEvery: "1",
    incrementStart: 1,
    incrementIncrement: 1,
    rangeStart: 0,
    rangeEnd: 0,
    specificSpecific: [],
    cronDaysBeforeEomMinus: 0,
    cronDaysNearestWeekday: 0,
  },
  week: {
    cronEvery: "1",
    incrementStart: 1,
    incrementIncrement: 1,
    specificSpecific: [],
    cronLastSpecificDomDay: 1,
    cronNthDayDay: 1,
    cronNthDayNth: 1,
  },
  month: {
    cronEvery: "1",
    incrementStart: 3,
    incrementIncrement: 5,
    rangeStart: 0,
    rangeEnd: 0,
    specificSpecific: [],
  },
  year: {
    cronEvery: "1",
    incrementStart: 2017,
    incrementIncrement: 1,
    rangeStart: 0,
    rangeEnd: 0,
    specificSpecific: [],
  },
  output: {
    second: "",
    minute: "",
    hour: "",
    day: "",
    month: "",
    Week: "",
    year: "",
  },
  text: computed(() => Language[state.language || "cn"])
});

const secondsText = () => {
  let seconds = "";
  let cronEvery = state.second.cronEvery;
  switch (cronEvery.toString()) {
    case "1":
      seconds = "*";
      break;
    case "2":
      seconds =
        state.second.incrementStart +
        "/" +
        state.second.incrementIncrement;
      break;
    case "3":
      state.second.specificSpecific.map((val) => {
        seconds += val + ",";
      });
      seconds = seconds.slice(0, -1);
      break;
    case "4":
      seconds = state.second.rangeStart + "-" + state.second.rangeEnd;
      break;
  }
  return seconds;
}
const minutesText = () => {
  let minutes = "";
  let cronEvery = state.minute.cronEvery;
  switch (cronEvery.toString()) {
    case "1":
      minutes = "*";
      break;
    case "2":
      minutes =
        state.minute.incrementStart +
        "/" +
        state.minute.incrementIncrement;
      break;
    case "3":
      state.minute.specificSpecific.map((val) => {
        minutes += val + ",";
      });
      minutes = minutes.slice(0, -1);
      break;
    case "4":
      minutes = state.minute.rangeStart + "-" + state.minute.rangeEnd;
      break;
  }
  return minutes;
}
const hoursText = () => {
  let hours = "";
  let cronEvery = state.hour.cronEvery;
  switch (cronEvery.toString()) {
    case "1":
      hours = "*";
      break;
    case "2":
      hours =
        state.hour.incrementStart + "/" + state.hour.incrementIncrement;
      break;
    case "3":
      state.hour.specificSpecific.map((val) => {
        hours += val + ",";
      });
      hours = hours.slice(0, -1);
      break;
    case "4":
      hours = state.hour.rangeStart + "-" + state.hour.rangeEnd;
      break;
  }
  return hours;
}
const daysText = () => {
  let days = "";
  let cronEvery = state.day.cronEvery;
  switch (cronEvery.toString()) {
    case "1":
      break;
    case "2":
    case "4":
    case "11":
    case "8":
      days = "?";
      break;
    case "3":
      days =
        state.day.incrementStart + "/" + state.day.incrementIncrement;
      break;
    case "5":
      state.day.specificSpecific.map((val) => {
        days += val + ",";
      });
      days = days.slice(0, -1);
      break;
    case "6":
      days = "L";
      break;
    case "7":
      days = "LW";
      break;
    case "9":
      days = "L-" + state.day.cronDaysBeforeEomMinus;
      break;
    case "10":
      days = state.day.cronDaysNearestWeekday + "W";
      break;
  }
  return days;
}
const weeksText = () => {
  let weeks = "";
  let cronEvery = state.day.cronEvery;
  switch (cronEvery.toString()) {
    case "1":
    case "3":
    case "5":
      weeks = "?";
      break;
    case "2":
      weeks =
        state.week.incrementStart + "/" + state.week.incrementIncrement;
      break;
    case "4":
      state.week.specificSpecific.map((val) => {
        weeks += val + ",";
      });
      weeks = weeks.slice(0, -1);
      break;
    case "6":
    case "7":
    case "9":
    case "10":
      weeks = "?";
      break;
    case "8":
      weeks = state.week.cronLastSpecificDomDay + "L";
      break;
    case "11":
      weeks = state.week.cronNthDayDay + "#" + state.week.cronNthDayNth;
      break;
  }
  return weeks;
}
const monthsText = () => {
  let months = "";
  let cronEvery = state.month.cronEvery;
  switch (cronEvery.toString()) {
    case "1":
      months = "*";
      break;
    case "2":
      months =
        state.month.incrementStart + "/" + state.month.incrementIncrement;
      break;
    case "3":
      state.month.specificSpecific.map((val) => {
        months += val + ",";
      });
      months = months.slice(0, -1);
      break;
    case "4":
      months = state.month.rangeStart + "-" + state.month.rangeEnd;
      break;
  }
  return months;
}
const yearsText = () => {
  let years = "";
  let cronEvery = state.year.cronEvery;
  switch (cronEvery.toString()) {
    case "1":
      years = "*";
      break;
    case "2":
      years =
        state.year.incrementStart + "/" + state.year.incrementIncrement;
      break;
    case "3":
      state.year.specificSpecific.map((val) => {
        years += val + ",";
      });
      years = years.slice(0, -1);
      break;
    case "4":
      years = state.year.rangeStart + "-" + state.year.rangeEnd;
      break;
  }
  return years;
}
const cron = () => {
  const str = `${secondsText() || "*"} ${minutesText() ||
    "*"} ${hoursText() || "*"} ${daysText() ||
    "*"} ${monthsText() || "*"} ${weeksText() ||
    "?"} ${yearsText() || "*"}`
  return str;
}

// 输出cron表达式
watch(
  () => [state.second, state.minute, state.hour, state.day, state.week, state.month, state.year],
  () => {
    const str = cron()
    emit('change', str)
  }, { deep: true }
)

// 回显
watch(() => props.cronValue, (newCron) => {
  if (typeof (newCron) !== 'string' || !newCron) return false
  let crons = newCron.split(" ");
  // 解析seconds
  let secondsText = crons[0].trim();
  if (secondsText === "*") {
    state.second.cronEvery = "1";
  } else if (secondsText.includes("/")) {
    state.second.cronEvery = "2";
    let secondsTexts = secondsText.split("/");
    state.second.incrementStart = parseInt(secondsTexts[0])
    state.second.incrementIncrement = parseInt(secondsTexts[1])
  } else if (secondsText.includes(",") || isFinite(secondsText)) {
    state.second.cronEvery = "3";
    state.second.specificSpecific = secondsText.split(",").map(item => parseInt(item));
  } else if (secondsText.includes("-")) {
    state.second.cronEvery = "4";
    let secondsTexts = secondsText.split("-");
    state.second.rangeStart = parseInt(secondsTexts[0])
    state.second.rangeEnd = parseInt(secondsTexts[1])
  }
  // 解析minutes
  let minutesText = crons[1].trim();
  if (minutesText === "*") {
    state.minute.cronEvery = "1";
  } else if (minutesText.includes("/")) {
    state.minute.cronEvery = "2";
    let minutesTexts = minutesText.split("/");
    state.minute.incrementStart = parseInt(minutesTexts[0])
    state.minute.incrementIncrement = parseInt(minutesTexts[1])
  } else if (minutesText.includes(",") || isFinite(minutesText)) {
    state.minute.cronEvery = "3";
    state.minute.specificSpecific = minutesText.split(",").map(item => parseInt(item));
  } else if (minutesText.includes("-")) {
    state.minute.cronEvery = "4";
    let minutesTexts = minutesText.split("-");
    state.minute.rangeStart = parseInt(minutesTexts[0])
    state.minute.rangeEnd = parseInt(minutesTexts[1])
  }
  // 解析hours
  let hoursText = crons[2].trim();
  if (hoursText === "*") {
    state.hour.cronEvery = "1";
  } else if (hoursText.includes("/")) {
    state.hour.cronEvery = "2";
    let hoursTexts = hoursText.split("/");
    state.hour.incrementStart = parseInt(hoursTexts[0])
    state.hour.incrementIncrement = parseInt(hoursTexts[1])
  } else if (hoursText.includes(",") || isFinite(hoursText)) {
    state.hour.cronEvery = "3";
    state.hour.specificSpecific = hoursText.split(",").map(item => parseInt(item));
  } else if (hoursText.includes("-")) {
    state.hour.cronEvery = "4";
    let hoursTexts = hoursText.split("-");
    state.hour.rangeStart = parseInt(hoursTexts[0])
    state.hour.rangeEnd = parseInt(hoursTexts[1])
  }
  // 解析days weeks
  let daysText = crons[3].trim();
  let weeksText = crons[5].trim();
  if (daysText.includes("/")) {
    state.day.cronEvery = "3";
    let daysTexts = daysText.split("/");
    state.day.incrementStart = parseInt(daysTexts[0])
    state.day.incrementIncrement = parseInt(daysTexts[1])
  } else if (daysText.includes(",") || isFinite(daysText)) {
    state.day.cronEvery = "5";
    state.day.specificSpecific = daysText.split(",").map(item => parseInt(item));
  } else if (daysText === "L") {
    state.day.cronEvery = "6";
  } else if (daysText === "LW") {
    state.day.cronEvery = "7";
  } else if (daysText.startsWith("L-")) {
    state.day.cronEvery = "9";
    state.day.cronDaysBeforeEomMinus = parseInt(daysText.replaceAll("L-", ""))
  } else if (daysText.endsWith("W")) {
    state.day.cronEvery = "10";
    state.day.cronDaysNearestWeekday = parseInt(daysText.replaceAll("W", ""))
  } else if (daysText === "?") {
    if (weeksText.includes("/")) {
      state.day.cronEvery = "2";
      let weeksTexts = weeksText.split("/");
      state.week.incrementStart = parseInt(weeksTexts[0])
      state.week.incrementIncrement = parseInt(weeksTexts[1])
    } else if (weeksText.includes(",") || isFinite(weeksText)) {
      state.day.cronEvery = "4";
      state.week.specificSpecific = weeksText.split(",").map(item => item);
    } else if (weeksText.includes("#")) {
      state.day.cronEvery = "11";
      let weeksTexts = weeksText.split("#");
      state.week.cronNthDayDay = parseInt(weeksTexts[0])
      state.week.cronNthDayNth = parseInt(weeksTexts[1])
    } else if (weeksText.endsWith("L")) {
      state.day.cronEvery = "8";
      state.week.cronLastSpecificDomDay = parseInt(weeksText.replaceAll("L", ""))
    }
  } else {
    state.day.cronEvery = "1";
  }

  // 解析months
  let monthsText = crons[4].trim();
  if (monthsText === "*") {
    state.month.cronEvery = "1";
  } else if (monthsText.includes("/")) {
    state.month.cronEvery = "2";
    let monthsTexts = monthsText.split("/");
    state.month.incrementStart = parseInt(monthsTexts[0])
    state.month.incrementIncrement = parseInt(monthsTexts[1])
  } else if (monthsText.includes(",") || isFinite(monthsText)) {
    state.month.cronEvery = "3";
    state.month.specificSpecific = monthsText.split(",").map(item => parseInt(item));
  } else if (monthsText.includes("-")) {
    state.month.cronEvery = "4";
    let monthsTexts = monthsText.split("-");
    state.month.rangeStart = parseInt(monthsTexts[0])
    state.month.rangeEnd = parseInt(monthsTexts[1])
  }
  // 解析years
  let yearsText = crons[6].trim();
  if (yearsText === "*") {
    state.year.cronEvery = "1";
  } else if (yearsText.includes("/")) {
    state.year.cronEvery = "2";
    let yearsTexts = yearsText.split("/");
    state.year.incrementStart = parseInt(yearsTexts[0])
    state.year.incrementIncrement = parseInt(yearsTexts[1])
  } else if (yearsText.includes(",") || isFinite(yearsText)) {
    state.year.cronEvery = "3";
    state.year.specificSpecific = yearsText.split(",").map(item => parseInt(item));
  } else if (yearsText.includes("-")) {
    state.year.cronEvery = "4";
    let yearsTexts = yearsText.split("-");
    state.year.rangeStart = parseInt(yearsTexts[0])
    state.year.rangeEnd = parseInt(yearsTexts[1])
  }

}, {
  immediate: true
})
const getValue = () => {
  return state.cron
}
const close = () => {
  emit('close')
}
const handleChange = () => {
  emit('change', state.cron)
  close()
}
const rest = (data) => {
  for (let i in data) {
    if (data[i] instanceof Object) {
      this.rest(data[i]);
    } else {
      switch (typeof data[i]) {
        case "object":
          data[i] = [];
          break;
        case "string":
          data[i] = "";
          break;
      }
    }
  }
}
</script>
  • App.vue
<template>
  <div>
    <el-input v-model="cronValue" style="margin-bottom: 14px;"></el-input>
    <TestComp :cronValue="cronValue" i18n="cn" @change="cronValue = $event"/>
  </div>
</template>

<script setup>
import TestComp from './TestComp/index.vue'
import { ref } from 'vue'
const cronValue = ref('3/6 * 1-0 2/1 4/5 ? 2019-2018')
</script>

<style lang="scss" scoped></style>

效果

Q.E.D.


一个二次元web开发咸鱼