mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-10-14 11:21:29 +00:00
import codes
This commit is contained in:
765
src/components/DateCalendar.vue
Executable file
765
src/components/DateCalendar.vue
Executable file
@@ -0,0 +1,765 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<div :class="`${state.pre}`">
|
||||
<div :class="`${state.pre}-head`">
|
||||
<a
|
||||
:class="`${state.pre}-prev-decade-btn`"
|
||||
v-show="state.showYears"
|
||||
@click="state.year -= 10"
|
||||
>
|
||||
<Icon size="sm" iconName="angle-double-left" />
|
||||
</a>
|
||||
<a
|
||||
:class="`${state.pre}-prev-year-btn`"
|
||||
v-show="!state.showYears"
|
||||
@click="state.year--"
|
||||
>
|
||||
<Icon size="sm" iconName="angle-double-left" />
|
||||
</a>
|
||||
<a
|
||||
:class="`${state.pre}-prev-month-btn`"
|
||||
v-show="!state.showYears && !state.showMonths"
|
||||
@click="pm"
|
||||
>
|
||||
<Icon size="middle" iconName="chevron-left" />
|
||||
</a>
|
||||
<a :class="`${state.pre}-year-select`" v-show="state.showYears">{{
|
||||
ys + "-" + ye
|
||||
}}</a>
|
||||
<template v-if="local.yearSuffix">
|
||||
<a
|
||||
:class="`${state.pre}-year-select`"
|
||||
@click="state.showYears = !state.showYears"
|
||||
v-show="!state.showYears"
|
||||
>{{ state.year }}{{ local.yearSuffix }}</a
|
||||
>
|
||||
<a
|
||||
:class="`${state.pre}-month-select`"
|
||||
@click="state.showMonths = !state.showMonths"
|
||||
v-show="!state.showYears && !state.showMonths"
|
||||
>{{ local.monthsHead[state.month] }}</a
|
||||
>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a
|
||||
:class="`${state.pre}-month-select`"
|
||||
@click="state.showMonths = !state.showMonths"
|
||||
v-show="!state.showYears && !state.showMonths"
|
||||
>{{ local.monthsHead[state.month] }}</a
|
||||
>
|
||||
<a
|
||||
:class="`${state.pre}-year-select`"
|
||||
@click="state.showYears = !state.showYears"
|
||||
v-show="!state.showYears"
|
||||
>{{ state.year }}</a
|
||||
>
|
||||
</template>
|
||||
<a
|
||||
:class="`${state.pre}-next-month-btn`"
|
||||
v-show="!state.showYears && !state.showMonths"
|
||||
@click="nm"
|
||||
>
|
||||
<Icon size="middle" iconName="chevron-right" />
|
||||
</a>
|
||||
<a
|
||||
:class="`${state.pre}-next-year-btn`"
|
||||
v-show="!state.showYears"
|
||||
@click="state.year++"
|
||||
>
|
||||
<Icon size="sm" iconName="angle-double-right" />
|
||||
</a>
|
||||
<a
|
||||
:class="`${state.pre}-next-decade-btn`"
|
||||
v-show="state.showYears"
|
||||
@click="state.year += 10"
|
||||
>
|
||||
<Icon size="sm" iconName="angle-double-right" />
|
||||
</a>
|
||||
</div>
|
||||
<div :class="`${state.pre}-body`">
|
||||
<div :class="`${state.pre}-days`">
|
||||
<a :class="`${state.pre}-week`" v-for="i in local.weeks" :key="i">{{
|
||||
i
|
||||
}}</a>
|
||||
<a
|
||||
v-for="(j, i) in days"
|
||||
@click="is($event) && ((state.day = j.i), ok(j))"
|
||||
:class="[
|
||||
j.p || j.n ? `${state.pre}-date-out` : '',
|
||||
status(
|
||||
j.y,
|
||||
j.m,
|
||||
j.i,
|
||||
state.hour,
|
||||
state.minute,
|
||||
state.second,
|
||||
'YYYYMMDD'
|
||||
),
|
||||
]"
|
||||
:key="i"
|
||||
>{{ j.i }}</a
|
||||
>
|
||||
</div>
|
||||
<div :class="`${state.pre}-months`" v-show="state.showMonths">
|
||||
<a
|
||||
v-for="(i, j) in local.months"
|
||||
@click="
|
||||
is($event) &&
|
||||
((state.showMonths = m === 'M'),
|
||||
(state.month = j),
|
||||
m === 'M' && ok('m'))
|
||||
"
|
||||
:class="[
|
||||
status(
|
||||
state.year,
|
||||
j,
|
||||
state.day,
|
||||
state.hour,
|
||||
state.minute,
|
||||
state.second,
|
||||
'YYYYMM'
|
||||
),
|
||||
]"
|
||||
:key="j"
|
||||
>{{ i }}</a
|
||||
>
|
||||
</div>
|
||||
<div :class="`${state.pre}-years`" v-show="state.showYears">
|
||||
<a
|
||||
v-for="(i, j) in years"
|
||||
@click="
|
||||
is($event) &&
|
||||
((state.showYears = m === 'Y'),
|
||||
(state.year = i),
|
||||
state.m === 'Y' && ok('y'))
|
||||
"
|
||||
:class="[
|
||||
j === 0 || j === 11 ? `${state.pre}-date-out` : '',
|
||||
status(
|
||||
i,
|
||||
state.month,
|
||||
state.day,
|
||||
state.hour,
|
||||
state.minute,
|
||||
state.second,
|
||||
'YYYY'
|
||||
),
|
||||
]"
|
||||
:key="j"
|
||||
>{{ i }}</a
|
||||
>
|
||||
</div>
|
||||
<div :class="`${state.pre}-hours scroll_hide`" v-show="state.showHours">
|
||||
<div :class="`${state.pre}-title`">{{ local.hourTip }}</div>
|
||||
<div class="scroll_hide calendar-overflow">
|
||||
<a
|
||||
v-for="(j, i) in 24"
|
||||
@click="
|
||||
is($event) &&
|
||||
((state.showHours = false), (state.hour = i), ok('h'))
|
||||
"
|
||||
:class="[
|
||||
status(
|
||||
state.year,
|
||||
state.month,
|
||||
state.day,
|
||||
i,
|
||||
state.minute,
|
||||
state.second,
|
||||
'YYYYMMDDHH'
|
||||
),
|
||||
]"
|
||||
:key="i"
|
||||
>{{ i }}</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="`${state.pre}-minutes`" v-show="state.showMinutes">
|
||||
<div :class="`${state.pre}-title`">{{ local.minuteTip }}</div>
|
||||
<div class="scroll_hide calendar-overflow">
|
||||
<a
|
||||
v-for="(j, i) in 60"
|
||||
@click="
|
||||
is($event) &&
|
||||
((state.showMinutes = false), (state.minute = i), ok('h'))
|
||||
"
|
||||
:class="[
|
||||
status(
|
||||
state.year,
|
||||
state.month,
|
||||
state.day,
|
||||
state.hour,
|
||||
i,
|
||||
state.second,
|
||||
'YYYYMMDDHHmm'
|
||||
),
|
||||
]"
|
||||
:key="i"
|
||||
>{{ i }}</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="`${state.pre}-seconds`" v-show="state.showSeconds">
|
||||
<div :class="`${state.pre}-title`">{{ local.secondTip }}</div>
|
||||
<div class="scroll_hide calendar-overflow">
|
||||
<a
|
||||
v-for="(j, i) in 60"
|
||||
@click="
|
||||
is($event) &&
|
||||
((state.showSeconds = false), (state.second = i), ok('h'))
|
||||
"
|
||||
:class="[
|
||||
status(
|
||||
state.year,
|
||||
state.month,
|
||||
state.day,
|
||||
state.hour,
|
||||
state.minute,
|
||||
i,
|
||||
'YYYYMMDDHHmmss'
|
||||
),
|
||||
]"
|
||||
:key="i"
|
||||
>{{ i }}</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="`${state.pre}-foot`">
|
||||
<div :class="`${state.pre}-hour`">
|
||||
<a
|
||||
:title="local.hourTip"
|
||||
@click="
|
||||
(state.showHours = !state.showHours),
|
||||
(state.showMinutes = state.showSeconds = false)
|
||||
"
|
||||
:class="{ on: state.showHours }"
|
||||
>{{ state.hour || dd }}</a
|
||||
>
|
||||
<span>:</span>
|
||||
<a
|
||||
:title="local.minuteTip"
|
||||
@click="
|
||||
(state.showMinutes = !state.showMinutes),
|
||||
(state.showHours = state.showSeconds = false)
|
||||
"
|
||||
:class="{ on: state.showMinutes }"
|
||||
>{{ state.minute || dd }}</a
|
||||
>
|
||||
<span v-show="state.m !== 'D'">
|
||||
<span>:</span>
|
||||
<a
|
||||
:title="local.secondTip"
|
||||
@click="
|
||||
(state.showSeconds = !state.showSeconds),
|
||||
(state.showHours = state.showMinutes = false)
|
||||
"
|
||||
:class="{ on: state.showSeconds }"
|
||||
>{{ state.second || dd }}</a
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
defineProps,
|
||||
computed,
|
||||
defineEmits,
|
||||
onMounted,
|
||||
watch,
|
||||
reactive,
|
||||
} from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
const emit = defineEmits(["input", "setDates", "ok"]);
|
||||
const { t } = useI18n();
|
||||
const props = defineProps({
|
||||
value: { type: Date },
|
||||
left: { type: Boolean, default: false },
|
||||
right: { type: Boolean, default: false },
|
||||
dates: { default: [] },
|
||||
disabledDate: { type: Function, default: () => false },
|
||||
format: {
|
||||
type: String,
|
||||
default: "YYYY-MM-DD",
|
||||
},
|
||||
});
|
||||
const state = reactive({
|
||||
pre: "",
|
||||
m: "",
|
||||
showYears: false,
|
||||
showMonths: false,
|
||||
showHours: false,
|
||||
showMinutes: false,
|
||||
showSeconds: false,
|
||||
year: 0,
|
||||
month: 0,
|
||||
day: 0,
|
||||
hour: 0,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
});
|
||||
const get = (time: Date): { [key: string]: any } => {
|
||||
return {
|
||||
year: time.getFullYear(),
|
||||
month: time.getMonth(),
|
||||
day: time.getDate(),
|
||||
hour: time.getHours(),
|
||||
minute: time.getMinutes(),
|
||||
second: time.getSeconds(),
|
||||
};
|
||||
};
|
||||
if (props.value) {
|
||||
const time = get(props.value);
|
||||
state.pre = "calendar";
|
||||
state.m = "D";
|
||||
state.showYears = false;
|
||||
state.showMonths = false;
|
||||
state.showHours = false;
|
||||
state.showMinutes = false;
|
||||
state.showSeconds = false;
|
||||
state.year = time.year;
|
||||
state.month = time.month;
|
||||
state.day = time.day;
|
||||
state.hour = time.hour;
|
||||
state.minute = time.minute;
|
||||
state.second = time.second;
|
||||
}
|
||||
watch(
|
||||
() => props.value,
|
||||
(val: Date | undefined) => {
|
||||
if (!val) {
|
||||
return;
|
||||
}
|
||||
const time = get(val);
|
||||
state.year = time.year;
|
||||
state.month = time.month;
|
||||
state.day = time.day;
|
||||
state.hour = time.hour;
|
||||
state.minute = time.minute;
|
||||
state.second = time.second;
|
||||
}
|
||||
);
|
||||
const parse = (num: number): number => {
|
||||
return Math.floor(num / 1000);
|
||||
};
|
||||
const start = computed(() => {
|
||||
return parse(props.dates[0]);
|
||||
});
|
||||
const end = computed(() => {
|
||||
return parse(props.dates[1]);
|
||||
});
|
||||
const ys = computed(() => {
|
||||
return Math.floor(state.year / 10) * 10;
|
||||
});
|
||||
const ye = computed(() => {
|
||||
return ys.value + 10;
|
||||
});
|
||||
const years = computed(() => {
|
||||
const arr = [];
|
||||
let start = ys.value - 1;
|
||||
while (arr.length < 12) {
|
||||
arr.push((start += 1));
|
||||
}
|
||||
return arr;
|
||||
});
|
||||
const local = computed(() => {
|
||||
return {
|
||||
dow: 1, // Monday is the first day of the week
|
||||
hourTip: t("hourTip"), // tip of select hour
|
||||
minuteTip: t("minuteTip"), // tip of select minute
|
||||
secondTip: t("secondTip"), // tip of select second
|
||||
yearSuffix: t("yearSuffix"), // format of head
|
||||
monthsHead: t("monthsHead").split("_"), // months of head
|
||||
months: t("months").split("_"), // months of panel
|
||||
weeks: t("weeks").split("_"), // weeks
|
||||
cancelTip: t("cancel"), // default text for cancel button
|
||||
submitTip: t("confirm"), // default text for submit button
|
||||
quarterHourCutTip: t("quarterHourCutTip"),
|
||||
halfHourCutTip: t("halfHourCutTip"),
|
||||
hourCutTip: t("hourCutTip"),
|
||||
dayCutTip: t("dayCutTip"),
|
||||
weekCutTip: t("weekCutTip"),
|
||||
monthCutTip: t("monthCutTip"),
|
||||
};
|
||||
});
|
||||
const days = computed(() => {
|
||||
const days = [];
|
||||
const year = state.year;
|
||||
const month = state.month;
|
||||
const time = new Date(year, month, 1);
|
||||
const dow = local.value.dow || 7;
|
||||
time.setDate(0); // switch to the last day of last month
|
||||
let lastDay = time.getDate();
|
||||
const week = time.getDay() || 7;
|
||||
let count = dow <= week ? week - dow + 1 : week + (7 - dow + 1);
|
||||
while (count > 0) {
|
||||
days.push({
|
||||
i: lastDay - count + 1,
|
||||
y: month > 0 ? year : year - 1,
|
||||
m: month > 0 ? month - 1 : 11,
|
||||
p: true,
|
||||
});
|
||||
count--;
|
||||
}
|
||||
time.setMonth(time.getMonth() + 2, 0); // switch to the last day of the current month
|
||||
lastDay = time.getDate();
|
||||
let i = 1;
|
||||
for (i = 1; i <= lastDay; i++) {
|
||||
days.push({
|
||||
i: i,
|
||||
y: year,
|
||||
m: month,
|
||||
});
|
||||
}
|
||||
for (i = 1; days.length < 42; i++) {
|
||||
days.push({
|
||||
i: i,
|
||||
y: month < 11 ? year : year + 1,
|
||||
m: month < 11 ? month + 1 : 0,
|
||||
n: true,
|
||||
});
|
||||
}
|
||||
return days;
|
||||
});
|
||||
const dd = (val: number) => ("0" + val).slice(-2);
|
||||
const status = (
|
||||
year: number,
|
||||
month: number,
|
||||
day: number,
|
||||
hour: number,
|
||||
minute: number,
|
||||
second: number,
|
||||
format: string
|
||||
) => {
|
||||
const maxDay = new Date(year, month + 1, 0).getDate();
|
||||
const time: any = new Date(
|
||||
year,
|
||||
month,
|
||||
day > maxDay ? maxDay : day,
|
||||
hour,
|
||||
minute,
|
||||
second
|
||||
);
|
||||
const t = parse(time);
|
||||
const tf = (time?: Date, format?: any): string => {
|
||||
if (!time) {
|
||||
return "";
|
||||
}
|
||||
const year = time.getFullYear();
|
||||
const month = time.getMonth();
|
||||
const day = time.getDate();
|
||||
const hours24 = time.getHours();
|
||||
const hours = hours24 % 12 === 0 ? 12 : hours24 % 12;
|
||||
const minutes = time.getMinutes();
|
||||
const seconds = time.getSeconds();
|
||||
const milliseconds = time.getMilliseconds();
|
||||
const dd = (t: number) => `0${t}`.slice(-2);
|
||||
const map: { [key: string]: string | number } = {
|
||||
YYYY: year,
|
||||
MM: dd(month + 1),
|
||||
MMM: local.value.months[month],
|
||||
MMMM: local.value.monthsHead[month],
|
||||
M: month + 1,
|
||||
DD: dd(day),
|
||||
D: day,
|
||||
HH: dd(hours24),
|
||||
H: hours24,
|
||||
hh: dd(hours),
|
||||
h: hours,
|
||||
mm: dd(minutes),
|
||||
m: minutes,
|
||||
ss: dd(seconds),
|
||||
s: seconds,
|
||||
S: milliseconds,
|
||||
};
|
||||
return (format || props.format).replace(
|
||||
/Y+|M+|D+|H+|h+|m+|s+|S+/g,
|
||||
(str: string) => map[str]
|
||||
);
|
||||
};
|
||||
const classObj: any = {};
|
||||
let flag = false;
|
||||
if (format === "YYYY") {
|
||||
flag = year === state.year;
|
||||
} else if (format === "YYYYMM") {
|
||||
flag = month === state.month;
|
||||
} else {
|
||||
flag = tf(props.value, format) === tf(time, format);
|
||||
}
|
||||
classObj[`${state.pre}-date`] = true;
|
||||
classObj[`${state.pre}-date-disabled`] =
|
||||
(props.right && t < start.value) || props.disabledDate(time, format);
|
||||
classObj[`${state.pre}-date-on`] =
|
||||
(props.left && t > start.value) || (props.right && t < end.value);
|
||||
classObj[`${state.pre}-date-selected`] = flag;
|
||||
return classObj;
|
||||
};
|
||||
const nm = () => {
|
||||
if (state.month < 11) {
|
||||
state.month++;
|
||||
} else {
|
||||
state.month = 0;
|
||||
state.year++;
|
||||
}
|
||||
};
|
||||
const pm = () => {
|
||||
if (state.month > 0) {
|
||||
state.month--;
|
||||
} else {
|
||||
state.month = 11;
|
||||
state.year--;
|
||||
}
|
||||
};
|
||||
const is = (e: any) => {
|
||||
return e.target.className.indexOf(`${state.pre}-date-disabled`) === -1;
|
||||
};
|
||||
const ok = (info: any) => {
|
||||
let year = "";
|
||||
let month = "";
|
||||
let day = "";
|
||||
info && info.n && nm();
|
||||
info && info.p && pm();
|
||||
if (info === "h") {
|
||||
if (props.value) {
|
||||
const time = get(props.value);
|
||||
year = time.year;
|
||||
month = time.month;
|
||||
}
|
||||
} else if (info === "m" || info === "y") {
|
||||
day = "1";
|
||||
}
|
||||
const _time: Date = new Date(
|
||||
year ? Number(year) : state.year,
|
||||
month ? Number(month) : state.month,
|
||||
day ? Number(day) : state.day,
|
||||
state.hour,
|
||||
state.minute,
|
||||
state.second
|
||||
);
|
||||
if (props.left && Math.floor(_time.getTime() / 1000) > end.value) {
|
||||
emit("setDates", _time);
|
||||
}
|
||||
emit("input", _time);
|
||||
ok(info === "h");
|
||||
};
|
||||
onMounted(() => {
|
||||
const is = (c: string) => props.format.indexOf(c) !== -1;
|
||||
if (is("s") && is("m") && (is("h") || is("H"))) {
|
||||
state.m = "H";
|
||||
} else if (is("D")) {
|
||||
state.m = "D";
|
||||
} else if (is("M")) {
|
||||
state.m = "M";
|
||||
state.showMonths = true;
|
||||
} else if (is("Y")) {
|
||||
state.m = "Y";
|
||||
state.showYears = true;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.calendar {
|
||||
float: left;
|
||||
user-select: none;
|
||||
color: #3d444f;
|
||||
}
|
||||
.calendar + .calendar {
|
||||
border-left: solid 1px #eaeaea;
|
||||
margin-left: 5px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
.calendar-head {
|
||||
line-height: 34px;
|
||||
height: 34px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.calendar-head a {
|
||||
color: #666;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
padding: 0 5px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.calendar-head a:hover {
|
||||
color: #3f97e3;
|
||||
}
|
||||
|
||||
.calendar-head .calendar-year-select,
|
||||
.calendar-head .calendar-month-select {
|
||||
font-size: 12px;
|
||||
padding: 0 2px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.calendar-prev-decade-btn,
|
||||
.calendar-prev-year-btn {
|
||||
left: 6px;
|
||||
}
|
||||
|
||||
.calendar-prev-month-btn {
|
||||
left: 24px;
|
||||
}
|
||||
|
||||
.calendar-next-decade-btn,
|
||||
.calendar-next-year-btn {
|
||||
right: 6px;
|
||||
}
|
||||
|
||||
.calendar-next-month-btn {
|
||||
right: 24px;
|
||||
}
|
||||
.calendar-next-month-btn .middle,
|
||||
.calendar-prev-month-btn .middle {
|
||||
margin-top: 8px;
|
||||
}
|
||||
.calendar-body {
|
||||
position: relative;
|
||||
width: 196px;
|
||||
height: 196px;
|
||||
}
|
||||
|
||||
.calendar-days {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.calendar-week,
|
||||
.calendar-date {
|
||||
font-weight: normal;
|
||||
width: 14.28%;
|
||||
height: 14.28%;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.calendar-week:before,
|
||||
.calendar-date:before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.calendar-date {
|
||||
cursor: pointer;
|
||||
line-height: 29px;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.calendar-date-out {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.calendar-date:hover,
|
||||
.calendar-date-on {
|
||||
color: #3f97e3;
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.calendar-date-selected,
|
||||
.calendar-date-selected:hover {
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
border-radius: 14px;
|
||||
background: #3f97e3;
|
||||
}
|
||||
|
||||
.calendar-date-disabled {
|
||||
cursor: not-allowed !important;
|
||||
color: #ccc !important;
|
||||
background: #fff !important;
|
||||
}
|
||||
|
||||
.calendar-foot {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.calendar-hour {
|
||||
display: inline-block;
|
||||
border: 1px solid #e6e5e5;
|
||||
color: #9e9e9e;
|
||||
}
|
||||
|
||||
.calendar-hour a {
|
||||
display: inline-block;
|
||||
padding: 2px 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.calendar-hour a:hover,
|
||||
.calendar-hour a.on {
|
||||
color: #3f97e3;
|
||||
}
|
||||
|
||||
.calendar-years,
|
||||
.calendar-months,
|
||||
.calendar-hours,
|
||||
.calendar-minutes,
|
||||
.calendar-seconds {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
background: #fff;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.calendar-months a {
|
||||
width: 33.33%;
|
||||
height: 25%;
|
||||
}
|
||||
|
||||
.calendar-years a {
|
||||
width: 33.33%;
|
||||
height: 25%;
|
||||
}
|
||||
|
||||
.calendar-overflow {
|
||||
overflow-x: scroll;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* .calendar-hours a {
|
||||
width: 20%;
|
||||
height: 20%;
|
||||
}
|
||||
|
||||
.calendar-minutes a,
|
||||
.calendar-seconds a {
|
||||
width: 16.66%;
|
||||
height: 10%;
|
||||
} */
|
||||
|
||||
.calendar-title {
|
||||
margin-top: -30px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
background: #fff;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
69
src/components/Icon.vue
Normal file
69
src/components/Icon.vue
Normal file
@@ -0,0 +1,69 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<svg
|
||||
class="icon"
|
||||
:class="{
|
||||
sm: size === 'sm',
|
||||
middle: size === 'middle',
|
||||
lg: size === 'lg',
|
||||
xl: size === 'xl',
|
||||
logo: size === 'logo',
|
||||
loading: loading,
|
||||
}"
|
||||
>
|
||||
<use :xlink:href="`#${iconName}`"></use>
|
||||
</svg>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps } from "vue";
|
||||
import "@/assets/icons/index";
|
||||
defineProps({
|
||||
iconName: { type: String, default: "" },
|
||||
size: { type: String, default: "sm" },
|
||||
loading: { type: Boolean, default: false },
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scope>
|
||||
.icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
vertical-align: middle;
|
||||
fill: currentColor;
|
||||
&.sm {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
&.middle {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
&.lg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
&.loading {
|
||||
animation: loading 1.5s linear infinite;
|
||||
}
|
||||
&.logo {
|
||||
height: 30px;
|
||||
width: 110px;
|
||||
}
|
||||
&.xl {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
}
|
||||
}
|
||||
</style>
|
570
src/components/TimePicker.vue
Executable file
570
src/components/TimePicker.vue
Executable file
@@ -0,0 +1,570 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<div
|
||||
class="datepicker cp"
|
||||
:class="{
|
||||
'datepicker-range': range,
|
||||
datepicker__clearable: clearable && text && !disabled,
|
||||
}"
|
||||
ref="datepicker"
|
||||
>
|
||||
<input
|
||||
class="cp"
|
||||
readonly
|
||||
:value="text"
|
||||
:class="[show ? 'focus' : '', inputClass]"
|
||||
:disabled="disabled"
|
||||
:placeholder="placeholder"
|
||||
:name="name"
|
||||
v-if="type !== 'inline'"
|
||||
/>
|
||||
<a class="datepicker-close" @click.stop="cls"></a>
|
||||
<transition name="datepicker-anim">
|
||||
<div
|
||||
class="datepicker-popup"
|
||||
:class="[
|
||||
popupClass,
|
||||
{ 'datepicker-inline': type === 'inline' },
|
||||
position,
|
||||
]"
|
||||
tabindex="-1"
|
||||
v-if="show || type === 'inline'"
|
||||
>
|
||||
<template v-if="range">
|
||||
<div class="datepicker-popup__sidebar">
|
||||
<button
|
||||
type="button"
|
||||
class="datepicker-popup__shortcut"
|
||||
@click="quickPick('quarter')"
|
||||
>
|
||||
{{ local.quarterHourCutTip }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="datepicker-popup__shortcut"
|
||||
@click="quickPick('half')"
|
||||
>
|
||||
{{ local.halfHourCutTip }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="datepicker-popup__shortcut"
|
||||
@click="quickPick('hour')"
|
||||
>
|
||||
{{ local.hourCutTip }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="datepicker-popup__shortcut"
|
||||
@click="quickPick('day')"
|
||||
>
|
||||
{{ local.dayCutTip }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="datepicker-popup__shortcut"
|
||||
@click="quickPick('week')"
|
||||
>
|
||||
{{ local.weekCutTip }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="datepicker-popup__shortcut"
|
||||
@click="quickPick('month')"
|
||||
>
|
||||
{{ local.monthCutTip }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="datepicker-popup__body">
|
||||
<DateCalendar
|
||||
v-model="dates[0]"
|
||||
:value="dates[0]"
|
||||
:dates="dates"
|
||||
:left="true"
|
||||
:disabledDate="disabledDate"
|
||||
:format="format"
|
||||
@ok="ok"
|
||||
@setDates="setDates"
|
||||
/>
|
||||
<DateCalendar
|
||||
v-model="dates[1]"
|
||||
:value="dates[1]"
|
||||
:dates="dates"
|
||||
:right="true"
|
||||
:disabledDate="disabledDate"
|
||||
:format="format"
|
||||
@ok="ok"
|
||||
@setDates="setDates"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<DateCalendar
|
||||
v-model="dates[0]"
|
||||
:value="dates[0]"
|
||||
:disabledDate="disabledDate"
|
||||
:dates="dates"
|
||||
:format="format"
|
||||
@ok="ok"
|
||||
@setDates="setDates"
|
||||
/>
|
||||
</template>
|
||||
<div v-if="showButtons" class="datepicker__buttons">
|
||||
<button
|
||||
@click.prevent.stop="cancel"
|
||||
class="datepicker__button-cancel"
|
||||
>
|
||||
{{ local.cancelTip }}
|
||||
</button>
|
||||
<button
|
||||
@click.prevent.stop="submit"
|
||||
class="datepicker__button-select"
|
||||
>
|
||||
{{ local.submitTip }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
defineProps,
|
||||
ref,
|
||||
computed,
|
||||
defineEmits,
|
||||
onMounted,
|
||||
onBeforeUnmount,
|
||||
watch,
|
||||
} from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import DateCalendar from "./DateCalendar.vue";
|
||||
const datepicker = ref(null);
|
||||
const { t } = useI18n();
|
||||
const show = ref<boolean>(false);
|
||||
const dates = ref<Date[]>([]);
|
||||
const props = defineProps({
|
||||
position: { type: String, default: "bottom" },
|
||||
name: [String],
|
||||
inputClass: [String],
|
||||
popupClass: [String],
|
||||
value: [Date, Array, String],
|
||||
disabled: [Boolean],
|
||||
type: {
|
||||
type: String,
|
||||
default: "normal",
|
||||
},
|
||||
rangeSeparator: {
|
||||
type: String,
|
||||
default: "~",
|
||||
},
|
||||
clearable: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
placeholder: [String],
|
||||
disabledDate: {
|
||||
type: Function,
|
||||
default: () => false,
|
||||
},
|
||||
format: {
|
||||
type: String,
|
||||
default: "YYYY-MM-DD",
|
||||
},
|
||||
showButtons: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
dateRangeSelect: [Function],
|
||||
});
|
||||
const emit = defineEmits(["clear", "input", "confirm", "cancel"]);
|
||||
const local = computed(() => {
|
||||
return {
|
||||
dow: 1, // Monday is the first day of the week
|
||||
hourTip: t("hourTip"), // tip of select hour
|
||||
minuteTip: t("minuteTip"), // tip of select minute
|
||||
secondTip: t("secondTip"), // tip of select second
|
||||
yearSuffix: t("yearSuffix"), // format of head
|
||||
monthsHead: t("monthsHead").split("_"), // months of head
|
||||
months: t("months").split("_"), // months of panel
|
||||
weeks: t("weeks").split("_"), // weeks
|
||||
cancelTip: t("cancel"), // default text for cancel button
|
||||
submitTip: t("confirm"), // default text for submit button
|
||||
quarterHourCutTip: t("quarterHourCutTip"),
|
||||
halfHourCutTip: t("halfHourCutTip"),
|
||||
hourCutTip: t("hourCutTip"),
|
||||
dayCutTip: t("dayCutTip"),
|
||||
weekCutTip: t("weekCutTip"),
|
||||
monthCutTip: t("monthCutTip"),
|
||||
};
|
||||
});
|
||||
const tf = (time: Date, format?: any): string => {
|
||||
const year = time.getFullYear();
|
||||
const month = time.getMonth();
|
||||
const day = time.getDate();
|
||||
const hours24 = time.getHours();
|
||||
const hours = hours24 % 12 === 0 ? 12 : hours24 % 12;
|
||||
const minutes = time.getMinutes();
|
||||
const seconds = time.getSeconds();
|
||||
const milliseconds = time.getMilliseconds();
|
||||
const dd = (t: number) => `0${t}`.slice(-2);
|
||||
const map: { [key: string]: string | number } = {
|
||||
YYYY: year,
|
||||
MM: dd(month + 1),
|
||||
MMM: local.value.months[month],
|
||||
MMMM: local.value.monthsHead[month],
|
||||
M: month + 1,
|
||||
DD: dd(day),
|
||||
D: day,
|
||||
HH: dd(hours24),
|
||||
H: hours24,
|
||||
hh: dd(hours),
|
||||
h: hours,
|
||||
mm: dd(minutes),
|
||||
m: minutes,
|
||||
ss: dd(seconds),
|
||||
s: seconds,
|
||||
S: milliseconds,
|
||||
};
|
||||
return (format || props.format).replace(
|
||||
/Y+|M+|D+|H+|h+|m+|s+|S+/g,
|
||||
(str: string) => map[str]
|
||||
);
|
||||
};
|
||||
const range = computed(() => {
|
||||
return dates.value.length === 2;
|
||||
});
|
||||
const text = computed(() => {
|
||||
const val = props.value;
|
||||
const txt = dates.value
|
||||
.map((date) => tf(date))
|
||||
.join(` ${props.rangeSeparator} `);
|
||||
if (Array.isArray(val)) {
|
||||
return val.length > 1 ? txt : "";
|
||||
}
|
||||
return val ? txt : "";
|
||||
});
|
||||
const get = () => {
|
||||
return Array.isArray(props.value) ? dates.value : dates.value[0];
|
||||
};
|
||||
const cls = () => {
|
||||
emit("clear");
|
||||
emit("input", range.value ? [] : "");
|
||||
};
|
||||
const vi = (val: any) => {
|
||||
if (Array.isArray(val)) {
|
||||
return val.length > 1
|
||||
? val.map((item) => new Date(item))
|
||||
: [new Date(), new Date()];
|
||||
}
|
||||
return val ? [new Date(val)] : [new Date()];
|
||||
};
|
||||
const ok = (leaveOpened: boolean) => {
|
||||
emit("input", get());
|
||||
!leaveOpened &&
|
||||
!props.showButtons &&
|
||||
setTimeout(() => {
|
||||
show.value = range.value;
|
||||
});
|
||||
};
|
||||
const setDates = (d: Date) => {
|
||||
dates.value[1] = d;
|
||||
};
|
||||
const dc = (e: any) => {
|
||||
show.value = (datepicker.value as any).contains(e.target) && !props.disabled;
|
||||
};
|
||||
const quickPick = (type: string) => {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
switch (type) {
|
||||
case "quarter":
|
||||
start.setTime(start.getTime() - 60 * 15 * 1000); //15 mins
|
||||
break;
|
||||
case "half":
|
||||
start.setTime(start.getTime() - 60 * 30 * 1000); //30 mins
|
||||
break;
|
||||
case "hour":
|
||||
start.setTime(start.getTime() - 3600 * 1000); //1 hour
|
||||
break;
|
||||
case "day":
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24); //1 day
|
||||
break;
|
||||
case "week":
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7); //1 week
|
||||
break;
|
||||
case "month":
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30); //1 month
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
dates.value = [start, end];
|
||||
emit("input", get());
|
||||
};
|
||||
const submit = () => {
|
||||
emit("confirm", get());
|
||||
show.value = false;
|
||||
};
|
||||
const cancel = () => {
|
||||
emit("cancel");
|
||||
show.value = false;
|
||||
};
|
||||
onMounted(() => {
|
||||
dates.value = vi(props.value);
|
||||
document.addEventListener("click", dc, true);
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
document.removeEventListener("click", dc, true);
|
||||
});
|
||||
watch(
|
||||
() => props.value,
|
||||
(val: unknown) => {
|
||||
dates.value = vi(val);
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.datepicker {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.datepicker-icon {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 8px;
|
||||
color: #515a6ecc;
|
||||
}
|
||||
|
||||
.datepicker-close {
|
||||
display: none;
|
||||
position: absolute;
|
||||
width: 34px;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
right: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.datepicker-close:before {
|
||||
display: block;
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
margin-left: -8px;
|
||||
margin-top: -8px;
|
||||
text-align: center;
|
||||
background: #ccc;
|
||||
color: #fff;
|
||||
border-radius: 50%;
|
||||
background: #ccc
|
||||
url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA3IDciIHdpZHRoPSI3IiBoZWlnaHQ9IjciPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik01LjU4LDVsMi44LTIuODFBLjQxLjQxLDAsMSwwLDcuOCwxLjZMNSw0LjQxLDIuMiwxLjZhLjQxLjQxLDAsMCwwLS41OC41OGgwTDQuNDIsNSwxLjYyLDcuOGEuNDEuNDEsMCwwLDAsLjU4LjU4TDUsNS41OCw3LjgsOC4zOWEuNDEuNDEsMCwwLDAsLjU4LS41OGgwWiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTEuNSAtMS40OCkiIHN0eWxlPSJmaWxsOiNmZmYiLz48L3N2Zz4NCg==")
|
||||
no-repeat 50% 50%;
|
||||
}
|
||||
|
||||
.datepicker__clearable:hover:before {
|
||||
display: none;
|
||||
}
|
||||
.datepicker__clearable:hover .datepicker-close {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.datepicker-close:hover:before {
|
||||
background-color: #afafaf;
|
||||
}
|
||||
|
||||
.datepicker > input {
|
||||
color: inherit;
|
||||
// transition: all 200ms ease;
|
||||
border-radius: 4px;
|
||||
border: 0;
|
||||
background: none;
|
||||
height: 28px;
|
||||
box-sizing: border-box;
|
||||
outline: none;
|
||||
padding: 0 5px;
|
||||
width: 100%;
|
||||
user-select: none;
|
||||
font-family: "Monaco";
|
||||
letter-spacing: -0.7px;
|
||||
}
|
||||
|
||||
// .datepicker > input.focus {
|
||||
// border-color: #3f97e3;
|
||||
// -webkit-box-shadow: 0 0 5px rgba(59, 180, 242, 0.3);
|
||||
// box-shadow: 0 0 5px rgba(59, 180, 242, 0.3);
|
||||
// }
|
||||
|
||||
.datepicker > input:disabled {
|
||||
cursor: not-allowed;
|
||||
background-color: #ebebe4;
|
||||
border-color: #e5e5e5;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.datepicker-popup {
|
||||
border-radius: 4px;
|
||||
position: absolute;
|
||||
transition: all 200ms ease;
|
||||
opacity: 1;
|
||||
transform: scaleY(1);
|
||||
font-size: 12px;
|
||||
background: #fff;
|
||||
box-shadow: 0 1px 6px rgba(99, 99, 99, 0.2);
|
||||
margin-top: 2px;
|
||||
outline: 0;
|
||||
padding: 5px;
|
||||
overflow: hidden;
|
||||
z-index: 999;
|
||||
&.top {
|
||||
bottom: 30px;
|
||||
right: 0;
|
||||
transform-origin: center bottom;
|
||||
}
|
||||
&.bottom {
|
||||
top: 30px;
|
||||
right: 0;
|
||||
transform-origin: center top;
|
||||
}
|
||||
&.left {
|
||||
top: 30px;
|
||||
transform-origin: center top;
|
||||
}
|
||||
&.right {
|
||||
right: -80px;
|
||||
top: 30px;
|
||||
transform-origin: center top;
|
||||
}
|
||||
&__sidebar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 100px;
|
||||
height: 100%;
|
||||
padding: 5px;
|
||||
border-right: solid 1px #eaeaea;
|
||||
}
|
||||
&__shortcut {
|
||||
display: block;
|
||||
width: 100%;
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
line-height: 34px;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
text-align: left;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
&:hover {
|
||||
color: #3f97e3;
|
||||
}
|
||||
}
|
||||
&__body {
|
||||
margin-left: 100px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker-inline {
|
||||
position: relative;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.datepicker-range {
|
||||
min-width: 238px;
|
||||
}
|
||||
|
||||
.datepicker-range .datepicker-popup {
|
||||
width: 520px;
|
||||
}
|
||||
|
||||
.datepicker-bottom {
|
||||
float: left;
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.datepicker-btn {
|
||||
padding: 5px 10px;
|
||||
background: #3f97e3;
|
||||
color: #fff;
|
||||
border-radius: 2px;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
}
|
||||
.datepicker-anim-enter-active {
|
||||
transform-origin: 0 0;
|
||||
animation: datepicker-anim-in 0.2s cubic-bezier(0.23, 1, 0.32, 1);
|
||||
}
|
||||
|
||||
.datepicker-anim-leave-active {
|
||||
transform-origin: 0 0;
|
||||
animation: datepicker-anim-out 0.2s cubic-bezier(0.755, 0.05, 0.855, 0.06);
|
||||
}
|
||||
|
||||
.datepicker__buttons {
|
||||
display: block;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.datepicker__buttons button {
|
||||
display: inline-block;
|
||||
font-size: 13px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
margin: 10px 0 0 5px;
|
||||
padding: 5px 15px;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.datepicker__buttons .datepicker__button-select {
|
||||
background: #3f97e3;
|
||||
}
|
||||
|
||||
.datepicker__buttons .datepicker__button-cancel {
|
||||
background: #666;
|
||||
}
|
||||
|
||||
@keyframes datepicker-anim-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: scaleY(0.8);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scaleY(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes datepicker-anim-out {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: scaleY(1);
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: scaleY(0.8);
|
||||
}
|
||||
}
|
||||
</style>
|
30
src/components/index.ts
Normal file
30
src/components/index.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import Icon from "./Icon.vue";
|
||||
import TimePicker from "./TimePicker.vue";
|
||||
import type { App } from "vue";
|
||||
|
||||
const components: { [key: string]: any } = { Icon, TimePicker };
|
||||
const componentsName: string[] = Object.keys(components);
|
||||
|
||||
export default {
|
||||
install: (vue: App): void => {
|
||||
componentsName.forEach((i) => {
|
||||
vue.component(i, components[i]);
|
||||
});
|
||||
},
|
||||
};
|
Reference in New Issue
Block a user