<!--
 * @Description: form 表单下的Cron 生成器
-->
<template>
  <div v-bind="attrs" button-style="solid" class="text-editor">
    <a-input :value="state" @update:value="upadteValue" placeholder="请输入CRON定时规则">
      <template #addonAfter>
        <a-dropdown>
          <down-outlined />
          <template #overlay>
            <a-menu @click="handleShortcuts">
              <a-menu-item key="0 * * * * ?">每分钟</a-menu-item>
              <a-menu-item key="0 0 * * * ?">每小时</a-menu-item>
              <a-menu-item key="0 0 0 * * ?">每天零点</a-menu-item>
              <a-menu-item key="0 0 0 1 * ?">每月一号零点</a-menu-item>
              <a-menu-item key="0 0 0 L * ?">每月最后一天零点</a-menu-item>
              <a-menu-item key="0 0 0 ? * 1">每周星期日零点</a-menu-item>
              <a-menu-divider v-if="shortcuts" />
              <a-menu-item v-for="item in shortcuts" :key="item.value">{{ item.text }}</a-menu-item>
              <a-menu-divider />
              <a-menu-item key="custom">自定义</a-menu-item>
            </a-menu>
          </template>
        </a-dropdown>
      </template>
    </a-input>
    <a-modal
      title="CRON规则生成器"
      v-model:visible="modalVisible"
      :width="580"
      @cancel="modalVisible = false"
      @ok="submit"
      destroy-on-close
      append-to-body
    >
      <div class="sc-cron">
        <a-tabs v-model:activeKey="activeKey">
          <a-tab-pane key="1">
            <template #tab>
              <div class="cron-num">
                <h2>秒</h2>
                <a-tag
                  :color="activeKey === '1' ? `var(--primary-color)` : ''"
                  style="margin-right: 0px"
                  >{{ value_second }}</a-tag
                >
              </div>
            </template>
            <a-form>
              <a-form-item label="类型">
                <a-radio-group v-model:value="value.second.type">
                  <a-radio-button value="0">任意值</a-radio-button>
                  <a-radio-button value="1">范围</a-radio-button>
                  <a-radio-button value="2">间隔</a-radio-button>
                  <a-radio-button value="3">指定</a-radio-button>
                </a-radio-group>
              </a-form-item>
              <a-form-item label="范围" v-if="value.second.type == '1'">
                <a-input-number
                  v-model:value="value.second.range.start"
                  :min="0"
                  :max="59"
                  controls-position="right"
                />
                <span style="padding: 0 15px">-</span>
                <a-input-number
                  v-model:value="value.second.range.end"
                  :min="0"
                  :max="59"
                  controls-position="right"
                />
              </a-form-item>
              <a-form-item label="间隔" v-if="value.second.type == '2'">
                <a-input-number
                  v-model:value="value.second.loop.start"
                  :min="0"
                  :max="59"
                  controls-position="right"
                />
                秒开始，每
                <a-input-number
                  v-model:value="value.second.loop.end"
                  :min="0"
                  :max="59"
                  controls-position="right"
                />
                秒执行一次
              </a-form-item>
              <a-form-item label="指定" v-if="value.second.type == '3'">
                <a-select
                  v-model:value="value.second.appoint"
                  multiple
                  style="width: 100%"
                  mode="multiple"
                  placeholder="请选择"
                >
                  <a-select-option
                    v-for="(item, index) in data.second"
                    :key="index"
                    :label="item"
                    :value="item"
                  />
                </a-select>
              </a-form-item>
            </a-form>
          </a-tab-pane>
          <a-tab-pane key="2">
            <template #tab>
              <div class="cron-num">
                <h2>分钟</h2>
                <a-tag
                  :color="activeKey === '2' ? `var(--primary-color)` : ''"
                  style="margin-right: 0px"
                  >{{ value_minute }}</a-tag
                >
              </div>
            </template>
            <a-form>
              <a-form-item label="类型">
                <a-radio-group v-model:value="value.minute.type">
                  <a-radio-button value="0">任意值</a-radio-button>
                  <a-radio-button value="1">范围</a-radio-button>
                  <a-radio-button value="2">间隔</a-radio-button>
                  <a-radio-button value="3">指定</a-radio-button>
                </a-radio-group>
              </a-form-item>
              <a-form-item label="范围" v-if="value.minute.type == '1'">
                <a-input-number
                  v-model:value="value.minute.range.start"
                  :min="0"
                  :max="59"
                  controls-position="right"
                />
                <span style="padding: 0 15px">-</span>
                <a-input-number
                  v-model:value="value.minute.range.end"
                  :min="0"
                  :max="59"
                  controls-position="right"
                />
              </a-form-item>
              <a-form-item label="间隔" v-if="value.minute.type == '2'">
                <a-input-number
                  v-model:value="value.minute.loop.start"
                  :min="0"
                  :max="59"
                  controls-position="right"
                />
                分钟开始，每
                <a-input-number
                  v-model:value="value.minute.loop.end"
                  :min="0"
                  :max="59"
                  controls-position="right"
                />
                分钟执行一次
              </a-form-item>
              <a-form-item label="指定" v-if="value.minute.type == '3'">
                <a-select
                  v-model:value="value.minute.appoint"
                  multiple
                  style="width: 100%"
                  mode="multiple"
                  placeholder="请选择"
                >
                  <a-select-option
                    v-for="(item, index) in data.minute"
                    :key="index"
                    :label="item"
                    :value="item"
                  />
                </a-select>
              </a-form-item>
            </a-form>
          </a-tab-pane>
          <a-tab-pane key="3">
            <template #tab>
              <div class="cron-num">
                <h2>小时</h2>
                <a-tag
                  :color="activeKey === '3' ? `var(--primary-color)` : ''"
                  style="margin-right: 0px"
                  >{{ value_hour }}</a-tag
                >
              </div>
            </template>
            <a-form>
              <a-form-item label="类型">
                <a-radio-group v-model:value="value.hour.type">
                  <a-radio-button value="0">任意值</a-radio-button>
                  <a-radio-button value="1">范围</a-radio-button>
                  <a-radio-button value="2">间隔</a-radio-button>
                  <a-radio-button value="3">指定</a-radio-button>
                </a-radio-group>
              </a-form-item>
              <a-form-item label="范围" v-if="value.hour.type == '1'">
                <a-input-number
                  v-model:value="value.hour.range.start"
                  :min="0"
                  :max="23"
                  controls-position="right"
                />
                <span style="padding: 0 15px">-</span>
                <a-input-number
                  v-model:value="value.hour.range.end"
                  :min="0"
                  :max="23"
                  controls-position="right"
                />
              </a-form-item>
              <a-form-item label="间隔" v-if="value.hour.type == '2'">
                <a-input-number
                  v-model:value="value.hour.loop.start"
                  :min="0"
                  :max="23"
                  controls-position="right"
                />
                小时开始，每
                <a-input-number
                  v-model:value="value.hour.loop.end"
                  :min="0"
                  :max="23"
                  controls-position="right"
                />
                小时执行一次
              </a-form-item>
              <a-form-item label="指定" v-if="value.hour.type == '3'">
                <a-select
                  v-model:value="value.hour.appoint"
                  multiple
                  style="width: 100%"
                  mode="multiple"
                  placeholder="请选择"
                >
                  <a-select-option
                    v-for="(item, index) in data.hour"
                    :key="index"
                    :label="item"
                    :value="item"
                  />
                </a-select>
              </a-form-item>
            </a-form>
          </a-tab-pane>
          <a-tab-pane key="4">
            <template #tab>
              <div class="cron-num">
                <h2>日</h2>
                <a-tag
                  :color="activeKey === '4' ? `var(--primary-color)` : ''"
                  style="margin-right: 0px"
                  >{{ value_day }}</a-tag
                >
              </div>
            </template>
            <a-form>
              <a-form-item label="类型">
                <a-radio-group v-model:value="value.day.type">
                  <a-radio-button value="0">任意值</a-radio-button>
                  <a-radio-button value="1">范围</a-radio-button>
                  <a-radio-button value="2">间隔</a-radio-button>
                  <a-radio-button value="3">指定</a-radio-button>
                  <a-radio-button value="4">本月最后一天</a-radio-button>
                  <a-radio-button value="5">不指定</a-radio-button>
                </a-radio-group>
              </a-form-item>
              <a-form-item label="范围" v-if="value.day.type == '1'">
                <a-input-number
                  v-model:value="value.day.range.start"
                  :min="1"
                  :max="31"
                  controls-position="right"
                />
                <span style="padding: 0 15px">-</span>
                <a-input-number
                  v-model:value="value.day.range.end"
                  :min="1"
                  :max="31"
                  controls-position="right"
                />
              </a-form-item>
              <a-form-item label="间隔" v-if="value.day.type == '2'">
                <a-input-number
                  v-model:value="value.day.loop.start"
                  :min="1"
                  :max="31"
                  controls-position="right"
                />
                号开始，每
                <a-input-number
                  v-model:value="value.day.loop.end"
                  :min="1"
                  :max="31"
                  controls-position="right"
                />
                天执行一次
              </a-form-item>
              <a-form-item label="指定" v-if="value.day.type == '3'">
                <a-select
                  v-model:value="value.day.appoint"
                  multiple
                  style="width: 100%"
                  mode="multiple"
                  placeholder="请选择"
                >
                  <a-select-option
                    v-for="(item, index) in data.day"
                    :key="index"
                    :label="item"
                    :value="item"
                  />
                </a-select>
              </a-form-item>
            </a-form>
          </a-tab-pane>
          <a-tab-pane key="5">
            <template #tab>
              <div class="cron-num">
                <h2>月</h2>
                <a-tag
                  :color="activeKey === '5' ? `var(--primary-color)` : ''"
                  style="margin-right: 0px"
                  >{{ value_month }}</a-tag
                >
              </div>
            </template>
            <a-form>
              <a-form-item label="类型">
                <a-radio-group v-model:value="value.month.type">
                  <a-radio-button value="0">任意值</a-radio-button>
                  <a-radio-button value="1">范围</a-radio-button>
                  <a-radio-button value="2">间隔</a-radio-button>
                  <a-radio-button value="3">指定</a-radio-button>
                </a-radio-group>
              </a-form-item>
              <a-form-item label="范围" v-if="value.month.type == '1'">
                <a-input-number
                  v-model:value="value.month.range.start"
                  :min="1"
                  :max="12"
                  controls-position="right"
                />
                <span style="padding: 0 15px">-</span>
                <a-input-number
                  v-model:value="value.month.range.end"
                  :min="1"
                  :max="12"
                  controls-position="right"
                />
              </a-form-item>
              <a-form-item label="间隔" v-if="value.month.type == '2'">
                <a-input-number
                  v-model:value="value.month.loop.start"
                  :min="1"
                  :max="12"
                  controls-position="right"
                />
                月开始，每
                <a-input-number
                  v-model:value="value.month.loop.end"
                  :min="1"
                  :max="12"
                  controls-position="right"
                />
                月执行一次
              </a-form-item>
              <a-form-item label="指定" v-if="value.month.type == '3'">
                <a-select
                  v-model:value="value.month.appoint"
                  multiple
                  style="width: 100%"
                  mode="multiple"
                  placeholder="请选择"
                >
                  <a-select-option
                    v-for="(item, index) in data.month"
                    :key="index"
                    :label="item"
                    :value="item"
                  />
                </a-select>
              </a-form-item>
            </a-form>
          </a-tab-pane>
          <a-tab-pane key="6">
            <template #tab>
              <div class="cron-num">
                <h2>周</h2>
                <a-tag
                  :color="activeKey === '6' ? `var(--primary-color)` : ''"
                  style="margin-right: 0px"
                  >{{ value_week }}</a-tag
                >
              </div>
            </template>
            <a-form>
              <a-form>
                <a-form-item label="类型">
                  <a-radio-group v-model:value="value.week.type">
                    <a-radio-button value="0">任意值</a-radio-button>
                    <a-radio-button value="1">范围</a-radio-button>
                    <a-radio-button value="2">间隔</a-radio-button>
                    <a-radio-button value="3">指定</a-radio-button>
                    <a-radio-button value="4">本月最后一周</a-radio-button>
                    <a-radio-button value="5">不指定</a-radio-button>
                  </a-radio-group>
                </a-form-item>
                <a-form-item label="范围" v-if="value.week.type == '1'">
                  <a-select v-model:value="value.week.range.start" placeholder="请选择">
                    <a-select-option
                      v-for="(item, index) in data.week"
                      :key="index"
                      :label="item.label"
                      :value="item.value"
                    />
                  </a-select>
                  <span style="padding: 0 15px">-</span>
                  <a-select v-model:value="value.week.range.end" placeholder="请选择">
                    <a-select-option
                      v-for="(item, index) in data.week"
                      :key="index"
                      :label="item.label"
                      :value="item.value"
                    />
                  </a-select>
                </a-form-item>
                <a-form-item label="间隔" v-if="value.week.type == '2'">
                  第
                  <a-input-number
                    v-model:value="value.week.loop.start"
                    :min="1"
                    :max="4"
                    controls-position="right"
                  />
                  周的星期
                  <a-select v-model:value="value.week.loop.end" placeholder="请选择">
                    <a-select-option
                      v-for="(item, index) in data.week"
                      :key="index"
                      :label="item.label"
                      :value="item.value"
                    />
                  </a-select>
                  执行一次
                </a-form-item>
                <a-form-item label="指定" v-if="value.week.type == '3'">
                  <a-select
                    v-model:value="value.week.appoint"
                    multiple
                    style="width: 100%"
                    mode="multiple"
                    placeholder="请选择"
                  >
                    <a-select-option
                      v-for="(item, index) in data.week"
                      :key="index"
                      :label="item.label"
                      :value="item.value"
                    />
                  </a-select>
                </a-form-item>
                <a-form-item label="最后一周" v-if="value.week.type == '4'">
                  <a-select v-model:value="value.week.last" placeholder="请选择">
                    <a-select-option
                      v-for="(item, index) in data.week"
                      :key="index"
                      :label="item.label"
                      :value="item.value"
                    />
                  </a-select>
                </a-form-item>
              </a-form>
            </a-form>
          </a-tab-pane>
          <a-tab-pane key="7">
            <template #tab>
              <div class="cron-num">
                <h2>年</h2>
                <a-tag
                  :color="activeKey === '7' ? `var(--primary-color)` : ''"
                  style="margin-right: 0px"
                  >{{ value_year }}</a-tag
                >
              </div>
            </template>
            <a-form>
              <a-form-item label="类型">
                <a-radio-group v-model:value="value.year.type">
                  <a-radio-button value="-1">忽略</a-radio-button>
                  <a-radio-button value="0">任意值</a-radio-button>
                  <a-radio-button value="1">范围</a-radio-button>
                  <a-radio-button value="2">间隔</a-radio-button>
                  <a-radio-button value="3">指定</a-radio-button>
                </a-radio-group>
              </a-form-item>
              <a-form-item label="范围" v-if="value.year.type == '1'">
                <a-input-number v-model:value="value.year.range.start" controls-position="right" />
                <span style="padding: 0 15px">-</span>
                <a-input-number v-model:value="value.year.range.end" controls-position="right" />
              </a-form-item>
              <a-form-item label="间隔" v-if="value.year.type == '2'">
                <a-input-number v-model:value="value.year.loop.start" controls-position="right" />
                年开始，每
                <a-input-number
                  v-model:value="value.year.loop.end"
                  :min="1"
                  controls-position="right"
                />
                年执行一次
              </a-form-item>
              <a-form-item label="指定" v-if="value.year.type == '3'">
                <a-select
                  v-model:value="value.year.appoint"
                  multiple
                  style="width: 100%"
                  mode="multiple"
                  placeholder="请选择"
                >
                  <a-select-option
                    v-for="(item, index) in data.year"
                    :key="index"
                    :label="item"
                    :value="item"
                  />
                </a-select>
              </a-form-item>
            </a-form>
          </a-tab-pane>
        </a-tabs>
      </div>
    </a-modal>
  </div>
