大学生活动社交小程序开发笔记(1)

news2024/10/7 18:22:42

可研分析

大学生活动社交小程序是一种基于移动互联网的社交平台,旨在为大学生提供一个方便、快捷、安全的社交和活动交流平台

功能规划

  • 活动发布:平台可以发布将要举行的活动,包括时间、地点、费用等信息,并邀请其他用户参加。
  • 活动搜索:用户可以根据自己的兴趣爱好搜索活动,并参加感兴趣的活动。
  • 活动评价:用户可以对参加过的活动进行评价和反馈,帮助其他用户更好地选择活动。
  • 打卡模块:可以帮助大学生记录和评比每天的学习、阅读、文艺、体育、体育等活动。通过完成一个个小目标帮助大学生更好地管理自己的时间和目标。

实现目标

大学生活动社交小程序可以帮助大学生更好地组织和参加活动,扩展社交圈子,丰富大学生活。 本项目前后端完整代码包括公告通知,校园风采,活动分类与列表,活动报名与评价,打卡项目列表,打卡排行与每日动态,我的活动报名,我的每日打卡;后台打卡项目管理,打卡记录管理与导出,后台活动与报名管理,报名审核与数据导出等功能,活动组织方可以自定义要填写的内容
在这里插入图片描述

数据库设计


ActivityModel.DB_STRUCTURE = {
	_pid: 'string|true',
	ACTIVITY_ID: 'string|true',

	ACTIVITY_TITLE: 'string|true|comment=标题',
	ACTIVITY_STATUS: 'int|true|default=1|comment=状态 0=未启用,1=使用中',

	ACTIVITY_CATE_ID: 'string|true|default=0|comment=分类',
	ACTIVITY_CATE_NAME: 'string|false|comment=分类冗余',

	ACTIVITY_CANCEL_SET: 'int|true|default=1|comment=取消设置 0=不允,1=允许,2=仅截止前可取消',
	ACTIVITY_CHECK_SET: 'int|true|default=0|comment=审核 0=不需要审核,1=需要审核', 
	ACTIVITY_IS_MENU: 'int|true|default=1|comment=是否公开展示名单',

	ACTIVITY_MAX_CNT: 'int|true|default=20|comment=人数上限 0=不限',
	ACTIVITY_START: 'int|false|comment=活动开始时间',
	ACTIVITY_END: 'int|false|comment=活动截止时间',
	ACTIVITY_STOP: 'int|true|default=0|comment=报名截止时间 0=永不过期',

	ACTIVITY_ORDER: 'int|true|default=9999',
	ACTIVITY_VOUCH: 'int|true|default=0',

	ACTIVITY_FORMS: 'array|true|default=[]',
	ACTIVITY_OBJ: 'object|true|default={}',

	ACTIVITY_JOIN_FORMS: 'array|true|default=[]',

	ACTIVITY_ADDRESS: 'string|false|comment=详细地址',
	ACTIVITY_ADDRESS_GEO: 'object|false|comment=详细地址坐标参数',

	ACTIVITY_QR: 'string|false',
	ACTIVITY_VIEW_CNT: 'int|true|default=0',
	ACTIVITY_JOIN_CNT: 'int|true|default=0',
	ACTIVITY_COMMENT_CNT: 'int|true|default=0',

	ACTIVITY_USER_LIST: 'array|true|default=[]|comment={name,id,pic}',

	ACTIVITY_ADD_TIME: 'int|true',
	ACTIVITY_EDIT_TIME: 'int|true',
	ACTIVITY_ADD_IP: 'string|false',
	ACTIVITY_EDIT_IP: 'string|false',
};

