From d1448cb0ef10f358bb7bddb4e1ec268515e0b787 Mon Sep 17 00:00:00 2001 From: gaoluyang <2820782392@qq.com> Date: 星期二, 15 七月 2025 11:46:57 +0800 Subject: [PATCH] 项目初始化 --- uni_modules/uview-ui/components/u-calendar/u-calendar.vue | 383 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 383 insertions(+), 0 deletions(-) diff --git a/uni_modules/uview-ui/components/u-calendar/u-calendar.vue b/uni_modules/uview-ui/components/u-calendar/u-calendar.vue new file mode 100644 index 0000000..ad892ff --- /dev/null +++ b/uni_modules/uview-ui/components/u-calendar/u-calendar.vue @@ -0,0 +1,383 @@ +<template> + <u-popup + :show="show" + mode="bottom" + closeable + @close="close" + :round="round" + :closeOnClickOverlay="closeOnClickOverlay" + > + <view class="u-calendar"> + <uHeader + :title="title" + :subtitle="subtitle" + :showSubtitle="showSubtitle" + :showTitle="showTitle" + ></uHeader> + <scroll-view + :style="{ + height: $u.addUnit(listHeight) + }" + scroll-y + @scroll="onScroll" + :scroll-top="scrollTop" + :scrollIntoView="scrollIntoView" + > + <uMonth + :color="color" + :rowHeight="rowHeight" + :showMark="showMark" + :months="months" + :mode="mode" + :maxCount="maxCount" + :startText="startText" + :endText="endText" + :defaultDate="defaultDate" + :minDate="innerMinDate" + :maxDate="innerMaxDate" + :maxMonth="monthNum" + :readonly="readonly" + :maxRange="maxRange" + :rangePrompt="rangePrompt" + :showRangePrompt="showRangePrompt" + :allowSameDay="allowSameDay" + ref="month" + @monthSelected="monthSelected" + @updateMonthTop="updateMonthTop" + ></uMonth> + </scroll-view> + <slot name="footer" v-if="showConfirm"> + <view class="u-calendar__confirm"> + <u-button + shape="circle" + :text=" + buttonDisabled ? confirmDisabledText : confirmText + " + :color="color" + @click="confirm" + :disabled="buttonDisabled" + ></u-button> + </view> + </slot> + </view> + </u-popup> +</template> + +<script> +import uHeader from './header.vue' +import uMonth from './month.vue' +import props from './props.js' +import util from './util.js' +import dayjs from '../../libs/util/dayjs.js' +import Calendar from '../../libs/util/calendar.js' +/** + * Calendar 鏃ュ巻 + * @description 姝ょ粍浠剁敤浜庡崟涓�夋嫨鏃ユ湡锛岃寖鍥撮�夋嫨鏃ユ湡绛夛紝鏃ュ巻琚寘瑁瑰湪搴曢儴寮硅捣鐨勫鍣ㄤ腑. + * @tutorial https://www.uviewui.com/components/calendar.html + * + * @property {String} title 鏍囬鍐呭 (榛樿 鏃ユ湡閫夋嫨 ) + * @property {Boolean} showTitle 鏄惁鏄剧ず鏍囬 (榛樿 true ) + * @property {Boolean} showSubtitle 鏄惁鏄剧ず鍓爣棰� (榛樿 true ) + * @property {String} mode 鏃ユ湡绫诲瀷閫夋嫨 single-閫夋嫨鍗曚釜鏃ユ湡锛宮ultiple-鍙互閫夋嫨澶氫釜鏃ユ湡锛宺ange-閫夋嫨鏃ユ湡鑼冨洿 锛� 榛樿 'single' ) + * @property {String} startText mode=range鏃讹紝绗竴涓棩鏈熷簳閮ㄧ殑鎻愮ず鏂囧瓧 (榛樿 '寮�濮�' ) + * @property {String} endText mode=range鏃讹紝鏈�鍚庝竴涓棩鏈熷簳閮ㄧ殑鎻愮ず鏂囧瓧 (榛樿 '缁撴潫' ) + * @property {Array} customList 鑷畾涔夊垪琛� + * @property {String} color 涓婚鑹诧紝瀵瑰簳閮ㄦ寜閽拰閫変腑鏃ユ湡鏈夋晥 (榛樿 鈥�#3c9cff' ) + * @property {String | Number} minDate 鏈�灏忕殑鍙�夋棩鏈� (榛樿 0 ) + * @property {String | Number} maxDate 鏈�澶у彲閫夋棩鏈� (榛樿 0 ) + * @property {Array | String| Date} defaultDate 榛樿閫変腑鐨勬棩鏈燂紝mode涓簃ultiple鎴杛ange鏄繀椤讳负鏁扮粍鏍煎紡 + * @property {String | Number} maxCount mode=multiple鏃讹紝鏈�澶氬彲閫夊灏戜釜鏃ユ湡 (榛樿 Number.MAX_SAFE_INTEGER ) + * @property {String | Number} rowHeight 鏃ユ湡琛岄珮 (榛樿 56 ) + * @property {Function} formatter 鏃ユ湡鏍煎紡鍖栧嚱鏁� + * @property {Boolean} showLunar 鏄惁鏄剧ず鍐滃巻 (榛樿 false ) + * @property {Boolean} showMark 鏄惁鏄剧ず鏈堜唤鑳屾櫙鑹� (榛樿 true ) + * @property {String} confirmText 纭畾鎸夐挳鐨勬枃瀛� (榛樿 '纭畾' ) + * @property {String} confirmDisabledText 纭鎸夐挳澶勪簬绂佺敤鐘舵�佹椂鐨勬枃瀛� (榛樿 '纭畾' ) + * @property {Boolean} show 鏄惁鏄剧ず鏃ュ巻寮圭獥 (榛樿 false ) + * @property {Boolean} closeOnClickOverlay 鏄惁鍏佽鐐瑰嚮閬僵鍏抽棴鏃ュ巻 (榛樿 false ) + * @property {Boolean} readonly 鏄惁涓哄彧璇荤姸鎬侊紝鍙鐘舵�佷笅绂佹閫夋嫨鏃ユ湡 (榛樿 false ) + * @property {String | Number} maxRange 鏃ユ湡鍖洪棿鏈�澶氬彲閫夊ぉ鏁帮紝榛樿鏃犻檺鍒讹紝mode = range鏃舵湁鏁� + * @property {String} rangePrompt 鑼冨洿閫夋嫨瓒呰繃鏈�澶氬彲閫夊ぉ鏁版椂鐨勬彁绀烘枃妗堬紝mode = range鏃舵湁鏁� + * @property {Boolean} showRangePrompt 鑼冨洿閫夋嫨瓒呰繃鏈�澶氬彲閫夊ぉ鏁版椂锛屾槸鍚﹀睍绀烘彁绀烘枃妗堬紝mode = range鏃舵湁鏁� (榛樿 true ) + * @property {Boolean} allowSameDay 鏄惁鍏佽鏃ユ湡鑼冨洿鐨勮捣姝㈡椂闂翠负鍚屼竴澶╋紝mode = range鏃舵湁鏁� (榛樿 false ) + * @property {Number|String} round 鍦嗚鍊硷紝榛樿鏃犲渾瑙� (榛樿 0 ) + * @property {Number|String} monthNum 鏈�澶氬睍绀虹殑鏈堜唤鏁伴噺 (榛樿 3 ) + * + * @event {Function()} confirm 鐐瑰嚮纭畾鎸夐挳鏃惰Е鍙� 閫夋嫨鏃ユ湡鐩稿叧鐨勮繑鍥炲弬鏁� + * @event {Function()} close 鏃ュ巻鍏抽棴鏃惰Е鍙� 鍙畾涔夐〉闈㈠叧闂椂鐨勫洖璋冧簨浠� + * @example <u-calendar :defaultDate="defaultDateMultiple" :show="show" mode="multiple" @confirm="confirm"> + </u-calendar> + * */ +export default { + name: 'u-calendar', + mixins: [uni.$u.mpMixin, uni.$u.mixin, props], + components: { + uHeader, + uMonth + }, + data() { + return { + // 闇�瑕佹樉绀虹殑鏈堜唤鐨勬暟缁� + months: [], + // 鍦ㄦ湀浠芥粴鍔ㄥ尯鍩熶腑锛屽綋鍓嶈鍥句腑鏈堜唤鐨刬ndex绱㈠紩 + monthIndex: 0, + // 鏈堜唤婊氬姩鍖哄煙鐨勯珮搴� + listHeight: 0, + // month缁勪欢涓�夋嫨鐨勬棩鏈熸暟缁� + selected: [], + scrollIntoView: '', + scrollTop:0, + // 杩囨护澶勭悊鏂规硶 + innerFormatter: (value) => value + } + }, + watch: { + selectedChange: { + immediate: true, + handler(n) { + this.setMonth() + } + }, + // 鎵撳紑寮圭獥鏃讹紝璁剧疆鏈堜唤鏁版嵁 + show: { + immediate: true, + handler(n) { + this.setMonth() + } + } + }, + computed: { + // 鐢变簬maxDate鍜宮inDate鍙互涓哄瓧绗︿覆(2021-10-10)锛屾垨鑰呮暟鍊�(鏃堕棿鎴�)锛屼絾鏄痙ayjs濡傛灉鎺ュ彈瀛楃涓插舰寮忕殑鏃堕棿鎴充細鏈夐棶棰橈紝杩欓噷杩涜澶勭悊 + innerMaxDate() { + return uni.$u.test.number(this.maxDate) + ? Number(this.maxDate) + : this.maxDate + }, + innerMinDate() { + return uni.$u.test.number(this.minDate) + ? Number(this.minDate) + : this.minDate + }, + // 澶氫釜鏉′欢鐨勫彉鍖栵紝浼氬紩璧烽�変腑鏃ユ湡鐨勫彉鍖栵紝杩欓噷缁熶竴绠$悊鐩戝惉 + selectedChange() { + return [this.innerMinDate, this.innerMaxDate, this.defaultDate] + }, + subtitle() { + // 鍒濆鍖栨椂锛宼his.months涓虹┖鏁扮粍锛屾墍浠ラ渶瑕佺壒鍒垽鏂鐞� + if (this.months.length) { + return `${this.months[this.monthIndex].year}骞�${ + this.months[this.monthIndex].month + }鏈坄 + } else { + return '' + } + }, + buttonDisabled() { + // 濡傛灉涓簉ange绫诲瀷锛屼笖閫夋嫨鐨勬棩鏈熶釜鏁颁笉瓒�1涓椂锛岃搴曢儴鐨勬寜閽嚭浜巇isabled鐘舵�� + if (this.mode === 'range') { + if (this.selected.length <= 1) { + return true + } else { + return false + } + } else { + return false + } + } + }, + mounted() { + this.start = Date.now() + this.init() + }, + methods: { + // 鍦ㄥ井淇″皬绋嬪簭涓紝涓嶆敮鎸佸皢鍑芥暟褰撳仛props鍙傛暟锛屾晠鍙兘閫氳繃ref褰㈠紡璋冪敤 + setFormatter(e) { + this.innerFormatter = e + }, + // month缁勪欢鍐呴儴閫夋嫨鏃ユ湡鍚庯紝閫氳繃浜嬩欢閫氱煡缁欑埗缁勪欢 + monthSelected(e) { + this.selected = e + if (!this.showConfirm) { + // 鍦ㄤ笉闇�瑕佺‘璁ゆ寜閽殑鎯呭喌涓嬶紝濡傛灉涓哄崟閫夛紝鎴栬�呰寖鍥村閫変笖宸查�夐暱搴﹀ぇ浜�2锛屽垯鐩存帴杩涜杩旇繕 + if ( + this.mode === 'multiple' || + this.mode === 'single' || + (this.mode === 'range' && this.selected.length >= 2) + ) { + this.$emit('confirm', this.selected) + } + } + }, + init() { + // 鏍¢獙maxDate锛屼笉鑳藉皬浜庡綋鍓嶆椂闂� + if ( + this.innerMaxDate && + new Date(this.innerMaxDate).getTime() <= Date.now() + ) { + return uni.$u.error('maxDate涓嶈兘灏忎簬褰撳墠鏃堕棿') + } + // 婊氬姩鍖哄煙鐨勯珮搴� + this.listHeight = this.rowHeight * 5 + 30 + this.setMonth() + }, + close() { + this.$emit('close') + }, + // 鐐瑰嚮纭畾鎸夐挳 + confirm() { + if (!this.buttonDisabled) { + this.$emit('confirm', this.selected) + } + }, + // 鑾峰緱涓や釜鏃ユ湡涔嬮棿鐨勬湀浠芥暟 + getMonths(minDate, maxDate) { + const minYear = dayjs(minDate).year() + const minMonth = dayjs(minDate).month() + 1 + const maxYear = dayjs(maxDate).year() + const maxMonth = dayjs(maxDate).month() + 1 + return (maxYear - minYear) * 12 + (maxMonth - minMonth) + 1 + }, + // 璁剧疆鏈堜唤鏁版嵁 + setMonth() { + // 鏈�灏忔棩鏈熺殑姣鏁� + const minDate = this.innerMinDate || dayjs().valueOf() + // 濡傛灉娌℃湁鎸囧畾鏈�澶ф棩鏈燂紝鍒欏線鍚庢帹3涓湀 + const maxDate = + this.innerMaxDate || + dayjs(minDate) + .add(this.monthNum - 1, 'month') + .valueOf() + // 鏈�澶ф渶灏忔湀浠戒箣闂寸殑鍏辨湁澶氬皯涓湀浠斤紝 + const months = uni.$u.range( + 1, + this.monthNum, + this.getMonths(minDate, maxDate) + ) + // 鍏堟竻绌烘暟缁� + this.months = [] + for (let i = 0; i < months; i++) { + this.months.push({ + date: new Array( + dayjs(minDate).add(i, 'month').daysInMonth() + ) + .fill(1) + .map((item, index) => { + // 鏃ユ湡锛屽彇鍊�1-31 + let day = index + 1 + // 鏄熸湡锛�0-6锛�0涓哄懆鏃� + const week = dayjs(minDate) + .add(i, 'month') + .date(day) + .day() + const date = dayjs(minDate) + .add(i, 'month') + .date(day) + .format('YYYY-MM-DD') + let bottomInfo = '' + if (this.showLunar) { + // 灏嗘棩鏈熻浆涓哄啘鍘嗘牸寮� + const lunar = Calendar.solar2lunar( + dayjs(date).year(), + dayjs(date).month() + 1, + dayjs(date).date() + ) + bottomInfo = lunar.IDayCn + } + let config = { + day, + week, + // 灏忎簬鏈�灏忓厑璁哥殑鏃ユ湡锛屾垨鑰呭ぇ浜庢渶澶х殑鏃ユ湡锛屽垯璁剧疆涓篸isabled鐘舵�� + disabled: + dayjs(date).isBefore( + dayjs(minDate).format('YYYY-MM-DD') + ) || + dayjs(date).isAfter( + dayjs(maxDate).format('YYYY-MM-DD') + ), + // 杩斿洖涓�涓棩鏈熷璞★紝渚涘閮ㄧ殑formatter鑾峰彇褰撳墠鏃ユ湡鐨勫勾鏈堟棩绛変俊鎭紝杩涜鍔犲伐澶勭悊 + date: new Date(date), + bottomInfo, + dot: false, + month: + dayjs(minDate).add(i, 'month').month() + 1 + } + const formatter = + this.formatter || this.innerFormatter + return formatter(config) + }), + // 褰撳墠鎵�灞炵殑鏈堜唤 + month: dayjs(minDate).add(i, 'month').month() + 1, + // 褰撳墠骞翠唤 + year: dayjs(minDate).add(i, 'month').year() + }) + } + + }, + // 婊氬姩鍒伴粯璁よ缃殑鏈堜唤 + scrollIntoDefaultMonth(selected) { + // 鏌ヨ榛樿鏃ユ湡鍦ㄥ彲閫夊垪琛ㄧ殑涓嬫爣 + const _index = this.months.findIndex(({ + year, + month + }) => { + month = uni.$u.padZero(month) + return `${year}-${month}` === selected + }) + if (_index !== -1) { + // #ifndef MP-WEIXIN + this.$nextTick(() => { + this.scrollIntoView = `month-${_index}` + }) + // #endif + // #ifdef MP-WEIXIN + this.scrollTop = this.months[_index].top || 0; + // #endif + } + }, + // scroll-view婊氬姩鐩戝惉 + onScroll(event) { + // 涓嶅厑璁稿皬浜�0鐨勬粴鍔ㄥ�硷紝濡傛灉scroll-view鍒伴《浜嗭紝缁х画涓嬫媺锛屼細鍑虹幇璐熸暟鍊� + const scrollTop = Math.max(0, event.detail.scrollTop) + // 灏嗗綋鍓嶆粴鍔ㄦ潯鏁板�硷紝闄や互婊氬姩鍖哄煙鐨勯珮搴︼紝鍙互寰楀嚭褰撳墠婊氬姩鍒颁簡鍝竴涓湀浠界殑绱㈠紩 + for (let i = 0; i < this.months.length; i++) { + if (scrollTop >= (this.months[i].top || this.listHeight)) { + this.monthIndex = i + } + } + }, + // 鏇存柊鏈堜唤鐨則op鍊� + updateMonthTop(topArr = []) { + // 璁剧疆瀵瑰簲鏈堜唤鐨則op鍊硷紝鐢ㄤ簬onScroll鏂规硶鏇存柊鏈堜唤 + topArr.map((item, index) => { + this.months[index].top = item + }) + + // 鑾峰彇榛樿鏃ユ湡鐨勪笅鏍� + if (!this.defaultDate) { + // 濡傛灉娌℃湁璁剧疆榛樿鏃ユ湡锛屽垯灏嗗綋澶╂棩鏈熻缃负榛樿閫変腑鐨勬棩鏈� + const selected = dayjs().format("YYYY-MM") + this.scrollIntoDefaultMonth(selected) + return + } + let selected = dayjs().format("YYYY-MM"); + // 鍗曢�夋ā寮忥紝鍙互鏄瓧绗︿覆鎴栨暟缁勶紝Date瀵硅薄绛� + if (!uni.$u.test.array(this.defaultDate)) { + selected = dayjs(this.defaultDate).format("YYYY-MM") + } else { + selected = dayjs(this.defaultDate[0]).format("YYYY-MM"); + } + this.scrollIntoDefaultMonth(selected) + } + } +} +</script> + +<style lang="scss" scoped> +@import '../../libs/css/components.scss'; + +.u-calendar { + &__confirm { + padding: 7px 18px; + } +} +</style> -- Gitblit v1.9.3