vue中一周的时间选择多个阶段(手动表格选择)

 先给大家看一下效果图

 源代码

<template>
	<div style="width: 45%">
		<div style="width: 100%">
			<div class="time">
				<div class="timeleft">星期/时间</div>
				<div class="timeright">
					<div class="timeright_cell">
						<el-row :gutter="0">
							<el-col :span="12">
								<div class="topitem" style="font-size: 12px; font-weight: bold">
									00:00~12:00
								</div>
							</el-col>
							<el-col :span="12">
								<div class="topitem" style="font-size: 12px; font-weight: bold">
									12:00~24:00
								</div>
							</el-col>
						</el-row>
					</div>
					<div class="timeright_cell" style="color: #333333">
						<el-row :gutter="0">
							<el-col
								:span="1"
								v-for="(item, index) in 24"
								:key="item"
								@click="clicktime(index)"
							>
								<div
									class="topitem"
									:style="{ '--bgColor': bgColor }"
									:class="{ is_selected: isTimeSelected(index) }"
								>
									{{ index }}
								</div>
							</el-col>
						</el-row>
					</div>
				</div>
			</div>
			<div class="time">
				<div style="width: 8.8%">
					<div
						class="timelefts"
						:style="{ '--bgColor': bgColor }"
						:class="{ is_selected: isDaySelected(index) }"
						v-for="(dayName, index) in [
							'星期一',
							'星期二',
							'星期三',
							'星期四',
							'星期五',
							'星期六',
							'星期日'
						]"
						:key="dayName"
						@click="clickDay(index)"
					>
						{{ dayName }}
					</div>
				</div>

				<div class="objects" ref="objectsRef" @mousedown="handleMouseDown">
					<!-- 矩形选择框 -->
					<div
						class="mask"
						ref="maskRef"
						v-show="maskPosition.show"
						:style="
							'width:' +
							maskWidth +
							'left:' +
							maskLeft +
							'height:' +
							maskHeight +
							'top:' +
							maskTop
						"
					/>

					<!-- 选择对象内容的目标插槽 -->
					<!-- <slot name="selcetObject" /> -->
					<div class="objects_content">
						<div
							v-for="item in weekData"
							:key="item.id"
							class="select_object"
							:day_index="item.daynum"
							:time_index="item.timenum"
							:object_id="item.id"
							:class="{ is_selected: item.status }"
							:style="{ '--bgColor': bgColor }"
						>
							<!-- {{ item.id }} -->
						</div>
					</div>
				</div>
			</div>
			<!-- 鼠标画矩形选择对象 -->
		</div>
		<div class="box">
			<div>
				<div class="dt">已选择时间段</div>
				<!-- 按钮-->
				<el-button v-for="button in buttons" :key="button.text" :type="button.type" link>
					{{ button.text }}
				</el-button>
			</div>
			<div class="dtime">
				<ul
					v-for="item in weekData
						.filter((t) => t.status == true)
						.reduce(
							(prev, curr) =>
								prev.find((t) => t.daynum == curr.daynum) ? prev : [...prev, curr],
							[]
						)"
				>
					星期{{
						convertSum(item.daynum)
					}}:
					<span class="dts" v-for="item in tList(item.daynum)">
						{{ convertTime(item) }}
						<!--{{ item.timenum - 1 }}:{{ item.id % 2 == 0 ? "30" : "00" }} ~{{ item.timenum - 1 }}:{{ item.id % 1 == 0 ? "30" : "00" }}-->
					</span>
				</ul>
			</div>
		</div>
	</div>
</template>

