72 changed files with 3042 additions and 3973 deletions
@ -1,4 +0,0 @@ |
|||||||
export { default as CronTab } from './src/CronTabInput.vue' |
|
||||||
export { default as CronTabInner } from './src/CronTabInner.vue' |
|
||||||
export { default as CronTabModal } from './src/CronTabModal.vue' |
|
||||||
export { default as CronValidator } from './src/validator' |
|
@ -1,360 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { computed, provide, reactive, ref, watch } from 'vue' |
|
||||||
import { Col, Divider, Input, Row, TabPane, Tabs, Textarea, Tooltip } from 'ant-design-vue' |
|
||||||
import CronParser from 'cron-parser' |
|
||||||
import SecondUI from './tabs/SecondUI.vue' |
|
||||||
import MinuteUI from './tabs/MinuteUI.vue' |
|
||||||
import HourUI from './tabs/HourUI.vue' |
|
||||||
import DayUI from './tabs/DayUI.vue' |
|
||||||
import MonthUI from './tabs/MonthUI.vue' |
|
||||||
import WeekUI from './tabs/WeekUI.vue' |
|
||||||
import YearUI from './tabs/YearUI.vue' |
|
||||||
import { cronEmits, cronProps } from './cron.data' |
|
||||||
import { useDesign } from '@/hooks/web/useDesign' |
|
||||||
import { dateFormat } from '@/utils/dateUtil' |
|
||||||
import { simpleDebounce } from '@/utils' |
|
||||||
|
|
||||||
const props = defineProps({ ...cronProps }) |
|
||||||
const emit = defineEmits([...cronEmits]) |
|
||||||
const { prefixCls } = useDesign('cron-inner') |
|
||||||
provide('prefixCls', prefixCls) |
|
||||||
const activeKey = ref(props.hideSecond ? 'minute' : 'second') |
|
||||||
const second = ref('*') |
|
||||||
const minute = ref('*') |
|
||||||
const hour = ref('*') |
|
||||||
const day = ref('*') |
|
||||||
const month = ref('*') |
|
||||||
const week = ref('?') |
|
||||||
const year = ref('*') |
|
||||||
const inputValues = reactive({ |
|
||||||
second: '', |
|
||||||
minute: '', |
|
||||||
hour: '', |
|
||||||
day: '', |
|
||||||
month: '', |
|
||||||
week: '', |
|
||||||
year: '', |
|
||||||
cron: '', |
|
||||||
}) |
|
||||||
const preTimeList = ref('执行预览,会忽略年份参数。') |
|
||||||
|
|
||||||
// cron表达式 |
|
||||||
const cronValueInner = computed(() => { |
|
||||||
const result: string[] = [] |
|
||||||
if (!props.hideSecond) |
|
||||||
result.push(second.value ? second.value : '*') |
|
||||||
|
|
||||||
result.push(minute.value ? minute.value : '*') |
|
||||||
result.push(hour.value ? hour.value : '*') |
|
||||||
result.push(day.value ? day.value : '*') |
|
||||||
result.push(month.value ? month.value : '*') |
|
||||||
result.push(week.value ? week.value : '?') |
|
||||||
if (!props.hideYear && !props.hideSecond) |
|
||||||
result.push(year.value ? year.value : '*') |
|
||||||
return result.join(' ') |
|
||||||
}) |
|
||||||
// 不含年 |
|
||||||
const cronValueNoYear = computed(() => { |
|
||||||
const v = cronValueInner.value |
|
||||||
if (props.hideYear || props.hideSecond) |
|
||||||
return v |
|
||||||
const vs = v.split(' ') |
|
||||||
if (vs.length >= 6) { |
|
||||||
// 转成 Quartz 的规则 |
|
||||||
vs[5] = convertWeekToQuartz(vs[5]) |
|
||||||
} |
|
||||||
return vs.slice(0, vs.length - 1).join(' ') |
|
||||||
}) |
|
||||||
const calTriggerList = simpleDebounce(calTriggerListInner, 500) |
|
||||||
|
|
||||||
watch( |
|
||||||
() => props.value, |
|
||||||
(newVal) => { |
|
||||||
if (newVal === cronValueInner.value) |
|
||||||
return |
|
||||||
|
|
||||||
formatValue() |
|
||||||
}, |
|
||||||
) |
|
||||||
|
|
||||||
watch(cronValueInner, (newValue) => { |
|
||||||
calTriggerList() |
|
||||||
emitValue(newValue) |
|
||||||
assignInput() |
|
||||||
}) |
|
||||||
|
|
||||||
assignInput() |
|
||||||
formatValue() |
|
||||||
calTriggerListInner() |
|
||||||
|
|
||||||
function assignInput() { |
|
||||||
inputValues.second = second.value |
|
||||||
inputValues.minute = minute.value |
|
||||||
inputValues.hour = hour.value |
|
||||||
inputValues.day = day.value |
|
||||||
inputValues.month = month.value |
|
||||||
inputValues.week = week.value |
|
||||||
inputValues.year = year.value |
|
||||||
inputValues.cron = cronValueInner.value |
|
||||||
} |
|
||||||
|
|
||||||
function formatValue() { |
|
||||||
if (!props.value) |
|
||||||
return |
|
||||||
const values = props.value.split(' ').filter(item => !!item) |
|
||||||
if (!values || values.length <= 0) |
|
||||||
return |
|
||||||
let i = 0 |
|
||||||
if (!props.hideSecond) |
|
||||||
second.value = values[i++] |
|
||||||
if (values.length > i) |
|
||||||
minute.value = values[i++] |
|
||||||
if (values.length > i) |
|
||||||
hour.value = values[i++] |
|
||||||
if (values.length > i) |
|
||||||
day.value = values[i++] |
|
||||||
if (values.length > i) |
|
||||||
month.value = values[i++] |
|
||||||
if (values.length > i) |
|
||||||
week.value = values[i++] |
|
||||||
if (values.length > i) |
|
||||||
year.value = values[i] |
|
||||||
assignInput() |
|
||||||
} |
|
||||||
|
|
||||||
// Quartz 的规则: |
|
||||||
// 1 = 周日,2 = 周一,3 = 周二,4 = 周三,5 = 周四,6 = 周五,7 = 周六 |
|
||||||
function convertWeekToQuartz(week: string) { |
|
||||||
const convert = (v: string) => { |
|
||||||
if (v === '0') |
|
||||||
return '1' |
|
||||||
|
|
||||||
if (v === '1') |
|
||||||
return '0' |
|
||||||
|
|
||||||
return (Number.parseInt(v) - 1).toString() |
|
||||||
} |
|
||||||
// 匹配示例 1-7 or 1/7 |
|
||||||
const patten1 = /^([0-7])([-/])([0-7])$/ |
|
||||||
// 匹配示例 1,4,7 |
|
||||||
const patten2 = /^([0-7])(,[0-7])+$/ |
|
||||||
if (/^[0-7]$/.test(week)) { |
|
||||||
return convert(week) |
|
||||||
} |
|
||||||
else if (patten1.test(week)) { |
|
||||||
return week.replace(patten1, (_$0, before, separator, after) => { |
|
||||||
if (separator === '/') |
|
||||||
return convert(before) + separator + after |
|
||||||
else |
|
||||||
return convert(before) + separator + convert(after) |
|
||||||
}) |
|
||||||
} |
|
||||||
else if (patten2.test(week)) { |
|
||||||
return week |
|
||||||
.split(',') |
|
||||||
.map(v => convert(v)) |
|
||||||
.join(',') |
|
||||||
} |
|
||||||
return week |
|
||||||
} |
|
||||||
|
|
||||||
function calTriggerListInner() { |
|
||||||
// 设置了回调函数 |
|
||||||
if (props.remote) { |
|
||||||
props.remote(cronValueInner.value, +new Date(), (v) => { |
|
||||||
preTimeList.value = v |
|
||||||
}) |
|
||||||
return |
|
||||||
} |
|
||||||
const format = 'yyyy-MM-dd hh:mm:ss' |
|
||||||
const options = { |
|
||||||
currentDate: dateFormat(new Date(), format), |
|
||||||
} |
|
||||||
const iter = CronParser.parseExpression(cronValueNoYear.value, options) |
|
||||||
const result: string[] = [] |
|
||||||
for (let i = 1; i <= 10; i++) |
|
||||||
result.push(dateFormat(new Date(iter.next() as any), format)) |
|
||||||
|
|
||||||
preTimeList.value = result.length > 0 ? result.join('\n') : '无执行时间' |
|
||||||
} |
|
||||||
|
|
||||||
function onInputBlur() { |
|
||||||
second.value = inputValues.second |
|
||||||
minute.value = inputValues.minute |
|
||||||
hour.value = inputValues.hour |
|
||||||
day.value = inputValues.day |
|
||||||
month.value = inputValues.month |
|
||||||
week.value = inputValues.week |
|
||||||
year.value = inputValues.year |
|
||||||
} |
|
||||||
|
|
||||||
function onInputCronBlur(event) { |
|
||||||
emitValue(event.target.value) |
|
||||||
} |
|
||||||
|
|
||||||
function emitValue(value) { |
|
||||||
emit('change', value) |
|
||||||
emit('update:value', value) |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div :class="`${prefixCls}`"> |
|
||||||
<div class="content"> |
|
||||||
<Tabs v-model:activeKey="activeKey" size="small"> |
|
||||||
<TabPane v-if="!hideSecond" key="second" tab="秒"> |
|
||||||
<SecondUI v-model:value="second" :disabled="disabled" /> |
|
||||||
</TabPane> |
|
||||||
<TabPane key="minute" tab="分"> |
|
||||||
<MinuteUI v-model:value="minute" :disabled="disabled" /> |
|
||||||
</TabPane> |
|
||||||
<TabPane key="hour" tab="时"> |
|
||||||
<HourUI v-model:value="hour" :disabled="disabled" /> |
|
||||||
</TabPane> |
|
||||||
<TabPane key="day" tab="日"> |
|
||||||
<DayUI v-model:value="day" :week="week" :disabled="disabled" /> |
|
||||||
</TabPane> |
|
||||||
<TabPane key="month" tab="月"> |
|
||||||
<MonthUI v-model:value="month" :disabled="disabled" /> |
|
||||||
</TabPane> |
|
||||||
<TabPane key="week" tab="周"> |
|
||||||
<WeekUI v-model:value="week" :day="day" :disabled="disabled" /> |
|
||||||
</TabPane> |
|
||||||
<TabPane v-if="!hideYear && !hideSecond" key="year" tab="年"> |
|
||||||
<YearUI v-model:value="year" :disabled="disabled" /> |
|
||||||
</TabPane> |
|
||||||
</Tabs> |
|
||||||
<Divider /> |
|
||||||
<!-- 执行时间预览 --> |
|
||||||
<Row :gutter="8"> |
|
||||||
<Col :span="18" style="margin-top: 22px"> |
|
||||||
<Row :gutter="8"> |
|
||||||
<Col :span="8" style="margin-bottom: 12px"> |
|
||||||
<Input v-model:value="inputValues.second" @blur="onInputBlur"> |
|
||||||
<template #addonBefore> |
|
||||||
<span class="allow-click" @click="activeKey = 'second'">秒</span> |
|
||||||
</template> |
|
||||||
</Input> |
|
||||||
</Col> |
|
||||||
<Col :span="8" style="margin-bottom: 12px"> |
|
||||||
<Input v-model:value="inputValues.minute" @blur="onInputBlur"> |
|
||||||
<template #addonBefore> |
|
||||||
<span class="allow-click" @click="activeKey = 'minute'">分</span> |
|
||||||
</template> |
|
||||||
</Input> |
|
||||||
</Col> |
|
||||||
<Col :span="8" style="margin-bottom: 12px"> |
|
||||||
<Input v-model:value="inputValues.hour" @blur="onInputBlur"> |
|
||||||
<template #addonBefore> |
|
||||||
<span class="allow-click" @click="activeKey = 'hour'">时</span> |
|
||||||
</template> |
|
||||||
</Input> |
|
||||||
</Col> |
|
||||||
<Col :span="8" style="margin-bottom: 12px"> |
|
||||||
<Input v-model:value="inputValues.day" @blur="onInputBlur"> |
|
||||||
<template #addonBefore> |
|
||||||
<span class="allow-click" @click="activeKey = 'day'">日</span> |
|
||||||
</template> |
|
||||||
</Input> |
|
||||||
</Col> |
|
||||||
<Col :span="8" style="margin-bottom: 12px"> |
|
||||||
<Input v-model:value="inputValues.month" @blur="onInputBlur"> |
|
||||||
<template #addonBefore> |
|
||||||
<span class="allow-click" @click="activeKey = 'month'">月</span> |
|
||||||
</template> |
|
||||||
</Input> |
|
||||||
</Col> |
|
||||||
<Col :span="8" style="margin-bottom: 12px"> |
|
||||||
<Input v-model:value="inputValues.week" @blur="onInputBlur"> |
|
||||||
<template #addonBefore> |
|
||||||
<span class="allow-click" @click="activeKey = 'week'">周</span> |
|
||||||
</template> |
|
||||||
</Input> |
|
||||||
</Col> |
|
||||||
<Col :span="8"> |
|
||||||
<Input v-model:value="inputValues.year" @blur="onInputBlur"> |
|
||||||
<template #addonBefore> |
|
||||||
<span class="allow-click" @click="activeKey = 'year'">年</span> |
|
||||||
</template> |
|
||||||
</Input> |
|
||||||
</Col> |
|
||||||
<Col :span="16"> |
|
||||||
<Input v-model:value="inputValues.cron" @blur="onInputCronBlur"> |
|
||||||
<template #addonBefore> |
|
||||||
<Tooltip title="Cron表达式"> |
|
||||||
式 |
|
||||||
</Tooltip> |
|
||||||
</template> |
|
||||||
</Input> |
|
||||||
</Col> |
|
||||||
</Row> |
|
||||||
</Col> |
|
||||||
<Col :span="6"> |
|
||||||
<div>近十次执行时间(不含年)</div> |
|
||||||
<Textarea :value="preTimeList" :rows="5" /> |
|
||||||
</Col> |
|
||||||
</Row> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</template> |
|
||||||
|
|
||||||
<style lang="less"> |
|
||||||
@prefix-cls: ~'@{namespace}-cron-inner'; |
|
||||||
|
|
||||||
.@{prefix-cls} { |
|
||||||
.content { |
|
||||||
.ant-checkbox-wrapper + .ant-checkbox-wrapper { |
|
||||||
margin-left: 0; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
&-config-list { |
|
||||||
margin: 0 10px 10px; |
|
||||||
text-align: left; |
|
||||||
|
|
||||||
.item { |
|
||||||
margin-top: 5px; |
|
||||||
font-size: 14px; |
|
||||||
|
|
||||||
span { |
|
||||||
padding: 0 2px; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
.choice { |
|
||||||
padding: 5px 8px; |
|
||||||
} |
|
||||||
|
|
||||||
.w60 { |
|
||||||
width: 60px; |
|
||||||
min-width: 60px; |
|
||||||
} |
|
||||||
|
|
||||||
.w80 { |
|
||||||
width: 80px; |
|
||||||
min-width: 80px; |
|
||||||
} |
|
||||||
|
|
||||||
.list { |
|
||||||
margin: 0 20px; |
|
||||||
} |
|
||||||
|
|
||||||
.list-check-item { |
|
||||||
width: 4em; |
|
||||||
padding: 1px 3px; |
|
||||||
} |
|
||||||
|
|
||||||
.list-cn .list-check-item { |
|
||||||
width: 5em; |
|
||||||
} |
|
||||||
|
|
||||||
.tip-info { |
|
||||||
color: #999; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
.allow-click { |
|
||||||
cursor: pointer; |
|
||||||
} |
|
||||||
} |
|
||||||
</style> |
|
@ -1,55 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { ref, watch } from 'vue' |
|
||||||
import { Input } from 'ant-design-vue' |
|
||||||
import CronTabModal from './CronTabModal.vue' |
|
||||||
import { cronEmits, cronProps } from './cron.data' |
|
||||||
import { useModal } from '@/components/Modal' |
|
||||||
import { propTypes } from '@/utils/propTypes' |
|
||||||
|
|
||||||
const props = defineProps({ |
|
||||||
...cronProps, |
|
||||||
placeholder: propTypes.string.def('请输入cron表达式'), |
|
||||||
exeStartTime: propTypes.oneOfType([propTypes.number, propTypes.string, propTypes.object]).def(0), |
|
||||||
}) |
|
||||||
const emit = defineEmits([...cronEmits]) |
|
||||||
const [registerModal, { openModal }] = useModal() |
|
||||||
const editCronValue = ref(props.value) |
|
||||||
|
|
||||||
watch( |
|
||||||
() => props.value, |
|
||||||
(newVal) => { |
|
||||||
if (newVal !== editCronValue.value) |
|
||||||
editCronValue.value = newVal |
|
||||||
}, |
|
||||||
) |
|
||||||
watch(editCronValue, (newVal) => { |
|
||||||
emit('change', newVal) |
|
||||||
emit('update:value', newVal) |
|
||||||
}) |
|
||||||
|
|
||||||
function showConfigModal() { |
|
||||||
if (!props.disabled) |
|
||||||
openModal() |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<Input v-model:value="editCronValue" :placeholder="placeholder" :disabled="disabled"> |
|
||||||
<template #addonAfter> |
|
||||||
<a class="cursor-pointer" :disabled="disabled ? 'disabled' : null" @click="showConfigModal"> |
|
||||||
<span class="i-ant-design:setting-outlined relative right-0.5 top-0.25" /> |
|
||||||
<span>选择</span> |
|
||||||
</a> |
|
||||||
</template> |
|
||||||
</Input> |
|
||||||
<CronTabModal |
|
||||||
v-model:value="editCronValue" |
|
||||||
:exe-start-time="exeStartTime" |
|
||||||
:hide-year="hideYear" |
|
||||||
:remote="remote" |
|
||||||
:hide-second="hideSecond" |
|
||||||
@register="registerModal" |
|
||||||
/> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,18 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import CronTab from './CronTabInner.vue' |
|
||||||
import { BasicModal, useModalInner } from '@/components/Modal' |
|
||||||
|
|
||||||
defineOptions({ name: 'CronTabModal', inheritAttrs: false }) |
|
||||||
|
|
||||||
const [registerModal, { closeModal }] = useModalInner() |
|
||||||
|
|
||||||
function onOk() { |
|
||||||
closeModal() |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<BasicModal title="Cron表达式" width="800px" @register="registerModal" @ok="onOk"> |
|
||||||
<CronTab v-bind="$attrs" /> |
|
||||||
</BasicModal> |
|
||||||
</template> |
|
@ -1,10 +0,0 @@ |
|||||||
import { propTypes } from '@/utils/propTypes' |
|
||||||
|
|
||||||
export const cronEmits = ['change', 'update:value'] |
|
||||||
export const cronProps = { |
|
||||||
value: propTypes.string.def(''), |
|
||||||
disabled: propTypes.bool.def(false), |
|
||||||
hideSecond: propTypes.bool.def(false), |
|
||||||
hideYear: propTypes.bool.def(false), |
|
||||||
remote: propTypes.func, |
|
||||||
} |
|
@ -1,101 +0,0 @@ |
|||||||
<script lang="ts"> |
|
||||||
import { computed, defineComponent, watch } from 'vue' |
|
||||||
import { Checkbox, Input, Radio } from 'ant-design-vue' |
|
||||||
import { TypeEnum, useTabEmits, useTabProps, useTabSetup } from './useTabMixin' |
|
||||||
|
|
||||||
export default defineComponent({ |
|
||||||
name: 'DayUI', |
|
||||||
components: { AInput: Input, Checkbox, CheckboxGroup: Checkbox.Group, Radio, RadioGroup: Radio.Group }, |
|
||||||
props: useTabProps({ |
|
||||||
defaultValue: '*', |
|
||||||
props: { |
|
||||||
week: { type: String, default: '?' }, |
|
||||||
}, |
|
||||||
}), |
|
||||||
emits: useTabEmits(), |
|
||||||
setup(props, context) { |
|
||||||
const disabledChoice = computed(() => { |
|
||||||
return (props.week && props.week !== '?') || props.disabled |
|
||||||
}) |
|
||||||
const setup = useTabSetup(props, context, { |
|
||||||
defaultValue: '*', |
|
||||||
valueWork: 1, |
|
||||||
minValue: 1, |
|
||||||
maxValue: 31, |
|
||||||
valueRange: { start: 1, end: 31 }, |
|
||||||
valueLoop: { start: 1, interval: 1 }, |
|
||||||
disabled: disabledChoice, |
|
||||||
}) |
|
||||||
const typeWorkAttrs = computed(() => ({ |
|
||||||
disabled: setup.type.value !== TypeEnum.work || props.disabled || disabledChoice.value, |
|
||||||
...setup.inputNumberAttrs.value, |
|
||||||
})) |
|
||||||
|
|
||||||
watch( |
|
||||||
() => props.week, |
|
||||||
() => { |
|
||||||
setup.updateValue(disabledChoice.value ? '?' : setup.computeValue.value) |
|
||||||
}, |
|
||||||
) |
|
||||||
|
|
||||||
return { ...setup, typeWorkAttrs } |
|
||||||
}, |
|
||||||
}) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div :class="`${prefixCls}-config-list`"> |
|
||||||
<RadioGroup v-model:value="type"> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.unset" v-bind="beforeRadioAttrs"> |
|
||||||
不设置 |
|
||||||
</Radio> |
|
||||||
<span class="tip-info">日和周只能设置其中之一</span> |
|
||||||
</div> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.every" v-bind="beforeRadioAttrs"> |
|
||||||
每日 |
|
||||||
</Radio> |
|
||||||
</div> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.range" v-bind="beforeRadioAttrs"> |
|
||||||
区间 |
|
||||||
</Radio> |
|
||||||
<span> 从 </span> |
|
||||||
<AInput v-model:value="valueRange.start" type="number" v-bind="typeRangeAttrs" /> |
|
||||||
<span> 日 至 </span> |
|
||||||
<AInput v-model:value="valueRange.end" type="number" v-bind="typeRangeAttrs" /> |
|
||||||
<span> 日 </span> |
|
||||||
</div> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.loop" v-bind="beforeRadioAttrs"> |
|
||||||
循环 |
|
||||||
</Radio> |
|
||||||
<span> 从 </span> |
|
||||||
<AInput v-model:value="valueLoop.start" type="number" class="w-4" v-bind="typeLoopAttrs" /> |
|
||||||
<span> 日开始,间隔 </span> |
|
||||||
<AInput v-model:value="valueLoop.interval" type="number" v-bind="typeLoopAttrs" /> |
|
||||||
<span> 日 </span> |
|
||||||
</div> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.last" v-bind="beforeRadioAttrs"> |
|
||||||
最后一日 |
|
||||||
</Radio> |
|
||||||
</div> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.specify" v-bind="beforeRadioAttrs"> |
|
||||||
指定 |
|
||||||
</Radio> |
|
||||||
<div class="list"> |
|
||||||
<CheckboxGroup v-model:value="valueList"> |
|
||||||
<template v-for="i in specifyRange" :key="i"> |
|
||||||
<Checkbox :value="i" v-bind="typeSpecifyAttrs"> |
|
||||||
{{ i }} |
|
||||||
</Checkbox> |
|
||||||
</template> |
|
||||||
</CheckboxGroup> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</RadioGroup> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,69 +0,0 @@ |
|||||||
<script lang="ts"> |
|
||||||
import { defineComponent } from 'vue' |
|
||||||
import { Checkbox, Input, Radio } from 'ant-design-vue' |
|
||||||
import { useTabEmits, useTabProps, useTabSetup } from './useTabMixin' |
|
||||||
|
|
||||||
export default defineComponent({ |
|
||||||
name: 'HourUI', |
|
||||||
components: { AInput: Input, Checkbox, CheckboxGroup: Checkbox.Group, Radio, RadioGroup: Radio.Group }, |
|
||||||
props: useTabProps({ |
|
||||||
defaultValue: '*', |
|
||||||
}), |
|
||||||
emits: useTabEmits(), |
|
||||||
setup(props, context) { |
|
||||||
return useTabSetup(props, context, { |
|
||||||
defaultValue: '*', |
|
||||||
minValue: 0, |
|
||||||
maxValue: 23, |
|
||||||
valueRange: { start: 0, end: 23 }, |
|
||||||
valueLoop: { start: 0, interval: 1 }, |
|
||||||
}) |
|
||||||
}, |
|
||||||
}) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div :class="`${prefixCls}-config-list`"> |
|
||||||
<RadioGroup v-model:value="type"> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.every" v-bind="beforeRadioAttrs"> |
|
||||||
每时 |
|
||||||
</Radio> |
|
||||||
</div> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.range" v-bind="beforeRadioAttrs"> |
|
||||||
区间 |
|
||||||
</Radio> |
|
||||||
<span> 从 </span> |
|
||||||
<AInput v-model:value="valueRange.start" type="number" v-bind="typeRangeAttrs" /> |
|
||||||
<span> 时 至 </span> |
|
||||||
<AInput v-model:value="valueRange.end" type="number" v-bind="typeRangeAttrs" /> |
|
||||||
<span> 时 </span> |
|
||||||
</div> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.loop" v-bind="beforeRadioAttrs"> |
|
||||||
循环 |
|
||||||
</Radio> |
|
||||||
<span> 从 </span> |
|
||||||
<AInput v-model:value="valueLoop.start" type="number" v-bind="typeLoopAttrs" /> |
|
||||||
<span> 时开始,间隔 </span> |
|
||||||
<AInput v-model:value="valueLoop.interval" type="number" v-bind="typeLoopAttrs" /> |
|
||||||
<span> 时 </span> |
|
||||||
</div> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.specify" v-bind="beforeRadioAttrs"> |
|
||||||
指定 |
|
||||||
</Radio> |
|
||||||
<div class="list"> |
|
||||||
<CheckboxGroup v-model:value="valueList"> |
|
||||||
<template v-for="i in specifyRange" :key="i"> |
|
||||||
<Checkbox :value="i" v-bind="typeSpecifyAttrs"> |
|
||||||
{{ i }} |
|
||||||
</Checkbox> |
|
||||||
</template> |
|
||||||
</CheckboxGroup> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</RadioGroup> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,69 +0,0 @@ |
|||||||
<script lang="ts"> |
|
||||||
import { defineComponent } from 'vue' |
|
||||||
import { Checkbox, Input, Radio } from 'ant-design-vue' |
|
||||||
import { useTabEmits, useTabProps, useTabSetup } from './useTabMixin' |
|
||||||
|
|
||||||
export default defineComponent({ |
|
||||||
name: 'MinuteUI', |
|
||||||
components: { AInput: Input, Checkbox, CheckboxGroup: Checkbox.Group, Radio, RadioGroup: Radio.Group }, |
|
||||||
props: useTabProps({ |
|
||||||
defaultValue: '*', |
|
||||||
}), |
|
||||||
emits: useTabEmits(), |
|
||||||
setup(props, context) { |
|
||||||
return useTabSetup(props, context, { |
|
||||||
defaultValue: '*', |
|
||||||
minValue: 0, |
|
||||||
maxValue: 59, |
|
||||||
valueRange: { start: 0, end: 59 }, |
|
||||||
valueLoop: { start: 0, interval: 1 }, |
|
||||||
}) |
|
||||||
}, |
|
||||||
}) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div :class="`${prefixCls}-config-list`"> |
|
||||||
<RadioGroup v-model:value="type"> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.every" v-bind="beforeRadioAttrs"> |
|
||||||
每分 |
|
||||||
</Radio> |
|
||||||
</div> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.range" v-bind="beforeRadioAttrs"> |
|
||||||
区间 |
|
||||||
</Radio> |
|
||||||
<span> 从 </span> |
|
||||||
<AInput v-model:value="valueRange.start" type="number" v-bind="typeRangeAttrs" /> |
|
||||||
<span> 分 至 </span> |
|
||||||
<AInput v-model:value="valueRange.end" type="number" v-bind="typeRangeAttrs" /> |
|
||||||
<span> 分 </span> |
|
||||||
</div> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.loop" v-bind="beforeRadioAttrs"> |
|
||||||
循环 |
|
||||||
</Radio> |
|
||||||
<span> 从 </span> |
|
||||||
<AInput v-model:value="valueLoop.start" type="number" v-bind="typeLoopAttrs" /> |
|
||||||
<span> 分开始,间隔 </span> |
|
||||||
<AInput v-model:value="valueLoop.interval" type="number" v-bind="typeLoopAttrs" /> |
|
||||||
<span> 分 </span> |
|
||||||
</div> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.specify" v-bind="beforeRadioAttrs"> |
|
||||||
指定 |
|
||||||
</Radio> |
|
||||||
<div class="list"> |
|
||||||
<CheckboxGroup v-model:value="valueList"> |
|
||||||
<template v-for="i in specifyRange" :key="i"> |
|
||||||
<Checkbox :value="i" v-bind="typeSpecifyAttrs"> |
|
||||||
{{ i }} |
|
||||||
</Checkbox> |
|
||||||
</template> |
|
||||||
</CheckboxGroup> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</RadioGroup> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,69 +0,0 @@ |
|||||||
<script lang="ts"> |
|
||||||
import { defineComponent } from 'vue' |
|
||||||
import { Checkbox, Input, Radio } from 'ant-design-vue' |
|
||||||
import { useTabEmits, useTabProps, useTabSetup } from './useTabMixin' |
|
||||||
|
|
||||||
export default defineComponent({ |
|
||||||
name: 'MonthUI', |
|
||||||
components: { AInput: Input, Checkbox, CheckboxGroup: Checkbox.Group, Radio, RadioGroup: Radio.Group }, |
|
||||||
props: useTabProps({ |
|
||||||
defaultValue: '*', |
|
||||||
}), |
|
||||||
emits: useTabEmits(), |
|
||||||
setup(props, context) { |
|
||||||
return useTabSetup(props, context, { |
|
||||||
defaultValue: '*', |
|
||||||
minValue: 1, |
|
||||||
maxValue: 12, |
|
||||||
valueRange: { start: 1, end: 12 }, |
|
||||||
valueLoop: { start: 1, interval: 1 }, |
|
||||||
}) |
|
||||||
}, |
|
||||||
}) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div :class="`${prefixCls}-config-list`"> |
|
||||||
<RadioGroup v-model:value="type"> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.every" v-bind="beforeRadioAttrs"> |
|
||||||
每月 |
|
||||||
</Radio> |
|
||||||
</div> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.range" v-bind="beforeRadioAttrs"> |
|
||||||
区间 |
|
||||||
</Radio> |
|
||||||
<span> 从 </span> |
|
||||||
<AInput v-model:value="valueRange.start" type="number" v-bind="typeRangeAttrs" /> |
|
||||||
<span> 月 至 </span> |
|
||||||
<AInput v-model:value="valueRange.end" type="number" v-bind="typeRangeAttrs" /> |
|
||||||
<span> 月 </span> |
|
||||||
</div> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.loop" v-bind="beforeRadioAttrs"> |
|
||||||
循环 |
|
||||||
</Radio> |
|
||||||
<span> 从 </span> |
|
||||||
<AInput v-model:value="valueLoop.start" type="number" v-bind="typeLoopAttrs" /> |
|
||||||
<span> 月开始,间隔 </span> |
|
||||||
<AInput v-model:value="valueLoop.interval" type="number" v-bind="typeLoopAttrs" /> |
|
||||||
<span> 月 </span> |
|
||||||
</div> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.specify" v-bind="beforeRadioAttrs"> |
|
||||||
指定 |
|
||||||
</Radio> |
|
||||||
<div class="list"> |
|
||||||
<CheckboxGroup v-model:value="valueList"> |
|
||||||
<template v-for="i in specifyRange" :key="i"> |
|
||||||
<Checkbox :value="i" v-bind="typeSpecifyAttrs"> |
|
||||||
{{ i }} |
|
||||||
</Checkbox> |
|
||||||
</template> |
|
||||||
</CheckboxGroup> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</RadioGroup> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,69 +0,0 @@ |
|||||||
<script lang="ts"> |
|
||||||
import { defineComponent } from 'vue' |
|
||||||
import { Checkbox, Input, Radio } from 'ant-design-vue' |
|
||||||
import { useTabEmits, useTabProps, useTabSetup } from './useTabMixin' |
|
||||||
|
|
||||||
export default defineComponent({ |
|
||||||
name: 'SecondUI', |
|
||||||
components: { AInput: Input, Checkbox, CheckboxGroup: Checkbox.Group, Radio, RadioGroup: Radio.Group }, |
|
||||||
props: useTabProps({ |
|
||||||
defaultValue: '*', |
|
||||||
}), |
|
||||||
emits: useTabEmits(), |
|
||||||
setup(props, context) { |
|
||||||
return useTabSetup(props, context, { |
|
||||||
defaultValue: '*', |
|
||||||
minValue: 0, |
|
||||||
maxValue: 59, |
|
||||||
valueRange: { start: 0, end: 59 }, |
|
||||||
valueLoop: { start: 0, interval: 1 }, |
|
||||||
}) |
|
||||||
}, |
|
||||||
}) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div :class="`${prefixCls}-config-list`"> |
|
||||||
<RadioGroup v-model:value="type"> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.every" v-bind="beforeRadioAttrs"> |
|
||||||
每秒 |
|
||||||
</Radio> |
|
||||||
</div> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.range" v-bind="beforeRadioAttrs"> |
|
||||||
区间 |
|
||||||
</Radio> |
|
||||||
<span> 从 </span> |
|
||||||
<AInput v-model:value="valueRange.start" type="number" v-bind="typeRangeAttrs" /> |
|
||||||
<span> 秒 至 </span> |
|
||||||
<AInput v-model:value="valueRange.end" type="number" v-bind="typeRangeAttrs" /> |
|
||||||
<span> 秒 </span> |
|
||||||
</div> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.loop" v-bind="beforeRadioAttrs"> |
|
||||||
循环 |
|
||||||
</Radio> |
|
||||||
<span> 从 </span> |
|
||||||
<AInput v-model:value="valueLoop.start" type="number" v-bind="typeLoopAttrs" /> |
|
||||||
<span> 秒开始,间隔 </span> |
|
||||||
<AInput v-model:value="valueLoop.interval" type="number" v-bind="typeLoopAttrs" /> |
|
||||||
<span> 秒 </span> |
|
||||||
</div> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.specify" v-bind="beforeRadioAttrs"> |
|
||||||
指定 |
|
||||||
</Radio> |
|
||||||
<div class="list"> |
|
||||||
<CheckboxGroup v-model:value="valueList"> |
|
||||||
<template v-for="i in specifyRange" :key="i"> |
|
||||||
<Checkbox :value="i" v-bind="typeSpecifyAttrs"> |
|
||||||
{{ i }} |
|
||||||
</Checkbox> |
|
||||||
</template> |
|
||||||
</CheckboxGroup> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</RadioGroup> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,135 +0,0 @@ |
|||||||
<script lang="ts"> |
|
||||||
import { computed, defineComponent, watch } from 'vue' |
|
||||||
import { Checkbox, Input, Radio, Select } from 'ant-design-vue' |
|
||||||
import { TypeEnum, useTabEmits, useTabProps, useTabSetup } from './useTabMixin' |
|
||||||
|
|
||||||
const WEEK_MAP_EN = { |
|
||||||
1: 'SUN', |
|
||||||
2: 'MON', |
|
||||||
3: 'TUE', |
|
||||||
4: 'WED', |
|
||||||
5: 'THU', |
|
||||||
6: 'FRI', |
|
||||||
7: 'SAT', |
|
||||||
} |
|
||||||
|
|
||||||
const WEEK_MAP_CN = { |
|
||||||
1: '周日', |
|
||||||
2: '周一', |
|
||||||
3: '周二', |
|
||||||
4: '周三', |
|
||||||
5: '周四', |
|
||||||
6: '周五', |
|
||||||
7: '周六', |
|
||||||
} |
|
||||||
|
|
||||||
export default defineComponent({ |
|
||||||
name: 'WeekUI', |
|
||||||
components: { AInput: Input, ASelect: Select, Checkbox, CheckboxGroup: Checkbox.Group, Radio, RadioGroup: Radio.Group }, |
|
||||||
props: useTabProps({ |
|
||||||
defaultValue: '?', |
|
||||||
props: { |
|
||||||
day: { type: String, default: '*' }, |
|
||||||
}, |
|
||||||
}), |
|
||||||
emits: useTabEmits(), |
|
||||||
setup(props, context) { |
|
||||||
const disabledChoice = computed(() => { |
|
||||||
return (props.day && props.day !== '?') || props.disabled |
|
||||||
}) |
|
||||||
const setup = useTabSetup(props, context, { |
|
||||||
defaultType: TypeEnum.unset, |
|
||||||
defaultValue: '?', |
|
||||||
minValue: 1, |
|
||||||
maxValue: 7, |
|
||||||
// 0,7表示周日 1表示周一 |
|
||||||
valueRange: { start: 1, end: 7 }, |
|
||||||
valueLoop: { start: 2, interval: 1 }, |
|
||||||
disabled: disabledChoice, |
|
||||||
}) |
|
||||||
const weekOptions = computed(() => { |
|
||||||
const options: { label: string, value: number }[] = [] |
|
||||||
for (const weekKey of Object.keys(WEEK_MAP_CN)) { |
|
||||||
const weekName: string = WEEK_MAP_CN[weekKey] |
|
||||||
options.push({ |
|
||||||
value: Number.parseInt(weekKey), |
|
||||||
label: weekName, |
|
||||||
}) |
|
||||||
} |
|
||||||
return options |
|
||||||
}) |
|
||||||
|
|
||||||
const typeRangeSelectAttrs = computed(() => ({ |
|
||||||
class: ['w80'], |
|
||||||
disabled: setup.typeRangeAttrs.value.disabled, |
|
||||||
})) |
|
||||||
|
|
||||||
const typeLoopSelectAttrs = computed(() => ({ |
|
||||||
class: ['w80'], |
|
||||||
disabled: setup.typeLoopAttrs.value.disabled, |
|
||||||
})) |
|
||||||
|
|
||||||
watch( |
|
||||||
() => props.day, |
|
||||||
() => { |
|
||||||
setup.updateValue(disabledChoice.value ? '?' : setup.computeValue.value) |
|
||||||
}, |
|
||||||
) |
|
||||||
|
|
||||||
return { |
|
||||||
...setup, |
|
||||||
weekOptions, |
|
||||||
typeLoopSelectAttrs, |
|
||||||
typeRangeSelectAttrs, |
|
||||||
WEEK_MAP_CN, |
|
||||||
WEEK_MAP_EN, |
|
||||||
} |
|
||||||
}, |
|
||||||
}) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div :class="`${prefixCls}-config-list`"> |
|
||||||
<RadioGroup v-model:value="type"> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.unset" v-bind="beforeRadioAttrs"> |
|
||||||
不设置 |
|
||||||
</Radio> |
|
||||||
<span class="tip-info">日和周只能设置其中之一</span> |
|
||||||
</div> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.range" v-bind="beforeRadioAttrs"> |
|
||||||
区间 |
|
||||||
</Radio> |
|
||||||
<span> 从 </span> |
|
||||||
<ASelect v-model:value="valueRange.start" :options="weekOptions" v-bind="typeRangeSelectAttrs" /> |
|
||||||
<span> 至 </span> |
|
||||||
<ASelect v-model:value="valueRange.end" :options="weekOptions" v-bind="typeRangeSelectAttrs" /> |
|
||||||
</div> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.loop" v-bind="beforeRadioAttrs"> |
|
||||||
循环 |
|
||||||
</Radio> |
|
||||||
<span> 从 </span> |
|
||||||
<ASelect v-model:value="valueLoop.start" :options="weekOptions" v-bind="typeLoopSelectAttrs" /> |
|
||||||
<span> 开始,间隔 </span> |
|
||||||
<AInput v-model:value="valueLoop.interval" type="number" v-bind="typeLoopAttrs" /> |
|
||||||
<span> 天 </span> |
|
||||||
</div> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.specify" v-bind="beforeRadioAttrs"> |
|
||||||
指定 |
|
||||||
</Radio> |
|
||||||
<div class="list list-cn"> |
|
||||||
<CheckboxGroup v-model:value="valueList"> |
|
||||||
<template v-for="opt in weekOptions" :key="opt.value"> |
|
||||||
<Checkbox :value="opt.value" v-bind="typeSpecifyAttrs"> |
|
||||||
{{ opt.label }} |
|
||||||
</Checkbox> |
|
||||||
</template> |
|
||||||
</CheckboxGroup> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</RadioGroup> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,55 +0,0 @@ |
|||||||
<script lang="ts"> |
|
||||||
import { defineComponent } from 'vue' |
|
||||||
import { Input, Radio } from 'ant-design-vue' |
|
||||||
import { useTabEmits, useTabProps, useTabSetup } from './useTabMixin' |
|
||||||
|
|
||||||
export default defineComponent({ |
|
||||||
name: 'YearUI', |
|
||||||
components: { AInput: Input, Radio, RadioGroup: Radio.Group }, |
|
||||||
props: useTabProps({ |
|
||||||
defaultValue: '*', |
|
||||||
}), |
|
||||||
emits: useTabEmits(), |
|
||||||
setup(props, context) { |
|
||||||
const nowYear = new Date().getFullYear() |
|
||||||
return useTabSetup(props, context, { |
|
||||||
defaultValue: '*', |
|
||||||
minValue: 0, |
|
||||||
valueRange: { start: nowYear, end: nowYear + 100 }, |
|
||||||
valueLoop: { start: nowYear, interval: 1 }, |
|
||||||
}) |
|
||||||
}, |
|
||||||
}) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div :class="`${prefixCls}-config-list`"> |
|
||||||
<RadioGroup v-model:value="type"> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.every" v-bind="beforeRadioAttrs"> |
|
||||||
每年 |
|
||||||
</Radio> |
|
||||||
</div> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.range" v-bind="beforeRadioAttrs"> |
|
||||||
区间 |
|
||||||
</Radio> |
|
||||||
<span> 从 </span> |
|
||||||
<AInput v-model:value="valueRange.start" type="number" class="w80" v-bind="typeRangeAttrs" /> |
|
||||||
<span> 年 至 </span> |
|
||||||
<AInput v-model:value="valueRange.end" type="number" class="w80" v-bind="typeRangeAttrs" /> |
|
||||||
<span> 年 </span> |
|
||||||
</div> |
|
||||||
<div class="item"> |
|
||||||
<Radio :value="TypeEnum.loop" v-bind="beforeRadioAttrs"> |
|
||||||
循环 |
|
||||||
</Radio> |
|
||||||
<span> 从 </span> |
|
||||||
<AInput v-model:value="valueLoop.start" type="number" class="w80" v-bind="typeLoopAttrs" /> |
|
||||||
<span> 年开始,间隔 </span> |
|
||||||
<AInput v-model:value="valueLoop.interval" type="number" class="w80" v-bind="typeLoopAttrs" /> |
|
||||||
<span> 年 </span> |
|
||||||
</div> |
|
||||||
</RadioGroup> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,204 +0,0 @@ |
|||||||
// 主要用于日和星期的互斥使用
|
|
||||||
import { computed, inject, reactive, ref, unref, watch } from 'vue' |
|
||||||
import { propTypes } from '@/utils/propTypes' |
|
||||||
|
|
||||||
export enum TypeEnum { |
|
||||||
unset = 'UNSET', |
|
||||||
every = 'EVERY', |
|
||||||
range = 'RANGE', |
|
||||||
loop = 'LOOP', |
|
||||||
work = 'WORK', |
|
||||||
last = 'LAST', |
|
||||||
specify = 'SPECIFY', |
|
||||||
} |
|
||||||
|
|
||||||
// use 公共 props
|
|
||||||
export function useTabProps(options) { |
|
||||||
const defaultValue = options?.defaultValue ?? '?' |
|
||||||
return { |
|
||||||
value: propTypes.string.def(defaultValue), |
|
||||||
disabled: propTypes.bool.def(false), |
|
||||||
...options?.props, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// use 公共 emits
|
|
||||||
export function useTabEmits() { |
|
||||||
return ['change', 'update:value'] |
|
||||||
} |
|
||||||
|
|
||||||
// use 公共 setup
|
|
||||||
export function useTabSetup(props, context, options) { |
|
||||||
const { emit } = context |
|
||||||
const prefixCls = inject('prefixCls') |
|
||||||
const defaultValue = ref(options?.defaultValue ?? '?') |
|
||||||
// 类型
|
|
||||||
const type = ref(options.defaultType ?? TypeEnum.every) |
|
||||||
const valueList = ref<any[]>([]) |
|
||||||
// 对于不同的类型,所定义的值也有所不同
|
|
||||||
const valueRange = reactive(options.valueRange) |
|
||||||
const valueLoop = reactive(options.valueLoop) |
|
||||||
const valueWeek = reactive(options.valueWeek) |
|
||||||
const valueWork = ref(options.valueWork) |
|
||||||
const maxValue = ref(options.maxValue) |
|
||||||
const minValue = ref(options.minValue) |
|
||||||
|
|
||||||
// 根据不同的类型计算出的value
|
|
||||||
const computeValue = computed(() => { |
|
||||||
const valueArray: any[] = [] |
|
||||||
switch (type.value) { |
|
||||||
case TypeEnum.unset: |
|
||||||
valueArray.push('?') |
|
||||||
break |
|
||||||
case TypeEnum.every: |
|
||||||
valueArray.push('*') |
|
||||||
break |
|
||||||
case TypeEnum.range: |
|
||||||
valueArray.push(`${valueRange.start}-${valueRange.end}`) |
|
||||||
break |
|
||||||
case TypeEnum.loop: |
|
||||||
valueArray.push(`${valueLoop.start}/${valueLoop.interval}`) |
|
||||||
break |
|
||||||
case TypeEnum.work: |
|
||||||
valueArray.push(`${valueWork.value}W`) |
|
||||||
break |
|
||||||
case TypeEnum.last: |
|
||||||
valueArray.push('L') |
|
||||||
break |
|
||||||
case TypeEnum.specify: |
|
||||||
if (valueList.value.length === 0) |
|
||||||
valueList.value.push(minValue.value) |
|
||||||
|
|
||||||
valueArray.push(valueList.value.join(',')) |
|
||||||
break |
|
||||||
default: |
|
||||||
valueArray.push(defaultValue.value) |
|
||||||
break |
|
||||||
} |
|
||||||
return valueArray.length > 0 ? valueArray.join('') : defaultValue.value |
|
||||||
}) |
|
||||||
// 指定值范围区间,介于最小值和最大值之间
|
|
||||||
const specifyRange = computed(() => { |
|
||||||
const range: number[] = [] |
|
||||||
if (maxValue.value != null) { |
|
||||||
for (let i = minValue.value; i <= maxValue.value; i++) |
|
||||||
range.push(i) |
|
||||||
} |
|
||||||
return range |
|
||||||
}) |
|
||||||
|
|
||||||
watch( |
|
||||||
() => props.value, |
|
||||||
(val) => { |
|
||||||
if (val !== computeValue.value) |
|
||||||
parseValue(val) |
|
||||||
}, |
|
||||||
{ immediate: true }, |
|
||||||
) |
|
||||||
|
|
||||||
watch(computeValue, v => updateValue(v)) |
|
||||||
|
|
||||||
function updateValue(value) { |
|
||||||
emit('change', value) |
|
||||||
emit('update:value', value) |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* parseValue |
|
||||||
* @param value |
|
||||||
*/ |
|
||||||
function parseValue(value) { |
|
||||||
if (value === computeValue.value) |
|
||||||
return |
|
||||||
|
|
||||||
try { |
|
||||||
if (!value || value === defaultValue.value) { |
|
||||||
type.value = TypeEnum.every |
|
||||||
} |
|
||||||
else if (value.includes('?')) { |
|
||||||
type.value = TypeEnum.unset |
|
||||||
} |
|
||||||
else if (value.includes('-')) { |
|
||||||
type.value = TypeEnum.range |
|
||||||
const values = value.split('-') |
|
||||||
if (values.length >= 2) { |
|
||||||
valueRange.start = Number.parseInt(values[0]) |
|
||||||
valueRange.end = Number.parseInt(values[1]) |
|
||||||
} |
|
||||||
} |
|
||||||
else if (value.includes('/')) { |
|
||||||
type.value = TypeEnum.loop |
|
||||||
const values = value.split('/') |
|
||||||
if (values.length >= 2) { |
|
||||||
valueLoop.start = value[0] === '*' ? 0 : Number.parseInt(values[0]) |
|
||||||
valueLoop.interval = Number.parseInt(values[1]) |
|
||||||
} |
|
||||||
} |
|
||||||
else if (value.includes('W')) { |
|
||||||
type.value = TypeEnum.work |
|
||||||
const values = value.split('W') |
|
||||||
if (!values[0] && !Number.isNaN(values[0])) |
|
||||||
valueWork.value = Number.parseInt(values[0]) |
|
||||||
} |
|
||||||
else if (value.includes('L')) { |
|
||||||
type.value = TypeEnum.last |
|
||||||
} |
|
||||||
else if (value.includes(',') || !Number.isNaN(value)) { |
|
||||||
type.value = TypeEnum.specify |
|
||||||
valueList.value = value.split(',').map(item => Number.parseInt(item)) |
|
||||||
} |
|
||||||
else { |
|
||||||
type.value = TypeEnum.every |
|
||||||
} |
|
||||||
} |
|
||||||
catch (e) { |
|
||||||
type.value = TypeEnum.every |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
const beforeRadioAttrs = computed(() => ({ |
|
||||||
class: ['choice'], |
|
||||||
disabled: props.disabled || unref(options.disabled), |
|
||||||
})) |
|
||||||
const inputNumberAttrs = computed(() => ({ |
|
||||||
class: ['w60'], |
|
||||||
max: maxValue.value, |
|
||||||
min: minValue.value, |
|
||||||
precision: 0, |
|
||||||
})) |
|
||||||
const typeRangeAttrs = computed(() => ({ |
|
||||||
disabled: type.value !== TypeEnum.range || props.disabled || unref(options.disabled), |
|
||||||
...inputNumberAttrs.value, |
|
||||||
})) |
|
||||||
const typeLoopAttrs = computed(() => ({ |
|
||||||
disabled: type.value !== TypeEnum.loop || props.disabled || unref(options.disabled), |
|
||||||
...inputNumberAttrs.value, |
|
||||||
})) |
|
||||||
const typeSpecifyAttrs = computed(() => ({ |
|
||||||
disabled: type.value !== TypeEnum.specify || props.disabled || unref(options.disabled), |
|
||||||
class: ['list-check-item'], |
|
||||||
})) |
|
||||||
|
|
||||||
return { |
|
||||||
type, |
|
||||||
TypeEnum, |
|
||||||
prefixCls, |
|
||||||
defaultValue, |
|
||||||
valueRange, |
|
||||||
valueLoop, |
|
||||||
valueWeek, |
|
||||||
valueList, |
|
||||||
valueWork, |
|
||||||
maxValue, |
|
||||||
minValue, |
|
||||||
computeValue, |
|
||||||
specifyRange, |
|
||||||
updateValue, |
|
||||||
parseValue, |
|
||||||
beforeRadioAttrs, |
|
||||||
inputNumberAttrs, |
|
||||||
typeRangeAttrs, |
|
||||||
typeLoopAttrs, |
|
||||||
typeSpecifyAttrs, |
|
||||||
} |
|
||||||
} |
|
@ -1,50 +0,0 @@ |
|||||||
/* eslint-disable prefer-promise-reject-errors */ |
|
||||||
import CronParser from 'cron-parser' |
|
||||||
import type { ValidatorRule } from 'ant-design-vue/lib/form/interface' |
|
||||||
|
|
||||||
const cronRule: ValidatorRule = { |
|
||||||
// eslint-disable-next-line no-empty-pattern
|
|
||||||
validator({}, value) { |
|
||||||
// 没填写就不校验
|
|
||||||
if (!value) |
|
||||||
return Promise.resolve() |
|
||||||
|
|
||||||
const values: string[] = value.split(' ').filter(item => !!item) |
|
||||||
if (values.length > 7) |
|
||||||
return Promise.reject('Cron表达式最多7项!') |
|
||||||
|
|
||||||
// 检查第7项
|
|
||||||
let val: string = value |
|
||||||
if (values.length === 7) { |
|
||||||
const year = values[6] |
|
||||||
if (year !== '*' && year !== '?') { |
|
||||||
let yearValues: string[] = [] |
|
||||||
if (year.includes('-')) |
|
||||||
yearValues = year.split('-') |
|
||||||
else if (year.indexOf('/')) |
|
||||||
yearValues = year.split('/') |
|
||||||
else |
|
||||||
yearValues = [year] |
|
||||||
|
|
||||||
// 判断是否都是数字
|
|
||||||
const checkYear = yearValues.some(item => Number.isNaN(Number(item))) |
|
||||||
if (checkYear) |
|
||||||
return Promise.reject(`Cron表达式参数[年]错误:${year}`) |
|
||||||
} |
|
||||||
// 取其中的前六项
|
|
||||||
val = values.slice(0, 6).join(' ') |
|
||||||
} |
|
||||||
// 6位 没有年
|
|
||||||
// 5位没有秒、年
|
|
||||||
try { |
|
||||||
const iter = CronParser.parseExpression(val) |
|
||||||
iter.next() |
|
||||||
return Promise.resolve() |
|
||||||
} |
|
||||||
catch (e: any) { |
|
||||||
return Promise.reject(`Cron表达式错误:${e}`) |
|
||||||
} |
|
||||||
}, |
|
||||||
} |
|
||||||
|
|
||||||
export default cronRule.validator |
|
Loading…
Reference in new issue