AirScript与金山文档

AirScript相当于一段脚本,嵌入在金山文档组件中,运行在云端,使用JavaScript语言编写,提供对表格数据的增删改查等功能。正是因为他运行在云端,我们可以使用他来实现跨端共享数据

创建AirScript

登录金山文档

打开金山文档网页 https://kdocs.cn, 点击免费使用。按要求注册并登录。

20250112_151100_01.png

新建表格

20250112_151100_02.png

打开脚本编辑器

选择菜单 效率-高级开发-AirScript脚本编辑器

20250112_151100_03.png

新建脚本

这里有"文档共享脚本"和"我的脚本"两个类型,我们选择"文档共享脚本",脚本API有两种,我们这里选择1.0。(我自己的测试2.0有些bug,官方正在修复中)

20250112_151100_04.png

编辑脚本

我们先在代码编辑区简单的输入个return “hello world”

20250112_151100_05.png

复制脚本链接

点开脚本名称右边的省略号,选择“复制脚本webhook”。 这个webhook就是脚本的网址,我们后期就是要使用Web客户端访问这个网址

20250112_151100_06.png

创建脚本令牌

脚本令牌相当于访问上面这个webhook的口令,需要妥善保存,不可外泄。 点击盾牌按钮,开始创建脚本令牌。

20250112_151100_07.png

复制脚本令牌并妥善保存

20250112_151100_08.png

脚本令牌若忘记,只能删除令牌重新生成。 令牌有180天有效期,到期可以延期。

20250112_151100_09.png

建立Web客户端与金山文档的连接

界面设计

在App Inventor的设计界面中,添加一个按钮,一个标签,一个Web客户端

代码设计

创建两个变量

记录上面生成的webhook网址和脚本令牌

20250112_151100_10.png

自定义发送post请求的过程

设置Web的网址为webhook。 在请求头中设置脚本令牌和请求文本的格式为json。 post的文本有一定的格式,必须是{“Context”:{“argv”:payload}}格式的json文本。其中的payload就是我们要发送的参数,我们需要把参数也写成json格式。 (所有图片都可以双击放大查看)

20250112_151100_11.png

在Web.GotText事件中接收服务器返回的数据

现在我们发送一个空文本,看看服务器的返回文本,其中的result正是我们在脚本中写的hello world,说明我们的App Inventer与金山文档交互成功。返回文本中包含多个字段,其中的result和error是我们比较关注的,可以使用字典提取这两个键值。

20250112_151100_12.png

20250112_151100_13.png

使用AirScript操作金山云文档

添加行

20250112_151100_14.png

我们向AirScript发送两个字段,action和data。 我们可以把多个操作命令写在一个AirScript脚本文件中,为了区分各个命令,我们使用action来指定当前的操作。 data就是我们要添加的记录,为一维列表。

例如,我们要操作一个用户名和密码的表格。

20250112_151100_15.png

我们要添加一条记录[“wang”,“999”]:

20250112_151100_16.png

为了接收该条记录,在脚本编辑器中写入:

let action = Context.argv.action;
let sheetName = Context.argv.sheetname || "Sheet1";
let sh = Application.Sheets(sheetName);

if (action == "addrow") {
  let data = Context.argv.data || [];
  let row = sh.UsedRange.RowEnd + 1;
  for (let i = 0; i < data.length; i++) {
    sh.Cells(row, i + 1).Value = data[i];
  }
  return "done";
}

return "unknown action";

这段脚本的作用,是在文档的最后添加一行,并将收到的数据写入该行。其中的Context.argv.xxx 就是读取传来的参数。

现在,运行addrow,就会返回done

20250112_151100_17.png

云文档就变成了类似这样:

20250112_151100_18.png

读取行数据

20250112_151100_19.png

20250112_151100_20.png

告诉脚本需要读取的行的行号,让他返回该行的数据。

20250112_151100_21.png

脚本如下

if (action == "getrow") {
  let row = Context.argv.row || "1";
  let maxCol = sh.UsedRange.ColumnEnd;
  return sh.Range(sh.Cells(row, 1), sh.Cells(row, maxCol)).Value2;
}

查找数据

20250112_151100_22.png

20250112_151100_23.png

在第一列中查找zhang,返回:

20250112_151100_24.png

大多数情况下,我们是不知道数据所在的行号的。 我们可以在col列中查找value数据,若找到,返回当前行的数据列表,若没有,返回空列表。你也可以修改脚本,仅返回某个单元格的数据。