<script lang="ts" setup>
import { reactive, toRefs, ref, computed, onMounted, onBeforeMount } from "vue";
//数据格式1:默认0或者1,数据格式2:json字符串(x-(1-7)对应周一到周日), 如timeSet=”{‘1’:‘1,2,3’}”表示周一的0:30-1:00,1:00-1:30,1:30-2:00为播放时间,数据格式3:字符串,xHHmm x为1-7对应周一到周日,HH为小时,mm,00或30  00表示00-30这半小时, 30表示30-00这半小时
// 数据格式2:
// 格式为json字符串,(x-(1-7)对应周一到周日), 如timeSet=”{‘1’:‘1,2,3’}”表示周一的0:30-1:00,1:00-1:30,1:30-2:00为播放时间,
// 数据格式3:
// 格式是字符串,xHHmm     x为1-7对应周一到周日,HH为小时,mm,00或30  00表示00-30这半小时, 30表示30-00这半小时
// 10600,10630,10700,10730,10800,10830,10900,10930,11000,11030,11100,11130,11200,11230,11300,11330,11400,11430,11500,11530,11600,11630,11700,11730,11800,11830,11900,11930,12000,12030,12100,12130,12200,12230,12300,12330,20600,20630,20700,20730,20800,20830,20900,20930,21000,21030,21100,21130,21200,21230,21300
const clientX = ref(0);
const clientY = ref(0);

const props = withDefaults(
	defineProps<{
		datatype?: number; //数据类型
		week?: String; //绑定数组
		objectClassName?: string; // 选择对象的class name,用于定义如何获取对象
		objectIdName?: string; // 选择对象的id name,用于定义如何获取对象的id
		useCtrlSelect?: boolean; // 是否支持按住Ctrl多选
		bgColor?: string; //选中的背景色
	}>(),
	{
		datatype: 1,
		objectClassName: "select_object",
		objectIdName: "object_id",
		bgColor: "#197afb",
		useCtrlSelect: false // 默认支持按住Ctrl多选
	}
);
function findTimeInterval(arr) {
	if (arr.length === 0) return [];

	let intervals = [];
	let startTime = arr[0];
	let endTime = arr[0];

	for (let i = 1; i < arr.length; i++) {
		if (arr[i] === endTime + 1) {
			endTime = arr[i];
		} else {
			intervals.push({ startTime: startTime, endTime: endTime });
			startTime = arr[i];
			endTime = arr[i];
		}
	}
	intervals.push({ startTime: startTime, endTime: endTime });

	return intervals;
}

const convertTime = (items) => {
	let result = "";
	// 	<!--{{ item.timenum - 1 }}:{{ item.id % 2 == 0 ? "30" : "00" }} ~{{ item.timenum - 1 }}:{{ item.id % 1 == 0 ? "30" : "00" }}-->
	let list = items.map((el) => el.id);
	let convertList = findTimeInterval(list);
	console.log("转换后的", convertList);
	if (convertList?.length > 0) {
		convertList.forEach((el) => {
			let start = items.find((item) => el.startTime == item.id);
			let end = items.find((item) => el.endTime == item.id);
			console.log("end", end);
			if (el.startTime == el.endTime) {
				let startStr = `${formatNum(start.timenum - 1)} : ${start.id % 2 == 0 ? "30" : "00"} `;
				let endStr = "";
				if (end.id % 2 != 0) {
					endStr = `${formatNum(end.timenum - 1)} : 30`;
				} else {
					endStr = `${formatNum(end.timenum)} : 00`;
				}
				result += `${startStr} ~ ${endStr}`;
			} else {
				// 不一致 的
				let endStr = "";
				let startStr = `${formatNum(start.timenum - 1)} : ${start.id % 2 == 0 ? "30" : "00"} `;
				// 结束时间存在问题, 单个多半个小时
				if (el.endTime % 2 == 0) {
					endStr = `${formatNum(end.timenum)} : 00`;
				} else {
					endStr = `${formatNum(end.timenum - 1)} : 30`;
				}
				result += `${startStr} ~ ${endStr}`;
			}
		});
	}
	return result;
};

const formatNum = (num) => {
	return num < 10 ? `0${num}` : num;
}

/**
 * 转换星期
 * @param daynum
 */
const convertSum = (daynum) => {
	switch (daynum) {
		case 1:
			return "一";
		case 2:
			return "二";
		case 3:
			return "三";
		case 4:
			return "四";
		case 5:
			return "五";
		case 6:
			return "六";
		case 7:
			return "日";
	}
};

const tempStr = ref([]);
const tempStrComputed = computed(() => {
	return JSON.stringify(tempStr);
});

