当前位置:网站首页>My meeting of OA project (meeting seating & submission for approval)
My meeting of OA project (meeting seating & submission for approval)
2022-07-26 16:58:00 【Drunken cat (^ ェェ^)】
Catalog
One 、 Introduction to conference seating plug-in
Two 、 Meeting participant user data initialization
3、 ... and 、 Generation and display of meeting seating pictures
Four 、 Meeting submission for approval
One 、 Introduction to conference seating plug-in
First, meeting seating function significance :

After clarifying the significance of development meeting seating ,
1) We need to think about how to complete this function ?
1. Find out all participants in this meeting
2. You need to complete the drag function of elements on the page , Put the corresponding participants in the designated position , Such as : Important people are in the main place
3. Draw the already drawn seat map of the meeting , preserved , And bind it to the data of this meeting ;
Small make up j The implementation order of this code will be 2--->1--->3
2) Drag function of elements on the page ( Special features )
starting point : You can write it yourself 、 There will be material online
technological process : First find online materials , Change the source code in the material , Become what you want

1. Find online materials , Find more , Pick out the most suitable
Like this :

2. Analyze the shortcomings of existing materials
add to aaa Then add bbb、ccc:


① Found element overlap , It is impossible to determine how many people will participate
② The element block is too small to see clearly
3. Modify the deficiencies of existing materials
Adjust the style :

