template view classtime-switch-wrap !-- 顶部分段标签 activeKey 为u-tabs标准绑定字段 -- u-tabs :classtabsClass :listtabList :activeStylemergedActiveStyle :inactiveStylemergedInactiveStyle changeonChange / !-- 导航 -- view classdate-nav-1 u-icon v-ifactiveType ! custom classnav-left nameplay-left-fill size16 clickprevDate / view classdate-text clickopenDatePopup{{ displayDate }}/view u-icon v-ifactiveType ! custom classnav-right nameplay-right-fill size16 clicknextDate / /view !-- 选择日期 -- !-- 底部弹出层 -- view v-ifpopupShowactiveType day classpopup-calendar u-calendar :minDateminCalendarDate monthNum121 :disabledFunallDateCanSelect :showshow confirmonDaySelect / /view !-- 周选择弹窗区间选择 -- view v-ifpopupShowactiveType week classpopup-week u-calendar v-modelselectDay modesingle :showshow title选择任意一天自动匹配完整周一~周日 confirmonWeekSelect closeclosebtn / /view !-- 年月选择弹窗 -- view v-ifpopupShowactiveType month classpopup-month u-picker :showshow v-modelmonthPickerValue :columnsmonthColumns confirmonMonthSelect / /view !-- 年份选择弹窗 -- view v-ifpopupShowactiveType year classpopup-year u-picker :showshow v-modelyearPickerValue :columnsyearColumns confirmonYearSelect / /view !-- 自定义时间可自行扩展区间日历 -- view v-ifpopupShowactiveType custom classpopup-custom u-calendar closeclosebtn :minDateminCalendarDate monthNum121 v-modelweekRange allowSameDay :showshow moderange confirmonCustomSelect / /view /view /template script setup languts import { ref, computed, defineEmits, watch, withDefaults } from vue import { dayuts } from /uni_modules/lime-dayuts; export type TimeDimension day | week | month | year | custom const tabList [ { name: 日, value: day as TimeDimension }, { name: 周, value: week as TimeDimension }, { name: 月, value: month as TimeDimension }, { name: 年, value: year as TimeDimension }, { name: 自定义, value: custom as TimeDimension }, // { name: 自定义wwww, value: custom as TimeDimension }, ] const show ref(false) // 只定义一次Props删除下方重复interface Props interface Props { modelValue : TimeDimension currentDate : string | Date activeStyle ?: Recordstring, string inactiveStyle ?: Recordstring, string enableTabsClass ?: boolean } const props withDefaults(definePropsProps(), { // 【内置默认激活样式】 activeStyle: () ({ color: #1F2329, fontWeight: bold, background: #eff2f7, }), // 【内置默认未激活样式】 inactiveStyle: () ({ fontWeight: 400, color: #1F2329, }), enableTabsClass: false }) const emit defineEmits{ update:modelValue : [val: TimeDimension] update:currentDate : [date: string] change : [ type: TimeDimension, baseDate: string, range?: { start ?: string end ?: string yearMonth ?: string year ?: number } ] }() const tabsClass computed(() { return props.enableTabsClass ? u-tabs-f : }) const baseDate ref(dayuts(props.currentDate)) const popupShow ref(false) const activeType refTimeDimension(props.modelValue) const minCalendarDate computed(() { // 复制一份日期避免修改原baseDate const minDay baseDate.value.subtract(120, month) return minDay.format(YYYY-MM-DD) }) const mergedActiveStyle computed(() ({ ...props.activeStyle })) const mergedInactiveStyle computed(() ({ ...props.inactiveStyle })) const closebtn () { popupShow.value false } const onChange (e) { baseDate.value dayuts(props.currentDate) console.log(e, e) activeType.value e.value // 同步父组件选中tab emit(update:modelValue, e.value) const baseStr baseDate.value.format(YYYY-MM-DD) emit(update:currentDate, baseStr) if (activeType.value week) { const start getWeekStart(baseDate.value).format(YYYY-MM-DD) const end getWeekEnd(baseDate.value).format(YYYY-MM-DD) emit(change, activeType.value, baseStr, { start, end }) } else if (activeType.value month) { const yearMonth baseDate.value.format(YYYY-MM) emit(change, activeType.value, baseStr, { yearMonth }) } else if (activeType.value year) { const year baseDate.value.year() emit(change, activeType.value, baseStr, { year }) } else if (activeType.value custom) { // 自定义默认当天开始、当天结束 const start baseStr const end baseStr weekRange.value [baseStr, baseStr] emit(change, activeType.value, baseStr, { start, end }) } else { // day 无额外参数 emit(change, activeType.value, baseStr) } } const handleWeekDisabled (date : Date) : boolean { const target dayuts(date) const selectStart weekRange.value[0] ? dayuts(weekRange.value[0]) : null // 未选开始日期全部可点 if (!selectStart) return false const diffDays target.diff(selectStart, day) // 只能往后选最多6天凑满7天 if (diffDays 0 || diffDays 6) return true const startWeekDay selectStart.day() // 0周日 1周一 ...6周六 const endWeekDay target.day() // 规则起始必须周一结束必须周日且间隔正好6天共7天 const isFullWeek startWeekDay 1 endWeekDay 0 diffDays 6 return !isFullWeek } // 各选择器绑定值 const selectDay refstring(baseDate.value.format(YYYY-MM-DD)) // 周/自定义共用区间数组 const weekRange refstring[]([ getWeekStart(baseDate.value).format(YYYY-MM-DD), getWeekEnd(baseDate.value).format(YYYY-MM-DD) ]) const monthPickerValue refstring([ String(baseDate.value.year()), String(baseDate.value.month() 1) ]) const yearPickerValue refstring[]([String(baseDate.value.year())]) type DayutsInstance ReturnTypetypeof dayuts // 计算本周周一 function getWeekStart(d : DayutsInstance) : DayutsInstance { const dayNum d.day() const offset dayNum 0 ? -6 : 1 - dayNum return d.add(offset, day) } // 计算本周周日 function getWeekEnd(d : DayutsInstance) : DayutsInstance { return getWeekStart(d).add(6, day) } // 月份picker列 const monthColumns computed(() { const curYear baseDate.value.year() const years : string[] [] for (let i curYear - 10; i curYear 10; i) { years.push(String(i)) } const months [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] return [years, months] }) // 年份picker列 const yearColumns computed(() { const curYear baseDate.value.year() const years : string[] [] for (let i curYear - 10; i curYear 10; i) { years.push(String(i)) } return [years] }) // 监听外部参数 watch(() props.modelValue, (newVal : TimeDimension) { activeType.value newVal }) watch(() props.currentDate, (val) { baseDate.value dayuts(val) resetPickerValue() syncEmit() }) // 重置选择器绑定值自定义默认当天-当天 const resetPickerValue () { const safeDate baseDate.value.isValid() ? baseDate.value : dayuts() const today safeDate.format(YYYY-MM-DD) selectDay.value today if (activeType.value custom) { weekRange.value [today, today] } else if (activeType.value week) { // 打开周日历默认当前整周 const mon getWeekStart(safeDate) const sun getWeekEnd(safeDate) weekRange.value [mon.format(YYYY-MM-DD), sun.format(YYYY-MM-DD)] } else { weekRange.value [ getWeekStart(safeDate).format(YYYY-MM-DD), getWeekEnd(safeDate).format(YYYY-MM-DD) ] } monthPickerValue.value [ String(safeDate.year()), String(safeDate.month() 1) ] yearPickerValue.value [String(safeDate.year())] } // 打开底部弹窗 const openDatePopup () { resetPickerValue() popupShow.value true show.value true } // 页面展示日期文本新增custom分支展示区间 const displayDate computed(() { const d baseDate.value switch (activeType.value) { case day: return d.format(YYYY/M/D) case week: const s getWeekStart(d) const e getWeekEnd(d) return ${s.format(YYYY/M/D)} - ${e.format(YYYY/M/D)} case month: return d.format(YYYY/M) case year: return String(d.year()) case custom: // 自定义展示当前基准日-当前基准日 const start weekRange.value[0] const end weekRange.value[weekRange.value.length - 1] console.log(weekRange.value, weekRange.value) return ${dayuts(start).format(YYYY/M/D)} - ${dayuts(end).format(YYYY/M/D)} default: return d.format(YYYY/M/D) } }) // 上一周期 const prevDate () { switch (activeType.value) { case day: baseDate.value baseDate.value.subtract(1, day) break case week: baseDate.value baseDate.value.subtract(7, day) break case month: baseDate.value baseDate.value.subtract(1, month) break case year: baseDate.value baseDate.value.subtract(1, year) break case custom: baseDate.value baseDate.value.subtract(1, day) break } syncEmit() } // 下一周期 const nextDate () { switch (activeType.value) { case day: baseDate.value baseDate.value.add(1, day) break case week: baseDate.value baseDate.value.add(7, day) break case month: baseDate.value baseDate.value.add(1, month) break case year: baseDate.value baseDate.value.add(1, year) break case custom: baseDate.value baseDate.value.add(1, day) break } syncEmit() } // 同步通知父组件补全custom分支 const syncEmit () { const baseStr baseDate.value.format(YYYY-MM-DD) emit(update:currentDate, baseStr) if (activeType.value week) { const start getWeekStart(baseDate.value).format(YYYY-MM-DD) const end getWeekEnd(baseDate.value).format(YYYY-MM-DD) emit(change, activeType.value, baseStr, { start, end }) } else if (activeType.value month) { const yearMonth baseDate.value.format(YYYY-MM) console.log(yearMonth, yearMonth) emit(change, activeType.value, baseStr, { yearMonth }) } else if (activeType.value year) { const year baseDate.value.year() emit(change, activeType.value, baseStr, { year }) } else if (activeType.value custom) { const start weekRange.value[0] const end weekRange.value[weekRange.value.length - 1] emit(change, activeType.value, baseStr, { start, end }) } else { emit(change, activeType.value, baseStr) } } // 单日选择确认 const onDaySelect (date : string[]) { baseDate.value dayuts(date[0]) popupShow.value false show.value false syncEmit() } // 周区间选择确认 const onWeekSelect (dateArr : string[]) { const pickDay dayuts(dateArr[0]) // 获取选中日对应的周一、周日 const mon getWeekStart(pickDay) const sun getWeekEnd(pickDay) // 更新区间为完整一周 weekRange.value [mon.format(YYYY-MM-DD), sun.format(YYYY-MM-DD)] // 基准日期设为本周周一 baseDate.value mon popupShow.value false show.value false syncEmit() } // 月份选择确认 const onMonthSelect (res : string[]) { console.log(res, res) const year Number(res.value[0]) const month Number(res.value[1]) - 1 // 必须减1 console.log(转换后year, year, month, month, 最终month, month) baseDate.value dayuts().year(year).month(month).date(1) console.log(baseDate.value, baseDate.value ) popupShow.value false show.value false syncEmit() } // 年份选择确认 const onYearSelect (res : string[]) { const year Number(res.value[0]) baseDate.value dayuts().year(year).month(0).date(1) popupShow.value false show.value false syncEmit() } // 自定义区间选择确认 const onCustomSelect (res : string[]) { console.log(自定义选中区间, res) // 更新基准日期为选中起始日 baseDate.value dayuts(res[0]) // 更新全局区间数组 weekRange.value res // 关闭弹窗 popupShow.value false show.value false // 统一走syncEmit派发事件内部自动处理custom逻辑 syncEmit() } /script style langscss scoped .time-switch-wrap { width: 100%; .date-nav-1 { margin-top: 33rpx; display: flex; flex-direction: row; justify-content: center; align-items: center; .nav-left { margin-right: 53rpx; } .nav-right { margin-left: 53rpx; } .date-text { font-weight: 600; font-size: 29rpx; color: #1F2329; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } } } // 平板适配min-width:768px单位px media screen and (min-width: 768px) { .time-switch-wrap { // u-tabs 标签整体微调大屏不拥挤 :deep(.u-tabs) { height: 40rpx !important; } :deep(.u-tabs__wrapper__scroll-view__item) { padding: 0 40rpx; } :deep(.u-tabs__wrapper__scroll-view__item-text) { font-size: 21rpx !important; } .date-nav-1 { margin-top: 24rpx; .nav-left { margin-right: 36rpx; } .nav-right { margin-left: 36rpx; } .date-text { font-size: 22rpx; } } } } /styleimport { dayuts } from /uni_modules/lime-dayuts const timeTyperef(day) 初始类型 const selectDate ref(dayuts().format(YYYY-MM-DD)) 初始时间也就是当前时间 TimeTabSwitch v-modeltimeType :current-dateselectDate changehandleTimeChange / const handleTimeChange (type : TimeDimension, baseDate : string, range ?: { start ?: string; end ?: string; yearMonth ?: string; year ?: string }) { if (type week range) { console.log(周开始, range.start) console.log(周结束, range.end) itemizeModel.startTime range.start itemizeModel.endTime range.end // 接口请求传 start / end } else if (type month range) { console.log(选择年月, range.yearMonth) itemizeModel.startTime range.yearMonth itemizeModel.endTime range.yearMonth } else if (type year range) { console.log(选择年份, range.year) itemizeModel.startTime range.year } else if (type custom range) { itemizeModel.startTime range.start itemizeModel.endTime range.end } else { console.log(当前维度, type, 基准日期, baseDate) itemizeModel.startTime baseDate itemizeModel.endTime baseDate } // 接口请求逻辑 itemizeModel.time type findEnergyConsumptionSubItem()//调用自己方法 }