從0到1:培訓老師預約小程序開發筆記二

背景調研

培訓老師預約小程序: 教師和學生可以更便捷地安排課程,并提升教學質量和學習效果,使之成為管理和提升教學效果的強大工具。培訓老師可以在小程序上設置自己的可預約時間,學員可以根據老師的日程安排選擇合適的時間進行預約。這樣可以提高預約的效率,減少溝通成本,方便雙方的安排

功能規劃

    1. 首頁展示:展示最新的公告通知、老師推薦等內容,吸引用戶關注。
    1. 老師列表:列出所有開課的老師信息,包括老師的個人簡介、星級等,方便用戶選擇合適的老師。
    1. 預約功能:用戶可以根據自己的需求選擇老師,并進行預約。
    1. 預約管理:用戶可以查看自己的預約記錄,包括已完成的預約和待核銷的預約,也可以取消預約。
  • 后臺端:可以添加和設定老師的基本信息,賬號,登陸密碼等。

  • 老師端:可以編輯自己的個人資料(頭像,簡介,標簽集等),設定預約時段排期(可預約時段,各時段人數限定), 在現場核銷用戶的預約碼。

  • 顧客端:選擇自己需要的老師和時段,下單預約,預約成功后出示預約碼給老師或者工作人員核銷。

概要設計

在這里插入圖片描述

數據庫設計


MeetModel.DB_STRUCTURE = {_pid: 'string|true',MEET_ID: 'string|true',MEET_ADMIN_ID: 'string|true|comment=添加的管理員',MEET_TITLE: 'string|true|comment=標題',MEET_JOIN_FORMS: 'array|true|default=[]|comment=表單字段設置',MEET_DAYS: 'array|true|default=[]|comment=最近一次修改保存的可用日期',MEET_CATE_ID: 'string|true|comment=分類編號',MEET_CATE_NAME: 'string|true|comment=分類冗余', MEET_FORMS: 'array|true|default=[]',MEET_OBJ: 'object|true|default={}',  MEET_CANCEL_SET: 'int|true|default=1|comment=取消設置 0=不允,1=允許,2=僅開始前可取消',MEET_STATUS: 'int|true|default=1|comment=狀態 0=未啟用,1=使用中,9=停止預約,10=已關閉',MEET_ORDER: 'int|true|default=9999',MEET_VOUCH: 'int|true|default=0',MEET_QR: 'string|false',MEET_PHONE: 'string|false|comment=登錄手機',MEET_PASSWORD: 'string|false|comment=登錄密碼',MEET_TOKEN: 'string|false|comment=當前登錄token',MEET_TOKEN_TIME: 'int|true|default=0|comment=當前登錄token time',MEET_MINI_OPENID: 'string|false|comment=小程序openid',MEET_LOGIN_CNT: 'int|true|default=0|comment=登錄次數',MEET_LOGIN_TIME: 'int|false|comment=最近登錄時間',MEET_ADD_TIME: 'int|true',MEET_EDIT_TIME: 'int|true',MEET_ADD_IP: 'string|false',MEET_EDIT_IP: 'string|false',
};UserModel.DB_STRUCTURE = {_pid: 'string|true',USER_ID: 'string|true',USER_MINI_OPENID: 'string|true|comment=小程序openid',USER_STATUS: 'int|true|default=1|comment=狀態 0=待審核,1=正常,8=審核未過,9=禁用',USER_CHECK_REASON: 'string|false|comment=審核未過的理由',USER_NAME: 'string|false|comment=用戶昵稱',USER_MOBILE: 'string|false|comment=聯系電話',USER_FORMS: 'array|true|default=[]',USER_OBJ: 'object|true|default={}',USER_LOGIN_CNT: 'int|true|default=0|comment=登錄次數',USER_LOGIN_TIME: 'int|false|comment=最近登錄時間',USER_ADD_TIME: 'int|true',USER_ADD_IP: 'string|false',USER_EDIT_TIME: 'int|true',USER_EDIT_IP: 'string|false',
}

核心代碼