const tList = (daynum) => {
	let tArr = [];
	let tItem = [];
	let dayList = weekData.value
		.filter((t) => t.status == true)
		.reduce(
			(prev, curr) => (prev.find((t) => t.daynum == curr.daynum) ? prev : [...prev, curr]),
			[]
		);
	let dayAllDataList = weekData.value.filter((t) => t.daynum == daynum);
	for (let i = 0; i < dayAllDataList.length; i++) {
		let item = dayAllDataList[i];
		if (item.status == false) {
			if (tItem.length > 0) {
				tArr.push(new Array(...tItem));
				tItem.length = 0;
			}
		} else tItem.push(item);
	}
	if (tItem.length > 0) {
		tArr.push(new Array(...tItem));
		tItem.length = 0;
	}
	return tArr;
};

// const tList = computed(() => {
// 	console.log('tList');
// 	let tArr = [];
// 	let tItem = [];
// 	let dayList = weekData.value.filter(t=>t.status==true).reduce((prev, curr) => prev.find(t=>t.daynum == curr.daynum) ? prev : [...prev, curr], [])
// 	let dayAllDataList = weekData.value.filter(t=>t.daynum==2);
//
// 	for (let i = 0; i < dayAllDataList; i++) {
// 		let item = dayAllDataList[i];
// 		if(item.status==false){
// 			if (tItem.length > 0) {
// 				tArr.push(tItem);
// 				tItem.length = 0;
// 			}
// 		}else
// 			tItem.push(item);
// 	}
// 	return tArr;
// })
const hasHandleObjectIds = ref<number[]>([]); //已处理id数组
// 全局计数器
let uniqueId = 1;
// 初始化 weekData
const weekData = ref([] as any);
// 初始化 weekData 中的 hours
onMounted(() => {
	for (let i = 0; i < 7; i++) {
		for (let hour = 0, timenum = 1; hour < 48; hour += 2) {
			weekData.value.push({ id: uniqueId++, status: false, daynum: i + 1, timenum: timenum });
			weekData.value.push({ id: uniqueId++, status: false, daynum: i + 1, timenum: timenum });
			timenum = (timenum % 24) + 1; // 使 timenum 在 1 到 24 之间循环
		}
	}
	if (props.week) {
		datahandle();
	}
});

//初始化处理数据
const datahandle = () => {
	let data: any = props.week === undefined ? [] : props.week;
	if (props.datatype == 1) {
		for (let i = 0; i < data.length; i++) {
			if (Number(data[i]) == 1) {
				weekData.value[i].status = true;
			}
		}
	} else if (props.datatype == 2) {
		let obj: any = JSON.parse(data);
		for (const key in obj) {
			let value = obj[key].split(",");
			for (let i = 0; i < weekData.value.length; i++) {
				const element = weekData.value[i];
				if (element.daynum == key) {
					if (value.includes(String(i))) {
						weekData.value[i].status = true;
					}
				}
			}
		}
	} else if (props.datatype == 3) {
		let array = data.split(",");
		for (let i = 0; i < array.length; i++) {
			const element = array[i];
			const dayNum = Number(element.slice(0, 1));
			const hourNum = Number(element.slice(1, 3).replace(/\b(0+)/gi, ""));
			const timeNum = element.slice(3, 5);
			for (let i = 0; i < weekData.value.length; i++) {
				const element = weekData.value[i];
				if (element.daynum == dayNum && element.timenum == hourNum) {
					if (timeNum == "00") {
						if (i % 2 === 0) {
							weekData.value[i].status = true;
						}
					} else {
						if (i % 2 !== 0) {
							weekData.value[i].status = true;
						}
					}
				}
			}
		}
	}
};

const isDaySelected = computed(() => {
	return (index) => {
		if (weekData.value && weekData.value.length > 0) {
			return weekData.value
				.filter((t) => t.daynum === index + 1)
				.every((item) => item.status === true);
		}
		return false;
	};
});