ActivityJoinModel.DB_STRUCTURE = {
	_pid: 'string|true',
	ACTIVITY_JOIN_ID: 'string|true',
	ACTIVITY_JOIN_ACTIVITY_ID: 'string|true|comment=报名PK',

	ACTIVITY_JOIN_IS_ADMIN: 'int|true|default=0|comment=是否管理员添加 0/1',

	ACTIVITY_JOIN_CODE: 'string|true|comment=核验码15位',
	ACTIVITY_JOIN_IS_CHECKIN: 'int|true|default=0|comment=是否签到 0/1 ',
	ACTIVITY_JOIN_CHECKIN_TIME: 'int|false|default=0|签到时间',

	ACTIVITY_JOIN_USER_ID: 'string|true|comment=用户ID',


	ACTIVITY_JOIN_FORMS: 'array|true|default=[]|comment=表单',
	ACTIVITY_JOIN_OBJ: 'object|true|default={}',

	ACTIVITY_JOIN_STATUS: 'int|true|default=1|comment=状态  0=待审核 1=报名成功, 99=审核未过',
	ACTIVITY_JOIN_REASON: 'string|false|comment=审核拒绝或者取消理由',

	ACTIVITY_JOIN_ADD_TIME: 'int|true',
	ACTIVITY_JOIN_EDIT_TIME: 'int|true',
	ACTIVITY_JOIN_ADD_IP: 'string|false',
	ACTIVITY_JOIN_EDIT_IP: 'string|false',
};

核心实现


class ActivityService extends BaseProjectService {

	// 获取当前活动状态
	getJoinStatusDesc(activity) {
		let timestamp = this._timestamp;

		if (activity.ACTIVITY_STATUS == 0)
			return '活动停止';
		else if (activity.ACTIVITY_END <= timestamp)
			return '活动结束';
		else if (activity.ACTIVITY_STOP <= timestamp)
			return '报名结束';
		else if (activity.ACTIVITY_MAX_CNT > 0
			&& activity.ACTIVITY_JOIN_CNT >= activity.ACTIVITY_MAX_CNT)
			return '报名已满';
		else
			return '报名中';
	}

	/** 浏览信息 */
	async viewActivity(userId, id) {

		let fields = '*';

		let where = {
			_id: id,
			ACTIVITY_STATUS: ActivityModel.STATUS.COMM
		}
		let activity = await ActivityModel.getOne(where, fields);
		if (!activity) return null;

		ActivityModel.inc(id, 'ACTIVITY_VIEW_CNT', 1);

		// 判断是否有报名
		let whereJoin = {
			ACTIVITY_JOIN_USER_ID: userId,
			ACTIVITY_JOIN_ACTIVITY_ID: id,
			ACTIVITY_JOIN_STATUS: ['in', [ActivityJoinModel.STATUS.WAIT, ActivityJoinModel.STATUS.SUCC]]
		}
		let activityJoin = await ActivityJoinModel.getOne(whereJoin);
		if (activityJoin) {
			activity.myActivityJoinId = activityJoin._id;
			activity.myActivityJoinTag = (activityJoin.ACTIVITY_JOIN_STATUS == ActivityJoinModel.STATUS.WAIT) ? '待审核' : '已报名';
		}

		else {
			activity.myActivityJoinId = '';
			activity.myActivityJoinTag = '';
		}


		return activity;
	}