class MeetService extends BaseProjectService {constructor() {super();this._log = new LogUtil(projectConfig.MEET_LOG_LEVEL);}/*** 拋出異常* @param {*} msg * @param {*} code */AppError(msg) {this._log.error(msg);super.AppError(msg);}_meetLog(meet, func = '', msg = '') {let str = '';str = `[MEET=${meet.MEET_TITLE}][${func}] ${msg}`;this._log.debug(str);}/** 統一獲取Meet(某天) */async getMeetOneDay(meetId, day, where, fields = '*') {let meet = await MeetModel.getOne(where, fields);if (!meet) return meet;meet.MEET_DAYS_SET = await this.getDaysSet(meetId, day, day);return meet;}/** 獲取日期設置 */async getDaysSet(meetId, startDay, endDay = null) {let where = {DAY_MEET_ID: meetId}if (startDay && endDay && endDay == startDay)where.day = startDay;else if (startDay && endDay)where.day = ['between', startDay, endDay];else if (!startDay && endDay)where.day = ['<=', endDay];else if (startDay && !endDay)where.day = ['>=', startDay];let orderBy = {'day': 'asc'}let list = await DayModel.getAllBig(where, 'day,dayDesc,times', orderBy, 1000);for (let k = 0; k < list.length; k++) {delete list[k]._id;}return list;}// 按時段統計某時段報名情況async statJoinCnt(meetId, timeMark) {let whereDay = {DAY_MEET_ID: meetId,day: this.getDayByTimeMark(timeMark)};let day = await DayModel.getOne(whereDay, 'times');if (!day) return;let whereJoin = {JOIN_MEET_TIME_MARK: timeMark,JOIN_MEET_ID: meetId};let ret = await JoinModel.groupCount(whereJoin, 'JOIN_STATUS');let stat = { //統計數據succCnt: ret['JOIN_STATUS_1'] || 0, //1=預約成功,cancelCnt: ret['JOIN_STATUS_10'] || 0, //10=已取消, adminCancelCnt: ret['JOIN_STATUS_99'] || 0, //99=后臺取消};let times = day.times;for (let j in times) {if (times[j].mark === timeMark) {let data = {['times.' + j + '.stat']: stat}await DayModel.edit(whereDay, data);return;}}}// 預約前檢測async beforeJoin(userId, meetId, timeMark) {await this.checkMeetRules(userId, meetId, timeMark);}// 根據日期獲取其所在天設置getDaySetByDay(meet, day) {for (let k = 0; k < meet.MEET_DAYS_SET.length; k++) {if (meet.MEET_DAYS_SET[k].day == day)return dataUtil.deepClone(meet.MEET_DAYS_SET[k]);}return null;}// 根據時段標識獲取其所在天 getDayByTimeMark(timeMark) {return timeMark.substr(1, 4) + '-' + timeMark.substr(5, 2) + '-' + timeMark.substr(7, 2);}// 根據時段標識獲取其所在天設置getDaySetByTimeMark(meet, timeMark) {let day = this.getDayByTimeMark(timeMark);for (let k = 0; k < meet.MEET_DAYS_SET.length; k++) {if (meet.MEET_DAYS_SET[k].day == day)return dataUtil.deepClone(meet.MEET_DAYS_SET[k]);}return null;}// 根據時段標識獲取其所在時段設置getTimeSetByTimeMark(meet, timeMark) {let day = this.getDayByTimeMark(timeMark);for (let k = 0; k < meet.MEET_DAYS_SET.length; k++) {if (meet.MEET_DAYS_SET[k].day != day) continue;for (let j in meet.MEET_DAYS_SET[k].times) {if (meet.MEET_DAYS_SET[k].times[j].mark == timeMark)return dataUtil.deepClone(meet.MEET_DAYS_SET[k].times[j]);}}return null;}// 預約時段人數和狀態控制校驗async checkMeetTimeControll(meet, timeMark, meetPeopleCnt = 1) {if (!meet) this.AppError('預約時段設置錯誤, 預約項目不存在');let daySet = this.getDaySetByTimeMark(meet, timeMark); // 當天設置let timeSet = this.getTimeSetByTimeMark(meet, timeMark); // 預約時段設置if (!daySet || !timeSet) this.AppError('預約時段設置錯誤day&time');let statusDesc = timeSet.status == 1 ? '開啟' : '關閉';let limitDesc = '';if (timeSet.isLimit) {limitDesc = '人數上限MAX=' + timeSet.limit;} elselimitDesc = '人數不限制NO';this._meetLog(meet, `------------------------------`);this._meetLog(meet, `#預約時段控制,預約日期=<${daySet.day}>`, `預約時段=[${timeSet.start}-${timeSet.end}],狀態=${statusDesc}, ${limitDesc} 當前預約成功人數=${timeSet.stat.succCnt}`);if (timeSet.status == 0) this.AppError('該時段預約已經關閉,請選擇其他');// 時段總人數限制if (timeSet.isLimit) {if (timeSet.stat.succCnt >= timeSet.limit) {this.AppError('該時段預約人員已滿,請選擇其他');}let maxCnt = timeSet.limit - timeSet.stat.succCnt;if (maxCnt < meetPeopleCnt) {this.AppError('本時段最多還可以預約' + (maxCnt) + '人,您當前提交了' + meetPeopleCnt + '人,請調整后再提交');}}}/** 報名規則校驗 */async checkMeetRules(userId, meetId, timeMark, formsList = null) {// 預約時段是否存在let meetWhere = {_id: meetId};let day = this.getDayByTimeMark(timeMark);let meet = await this.getMeetOneDay(meetId, day, meetWhere);if (!meet) {this.AppError('預約時段選擇錯誤,請重新選擇');}// 預約時段人數和狀態控制校驗let meetPeopleCnt = formsList ? formsList.length : 1;await this.checkMeetTimeControll(meet, timeMark, meetPeopleCnt);// 截止規則  await this.checkMeetEndSet(meet, timeMark);// 針對用戶的次數限制await this.checkMeetLimitSet(userId, meet, timeMark, meetPeopleCnt);}// 預約次數限制校驗async checkMeetLimitSet(userId, meet, timeMark, nowCnt) {if (!meet) this.AppError('預約次數規則錯誤, 預約項目不存在');let meetId = meet._id;let daySet = this.getDaySetByTimeMark(meet, timeMark); // 當天設置let timeSet = this.getTimeSetByTimeMark(meet, timeMark); // 預約時段設置this._meetLog(meet, `------------------------------`);this._meetLog(meet, `#預約次數規則,預約日期=<${daySet.day}>`, `預約時段=[${timeSet.start}~${timeSet.end}]`);let where = {JOIN_MEET_ID: meetId,JOIN_MEET_TIME_MARK: timeMark,JOIN_USER_ID: userId,JOIN_STATUS: JoinModel.STATUS.SUCC}let cnt = await JoinModel.count(where);let maxCnt = projectConfig.MEET_MAX_JOIN_CNT;this._meetLog(meet, `預約次數規則,mode=本時段可預約${maxCnt}次`, `當前已預約=${cnt}次`);if (cnt >= maxCnt)this.AppError(`您本時段已經預約,不能繼續預約`);}// 預約截止設置校驗async checkMeetEndSet(meet, timeMark) {if (!meet) this.AppError('預約截止規則錯誤, 預約項目不存在');this._meetLog(meet, `------------------------------`);let daySet = this.getDaySetByTimeMark(meet, timeMark); // 當天設置let timeSet = this.getTimeSetByTimeMark(meet, timeMark); // 預約時段設置this._meetLog(meet, `#預約截止規則,預約日期=<${daySet.day}>`, `預約時段=[${timeSet.start}-${timeSet.end}]`);let nowTime = timeUtil.time('Y-M-D h:m:s');/*let startTime = daySet.day + ' ' + timeSet.start + ':00';this._meetLog(meet, `預約開始規則,mode=<時段過期判定>`, `預約開始時段=${startTime},當前時段=${nowTime}`);if (nowTime > startTime) {this.AppError('該時段已開始,無法預約,請選擇其他');}*/let endTime = daySet.day + ' ' + timeSet.end + ':59';this._meetLog(meet, `預約開始規則,mode=<時段過期判定>`, `預約結束時段=${endTime},當前時段=${nowTime}`);if (nowTime > endTime) {this.AppError('該時段已結束,無法預約,請選擇其他');}}/**  預約詳情 */async viewMeet(meetId) {let fields = '*';let where = {_id: meetId,MEET_STATUS: ['in', [MeetModel.STATUS.COMM, MeetModel.STATUS.OVER]]}let meet = await MeetModel.getOne(where, fields);if (!meet) return null;let getDaysSet = [];meet.MEET_DAYS_SET = await this.getDaysSet(meetId, timeUtil.time('Y-M-D')); //今天及以后let daysSet = meet.MEET_DAYS_SET;let now = timeUtil.time('Y-M-D');for (let k = 0; k < daysSet.length; k++) {let dayNode = daysSet[k];if (dayNode.day < now) continue; // 排除過期let getTimes = [];for (let j in dayNode.times) {let timeNode = dayNode.times[j];// 排除狀態關閉的時段if (timeNode.status != 1) continue;// 判斷數量是否已滿if (timeNode.isLimit && timeNode.stat.succCnt >= timeNode.limit)timeNode.error = '預約已滿';// 截止規則if (!timeNode.error) {try {await this.checkMeetEndSet(meet, timeNode.mark);} catch (ex) {if (ex.name == 'AppError')timeNode.error = '預約結束';elsethrow ex;}}getTimes.push(timeNode);}dayNode.times = getTimes;getDaysSet.push(dayNode);}// 只返回需要的字段let ret = {};ret.MEET_DAYS_SET = getDaysSet;ret.MEET_QR = meet.MEET_QR;ret.MEET_TITLE = meet.MEET_TITLE;ret.MEET_CATE_NAME = meet.MEET_CATE_NAME;ret.MEET_OBJ = meet.MEET_OBJ;return ret;}/**  預約前獲取關鍵信息 */async detailForJoin(userId, meetId, timeMark) {let fields = 'MEET_DAYS_SET,MEET_JOIN_FORMS, MEET_TITLE';let where = {_id: meetId,MEET_STATUS: ['in', [MeetModel.STATUS.COMM, MeetModel.STATUS.OVER]]}let day = this.getDayByTimeMark(timeMark);let meet = await this.getMeetOneDay(meetId, day, where, fields);if (!meet) return null;let dayDesc = timeUtil.fmtDateCHN(this.getDaySetByTimeMark(meet, timeMark).day);let timeSet = this.getTimeSetByTimeMark(meet, timeMark);let timeDesc = timeSet.start + '~' + timeSet.end;meet.dayDesc = dayDesc + ' ' + timeDesc;// 取出本人最近一次本時段填寫表單let whereMy = {JOIN_USER_ID: userId,}let orderByMy = {JOIN_ADD_TIME: 'desc'}let joinMy = await JoinModel.getOne(whereMy, 'JOIN_FORMS', orderByMy);if (joinMy)meet.myForms = joinMy.JOIN_FORMS;elsemeet.myForms = [];return meet;}/** 按天獲取預約項目 */async getMeetListByDay(day) {let where = {'meet.MEET_STATUS': ['in', [MeetModel.STATUS.COMM, MeetModel.STATUS.OVER]],'day': day,};let orderBy = {'MEET_ORDER': 'asc','MEET_ADD_TIME': 'desc'};let fields = 'meet.MEET_ORDER,meet.MEET_ADD_TIME,meet.MEET_TITLE,meet.MEET_DAYS_SET,meet.MEET_OBJ.cover, DAY_MEET_ID, day, times';let joinParams = {from: MeetModel.CL,localField: 'DAY_MEET_ID',foreignField: '_id',as: 'meet',};let list = await DayModel.getListJoin(joinParams, where, fields, orderBy, 1, 100, false);list = list.list;let retList = [];for (let k = 0; k < list.length; k++) {let usefulTimes = [];for (let j in list[k].times) {if (list[k].times[j].status != 1) continue;usefulTimes.push(list[k].times[j]);}if (usefulTimes.length == 0) continue;let node = {};node.timeDesc = usefulTimes.length > 1 ? usefulTimes.length + '個時段' : usefulTimes[0].start;node.title = list[k].meet.MEET_TITLE;node.pic = list[k].meet.MEET_OBJ.cover;node._id = list[k].DAY_MEET_ID;retList.push(node);}return retList;}/** 獲取從某天開始可預約的日期 */async getHasDaysFromDay(day) {let where = {day: ['>=', day],};let fields = 'times,day';let list = await DayModel.getAllBig(where, fields);let retList = [];for (let k = 0; k < list.length; k++) {for (let n in list[k].times) {if (list[k].times[n].status == 1) {retList.push(list[k].day);break;}}}return retList;}/** 取得預約分頁列表 */async getMeetList({search, // 搜索條件sortType, // 搜索菜單sortVal, // 搜索菜單orderBy, // 排序 cateId, //分類查詢條件page,size,isTotal = true,oldTotal}) {orderBy = orderBy || {'MEET_ORDER': 'asc','MEET_ADD_TIME': 'desc'};let fields = 'MEET_TITLE,MEET_OBJ,MEET_DAYS,MEET_CATE_NAME,MEET_CATE_ID';let where = {};where.and = {_pid: this.getProjectId() //復雜的查詢在此處標注PID};if (cateId && cateId !== '0') where.and.MEET_CATE_ID = cateId;where.and.MEET_STATUS = ['in', [MeetModel.STATUS.COMM, MeetModel.STATUS.OVER]]; // 狀態  if (util.isDefined(search) && search) {where.or = [{ MEET_TITLE: ['like', search] },];} else if (sortType && util.isDefined(sortVal)) {// 搜索菜單switch (sortType) {case 'sort': {orderBy = this.fmtOrderBySort(sortVal, 'NEWS_ADD_TIME');break;}case 'cateId': {if (sortVal) where.and.MEET_CATE_ID = String(sortVal);break;}}}let result = await MeetModel.getList(where, fields, orderBy, page, size, isTotal, oldTotal);return result;}/** 取消我的預約 只有成功可以取消 */async cancelMyJoin(userId, joinId) {let where = {JOIN_USER_ID: userId,_id: joinId,JOIN_IS_CHECKIN: 0, // 核銷不能取消JOIN_STATUS: JoinModel.STATUS.SUCC};let join = await JoinModel.getOne(where);if (!join) {this.AppError('未找到可取消的預約記錄');}// 取消規則判定let whereMeet = {_id: join.JOIN_MEET_ID,MEET_STATUS: ['in', [MeetModel.STATUS.COMM, MeetModel.STATUS.OVER]]}let meet = await this.getMeetOneDay(join.JOIN_MEET_ID, join.JOIN_MEET_DAY, whereMeet);if (!meet) this.AppError('預約項目不存在或者已關閉');let daySet = this.getDaySetByTimeMark(meet, join.JOIN_MEET_TIME_MARK);let timeSet = this.getTimeSetByTimeMark(meet, join.JOIN_MEET_TIME_MARK);if (!timeSet) this.AppError('被取消的時段不存在');if (meet.MEET_CANCEL_SET == 0)this.AppError('該預約不能取消');let startT = daySet.day + ' ' + timeSet.start + ':00';let startTime = timeUtil.time2Timestamp(startT);let now = timeUtil.time();if (meet.MEET_CANCEL_SET == 2 && now > startTime)this.AppError('該預約時段已經開始,無法取消');// TODO 已過期不能取消await JoinModel.del(where);// 統計this.statJoinCnt(join.JOIN_MEET_ID, join.JOIN_MEET_TIME_MARK);}/** 取得我的預約詳情 */async getMyJoinDetail(userId, joinId) {let fields = 'JOIN_COMPLETE_END_TIME,JOIN_IS_CHECKIN,JOIN_CHECKIN_TIME,JOIN_REASON,JOIN_MEET_ID,JOIN_MEET_TITLE,JOIN_MEET_DAY,JOIN_MEET_TIME_START,JOIN_MEET_TIME_END,JOIN_STATUS,JOIN_ADD_TIME,JOIN_CODE,JOIN_FORMS';let where = {_id: joinId,JOIN_USER_ID: userId};return await JoinModel.getOne(where, fields);}/** 取得我的預約分頁列表 */async getMyJoinList(userId, {search, // 搜索條件sortType, // 搜索菜單sortVal, // 搜索菜單orderBy, // 排序 page,size,isTotal = true,oldTotal}) {orderBy = orderBy || {//	'JOIN_MEET_DAY': 'desc',//	'JOIN_MEET_TIME_START': 'desc','JOIN_ADD_TIME': 'desc'};let fields = 'JOIN_COMPLETE_END_TIME,JOIN_IS_CHECKIN,JOIN_REASON,JOIN_MEET_ID,JOIN_MEET_TITLE,JOIN_MEET_DAY,JOIN_MEET_TIME_START,JOIN_MEET_TIME_END,JOIN_STATUS,JOIN_ADD_TIME,JOIN_OBJ';let where = {JOIN_USER_ID: userId};//where.MEET_STATUS = ['in', [MeetModel.STATUS.COMM, MeetModel.STATUS.OVER]]; // 狀態  if (util.isDefined(search) && search) {where['JOIN_MEET_TITLE'] = {$regex: '.*' + search,$options: 'i'};} else if (sortType) {// 搜索菜單switch (sortType) {case 'cateId': {if (sortVal) where.JOIN_MEET_CATE_ID = String(sortVal);break;}case 'all': { //所有 break;}case 'use': { //可用未過期where.JOIN_STATUS = JoinModel.STATUS.SUCC;where.JOIN_COMPLETE_END_TIME = ['>=', timeUtil.time('Y-M-D h:m')];break;}case 'check': { //已核銷where.JOIN_STATUS = JoinModel.STATUS.SUCC;where.JOIN_IS_CHECKIN = 1;break;}case 'timeout': { //已過期未核銷where.JOIN_STATUS = JoinModel.STATUS.SUCC;where.JOIN_IS_CHECKIN = 0;where.JOIN_COMPLETE_END_TIME = ['<', timeUtil.time('Y-M-D h:m')];break;}case 'succ': { //預約成功where.JOIN_STATUS = JoinModel.STATUS.SUCC;//where.JOIN_MEET_DAY = ['>=', timeUtil.time('Y-M-D h:m')];//where.JOIN_MEET_TIME_START = ['>=', timeUtil.time('h:m')];break;}case 'cancel': { //已取消where.JOIN_STATUS = ['in', [JoinModel.STATUS.CANCEL, JoinModel.STATUS.ADMIN_CANCEL]];break;}}}let result = await JoinModel.getList(where, fields, orderBy, page, size, isTotal, oldTotal);return result;}/** 取得我的某日預約列表 */async getMyJoinSomeday(userId, day) {let fields = 'JOIN_IS_CHECKIN,JOIN_MEET_ID,JOIN_MEET_TITLE,JOIN_MEET_DAY,JOIN_MEET_TIME_START,JOIN_MEET_TIME_END,JOIN_STATUS,JOIN_ADD_TIME';let where = {JOIN_USER_ID: userId,JOIN_MEET_DAY: day};//where.MEET_STATUS = ['in', [MeetModel.STATUS.COMM, MeetModel.STATUS.OVER]]; // 狀態  let orderBy = {'JOIN_MEET_TIME_START': 'asc','JOIN_ADD_TIME': 'desc'}return await JoinModel.getAll(where, fields, orderBy);}
}