const isTimeSelected = computed(() => {
	return (index) => {
		if (weekData.value && weekData.value.length > 0) {
			return weekData.value
				.filter((t) => t.timenum === index + 1)
				.every((item) => item.status === true);
		}
		return false;
	};
});

const objectsRef = ref();
const maskRef = ref();
const emits = defineEmits(["update:week"]);
const state = reactive({
	maskPosition: {
		show: false,
		startX: 0,
		startY: 0,
		endX: 0,
		endY: 0
	}, // 矩形框位置
	isPressCtrlKey: false // 是否按下了Ctrl键
});
const { maskPosition, isPressCtrlKey } = toRefs(state);

// 若支持按住Ctrl多选,监听Ctrl事件
if (props.useCtrlSelect) {
	// 释放
	document.addEventListener("keyup", (event) => {
		if (event.keyCode === 17) {
			isPressCtrlKey.value = false;
		}
	});
	// 按下
	document.addEventListener("keydown", (event) => {
		if (event.keyCode === 17) {
			isPressCtrlKey.value = true;
		}
	});
}
//点击星期天数的事件
const clickDay = (index) => {
	// var weekData: Array<any> = [];
	// weekData = weekData === undefined ? [] : weekData;
	// const hours = weekData[index].hours;
	// const allIn = hasHandleObjectIds.value.every(item => weekData.includes(item));
	const arr = weekData.value.filter((t) => t.daynum == index + 1);
	const allIn = arr.every((item) => item.status === true);
	if (allIn) {
		arr.forEach((e) => {
			e.status = false;
			hasHandleObjectIds.value.splice(
				hasHandleObjectIds.value.findIndex((t) => t == e.id),
				1
			);
		});
	} else {
		arr.forEach((e) => {
			e.status = true;
			hasHandleObjectIds.value.push(e.id);
		});
	}
	emits("update:week", handlerdata());
};

// 点击时间点数
const clicktime = (index) => {
	const arr = weekData.value.filter((t) => t.timenum == index + 1);
	const allIn = arr.every((item) => item.status === true);
	if (allIn) {
		arr.forEach((e) => {
			e.status = false;
			hasHandleObjectIds.value.splice(
				hasHandleObjectIds.value.findIndex((t) => t == e.id),
				1
			);
		});
	} else {
		arr.forEach((e) => {
			e.status = true;
			hasHandleObjectIds.value.push(e.id);
		});
	}
	emits("update:week", handlerdata());
};
/** 鼠标按下 */
const handleMouseDown = (event) => {
	//点下时清空已处理数组
	hasHandleObjectIds.value.length = 0;
	var id = Number(event.target.getAttribute(props.objectIdName));
	// var weekData: Array<any> = [];
	// weekData = weekData === undefined ? [] : weekData;
	// const hourItem = weekData.flatMap(day => day.hours).find(item => item.id === id);
	const index = weekData.value.findIndex((t) => t.id == id);
	if (index > -1) {
		weekData.value[index].status = !weekData.value[index].status;
	}
	if (!hasHandleObjectIds.value.includes(id)) {
		hasHandleObjectIds.value.push(id);
	} else {
		hasHandleObjectIds.value.splice(
			hasHandleObjectIds.value.findIndex((t) => t == id),
			1
		);
	}
	// 展示矩形框,通过坐标位置来画出矩形
	maskPosition.value.show = true;
	maskPosition.value.startX = event.clientX;
	maskPosition.value.startY = event.clientY;
	maskPosition.value.endX = event.clientX;
	maskPosition.value.endY = event.clientY;
	// 监听鼠标移动事件和抬起离开事件
	objectsRef.value.addEventListener("mousemove", handleMouseMove);
	objectsRef.value.addEventListener("mouseup", handleMouseUp);
};

