@ql-web/view-report 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/view-report.css +223 -1
- package/view-report.es.js +449 -232
- package/view-report.umd.js +578 -1
package/view-report.umd.js
CHANGED
|
@@ -1 +1,578 @@
|
|
|
1
|
-
(function(h,r){typeof exports=="object"&&typeof module<"u"?r(exports,require("vue-demi")):typeof define=="function"&&define.amd?define(["exports","vue-demi"],r):(h=typeof globalThis<"u"?globalThis:h||self,r(h["view-report"]={},h.VueDemi))})(this,(function(h,r){"use strict";function D(l,e,t,a,f,v,m,i){var s=typeof l=="function"?l.options:l;return e&&(s.render=e,s.staticRenderFns=t,s._compiled=!0),v&&(s._scopeId="data-v-"+v),{exports:l,options:s}}const Y=r.defineComponent({name:"MyButton",props:{text:{type:String,default:"默认按钮"},color:{type:String,default:"#409eff"}},setup(l,{emit:e}){return{handleClick:()=>{e("click","按钮被点击")}}}});var P=function(){var e=this,t=e._self._c;return e._self._setupProxy,t("button",{staticClass:"my-button",style:{background:e.color},on:{click:e.handleClick}},[e._t("default",function(){return[e._v(e._s(e.text))]})],2)},x=[],S=D(Y,P,x,!1,null,"d19bd5c3");const k=S.exports;class d{static formatDate(e){if(!e||!(e instanceof Date)||isNaN(e.getTime()))return"";const t=e.getFullYear(),a=String(e.getMonth()+1).padStart(2,"0"),f=String(e.getDate()).padStart(2,"0");return`${t}-${a}-${f}`}static getFirstDayOfMonth(e){return new Date(e.getFullYear(),e.getMonth(),1)}static getLastDayOfMonth(e){return new Date(e.getFullYear(),e.getMonth()+1,0)}static getDayOfWeek(e){return e.getDay()}static getPrevMonth(e){const t=e.getMonth()===0?e.getFullYear()-1:e.getFullYear(),a=e.getMonth()===0?11:e.getMonth()-1;return new Date(t,a,1)}static getNextMonth(e){const t=e.getMonth()===11?e.getFullYear()+1:e.getFullYear(),a=e.getMonth()===11?0:e.getMonth()+1;return new Date(t,a,1)}static getPrevYear(e){return new Date(e.getFullYear()-1,e.getMonth(),1)}static getNextYear(e){return new Date(e.getFullYear()+1,e.getMonth(),1)}static generateMonthPanel(e,t=""){const a=[],f=this.getFirstDayOfMonth(e),v=this.getLastDayOfMonth(e),i=this.getDayOfWeek(f);for(let c=i;c>0;c--){const u=new Date(f.getTime()-c*24*60*60*1e3);a.push({date:u,formatDate:this.formatDate(u),isCurrentMonth:!1,isSelected:this.formatDate(u)===t})}const s=v.getDate();for(let c=1;c<=s;c++){const u=new Date(e.getFullYear(),e.getMonth(),c);a.push({date:u,formatDate:this.formatDate(u),isCurrentMonth:!0,isSelected:this.formatDate(u)===t})}const y=42-a.length;for(let c=1;c<=y;c++){const u=new Date(v.getTime()+c*24*60*60*1e3);a.push({date:u,formatDate:this.formatDate(u),isCurrentMonth:!1,isSelected:this.formatDate(u)===t})}return a}static getDecadeStart(e){const t=e.getFullYear();return Math.floor(t/10)*10}static getNextDecade(e){return e+10}static getPrevDecade(e){return e-10}static generateDecadeYears(e){return Array.from({length:10},(t,a)=>e+a)}}const N=r.defineComponent({name:"ViewDatePicker",props:{value:{type:String,default:()=>d.formatDate(new Date)},modelValue:{type:String,default:()=>d.formatDate(new Date)}},emits:["input","update:modelValue","change"],setup(l,{emit:e}){const t=r.ref(null),a=r.ref(null),f=r.ref(null),v=r.ref(!1),m=r.ref({}),i=r.ref(new Date().getFullYear()),s=r.ref(new Date().getMonth()+1),y=r.ref(""),c=r.ref(""),u=r.ref("date"),p=r.ref(d.getDecadeStart(new Date(i.value,s.value-1))),R=r.computed(()=>{const n=d.generateDecadeYears(p.value);return Array.isArray(n)?n:[]}),O=r.computed(()=>{const n=p.value,o=n+9;return`${n}年-${o}年`}),I=r.computed(()=>{const n=new Date(i.value,s.value-1,1),o=d.generateMonthPanel(n,c.value);return Array.isArray(o)?o:[]}),M=()=>{const n=r.isVue2?l.value:l.modelValue;if(n){c.value=n;const o=new Date(n);isNaN(o.getTime())||(i.value=o.getFullYear(),s.value=o.getMonth()+1,p.value=d.getDecadeStart(o))}else{const o=new Date;c.value=d.formatDate(o),i.value=o.getFullYear(),s.value=o.getMonth()+1,p.value=d.getDecadeStart(o)}};r.watch(()=>[l.value,l.modelValue],()=>{M()},{immediate:!0,deep:!0});const b=()=>{if(!a.value||!f.value)return;const n=a.value.getBoundingClientRect(),o=t.value.getBoundingClientRect();m.value={position:"absolute",top:`${n.bottom-o.top+4}px`,left:`${n.left-o.left}px`,zIndex:9999,width:"322px"}},A=()=>{v.value=!v.value,v.value&&(setTimeout(()=>b(),0),u.value="date")},W=()=>{p.value=d.getDecadeStart(new Date(i.value,s.value-1)),u.value="year"},B=()=>{u.value="month"},z=n=>{i.value=n,u.value="month"},j=n=>{s.value=n,u.value="date"},U=n=>{c.value=n.formatDate,i.value=n.date.getFullYear(),s.value=n.date.getMonth()+1,r.isVue2?e("input",c.value):e("update:modelValue",c.value),e("change",{date:n.date,formatDate:c.value}),v.value=!1},q=()=>{i.value-=1,p.value=d.getDecadeStart(new Date(i.value,s.value-1))},G=()=>{s.value===1?(s.value=12,i.value-=1):s.value-=1,p.value=d.getDecadeStart(new Date(i.value,s.value-1))},H=()=>{s.value===12?(s.value=1,i.value+=1):s.value+=1,p.value=d.getDecadeStart(new Date(i.value,s.value-1))},J=()=>{i.value+=1,p.value=d.getDecadeStart(new Date(i.value,s.value-1))},K=()=>{p.value=d.getNextDecade(p.value)},Q=()=>{p.value=d.getPrevDecade(p.value)},X=n=>{c.value=n.target.value},Z=(n,o)=>{if(!n||!o)return!1;if(o.contains(n)||n.classList.contains("year-item")||n.classList.contains("month-item"))return!0;let g=n;for(;g.parentElement;){if(g=g.parentElement,g===o)return!0;if(g.tagName==="BODY")break}return!1},T=n=>{const o=Z(n.target,t.value);v.value&&t.value&&!o&&(v.value=!1,u.value="date")},w=()=>{v.value&&b()};return r.onMounted(()=>{M(),document.addEventListener("click",T),window.addEventListener("scroll",w,!0),window.addEventListener("resize",w)}),r.onUnmounted(()=>{document.removeEventListener("click",T),window.removeEventListener("scroll",w,!0),window.removeEventListener("resize",w)}),{pickerWrapper:t,dateInput:a,datePanel:f,panelVisible:v,panelStyle:m,currentYear:i,currentMonth:s,hoverDate:y,displayDate:c,panelType:u,decadeYears:R,panelDates:I,togglePanel:A,openYearPanel:W,openMonthPanel:B,selectDecadeYear:z,selectTargetMonth:j,selectDate:U,switchToPrevYear:q,switchToPrevMonth:G,switchToNextMonth:H,switchToNextYear:J,handleInput:X,getDecadeStartAndEnd:O,switchToPrevTenYears:Q,switchToNextTenYears:K}}});var F=function(){var e=this,t=e._self._c;return e._self._setupProxy,t("div",{ref:"pickerWrapper",staticClass:"view-date-picker-wrapper"},[t("div",{staticClass:"native-input-wrapper"},[t("input",{ref:"dateInput",staticClass:"native-input",attrs:{type:"text",placeholder:"请选择日期",readonly:""},domProps:{value:e.displayDate},on:{input:e.handleInput,click:e.togglePanel}}),t("span",{staticClass:"date-icon",on:{click:e.togglePanel}},[e._v("📅")])]),t("div",{directives:[{name:"show",rawName:"v-show",value:e.panelVisible,expression:"panelVisible"}],ref:"datePanel",staticClass:"date-picker-dropdown",style:e.panelStyle},[t("div",{staticClass:"date-picker-panel"},[t("div",{directives:[{name:"show",rawName:"v-show",value:e.panelType=="date",expression:"panelType == 'date'"}],staticClass:"picker-header"},[t("button",{staticClass:"toggle-btn year-btn prev-year",on:{click:e.switchToPrevYear}},[e._v("«")]),t("button",{staticClass:"toggle-btn month-btn prev-month",on:{click:e.switchToPrevMonth}},[e._v(" < ")]),t("div",{staticClass:"current-month"},[t("span",{staticClass:"clickable-year",on:{click:e.openYearPanel}},[e._v(e._s(e.currentYear)+"年")]),t("span",{staticClass:"clickable-month",on:{click:e.openMonthPanel}},[e._v(e._s(e.currentMonth)+"月")])]),t("button",{staticClass:"toggle-btn month-btn next-month",on:{click:e.switchToNextMonth}},[e._v(">")]),t("button",{staticClass:"toggle-btn year-btn next-year",on:{click:e.switchToNextYear}},[e._v("»")])]),t("div",{directives:[{name:"show",rawName:"v-show",value:e.panelType=="year",expression:"panelType == 'year'"}],staticClass:"picker-header"},[t("button",{staticClass:"toggle-btn month-btn prev-month",on:{click:e.switchToPrevTenYears}},[e._v(" < ")]),t("div",{staticClass:"current-month"},[t("span",{staticClass:"clickable-year"},[e._v(e._s(e.getDecadeStartAndEnd)+"年")])]),t("button",{staticClass:"toggle-btn month-btn next-month",on:{click:e.switchToNextTenYears}},[e._v(">")])]),t("div",{directives:[{name:"show",rawName:"v-show",value:e.panelType=="month",expression:"panelType == 'month'"}],staticClass:"picker-header"},[t("button",{staticClass:"toggle-btn month-btn prev-month",on:{click:e.switchToPrevYear}},[e._v(" < ")]),t("div",{staticClass:"current-month"},[t("span",{staticClass:"clickable-year"},[e._v(e._s(e.currentYear)+"年")])]),t("button",{staticClass:"toggle-btn month-btn next-month",on:{click:e.switchToNextYear}},[e._v(">")])]),e.panelType==="date"?t("div",{staticClass:"bod-mb"},[e._m(0),t("div",{staticClass:"picker-panel"},e._l(e.panelDates,function(a,f){return t("div",{key:f,staticClass:"date-item",class:{"not-current-month":!a.isCurrentMonth,selected:a.formatDate===e.displayDate,hover:e.hoverDate===a.formatDate&&a.formatDate!==e.displayDate},on:{click:function(v){return e.selectDate(a)},mouseenter:function(v){e.hoverDate=a.formatDate},mouseleave:function(v){e.hoverDate=""}}},[e._v(" "+e._s(a.date.getDate())+" ")])}),0)]):e.panelType==="year"?t("div",{staticClass:"bod-mb"},e._l(e.decadeYears,function(a){return t("div",{key:a,staticClass:"year-item",class:{selected:a===e.currentYear},on:{click:function(f){return e.selectDecadeYear(a)}}},[e._v(" "+e._s(a)+"年 ")])}),0):e.panelType==="month"?t("div",{staticClass:"bod-mb"},e._l(12,function(a){return t("div",{key:a,staticClass:"month-item",class:{selected:a===e.currentMonth},on:{click:function(f){return e.selectTargetMonth(a)}}},[e._v(" "+e._s(a)+"月 ")])}),0):e._e()])])])},V=[function(){var l=this,e=l._self._c;return l._self._setupProxy,e("div",{staticClass:"picker-week-header"},[e("div",{staticClass:"week-item"},[l._v("日")]),e("div",{staticClass:"week-item"},[l._v("一")]),e("div",{staticClass:"week-item"},[l._v("二")]),e("div",{staticClass:"week-item"},[l._v("三")]),e("div",{staticClass:"week-item"},[l._v("四")]),e("div",{staticClass:"week-item"},[l._v("五")]),e("div",{staticClass:"week-item"},[l._v("六")])])}],$=D(N,F,V,!1,null,"e6885493");const C=$.exports,E=[k,C],_=l=>{E.forEach(e=>{l.component(e.name,e)})};typeof window<"u"&&window.Vue&&_(window.Vue);const L={install:_};h.MyButton=k,h.ViewDatePicker=C,h.default=L,h.install=_,Object.defineProperties(h,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
|
|
1
|
+
(function(global, factory) {
|
|
2
|
+
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("vue-demi"), require("vue")) : typeof define === "function" && define.amd ? define(["exports", "vue-demi", "vue"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global["view-report"] = {}, global.VueDemi, global.Vue));
|
|
3
|
+
})(this, (function(exports2, vueDemi, vue) {
|
|
4
|
+
"use strict";
|
|
5
|
+
const _export_sfc = (sfc, props) => {
|
|
6
|
+
const target = sfc.__vccOpts || sfc;
|
|
7
|
+
for (const [key, val] of props) {
|
|
8
|
+
target[key] = val;
|
|
9
|
+
}
|
|
10
|
+
return target;
|
|
11
|
+
};
|
|
12
|
+
const _sfc_main$1 = vueDemi.defineComponent({
|
|
13
|
+
name: "MyButton",
|
|
14
|
+
// 必须声明 name,用于全局注册
|
|
15
|
+
props: {
|
|
16
|
+
text: {
|
|
17
|
+
type: String,
|
|
18
|
+
default: "默认按钮"
|
|
19
|
+
},
|
|
20
|
+
color: {
|
|
21
|
+
type: String,
|
|
22
|
+
default: "#409eff"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
setup(props, { emit }) {
|
|
26
|
+
const handleClick = () => {
|
|
27
|
+
emit("click", "按钮被点击");
|
|
28
|
+
};
|
|
29
|
+
return { handleClick };
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
|
|
33
|
+
return vue.openBlock(), vue.createElementBlock("button", {
|
|
34
|
+
class: "my-button",
|
|
35
|
+
style: vue.normalizeStyle({ background: _ctx.color }),
|
|
36
|
+
onClick: _cache[0] || (_cache[0] = (...args) => _ctx.handleClick && _ctx.handleClick(...args))
|
|
37
|
+
}, [
|
|
38
|
+
vue.renderSlot(_ctx.$slots, "default", {}, () => [
|
|
39
|
+
vue.createTextVNode(vue.toDisplayString(_ctx.text), 1)
|
|
40
|
+
], true)
|
|
41
|
+
], 4);
|
|
42
|
+
}
|
|
43
|
+
const MyButton = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["render", _sfc_render$1], ["__scopeId", "data-v-d19bd5c3"]]);
|
|
44
|
+
class DateUtils {
|
|
45
|
+
/**
|
|
46
|
+
* 格式化日期为 YYYY-MM-DD 格式
|
|
47
|
+
* @param {Date} date 日期对象
|
|
48
|
+
* @returns {string} 格式化后的日期字符串
|
|
49
|
+
*/
|
|
50
|
+
static formatDate(date) {
|
|
51
|
+
if (!date || !(date instanceof Date) || isNaN(date.getTime())) return "";
|
|
52
|
+
const year = date.getFullYear();
|
|
53
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
54
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
55
|
+
return `${year}-${month}-${day}`;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* 获取指定日期所在月份的第一天
|
|
59
|
+
* @param {Date} date 基准日期
|
|
60
|
+
* @returns {Date} 月份第一天
|
|
61
|
+
*/
|
|
62
|
+
static getFirstDayOfMonth(date) {
|
|
63
|
+
return new Date(date.getFullYear(), date.getMonth(), 1);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 获取指定日期所在月份的最后一天
|
|
67
|
+
* @param {Date} date 基准日期
|
|
68
|
+
* @returns {Date} 月份最后一天
|
|
69
|
+
*/
|
|
70
|
+
static getLastDayOfMonth(date) {
|
|
71
|
+
return new Date(date.getFullYear(), date.getMonth() + 1, 0);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* 获取日期对应的星期数(周日=0,周六=6)
|
|
75
|
+
* @returns {number} 星期数
|
|
76
|
+
*/
|
|
77
|
+
static getDayOfWeek(date) {
|
|
78
|
+
return date.getDay();
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* 上一个月(支持跨年,如2026-01 → 2025-12)
|
|
82
|
+
* @returns {Date} 上月日期
|
|
83
|
+
*/
|
|
84
|
+
static getPrevMonth(date) {
|
|
85
|
+
const year = date.getMonth() === 0 ? date.getFullYear() - 1 : date.getFullYear();
|
|
86
|
+
const month = date.getMonth() === 0 ? 11 : date.getMonth() - 1;
|
|
87
|
+
return new Date(year, month, 1);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* 下一个月(支持跨年,如2025-12 → 2026-01)
|
|
91
|
+
* @returns {Date} 下月日期
|
|
92
|
+
*/
|
|
93
|
+
static getNextMonth(date) {
|
|
94
|
+
const year = date.getMonth() === 11 ? date.getFullYear() + 1 : date.getFullYear();
|
|
95
|
+
const month = date.getMonth() === 11 ? 0 : date.getMonth() + 1;
|
|
96
|
+
return new Date(year, month, 1);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* 上一年(直接切换年份,如2026 → 2025)
|
|
100
|
+
* @returns {Date} 上年同月日期
|
|
101
|
+
*/
|
|
102
|
+
static getPrevYear(date) {
|
|
103
|
+
return new Date(date.getFullYear() - 1, date.getMonth(), 1);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* 下一年(直接切换年份,如2025 → 2026)
|
|
107
|
+
* @returns {Date} 下年同月日期
|
|
108
|
+
*/
|
|
109
|
+
static getNextYear(date) {
|
|
110
|
+
return new Date(date.getFullYear() + 1, date.getMonth(), 1);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* 生成6行7列的日期面板数据(42个,自动补充跨月/跨年日期)
|
|
114
|
+
* @returns {Array} 42个日期对象的数组(6*7)
|
|
115
|
+
*/
|
|
116
|
+
static generateMonthPanel(currentDate, selectedDate = "") {
|
|
117
|
+
const panel = [];
|
|
118
|
+
const firstDay = this.getFirstDayOfMonth(currentDate);
|
|
119
|
+
const lastDay = this.getLastDayOfMonth(currentDate);
|
|
120
|
+
const firstDayWeek = this.getDayOfWeek(firstDay);
|
|
121
|
+
const prevMonthDaysCount = firstDayWeek;
|
|
122
|
+
for (let i = prevMonthDaysCount; i > 0; i--) {
|
|
123
|
+
const prevDay = new Date(firstDay.getTime() - i * 24 * 60 * 60 * 1e3);
|
|
124
|
+
panel.push({
|
|
125
|
+
date: prevDay,
|
|
126
|
+
formatDate: this.formatDate(prevDay),
|
|
127
|
+
isCurrentMonth: false,
|
|
128
|
+
isSelected: this.formatDate(prevDay) === selectedDate
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
const currentMonthDays = lastDay.getDate();
|
|
132
|
+
for (let i = 1; i <= currentMonthDays; i++) {
|
|
133
|
+
const currentDay = new Date(currentDate.getFullYear(), currentDate.getMonth(), i);
|
|
134
|
+
panel.push({
|
|
135
|
+
date: currentDay,
|
|
136
|
+
formatDate: this.formatDate(currentDay),
|
|
137
|
+
isCurrentMonth: true,
|
|
138
|
+
isSelected: this.formatDate(currentDay) === selectedDate
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
const needNextDays = 42 - panel.length;
|
|
142
|
+
for (let i = 1; i <= needNextDays; i++) {
|
|
143
|
+
const nextDay = new Date(lastDay.getTime() + i * 24 * 60 * 60 * 1e3);
|
|
144
|
+
panel.push({
|
|
145
|
+
date: nextDay,
|
|
146
|
+
formatDate: this.formatDate(nextDay),
|
|
147
|
+
isCurrentMonth: false,
|
|
148
|
+
isSelected: this.formatDate(nextDay) === selectedDate
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
return panel;
|
|
152
|
+
}
|
|
153
|
+
// ========== 新增十年跨度相关方法(不改动原有逻辑) ==========
|
|
154
|
+
/**
|
|
155
|
+
* 获取当前年份所在的十年区间起始年份
|
|
156
|
+
* @param {Date} date 基准日期
|
|
157
|
+
* @returns {number} 十年起始年份(如2026 → 2020)
|
|
158
|
+
*/
|
|
159
|
+
static getDecadeStart(date) {
|
|
160
|
+
const year = date.getFullYear();
|
|
161
|
+
return Math.floor(year / 10) * 10;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* 获取下一个十年区间起始年份
|
|
165
|
+
* @param {number} decadeStart 当前十年起始年份
|
|
166
|
+
* @returns {number} 下一个十年起始年份(如2020 → 2030)
|
|
167
|
+
*/
|
|
168
|
+
static getNextDecade(decadeStart) {
|
|
169
|
+
return decadeStart + 10;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* 获取上一个十年区间起始年份
|
|
173
|
+
* @param {number} decadeStart 当前十年起始年份
|
|
174
|
+
* @returns {number} 上一个十年起始年份(如2020 → 2010)
|
|
175
|
+
*/
|
|
176
|
+
static getPrevDecade(decadeStart) {
|
|
177
|
+
return decadeStart - 10;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* 生成十年跨度的年份数组(如2020-2029)
|
|
181
|
+
* @param {number} decadeStart 十年起始年份
|
|
182
|
+
* @returns {Array} 十年年份数组
|
|
183
|
+
*/
|
|
184
|
+
static generateDecadeYears(decadeStart) {
|
|
185
|
+
return Array.from({ length: 10 }, (_, i) => decadeStart + i);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const _sfc_main = vueDemi.defineComponent({
|
|
189
|
+
name: "ViewDatePicker",
|
|
190
|
+
// Vue2兼容:props定义(vue-demi已适配)
|
|
191
|
+
props: {
|
|
192
|
+
value: {
|
|
193
|
+
// Vue2的v-model绑定值(兼容Vue3的modelValue)
|
|
194
|
+
type: String,
|
|
195
|
+
default: () => DateUtils.formatDate(/* @__PURE__ */ new Date())
|
|
196
|
+
},
|
|
197
|
+
modelValue: {
|
|
198
|
+
// Vue3的v-model绑定值
|
|
199
|
+
type: String,
|
|
200
|
+
default: () => DateUtils.formatDate(/* @__PURE__ */ new Date())
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
// Vue2/Vue3兼容:emits定义
|
|
204
|
+
emits: ["input", "update:modelValue", "change"],
|
|
205
|
+
setup(props, { emit }) {
|
|
206
|
+
const pickerWrapper = vueDemi.ref(null);
|
|
207
|
+
const dateInput = vueDemi.ref(null);
|
|
208
|
+
const datePanel = vueDemi.ref(null);
|
|
209
|
+
const panelVisible = vueDemi.ref(false);
|
|
210
|
+
const panelStyle = vueDemi.ref({});
|
|
211
|
+
const currentYear = vueDemi.ref((/* @__PURE__ */ new Date()).getFullYear());
|
|
212
|
+
const currentMonth = vueDemi.ref((/* @__PURE__ */ new Date()).getMonth() + 1);
|
|
213
|
+
const hoverDate = vueDemi.ref("");
|
|
214
|
+
const displayDate = vueDemi.ref("");
|
|
215
|
+
const panelType = vueDemi.ref("date");
|
|
216
|
+
const decadeStart = vueDemi.ref(DateUtils.getDecadeStart(new Date(currentYear.value, currentMonth.value - 1)));
|
|
217
|
+
const decadeYears = vueDemi.computed(() => {
|
|
218
|
+
const years = DateUtils.generateDecadeYears(decadeStart.value);
|
|
219
|
+
return Array.isArray(years) ? years : [];
|
|
220
|
+
});
|
|
221
|
+
const getDecadeStartAndEnd = vueDemi.computed(() => {
|
|
222
|
+
const start = decadeStart.value;
|
|
223
|
+
const end = start + 9;
|
|
224
|
+
return `${start}年-${end}年`;
|
|
225
|
+
});
|
|
226
|
+
const panelDates = vueDemi.computed(() => {
|
|
227
|
+
const currentDateTemp = new Date(currentYear.value, currentMonth.value - 1, 1);
|
|
228
|
+
const dates = DateUtils.generateMonthPanel(currentDateTemp, displayDate.value);
|
|
229
|
+
return Array.isArray(dates) ? dates : [];
|
|
230
|
+
});
|
|
231
|
+
const initDisplayDate = () => {
|
|
232
|
+
const initValue = vueDemi.isVue2 ? props.value : props.modelValue;
|
|
233
|
+
if (initValue) {
|
|
234
|
+
displayDate.value = initValue;
|
|
235
|
+
const date = new Date(initValue);
|
|
236
|
+
if (!isNaN(date.getTime())) {
|
|
237
|
+
currentYear.value = date.getFullYear();
|
|
238
|
+
currentMonth.value = date.getMonth() + 1;
|
|
239
|
+
decadeStart.value = DateUtils.getDecadeStart(date);
|
|
240
|
+
}
|
|
241
|
+
} else {
|
|
242
|
+
const now = /* @__PURE__ */ new Date();
|
|
243
|
+
displayDate.value = DateUtils.formatDate(now);
|
|
244
|
+
currentYear.value = now.getFullYear();
|
|
245
|
+
currentMonth.value = now.getMonth() + 1;
|
|
246
|
+
decadeStart.value = DateUtils.getDecadeStart(now);
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
vueDemi.watch(
|
|
250
|
+
() => [props.value, props.modelValue],
|
|
251
|
+
() => {
|
|
252
|
+
initDisplayDate();
|
|
253
|
+
},
|
|
254
|
+
{ immediate: true, deep: true }
|
|
255
|
+
);
|
|
256
|
+
const calcPanelPosition = () => {
|
|
257
|
+
if (!dateInput.value || !datePanel.value) return;
|
|
258
|
+
const inputRect = dateInput.value.getBoundingClientRect();
|
|
259
|
+
const wrapperRect = pickerWrapper.value.getBoundingClientRect();
|
|
260
|
+
panelStyle.value = {
|
|
261
|
+
position: "absolute",
|
|
262
|
+
top: `${inputRect.bottom - wrapperRect.top + 4}px`,
|
|
263
|
+
left: `${inputRect.left - wrapperRect.left}px`,
|
|
264
|
+
zIndex: 9999,
|
|
265
|
+
width: `322px`
|
|
266
|
+
};
|
|
267
|
+
};
|
|
268
|
+
const togglePanel = () => {
|
|
269
|
+
panelVisible.value = !panelVisible.value;
|
|
270
|
+
if (panelVisible.value) {
|
|
271
|
+
setTimeout(() => calcPanelPosition(), 0);
|
|
272
|
+
panelType.value = "date";
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
const openYearPanel = () => {
|
|
276
|
+
decadeStart.value = DateUtils.getDecadeStart(new Date(currentYear.value, currentMonth.value - 1));
|
|
277
|
+
panelType.value = "year";
|
|
278
|
+
};
|
|
279
|
+
const openMonthPanel = () => {
|
|
280
|
+
panelType.value = "month";
|
|
281
|
+
};
|
|
282
|
+
const selectDecadeYear = (year) => {
|
|
283
|
+
currentYear.value = year;
|
|
284
|
+
panelType.value = "month";
|
|
285
|
+
};
|
|
286
|
+
const selectTargetMonth = (month) => {
|
|
287
|
+
currentMonth.value = month;
|
|
288
|
+
panelType.value = "date";
|
|
289
|
+
};
|
|
290
|
+
const selectDate = (item) => {
|
|
291
|
+
displayDate.value = item.formatDate;
|
|
292
|
+
currentYear.value = item.date.getFullYear();
|
|
293
|
+
currentMonth.value = item.date.getMonth() + 1;
|
|
294
|
+
if (vueDemi.isVue2) {
|
|
295
|
+
emit("input", displayDate.value);
|
|
296
|
+
} else {
|
|
297
|
+
emit("update:modelValue", displayDate.value);
|
|
298
|
+
}
|
|
299
|
+
emit("change", {
|
|
300
|
+
date: item.date,
|
|
301
|
+
formatDate: displayDate.value
|
|
302
|
+
});
|
|
303
|
+
panelVisible.value = false;
|
|
304
|
+
};
|
|
305
|
+
const switchToPrevYear = () => {
|
|
306
|
+
currentYear.value -= 1;
|
|
307
|
+
decadeStart.value = DateUtils.getDecadeStart(new Date(currentYear.value, currentMonth.value - 1));
|
|
308
|
+
};
|
|
309
|
+
const switchToPrevMonth = () => {
|
|
310
|
+
if (currentMonth.value === 1) {
|
|
311
|
+
currentMonth.value = 12;
|
|
312
|
+
currentYear.value -= 1;
|
|
313
|
+
} else {
|
|
314
|
+
currentMonth.value -= 1;
|
|
315
|
+
}
|
|
316
|
+
decadeStart.value = DateUtils.getDecadeStart(new Date(currentYear.value, currentMonth.value - 1));
|
|
317
|
+
};
|
|
318
|
+
const switchToNextMonth = () => {
|
|
319
|
+
if (currentMonth.value === 12) {
|
|
320
|
+
currentMonth.value = 1;
|
|
321
|
+
currentYear.value += 1;
|
|
322
|
+
} else {
|
|
323
|
+
currentMonth.value += 1;
|
|
324
|
+
}
|
|
325
|
+
decadeStart.value = DateUtils.getDecadeStart(new Date(currentYear.value, currentMonth.value - 1));
|
|
326
|
+
};
|
|
327
|
+
const switchToNextYear = () => {
|
|
328
|
+
currentYear.value += 1;
|
|
329
|
+
decadeStart.value = DateUtils.getDecadeStart(new Date(currentYear.value, currentMonth.value - 1));
|
|
330
|
+
};
|
|
331
|
+
const switchToNextTenYears = () => {
|
|
332
|
+
decadeStart.value = DateUtils.getNextDecade(decadeStart.value);
|
|
333
|
+
};
|
|
334
|
+
const switchToPrevTenYears = () => {
|
|
335
|
+
decadeStart.value = DateUtils.getPrevDecade(decadeStart.value);
|
|
336
|
+
};
|
|
337
|
+
const handleInput = (e) => {
|
|
338
|
+
displayDate.value = e.target.value;
|
|
339
|
+
};
|
|
340
|
+
const isElementInContainer = (el, container) => {
|
|
341
|
+
if (!el || !container) return false;
|
|
342
|
+
if (container.contains(el)) return true;
|
|
343
|
+
if (el.classList.contains("year-item")) return true;
|
|
344
|
+
if (el.classList.contains("month-item")) return true;
|
|
345
|
+
let currentEl = el;
|
|
346
|
+
while (currentEl.parentElement) {
|
|
347
|
+
currentEl = currentEl.parentElement;
|
|
348
|
+
if (currentEl === container) {
|
|
349
|
+
return true;
|
|
350
|
+
}
|
|
351
|
+
if (currentEl.tagName === "BODY") break;
|
|
352
|
+
}
|
|
353
|
+
return false;
|
|
354
|
+
};
|
|
355
|
+
const handleViewReportClickOutside = (e) => {
|
|
356
|
+
const isInWrapper = isElementInContainer(e.target, pickerWrapper.value);
|
|
357
|
+
if (panelVisible.value && pickerWrapper.value && !isInWrapper) {
|
|
358
|
+
panelVisible.value = false;
|
|
359
|
+
panelType.value = "date";
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
const handleViewReportResizes = () => {
|
|
363
|
+
if (panelVisible.value) calcPanelPosition();
|
|
364
|
+
};
|
|
365
|
+
vueDemi.onMounted(() => {
|
|
366
|
+
initDisplayDate();
|
|
367
|
+
document.addEventListener("click", handleViewReportClickOutside);
|
|
368
|
+
window.addEventListener("scroll", handleViewReportResizes, true);
|
|
369
|
+
window.addEventListener("resize", handleViewReportResizes);
|
|
370
|
+
});
|
|
371
|
+
vueDemi.onUnmounted(() => {
|
|
372
|
+
document.removeEventListener("click", handleViewReportClickOutside);
|
|
373
|
+
window.removeEventListener("scroll", handleViewReportResizes, true);
|
|
374
|
+
window.removeEventListener("resize", handleViewReportResizes);
|
|
375
|
+
});
|
|
376
|
+
return {
|
|
377
|
+
pickerWrapper,
|
|
378
|
+
dateInput,
|
|
379
|
+
datePanel,
|
|
380
|
+
panelVisible,
|
|
381
|
+
panelStyle,
|
|
382
|
+
currentYear,
|
|
383
|
+
// 仅暴露currentYear/currentMonth
|
|
384
|
+
currentMonth,
|
|
385
|
+
hoverDate,
|
|
386
|
+
displayDate,
|
|
387
|
+
panelType,
|
|
388
|
+
decadeYears,
|
|
389
|
+
panelDates,
|
|
390
|
+
togglePanel,
|
|
391
|
+
openYearPanel,
|
|
392
|
+
openMonthPanel,
|
|
393
|
+
selectDecadeYear,
|
|
394
|
+
selectTargetMonth,
|
|
395
|
+
selectDate,
|
|
396
|
+
switchToPrevYear,
|
|
397
|
+
switchToPrevMonth,
|
|
398
|
+
switchToNextMonth,
|
|
399
|
+
switchToNextYear,
|
|
400
|
+
handleInput,
|
|
401
|
+
getDecadeStartAndEnd,
|
|
402
|
+
switchToPrevTenYears,
|
|
403
|
+
switchToNextTenYears
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
const _hoisted_1 = {
|
|
408
|
+
class: "view-date-picker-wrapper",
|
|
409
|
+
ref: "pickerWrapper"
|
|
410
|
+
};
|
|
411
|
+
const _hoisted_2 = { class: "native-input-wrapper" };
|
|
412
|
+
const _hoisted_3 = ["value"];
|
|
413
|
+
const _hoisted_4 = { class: "date-picker-panel" };
|
|
414
|
+
const _hoisted_5 = { class: "picker-header" };
|
|
415
|
+
const _hoisted_6 = { class: "current-month" };
|
|
416
|
+
const _hoisted_7 = { class: "picker-header" };
|
|
417
|
+
const _hoisted_8 = { class: "current-month" };
|
|
418
|
+
const _hoisted_9 = { class: "clickable-year" };
|
|
419
|
+
const _hoisted_10 = { class: "picker-header" };
|
|
420
|
+
const _hoisted_11 = { class: "current-month" };
|
|
421
|
+
const _hoisted_12 = { class: "clickable-year" };
|
|
422
|
+
const _hoisted_13 = {
|
|
423
|
+
key: 0,
|
|
424
|
+
class: "bod-mb"
|
|
425
|
+
};
|
|
426
|
+
const _hoisted_14 = { class: "picker-panel" };
|
|
427
|
+
const _hoisted_15 = ["onClick", "onMouseenter"];
|
|
428
|
+
const _hoisted_16 = {
|
|
429
|
+
key: 1,
|
|
430
|
+
class: "bod-mb"
|
|
431
|
+
};
|
|
432
|
+
const _hoisted_17 = ["onClick"];
|
|
433
|
+
const _hoisted_18 = {
|
|
434
|
+
key: 2,
|
|
435
|
+
class: "bod-mb"
|
|
436
|
+
};
|
|
437
|
+
const _hoisted_19 = ["onClick"];
|
|
438
|
+
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
439
|
+
return vue.openBlock(), vue.createElementBlock("div", _hoisted_1, [
|
|
440
|
+
vue.createElementVNode("div", _hoisted_2, [
|
|
441
|
+
vue.createElementVNode("input", {
|
|
442
|
+
ref: "dateInput",
|
|
443
|
+
type: "text",
|
|
444
|
+
value: _ctx.displayDate,
|
|
445
|
+
onInput: _cache[0] || (_cache[0] = (...args) => _ctx.handleInput && _ctx.handleInput(...args)),
|
|
446
|
+
placeholder: "请选择日期",
|
|
447
|
+
readonly: "",
|
|
448
|
+
class: "native-input",
|
|
449
|
+
onClick: _cache[1] || (_cache[1] = (...args) => _ctx.togglePanel && _ctx.togglePanel(...args))
|
|
450
|
+
}, null, 40, _hoisted_3),
|
|
451
|
+
vue.createElementVNode("span", {
|
|
452
|
+
class: "date-icon",
|
|
453
|
+
onClick: _cache[2] || (_cache[2] = (...args) => _ctx.togglePanel && _ctx.togglePanel(...args))
|
|
454
|
+
}, "📅")
|
|
455
|
+
]),
|
|
456
|
+
vue.withDirectives(vue.createElementVNode("div", {
|
|
457
|
+
ref: "datePanel",
|
|
458
|
+
class: "date-picker-dropdown",
|
|
459
|
+
style: vue.normalizeStyle(_ctx.panelStyle)
|
|
460
|
+
}, [
|
|
461
|
+
vue.createElementVNode("div", _hoisted_4, [
|
|
462
|
+
vue.withDirectives(vue.createElementVNode("div", _hoisted_5, [
|
|
463
|
+
vue.createElementVNode("button", {
|
|
464
|
+
class: "toggle-btn year-btn prev-year",
|
|
465
|
+
onClick: _cache[3] || (_cache[3] = (...args) => _ctx.switchToPrevYear && _ctx.switchToPrevYear(...args))
|
|
466
|
+
}, "«"),
|
|
467
|
+
vue.createElementVNode("button", {
|
|
468
|
+
class: "toggle-btn month-btn prev-month",
|
|
469
|
+
onClick: _cache[4] || (_cache[4] = (...args) => _ctx.switchToPrevMonth && _ctx.switchToPrevMonth(...args))
|
|
470
|
+
}, " < "),
|
|
471
|
+
vue.createElementVNode("div", _hoisted_6, [
|
|
472
|
+
vue.createElementVNode("span", {
|
|
473
|
+
onClick: _cache[5] || (_cache[5] = (...args) => _ctx.openYearPanel && _ctx.openYearPanel(...args)),
|
|
474
|
+
class: "clickable-year"
|
|
475
|
+
}, vue.toDisplayString(_ctx.currentYear) + "年", 1),
|
|
476
|
+
vue.createElementVNode("span", {
|
|
477
|
+
onClick: _cache[6] || (_cache[6] = (...args) => _ctx.openMonthPanel && _ctx.openMonthPanel(...args)),
|
|
478
|
+
class: "clickable-month"
|
|
479
|
+
}, vue.toDisplayString(_ctx.currentMonth) + "月", 1)
|
|
480
|
+
]),
|
|
481
|
+
vue.createElementVNode("button", {
|
|
482
|
+
class: "toggle-btn month-btn next-month",
|
|
483
|
+
onClick: _cache[7] || (_cache[7] = (...args) => _ctx.switchToNextMonth && _ctx.switchToNextMonth(...args))
|
|
484
|
+
}, ">"),
|
|
485
|
+
vue.createElementVNode("button", {
|
|
486
|
+
class: "toggle-btn year-btn next-year",
|
|
487
|
+
onClick: _cache[8] || (_cache[8] = (...args) => _ctx.switchToNextYear && _ctx.switchToNextYear(...args))
|
|
488
|
+
}, "»")
|
|
489
|
+
], 512), [
|
|
490
|
+
[vue.vShow, _ctx.panelType == "date"]
|
|
491
|
+
]),
|
|
492
|
+
vue.withDirectives(vue.createElementVNode("div", _hoisted_7, [
|
|
493
|
+
vue.createElementVNode("button", {
|
|
494
|
+
class: "toggle-btn month-btn prev-month",
|
|
495
|
+
onClick: _cache[9] || (_cache[9] = (...args) => _ctx.switchToPrevTenYears && _ctx.switchToPrevTenYears(...args))
|
|
496
|
+
}, " < "),
|
|
497
|
+
vue.createElementVNode("div", _hoisted_8, [
|
|
498
|
+
vue.createElementVNode("span", _hoisted_9, vue.toDisplayString(_ctx.getDecadeStartAndEnd) + "年", 1)
|
|
499
|
+
]),
|
|
500
|
+
vue.createElementVNode("button", {
|
|
501
|
+
class: "toggle-btn month-btn next-month",
|
|
502
|
+
onClick: _cache[10] || (_cache[10] = (...args) => _ctx.switchToNextTenYears && _ctx.switchToNextTenYears(...args))
|
|
503
|
+
}, ">")
|
|
504
|
+
], 512), [
|
|
505
|
+
[vue.vShow, _ctx.panelType == "year"]
|
|
506
|
+
]),
|
|
507
|
+
vue.withDirectives(vue.createElementVNode("div", _hoisted_10, [
|
|
508
|
+
vue.createElementVNode("button", {
|
|
509
|
+
class: "toggle-btn month-btn prev-month",
|
|
510
|
+
onClick: _cache[11] || (_cache[11] = (...args) => _ctx.switchToPrevYear && _ctx.switchToPrevYear(...args))
|
|
511
|
+
}, " < "),
|
|
512
|
+
vue.createElementVNode("div", _hoisted_11, [
|
|
513
|
+
vue.createElementVNode("span", _hoisted_12, vue.toDisplayString(_ctx.currentYear) + "年", 1)
|
|
514
|
+
]),
|
|
515
|
+
vue.createElementVNode("button", {
|
|
516
|
+
class: "toggle-btn month-btn next-month",
|
|
517
|
+
onClick: _cache[12] || (_cache[12] = (...args) => _ctx.switchToNextYear && _ctx.switchToNextYear(...args))
|
|
518
|
+
}, ">")
|
|
519
|
+
], 512), [
|
|
520
|
+
[vue.vShow, _ctx.panelType == "month"]
|
|
521
|
+
]),
|
|
522
|
+
_ctx.panelType === "date" ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_13, [
|
|
523
|
+
_cache[14] || (_cache[14] = vue.createStaticVNode('<div class="picker-week-header" data-v-e6885493><div class="week-item" data-v-e6885493>日</div><div class="week-item" data-v-e6885493>一</div><div class="week-item" data-v-e6885493>二</div><div class="week-item" data-v-e6885493>三</div><div class="week-item" data-v-e6885493>四</div><div class="week-item" data-v-e6885493>五</div><div class="week-item" data-v-e6885493>六</div></div>', 1)),
|
|
524
|
+
vue.createElementVNode("div", _hoisted_14, [
|
|
525
|
+
(vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(_ctx.panelDates, (item, index2) => {
|
|
526
|
+
return vue.openBlock(), vue.createElementBlock("div", {
|
|
527
|
+
class: vue.normalizeClass(["date-item", {
|
|
528
|
+
"not-current-month": !item.isCurrentMonth,
|
|
529
|
+
"selected": item.formatDate === _ctx.displayDate,
|
|
530
|
+
"hover": _ctx.hoverDate === item.formatDate && item.formatDate !== _ctx.displayDate
|
|
531
|
+
}]),
|
|
532
|
+
key: index2,
|
|
533
|
+
onClick: ($event) => _ctx.selectDate(item),
|
|
534
|
+
onMouseenter: ($event) => _ctx.hoverDate = item.formatDate,
|
|
535
|
+
onMouseleave: _cache[13] || (_cache[13] = ($event) => _ctx.hoverDate = "")
|
|
536
|
+
}, vue.toDisplayString(item.date.getDate()), 43, _hoisted_15);
|
|
537
|
+
}), 128))
|
|
538
|
+
])
|
|
539
|
+
])) : _ctx.panelType === "year" ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_16, [
|
|
540
|
+
(vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(_ctx.decadeYears, (year) => {
|
|
541
|
+
return vue.openBlock(), vue.createElementBlock("div", {
|
|
542
|
+
class: vue.normalizeClass(["year-item", { "selected": year === _ctx.currentYear }]),
|
|
543
|
+
key: year,
|
|
544
|
+
onClick: ($event) => _ctx.selectDecadeYear(year)
|
|
545
|
+
}, vue.toDisplayString(year) + "年 ", 11, _hoisted_17);
|
|
546
|
+
}), 128))
|
|
547
|
+
])) : _ctx.panelType === "month" ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_18, [
|
|
548
|
+
(vue.openBlock(), vue.createElementBlock(vue.Fragment, null, vue.renderList(12, (month) => {
|
|
549
|
+
return vue.createElementVNode("div", {
|
|
550
|
+
class: vue.normalizeClass(["month-item", { "selected": month === _ctx.currentMonth }]),
|
|
551
|
+
key: month,
|
|
552
|
+
onClick: ($event) => _ctx.selectTargetMonth(month)
|
|
553
|
+
}, vue.toDisplayString(month) + "月 ", 11, _hoisted_19);
|
|
554
|
+
}), 64))
|
|
555
|
+
])) : vue.createCommentVNode("", true)
|
|
556
|
+
])
|
|
557
|
+
], 4), [
|
|
558
|
+
[vue.vShow, _ctx.panelVisible]
|
|
559
|
+
])
|
|
560
|
+
], 512);
|
|
561
|
+
}
|
|
562
|
+
const ViewDatePicker = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-e6885493"]]);
|
|
563
|
+
const components = [MyButton, ViewDatePicker];
|
|
564
|
+
const install = (app) => {
|
|
565
|
+
components.forEach((component) => {
|
|
566
|
+
app.component(component.name, component);
|
|
567
|
+
});
|
|
568
|
+
};
|
|
569
|
+
if (typeof window !== "undefined" && window.Vue) {
|
|
570
|
+
install(window.Vue);
|
|
571
|
+
}
|
|
572
|
+
const index = { install };
|
|
573
|
+
exports2.MyButton = MyButton;
|
|
574
|
+
exports2.ViewDatePicker = ViewDatePicker;
|
|
575
|
+
exports2.default = index;
|
|
576
|
+
exports2.install = install;
|
|
577
|
+
Object.defineProperties(exports2, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
578
|
+
}));
|