UI設計

在這里插入圖片描述在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

老師端設計

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

管理端

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

git代碼下載

git下載

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/40807.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/40807.shtml
英文地址,請注明出處:http://en.pswp.cn/web/40807.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

記錄第一次使用air熱更新golang項目

下載 go install github.com/cosmtrek/airlatest 下載時提示&#xff1a; module declares its path as: github.com/air-verse/air but was required as: github.com/cosmtrek/air 此時&#xff0c;需要在go.mod中加上這么一句&#xff1a; replace github.com/cosmtrek/air &…

如何使用Pip從Git倉庫安裝Python包:深入探索遠程依賴管理

如何使用Pip從Git倉庫安裝Python包&#xff1a;深入探索遠程依賴管理 Python的包管理工具Pip使得安裝和管理Python庫變得非常簡單。有時&#xff0c;我們需要安裝那些尚未發布到PyPI的包&#xff0c;或者想要嘗試最新的開發版本。這時&#xff0c;可以直接從Git倉庫安裝包。本…

qt QGridLayout 簡單實驗1

1.概要 2.實驗 2.1 實驗1 簡單實驗跨行 2.1.1 代碼 #ifndef WIDGET_H #define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);~W…

STM32 - 內存分區與OTA

最近搞MCU&#xff0c;發現它與SOC之間存在諸多差異&#xff0c;不能沿用SOC上一些技術理論。本文以STM L4為例&#xff0c;總結了一些STM32 小白入門指南。 標題MCU沒有DDR&#xff1f; 是的。MCU并沒有DDR&#xff0c;而是讓代碼存儲在nor flash上&#xff0c;臨時變量和棧…

