请选择 进入手机版 | 继续访问电脑版
 找回密码
 立即注册

QQ登录

只需一步,快速开始

小仙

注册会员

12

主题

21

帖子

75

积分

注册会员

积分
75
小仙
注册会员   /  发表于:2025-4-14 09:11  /   查看:92  /  回复:4
20金币
本帖最后由 小仙 于 2025-4-14 14:29 编辑

现在的场景是这样,我定义了一个异步函数,然后我打开excel的方式是重新计算公式,所以单元格都会显示Loading

但是现在我获取公式结果后,看起来是回填到单元格了,但是我随便点一下excel的单元格就会重新显示Loading,之后重新获取公式结果就没问题,第一次就会有问题
Snipaste_2025-04-14_09-11-10.png

  1. class StatementF extends GC.Spread.CalcEngine.Functions.AsyncFunction {
  2.   cellRequestMap: Map<string, CellRequest>;

  3.   constructor(name: string) {
  4.     super(name, 1, 255);
  5.     this.cellRequestMap = new Map<string, CellRequest>();
  6.   }

  7.   defaultValue(): any {
  8.     return "Loading";
  9.   }

  10.   evaluateAsync(context: GC.Spread.CalcEngine.AsyncEvaluateContext): any {
  11.     const args = arguments;
  12.     const p = arguments[0]
  13.     // console.log(p.ctx.source)
  14.     const workbookName = p.ctx.source.getSheet().getParent().name || 'xxxx-when-workbook-new'
  15.     const sheetName = p.ctx.source.getSheet().name()
  16.     if (args.length != 3) {
  17.       context.setAsyncResult("参数异常");
  18.       return;
  19.     }
  20.     // console.log(workbookName, sheetName, p.row, p.col)
  21.     let mapKey = workbookName + '-' + sheetName + '-' + p.row + '-' + p.col
  22.     if (this.cellRequestMap.has(mapKey)) {
  23.       const cellMap = this.cellRequestMap.get(mapKey)
  24.       if (cellMap) {
  25.         cellMap.formula.push(args[1])
  26.         cellMap.argStr.push(args[2])
  27.         cellMap.context.push(context)
  28.       }
  29.     } else {
  30.       this.cellRequestMap.set(mapKey, {
  31.         formula: [args[1]],
  32.         argStr: [args[2]],
  33.         context: [context]
  34.       });
  35.     }
  36.     console.log(this.cellRequestMap)
  37.     // 设置默认值,默认值是文本类型,和其他的一起的时候会报#NAME?
  38.     context.setAsyncResult("Loading...");
  39.   }
  40. }
复制代码
Snipaste_2025-04-14_09-14-57.png
我打印了一下,发现同一个单元格的公式被触发了两次请求的收集,首次加载还是会触发6次请求收集,但获取公式结果后,再点一下任意单元格这6个单元格异步公式还是触发了一次,为什么会这样

QQ2025414-142023.gif

保存的代码逻辑如下
  1. function handleSave() {
  2.   loading.value = true
  3.   const spread = toRaw(spreadRef.value);
  4.   spread?.export(async function (blob: Blob) {
  5.     try {
  6.       fstForm.content = await blobToBase64(blob); // 将 Base64 数据存储在 form 中
  7.     } catch (error) {
  8.       console.error('Blob 转 Base64 失败:', error);
  9.     }
  10.     // 发送请求保存表单
  11.     apiSaveForm(fstForm).then(() => {
  12.       ElMessage.success('保存成功')
  13.     }).finally(() => {
  14.       loading.value = false
  15.     })
  16.   }, function (err: any) {
  17.     console.log(err);
  18.     loading.value = false
  19.   }, {
  20.     fileType: GC.Spread.Sheets.FileType.excel,
  21.     includeStyles: true,
  22.     includeFormulas: true,
  23.     includeBindingSource: true
  24.   })
  25. }
复制代码


4 个回复

倒序浏览
Lynn.Dou讲师达人认证 悬赏达人认证 SpreadJS 开发认证
超级版主   /  发表于:2025-4-14 11:58:10
沙发
您好,

由于您提供的自定义函数代码缺少变量,我本地用学习指南示例的异步函数做了替代,之后根据您描述的信息尝试进行复现,结果如下:
(如果有操作步骤有误,请详细指出)
async.gif171636351.png
根据此动图,xlsx文件中包含自定义函数,之后在demo中导入xlsx文件,并勾选“导入后自动计算”。此时未复现“随便点一下excel的单元格就会重新显示Loading”问题,且控制台仅打印一次“ASUM”。