4. Analyze existing materials , How to relate to business requirements ( The most important step )
What we need to do is , View the source code , Analyze the reasons for the image generation / step
download The button is bound with a method , The main method is downloadFile Method
downloadFile Method has two parameters :FileName、content, The next step is to think about which parameter is related to the picture
Conclusion : Through analysis downloadFile In the method content The parameter represents the picture - front end
5.content It needs to be delivered to the background , And generate pictures , That's the only way , We can decide where to store pictures through code
①、 How to send it backstage -$.post
$.get( No good , Because the parameter is too large ) wrong
②、String content String to be converted into picture
Two 、 Meeting participant user data initialization
myMeeting.js:
let layer,$,table;
var row;
layui.use(['jquery', 'layer', 'table'], function(){
layer = layui.layer
,$ = layui.jquery
,table = layui.table;
// Initialize the data table
initTable();
// Bind the click event of the query button
$('#btn_search').click(function(){
query();
});
});
//1. Initialize the data table
function initTable(){
table.render({ // Perform rendering
elem: '#tb', // Specify the original table element selector ( recommend id Selectors )
// url: 'user.action?methodName=list', // Request address
height:500, // Custom height
loading: false, // Whether to load the bar ( Default true)
cols: [[ // Set the header
{field: 'id', title: ' Conference number ', width: 120},
{field: 'title', title: ' The title of the meeting ', width: 120},
{field: 'location', title: ' Place of meeting ', width: 140},
{field: 'startTime', title: ' Starting time ', width: 120},
{field: 'endTime', title: ' End time ', width: 120},
{field: 'meetingstate', title: ' Meeting status ', width: 140},
{field: 'seatPic', title: ' Meeting row ', width: 120,templet: function(d){
console.log(d.LAY_INDEX); // Get the serial number . It's not commonly used
console.log(d.LAY_COL); // Get the current list header configuration information (layui 2.6.8 newly added ). It's not commonly used
if(d.seatPic==null||d.seatPic=="")
return " Not yet seated ";
else // Get the current row data , And spliced into a custom template
return "<img width='120px' src='"+d.seatPic+"'}/>";
}
},
{field: 'name', title: ' Approved by ', width: 120},
{field: 'auditor', title: ' operation ', width: 220,toolbar:'#tbar'},
]]
});
// In the page <table> Must be configured in lay-filter="tb_goods" Attribute can trigger attribute !!!
table.on('tool(tb)', function (obj) {
row = obj.data;
if (obj.event == 'seat') {
open(row.id);
}else if(obj.event == "send"){
layer.msg(" submit for censorship ");
}
else if(obj.event == "del"){
layer.confirm(' Are you sure to delete ?', {icon: 3, title:' Tips '}, function(index){
$.post($("#ctx").val()+'/user.action',{
'methodName':'del',
'id':row.id
},function(rs){
if(rs.success){
// Call the query method to refresh the data
query();
}else{
layer.msg(rs.msg,function(){});
}
},'json');
layer.close(index);
});
layer.msg(" Cancel the meeting ");
}
else if(obj.event == "back"){
layer.msg(" Feedback details ");
}else{
}
});
}
//2. Click to query
function query(){
table.reload('tb', {
url: 'info.action', // Request address
method: 'POST', // Request mode ,GET perhaps POST
loading: true, // Whether to load the bar ( Default true)
page: true, // Pagination or not
where: { // Set additional parameters for asynchronous data interface , Arbitrarily set
'methodName':'myInfos',
'title':$('#title').val(),
'zhuchiren':$("#zhuchiren").val()
},
request: { // Custom paging request parameter name
pageName: 'page', // Parameter name of page number , Default :page
limitName: 'rows' // Parameter name of data volume per page , Default :limit
}
});
}
// Open the meeting seating dialog box
function open(id){
layer.open({
type: 2, //layer Provides 5 Layer type . The values that can be passed in are :0( Message box , Default )1( Page layer )2(iframe layer )3( Loading layer )4(tips layer )
title: ' Meeting row ', // Dialog title
area: ['460px', '340px'], // Wide and high
skin: 'layui-layer-rim', // Style class name
content: $("#ctx").val()+'/jsp/meeting/seatPic.jsp?id='+id, // Pop up content . You can pass in ordinary html Content , You can also specify DOM, With more type Different but different
});
}Click meeting seating ,
Run the following :( Completed the drag function of elements on the page , Put the corresponding participants in the designated position )
UserDao:
public List<User> list(Integer 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);
}UserAction:
// Query the user id
public String queryUserByMeetingId(HttpServletRequest req, HttpServletResponse resp) {
try {
String meetingId = req.getParameter("meetingId");
List<User> users = userDao.list(Integer.valueOf(meetingId));
// Be careful :layui Format of data table in
ResponseUtil.writeJson(resp, R.ok(0, " Conference user data initialization succeeded ",users));
} catch (Exception e) {
e.printStackTrace();
try {
ResponseUtil.writeJson(resp, R.error(0, " Conference user data initialization failed "));
} catch (Exception e2) {
e2.printStackTrace();
}
}
return null;
}
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> Meeting seating </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>
<!-- Don't use layui Form inline mode , It can lead to canvas Of toDataURL() The data is 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"> Add seats </button><input id="jie_input" type="button" class="layui-btn layui-btn-sm" value=' download '>
</div>
</div>
</body>
<script type="text/javascript">
var $id = function(id) {
return document.getElementById(id);
}
// Drag and drop in the meeting row
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();
} /* Block annotation <a href='/site/js-5791-1.html' target='_blank'><u> browser </u></a> Drag down a,img Default event for */
dragF.locked = true;
$id(obj).style.position = "absolute";
$id(obj).style.zIndex = "100";
if (dragF.lastObj && dragF.lastObj != $id(obj)) { /* Multi element dragging needs to restore the last element state */
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;
} /* prevent ie Next a,img Default event for */
}
document.onmouseup = function() {
dragF.locked = false;
}
}
}
}
</script>
<script type="text/javascript">
var layer;
layui.use(['layer'],function(){
layer=layui.layer;
// Initialize meeting seating : According to the meeting ID Get the names of all participants ( host + Participants + People in attendance )
initMeetingUsers();
// Draw pictures of meeting seating
$("#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);
// Here you need to upload the pictures of meeting seating
$.post('${pageContext.request.contextPath }/info.action',param,function(rs){
if(rs.success){
// Get the current status first iframe Layer index
var index = parent.layer.getFrameIndex(window.name);
// And then close it
parent.layer.close(index);
// Call the refresh method of the parent page
parent.query();
}else{
layer.msg(rs.msg,{icon:5},function(){});
}
},'json');
});
});
});
function initMeetingUsers(){
//http://localhost:8080/xxx/seatPic.jsp?id=12 -> ${param.id}
$.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();
});
});
}
// Add meeting seating
function addDanMu() {
var dan = document.getElementById("dan_input").value;
if (dan == "") {
alert(" Please enter barrage ~");
return false;
} else {
document.getElementById("dan_input").value = ""; // Empty Bullet screen input box
// var br = document.createElement("BR"); // <br />
var node = document.createElement("DIV"); // <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"); // <p>
node.setAttribute("class", "tips");
node.setAttribute("id", "tips" + i);
node.setAttribute("onmouseover", "dragF.drag('tips" + i + "');");
var textnode = document.createTextNode(dan); // Create a Text node , A barrage of user input , Deposit in Created Element nodes <p> in
// aNode.appendChild(textnode);
node.appendChild(textnode);
// document.body.appendChild(br);
// document.body.appendChild(node);
document.getElementById("tu").appendChild(node);
return true;
}
}
</script>
</html>
Running effect :