yolov5實例分割跑通以及C#讀取yolov5_Seg實例分割轉換onnx進行檢測部署

一、首先需要訓練yolov5_seg的模型&#xff0c;可以去網上學習&#xff0c;或者你直接用我的&#xff0c; 訓練環境和yolov5—7.0的環境一樣&#xff0c;你可以直接拷過來用。 yolov5_seg算法 鏈接&#xff1a;https://pan.baidu.com/s/1m-3lFWRHwg5t8MmIOKm4FA 提取碼&…

【MySQL】1.初識MySQL

初識MySQL 一.MySQL 安裝1.卸載已有的 MySQL2.獲取官方 yum 源3.安裝 MySQL4.登錄 MySQL5.配置 my.cnf 二.MySQL 數據庫基礎1.MySQL 是什么&#xff1f;2.服務器&#xff0c;數據庫和表3.mysqld 的層狀結構4.SQL 語句分類 一.MySQL 安裝 1.卸載已有的 MySQL //查詢是否有相關…

《Windows API每日一練》8.3 scrollbar控件

在第三章SYSMETS2.C實例中&#xff0c;我們是通過CreateWindow函數創建窗口的參數窗口樣式中添加垂直或水平滾動條。本節我們將講述作為子窗口控件的滾動條。 本節必須掌握的知識點&#xff1a; 滾動條類 滾動條控件和著色 8.3.1 滾動條類 ■窗口滾動條與滾動條控件的異同 …

