如何实现会议室预约?
场景描述
使用轻流系统实现会议室预约场景,满足会议室被占用期间不可被预约,以及取消后需要将该会议室该时段需要被释放出来。
预约会议室实现要求
1、会议室被占用期间不可被预约
2、取消后需要将该会议室该时段需要被释放出来
3、会议室预约时间至少30分钟起步(可修改)
4、会议室预约时间不可预约之前时间
5、会议室预约时间需要以5分钟为精度(可修改)
思路逻辑
具体使用代码块来完成遇上预约会议室要求。其中需要调用OpenApi获取自身应用数据的会议室以及预约会议室起止时间,然后拿发起新数据的会议室以及预约会议室起止时间来跟自身应用的数据进行对比。
如果当前会议室的预约时间跟自身应用数据的历史会议时间有冲突就会无法提交预约
注意:因为是跟自身应用做比较的,所以可能会存在并发的情况。所以请避免同时发起预约同一时段。
后续代码块节点功能上线可解决。
配置过程


其中,【校验时段是否被占用】、【显示该会议室预约情况】、【校验时段时分能被5整除】、【今天会议室预约情况】为代码块
表单字段的设计
预约会议起止时间,格式为年月日时分

预约开始日期(校验)
含义:获取预约会议起止时间字段的开始日期,格式为年月日时分时分秒
公式:LEFT(预约会议起止时间,16)


预约结束日期(校验)
含义:获取预约会议起止时间字段的结束日期,格式为年月日时分
公式:RIGHT(预约会议起止时间,16)


预约开始日期(筛选)
含义:获取预约会议起止时间字段的开始日期,格式年月日
公式:LEFT(预约会议起止时间,10)


预约结束日期(筛选)
含义:获取预约会议起止时间字段的结束日期,格式年月日时分秒
公式:MID(预约会议起止时间,18,10)

预约人
预约人设置为当前用户,然后字段可以设置为仅可见

校验时段是否被占用

代码注释
- 代码中,【会议室】以及【预约会议起止时间】表示会议室预约表单中的对应的字段名称

2、URL为获取应用数据接口,文档参考:https://help.qingflow.com/help-docs?type=qingCode&docId=fc8e64656428ea3a06fe9b406b9b7be9&parentId=
queid为【会议室预约】应用的会议室以及预约起止时间的字段ID
queid的获取方式:https://exiao.yuque.com/rlf3k1/oanb79/ub34vw3b7cdqvovg?singleDoc# 《调用添加数据接口,如何写body内容》

3、 qf_field.{预约会议起止时间$$178A98D01$$}以及qf_field.{会议室$$178A8997A$$}:替换成表单对应的字段
完整代码
const axios = require('axios');
function isOverlap(date, startTime, endTime) {
const [start, end] = date.split('~');
if (startTime <= start && start <= endTime) {
return true;
}
if (startTime <= end && end <= endTime) {
return true;
}
if (start <= startTime && endTime <= end) {
return true;
}
return false;
}
function checkAvailability(date, room, reslist) {
const filteredResList = reslist.filter(item => item['会议室'] === room);
for (const item of filteredResList) {
const [reservationStart, reservationEnd] = item['预约会议起止时间'].split('~');
const overlap = isOverlap(date, reservationStart, reservationEnd);
if (overlap) {
return false; // 时间区间已被覆盖
}
}
return true; // 时间区间可用
}
// 调用接口获取reslist
async function fetchData() {
const data = JSON.stringify({
"pageSize": "50",
"pageNum": "1"
});
const config = {
method: 'post',
url: 'https://api.qingflow.com/app/16365e01/apply/filter',
headers: {
'accessToken': 'd866db1d-79ca-42c5-9e9c-0b1ce21135d2',
'Content-Type': 'application/json'
},
data: data
};
const res = await axios(config);
const msg = res.data;
const result = msg.result.result;
const reslist = result.map(value => {
const res_msg = {};
value.answers.forEach(v => {
const queId = v.queId;
const queTitle = v.queTitle;
if (queId === 166744302 || queId === 166753788) {
const values = v.values;
const dataValue = values[0].dataValue;
res_msg[queTitle] = dataValue;
}
});
return res_msg;
});
const date = qf_field.{预约会议起止时间$$178A98D01$$}; // 添加一个判断条件,若为null,则isAvailable为true
const room = qf_field.{会议室$$178A8997A$$};
const isAvailable = (date === null) ? true : await checkAvailability(date, room, reslist);
qf_output={isAvailable}
//console.log(isAvailable);
}
fetchData();
代码测试