	/** 取得分页列表 */
	async getActivityList({
		cateId, //分类查询条件
		search, // 搜索条件
		sortType, // 搜索菜单
		sortVal, // 搜索菜单
		orderBy, // 排序 
		page,
		size,
		isTotal = true,
		oldTotal
	}) {

		orderBy = orderBy || {
			'ACTIVITY_ORDER': 'asc',
			'ACTIVITY_ADD_TIME': 'desc'
		};
		let fields = 'ACTIVITY_USER_LIST,ACTIVITY_STOP,ACTIVITY_JOIN_CNT,ACTIVITY_OBJ,ACTIVITY_VIEW_CNT,ACTIVITY_TITLE,ACTIVITY_MAX_CNT,ACTIVITY_START,ACTIVITY_END,ACTIVITY_ORDER,ACTIVITY_STATUS,ACTIVITY_CATE_NAME,ACTIVITY_OBJ';

		let where = {};
		where.and = {
			_pid: this.getProjectId() //复杂的查询在此处标注PID
		};
		if (cateId && cateId !== '0') where.and.ACTIVITY_CATE_ID = cateId;

		where.and.ACTIVITY_STATUS = ActivityModel.STATUS.COMM; // 状态  


		if (util.isDefined(search) && search) {
			where.or = [{
				ACTIVITY_TITLE: ['like', search]
			},];
		} else if (sortType && util.isDefined(sortVal)) {
			// 搜索菜单
			switch (sortType) {
				case 'cateId': {
					if (sortVal) where.and.ACTIVITY_CATE_ID = String(sortVal);
					break;
				}
				case 'sort': {
					// 排序
					orderBy = this.fmtOrderBySort(sortVal, 'ACTIVITY_ADD_TIME');
					break;
				}
				case 'today': { //今天
					let start = timeUtil.getDayFirstTimestamp();
					let end = start + 86400 * 1000 - 1;
					where.and.ACTIVITY_START = ['between', start, end];
					break;
				}
				case 'tomorrow': { //明日
					let start = timeUtil.getDayFirstTimestamp() + 86400 * 1000;
					let end = start + 86400 * 1000 - 1;
					where.and.ACTIVITY_START = ['between', start, end];
					break;
				}
				case 'month': { //本月
					let day = timeUtil.time('Y-M-D');
					let start = timeUtil.getMonthFirstTimestamp(day);
					let end = timeUtil.getMonthLastTimestamp(day);

					where.and.ACTIVITY_START = ['between', start, end];
					break;
				}
			}
		}

		return await ActivityModel.getList(where, fields, orderBy, page, size, isTotal, oldTotal);
	}


	/** 取得某一个报名分页列表 */
	async getActivityJoinList(activityId, {
		search, // 搜索条件
		sortType, // 搜索菜单
		sortVal, // 搜索菜单
		orderBy, // 排序 
		page,
		size,
		isTotal = true,
		oldTotal
	}) {
		orderBy = orderBy || {
			'ACTIVITY_JOIN_ADD_TIME': 'desc'
		};
		let fields = 'ACTIVITY_JOIN_OBJ,ACTIVITY_JOIN_IS_CHECKIN,ACTIVITY_JOIN_REASON,ACTIVITY_JOIN_ACTIVITY_ID,ACTIVITY_JOIN_STATUS,ACTIVITY_JOIN_ADD_TIME,user.USER_PIC,user.USER_NAME,user.USER_OBJ';

		let where = {
			ACTIVITY_JOIN_ACTIVITY_ID: activityId,
			ACTIVITY_JOIN_STATUS: ActivityModel.STATUS.COMM
		};

		let joinParams = {
			from: UserModel.CL,
			localField: 'ACTIVITY_JOIN_USER_ID',
			foreignField: 'USER_MINI_OPENID',
			as: 'user',
		};

		let result = await ActivityJoinModel.getListJoin(joinParams, where, fields, orderBy, page, size, isTotal, oldTotal);

		return result;
	}