/** 鼠标移动 */
const handleMouseMove = (event) => {
	if (clientX.value !== event.clientX || clientY.value !== event.clientY) {
		clientX.value = event.clientX;
		clientY.value = event.clientY;
		maskPosition.value.endX = event.clientX;
		maskPosition.value.endY = event.clientY;
		// var weekData: Array<any> = [];
		// weekData = props.weekData === undefined ? [] : props.weekData;
		const selectedObjects = objectsRef.value.querySelectorAll(`.${props.objectClassName}`);
		// 获取鼠标画出的矩形框位置
		const rectanglePosition = maskRef.value.getClientRects()[0];
		var rectangleSelObjects: Array<number> = []; //矩形框内的id数组
		selectedObjects.forEach((item) => {
			const objectPosition = item.getClientRects()[0];
			// 这里获取的id的方式定义于父组件的objectIdName
			if (compareObjectPosition(objectPosition, rectanglePosition)) {
				let id = item.getAttribute(props.objectIdName);
				rectangleSelObjects.push(Number(id));
			}
		});
		let handle = (id: number) => {
			const index = weekData.value.findIndex((t) => t.id == id);
			if (index > -1) weekData.value[index].status = !weekData.value[index].status;
			// let index = tempSelectObjectIds.findIndex(t => t == id);
		};
		// 处理存在于 hasHandleObjectIds 中但不在 rectangleSelObjects 中的元素
		for (let i = hasHandleObjectIds.value.length - 1; i >= 0; i--) {
			const id = hasHandleObjectIds.value[i];
			if (!rectangleSelObjects.includes(id)) {
				handle(id);
				hasHandleObjectIds.value.splice(i, 1);
			}
		}

		// 处理存在于 rectangleSelObjects 中但不在 hasHandleObjectIds 中的元素
		for (const id of rectangleSelObjects) {
			if (!hasHandleObjectIds.value.includes(id)) {
				handle(id);
				hasHandleObjectIds.value.push(id);
			}
		}
		// emits("update:weekData", weekData);
		// emits("update:selectObjectIds", tempSelectObjectIds);
	}
};

/** 鼠标抬起离开 */
const handleMouseUp = () => {
	// 移除鼠标监听事件
	objectsRef.value.removeEventListener("mousemove", handleMouseMove);
	objectsRef.value.removeEventListener("mouseup", handleMouseUp);
	maskPosition.value.show = false;
	handleResetMaskPosition();
	emits("update:week", handlerdata());
};

const handlerdata = () => {
	let arr = weekData.value;
	tempStr.value.push(Date.now() + "");
	if (props.datatype == 1) {
		let array = [] as any;
		for (let i = 0; i < arr.length; i++) {
			const element = arr[i];
			if (element.status) {
				array.push(1);
			} else {
				array.push(0);
			}
		}
		return array.join("");
	}
	if (props.datatype == 2) {
		let obj = {};
		for (let i = 0; i < arr.length; i++) {
			const element = arr[i];
			if (element.status) {
				if (obj[element.daynum]) {
					obj[element.daynum].push(i);
				} else {
					obj[element.daynum] = [i];
				}
			}
		}
		for (let key in obj) {
			if (Array.isArray(obj[key])) {
				obj[key] = obj[key].join(","); // 使用逗号连接数组中的元素
			}
		}
		// console.log(JSON.stringify(obj));
		return JSON.stringify(obj);
	}
	if (props.datatype == 3) {
		let array = [] as any;
		for (let i = 0; i < arr.length; i++) {
			const element = arr[i];
			if (element.status) {
				let day = String(element.daynum);
				let time = element.timenum < 10 ? "0" + element.timenum : String(element.timenum);
				let finalStr;
				if (i % 2 === 0) {
					finalStr = day + time + "00";
				} else {
					finalStr = day + time + "30";
				}
				array.push(finalStr);
			}
		}
		return array.toString();
	}
	// return arr.filter(item => item.status == true);
};
/**
 * 判断对象坐标是否在鼠标画出的矩形框坐标位置内
 * @param objectPosition 对象坐标位置
 * @param rectanglePosition 鼠标画出的矩形框坐标位置
 */
const compareObjectPosition = (objectPosition, rectanglePosition) => {
	const maxX = Math.max(
		objectPosition.x + objectPosition.width,
		rectanglePosition.x + rectanglePosition.width
	);
	const maxY = Math.max(
		objectPosition.y + objectPosition.height,
		rectanglePosition.y + rectanglePosition.height
	);
	const minX = Math.min(objectPosition.x, rectanglePosition.x);
	const minY = Math.min(objectPosition.y, rectanglePosition.y);
	return (
		maxX - minX <= objectPosition.width + rectanglePosition.width &&
		maxY - minY <= objectPosition.height + rectanglePosition.height
	);
};