3、 ... and 、 Generation and display of meeting seating pictures
resource.properties:
dirPath=E:/temp/images/T280/
serverPath=/upload/paizuo/
dirPathSign=E:/temp/images/T280/sign/
serverPathSign=/upload/sign/MeetingInfoDao:
/ Set the picture of meeting seating
public int updateSeatPicById(MeetingInfo info) throws Exception {
String sql="update t_oa_meeting_info set seatPic=? where id=?";
return super.executeUpdate(sql, info, new String[] {"seatPic","id"});
}
MeetingInfoAction:
public String updateSeatPicById(HttpServletRequest req, HttpServletResponse resp) {
/**
* 1、 Receive the string corresponding to the picture passed from the front-end page to the background
* 2、 With the help of tool classes, the string is generated into an image , Save to the path configured by the configuration file
* 3、 Add server hard disk and request address Mapping , Can access
* 4、 The requested address Save to the database
*/
// Get the storage address of the picture
try {
String dirPath = PropertiesUtil.getValue("dirPath");
// Get the browser request path , For subsequent saving to the database
String serverPath = PropertiesUtil.getValue("serverPath");
// Randomly generate a picture name
String fileName = UUID.randomUUID().toString().replace("-", "")+".png";
//info.getSeatPic();// Picture string
Base64ImageUtils.GenerateImage(info.getSeatPic().replaceAll("data:image/png;base64", ""), dirPath+fileName);
// take seatPic The content in is modified as Request address
info.setSeatPic(serverPath+fileName);
// Modify the meeting seating Database image Corresponding database column segment
int rs = infoDao.updateSeatPicById(info);
if(rs>0) {
ResponseUtil.writeJson(resp, R.ok(200, " The meeting was successfully booked "));
}else {
ResponseUtil.writeJson(resp, R.error(0, " Meeting seating failed "));
}
} catch (Exception e) {
e.printStackTrace();
try {
ResponseUtil.writeJson(resp, R.error(0, " Meeting seating failed "));
} catch (Exception e2) {
e2.printStackTrace();
}
}
return null;
}
Four 、 Meeting submission for approval
When we click send for approval , A box should pop up , Then select the approver , So we go to the official website to find :