	/** 取得我的报名分页列表 */
	async getMyActivityJoinList(userId, {
		search, // 搜索条件
		sortType, // 搜索菜单
		sortVal, // 搜索菜单
		orderBy, // 排序 
		page,
		size,
		isTotal = true,
		oldTotal
	}) {
		orderBy = orderBy || {
			'ACTIVITY_JOIN_ADD_TIME': 'desc'
		};
		let fields = 'ACTIVITY_JOIN_IS_CHECKIN,ACTIVITY_JOIN_REASON,ACTIVITY_JOIN_ACTIVITY_ID,ACTIVITY_JOIN_STATUS,ACTIVITY_JOIN_ADD_TIME,activity.ACTIVITY_END,activity.ACTIVITY_START,activity.ACTIVITY_TITLE';

		let where = {
			ACTIVITY_JOIN_USER_ID: userId
		};

		if (util.isDefined(search) && search) {
			where['activity.ACTIVITY_TITLE'] = {
				$regex: '.*' + search,
				$options: 'i'
			};
		} else if (sortType) {
			// 搜索菜单
			switch (sortType) {
				case 'timedesc': { //按时间倒序
					orderBy = {
						'activity.ACTIVITY_START': 'desc',
						'ACTIVITY_JOIN_ADD_TIME': 'desc'
					};
					break;
				}
				case 'timeasc': { //按时间正序
					orderBy = {
						'activity.ACTIVITY_START': 'asc',
						'ACTIVITY_JOIN_ADD_TIME': 'asc'
					};
					break;
				}
				case 'succ': {
					where.ACTIVITY_JOIN_STATUS = ActivityJoinModel.STATUS.SUCC;
					break;
				}
				case 'wait': {
					where.ACTIVITY_JOIN_STATUS = ActivityJoinModel.STATUS.WAIT;
					break;
				}
				case 'cancel': {
					where.ACTIVITY_JOIN_STATUS = ActivityJoinModel.STATUS.ADMIN_CANCEL;
					break;
				}
			}
		}

		let joinParams = {
			from: ActivityModel.CL,
			localField: 'ACTIVITY_JOIN_ACTIVITY_ID',
			foreignField: '_id',
			as: 'activity',
		};

		let result = await ActivityJoinModel.getListJoin(joinParams, where, fields, orderBy, page, size, isTotal, oldTotal);

		return result;
	}

	/** 取得我的报名详情 */
	async getMyActivityJoinDetail(userId, activityJoinId) {

		let fields = '*';

		let where = {
			_id: activityJoinId,
			ACTIVITY_JOIN_USER_ID: userId
		};
		let activityJoin = await ActivityJoinModel.getOne(where, fields);
		if (activityJoin) {
			activityJoin.activity = await ActivityModel.getOne(activityJoin.ACTIVITY_JOIN_ACTIVITY_ID, 'ACTIVITY_TITLE,ACTIVITY_START,ACTIVITY_END');
		}
		return activityJoin;
	}

	//################## 报名 
	// 报名 
	async activityJoin(userId, activityId, forms) {

		// 报名是否结束
		let whereActivity = {
			_id: activityId,
			ACTIVITY_STATUS: ActivityModel.STATUS.COMM
		}
		let activity = await ActivityModel.getOne(whereActivity);
		if (!activity)
			this.AppError('该活动不存在或者已经停止');

		// 是否活动结束
		if (activity.ACTIVITY_END < this._timestamp)
			this.AppError('该活动已经结束,请选择其他活动');

		// 是否过了报名截止期
		if (activity.ACTIVITY_STOP < this._timestamp)
			this.AppError('该活动报名已经截止,请选择其他活动');


		// 人数是否满
		if (activity.ACTIVITY_MAX_CNT > 0) {
			let whereCnt = {
				ACTIVITY_JOIN_ACTIVITY_ID: activityId,
				ACTIVITY_JOIN_STATUS: ['in', [ActivityJoinModel.STATUS.WAIT, ActivityJoinModel.STATUS.SUCC]]
			}
			let cntJoin = await ActivityJoinModel.count(whereCnt);
			if (cntJoin >= activity.ACTIVITY_MAX_CNT)
				this.AppError('该活动报名已满,请选择其他活动');
		}

		// 自己是否已经有报名
		let whereMy = {
			ACTIVITY_JOIN_USER_ID: userId,
			ACTIVITY_JOIN_ACTIVITY_ID: activityId,
			ACTIVITY_JOIN_STATUS: ['in', [ActivityJoinModel.STATUS.WAIT, ActivityJoinModel.STATUS.SUCC]]
		}
		let my = await ActivityJoinModel.getOne(whereMy);
		if (my) {
			if (my.ACTIVITY_JOIN_STATUS == ActivityJoinModel.STATUS.WAIT)
				this.AppError('您已经报名,正在等待审核,无须重复报名');
			else
				this.AppError('您已经报名成功,无须重复报名');
		}


		// 入库
		let data = {
			ACTIVITY_JOIN_USER_ID: userId,
			ACTIVITY_JOIN_ACTIVITY_ID: activityId,
			ACTIVITY_JOIN_STATUS: (activity.ACTIVITY_CHECK_SET == 0) ? ActivityJoinModel.STATUS.SUCC : ActivityJoinModel.STATUS.WAIT,
			ACTIVITY_JOIN_FORMS: forms,
			ACTIVITY_JOIN_OBJ: dataUtil.dbForms2Obj(forms),
			ACTIVITY_JOIN_CODE: dataUtil.genRandomIntString(15),

		}

		let activityJoinId = await ActivityJoinModel.insert(data); 

		// 统计数量
		await this.statActivityJoin(activityId);

		let check = activity.ACTIVITY_CHECK_SET;

		return { activityJoinId, check }

	} 
 