if (action == "lookup") {
  let value = Context.argv.value || "";
  let col = Context.argv.col || "1";
  let rowEnd = sh.UsedRange.RowEnd;
  let colEnd = sh.UsedRange.ColumnEnd;
  let cells = sh.Cells;
  let found = -1;
  for (let i = 1; i <= rowEnd; i++) {
    if (cells(i, col).Value2 == value) {
      found = i;
      break;
    }
  }
  if (found == -1) {
    return [];
  } else {
    return sh.Range(sh.Cells(found, 1), sh.Cells(found, colEnd)).Value2;
  }
}

删除行

20250112_151100_25.png

20250112_151100_26.png

在col列中查找value,若找到,将当前行删除。

脚本如下:

if (action == "delete") {
  let value = Context.argv.value || "";
  let col = Context.argv.col || "1";
  let rowEnd = sh.UsedRange.RowEnd;
  let cells = sh.Cells;
  //这里我们要从最后一行倒着向上查找
  for (let i = rowEnd; i >=1; i--) {
    if (cells(i, col).Value2 == value) {
      cells(i, col).EntireRow.Delete()
}
  }
  return "done"
}

更多的更复杂的查询脚本可以在此基础上修改而来。

云文档增删改查脚本

这段脚本包含了读取行、列、单元格、整张表,查询行,添加行,删除行等功能,可以直接使用。

//获取命令参数和数据表名。若没有指定就用默认值。
let action = Context.argv.action || "getsheet";
let sheetName = Context.argv.sheetname || "Sheet1";
let sh = Application.Sheets(sheetName);

//在col列中查找value值,若找到返回整行,否则返回空
if (action == "lookup") {
  let value = Context.argv.value || "";
  let col = Context.argv.col || "1";
  let colEnd = sh.UsedRange.ColumnEnd || "1";
  let rowEnd = sh.UsedRange.RowEnd;
  let cells = sh.Cells;
  let found = -1;
  for (let i = 1; i <= rowEnd; i++) {
    if (cells(i, col).Value2 == value) {
      found = i;
      break;
    }
  }
  if (found == -1) {
    return buildData("[]");
  } else {
    return buildData(sh.Range(sh.Cells(found, 1), sh.Cells(found, colEnd)).Value2);
  }
}

//返回row行col列的单元格的值
else if (action == "getcell") {
  let col = Context.argv.col || "1";
  let row = Context.argv.row || "1";
  return buildData(sh.Cells(row, col).Value);
}

//返回第row行的值列表
else if (action == "getrow") {
  let row = Context.argv.row || "1";
  let maxCol = sh.UsedRange.ColumnEnd;
    return buildData(sh.Range(sh.Cells(row, 1), sh.Cells(row, maxCol)).Value2);

}

//返回第col列的值列表(的列表)
else if (action == "getcol") {
  let col = Context.argv.col || "1";
  let maxRow = sh.UsedRange.RowEnd;
  return buildData(sh.Range(sh.Cells(1, col), sh.Cells(maxRow, col)).Value2);
}

//返回整个表格的值列表
else if (action == "getsheet") {
  return buildData(sh.UsedRange.Value2);
}

//在表格末尾添加一行并赋值
else if (action == "addrow") {
  let data = Context.argv.data || [];
  let row = sh.UsedRange.RowEnd + 1;
  for (let i = 0; i < data.length; i++) {
    sh.Cells(row, i + 1).Value = data[i];
  }
  return buildData("done");
}

//设置第row行的数据
else if (action == "setrow") {
  let row = Context.argv.row || sh.UsedRange.RowEnd + 1;
  let data = Context.argv.data || [];

  for (let i = 0; i < data.length; i++) {
    sh.Cells(row, i + 1).Value = data[i];
  }
  return buildData("done");
}

//设置第row行第col列的单元格的值
else if (action == "setcell") {
  let col = Context.argv.col || "1";
  let row = Context.argv.row || "1";
  let value = Context.argv.value || "";
  sh.Cells(row, col).Value = value;
  return buildData("done");
}

//在第col列中查找value值,若找到,则删除整行
else if (action == "delete") {
  let value = Context.argv.value || "";
  let col = Context.argv.col || "1";
  let rowEnd = sh.UsedRange.RowEnd;
  let cells = sh.Cells;
  //这里我们要从最后一行倒着向上查找
  for (let i = rowEnd; i >= 1; i--) {
    if (cells(i, col).Value2 == value) {
      cells(i, col).EntireRow.Delete()
    }
  }
  return buildData("done")
}

return buildData("unknown action")

//格式化返回值
function buildData(data) {
  return { "action": action, "result": data }
}

结束语

现在,使用脚本令牌我们可以轻松的完成数据的增删改查,扔掉老爷车 SQL,使用 JavaScript 来进行“为所欲为”的结构化查询,快来体验一下吧。

参考文档: AirScript文档: https://airsheet.wps.cn/docs/