在日常的工作和生活中,我们常常需要预定会议室或者某个场所进行某个活动,例如:在公司里,需要预定某个时间段的会议室,还有在学校里,我们需要预定羽毛球馆、篮球馆、等等活动,像这种资源预定的场景比比皆是,那我们怎么能简单的实现资源预定呢?答案是通过zOffice在线表格
zOffice简介
zOffice提供云端Office能力,包括word、excel、ppt三类办公文档的在线协同编辑,通过专业级的文档能力,高效的协作体验,内容级的安全管控,丰富的集成开发接口,来赋能企业的业务系统,帮助业务系统实现文档在线预览和编辑,文档操作过程全部线上进行,完成在线办公的场景闭环。
zOffice链接:https://www.filez.com/zoffice
集成介绍文档:http:// https://lenovocloud.zbox.filez.com/l/a0OsO0
实现方案
1、方式一:通过zOffice多人协同在线编辑实现资源预定
业务系统可以与zOffice集成,具体如何集成参考:
https://hello.word.com/(替换成集成链接)
比如会议室预定,我们建一个这样的在线表格,只要想订会议室的人都可以进这个表格,也许你会认为别人会篡改你的内容,但是zOffice在线编辑有单元格历史记录,还有协作记录,如果你的内容被改了,很快就能找到是谁,非常的安全好用。
2、方式二:通过zOffice SDK实现
通过zOffice SDK实现资源预定,zOffice SDK拥有非常丰富的接口,可以通过监听预定的区域,当有人输入内容时,校验是否有冲突,冲突的结果可以用颜色标记。
步骤一:挂载一个会议室模板文件,定义一个app变量,添加监听
app.addListener('Workbook.Event.Change', callback);
当你输入内容,callback函数就会执行。
步骤二:获取会议室模板文件的会议室,预定日期
const roomsheet = await app.ActiveWorkbook.getSheetByName('会议室预定');
const meetingRoomNum: number[] = [702, 708, 709, 710];
const listendRange = roomsheet.getRange(1, 1, 30, 25);
const firstCol = roomsheet.getRange(1, 1, 30, 1); // 第一列存储了会议室
const firstRow = roomsheet.getRange(1, 1, 1, 25); // 第一行存储了预定日期
步骤三:判断输入的预定时间是否冲突,1代表冲突,0代表不冲突,可以设置条件格式用红色表示1。
所有的demo的代码如下:
{
text: '会议室demo',
exec: async(app: Excel.APP) => {
if (app.events.includes('Workbook.Event.Change')) {
app.removeListener('Workbook.Event.Change');
console.log('取消监听Change');
return;
}
const callback = async(range: Excel.Range) => {
console.log('会议室callback执行');
if (isInsectedRange(listendRange, range)) { // 修改位置位于监听区域内
const timeTableMap = await updateModel(); // update model
// 获得冲突位置对应的item
for (let i = 0; i < timeTableMap.length; i += 1) {
const currentRange = timeTableMap[i].timeRange;
if (isInsectedRange(currentRange, range)) { // 是冲突区间
const repeatTime = getRepeatTime(timeTableMap[i].timeArr);
const posRange = timeTableMap[i].posRange;
const ret = [];
for (let j = 0; j < repeatTime.length; j += 1) {
if (repeatTime[j]) {
ret.push(['1']);
} else {
ret.push(['0']);
}
}
await posRange.setValues(ret);
}
}
}
};
app.addListener('Workbook.Event.Change', callback);
console.log('添加监听Change');
const roomsheet = await app.ActiveWorkbook.getSheetByName('会议室预定');
const meetingRoomNum: number[] = [702, 708, 709, 710];
const listendRange = roomsheet.getRange(1, 1, 30, 25);
const firstCol = roomsheet.getRange(1, 1, 30, 1); // 第一列存储了会议室
const firstRow = roomsheet.getRange(1, 1, 1, 25); // 第一行存储了预定日期
interface timeTableItem {
room: number; // 房间号
date: string; // 日期
timeArr: string [][]; // 二维数组,n x 2 eg.start_time end_time
timeRange: Excel.Range; // 用来存储timeArr所在的位置
posRange: Excel.Range; // 用来存储冲突校验的结果
}
enum FindingType {
FindDate = 1,
FindRoom = 2,
// FindCondition = 3,
}
const getIndexTable = async(targetRange: Excel.Range, type: FindingType): Promise<any> => {
const mergedRanges = await targetRange.getMergedRanges();
if (mergedRanges.length > 0) {
switch (type) {
case FindingType.FindDate: {
const ret: number[][] = [];
for (let i = 0; i < mergedRanges.length; i += 1) {
const current = mergedRanges[i];
if (current.endColumn > current.column) { // colspan > 1 认为是date
ret.push([current.column, current.endColumn]);
}
}
return ret;
}
case FindingType.FindRoom: {
const ret: number[][] = [];
for (let i = 0; i < mergedRanges.length; i += 1) {
const current = mergedRanges[i];
if (current.endRow > current.row) { // rowspan > 1 认为是room
ret.push([current.row, current.endRow]);
}
}
return ret;
}
}
}
};
const rowIdx = await getIndexTable(firstCol, FindingType.FindRoom);
const colIdx = await getIndexTable(firstRow, FindingType.FindDate);
// 首先填充数据模型
const updateModel = async() => {
const timeTableMap: timeTableItem[] = [];
for (let i = 0; i < rowIdx.length; i += 1) {
for (let j = 0; j < colIdx.length; j += 1) {
const roomCell = await firstCol.getCell(rowIdx[i][0], 1);
const roomValue = await roomCell.getValue(); // 拿到房间号
const dateCell = await firstRow.getCell(1, colIdx[j][0]);
const dateValue = await dateCell.getValue(); // 拿到日期
const timeRange = await roomsheet.getRange(rowIdx[i][0], colIdx[j][0], rowIdx[i][1], colIdx[j][1]); // 拿到时间数组所在的位置
const timeValues = await timeRange.getValues(); // 拿到时间数组
// 拿到条件格式位置信息(没有时间内容,不算posRange
const timeLen = timeValues.length;
const posRange = await roomsheet.getRange(rowIdx[i][0], colIdx[j][1] + 1, rowIdx[i][0] + timeLen - 1, colIdx[j][1] + 1);
timeTableMap.push({ room: roomValue, date: dateValue, timeArr: timeValues, posRange, timeRange });
}
}
return timeTableMap;
};
// 寻找冲突项
const isInsectedRange = (targetRange: Excel.Range, sourceRange: Excel.Range) => {
const rowInsected = !(targetRange.endRow < sourceRange.row targetRange.row > sourceRange.endRow);
const colInseted = !(targetRange.endColumn < sourceRange.column targetRange.column > sourceRange.endColumn);
return rowInsected && colInseted ? true : false;
};
// 其次判断时间冲突
const getRepeatTime = (timeArr: string[][]) => {
const len = timeArr.length;
const repeatFlag: boolean[] = Array(len).fill(false);
for (let i = 0; i < timeArr.length; i += 1) {
const orderA = timeArr[i];
if (!isValidTimeArr(orderA)) {
repeatFlag[i] = true;
if (isEmptyArray(orderA)) repeatFlag[i] = false;
continue;
}
for (let j = i + 1; j < timeArr.length; j += 1) {
const orderB = timeArr[j];
if (!isValidTimeArr(orderB)) {
repeatFlag[j] = true;
if (isEmptyArray(orderB)) repeatFlag[i] = false;
continue;
}
if (!(orderA[1] <= orderB[0] orderA[0] >= orderB[1])) {
repeatFlag[i] = true;
repeatFlag[j] = true;
}
}
}
return repeatFlag;
};
// 是否是合法的时间组
const isValidTimeArr = (timeArr: string[]) => {
const startTime = timeArr[0];
const endTime = timeArr[1];
// eslint-disable-next-line eqeqeq
if (startTime === '' startTime == null endTime === '' endTime == null) { // 缺少开始时间或者结束时间,false
return false;
}
if (startTime > endTime) { // 开始时间大于结束时间,false
return false;
}
return true;
}
// 是否为空数组
const isEmptyArray = (arr: string[]) => {
if (arr.length > 0) {
return false;
}
return true;
};
},
},
],
},
总结
综上,可以通过集成zOffice在线编辑和zOffice SDK两种方式简单快捷的实现资源预定。