	async statActivityJoin(id) {
        // 报名数
		let where = {
			ACTIVITY_JOIN_ACTIVITY_ID: id,
			ACTIVITY_JOIN_STATUS: ['in', [ActivityJoinModel.STATUS.WAIT, ActivityJoinModel.STATUS.SUCC]]
		}
		let cnt = await ActivityJoinModel.count(where);


        // 用户列表
		where = {
			ACTIVITY_JOIN_ACTIVITY_ID: id,
			ACTIVITY_JOIN_STATUS: ActivityJoinModel.STATUS.SUCC
		}
		let joinParams = {
			from: UserModel.CL,
			localField: 'ACTIVITY_JOIN_USER_ID',
			foreignField: 'USER_MINI_OPENID',
			as: 'user',
		};
		let orderBy = {
			ACTIVITY_JOIN_ADD_TIME: 'desc'
		}
		let list = await ActivityJoinModel.getListJoin(joinParams, where, 'ACTIVITY_JOIN_ADD_TIME,user.USER_MINI_OPENID,user.USER_NAME,user.USER_PIC', orderBy, 1, 6, false, 0);
		list = list.list;

		for (let k = 0; k < list.length; k++) {
			list[k] = list[k].user;
		} 

		await ActivityModel.edit(id, { ACTIVITY_JOIN_CNT: cnt, ACTIVITY_USER_LIST: list });
	}

	/**  报名前获取关键信息 */
	async detailForActivityJoin(userId, activityId) {
		let fields = 'ACTIVITY_JOIN_FORMS, ACTIVITY_TITLE';

		let where = {
			_id: activityId,
			ACTIVITY_STATUS: ActivityModel.STATUS.COMM
		}
		let activity = await ActivityModel.getOne(where, fields);
		if (!activity)
			this.AppError('该活动不存在');


		// 取出本人最近一次的填写表单

		let whereMy = {
			ACTIVITY_JOIN_USER_ID: userId,
		}
		let orderByMy = {
			ACTIVITY_JOIN_ADD_TIME: 'desc'
		}
		let joinMy = await ActivityJoinModel.getOne(whereMy, 'ACTIVITY_JOIN_FORMS', orderByMy);


		let myForms = joinMy ? joinMy.ACTIVITY_JOIN_FORMS : [];
		activity.myForms = myForms;

		return activity;
	}

