# 前端业务逻辑使用说明

前端业务逻辑指：**用与后端相同的表达式语法书写**，在**浏览器中执行**，用于**操作界面组件与响应式数据**的逻辑脚本。语法与后端 Logic 一致，但运行在前端，入参中可传入 Vue 实例、ref、响应式数据等，供脚本读写界面状态或调用组件方法。

---

## 一、运行方式

### 1. 全局调用：`this.$runFrontLogic(logicName, param)`（推荐在配置脚本中使用）

通过 Vue 插件注册，**任意组件**及**配置中的可执行脚本**（如报表的 `dataProcessScript`、按钮的 `customFunction`）内均可使用，无需 import。

- 返回 **Promise**，可 `.then()` / `.catch()` 处理结果或错误。
- 插件在 base-client 中注册，使用 `Vue.use(Plugins)` 的应用自动具备该能力。

```javascript
// 例如在 dataProcessScript、customFunction 等配置脚本中（this 为当前组件）
var c = (data && data.patientComplaint != null) ? data.patientComplaint : ''
this.$runFrontLogic('aiDiagnosesCoverDataProcess', { patientComplaint: c, proxy: this }).catch(function (e) {
  if (this.$message && this.$message.warn) this.$message.warn('执行失败，请稍后重试')
})
```

### 2. 按配置名执行：`LogicRunner.run(logicName, param)`

- 从后端/配置中心按 `logicName` 拉取逻辑内容（与后端 Logic 同源的配置），在前端执行。
- 执行时自动注入插件：`data`（即本次传入的 `param`）、`log`、`ENV`、`logic`、`dateTools`、`vueTools`、`http`。
- 适合逻辑内容放在配置里、由界面传入「当前组件 / 响应式数据」的场景。

```javascript
import LogicRunner from '@vue2-client/logic/LogicRunner'

// 传入当前组件 proxy 和响应式数据，供逻辑脚本操作界面
const result = await LogicRunner.run('testVueLogic', {
  metaData: metaData,  // 例如 ref({ inputValue, displayValue })
  proxy: proxy         // 当前组件实例 getCurrentInstance().proxy
})
```

### 3. 直接执行表达式字符串：`LogicRunner.runExpression(source, params)`

- 不拉取配置，直接执行一段表达式字符串。
- `params` 即脚本内的入参（通常包含 `data` 等），无默认插件，需调用方自己构造。
- 适合逻辑内容来自表单配置、工作流配置等动态字符串的场景。

```javascript
import LogicRunner from '@vue2-client/logic/LogicRunner'

const result = await LogicRunner.runExpression(expression, {
  WF_FORM: { ...formData }   // 脚本内通过 data.WF_FORM 或对应 key 访问
})
```

---

## 二、前端可用插件 / 入参

在**按配置名执行**（`LogicRunner.run`）时，脚本内可用的对象包括：

| 名称 | 说明 |
|------|------|
| `data` | 本次调用传入的 `param`，例如 `data.metaData`、`data.proxy`。用于读写在页面传入的响应式数据或组件引用。 |
| `log` | 日志，如 `log.info(...)`、`log.debug(...)`。 |
| `ENV` | 运行环境信息（来自配置的 `$globalProp`）。 |
| `logic` | LogicRunner 自身，可再调 `logic.run(其他逻辑名, 参数)`（会再拉配置执行）。 |
| `dateTools` | 日期工具，与后端 dateTools 用法一致。 |
| `vueTools` | 前端专用：`vueTools.getComponent(vueRef, componentName)`，等价于 `vueRef.$refs[componentName]`，用于按 ref 名取子组件。 |
| `http` | 请求插件（返回 Promise）：`http.post(url, body)`、`http.get(url, params)`。返回值为响应体（response.data），执行器会自动等待 Promise 完成后再继续，可在 Logic 中直接写 `res = http.post('/api/xxx', { key: value })` 再使用 `res.xxx`。 |

在**直接执行表达式**（`runExpression`）时，没有默认插件，完全由第二个参数 `params` 提供，例如把当前表单数据放进 `params.WF_FORM`，脚本里用 `data.WF_FORM` 访问（若 params 里 key 为 `data` 且值为该对象）。

---

## 三、语法要点（与后端 Logic 一致）