/** 重置鼠标位置 */
const handleResetMaskPosition = () => {
	maskPosition.value.startX = 0;
	maskPosition.value.startY = 0;
	maskPosition.value.endX = 0;
	maskPosition.value.endY = 0;
};

/** 通过鼠标位置实时计算矩形框大小 */
const maskWidth = computed(() => {
	return `${Math.abs(maskPosition.value.endX - maskPosition.value.startX)}px;`;
});
const maskHeight = computed(() => {
	return `${Math.abs(maskPosition.value.endY - maskPosition.value.startY)}px;`;
});
const maskLeft = computed(() => {
	return `${Math.min(maskPosition.value.startX, maskPosition.value.endX)}px;`;
});
const maskTop = computed(() => {
	return `${Math.min(maskPosition.value.startY, maskPosition.value.endY)}px;`;
});

const buttons = [{ type: "primary", text: "清空选择" }] as const;
</script>

<style scoped lang="scss">
.dtime {
	line-height: 22px;
	margin-top: 10px;
	padding: 5px;
	color: #6c757d;
	font-size: 12px;
	transform: translateY(-20px);
}

.dt {
	line-height: 22px;
	padding: 4px;
	color: #6c757d;
	font-size: 13px;
	display: inline-block;
}

.dts {
	color: #000000;
	font-size: 12px;
	padding: 15px;
}

.box {
	width: 100%;
	border-left: #909399 1px solid;
	border-bottom: #909399 1px solid;
	border-right: #909399 1px solid;
}

.el-button {
	justify-content: flex-end;
	margin-left: 90%;
	display: inline-block;
	line-height: 22px;
	transform: translateY(-28px);
}

.time {
	width: 100%;
	display: flex;
	align-items: center;
	font-size: 10px;
	color: #222222;
	// border: #999 1px solid;
	.timeleft {
		width: 8.75%;
		height: 45.8px;
		display: flex;
		align-items: center;
		justify-content: center;
		background: #f5f7fa;
		border-bottom: #999 1px solid;
		border-top: #999 1px solid;
		border-left: #999 1px solid;
		box-sizing: border-box;
		font-size: 10px;
	}

	.timeright {
		height: 44.9px;
		background: #f5f7fa;
		width: 100%;
		border-right: #999 1px solid;
		box-sizing: border-box;
		border-top: #999 1px solid;
		font-size: 10px;

		.timeright_cell {
			border-bottom: #999 1px solid;
			box-sizing: border-box;

			.topitem {
				height: 21.5px;
				display: flex;
				align-items: center;
				justify-content: center;
				border-left: #999 1px solid;
				text-align: center;
				box-sizing: border-box;
			}
		}
	}

	.timelefts {
		height: 40px;
		display: flex;
		align-items: center;
		justify-content: center;
		background: #f5f7fa;
		border-bottom: #999 1px solid;
		border-left: #999 1px solid;
		border-right: #999 1px solid;
		box-sizing: border-box;
	}

	.is_selected {
		background: var(--bgColor);
		color: #fff;
	}

	.objects {
		height: 100%;
		width: 100%;
		// overflow-y: auto;

		.mask {
			position: fixed;
			background: #409eff;
			opacity: 0;
			z-index: 100;
		}

		.objects_content {
			user-select: none;
			display: flex;
			flex-wrap: wrap;

			div {
				display: flex;
				align-items: center;
				justify-content: center;
				width: 2.083%;
				height: 40px;
				box-sizing: border-box;
				border-bottom: #999 1px solid;
				border-right: #999 1px solid;
			}
		}
	}
}
</style>

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/773233.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

算法金 | 我最常用的两个数据可视化软件,强烈推荐