Python常量與變量的終極指南:從基礎到進階的15個要點

今天&#xff0c;我們將一起揭開Python中最基本但也極其重要的概念——常量與變量的神秘面紗。別擔心&#xff0c;我會用最簡單直白的語言&#xff0c;讓你從入門到略有小成&#xff0c;一步步掌握這些核心知識。準備好你的筆記本&#xff0c;讓我們開始這場Python之旅吧&#…

在Linux環境下搭建Redis服務結合內網穿透實現通過GUI工具遠程管理數據庫

文章目錄 前言1. 安裝Docker步驟2. 使用docker拉取redis鏡像3. 啟動redis容器4. 本地連接測試4.1 安裝redis圖形化界面工具4.2 使用RDM連接測試 5. 公網遠程訪問本地redis5.1 內網穿透工具安裝5.2 創建遠程連接公網地址5.3 使用固定TCP地址遠程訪問 前言 本文主要介紹如何在Li…

mysql 9 新特新

mysql9新特性 新特性Audit Log NotesC API NotesCharacter Set SupportCompilation NotesComponent NotesConfiguration NotesData Dictionary NotesData Type NotesDeprecation and Removal NotesEvent Scheduler NotesJavaScript ProgramsOptimizer NotesPerformance Schema …

Spring中的事件監聽器使用學習