- 整体是一条**表达式**，多条语句用逗号 `,` 分隔。
- **赋值**：`变量 = 表达式` 或 `对象.属性 = 表达式`。
- **条件**：`条件 : 结果 , 默认值`，无 if/else，用逗号接默认值。
- **循环**：用数组的 `each`，例如 `data.xxx.each( row = row + 1 )`，其中 `row` 表示当前项。
- **JSON**：支持 `{ key: value }`、`[ a, b ]`。
- **字符串插值**：仅支持双引号字符串，字符串内用 `"现在是{dateTools.getNow2()}"` 形式嵌入表达式（不再支持 `$...$` 形式的字符串）。`$` 可作为标识符的一部分使用，与普通字母一致，例如 `data.$runFrontLogic(...)`。
- 其他：`return`、`try/catch/finally`、`validate { ... }`、`assert`、lambda `=> { }` 等，与后端一致。
- **异步请求**：表达式语法不支持 `await`，需使用返回 Promise 的插件方法。`http.post(url, body)`、`http.get(url, params)` 返回 Promise，执行器会在调用处自动等待完成并把结果赋给左侧变量，例如：`res = http.post('/hai-api/suggest-by-complaint', { chief_complaint: data.c }), sug = res.suggestions, ...`。

更完整的语法见 `src/expression/core/Program.js`（解析）和 `src/expression/TestExpression.js`（大量表达式示例）。

---

## 四、操作界面组件的示例

### 示例 1：在页面中执行“前端逻辑”并操作组件与数据

页面中传入 `proxy` 和响应式数据 `metaData`，逻辑脚本内通过 `data` 修改界面数据，或通过 `vueTools` 取子组件调用方法：

```vue
<!-- src/pages/LogicCallExample/index.vue -->
<script setup>
import LogicRunner from '@vue2-client/logic/LogicRunner'
import { getCurrentInstance, ref } from 'vue'

const { proxy } = getCurrentInstance()
const metaData = ref({
  inputValue: '',
  displayValue: 'default'
})

async function testLogic () {
  await LogicRunner.run('testVueLogic', {
    metaData: metaData,
    proxy: proxy
  })
}
</script>

<template>
  <div>
    录入值：<a-input v-model="metaData.inputValue" />
    显示值：<span>{{ metaData.displayValue }}</span>
    <a-button @click="testLogic">修改</a-button>
    <x-form-table ref="testFormTable" ... />
  </div>
</template>
```

配置项 `testVueLogic` 中的逻辑脚本可以这样写（与后端同语法，操作 `data` 与组件）：

- 改界面上的响应式数据：`data.metaData.displayValue = data.metaData.inputValue , null`
- 通过 `vueTools` 拿子组件：`vueTools.getComponent(data.proxy, 'testFormTable')`，再调用该组件的 refreshTable 等方法（需在表达式语法内通过属性/方法调用完成）。

### 示例 2：工作流中根据表单数据做分支判断

不涉及组件引用，仅根据表单数据执行表达式，得到 true/false 或结果值：

```javascript
// 摘自 WorkFlowHandle.vue：根据表单数据评估条件表达式
const result = await LogicRunner.runExpression(expression, {
  WF_FORM: { ...formData }
})
// 表达式内可用 data.WF_FORM.xxx 访问表单字段
```

---

## 五、相关文件与文档

| 内容 | 路径 |
|------|------|
| **前端 Logic Vue 插件** | `src/base-client/plugins/FrontLogicPlugin.js`（注册 `$runFrontLogic`） |
| 运行器 | `src/logic/LogicRunner.js` |
| 表达式解析与执行 | `src/expression/ExpressionRunner.js`、`src/expression/core/Program.js`、`src/expression/core/Expression.js` |
| 前端插件 | `src/logic/plugins/index.js`、`src/logic/plugins/common/VueTools.js`、`src/logic/plugins/common/DateTools.js`、`src/logic/plugins/common/HttpTools.js` |
| 页面示例 | `src/pages/LogicCallExample/index.vue` |
| 工作流表达式示例 | `src/pages/WorkflowDetail/WorkflowPageDetail/WorkFlowHandle.vue`（`evaluateExpression`） |
| 表达式语法用例 | `src/expression/TestExpression.js` |
| 后端 Logic 插件说明 | `docs/Logic函数使用相关.md`（后端 sql、entity、log 等；前端 run 时仅有上述插件） |

当前项目**没有单独一份“前端逻辑语法手册”**，语法与后端业务逻辑一致，可参考后端说明与 `Program.js`、`TestExpression.js` 对照使用。本文档侧重前端运行方式、入参/插件和操作界面组件的用法。