初步对比来看,您在 defaultValue() 已经设置了默认值,为什么还要在evaluateAsync中加 context.setAsyncResult("Loading...")这句代码呢?
或者您在附件demo基础上补充上自己的代码,要求能复现此问题,以便问题的进一步调研。

demo.zip

1.66 KB, 下载次数: 3

回复 使用道具 举报
小仙
注册会员   /  发表于:2025-4-14 14:21:07
板凳
Lynn.Dou 发表于 2025-4-14 11:58
您好,

由于您提供的自定义函数代码缺少变量,我本地用学习指南示例的异步函数做了替代,之后根据您描述 ...
  1. function handleGetWorkBook() {
  2.   const id = route.params.id;
  3.   if (typeof id !== 'string') return;
  4.   apiGetForm(id).then(res => {
  5.     fstForm.clone(res)
  6.     if (res.period == '0000-00') {
  7.       buttonType.value = 0
  8.     } else if (Number(route.params.leaf) == 1) {
  9.       buttonType.value = 2
  10.     } else {
  11.       buttonType.value = 3
  12.     }
  13.     const file = new File([base64ToArrayBuffer(res.content)], `${res.name}.xlsx`, {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
  14.     const spread = toRaw(spreadRef.value)

  15.     spread?.import(file, function () {
  16.       loading.value = false
  17.       // 监听清除内容动作
  18.       spread?.bind(GC.Spread.Sheets.Events.RangeChanged, function (sender: any, args: any) {
  19.         console.log(sender, args)
  20.         if (args.action == 2 && !args.isUndo) {
  21.           onCellClear({
  22.             type: 'RangeChanged',
  23.             keyList: args.changedCells.map((item: any) => {
  24.               return spread.name + '-' + args.sheetName + '-' + item.row + '-' + item.col
  25.             })
  26.           })
  27.         }
  28.       })
  29.       // 监听值改变
  30.       spread?.bind(GC.Spread.Sheets.Events.ValueChanged, function (sender: any, args: any) {
  31.         console.log(sender, args)
  32.         if (!args.newValue) {
  33.           const key = spread.name + '-' + args.sheetName + '-' + args.row + '-' + args.col
  34.           onCellClear({
  35.             type: 'ValueChanged',
  36.             keyList: [key]
  37.           })
  38.         }
  39.       })
  40.       spread.name = res.id
  41.       const sheetCount = spread?.getSheetCount() || 0;
  42.       for (let i = 0; i < sheetCount; i++) {
  43.         const sheet = spread?.getSheet(i);
  44.         if (sheet == undefined) continue;
  45.         sheet.options.showFormulas = false

  46.         // sheet.options.isProtected = true
  47.       }
  48.     }, function (err: any) {
  49.       loading.value = false
  50.       console.log(err)
  51.     }, {
  52.       fileType: GC.Spread.Sheets.FileType.excel,
  53.       fullRecalc: false,
  54.       includeFormulas: true,
  55.       openMode: 1
  56.     })
  57.   })
  58. }
复制代码

你好,我这里目前实现的逻辑是,把内容用import的方式引入后,默认不会fullRecalc,然后切换的时候,会触发以下方法
  1. function handleFullRecalc() {
  2.   const file = new File([base64ToArrayBuffer(fstForm.content)], `${fstForm.name}.xlsx`, {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
  3.   const spread = toRaw(spreadRef.value)
  4.   spread?.suspendPaint()
  5.   spread?.import(file, function () {
  6.     console.log(spread.name)
  7.     spread?.resumePaint()
  8.     loading.value = false
  9.   }, function (err: any) {
  10.     loading.value = false
  11.     console.log(err)
  12.   }, {
  13.     fileType: GC.Spread.Sheets.FileType.excel,
  14.     includeFormulas: true,
  15.     fullRecalc: fullRecalc.value,
  16.     openMode: 1
  17.   })
  18. }
复制代码

然后获取公式就不行
回复 使用道具 举报
Lynn.Dou讲师达人认证 悬赏达人认证 SpreadJS 开发认证
超级版主   /  发表于:2025-4-14 15:03:30
地板
您留下联系方式,稍后与您电话沟通下此问题。
回复 使用道具 举报
Ellia.DuanSpreadJS 开发认证
超级版主   /  发表于:7 天前
5#
小仙 发表于 2025-4-14 14:21
你好,我这里目前实现的逻辑是,把内容用import的方式引入后,默认不会fullRecalc,然后切换的时候,会 ...

您好,尝试修改openMode ,看是否会影响您的测试结果:
image.png803981933.png
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 立即注册
返回顶部