大侠幸会&#xff0c;在下全网同名「算法金」 0 基础转 AI 上岸&#xff0c;多个算法赛 Top 「日更万日&#xff0c;让更多人享受智能乐趣」 抱个拳&#xff0c;送个礼 预警&#xff1a;今天文章的描述可能会让你有点别扭&#xff1b;如感到不适&#xff0c;请及时停止 在我行…

macos下搭建minikube dashboard的启动

背景 最近在复习一下k8s环境相关的知识&#xff0c;需要在自己电脑上搭建一个minikube的环境供自己使用。但是因为docker的镜像仓库最近被墙了&#xff0c;因此在执行minikube dashboard的时候&#xff0c;拉不到相应的镜像&#xff0c;就导致页面看不到相应的一些信息因此本文…

如何用手机拍出高级感黑白色调照片?华为Pura70系列XMAGE演绎黑白艺术

在影像的世界里&#xff0c;色彩可以让画面更丰富&#xff0c;更具有表现力&#xff0c;往往也能带来更多的视觉冲击。但有时候&#xff0c;黑白却有着一种独特的魅力。华为Pura 70系列XMAGE黑白风格&#xff0c;则给我们了一把通过纯粹艺术大门的钥匙。 XMAGE黑白并非简单的色…

2024 年第十四届 APMCM 亚太地区大学生数学建模A题 飞行器外形的优化问题--完整思路代码分享(仅供学习)

飞行器是在大气层内或大气层外空间飞行的器。飞行器可以分为:航空器航天器、火箭和导弹。在大气层内飞行的称为航空器&#xff0c;如气球、飞艇、飞机等。它们靠空气的静浮力或空气相对运动产生的空气动力升空飞行。在太空飞行的称为航天器&#xff0c;如人造地球卫星、载人飞船…

05-《猪笼草》

猪笼草 猪笼草是猪笼草属全体物种的总称。属于热带食虫植物&#xff0c;原产地主要为旧大陆热带地区。其拥有一个独特的吸取营养的器官——捕虫笼&#xff0c;捕虫笼呈圆筒形&#xff0c;下半部稍膨大&#xff0c;笼口上具有盖子&#xff0c;因其形状像猪笼而得名。 猪笼草 形…

开源协作wiki和文档软件Docmost

什么是 Docmost &#xff1f; Docmost 是一款开源协作 wiki 和文档软件。它是 Confluence 和 Notion 等软件的开源替代品。使用 Docmost 可以无缝创建、协作和共享知识。非常适合管理您的 wiki、知识库、文档等。目前 Docmost 处于测试阶段。 软件的主要特点 安装 在群晖上以 …

从OpenAI停服看中国市场:国产替代崛起的机遇与挑战

一、OpenAI 停服事件背景 OpenAI 自 2020 年推出 GPT-3 以来&#xff0c;在全球范围内引起了极大的反响。其强大的自然语言处理能力使其成为许多企业和开发者的首选工具。然而&#xff0c;2024 年 6 月 25 日&#xff0c;许多中国用户收到了一封来自 OpenAI 的邮件&#xff0c…

《地平线开发板小技巧》-- 备份与恢复SD卡镜像

在我们的机器人系统开发过程中&#xff0c;需要提前安装配置操作系统和依赖项&#xff0c;将这些依赖全部安装完成后&#xff0c;将系统镜像备份。在之后的系统安装中只要将备份好的镜像烧录进开发板中&#xff0c;岂不快哉~ 下面讲的便是地地平线开发板中镜像备份与恢复过程 …

人脸识别考勤系统

人脸识别考勤系统是一种利用生物识别技术进行自动身份验证的现代解决方案&#xff0c;它通过分析和比对人脸特征来进行员工的出勤记录。这种系统不仅提升了工作效率&#xff0c;还大大减少了人为错误和欺诈行为的可能性。 一、工作原理 人脸识别考勤系统的核心在于其生物识别…

Vue3进度条nprogress(手机端、PC端通用)

Vue3进度条nprogress是一个用于显示页面加载进度的库。要在Vue3项目中使用nprogress&#xff0c;需要先安装它&#xff0c;然后在你的项目中引入和使用。 安装nprogress npm install nprogress --save配置nprogress 在目录src下创建nprogress文件夹&#xff0c;里面创建nprogr…