js Key code :
// In the page <table> Must be configured in lay-filter="tb_goods" Attribute can trigger attribute !!!
table.on('tool(tb)', function (obj) {
row = obj.data;
if (obj.event == 'seat') {
open(row.id);
}else if(obj.event == "send"){
// layer.msg(" submit for censorship ");
// Judge whether the seats have been arranged
if(row.seatPic==null || row.seatPic==""){
layer.msg(' Please complete the meeting seating first , Then submit for approval !',function(){});
return false;
}
// Initialize approver
initFormSelects();
/** The meeting submitter in the pop-up layer must be queried The backstage has been completed , Completed in the multi-function drop-down box */
// Before opening the submission page , Please finish the meeting first ID Assignment of
$('#meetingId').val(row.id);
// Open the meeting for approval HTML Page layer
openLayerAudit();
}
// Initialize approver
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));
});
// To render
form.render('select');
});
}
// Meeting submission for approval
function openLayerAudit(){
// Each time you open it, you will initialize the submitter and set the default value
$('#auditor').val("");
// You have to re render
form.render('select');
// Pop-up dialog box
layer.open({
type: 1, //layer Provides 5 Layer type . The values that can be passed in are :0( Message box , Default )1( Page layer )2(iframe layer )3( Loading layer )4(tips layer )
title:' Meeting submission for approval ',
area: ['426px', '140px'], // Wide and high
skin: 'layui-layer-rim', // Style class name
content: $('#audit'), // Pop up content . You can pass in ordinary html Content , You can also specify DOM, With more type Different but different
});
} Running effect : 
Next , Click send for approval , To get meeting id as well as Submitter :
MeetingInfoDao:
// Meeting submission for approval
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"});
}
MeetingInfoAction:
// Meeting submission for approval
public String updateAuditorById(HttpServletRequest req, HttpServletResponse resp) {
try {
// rs yes sql Number of lines affected by statement execution
int rs = infoDao.updateAuditorById(info);
if(rs>0) {
ResponseUtil.writeJson(resp, R.ok(200, " The meeting was successfully submitted for approval "));
}else {
ResponseUtil.writeJson(resp, R.error(0, " The meeting failed to submit for approval "));
}
} catch (Exception e) {
e.printStackTrace();
try {
ResponseUtil.writeJson(resp, R.error(0, " The meeting failed to submit for approval "));
} catch (Exception e2) {
e2.printStackTrace();
}
}
return null;
}myMeeting.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();
// Query events
$('#btn_search').click(function(){
query();
});
// Initialize approver
initFormSelects();
// submit for censorship
$('#btn_auditor').click(function(){
$.post($("#ctx").val()+'/info.action',{
'methodName':'updateAuditorById',
'id':$('#meetingId').val(),
'auditor':$('#auditor').val()
},function(rs){
if(rs.success){
// close dialog boxes
layer.closeAll();
// Refresh List
query();
}else{
layer.msg(rs.msg,{icon:5},function(){});
}
},'json');
return false;
});
});
//1. Initialize the data table
function initTable(){
table.render({ // Perform rendering
elem: '#tb', // Specify the original table element selector ( recommend id Selectors )
height: 400, // Custom height
loading: false, // Whether to load the bar ( Default true)
cols: [[ // Set the header
{field: 'id', title: ' Conference number ', width: 90},
{field: 'title', title: ' The title of the meeting ', width: 120},
{field: 'location', title: ' Place of meeting ', width: 140},
{field: 'startTime', title: ' Starting time ', width: 120},
{field: 'endTime', title: ' End time ', width: 120},
{field: 'meetingState', title: ' Meeting status ', width: 120},
{field: 'seatPic', title: ' Meeting row ', width: 120,
templet: function(d){
if(d.seatPic==null || d.seatPic=="")
return " Not yet seated ";
else
return "<img width='120px' src='"+d.seatPic+"'/>";
}
},
{field: 'auditName', title: ' Approved by ', width: 120},
{field: '', title: ' operation ', width: 200,toolbar:'#tbar'},
]]
});
}
//2. Click to query
function query(){
table.reload('tb', {
url: $("#ctx").val()+'/info.action', // Request address
method: 'POST', // Request mode ,GET perhaps POST
loading: true, // Whether to load the bar ( Default true)
page: true, // Pagination or not
where: { // Set additional parameters for asynchronous data interface , Arbitrarily set
'methodName':'myInfos',
'zhuchiren':$('#zhuchiren').val(),
'title':$('#title').val(),
},
request: { // Custom paging request parameter name
pageName: 'page', // Parameter name of page number , Default :page
limitName: 'rows' // Parameter name of data volume per page , Default :limit
},
done: function (res, curr, count) {
console.log(res);
}
});
// Toolbar events
table.on('tool(tb)', function(obj){ // notes :tool Is the toolbar event name ,test yes table Properties of the original container lay-filter=" Corresponding value "
row = obj.data; // Get current row data
var layEvent = obj.event; // get lay-event Corresponding value ( It can also be in the header event The corresponding value of the parameter )
var tr = obj.tr; // Get the current line tr Of DOM object ( If any )
console.log(row);
if(layEvent === 'seat'){ // Meeting row
open(row.id);
} else if(layEvent === 'send'){ // submit for censorship
if(row.seatPic==null || row.seatPic==""){
layer.msg(' Please complete the meeting seating first , Then submit for approval !',function(){});
return false;
}
// Before opening the submission page , Please finish the meeting first ID Assignment of
$('#meetingId').val(row.id);
openLayerAudit();
} else if(layEvent==="back"){ // Feedback details
openLayerFeedBack(row.id);
} else {
}
});
}
// Open the meeting seating dialog box
function open(id){
layer.open({
type: 2, //layer Provides 5 Layer type . The values that can be passed in are :0( Message box , Default )1( Page layer )2(iframe layer )3( Loading layer )4(tips layer )
title: ' Meeting row ', // Dialog title
area: ['460px', '340px'], // Wide and high
skin: 'layui-layer-rim', // Style class name
content: $("#ctx").val()+'/jsp/meeting/seatPic.jsp?id='+id, // Pop up content . You can pass in ordinary html Content , You can also specify DOM, With more type Different but different
});
}
// Meeting submission for approval
function openLayerAudit(){
// Each time you open it, you will initialize the submitter and set the default value
$('#auditor').val("");
// You have to re render
form.render('select');
// Pop-up dialog box
layer.open({
type: 1, //layer Provides 5 Layer type . The values that can be passed in are :0( Message box , Default )1( Page layer )2(iframe layer )3( Loading layer )4(tips layer )
title:' Meeting submission for approval ',
area: ['426px', '140px'], // Wide and high
skin: 'layui-layer-rim', // Style class name
content: $('#audit'), // Pop up content . You can pass in ordinary html Content , You can also specify DOM, With more type Different but different
});
}
// Initialize approver
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));
});
// To render
form.render('select');
});
}
// Open to view the feedback details of this meeting
function openLayerFeedBack(id){
$.getJSON('feedBack.action',{
methodName:'queryMeetingBackByMeetingId',
meetingId:id
},function(data){
$('#meeting_ok').html("");
$('#meeting_no').html("");
$('#meeting_noread').html("");
if(data.success){
console.log(data.data);
$.each(data.data,function(i,e){
if(e.result==1)
$('#meeting_ok').html(e.names);
else if(e.result==2)
$('#meeting_no').html(e.names);
else
$('#meeting_noread').html(e.names);
});
// Pop-up dialog box
layer.open({
type: 1, //layer Provides 5 Layer type . The values that can be passed in are :0( Message box , Default )1( Page layer )2(iframe layer )3( Loading layer )4(tips layer )
title:' Feedback details ',
area: ['426px', '420px'], // Wide and high
skin: 'layui-layer-rim', // Style class name
content: $('#feedback'), // Pop up content . You can pass in ordinary html Content , You can also specify DOM, With more type Different but different
btn:[' close '],
yes:function(index,layero){
layer.closeAll();
}
});
}
});
}
After clicking download :
Will be automatically saved in my local E tray :

