From f26f29d84e0a68831a6af14dab3eec5500496d2e Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期三, 28 五月 2025 16:48:52 +0800
Subject: [PATCH] 初始化项目

---
 uview-ui/components/u-count-down/u-count-down.vue |  318 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 318 insertions(+), 0 deletions(-)

diff --git a/uview-ui/components/u-count-down/u-count-down.vue b/uview-ui/components/u-count-down/u-count-down.vue
new file mode 100644
index 0000000..7285d67
--- /dev/null
+++ b/uview-ui/components/u-count-down/u-count-down.vue
@@ -0,0 +1,318 @@
+<template>
+	<view class="u-countdown">
+		<view class="u-countdown-item" :style="[itemStyle]" v-if="showDays && (hideZeroDay || (!hideZeroDay && d != '00'))">
+			<view class="u-countdown-time" :style="[letterStyle]">
+				{{ d }}
+			</view>
+		</view>
+		<view
+			class="u-countdown-colon"
+			:style="{fontSize: separatorSize + 'rpx', color: separatorColor, paddingBottom: separator == 'colon' ? '4rpx' : 0}"
+			v-if="showDays && (hideZeroDay || (!hideZeroDay && d != '00'))"
+		>
+			{{ separator == 'colon' ? ':' : '澶�' }}
+		</view>
+		<view class="u-countdown-item" :style="[itemStyle]" v-if="showHours">
+			<view class="u-countdown-time" :style="{ fontSize: fontSize + 'rpx', color: color}">
+				{{ h }}
+			</view>
+		</view>
+		<view
+			class="u-countdown-colon"
+			:style="{fontSize: separatorSize + 'rpx', color: separatorColor, paddingBottom: separator == 'colon' ? '4rpx' : 0}"
+			v-if="showHours"
+		>
+			{{ separator == 'colon' ? ':' : '鏃�' }}
+		</view>
+		<view class="u-countdown-item" :style="[itemStyle]" v-if="showMinutes">
+			<view class="u-countdown-time" :style="{ fontSize: fontSize + 'rpx', color: color}">
+				{{ i }}
+			</view>
+		</view>
+		<view
+			class="u-countdown-colon"
+			:style="{fontSize: separatorSize + 'rpx', color: separatorColor, paddingBottom: separator == 'colon' ? '4rpx' : 0}"
+			v-if="showMinutes"
+		>
+			{{ separator == 'colon' ? ':' : '鍒�' }}
+		</view>
+		<view class="u-countdown-item" :style="[itemStyle]" v-if="showSeconds">
+			<view class="u-countdown-time" :style="{ fontSize: fontSize + 'rpx', color: color}">
+				{{ s }}
+			</view>
+		</view>
+		<view
+			class="u-countdown-colon"
+			:style="{fontSize: separatorSize + 'rpx', color: separatorColor, paddingBottom: separator == 'colon' ? '4rpx' : 0}"
+			v-if="showSeconds && separator == 'zh'"
+		>
+			绉�
+		</view>
+	</view>
+</template>
+
+<script>
+/**
+ * countDown 鍊掕鏃�
+ * @description 璇ョ粍浠朵竴鑸娇鐢ㄤ簬鏌愪釜娲诲姩鐨勬埅姝㈡椂闂翠笂锛岄�氳繃鏁板瓧鐨勫彉鍖栵紝缁欑敤鎴锋槑纭殑鏃堕棿鎰熷彈锛屾彁绀虹敤鎴疯繘琛屾煇涓�涓涓烘搷浣溿��
+ * @tutorial https://www.uviewui.com/components/countDown.html
+ * @property {String Number} timestamp 鍊掕鏃讹紝鍗曚綅涓虹
+ * @property {Boolean} autoplay 鏄惁鑷姩寮�濮嬪�掕鏃讹紝濡傛灉涓篺alse锛岄渶鎵嬪姩璋冪敤寮�濮嬫柟娉曘�傝瀹樼綉璇存槑锛堥粯璁rue锛�
+ * @property {String} separator 鍒嗛殧绗︼紝colon涓鸿嫳鏂囧啋鍙凤紝zh涓轰腑鏂囷紙榛樿colon锛�
+ * @property {String Number} separator-size 鍒嗛殧绗︾殑瀛椾綋澶у皬锛屽崟浣峳px锛堥粯璁�30锛�
+ * @property {String} separator-color 鍒嗛殧绗︾殑棰滆壊锛堥粯璁�#303133锛�
+ * @property {String Number} font-size 鍊掕鏃跺瓧浣撳ぇ灏忥紝鍗曚綅rpx锛堥粯璁�30锛�
+ * @property {Boolean} show-border 鏄惁鏄剧ず鍊掕鏃舵暟瀛楃殑杈规锛堥粯璁alse锛�
+ * @property {Boolean} hide-zero-day 褰�"澶�"鐨勯儴鍒嗕负0鏃讹紝闅愯棌璇ュ瓧娈� 锛堥粯璁rue锛�
+ * @property {String} border-color 鏁板瓧杈规鐨勯鑹诧紙榛樿#303133锛�
+ * @property {String} bg-color 鍊掕鏃舵暟瀛楃殑鑳屾櫙棰滆壊锛堥粯璁�#ffffff锛�
+ * @property {String} color 鍊掕鏃舵暟瀛楃殑棰滆壊锛堥粯璁�#303133锛�
+ * @property {String} height 鏁板瓧楂樺害鍊�(瀹藉害绛夊悓姝ゅ��)锛岃缃竟妗嗘椂鐪嬫儏鍐垫槸鍚﹂渶瑕佽缃鍊硷紝鍗曚綅rpx锛堥粯璁uto锛�
+ * @property {Boolean} show-days 鏄惁鏄剧ず鍊掕鏃剁殑"澶�"閮ㄥ垎锛堥粯璁rue锛�
+ * @property {Boolean} show-hours 鏄惁鏄剧ず鍊掕鏃剁殑"鏃�"閮ㄥ垎锛堥粯璁rue锛�
+ * @property {Boolean} show-minutes 鏄惁鏄剧ず鍊掕鏃剁殑"鍒�"閮ㄥ垎锛堥粯璁rue锛�
+ * @property {Boolean} show-seconds 鏄惁鏄剧ず鍊掕鏃剁殑"绉�"閮ㄥ垎锛堥粯璁rue锛�
+ * @event {Function} end 鍊掕鏃剁粨鏉�
+ * @event {Function} change 姣忕瑙﹀彂涓�娆★紝鍥炶皟涓哄綋鍓嶅墿浣欑殑鍊掕绉掓暟
+ * @example <u-count-down ref="uCountDown" :timestamp="86400" :autoplay="false"></u-count-down>
+ */
+export default {
+	name: 'u-count-down',
+	props: {
+		// 鍊掕鏃剁殑鏃堕棿锛岀涓哄崟浣�
+		timestamp: {
+			type: [Number, String],
+			default: 0
+		},
+		// 鏄惁鑷姩寮�濮嬪�掕鏃�
+		autoplay: {
+			type: Boolean,
+			default: true
+		},
+		// 鐢ㄨ嫳鏂囧啋鍙�(colon)鎴栬�呬腑鏂�(zh)褰撳仛鍒嗛殧绗︼紝false鐨勬椂鍊欎负涓枃锛屽锛�"11:22"鎴�"11鏃�22绉�"
+		separator: {
+			type: String,
+			default: 'colon'
+		},
+		// 鍒嗛殧绗︾殑澶у皬锛屽崟浣峳px
+		separatorSize: {
+			type: [Number, String],
+			default: 30
+		},
+		// 鍒嗛殧绗﹂鑹�
+		separatorColor: {
+			type: String,
+			default: "#303133"
+		},
+		// 瀛椾綋棰滆壊
+		color: {
+			type: String,
+			default: '#303133'
+		},
+		// 瀛椾綋澶у皬锛屽崟浣峳px
+		fontSize: {
+			type: [Number, String],
+			default: 30
+		},
+		// 鑳屾櫙棰滆壊
+		bgColor: {
+			type: String,
+			default: '#fff'
+		},
+		// 鏁板瓧妗嗛珮搴︼紝鍗曚綅rpx
+		height: {
+			type: [Number, String],
+			default: 'auto'
+		},
+		// 鏄惁鏄剧ず鏁板瓧妗�
+		showBorder: {
+			type: Boolean,
+			default: false
+		},
+		// 杈规棰滆壊
+		borderColor: {
+			type: String,
+			default: '#303133'
+		},
+		// 鏄惁鏄剧ず绉�
+		showSeconds: {
+			type: Boolean,
+			default: true
+		},
+		// 鏄惁鏄剧ず鍒嗛挓
+		showMinutes: {
+			type: Boolean,
+			default: true
+		},
+		// 鏄惁鏄剧ず灏忔椂
+		showHours: {
+			type: Boolean,
+			default: true
+		},
+		// 鏄惁鏄剧ず鈥滃ぉ鈥�
+		showDays: {
+			type: Boolean,
+			default: true
+		},
+		// 褰�"澶�"鐨勯儴鍒嗕负0鏃讹紝涓嶆樉绀�
+		hideZeroDay: {
+			type: Boolean,
+			default: false
+		}
+	},
+	watch: {
+		// 鐩戝惉鏃堕棿鎴崇殑鍙樺寲
+		timestamp(newVal, oldVal) {
+			// 濡傛灉鍊掕鏃堕棿鍙戠敓鍙樺寲锛屾竻闄ゅ畾鏃跺櫒锛岄噸鏂板紑濮嬪�掕鏃�
+			this.clearTimer();
+			this.start();
+		}
+	},
+	data() {
+		return {
+			d: '00', // 澶╃殑榛樿鍊�
+			h: '00', // 灏忔椂鐨勯粯璁ゅ��
+			i: '00', // 鍒嗛挓鐨勯粯璁ゅ��
+			s: '00', // 绉掔殑榛樿鍊�
+			timer: null ,// 瀹氭椂鍣�
+			seconds: 0, // 璁板綍涓嶅仠鍊掕杩囩▼涓彉鍖栫殑绉掓暟
+		};
+	},
+	computed: {
+		// 鍊掕鏃秈tem鐨勬牱寮忥紝item涓哄垎鍒殑鏃跺垎绉掗儴鍒嗙殑鏁板瓧
+		itemStyle() {
+			let style = {};
+			if(this.height) {
+				style.height = this.height + 'rpx';
+				style.width = this.height + 'rpx';
+			}
+			if(this.showBorder) {
+				style.borderStyle = 'solid';
+				style.borderColor = this.borderColor;
+				style.borderWidth = '1px';
+			}
+			if(this.bgColor) {
+				style.backgroundColor = this.bgColor;
+			}
+			return style;
+		},
+		// 鍊掕鏃舵暟瀛楃殑鏍峰紡
+		letterStyle() {
+			let style = {};
+			if(this.fontSize) style.fontSize = this.fontSize +  'rpx';
+			if(this.color) style.color = this.color;
+			return style;
+		}
+	},
+	mounted() {
+		// 濡傛灉鑷姩鍊掕鏃�
+		this.autoplay && this.timestamp && this.start();
+	},
+	methods: {
+		// 鍊掕鏃�
+		start() {
+			// 閬垮厤鍙兘鍑虹幇鐨勫�掕鏃堕噸鍙犳儏鍐�
+			this.clearTimer();
+			if (this.timestamp <= 0) return;
+			this.seconds = Number(this.timestamp);
+			this.formatTime(this.seconds);
+			this.timer = setInterval(() => {
+				this.seconds--;
+				// 鍙戝嚭change浜嬩欢
+				this.$emit('change', this.seconds);
+				if (this.seconds < 0) {
+					return this.end();
+				}
+				this.formatTime(this.seconds);
+			}, 1000);
+		},
+		// 鏍煎紡鍖栨椂闂�
+		formatTime(seconds) {
+			// 灏忎簬绛変簬0鐨勮瘽锛岀粨鏉熷�掕鏃�
+			seconds <= 0 && this.end();
+			let [day, hour, minute, second] = [0, 0, 0, 0];
+			day = Math.floor(seconds / (60 * 60 * 24));
+			// 鍒ゆ柇鏄惁鏄剧ず鈥滃ぉ鈥濆弬鏁帮紝濡傛灉涓嶆樉绀猴紝灏嗗ぉ閮ㄥ垎鐨勫�硷紝鍔犲叆鍒板皬鏃朵腑
+			// hour涓虹粰鍚庨潰璁$畻绉掑拰鍒嗙瓑鐢ㄧ殑(鍩轰簬鏄剧ず澶╃殑鍓嶆彁涓嬭绠�)
+			hour = Math.floor(seconds / (60 * 60)) - day * 24;
+			// showHour涓洪渶瑕佹樉绀虹殑灏忔椂
+			let showHour = null;
+			if(this.showDays) {
+				showHour = hour;
+			} else {
+				// 濡傛灉涓嶆樉绀哄ぉ鏁帮紝灏嗏�滃ぉ鈥濋儴鍒嗙殑鏃堕棿鎶樼畻鍒板皬鏃朵腑鍘�
+				showHour = Math.floor(seconds / (60 * 60));
+			}
+			minute = Math.floor(seconds / 60) - hour * 60 - day * 24 * 60;
+			second = Math.floor(seconds) - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60;
+			// 濡傛灉灏忎簬10锛屽湪鍓嶉潰琛ヤ笂涓�涓�"0"
+			showHour = showHour < 10 ? '0' + showHour : showHour;
+			minute = minute < 10 ? '0' + minute : minute;
+			second = second < 10 ? '0' + second : second;
+			day = day < 10 ? '0' + day : day;
+			this.d = day;
+			this.h = showHour;
+			this.i = minute;
+			this.s = second;
+		},
+		// 鍋滄鍊掕鏃�
+		end() {
+			this.clearTimer();
+			this.$emit('end', {});
+		},
+		// 娓呴櫎瀹氭椂鍣�
+		clearTimer() {
+			if(this.timer) {
+				// 娓呴櫎瀹氭椂鍣�
+				clearInterval(this.timer);
+				this.timer = null;
+			}
+		}
+	},
+	beforeDestroy() {
+		clearInterval(this.timer);
+		this.timer = null;
+	}
+};
+</script>
+
+<style scoped lang="scss">
+	@import "../../libs/css/style.components.scss";
+
+	.u-countdown {
+		/* #ifndef APP-NVUE */
+		display: inline-flex;		
+		/* #endif */
+		align-items: center;
+	}
+
+	.u-countdown-item {
+		@include vue-flex;
+		align-items: center;
+		justify-content: center;
+		padding: 2rpx;
+		border-radius: 6rpx;
+		white-space: nowrap;
+		transform: translateZ(0);
+	}
+
+	.u-countdown-time {
+		margin: 0;
+		padding: 0;
+		line-height: 1;
+	}
+
+	.u-countdown-colon {
+		@include vue-flex;
+		justify-content: center;
+		padding: 0 5rpx;
+		line-height: 1;
+		align-items: center;
+		padding-bottom: 4rpx;
+	}
+
+	.u-countdown-scale {
+		transform: scale(0.9);
+		transform-origin: center center;
+	}
+</style>

--
Gitblit v1.9.3