一、什么是Spring中的事件監聽機制&#xff1f; Spring框架中的事件監聽機制是一種設計模式&#xff0c;它允許你定義和觸發事件&#xff0c;同時允許其他組件監聽這些事件并在事件發生時作出響應。這種機制基于觀察者模式&#xff0c;提供了一種松耦合的方式來實現組件間的通信…

Linux 系統性能分析與故障排查:從入門到進階

Linux 系統性能分析與故障排查&#xff1a;從入門到進階 作為系統管理員或 IT 專業人員&#xff0c;掌握系統性能分析和故障排查技能至關重要。這些技能可以幫助你識別和解決系統性能問題&#xff0c;確保系統穩定運行。本文將介紹系統性能分析和故障排查的基本方法&#xff0…

CTF實戰:從入門到提升

CTF實戰&#xff1a;從入門到提升 &#x1f680;前言 沒有網絡安全就沒有國家安全&#xff0c;網絡安全不僅關系到國家整體信息安全&#xff0c;也關系到民生安全。近年來&#xff0c;隨著全國各行各業信息化的發展&#xff0c;網絡與信息安全得到了進一步重視&#xff0c;越…

XAML 框架橫向對比

多年來&#xff0c;基于 XAML 的 UI 框架有了很大的發展。下面的圖表很好地證明了這個觀點。XAML UI 框架的三大巨頭&#xff1a;Avalonia UI、Uno Platform 和 .NET MAUI 都支持跨平臺的應用。事實上&#xff0c;除了 Avalonia UI&#xff0c;對跨平臺 XAML 的需求是它們發展的…

