从0到1:多医院陪诊小程序开发笔记(上)

概要设计

医院陪诊预约小程序:随着移动互联网的普及,越来越多的医院陪诊服务开始向线上转型, 传统的预约方式往往效率低下,用户需耗费大量时间进行电话预约或现场排队,陪诊服务预约小程序集多种服务于一体,可以提高服务效率、提升用户体验。 用户可以浏览不同医院的位置、陪诊项目和陪诊时间,用户可以选择日期、时间段和人数,然后进行预约。

功能规划

本项目前后端完整代码包括公告通知,用户预约,签到核销, 管理者可以自定义预约要填写的内容,比如姓名、性别、年龄、诊疗科室、手机号等,后台预约管理,后台预约名单管理和导出Excel,后台设置预约时段和人数上线,后台管理最新通知公告,后台用户管理,后台医院管理,医院管理员设定等功能。

在这里插入图片描述

数据库设计

MeetModel.DB_STRUCTURE = {_pid: 'string|true',MEET_ID: 'string|true',MEET_ADMIN_ID: 'string|true|comment=添加的管理员',MEET_TITLE: 'string|true|comment=标题',MEET_UNIT_ID: 'string|false',MEET_UNIT_NAME: 'string|false',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_ADD_TIME: 'int|true',MEET_EDIT_TIME: 'int|true',MEET_ADD_IP: 'string|false',MEET_EDIT_IP: 'string|false',
};JoinModel.DB_STRUCTURE = {_pid: 'string|true',JOIN_ID: 'string|true',JOIN_UNIT_ID: 'string|false',JOIN_UNIT_NAME: 'string|false',JOIN_EDIT_ADMIN_ID: 'string|false|comment=最近修改的管理员ID',JOIN_EDIT_ADMIN_NAME: 'string|false|comment=最近修改的管理员名',JOIN_EDIT_ADMIN_TIME: 'int|true|default=0|comment=管理员最近修改的时间',JOIN_EDIT_ADMIN_STATUS: 'int|false|comment=最近管理员修改为的状态 ',JOIN_IS_ADMIN: 'int|true|default=0|comment=是否管理员添加 0/1',JOIN_CODE: 'string|true|comment=核验码15位',JOIN_IS_CHECKIN: 'int|true|default=0|comment=是否核销 0/1 ',JOIN_CHECKIN_TIME: 'int|true|default=0',JOIN_USER_ID: 'string|true|comment=用户ID',JOIN_MEET_ID: 'string|true|comment=预约PK',JOIN_MEET_CATE_ID: 'string|true',JOIN_MEET_CATE_NAME: 'string|true',JOIN_MEET_TITLE: 'string|true|comment=项目',JOIN_MEET_DAY: 'string|true|comment=日期',JOIN_MEET_TIME_START: 'string|true|comment=时段开始',JOIN_MEET_TIME_END: 'string|true|comment=时段结束',JOIN_MEET_TIME_MARK: 'string|true|comment=时段标识',JOIN_COMPLETE_END_TIME: 'string|false|comment=完整结束时间',JOIN_START_TIME: 'int|true|comment=开始时间戳',JOIN_FORMS: 'array|true|default=[]|comment=表单',/* title:mark:type:val:*/JOIN_OBJ: 'object|true|default={}',JOIN_STATUS: 'int|true|default=1|comment=状态 1=预约成功,10=已取消, 99=系统取消',JOIN_REASON: 'string|false|comment=审核拒绝或者取消理由',JOIN_ADD_TIME: 'int|true',JOIN_EDIT_TIME: 'int|true',JOIN_ADD_IP: 'string|false',JOIN_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;ret.MEET_UNIT_NAME = meet.MEET_UNIT_NAME;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(unit, day) {let where = {'meet.MEET_STATUS': ['in', [MeetModel.STATUS.COMM, MeetModel.STATUS.OVER]],'day': day,DAY_UNIT_NAME: unit,};let orderBy = {'MEET_ORDER': 'asc','MEET_ADD_TIME': 'desc'};let fields = 'meet.MEET_UNIT_NAME,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(unit, day) {console.log(unit)let where = {DAY_UNIT_NAME: unit,day: ['>=', day],};let fields = 'DAY_UNIT_NAME,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;}}} console.log(retList)return retList;}/** 取得预约分页列表 */async getMeetList({unit,search, // 搜索条件sortType, // 搜索菜单sortVal, // 搜索菜单orderBy, // 排序 cateId, //分类查询条件page,size,isTotal = true,oldTotal}) {orderBy = orderBy || {'MEET_ORDER': 'asc','MEET_ADD_TIME': 'desc'};let fields = 'MEET_UNIT_NAME,MEET_TITLE,MEET_OBJ,MEET_DAYS,MEET_CATE_NAME,MEET_CATE_ID';let where = {};where.and = {MEET_UNIT_NAME: unit,_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_UNIT_NAME,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_UNIT_NAME,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下载

github下载

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

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

相关文章

定时任务:springboot集成xxl-job-core(二)

定时任务实现方式&#xff1a; 存在的问题&#xff1a; xxl-job的原理&#xff1a; 可以根据服务器的个数进行动态分片&#xff0c;每台服务器分到的处理数据是不一样的。 1. 多台机器动态注册 多台机器同时配置了调度器xxl-job-admin之后&#xff0c;执行器那里会有多个注…

Unity使用Lua框架和C#框架开发游戏的区别

在Unity中使用Lua框架和C#框架开发游戏有显著的区别&#xff0c;主要体现在性能、开发效率、热更新能力、维护成本等方面。 1. 语言类型与设计目标 维度LuaC#类型动态类型、解释型脚本语言静态类型、编译型面向对象语言设计初衷轻量级嵌入、配置和扩展宿主程序通用开发&#…

高精度文档解析利器:Mistral OCR 全面解析与技术应用

目录 &#x1f680; 高精度文档解析利器&#xff1a;Mistral OCR 全面解析与技术应用 一、什么是 Mistral OCR&#xff1f; 二、Mistral OCR 的核心特点 ✅ 1. 支持复杂文档结构解析 ✅ 2. 高识别精度 ✅ 3. 与 AI 系统深度集成 ✅ 4. 可扩展性与容错能力 三、技术原理…

腾讯云开发者社区文章内容提取免费API接口教程

接口简介&#xff1a; 提取指定腾讯云开发者社区文章内容。本接口仅做内容提取&#xff0c;未经作者授权请勿转载。 请求地址&#xff1a; https://cn.apihz.cn/api/caiji/tencent.php 请求方式&#xff1a; POST或GET。 请求参数&#xff1a; 【名称】【参数】【必填】【说…

【项目】在线OJ(负载均衡式)

目录 一、项目目标 二、开发环境 1.技术栈 2.开发环境 三、项目树 目录结构 功能逻辑 编写思路 四、编码 1.complie_server 服务功能 代码蓝图 开发编译功能 日志功能 ​编辑 测试编译模块 开发运行功能 设置运行限制 jsoncpp 编写CR 如何生成唯一文件名 …

【后端高阶面经:架构篇】50、数据存储架构:如何改善系统的数据存储能力?

一、数据存储架构设计核心原则 (一)分层存储架构:让数据各得其所 根据数据访问频率和价值,将数据划分为热、温、冷三层,匹配不同存储介质,实现性能与成本的平衡。 热数据层:访问频率>100次/秒。采用Redis集群存储高频访问数据(如用户登录态、实时交易数据),配合…

B1、进度汇报(— 25/05/31)

本文档汇总了各成员在 2025 年 5 月 11 日 ~ 5 月 31 日完成的工作。我们遇到了进度问题&#xff08;收工后需反思&#xff09;&#xff1a; 本学期第十四周&#xff08;05/19 ~ 05/25&#xff09;有相当多课程需要提交实验结果或上台展示。本学期第十六周&#xff08;06/02 ~…

每天总结一个html标签——a标签

文章目录 一、定义与使用说明二、支持的属性三、支持的事件四、默认样式五、常见用法1. 文本链接2. 图片链接3. 导航栏 在前端开发中&#xff0c;a标签&#xff08;锚点标签&#xff09;是最常用的HTML标签之一&#xff0c;主要用于创建超链接&#xff0c;实现页面间的跳转或下…

云服务器突发宕机或无响应怎么办

当云服务器突发宕机或无响应时&#xff0c;需快速定位问题并恢复服务。以下是分步骤的解决方案&#xff1a; 1. 初步确认问题 检查网络连接 本地网络是否正常&#xff1f;尝试 ping 其他网站 排除本地问题。 使用 ping <服务器IP> 或 traceroute <IP> 测试网络连通…

动态IP与区块链:重构网络信任的底层革命

在数字经济蓬勃发展的今天&#xff0c;网络安全与数据隐私正面临前所未有的挑战。动态IP技术与区块链的深度融合&#xff0c;正在构建一个去中心化、高可信的网络基础设施&#xff0c;为Web3.0时代的到来奠定基础。 一、技术碰撞&#xff1a;动态IP与区块链的天然契合 动态I…

从0开始学vue:vue3和vue2的关系

一、版本演进关系1. 继承关系2. 版本生命周期 二、核心差异对比三、关键演进方向1. Composition API2. 性能优化 四、迁移策略1. 兼容构建模式2. 关键破坏性变更 五、生态演进1. 官方库升级2. 构建工具链 六、选型建议1. 新项目2. 现有项目 七、未来展望 一、版本演进关系 1. …

Vue 核心技术与实战智慧商城项目Day08-10

温馨提示&#xff1a;这个黑马的视频在b占可以找到&#xff0c;里面有完整的教学过程 然后这个项目有完整的代码&#xff0c;我已经上传了&#xff0c;如果审核成功大家就可以看了&#xff0c;但是需要审核多久我也不是很确定 1.项目演示 2. 项目收获 3. 创建项目 4. 调整初始化…

AR/MR实时光照阴影开发教程

一、效果演示 1、PICO4 Ultra MR 发光的球 2、AR实时光照 二、实现原理 PICO4 Ultra MR开发时&#xff0c;通过空间网格能力扫描周围环境&#xff0c;然后将扫描到的环境网格材质替换为一个透明材质并停止扫描&#xff1b;基于Google ARCore XR Plugin和ARFoundation进行安卓手…

【Python训练营打卡】day42 @浙大疏锦行

DAY 42 Grad-CAM与Hook函数 知识点回顾 1. 回调函数 2. lambda函数 3. hook函数的模块钩子和张量钩子 4. Grad-CAM的示例 作业&#xff1a;理解下今天的代码即可 Grad-CAM 在深度学习中&#xff0c;我们经常需要查看或修改模型中间层的输出或梯度。然而&#xff0c;标准的…

创建ipv6 only和ipv6+ip4的k8s集群的注意事项

关键字 : CNI calico vxlan flannel ipv6-only ipv6ipv4 在搭建ipv6-only或ipv6ipv4的k8s集群时&#xff0c;在worker节点加入集群后&#xff0c;发现worker节点上的CNI启动失败。 以下是calico的启动失败情况 : kubectl get pod -A输出如下 : NAMESPACE NAME …

鸿蒙OSUniApp离线优先数据同步实战:打造无缝衔接的鸿蒙应用体验#三方框架 #Uniapp

UniApp离线优先数据同步实战&#xff1a;打造无缝衔接的鸿蒙应用体验 最近在开发一个面向鸿蒙生态的UniApp应用时&#xff0c;遇到了一个有趣的挑战&#xff1a;如何在网络不稳定的情况下保证数据的实时性和可用性。经过一番探索和实践&#xff0c;我们最终实现了一套行之有效…

day 43

应用cnn对kaggle上的图像数据集进行练习 数据集地址&#xff1a;Cat and Dog import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pyplot as plt im…

Spring Boot 如何实现定时任务

Spring Boot 如何实现定时任务 在现代的微服务架构中&#xff0c;定时任务是一个常见的需求。无论是数据定时同步、定时清理缓存&#xff0c;还是定时发送通知&#xff0c;Spring Boot 提供了非常强大且灵活的定时任务支持。本文将详细介绍如何在 Spring Boot 中实现定时任务&…

“粽”览全局:分布式系统架构与实践深度解析(端午特别版)

第一部分&#xff1a;引言——技术世界的“端午”第二部分&#xff1a;分布式系统概述——粽子节点初探第三部分&#xff1a;核心技术详解——技术“粽子”大解构 粽叶篇&#xff1a;通信协议糯米篇&#xff1a;一致性算法馅料篇&#xff1a;任务调度与计算包扎篇&#xff1a;系…

AppTrace 视角下 App 一键拉起:提升应用转化率的高效方案​

官网地址&#xff1a;AppTrace - 专业的移动应用推广追踪平台 在大规模开展 App 推广、用户召回、广告投放、邀请传播等活动时&#xff0c;高效的深度链接方案至关重要。它不仅能缩短用户路径&#xff0c;带来无缝、流畅的跳转体验&#xff0c;更核心的是通过参数传递打通 web…