	/** 取消我的报名 只有成功和待审核可以取消 取消即为删除记录 */
	async cancelMyActivityJoin(userId, activityJoinId) {
		let where = {
			ACTIVITY_JOIN_USER_ID: userId,
			_id: activityJoinId,
			ACTIVITY_JOIN_STATUS: ['in', [ActivityJoinModel.STATUS.WAIT, ActivityJoinModel.STATUS.SUCC]]
		};
		let activityJoin = await ActivityJoinModel.getOne(where);

		if (!activityJoin) {
			this.AppError('未找到可取消的报名记录');
		}

		if (activityJoin.ACTIVITY_JOIN_IS_CHECKIN == 1)
			this.AppError('该活动已经签到,无法取消');

		let activity = await ActivityModel.getOne(activityJoin.ACTIVITY_JOIN_ACTIVITY_ID);
		if (!activity)
			this.AppError('该活动不存在');

		if (activity.ACTIVITY_END <= this._timestamp)
			this.AppError('该活动已经结束,无法取消');

		if (activity.ACTIVITY_CANCEL_SET == 0)
			this.AppError('该活动不能取消');

		if (activity.ACTIVITY_CANCEL_SET == 2 && activity.ACTIVITY_STOP < this._timestamp)
			this.AppError('该活动已经截止报名,不能取消');

		await ActivityJoinModel.del(where); 

		// 统计
		await this.statActivityJoin(activityJoin.ACTIVITY_JOIN_ACTIVITY_ID);
	}


	/** 用户自助签到 */
	async myJoinSelf(userId, activityId) {
		let activity = await ActivityModel.getOne(activityId);
		if (!activity)
			this.AppError('活动不存在或者已经关闭');

		let day = timeUtil.timestamp2Time(activity.ACTIVITY_START, 'Y-M-D');

		let today = timeUtil.time('Y-M-D');
		if (day != today)
			this.AppError('仅在活动当天可以签到,当前签到码的日期是' + day);

		let whereSucc = {
			ACTIVITY_JOIN_USER_ID: userId,
			ACTIVITY_JOIN_STATUS: ActivityJoinModel.STATUS.SUCC
		}
		let cntSucc = await ActivityJoinModel.count(whereSucc);

		let whereCheckin = {
			ACTIVITY_JOIN_USER_ID: userId,
			ACTIVITY_JOIN_IS_CHECKIN: 1,
			ACTIVITY_JOIN_STATUS: ActivityJoinModel.STATUS.SUCC
		}
		let cntCheckin = await ActivityJoinModel.count(whereCheckin);

		let ret = '';
		if (cntSucc == 0) {
			ret = '您没有本次活动报名成功的记录,请在「个人中心 - 我的活动报名」查看详情~';
		} else if (cntSucc == cntCheckin) {
			// 同一活动多次报名的情况
			ret = '您已签到,无须重复签到,请在「个人中心 - 我的活动报名」查看详情~';
		} else {
			let where = {
				ACTIVITY_JOIN_USER_ID: userId,
				ACTIVITY_JOIN_IS_CHECKIN: 0,
				ACTIVITY_JOIN_STATUS: ActivityJoinModel.STATUS.SUCC
			}
			let data = {
				ACTIVITY_JOIN_IS_CHECKIN: 1,
				ACTIVITY_JOIN_CHECKIN_TIME: this._timestamp,
			}
			await ActivityJoinModel.edit(where, data);
			ret = '签到成功,请在「个人中心 - 我的活动报名」查看详情~'
		}
		return {
			ret
		};
	}

	/** 按天获取报名项目 */
	async getActivityListByDay(day) {
		let start = timeUtil.time2Timestamp(day);
		let end = start + 86400 * 1000 - 1;
		let where = {
			ACTIVITY_STATUS: ActivityModel.STATUS.COMM,
			ACTIVITY_START: ['between', start, end],
		};

		let orderBy = {
			'ACTIVITY_ORDER': 'asc',
			'ACTIVITY_ADD_TIME': 'desc'
		};

		let fields = 'ACTIVITY_TITLE,ACTIVITY_START,ACTIVITY_OBJ.cover';

		let list = await ActivityModel.getAll(where, fields, orderBy);

		let retList = [];

		for (let k = 0; k < list.length; k++) {

			let node = {};
			node.timeDesc = timeUtil.timestamp2Time(list[k].ACTIVITY_START, 'h:m');
			node.title = list[k].ACTIVITY_TITLE;
			node.pic = list[k].ACTIVITY_OBJ.cover[0];
			node._id = list[k]._id;
			retList.push(node);

		}
		return retList;
	}