【深度學習】圖形模型基礎(5):線性回歸模型第四部分:預測與貝葉斯推斷

1.引言 貝葉斯推斷超越了傳統估計方法&#xff0c;它包含三個關鍵步驟&#xff1a;結合數據和模型形成后驗分布&#xff0c;通過模擬傳播不確定性&#xff0c;以及利用先驗分布整合額外信息。本文將通過實際案例闡釋這些步驟&#xff0c;展示它們在預測和推斷中的挑戰和應用。…

Unity 使用AVProMovieCapture實現Game視圖屏幕錄制

內容將會持續更新&#xff0c;有錯誤的地方歡迎指正&#xff0c;謝謝! Unity 使用AVProMovieCapture實現Game視圖屏幕錄制 TechX 堅持將創新的科技帶給世界&#xff01; 擁有更好的學習體驗 —— 不斷努力&#xff0c;不斷進步&#xff0c;不斷探索 TechX —— 心探索、心…

【云計算】公有云、私有云、混合云、社區云、多云

公有云、私有云、混合云、社區云、多云 1.云計算的形態1.1 公有云1.2 私有云1.3 混合云1.4 社區云1.5 多云1.5.1 多云和混合云之間的關系1.5.2 多云的用途1.5.3 影子 IT 和多云1.5.4 優缺點 2.不同云形態的對比 1.云計算的形態 張三??在家做飯吃&#xff0c;這是 私有云&…

liunx上修改Firefox版本號

在Linux上修改Firefox的版本號并不直接推薦也不鼓勵&#xff0c;因為這可能會影響到瀏覽器的安全性、兼容性和自動更新功能。但如果你因為某些特殊測試場景確實需要修改其顯示的版本號&#xff08;請注意&#xff0c;這樣做可能會引發不可預料的問題&#xff09;&#xff0c;可…

【擴散模型】LCM LoRA:一個通用的Stable Diffusion加速模塊

潛在一致性模型&#xff1a;[2310.04378] Latent Consistency Models: Synthesizing High-Resolution Images with Few-Step Inference (arxiv.org) 原文&#xff1a;Paper page - Latent Consistency Models: Synthesizing High-Resolution Images with Few-Step Inference (…

ELK優化之Filebeat部署

目錄 1.安裝配置Nginx 2.安裝 Filebeat 3.設置 filebeat 的主配置文件 4.修改Logstash配置 5.啟動配置 6.kibana驗證 主機名ip地址主要軟件es01192.168.9.114ElasticSearches02192.168.9.115ElasticSearches03192.168.9.116ElasticSearch、Kibananginx01192.168.9.113ng…