解析规则配置

字段接收配置

预约时间是否没有被占用
该字段需要配置逻辑表单
作用:当预约时段被占用的话,就显示对应字段,展示具体对应会议室当前日期的占用情况

显示该会议室预约情况

代码注释
1、qf_field.{会议室$$178A8997A$$}、qf_field.{预约开始日期(筛选)$$1793BA08D$$}、qf_field.{预约结束日期(筛选)$$1793BA08E$$}对应【会议室】应用表单的对应字段
2、这里的queid对应分别是会议室字段的queid,以及预约开始日期(筛选)的queid

完整代码
const axios = require('axios');
let key = qf_field.{会议室$$178A8997A$$}; // 定义变量 'key' 并将其设置为 null
// 检查 key 是否为 null。如果为 true,则输出一个空数组到控制台
if (key === null) {
//return [];
const reslist=[];
qf_output={reslist}
} else {
let data = JSON.stringify({
"pageSize": "50",
"pageNum": "1",
"queries": [
{
"queId": 166744302,
"searchKey": key // 使用变量 'key' 的值作为 "searchKey"
},
{
"queType": 14,
"scope": 1,
"queId":167075915,
"minValue":qf_field.{预约开始日期(筛选)$$1793BA08D$$},
"maxValue":qf_field.{预约结束日期(筛选)$$1793BA08E$$}
}
]
});
let config = {
method: 'post',
url: 'https://api.qingflow.com/app/16365e01/apply/filter',
headers: {
'accessToken': 'd866db1d-79ca-42c5-9e9c-0b1ce21135d2',
'Content-Type': 'application/json'
},
data: data
};
axios(config)
.then(function (res) {
const msg = res.data;
const result = msg.result.result;
const reslist = [];
result.forEach(value => {
const res_msg = {};
value.answers.forEach(v => {
const queId = v.queId;
const queTitle = v.queTitle;
if (queId === 166744302 || queId === 166753788) {
const values = v.values;
const dataValue = values[0].dataValue;
res_msg[queTitle] = dataValue;
}
});
reslist.push(res_msg);
});
reslist.sort((a, b) => {
const timeA = new Date(a['预约会议起止时间'].split('~')[0]);
const timeB = new Date(b['预约会议起止时间'].split('~')[0]);
return timeA - timeB;
});
qf_output={reslist}
//console.log(reslist);
});
}
代码测试

解析规则配置

字段接收配置

校验时段时分能被5整除
代码注释
qf_field.{预约会议起止时间$$178A98D01$$}:表单中预约会议起止时间字段
完整代码
function validateTime(time) {
// 分割起止时间
const [startTime, endTime] = time.split("~");
// 提取起始时间的时分部分
const [startHour, startMinute] = startTime.split(" ")[1].split(":");
// 提取结束时间的时分部分
const [endHour, endMinute] = endTime.split(" ")[1].split(":");
// 将时分转换为分钟
const startTotalMinutes = parseInt(startHour) * 60 + parseInt(startMinute);
const endTotalMinutes = parseInt(endHour) * 60 + parseInt(endMinute);
// 校验条件:时分换算成分之后,除以5能被整除,时分为00:00的话除外
if (startTotalMinutes === 0 && endTotalMinutes === 0) {
return true; // 时分为00:00,通过校验
} else {
return (startTotalMinutes % 5 === 0) && (endTotalMinutes % 5 === 0);
}
}
// 测试校验函数
const date = qf_field.{预约会议起止时间$$178A98D01$$};
const isValid = (date === null) ? true: validateTime(date);
qf_output={isValid}
//console.log(isValid); // 输出 true 或者 false
代码测试

解析规则配置

字段接收配置

今天会议室预约情况

