• 会议OA之我的会议(排座&送审)


    一、排座

    思路实现

    1.需要完成在页面上元素的拖动功能,把对应的参会人员放在指定位置,如:重要的人就放在主位
    2.查询出本场会议中的所有参与人员
    3.将已经画好的会议座位图,保存下来,并且绑定到本次会议数据上去;

    1.1 后台代码

    dao方法

    userDao.java

    public List<User> queryUserByMeetingId(Long meetingId) throws Exception{
    		String sql="select * from t_oa_user where FIND_IN_SET(id,"
    				+ "(select concat(canyuze,',',liexize,',',zhuchiren) "
    				+ "from t_oa_meeting_info where id="+meetingId+"))";
    		return super.executeQuery(sql, User.class, null);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    web层

    userAction.java

    //	获取排座用户数据
    	public String queryUserByMeetingId(HttpServletRequest req, HttpServletResponse resp) {
    		try {
    			Long meetingId = Long.parseLong(req.getParameter("meetingId"));
    			List<User> users = userdao.queryUserByMeetingId(meetingId);
    			ResponseUtil.writeJson(resp, R.ok(200, "获取排座用户数据成功!!!", users));
    		} catch (Exception e) {
    			e.printStackTrace();
    			try {
    				ResponseUtil.writeJson(resp, R.error(0, "获取排座用户数据失败!!!"));
    			} catch (Exception e1) {
    				e1.printStackTrace();
    			}
    		}
    
    		return null;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    MeetingInfoAction .java

    package com.zking.web;
    
    import java.io.IOException;
    import java.util.Date;
    import java.util.List;
    import java.util.Map;
    import java.util.UUID;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.commons.beanutils.ConvertUtils;
    
    import com.zking.dao.MeetingInfoDao;
    import com.zking.entity.MeetingInfo;
    import com.zking.framework.ActionSupport;
    import com.zking.framework.ModelDriver;
    import com.zking.util.Base64ImageUtils;
    import com.zking.util.MyDateConverter;
    import com.zking.util.PageBean;
    import com.zking.util.PropertiesUtil;
    import com.zking.util.R;
    import com.zking.util.ResponseUtil;
    
    public class MeetingInfoAction extends ActionSupport implements ModelDriver<MeetingInfo>{
    	private MeetingInfo info = new MeetingInfo();
    	private MeetingInfoDao meetingInfoDao = new MeetingInfoDao();
    
    	@Override
    	public MeetingInfo getModel() {
    		//方式二:
    	    ConvertUtils.register(new MyDateConverter(),Date.class);
    		return info;
    	}
    	
    	
    //	根据会议ID更新会议的排座图片
    	public String updateSeatPicById(HttpServletRequest req,
    			HttpServletResponse resp) throws ServletException,IOException{
    		try {
    			//1.将排座图片保存到指定的位置并得到图片路径
    			//1) 定义会议图片的保存路径
    			String serverPath=PropertiesUtil.getValue("serverPath");
    			String dirPath=PropertiesUtil.getValue("dirPath");
    			//2) 定义会议排座图片的名称(最终要保存到数据库表中),例如:/uploads/xxxxx.jpg
    			String fileName=UUID.randomUUID().toString().replace("-", "")+".jpg";
    			//3) 拼接成完整的路径
    			String realPath=dirPath+fileName;
    			//4) 将图片保存到指定位置
    			Base64ImageUtils.GenerateImage(info.getSeatPic().replace("data:image/png;base64,",""), realPath);
    			
    			//2.根据会议ID修改会议图片信息
    			info.setSeatPic(serverPath+fileName);
    			meetingInfoDao.updateSeatPicById(info);
    			ResponseUtil.writeJson(resp, R.ok(200, "更新会议的排座图片成功"));
    		} catch (Exception e) {
    			e.printStackTrace();
    			try {
    				ResponseUtil.writeJson(resp, R.error(0, "更新会议的排座图片失败"));
    			} catch (Exception e1) {
    				e1.printStackTrace();
    			}
    		}
    		return null;
    	}
    	
    	
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    js代码

    meeting.js

    //打开会议排座对话框
    function open(id){
    	layer.open({
            type: 2,                    //layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)
            title: '会议排座',                   //对话框标题
            area: ['460px', '340px'],   //宽高
            skin: 'layui-layer-rim',    //样式类名
            content: $("#ctx").val()+'/jsp/meeting/seatPic.jsp?id='+id,                //弹出内容。可以传入普通的html内容,还可以指定DOM,更可以随着type的不同而不同
        });
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    配置文件

    注:1.在这里的E盘是本人的保存排座的路径,可以自己修改;
    2.该配置文件要放在根目录,并在server里进行配置

    dirPath=E:/temp/images/T280/
    serverPath=/upload/paizuo/(在/upload前不要加项目名,防止当其他项目用的时候,图片路径错误,提高使用率)
    dirPathSign=E:/temp/images/T280/sign/
    serverPathSign=/upload/sign/
    
    • 1
    • 2
    • 3
    • 4

    server配置步骤:

    1、双击打开server

    在这里插入图片描述

    2、选择最下面的Modules

    在这里插入图片描述

    3、选择第二个,将配置文件的内容一一对应进行添加
    dirPath——>serverPath
    dirPathSign——>serverPathSign

    在这里插入图片描述

    1.2 前台代码

    jsp界面

    seatPic.jsp

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <base href="${pageContext.request.contextPath }/"/>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <link href="static/js/layui/css/layui.css" rel="stylesheet" type="text/css"/>
    <script type="text/javascript" src="static/js/jquery-3.3.1.min.js"></script>
    <script type="text/javascript" src="static/js/layui/layui.js"></script>
    <script type="text/javascript" src="static/js/plugins/html2canvas/html2canvas.js"></script>
    <title>会议座位安排</title>
    </head>
    <style type="text/css">
    * {
    	padding: 0;
    	margin: 0;
    }
    		
    body{
    	width: 100%;
    	height: 100%;
    	/* background: red; */
    }
    
    .tips {
    	/* position: absolute; */
    	background: pink;
    	display: inline-block;
    	height: 60px;
    	/* width: 60px; */
    	line-height: 60px;
    	text-align: center;
    	margin: 5px;
    	padding: 0 10px;
    }
    
    .add {
    	position: fixed;
    	right: 10px;
    	top: 10px;
    	display:inline;
    }
    
    #tu {
    	width: 100%;
    	height: 100%;
    	/* background: lightblue; */
    		/*background: url('u=3318199716,2583790385&fm=26&gp=0.jpg');*/
    }
    .layui-input{
    	height:30px;
    }
    </style>
    <body id="screen_body">
        <div id="tu"></div>
        <!-- 下面不要使用layui的表单行内模式,会导致canvas的toDataURL()数据为 data:, -->
    	<div class="add">
    		<div style="display:inline-block;">
    			<input id="dan_input" type="text" value="" class="layui-input">
    		</div>
    		<div style="display:inline-block;">
    			<button onclick="return addDanMu()" class="layui-btn layui-btn-sm">添加座位</button><input id="jie_input" type="button" class="layui-btn layui-btn-sm" value='下载'>
    		</div>
    	</div>
    </body>
    <script type="text/javascript">
    var $id = function(id) {
    	return document.getElementById(id);
    }
    //会议排座拖拽
    var dragF = {
    	locked: false,
    	lastObj: undefined,
    	drag: function(obj) {
    		$id(obj).onmousedown = function(e) {
    			var e = e ? e : window.event;
    			if (!window.event) {
    				e.preventDefault();
    			} /* 阻止标注浏览器下拖动a,img的默认事件 */
    			dragF.locked = true;
    			$id(obj).style.position = "absolute";
    			$id(obj).style.zIndex = "100";
    			if (dragF.lastObj && dragF.lastObj != $id(obj)) { /* 多元素拖动需要恢复上次元素状态 */
    				dragF.lastObj.style.zIndex = "1";
    			}
    
    			dragF.lastObj = $id(obj);
    			var tempX = $id(obj).offsetLeft;
    			var tempY = $id(obj).offsetTop;
    
    			dragF.x = e.clientX;
    			dragF.y = e.clientY;
    			document.onmousemove = function(e) {
    				var e = e ? e : window.event;
    				if (dragF.locked == false) return false;
    				$id(obj).style.left = tempX + e.clientX - dragF.x + "px";
    				$id(obj).style.top = tempY + e.clientY - dragF.y + "px";
    				if (window.event) {
    					e.returnValue = false;
    				} /* 阻止ie下a,img的默认事件 */
    
    			}
    
    			document.onmouseup = function() {
    				dragF.locked = false;
    			}
    		}
    	}
    }
    </script>
    
    <script type="text/javascript">
    var layer;
    layui.use(['layer'],function(){
    	layer=layui.layer;
    
        //初始化会议排座:根据会议ID获取参会的所有人员的名字(主持人+参会人+列席人)
    	initMeetingUsers();
    	
    	//绘制会议排座图片
    	$("#jie_input").on("click", function(event) {
    		$('.add').hide();
    		event.preventDefault();
    		html2canvas(document.getElementById("screen_body")).then(function(canvas) {
    			var dataUrl = canvas.toDataURL();
    			console.log(dataUrl);
    			var param = {};
    			param['seatPic'] = dataUrl;
    			param['id'] = '${param.id}';
    			param['methodName']='updateSeatPicById';
    			console.log(param);
    			//此处需要完成会议排座图片上传操作
    			$.post('${pageContext.request.contextPath }/info.action',param,function(rs){
    				console.log(rs);
    				if(rs.success){
    					//先得到当前iframe层的索引
    					var index = parent.layer.getFrameIndex(window.name); 
    					//再执行关闭
    					parent.layer.close(index); 
    					//调用父页面的刷新方法
    					parent.query();
    				}else{
    					layer.msg(rs.msg,{icon:5},function(){});
    				}
    			},'json');
    		});
    	});
    });
    
    function initMeetingUsers(){
    	$.getJSON('${pageContext.request.contextPath }/user.action',{
    		'methodName':'queryUserByMeetingId',
    		'meetingId':'${param.id}'
    	},function(rs){
    		console.log(rs);
    		let data=rs.data;
    		$.each(data,function(i,e){
    			$('#dan_input').val(e.name);
    			addDanMu();
    		});
    	});
    }
    
    
    //添加会议排座
    function addDanMu() {
    	var dan = document.getElementById("dan_input").value;
    	if (dan == "") {
    		alert("请输入弹幕~");
    		return false;
    	} else {
    		document.getElementById("dan_input").value = ""; //清空 弹幕输入框
    		// var br = document.createElement("BR");  // 
    var node = document.createElement("DIV"); //
    var tipsArr = document.getElementsByClassName('tips'); var i; // console.log(parseInt(tipsArr[tipsArr.length-1].id.substr(4))+1); if (tipsArr.length == 0) { i = 1 } else { i = parseInt(tipsArr[tipsArr.length - 1].id.substr(4)) + 1; } // var aNode = document.createElement("P"); //

    node.setAttribute("class", "tips"); node.setAttribute("id", "tips" + i); node.setAttribute("onmouseover", "dragF.drag('tips" + i + "');"); var textnode = document.createTextNode(dan); // 创建个 文本节点, 将用户输入的弹幕,存入 创建的 元素节点

    // aNode.appendChild(textnode); node.appendChild(textnode); // document.body.appendChild(br); // document.body.appendChild(node); document.getElementById("tu").appendChild(node); return true; } } </script> </html>

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201

    展示:
    在这里插入图片描述

    二、送审

    2.1 后台代码

    dao方法

    MeetingInfoDao.java

    //	根据会议ID更新会议的审批人(送审)
    	public int updateAuditorById(MeetingInfo info) throws Exception {
    		String sql="update t_oa_meeting_info set auditor=?,state=2 where id=?";
    		return super.executeUpdate(sql, info, new String[] {"auditor","id"});
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5

    web层

    MeetingInfoAction.java

    //	根据会议ID更新会议的审批人(送审)
    	public String updateAuditorById(HttpServletRequest req, HttpServletResponse resp) {
    		try {
    			int rs = meetingInfoDao.updateAuditorById(info);
    			if (rs > 0) {
    				ResponseUtil.writeJson(resp, R.ok(200, "会议审批成功"));
    			}else {
    				ResponseUtil.writeJson(resp, R.error(0, "会议审批失败"));
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    			try {
    				ResponseUtil.writeJson(resp, R.error(0, "会议审批失败"));
    			} catch (Exception e1) {
    				e1.printStackTrace();
    			}
    		}
    		return null;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    js代码

    let layer,table,$,form;
    let row;
    layui.use(['layer','table','jquery','form'],function(){
    	layer=layui.layer,
    	table=layui.table,
    	form=layui.form,
    	$=layui.jquery;
    	
    	initTable();
    	
    	//查询事件
    	$('#btn_search').click(function(){
    		query();
    	});
    	
    	//初始化审批人
    	initFormSelects();
    	
    	//送审
    	$('#btn_auditor').click(function(){
    		$.post($("#ctx").val()+'/info.action',{
    			'methodName':'updateAuditorById',
    			'id':$('#meetingId').val(),
    			'auditorName':$('#auditorName').val()
    		},function(rs){
    			if(rs.success){
    				//关闭对话框
    				layer.closeAll();
    				//刷新列表
    				query();
    			}else{
    				layer.msg(rs.msg,{icon:5},function(){});
    			}
    		},'json');
    		return false;
    	});
    	
    });
    
    //1.初始化数据表格
    function initTable(){
    	table.render({          //执行渲染
            elem: '#tb',   //指定原始表格元素选择器(推荐id选择器)
            height: 400,         //自定义高度
            loading: false,      //是否显示加载条(默认 true)
            cols: [[             //设置表头
                {field: 'id', title: '会议编号', width: 90},
                {field: 'title', title: '会议标题', width: 120},
                {field: 'location', title: '会议地点', width: 140},
                {field: 'startTime', title: '开始时间', width: 120},
                {field: 'endTime', title: '结束时间', width: 120},
                {field: 'meetingState', title: '会议状态', width: 120},
                {field: 'seatPic', title: '会议排座', width: 120,
                	templet: function(d){
                        if(d.seatPic==null || d.seatPic=="")
                        	return "尚未排座";
                        else
                        	return "";
                    }
                },
                {field: 'auditorName', title: '审批人', width: 120},
                {field: '', title: '操作', width: 200,toolbar:'#tbar'},
            ]]
       });
    }
    
    //2.点击查询
    function query(){
    	table.reload('tb', {
            url: $("#ctx").val()+'/info.action',     //请求地址
            method: 'POST',                    //请求方式,GET或者POST
            loading: true,                     //是否显示加载条(默认 true)
            page: true,                        //是否分页
            where: {                           //设定异步数据接口的额外参数,任意设
            	'methodName':'myInfos',
            	'zhuchiren':$('#zhuchiren').val(),
            	'title':$('#title').val(),
            },  
            request: {                         //自定义分页请求参数名
                pageName: 'page', //页码的参数名称,默认:page
                limitName: 'rows' //每页数据量的参数名,默认:limit
            },
            done: function (res, curr, count) {
            	console.log(res);
            }
       });
    	
    	//工具条事件
    	table.on('tool(tb)', function(obj){ //注:tool 是工具条事件名,test 是 table 原始容器的属性 lay-filter="对应的值"
    	  row = obj.data; //获得当前行数据
    	  var layEvent = obj.event; //获得 lay-event 对应的值(也可以是表头的 event 参数对应的值)
    	  var tr = obj.tr; //获得当前行 tr 的 DOM 对象(如果有的话)
    	  console.log(row);
    	  if(layEvent === 'seat'){ //会议排座
    		  open(row.id);
    	  } else if(layEvent === 'send'){ //送审
    		  if(row.seatPic==null || row.seatPic==""){
    			  layer.msg('先请完成会议排座,再进行送审操作!',function(){});
    			  return false;
    		  }
    		  //在打开送审页面之前,先请完成会议ID的赋值操作
    		  $('#meetingId').val(row.id);
    		  openLayerAudit();
    	  } else if(layEvent==="back"){ //反馈详情
    		 
    	  } else {//删除
    		  layer.confirm('确认要取消会议吗?', {icon: 3, title:'提示'}, function(index){
    				$.post($("#ctx").val()+'/info.action',{
    					'methodName':'updatezt',
    					'state':0,
    					'id':row.id
    				},function(rs){
    					if(rs.success){
    						//调用查询方法刷新数据
    						query();
    					}else{
    						layer.msg(rs.msg,function(){});
    					}
    				},'json');
    				layer.close(index);
    			});
    	  }
    	});
    }
    
    //打开会议排座对话框
    function open(id){
    	layer.open({
            type: 2,                    //layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)
            title: '会议排座',                   //对话框标题
            area: ['460px', '340px'],   //宽高
            skin: 'layui-layer-rim',    //样式类名
            content: $("#ctx").val()+'/jsp/meeting/seatPic.jsp?id='+id,                //弹出内容。可以传入普通的html内容,还可以指定DOM,更可以随着type的不同而不同
        });
    }
    
    //会议送审
    function openLayerAudit(){
    	//每次打开都对送审人进行初始化默认值设置
    	$('#auditor').val("");
    	//必须重新渲染
    	form.render('select');
    	//弹出对话框
        layer.open({
            type: 1,                    //layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)
            title:'会议送审',
            area: ['426px', '140px'],   //宽高
            skin: 'layui-layer-rim',    //样式类名
            content: $('#audit'),   //弹出内容。可以传入普通的html内容,还可以指定DOM,更可以随着type的不同而不同
        });
    }
    
    //初始化审批人
    function initFormSelects(){
    	$.getJSON($("#ctx").val()+'/user.action',{
    		'methodName':'queryUserAll'
    	},function(rs){
    		console.log(rs);
    		let data=rs.data;
    		$.each(data,function(i,e){
    			$('#auditor').append(new Option(e.name,e.value));
    		});
    		//重新渲染
    		form.render('select');
    	});
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167

    展示:
    在这里插入图片描述

  • 相关阅读:
    Electron常见问题 62 - Electron配置私有化sentry的方法
    vue实现上传文件到七牛云
    改变光标形状的多种方式
    [足式机器人]Part3机构运动微分几何学分析与综合Ch02-2 平面机构离散运动鞍点综合——【读书笔记】
    【Vue】Vue2知识点总结
    《动机与人格》笔记(一)——人类似乎从来就没有长久地感到过心满意足
    招投标系统简介 企业电子招投标采购系统源码之电子招投标系统 —降低企业采购成本
    Flink CDC引起的Mysql元数据锁
    Spring拓展知识:后置处理器与事件监听器
    行为型设计模式——责任链模式
  • 原文地址:https://blog.csdn.net/m0_62528678/article/details/125990223