254 lines
8.6 KiB
Vue
254 lines
8.6 KiB
Vue
<script setup lang="ts">
|
|
import { computed, ref, watch } from 'vue';
|
|
import { DATE, DEFAULT_LOCALE, LOCALE_EN, TYPE, WEEK, YEAR } from '../../shared/constants';
|
|
import { generateSpecifies, weekLetterToNumber } from '../../shared/utils';
|
|
import Locales from '../../i18n';
|
|
import InputNumber from './input-number.vue';
|
|
|
|
defineOptions({ name: 'CronBase' });
|
|
|
|
interface Props {
|
|
modelValue: string;
|
|
field: {
|
|
value: I18n.FieldType;
|
|
label: string;
|
|
min: number;
|
|
max: number;
|
|
};
|
|
locale?: I18n.LocaleType;
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
locale: DEFAULT_LOCALE
|
|
});
|
|
|
|
interface Emits {
|
|
(e: 'update:modelValue', value: string): void;
|
|
}
|
|
|
|
const emit = defineEmits<Emits>();
|
|
|
|
const labels = props.field.value === 'week' ? Object.values(Locales[props.locale].week) : null;
|
|
|
|
const { min, max, value: fieldValue } = props.field;
|
|
|
|
const type = ref(TYPE.EVERY);
|
|
const range = ref([min, min + 1]);
|
|
const step = ref([min, 1]);
|
|
const well = ref([min, 1]);
|
|
const specify = ref<number[]>([]);
|
|
const weekday = ref(1);
|
|
const lastDayOfWeek = ref(0);
|
|
const rangeStart = ref<[number, number]>([min, max - 1]);
|
|
const stepLeft = ref<[number, number]>([min, max]);
|
|
const stepRight = ref<[number, number]>([1, max]);
|
|
const wellLeft = ref<[number, number]>([0, 0]);
|
|
const wellRight = ref<[number, number]>([0, 0]);
|
|
const specifies = ref(generateSpecifies(min, max, labels));
|
|
|
|
if (fieldValue === WEEK) {
|
|
wellLeft.value = [1, 5];
|
|
wellRight.value = [min, max];
|
|
}
|
|
|
|
const label = computed(() => {
|
|
const i18n = Locales[props.locale];
|
|
const { type: typeLabel, fieldAlias: fieldAliasLabel } = i18n;
|
|
return {
|
|
empty: typeLabel.empty,
|
|
every: `${typeLabel.every}${fieldAliasLabel[props.field.value]}`,
|
|
unspecific: typeLabel.unspecific,
|
|
range: [
|
|
typeLabel.range[0],
|
|
(props.field.value === WEEK || props.locale === LOCALE_EN ? '' : props.field.label) + typeLabel.range[1],
|
|
props.field.value === WEEK || props.locale === LOCALE_EN ? '' : props.field.label
|
|
],
|
|
step: [
|
|
typeLabel.step[0],
|
|
props.field.label + typeLabel.step[1],
|
|
fieldAliasLabel[props.field.value] + typeLabel.step[2]
|
|
],
|
|
well: typeLabel.well,
|
|
weekday: typeLabel.weekday,
|
|
lastWeekday: typeLabel.lastWeekday,
|
|
lastDayOfDate: typeLabel.lastDayOfDate,
|
|
lastDayOfWeek: typeLabel.lastDayOfWeek,
|
|
specify: typeLabel.specify
|
|
};
|
|
});
|
|
|
|
const isEnWeek = computed(() => props.field.value === WEEK && props.locale === LOCALE_EN);
|
|
const rangeEnd = computed<[number, number]>(() => [range.value[0] + 1, props.field.max]);
|
|
const isEmpty = computed(() => props.field.value === YEAR);
|
|
const isUnspecific = computed(() => [DATE, WEEK].includes(props.field.value));
|
|
const isStep = computed(() => props.field.value !== WEEK);
|
|
const isWell = computed(() => props.field.value === WEEK);
|
|
const isLastDayOfDate = computed(() => props.field.value === DATE);
|
|
const isLastDayOfWeek = computed(() => props.field.value === WEEK);
|
|
const isWeekday = computed(() => props.field.value === DATE);
|
|
const isLastWeekday = computed(() => props.field.value === DATE);
|
|
const value = computed(() => {
|
|
switch (type.value) {
|
|
case TYPE.EMPTY:
|
|
case TYPE.UNSPECIFIC:
|
|
case TYPE.LAST_WEEKDAY:
|
|
case TYPE.EVERY:
|
|
return type.value;
|
|
case TYPE.RANGE:
|
|
return range.value.join(type.value);
|
|
case TYPE.STEP:
|
|
return step.value.join(type.value);
|
|
case TYPE.WELL:
|
|
return well.value.join(type.value);
|
|
case TYPE.WEEKDAY:
|
|
return `${weekday.value}${type.value}`;
|
|
case TYPE.LAST_DAY:
|
|
return props.field.value === DATE ? type.value : `${lastDayOfWeek.value}${type.value}`;
|
|
case TYPE.SPECIFY: {
|
|
const specifyValue = specify.value;
|
|
return specifyValue.length
|
|
? specifyValue.sort((a, b) => a - b).join(type.value)
|
|
: `${specifyValue[0] || specifies.value[0].value}`;
|
|
}
|
|
default:
|
|
return '';
|
|
}
|
|
});
|
|
|
|
watch(
|
|
() => props.modelValue,
|
|
val => {
|
|
let data = val;
|
|
|
|
if (props.field.value === WEEK) {
|
|
data = weekLetterToNumber(val).replaceAll('7', '0');
|
|
}
|
|
|
|
if ([TYPE.EMPTY, TYPE.UNSPECIFIC, TYPE.LAST_DAY, TYPE.LAST_WEEKDAY, TYPE.EVERY].includes(data)) {
|
|
type.value = data;
|
|
} else if (data.includes(TYPE.RANGE)) {
|
|
type.value = TYPE.RANGE;
|
|
range.value = data.split(TYPE.RANGE).map(i => Number.parseInt(i, 10));
|
|
} else if (data.includes(TYPE.STEP)) {
|
|
type.value = TYPE.STEP;
|
|
step.value = data.split(TYPE.STEP).map(i => Number.parseInt(i, 10));
|
|
} else if (data.includes(TYPE.WELL)) {
|
|
type.value = TYPE.WELL;
|
|
well.value = data.split(TYPE.WELL).map(i => Number.parseInt(i, 10));
|
|
} else if (data.includes(TYPE.WEEKDAY)) {
|
|
type.value = TYPE.WEEKDAY;
|
|
weekday.value = Number.parseInt(data, 10);
|
|
} else if (data.includes(TYPE.LAST_DAY)) {
|
|
type.value = TYPE.LAST_DAY;
|
|
lastDayOfWeek.value = Number.parseInt(data, 10);
|
|
} else {
|
|
type.value = TYPE.SPECIFY;
|
|
specify.value =
|
|
data !== 'undefined' && data !== 'NaN' ? data.split(TYPE.SPECIFY).map(i => Number.parseInt(i, 10)) : [];
|
|
}
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
|
|
watch(
|
|
() => value.value,
|
|
val => {
|
|
emit('update:modelValue', val);
|
|
}
|
|
);
|
|
|
|
const onRangeStartChange = (val: number) => {
|
|
const [, ranEnd] = range.value;
|
|
|
|
if (val >= ranEnd) {
|
|
range.value[1] = val + 1;
|
|
}
|
|
};
|
|
|
|
const onCheckboxGroupChange = () => {
|
|
let checkType = TYPE.SPECIFY;
|
|
|
|
if (specify.value.length === 0) {
|
|
checkType = props.field.value === YEAR ? TYPE.EMPTY : TYPE.EVERY;
|
|
}
|
|
|
|
type.value = checkType;
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<NRadioGroup v-model:value="type" class="flex-col">
|
|
<NRadio v-if="isEmpty && field.value !== YEAR" class="cron-radio" :value="TYPE.EMPTY">{{ label.empty }}</NRadio>
|
|
<NRadio class="cron-radio" :value="TYPE.EVERY">{{ label.every }}</NRadio>
|
|
<NRadio v-if="isEmpty && field.value === YEAR" class="cron-radio" :value="TYPE.EMPTY">{{ label.empty }}</NRadio>
|
|
<NRadio v-if="isUnspecific" class="cron-radio" :value="TYPE.UNSPECIFIC">{{ label.unspecific }}</NRadio>
|
|
<div class="cron-radio flex items-center justify-start gap-5px">
|
|
<NRadio :value="TYPE.RANGE" />
|
|
{{ label.range[0] }}
|
|
<InputNumber
|
|
v-model="range[0]"
|
|
:range="rangeStart"
|
|
:field-value="field.value"
|
|
:locale="locale"
|
|
@update:value="onRangeStartChange"
|
|
/>
|
|
{{ label.range[1] }}
|
|
<InputNumber v-model="range[1]" :range="rangeEnd" :field-value="field.value" :locale="locale" />
|
|
{{ label.range[2] }}
|
|
</div>
|
|
<div v-if="isStep" class="cron-radio flex items-center justify-start gap-5px">
|
|
<NRadio :value="TYPE.STEP" />
|
|
<span>{{ label.step[0] }}</span>
|
|
<InputNumber v-model="step[0]" :range="stepLeft" />
|
|
<span>{{ label.step[1] }}</span>
|
|
<InputNumber v-model="step[1]" :range="stepRight" />
|
|
<span>{{ label.step[2] }}</span>
|
|
</div>
|
|
<div v-if="isWell" class="cron-radio flex items-center justify-start gap-5px">
|
|
<NRadio :value="TYPE.WELL" />
|
|
{{ label.well[0] }}
|
|
<InputNumber v-model="well[1]" :range="[...wellLeft]" />
|
|
{{ label.well[1] }}
|
|
<InputNumber v-model="well[0]" :range="[...wellRight]" :field-value="field.value" :locale="locale" />
|
|
</div>
|
|
<div v-if="isWeekday" class="cron-radio flex items-center justify-start gap-5px">
|
|
<NRadio :value="TYPE.WEEKDAY" />
|
|
{{ label.weekday[0] }}
|
|
<InputNumber v-model="weekday" :range="rangeStart" />
|
|
{{ label.weekday[1] }}
|
|
</div>
|
|
<NRadio v-if="isLastWeekday" class="cron-radio" :value="TYPE.LAST_WEEKDAY">{{ label.lastWeekday }}</NRadio>
|
|
<NRadio v-if="isLastDayOfDate" class="cron-radio" :value="TYPE.LAST_DAY">{{ label.lastDayOfDate }}</NRadio>
|
|
<div v-if="isLastDayOfWeek" class="cron-radio flex items-center justify-start gap-5px">
|
|
<NRadio v-if="isLastDayOfWeek" :value="TYPE.LAST_DAY" />
|
|
{{ label.lastDayOfWeek }}
|
|
<InputNumber v-model="lastDayOfWeek" :range="[0, 6]" :field-value="field.value" :locale="locale" />
|
|
</div>
|
|
<div class="cron-radio flex flex-wrap items-center justify-start gap-5px">
|
|
<NRadio class="cron-radio" :value="TYPE.SPECIFY">{{ label.specify }}</NRadio>
|
|
<NCheckboxGroup
|
|
v-if="type === TYPE.SPECIFY"
|
|
v-model:value="specify"
|
|
class="p-l-22px"
|
|
:class="{ 'checkbox-group-en-week': isEnWeek }"
|
|
@update:value="onCheckboxGroupChange"
|
|
>
|
|
<NCheckbox
|
|
v-for="option in specifies"
|
|
:key="option.value"
|
|
:label="option.label"
|
|
:value="option.value"
|
|
size="small"
|
|
class="min-w-50px"
|
|
/>
|
|
</NCheckboxGroup>
|
|
</div>
|
|
</NRadioGroup>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
.cron-radio:not(:first-child) {
|
|
margin-top: 12px;
|
|
}
|
|
</style>
|