Python面试宝典第6题:有效的括号

题目 给定一个只包括 (、)、{、}、[、] 这些字符的字符串&#xff0c;判断该字符串是否有效。有效字符串需要满足以下的条件。 1、左括号必须用相同类型的右括号闭合。 2、左括号必须以正确的顺序闭合。 3、每个右括号都有一个对应的相同类型的左括号。 注意&#xff1a;空字符…

九浅一深Jemalloc5.3.0 -- ⑨浅*gc

目前市面上有不少分析Jemalloc老版本的博文&#xff0c;但5.3.0却少之又少。而且5.3.0的架构与之前的版本也有较大不同&#xff0c;本着“与时俱进”、“由浅入深”的宗旨&#xff0c;我将逐步分析Jemalloc5.3.0的实现。 另外&#xff0c;单讲实现代码是极其枯燥的&#xff0c;…

拆解COLA框架

COLA 是 Clean Object-Oriented and Layered Architecture的缩写&#xff0c;代表“整洁面向对象分层架构”。由阿里大佬张建飞所提出的一种基于DDD和代码整洁理论所诞生的实践理论框架&#xff0c;详细内容可阅读《程序员的底层思维》和相关git代码去了解 项目地址&#xff1a…

在地图上根据经纬度,画一个矩型围栏,设置每个点的经纬度

在做一个需求时有一个小点就是添加一个配送区域(5公里直径内的)矩形围栏 我做的比较简单 大家看看有没有帮助, 也是精简代码。测试效果上相对是精准的 //谷歌&#xff0c;根据经纬度获取以它为中心半径为5公里内的矩形的四个点经纬度getDefalutPoints (lng: number, lat: num…

lt6911UXC 国产原装 高性能HDMI2.0转MIPI DSI / CSI芯片方案 提供LT 开发资料包及在线软硬件技术支持!

1.说明 LT6911UXC是一款高性能HDMI2.0到MIPI DSI / CSI转换器&#xff0c;用于VR&#xff0c;智能电话&#xff0c;显示应用。 HDMI2.0输入支持高达6Gbps的数据速率&#xff0c;从而为4k 60Hz视频提供足够的带宽。还支持HDCP2.2进行数据解密。 对于MIPI DSI / CSI输出&#xf…

企业数据API平台:获取企业多维度信息

数据API平台是指提供一系列预先定义的接口、协议与工具&#xff0c;允许不同应用程序或系统之间进行数据交换和通信的平台。这些接口被称为数据API&#xff08;Data Application Programming Interface&#xff09;&#xff0c;是数据管理系统或应用程序提供的一组开放式接口。…

Linux手动安装JDK1.8

1、下载要安装的jdk安装包文件 官网下载地址&#xff1a;https://www.oracle.com/cn/java/technologies/downloads/ 2、上传jdk安装包至要安装服务器 3、在要安装jdk位置使用命令解压安装包 安装路径: /usr/local/java 解压安装包&#xff0c;解压命令 tar -zxvf /install…

【博客21】缤果Qt5仿小米耳机APP布局_PC端软件(高级篇)

小米耳机 备注&#xff1a;此软件只是简单的实现布局和界面跳转逻辑, 并未加入小米协议相关内容,因需要鉴权方式验证,故无法进行通讯编程. 开发工具: qt-opensource-windows-x86-5.14.2 (编程语言C) Android反编译工具: apktool 小米小爱开放平台 - 语音服务平台 - 文档中…

3-1 激活函数和神经网络思想

3-1 激活函数和神经网络思想 主目录点这里

android应用的持续构建CI(四)-- 依赖环境(兼容多版本的gradle和jdk)

一、背景 android应用的构建前提是&#xff0c;安装好了gradle和jdk。在实际使用的过程中&#xff0c;不同的android应用&#xff0c;对gradle和jdk的版本要求不一。 于是&#xff0c;在jenkins服务器上&#xff0c;我们需要安装多种版本的gradle和jdk。 安装过jdk的小伙伴应…