	/**
	 * 获取从某天开始可报名的日期
	 * @param {*} fromDay  日期 Y-M-D
	 */
	async getActivityHasDaysFromDay(fromDay) {
		let where = {
			ACTIVITY_START: ['>=', timeUtil.time2Timestamp(fromDay)],
		};

		let fields = 'ACTIVITY_START';
		let list = await ActivityModel.getAllBig(where, fields);

		let retList = [];
		for (let k = 0; k < list.length; k++) {
			let day = timeUtil.timestamp2Time(list[k].ACTIVITY_START, 'Y-M-D');
			if (!retList.includes(day)) retList.push(day);
		}
		return retList;
	}


}

UI设计

在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

后台UI

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

git地址

git代码地址

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《UNUX环境高级编程》(8)进程控制

1、引言 2、进程标识 每个进程都用一个唯一的非负整数标识&#xff0c;即为进程id&#xff1a;pid。进程ID是可以复用的&#xff0c;当一个进程终止时&#xff0c;其进程ID就可以用来标识其他进程。系统中有一些专用进程&#xff1a; 进程ID为0的是调度进程&#xff0c;也称交…

【软件测试】Git 远程仓库的使用(详细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 查看远程仓库 想…

Docker笔记 容器的数据卷

1. 数据卷概念 思考&#xff1a; Docker容器删除后&#xff0c;在容器中产生的数据还在吗&#xff1f; 答案是不在了&#xff0c;数据存放在容器中&#xff0c;如果将容器删除&#xff0c;数据也会被一并删除 Docker容器和外部机器可以直接交换文件吗&#xff1f; 答案是不…

为什么需要Promises ?

同步"异步操作", 避免Block多层嵌套造成的"回调地狱" The problem with async code (without Promises) Typically, async operations take a completion handler in a form of a block, which is called to provide either a result or an error. To per…

银河麒麟服务器v10 sp1 部署 redis 及redis gui 客户端工具

上一篇&#xff1a;银河麒麟服务器v10 sp1 redis开机自动启动_csdn_aspnet的博客-CSDN博客 本文介绍另一种redis安装方式及客户端工具安装。 Redis 是一种内存数据模型存储&#xff0c;可用作数据库、缓冲区和消息传递中继。它是开源的&#xff08;BSD 许可&#xff09;。字符…

热爱python的第一天:初识python,搭建python环境,运行第一个python小程序

目录 1 初始python python 概述 python的应用领域 应用python的公司 2 搭建python 开发环境 2.1 安装python&#xff08;以windows 系统为例&#xff09;&#xff08;1&#xff09;下载安装包 &#xff08;2&#xff09; 下载保存后打开文件夹点击以管理员身份运行 &…

IntegrityError: FOREIGN KEY constraint failed解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

nginx漏洞修复之检测到目标URL存在http host头攻击漏洞

漏洞说明 为了方便的获得网站域名&#xff0c;开发人员一般依赖于HTTP Host header。例如&#xff0c;在php里用_SERVER[“HTTP_HOST”]。但是这个header是不可信赖的&#xff0c;如果应用程序没有对host header值进行处理&#xff0c;就有可能造成恶意代码的传入。 解决方法…

安全狗亮相2023第二届上海网络安全博览会

7月5日至7日&#xff0c;“新耀东方-2023第二届上海网络安全博览会暨高峰论坛”在上海顺利举办。此次大会由上海市信息网络安全管理协会、国家计算机网络应急技术处理协调中心上海分中心、(ISC)2上海分会、上海市普陀区科学技术委员会、上海市网络安全产业示范园共同主办。 作…

Keil5开发STM32F4

Gitee keil工程 软件下载和安装&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1PWDAU0EhVZ6J8h6xH_uw5g 提取码&#xff1a;b343 MDK526.exe Keil.STM32F4xx_DFP.2.17.1.pack keygen_2032.exe JLink_Windows_V640.exe en.stsw-stm32065_v1-7-1_STM32F4 &…

【数据仓库】Windows源码安装DataEase,DataEase二次开发

上文记录了DataEase入门使用指南&#xff0c;本文主要记录Windows下源码安装及二次开发步骤【数据仓库】BI看板DataEase入坑指南_wenchun001的博客-CSDN博客 改动文件 源码 GitHub release 链接: Releases dataease/dataease GitHub SDK 软件环境 后端&#xff1a; JDK …

MongoDB快速入门

虽说现在关系型数据库还是主流&#xff0c;但是面对某些需求的时候&#xff0c;需要非关系型数据库来补充它&#xff0c;学习一个主流的NoSQL数据库还是很有必要的。MongoDB是一个功能丰富的NoSQL数据库&#xff0c;本文整理了它最常用的部分形成了这篇入门教程&#xff0c;希望…

设计模式——命令模式

命令模式 定义 将一个请求封装成一个对象&#xff0c;从而让你使用不同的请求吧客户端参数化&#xff0c;对请求排队或者记录请求日志&#xff0c;可以提供命令的撤销和恢复功能。 命令模式是一个高内聚的模式。 优缺点、应用场景 优点 类间解耦。调用者与接收者之间没有任…

探索AI领域,AI图像安全技术助力行业健康发展

目录 一、AI时代降临二、AIOCR与传统OCR技术三、通过人工智能模型生成AI图片技术探索四、提前布局&#xff0c;合合信息AI图像安全技术助力行业健康发展1、识别医疗门诊发票和报告2、图像篡改检测升级&#xff0c;截图篡改检测3、AIGC判别&#xff0c;人脸伪造检测4、OCR对抗攻…

WebSocket使用记录

使用视频地址 1、添加前端使用文件 2、后端配置 2.1添加依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>2.2添加websocket配置类 import org.spri…

NETSDK1141 无法解析位于 global.json 中指定的 .NET SDK 版本

1. 使用cmd命令 dotnet --info 查看自己使用的SDK版本 3.直接找到项目中的 global.json 文件&#xff0c;右键打开&#xff0c;直接修改版本为本机的SDK版本&#xff0c;就可以用了 微软文档也有详细说明: ​​​​​​NETSDK1141&#xff1a;无法解析 global.json 中指定的…

浅析CAS

CAS基本使用 以ReentrantLock为例&#xff0c;观察CAS基本使用。 class ReentrantLockExample {int a 0;// 非公平锁ReentrantLock lock new ReentrantLock(false);public void writer() {// 获取锁lock.lock();try {a;} finally {// 释放锁lock.unlock();}}public void re…

生产环境 kafka 平滑迁移之旅

文章目录 背景分析测试环境验证现实很残酷两种抉择-----leader分区切换方案选择实施步骤手工副本集增加步骤手工leader分区切换步骤 总结 背景 线上kafka集群&#xff0c;3台机器&#xff0c;3个broker&#xff1b;其中某台机器因为硬件故障&#xff0c;需要停机维修&#xff…

MSP432学习笔记12:MSP432时钟源与定时器A时钟源配置

今日深入学习一下MSP432的时钟源与配置&#xff0c; 可以结合之前的滴答计时器相关文章&#xff1a; MSP432学习笔记4&#xff1a;时钟与滴答计时器_NULL指向我的博客-CSDN博客 目录 MSP432有关时钟源系统的性能&#xff1a; 七种时钟源&#xff1a; 五种时钟&#xff1a; …

创新实践,复合机器人采摘运输教育沙盘案例研究

引言 在之前我们已经介绍了水果采摘和分拣机器人的应用场景&#xff0c;今天我们来介绍复合机器人水果采摘运输的场景。 作为最热门的技术领域&#xff0c;机器人技术正在彻底改变各行各业&#xff0c;推动全球创新。为了满足这一快速发展领域对专业技术人才日益增长的需求&a…