</template>
<script lang="ts">
  import { defineComponent, reactive, ref, watch } from 'vue';
  import { useAttrs } from '/@/hooks/core/useAttrs';
  import { useRuleFormItem } from '/@/hooks/component/useFormItem';
  import { computed } from 'vue';
  import { onMounted } from 'vue';
  export default defineComponent({
    name: 'Cron',
    props: {
      modelValue: {
        type: String,
        default: '请输入CRON定时规则',
      },
      shortcuts: { type: Array, default: () => [] as any },
    },
    emits: ['change', 'update:modelValue'],
    setup(props, { emit }) {
      const attrs = useAttrs();
      // Embedded in the form, just use the hook binding to perform form verification
      const [state] = useRuleFormItem(props);
      const activeKey = ref('1');
      const type = ref('0');
      const defaultValue = ref('');
      const modalVisible = ref(false);

      const getYear = () => {
        const v = [];
        const y = new Date().getFullYear();
        for (let i = 0; i < 11; i++) {
          v.push(y + i);
        }
        return v;
      };

      const data = reactive({
        second: ['0', '5', '15', '20', '25', '30', '35', '40', '45', '50', '55', '59'],
        minute: ['0', '5', '15', '20', '25', '30', '35', '40', '45', '50', '55', '59'],
        hour: [
          '0',
          '1',
          '2',
          '3',
          '4',
          '5',
          '6',
          '7',
          '8',
          '9',
          '10',
          '11',
          '12',
          '13',
          '14',
          '15',
          '16',
          '17',
          '18',
          '19',
          '20',
          '21',
          '22',
          '23',
        ],
        day: [
          '1',
          '2',
          '3',
          '4',
          '5',
          '6',
          '7',
          '8',
          '9',
          '10',
          '11',
          '12',
          '13',
          '14',
          '15',
          '16',
          '17',
          '18',
          '19',
          '20',
          '21',
          '22',
          '23',
          '24',
          '25',
          '26',
          '27',
          '28',
          '29',
          '30',
          '31',
        ],
        month: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'],
        week: [
          {
            value: '1',
            label: '周日',
          },
          {
            value: '2',
            label: '周一',
          },
          {
            value: '3',
            label: '周二',
          },
          {
            value: '4',
            label: '周三',
          },
          {
            value: '5',
            label: '周四',
          },
          {
            value: '6',
            label: '周五',
          },
          {
            value: '7',
            label: '周六',
          },
        ],
        year: getYear(),
      });
      const value = reactive({
        second: {
          type: '0',
          range: {
            start: 1,
            end: 2,
          },
          loop: {
            start: 0,
            end: 1,
          },
          appoint: [],
        },
        minute: {
          type: '0',
          range: {
            start: 1,
            end: 2,
          },
          loop: {
            start: 0,
            end: 1,
          },
          appoint: [],
        },
        hour: {
          type: '0',
          range: {
            start: 1,
            end: 2,
          },
          loop: {
            start: 0,
            end: 1,
          },
          appoint: [],
        },
        day: {
          type: '0',
          range: {
            start: 1,
            end: 2,
          },
          loop: {
            start: 1,
            end: 1,
          },
          appoint: [],
        },
        month: {
          type: '0',
          range: {
            start: 1,
            end: 2,
          },
          loop: {
            start: 1,
            end: 1,
          },
          appoint: [],
        },
        week: {
          type: '5',
          range: {
            start: '2',
            end: '3',
          },
          loop: {
            start: 0,
            end: '2',
          },
          last: '2',
          appoint: [],
        },
        year: {
          type: '-1',
          range: {
            start: getYear()[0],
            end: getYear()[1],
          },
          loop: {
            start: getYear()[0],
            end: 1,
          },
          appoint: [],
        },
      });

      const value_second = computed(() => {
        return computedValue(value.second);
      });
      const value_minute = computed(() => {
        return computedValue(value.minute);
      });
      const value_hour = computed(() => {
        return computedValue(value.hour);
      });
      const value_day = computed(() => {
        return computedValue(value.day);
      });
      const value_month = computed(() => {
        return computedValue(value.month);
      });
      const value_week = computed(() => {
        return computedValue(value.week, 'week');
      });
      const value_year = computed(() => {
        return computedValue(value.week, 'year');
      });

      const computedValue = (v, name?: string) => {
        if (v.type == '0') {
          return '*';
        } else if (v.type == '1') {
          return v.range.start + '-' + v.range.end;
        } else if (v.type == '2') {
          if (name == 'week') {
            return v.loop.end + '#' + v.loop.start;
          }
          return v.loop.start + '/' + v.loop.end;
        } else if (v.type == '3') {
          if (name == 'year') {
            return v.appoint.length > 0 ? v.appoint.join(',') : '';
          }
          return v.appoint.length > 0 ? v.appoint.join(',') : '*';
        } else if (v.type == 4) {
          return 'L';
        } else if (v.type == 5) {
          return '?';
        } else {
          return '*';
        }
      };

      watch(
        () => [value.week.type, value.day.type, props.modelValue],
        (newVal, _oldVal) => {
          // console.log(newVal, oldVal); // [11, 22], [1, 2]
          // console.log(newVal[0], oldVal[0], newVal[1], oldVal[1]); // 11, 1, 22, 2
          if (newVal[0] == '5') {
            value.day.type = '5';
          }
          if (newVal[1] == '5') {
            value.day.type = '5';
          }
          if (newVal[2]) {
            defaultValue.value = props.modelValue;
          }
        },
      );

      onMounted(() => {
        defaultValue.value = props.modelValue;
      });

      function handleChange(data) {
        // console.log('data', data);
        emit('change', data);
      }
      // 更新值
      const upadteValue = v => {
        emit('update:modelValue', v);
      };

      function handleShortcuts(obj: any) {
        if (obj.key === 'custom') {
          open();
        } else {
          // this.state = obj.key;
          emit('update:modelValue', obj.key);
        }
      }

      const open = () => {
        set();
        modalVisible.value = true;
      };

      const set = () => {
        defaultValue.value = props.modelValue;
        let arr = (props.modelValue || '* * * * * ?').split(' ');
        //简单检查
        if (arr.length < 6) {
          arr = '* * * * * ?'.split(' ');
        }
        // 秒
        setValue(arr[0], 'second');
        // 分
        setValue(arr[1], 'minute');
        // 小时
        setValue(arr[2], 'hour');
        // 日
        setValue(arr[3], 'day');
        // 月
        setValue(arr[4], 'month');
        // 周
        setValue(arr[5], 'week');
        if (!arr[6]) {
          value.year.type = '-1';
        }
        // 年
        setValue(arr[6], 'year');
      };

      const setValue = (val, name?: string) => {
        const obj = {} as any;
        if (val == '*') {
          obj.type = '0';
        } else if (val.includes('-')) {
          obj.type = '1';
          obj.range.start = Number(val.split('-')[0]);
          obj.range.end = Number(val.split('-')[1]);
        } else if (val.includes('/')) {
          obj.type = '2';
          obj.loop.start = Number(val.split('/')[0]);
          obj.loop.end = Number(val.split('/')[1]);
        } else if (val == 'L') {
          obj.type = '4';
        } else if (val == '?') {
          obj.type = '5';
        } else if (val.includes('#')) {
          if (name == 'week') {
            obj.type = '2';
            obj.loop.start = Number(val.split('#')[1]);
            obj.loop.end = val.split('#')[0];
          }
        } else if (val.includes('L')) {
          obj.type = '4';
          if (name == 'week') {
            obj.last = val.split('L')[0];
          }
        } else {
          obj.type = '3';
          obj.appoint = val.split(',');
        }
        if (name == 'second') {
          value[name] = obj;
        }
      };
      const submit = () => {
        const year = value_year.value ? ' ' + value_year.value : '';
        defaultValue.value =
          value_second.value +
          ' ' +
          value_minute.value +
          ' ' +
          value_hour.value +
          ' ' +
          value_day.value +
          ' ' +
          value_month.value +
          ' ' +
          value_week.value +
          year;
        emit('update:modelValue', defaultValue.value);
        modalVisible.value = false;
      };

      return {
        attrs,
        state,
        handleChange,
        upadteValue,
        handleShortcuts,
        value_second,
        value_minute,
        value_hour,
        value_day,
        value_month,
        value_week,
        value_year,
        submit,
        activeKey,
        type,
        data,
        value,
        modalVisible,
      };
    },
  });
</script>
<style lang="less" scoped>
  .sc-cron:deep(.el-tabs__item) {
    height: auto;
    line-height: 1;
    padding: 0 7px;
    vertical-align: bottom;
  }
  .cron-num {
    text-align: center;
    width: 100%;
  }
  .cron-num h2 {
    font-size: 12px;
    font-weight: normal;
  }
  .sc-cron:deep(.el-tabs__item.is-active) .cron-num h4 {
    background: var(--ant-primary-color);
    color: #fff;
  }

  [data-theme='dark'] .cron-num h4 {
    background: var(--ant-primary-color);
  }
</style>
