---
order: 7
navTitle: 表达式函数脚本
---
# 后端表达式函数脚本

后端表达式函数脚本运行在服务器端，适合把需要服务端能力的逻辑接入表达式。例如读取当前用户、判断权限、访问服务端 API、查询数据库或处理不能暴露到浏览器端的业务规则。

如果逻辑只在浏览器页面内使用，优先使用[前端表达式脚本函数](../frontend/expression-functions.md)。如果函数需要沉淀成像内置函数一样的通用能力，再参考[表达式函数扩展](../../extension/extension-points/expressionFunction/README.md)。

## 写在哪里{#where}

按复用范围选择脚本位置：只给一个页面用，写在页面同目录的同名 `.action.ts`；应用或项目内多个页面都要用，写到对应层级的 `hooks.action.ts`；多个项目都要用，才写到系统级脚本。具体路径和作用范围见[脚本文件组织](../file-organization.md#backend-script)。

## 编写和调用{#usage}

在后端脚本中导出以 `expfunc_` 开头的函数。函数第一个参数是服务端表达式计算上下文，后面的参数来自表达式调用。

```ts
export function expfunc_RISKLEVEL(_ctx: unknown, amount: number): string {
  if (amount == null) {
    return 'unknown';
  }
  if (amount >= 1000000) {
    return 'high';
  }
  if (amount >= 100000) {
    return 'medium';
  }
  return 'low';
}
```

写法要求：

1. 必须 `export` 函数。
2. 函数名必须以 `expfunc_` 开头；表达式调用时去掉这个前缀。
3. 表达式通过 [`SCRIPT`](../../../exp/func/others/SCRIPT.md) 调用脚本函数，第一个参数写去掉 `expfunc_` 后的函数名。
4. 后端表达式函数不返回 `Promise`。需要调用外部系统时，应使用服务端脚本中可用的同步 API 或封装成后端可执行的接口。
5. 函数内不要依赖浏览器对象，例如 `window`、`document`、DOM 组件实例或前端页面状态。

表达式中这样调用：

```js
SCRIPT('RISKLEVEL', [订单].[金额])
```

表达式会先计算 `SCRIPT` 后面的参数，再把参数值传给脚本函数。例如 `SCRIPT('RISKLEVEL', [订单].[金额])` 会调用 `expfunc_RISKLEVEL(_ctx, amount)`，`amount` 的值来自 `[订单].[金额]`。

脚本函数从第二个参数开始接收表达式传入的值。参数建议使用字符串、数值、布尔值、日期等基础类型；对空值、非法值要在函数内显式处理。

```ts
export function expfunc_ORDERLABEL(_ctx: unknown, orderNo: string, amount: number): string {
  if (!orderNo) {
    return '';
  }
  return `${orderNo}-${amount ?? 0}`;
}
```

表达式调用：

```js
SCRIPT('ORDERLABEL', [订单].[订单号], [订单].[金额])
```

函数可以返回字符串、数值、布尔值、日期或 JSON 对象等表达式可处理的结果。函数返回 `undefined` 时，表达式通常会按空值处理；函数抛出异常时，会导致对应表达式计算失败。

```ts
export function expfunc_CANSUBMIT(_ctx: unknown, status: string): boolean {
  return status === 'draft' || status === 'returned';
}
```

表达式调用：

```js
SCRIPT('CANSUBMIT', [单据].[状态])
```

## 控制权限{#permission}

后端表达式函数的权限通常跟随页面和数据查询权限。用户能打开页面、能计算页面中的表达式时，表达式脚本函数就按这次页面访问的上下文执行；数据查询仍按普通数据查询权限、数据范围和页面权限生效。

因此，常规场景优先把页面权限、模型权限和数据查询权限配置好，不需要在每个表达式脚本函数里重复判断。只有在确实有特殊展示需求时，才在脚本中读取当前用户或上下文，返回不同结果，让前端页面根据结果显示不同内容。

例如：

```ts
export function expfunc_AMOUNTDISPLAY(_ctx: unknown, amount: number, masked: boolean): string {
  if (masked) {
    return "******";
  }
  return amount == null ? "" : String(amount);
}
```

表达式调用：

```js
SCRIPT('AMOUNTDISPLAY', [订单].[金额], params.maskAmount)
```

如果不是表达式计算，而是单独开放后端 WEB API、导出、写入或删除数据，权限控制方式见[后端 WEB API 脚本权限控制](./web-api-permission.md)。

## 与扩展函数的区别{#extension}

应用或项目内的表达式函数优先写在页面同名 `.action.ts` 或 `hooks.action.ts` 中。只有当函数需要作为产品级通用能力发布、出现在函数列表中、配置参数说明、支持多运行环境或 SQL 翻译时，再开发[表达式函数扩展](../../extension/extension-points/expressionFunction/README.md)。