代码注释
请参考【9】显示该会议室预约情况代码块注释
完整代码
const axios = require('axios');
// 导入`date-fns`模块中与日期相关的函数
const { format, toDate } = require('date-fns');
// 获取当前日期
const currentDate = new Date();
// 格式化并输出当前日期
const formattedDate = format(currentDate, 'yyyy-MM-dd');
let key = qf_field.{会议室$$178A8997A$$}; // 定义变量 'key' 并将其设置为 null
// 检查 key 是否为 null。如果为 true,则输出一个空数组到控制台
if (key === null) {
//return [];
const reslist=[];
qf_output={reslist}
} else {
let data = JSON.stringify({
"pageSize": "50",
"pageNum": "1",
"queries": [
{
"queId": 166744302,
"searchKey": key // 使用变量 'key' 的值作为 "searchKey"
},
{
"queType": 14,
"scope": 1,
"queId":167075915,
"minValue":formattedDate,
"maxValue":formattedDate
}
]
});
let config = {
method: 'post',
url: 'https://api.qingflow.com/app/16365e01/apply/filter',
headers: {
'accessToken': 'd866db1d-79ca-42c5-9e9c-0b1ce21135d2',
'Content-Type': 'application/json'
},
data: data
};
axios(config)
.then(function (res) {
const msg = res.data;
const result = msg.result.result;
const reslist = [];
result.forEach(value => {
const res_msg = {};
value.answers.forEach(v => {
const queId = v.queId;
const queTitle = v.queTitle;
if (queId === 166744302 || queId === 166753788) {
const values = v.values;
const dataValue = values[0].dataValue;
res_msg[queTitle] = dataValue;
}
});
reslist.push(res_msg);
});
reslist.sort((a, b) => {
const timeA = new Date(a['预约会议起止时间'].split('~')[0]);
const timeB = new Date(b['预约会议起止时间'].split('~')[0]);
return timeA - timeB;
});
qf_output={reslist}
//console.log(reslist);
});
}
代码测试

解析规则配置

字段接收配置

数据提交校验设置

校验1
作用:需要预约开始时间大于当前时间
公式:(DATETOTIMESTAMP(预约开始日期(校验)-DATETOTIMESTAMP(DATE(YEAR(NOW()),MONTH(NOW()),DAY(NOW()),HOUR(NOW()),MINUTE(NOW()))))>=0

校验2
作用:预约时长至少30分钟起步,如果有需要可以做相应的修改
公式:((DATETOTIMESTAMP(预约结束日期(校验)-DATETOTIMESTAMP(预约开始日期(校验)))/60000)>=30

校验3
作用:该时段已被预约,请重新选择时段
公式:预约时间是否没有被占用=="true"

校验4
作用:预约时段分钟需要以5分钟为精度
公式:预约时段时分是否能被5整除=="true"

门户创建
作用:方便个人通过门户查询当日的预约会议室的情况
1、会议室预约应用中创建对应数据表

2、数据范围设置为:当前用户发起的数据

3、门户设置

4、门户筛选组配置

取消会议室预约
作用:如果预约后会议之后,需要取消预约的会议室
实现逻辑:在门户中点击对应的那条数据,然后点击取消预约按钮,然后进行取消
表单设计
对应字段设置为仅可见


注意点:预约起止时间需要格式设置为年月日时分秒

webhook配置
接口文档(删除应用数据):https://help.qingflow.com/help-docs?type=qingCode&docId=2cc84e266428e9c7070e75f351e7eeba&parentId=
配置
一些参数获取位置:https://help.qingflow.com/help-docs?type=qingCode&docId=7cd57ede6425a9c9001147b15f1940a7&parentId=
appkey:应用的唯一标识,获取方式

accesstoken:轻商城——拓展插件——openAPI



curl --location --request DELETE 'https://api.qingflow.com/app/16365e01/apply' \
--header 'accessToken: d866db1d-79ca-42c5-9e9c-0b1ce211**2' \
--header 'Content-Type: application/json' \
--header 'Cookie: JSESSIONID=4CB16898060AD091BBEDC26821599F59' \
--data '{
"queries": [
{
"queId": 167092295,
"searchKey": "1111"
},
{
"queId": 166744302,
"searchKey": "地球"
},
{
"queId": 166753788,
"searchKey": "2023-09-15 16:06:00~2023-09-16 18:10:00"
}
]
}'
3、自定义按钮配置
会议室预约——拓展设置



对应报表中添加自定义按钮
在会议室预约-个人会议室预约详情报表中选择自定义按钮进行配置

实现效果