also It is also displayed on the front page :

That's all for today , farewell ~
边栏推荐
- Acl-ijcai-sigir top conference paper report meeting (AIS 2022) Note 3: dialogue and generation
- Detailed explanation of tcpdump command
- Nacos win10 installation and configuration tutorial
- Packet capturing and streaming software and network diagnosis
- Vlang's way of beating drums
- How to write unit tests
- 导数、微分、偏导数、全微分、方向导数、梯度的定义与关系
- Configmap of kubernetes
- 广东首例!广州一公司未履行数据安全保护义务被警方处罚
- PyQt5快速开发与实战 3.4 信号与槽关联
猜你喜欢
![[Development Tutorial 9] crazy shell arm function mobile phone-i2c tutorial](/img/9d/2a1deca934e6d56d729922b1d9e515.png)
[Development Tutorial 9] crazy shell arm function mobile phone-i2c tutorial
![[express receives get, post, and route request parameters]](/img/6c/ac936a8dff50b803993bef5192723b.png)
[express receives get, post, and route request parameters]

Win11 how to close a shared folder

微信小程序---网络数据请求

Difference between C event and delegation

PXE efficient batch network installation

【飞控开发基础教程3】疯壳·开源编队无人机-串口(基础收发)

Alibaba cloud Toolkit - project one click deployment tool

操作系统迁移实战之在openEuler上部署MySQL数据库

Guetzli simple to use
随机推荐
Recurrence of historical loopholes in ThinkPHP
Guetzli simple to use
VS2017打开项目提示需要迁移的解决方法
Marxan model, reserve optimization and protection vacancy selection technology, application in invest ecosystem
About the idea plug-in I wrote that can generate service and mapper with one click (with source code)
Thinkphp历史漏洞复现
IDEA 阿里云多模块部署
Matlab论文插图绘制模板第40期—带偏移扇区的饼图
广东首例!广州一公司未履行数据安全保护义务被警方处罚
公安部发出暑期旅游客运交通安全预警:手握方向盘 绷紧安全弦
[basic course of flight control development 2] crazy shell · open source formation UAV - timer (LED flight information light and indicator light flash)
Movable view component (it can be dragged up, down, left and right)
Tao and art of R & D Efficiency - Tao chapter
Response object - response character data
利用MySQL主从复制延迟拯救误删数据
[e-mr] error recovery record of namenode
JS API summary of Array Operations
Final consistency distributed transaction TCC
公共数据如何兼顾开放利用和隐私安全合规?
Probe of kubernetes