diff --git b/.gitignore a/.gitignore new file mode 100644 index 0000000..f8252e2 --- /dev/null +++ a/.gitignore @@ -0,0 +1,12 @@ +/node_modules +/.env.local +/.umirc.local.ts +/config/config.local.ts +/src/.umi +/src/.umi-production +/src/.umi-test +/dist +.swc +/.history +.DS_Store +pnpm-lock.yaml diff --git b/.npmrc a/.npmrc new file mode 100644 index 0000000..0b44d45 --- /dev/null +++ a/.npmrc @@ -0,0 +1,2 @@ +registry=https://registry.npmjs.com/ + diff --git b/.prettierrc a/.prettierrc new file mode 100644 index 0000000..ac2162e --- /dev/null +++ a/.prettierrc @@ -0,0 +1,21 @@ +{ + "printWidth": 100, + "eslintIntegration": true, + "stylelintIntegration": true, + "tabWidth": 2, + "semi": true, + "singleQuote": false, + "quoteProps": "as-needed", + "jsxSingleQuote": false, + "bracketSpacing": true, + "arrowParens": "avoid", + "htmlWhitespaceSensitivity": "css", + "javascript.format.insertSpaceBeforeFunctionParenthesis": true, + "files.insertFinalNewline": true, + "useTabs": false, + "endOfLine": "lf", + "ignorePath": ".gnore", + "trailingComma": "es5", + "jsxBracketSameLine": false, + "bracketSameLine": false +} \ No newline at end of file diff --git b/.umirc.ts a/.umirc.ts new file mode 100644 index 0000000..a810da3 --- /dev/null +++ a/.umirc.ts @@ -0,0 +1,12 @@ +import { defineConfig } from "umi"; + +export default defineConfig({ + routes: [ + { path: "/", redirect: "/index" }, + { path: "/index", component: "index" }, + ], + npmClient: 'pnpm', + publicPath: '/InsSet/', + history: { type: 'hash' }, + hash: true, +}); diff --git b/package.json a/package.json new file mode 100644 index 0000000..75dde25 --- /dev/null +++ a/package.json @@ -0,0 +1,28 @@ +{ + "private": true, + "author": "zhangzhen <525765282@qq.com>", + "scripts": { + "dev": "cross-env PORT=9099 umi dev", + "build": "umi build", + "postinstall": "umi setup", + "setup": "umi setup", + "start": "npm run dev" + }, + "dependencies": { + "@ant-design/icons": "^6.0.0", + "antd": "^5.26.4", + "cross-env": "^7.0.3", + "dt-react-component": "5.2.0-beta.0", + "lodash": "^4.17.21", + "sortablejs": "^1.15.6", + "umi": "^4.4.11" + }, + "devDependencies": { + "@types/lodash": "^4.17.20", + "@types/react": "^18.0.33", + "@types/react-dom": "^18.0.11", + "@types/sortablejs": "^1.15.8", + "@umijs/plugins": "^4.4.11", + "typescript": "^5.0.3" + } +} \ No newline at end of file diff --git b/src/assets/yay.jpg a/src/assets/yay.jpg new file mode 100644 index 0000000..e72bd8f --- /dev/null +++ a/src/assets/yay.jpg diff --git b/src/assets/指令集说明文档.html a/src/assets/指令集说明文档.html new file mode 100644 index 0000000..70675ac --- /dev/null +++ a/src/assets/指令集说明文档.html @@ -0,0 +1,687 @@ + + + + + +指令集说明文档 + +
+

指令集说明文档

 

创建空数据集 --- newempty

API

属性说明类型默认值是否必填
opr指令类型string/
newDataset新产生的临时数据string/是(newDataset/desDataset二选一)
desDataset覆盖掉原来的数据(新增新表单时用)string/是(newDataset/desDataset二选一)

举例1

举例2

 

清空表数据 --- emptyAll

说明:清空数据集,但不保存到数据库

API

属性说明类型默认值是否必填
opr指令类型string/
desDataset被编辑的数据源(仅支持逗号)string/

举例

 

过滤 --- filter

API

属性说明类型默认值是否必填
opr指令类型string/
srcDataset被过滤的数据(支持@筛选)string/
newDataset新产生的临时数据string/
datasetcondition用到的数据集string/
condition筛选srcDataset数据(需要用到js判断的情况下使用,简单的可以用desDataset的@删选实现)string/

举例

 

如果 --- ifdo

API

属性说明类型默认值是否必填
opr指令类型string/
datasetcondition用到的数据集string/
conditions固定格式,里面写详细条件object[]/

conditions API

属性说明类型默认值是否必填
condition条件语句string/
commands满足条件后执行的指令集object[]/
conditionNotEmpty数据集如果都不为空,继续执行(多个数据集逗号分隔)string/
conditionEmpty数据集如果都为空,继续执行(多个数据集逗号分隔)string/

举例1

举例2

 

循环 --- fordo

API

属性说明类型默认值是否必填
opr指令类型string/
dataset被循环的数据集(不支持@、不支持逗号分隔)string/
conditions固定写法,里面写具体条件Object[]/

说明

循环中当前条数据用 dataset名称+One 表示

举例

 

新增 --- add

API

属性说明类型默认值是否必填
opr指令类型string/
desDataset被新增的数据集string/
datasetsValue进行简单计算用到的数据集(支持逗号分隔,@筛选)dataset说明string/
sValue赋值规则 sValue说明string/

sValue说明

支持如下写法:

举例

 

 

删除 --- del

API

属性说明类型默认值是否必填
opr指令类型string/
desDataset被编辑的数据源(仅支持@筛选)string/
datasetcondition用到的数据集(支持逗号分隔,@筛选)dataset说明string/
condition筛选srcDataset数据(需要用到js判断的情况下使用,简单的可以用desDataset的@删选实现)string/

举例

复制 --- copy

API

属性说明类型默认值是否必填
opr指令类型string/
srcDataset被复制的数据源(仅支持@筛选)string/
newDataset新产生的临时数据stirng/
datasetsValue进行简单计算用到的数据集(支持逗号分隔,@筛选)dataset说明string/
sValue赋值规则 sValue说明string/

举例

 

编辑 --- edit

API

属性说明类型默认值是否必填
opr指令类型string/
desDataset被编辑的数据源(仅支持@筛选)string/
datasetcondition/sValue进行简单计算用到的数据集(支持逗号分隔,@筛选)dataset说明string/
condition筛选srcDataset数据(需要用到js判断的情况下使用,简单的可以用desDataset的@删选实现)string/
sValue赋值规则string/

举例

 

 

打印 --- print

API

属性说明类型默认值是否必填
opr指令类型string/
reportName报表名称string/
reportType报表类型stirng/
srcDataset报表数据源(支持逗号分隔,@筛选)string/
bPreviewOnly只要预览,不要显示打印页面boleanfalse

举例

 

刷新 --- refresh

API

属性说明类型默认值是否必填
opr指令类型string/
dataset需要刷新的数据源
(不填/填*表示刷新整个页面)
(parent.数据源名 表示刷新父页面数据源)
string*

举例

清空选中 --- clearrowkey

API

属性说明类型默认值是否必填
opr指令类型string/
dataset需要刷新的数据源(支持逗号分隔)string/

举例

选中表格第一行 --- selectfirstline

API

属性说明类型默认值是否必填
opr指令类型string/
dataset需要选中的数据源(支持逗号分隔)string/

举例

查询SQL --- opensql

API

属性说明类型默认值是否必填
opr指令类型string/
data详细配置object[]/

data API

属性说明类型默认值是否必填
sql指令类型string/
srcDataset传入接口的数据源(支持@筛选, 逗号分隔会把两个数据合并)string/
newDataset接口返回数据的存放数据源string/
sSqlCondition后台用到的参数string/

举例

 

执行SQL --- exesql

API

属性说明类型默认值是否必填
opr指令类型string/
data详细配置object[]/

data API

属性说明类型默认值是否必填
sql指令类型string/
srcDataset传入接口的数据源(仅支持@筛选)string/

举例

 

消息指令 --- msg

API

属性说明类型默认值是否必填
sql指令类型string/
code消息类型number/
msg消息内容string/
time弹窗消失时间(单位:秒)(能自动消失的类型才生效)number3

code类型 API

说明是否自动消失
-1错误类型消息
1成功类型消息
2提示类型消息
-8错误类型消息
-7确认类型消息(确定:继续执行,取消:指令集立即结束)

举例

 

保存指令 --- save

API

属性说明类型默认值是否必填
opr指令类型string/
data单表保存专用
(传统表单保存请不要添加这个属性)
object[]/
doNotValidate保存不进行校验booleanfalse
doNotRefresh保存后不刷新表格booleanfalse

data API

属性说明类型默认值是否必填
tablename表名string/
srcDataset表格名称string/

举例

 

弹窗指令 --- popup

API

属性说明类型默认值是否必填
opr指令类型string/
dataset弹窗【SQL条件】用到的数据源string/

举例

弹窗内容说明

弹窗配置参照【MES功能配置】-【 6、表格按钮弹窗带参数配置】

 

关闭弹窗指令集 --- closepop

API

属性说明类型默认值是否必填
opr指令类型string/

举例

 

按钮指令集 --- btnhandle

API

属性说明类型默认值是否必填
opr指令类型string/
data各个按钮配置object[]/
conditionGroup可多次复用的条件数组object{}/

conditionGroup 介绍

key值: 自定义

value值:下方enabled/show/condition内会复用到的条件

调用时支持 conditionGroup.key值 或 !conditionGroup.key值 两种格式

举例

 

data API

属性说明类型默认值是否必填
name按钮的控件名(支持逗号分隔)string/
show是否显示boolean/stringtrue
enabled是否可以点击boolean/stringfalse
showText按钮名称object[]/
click点击指令集(表格中生效)object[]/
afterClick按钮点击后调用booleanfalse
clickOnly只执行指令集,不执行原先按钮功能booleanfalse
showText API
属性说明类型默认值是否必填
condition条件string/
text按钮显示名称string/

说明

show/enabled的值

填 true/false 时就是固定情况,永远不变

填${xxx}就是根据条件判断显示不显示/可点击不可点击

举例1:顶部工具栏按钮指令集

举例2: 表格按钮指令集

特殊说明

${表名@one.表字段.比较条件.比较内容}

表示:【某表所有选中数据中】【只要有一条数据满足】 【某个字段】【等于/不等于/大于/小于】【比较内容】

${表名@all.表字段.比较条件.比较内容}

表示:【某表所有选中数据中】【所有数据都满足】 【某个字段】【等于/不等于/大于/小于】【比较内容】

 

tab页签显示隐藏 --- btnhandle

API

属性说明类型默认值是否必填
opr指令类型string/
tabs各个tab页签配置object[]/

data API

属性说明类型默认值是否必填
nametab页签名称string/
show是否显示boolean/stringtrue

举例

说明

 

存储过程指令 --- procedure

API

属性说明类型默认值是否必填
opr指令类型string/
config存储过程配置(配置和普通存储过程配置保持一致)object{}/
bRefresh等待刷新后继续执行剩余指令集booleanfalse
bValidateList表单校验object[]/

举例

说明

存储过程指令执行完成后,会刷新页面,页面重新获取数据后再执行剩余指令集

 

跳转tab指令 --- changetab

API

属性说明类型默认值是否必填
opr指令类型string/
tabName需要跳转到的tab名称(中文)string/

举例

 

弹窗修改字段指令 --- poprepair

API

属性说明类型默认值是否必填
opr指令类型string/
title弹窗名称string/
confirmBtnName自定义确认按钮名称string/
fieldNames弹窗展示字段string/
datasetsValue用到的数据集(支持@和逗号分割)string/
sValue给弹窗数据赋默认值string/
srcDataset表单下方按钮弹窗时指定的当前表名(表单时才有用!)string/
formEnabledCondition表单可编辑条件(优先级高于表单的formEnabledCondition)string/

fieldNames说明

表格配置的【字段名】,多个时用英文逗号【,】拼接

举例

calcprocedure指令

API

属性说明类型默认值是否必填
opr指令类型string/
dataset指令传给后台的数据集(默认全部,若要指定,用逗号分隔,例如tabe1,table2)string*
sProName存储过程名称string/
sButtonParamsButtonParam参数string/

举例

 

sValue说明

格式1:newDataset的字段名.srcDataset的字段名 +格式2:newDataset的字段名.简单js运算 // 详见简单js运算 +格式2: var运算

简单js运算说明

dataset说明

作用:condition、sValue做js运算时用到的数据

特点:筛选出的数据只有一条

种类:

  1. 只有数据集名称, 例如:slave,传到运算中的数据为【当前数据集的第一条】

  2. 数据集名称@过滤类型,例如:slave@sec, 传到运算中的数据为【过滤出数据集的第一条】

  3. 数据集名称@parnet过滤类型,例如:slave@parentsec, 传到运算中的数据为【过滤出父页面该数据集的第一条】

 

合计、合并语法(适用于sValue)

合计

${表名@sum保留小数位数.字段名}

表示合计某张表的某个字段的数量,并保留指定位小数

举例:${slave@sum2.dProductPrice} 表示合计slave表的dProductPrice数量,并保留两位小数

 

合并

${表名@merge连接符.字段名}

表示合并某张表的某个字段的值,并用连接符连接

举例:${slave@mergedot.sId} 表示合并slave表的sId的值,并用逗号连接,输出结果类似:"12345,23456'"

连接符类型

连接符名称实际连接符
空(merge.字段名)
dot,
minus-
plus+
divide/
underline_

合并1

${表名@mergequo连接符.字段名}

用法同上

区别,mergequo输出的结果会带单引号,输出结果类似:"'12345','23456'"

 

获取最大值(适用于sValue)

${表名@max.字段名}

举例

 

 

获取表格数据数量(适用于sValue)

${表名@count}

举例

 

获取数组中某个字段分组后的组数

${表名@groupCount.字段名}

举例(适用于sValue)

举例 (适用于condition)

+ + \ No newline at end of file diff --git b/src/component/add.ts a/src/component/add.ts new file mode 100644 index 0000000..abb1933 --- /dev/null +++ a/src/component/add.ts @@ -0,0 +1,12 @@ +// export json 配置 +export const add = (data: any) => ({ + type: "add", + title: "新增", + attrs: [ + { + label: "数据集名称", + name: "desDataset", + type: "input", + } + ] +}); \ No newline at end of file diff --git b/src/constants/common.tsx a/src/constants/common.tsx new file mode 100644 index 0000000..07818ed --- /dev/null +++ a/src/constants/common.tsx @@ -0,0 +1,142 @@ +// 判断条件下拉 +export const CONDITION_DATA = [ + { + label: "等于", + value: "===", + }, + { + label: "不等于", + value: "!=", + }, + + { + label: "大于", + value: ">", + }, + { + label: "小于", + value: "<", + }, + { + label: "大于等于", + value: ">=", + }, + { + label: "小于等于", + value: "<=", + }, + { + label: "包含", + value: "includes", + }, + { + label: "不包含", + value: "!includes", + }, + { + label: "为(空/0)", + value: "empty", + }, + { + label: "不为(空/0)", + value: "!empty", + }, +]; + +// 判断条件下拉 按钮非主表 b类型 +export const CONDITION_DATA_TYPEB = [ + { + label: "全部为true", + value: "trueAll", + }, + { + label: "全部为false", + value: "falseAll", + }, + { + label: "至少一个为true", + value: "trueOne", + }, + { + label: "至少一个为false", + value: "falseOne", + }, +]; + +// 判断条件下拉 按钮非主表 非b类型 +export const CONDITION_DATA_TYPE_NOTB = CONDITION_DATA.reduce((pre, item): any => { + const { label, value } = item; + if (value.includes("includes")) { + return pre; + } + pre.push({ + label: `全部${label}`, + value: `${value}All`, + }); + pre.push({ + label: `至少一个${label}`, + value: `${value}One`, + }); + return pre; +}, []); + +// 且或组件rowValues默认值 +export const INIT_ROW_VALUES = { + pre1: undefined, + value1: "", + condition: undefined, + pre2: undefined, + value2: "", +}; + +// 且或组件表名下拉固定类型 +export const ROW_PRE_OPTIONS = [ + { + label: "字符串", + value: "string", + }, + { + label: "数字", + value: "number", + }, +]; + +// props +export const PROPS_OPTIONS = [ + { + label: "全局变量", + value: "props", + }, +]; + +// 简易筛选数据集 +export const SIMPLE_DATASET_FILTER_OPTIONS = [ + { + label: "全部数据", + value: "", + }, + { + label: "选中数据", + value: "sec", + }, + { + label: "首条数据", + value: "first", + }, + { + label: "末条数据", + value: "last", + }, +]; + +// radio是否选项 +export const RADIO_OPTIONS = [ + { + label: "是", + value: "!empty", + }, + { + label: "否", + value: "empty", + }, +]; diff --git b/src/global.less a/src/global.less new file mode 100644 index 0000000..f2bcd03 --- /dev/null +++ a/src/global.less @@ -0,0 +1,24 @@ +* { + box-sizing: border-box; +} + +html, +body, +#root { + width: 100%; + height: 100%; + padding: 0; + margin: 0; +} + +html { + background: #f6f6f6; +} + +.ant-form-item-extra { + min-height: 0 !important; +} + +.dtc-ruleController__item--operation { + width: 50px !important; +} \ No newline at end of file diff --git b/src/layouts/index.less a/src/layouts/index.less new file mode 100644 index 0000000..2e1d3f8 --- /dev/null +++ a/src/layouts/index.less @@ -0,0 +1,10 @@ +.navs { + ul { + padding: 0; + list-style: none; + display: flex; + } + li { + margin-right: 1em; + } +} diff --git b/src/layouts/index.tsx a/src/layouts/index.tsx new file mode 100644 index 0000000..1b92174 --- /dev/null +++ a/src/layouts/index.tsx @@ -0,0 +1,10 @@ +import { Outlet } from 'umi'; +import { ConfigProvider } from 'antd'; + +export default function Layout() { + return ( + + + + ); +} diff --git b/src/pages/index.less a/src/pages/index.less new file mode 100644 index 0000000..fa167e1 --- /dev/null +++ a/src/pages/index.less @@ -0,0 +1,138 @@ +.indexCard { + height: 100%; + + :global { + .ant-card-body { + padding: 0; + height: calc(100% - 38px); + display: flex; + } + } + + .instructionSet { + width: 200px; + height: 100%; + } + + .instructionContent { + width: calc(100% - 400px); + height: 100%; + } + + .draggableTree { + width: 100%; + overflow: auto; + } + + .instructionResult { + width: 200px; + height: 100%; + } + + .collapseItem { + margin-bottom: 0; + background: transparent; + border-radius: 0; + border: none; + + :global { + .ant-collapse-content-box { + padding: 10px 10px 4px 16px !important; + } + + .ant-form-item { + margin-bottom: 16px; + } + } + } + + .draggableList { + width: 100%; + height: 100%; + overflow-y: auto; + + :global { + .draggable-item { + width: 100%; + min-height: 50px; + border: 1px solid rgba(0, 0, 0, .125); + padding: 20px; + margin-bottom: 4px; + border-radius: 4px; + } + + .draggable-item.lv1 { + background-color: #e6e6e6; + } + + .draggable-item.lv2 { + background-color: #cccccc; + } + + .draggable-item-title { + width: 100%; + height: 40px; + } + } + } + + .settingBtn { + position: absolute; + top: 0; + right: 0; + display: flex; + flex-direction: column; + gap: 4px; + width: 25px; + height: auto; + } + +} + +.draggableItemSelected { + background: rgb(140, 204, 228) !important; +} + +// 下拉颜色 +.code1 { + background-color: rgba(34, 197, 94, 0.2) !important; + margin-bottom: 2px; +} + +.code_1 { + background-color: rgba(239, 68, 68, 0.2) !important; + margin-bottom: 2px; +} + +.code_8 { + background-color: rgba(220, 38, 38, 0.3) !important; + margin-bottom: 2px; +} + +.code2 { + background-color: rgba(234, 179, 8, 0.2) !important; + margin-bottom: 2px; +} + +.code_7 { + background-color: rgba(59, 130, 246, 0.2) !important; +} + +.settingModal { + top: 20px; + left: 10px; + width: auto !important; + + :global { + .ant-modal-content { + margin: 0; + width: calc(100vw - 50px); + height: calc(100vh - 50px); + } + } +} + +// .settingModal { +// width: calc(100vw - 20px); +// height: calc(100vh - 100px); +// } \ No newline at end of file diff --git b/src/pages/index.tsx a/src/pages/index.tsx new file mode 100644 index 0000000..517c4d1 --- /dev/null +++ a/src/pages/index.tsx @@ -0,0 +1,2562 @@ +import { createContext, useReducer, useContext, useEffect, useRef, useState, useMemo } from "react"; +import { + Card, + Collapse, + List, + Form, + Input, + InputNumber, + Button, + Select, + Radio, + Space, + Table, + Checkbox, + Divider, + Modal, + Tree, + message, +} from "antd"; +import { + PlusOutlined, + MinusCircleOutlined, + FileSearchOutlined, + SettingOutlined, +} from "@ant-design/icons"; +import { cloneDeep, cond, set } from "lodash"; +import Sortable from "sortablejs"; +import { FilterRules } from "dt-react-component"; +import styles from "./index.less"; + +import type { InstructionItem, ContextType } from "./type"; +import { shortid } from "../utils/utils"; +import { + CONDITION_DATA, + CONDITION_DATA_TYPEB, + CONDITION_DATA_TYPE_NOTB, + INIT_ROW_VALUES, + ROW_PRE_OPTIONS, + PROPS_OPTIONS, + SIMPLE_DATASET_FILTER_OPTIONS, + RADIO_OPTIONS, +} from "../constants/common"; + +const initValues = { + baseList: [ + { + title: "条件判断", + key: "ifdo", + component: (props: any) => , + }, + { + title: "新增", + key: "add", + component: (props: any) => , + }, + { + title: "修改", + key: "edit", + component: (props: any) => , + bFullMode: true, + }, + { + title: "删除", + key: "del", + component: (props: any) => , + bFullMode: true, + }, + { + title: "复制", + key: "copy", + component: (props: any) => , + bFullMode: true, + }, + { + title: "保存", + key: "save", + component: (props: any) => , + }, + { + title: "过滤", + key: "filter", + component: (props: any) => , + bFullMode: true, + }, + { + title: "创建新数据集", + key: "newempty", + component: (props: any) => , + }, + { + title: "清空数据集", + key: "emptyAll", + component: (props: any) => , + }, + { + title: "刷新数据集", + key: "refresh", + component: (props: any) => , + }, + { + title: "清空选中行", + key: "clearrowkey", + component: (props: any) => , + }, + { + title: "选中表格第一行", + key: "selectfirstline", + component: (props: any) => , + }, + ], + funList: [ + { + title: "打印", + key: "print", + component: (props: any) => , + }, + { + title: "查询sql", + key: "opensql", + component: (props: any) => , + }, + { + title: "执行sql", + key: "exesql", + component: (props: any) => , + }, + { + title: "提示信息", + key: "msg", + component: (props: any) => , + }, + ], + btnsList: [ + { + title: "工具栏按钮配置", + key: "btnhandle", + component: (props: any) => , + }, + ], + instructionList: [], // 步骤列表 + settingPorps: {}, +}; + +const myContext = createContext(null as any); +const reducer = (state: any, action: [any, any]) => { + const [type, payload] = action; + switch (type) { + case "saveState": + return { + ...state, + ...payload, + }; + default: + return { + ...state, + ...payload, + }; + } +}; + +const oThis: any = { + activeJson: {}, +}; + +const convertData2Str = (dataValue: any, bList: boolean) => { + const { type, children = [] } = dataValue; + const childrenFilter = children.filter((child: any) => { + if (child.children?.length) { + return true; + } + if (child.rowValues) { + const { pre1, value1, condition, pre2 } = child.rowValues; + return ( + child.children || + (pre1 === "custom" && value1 !== undefined) || + (pre1 && + condition && + (pre2 || + condition?.includes("empty") || + condition?.includes("All") || + condition?.includes("One"))) + ); + } + return false; + }); + + if (bList) { + const result = [ + ...childrenFilter.map((child: any) => { + if (child.children) { + return convertData2Str(child, bList); + } else { + const { pre1, value1, condition, pre2, value2 } = child.rowValues; + return [pre1, value1, condition, pre2, value2]; + } + }), + type, + ]; + + return result; + } + + return childrenFilter + .map((child: any) => { + if (child.children) { + return `(${convertData2Str(child, bList)})`; + } else { + const { pre1, value1, condition, pre2, value2 } = child.rowValues; + let key1 = ""; + let key2 = ""; + if (pre1 === "number" || pre1 === "boolean") { + key1 = value1; + } else if (pre1 === "string") { + key1 = `'${value1}'`; + } else { + if ( + value1?.startsWith("i") || + value1?.startsWith("d") || + value1?.startsWith("b") || + value1 === "enabled" + ) { + key1 = `\${${pre1}.${value1}}`; + } else { + key1 = `'\${${pre1}.${value1}}'`; + } + } + + if (pre2 === "number" || pre2 === "boolean") { + key2 = value2; + } else if (pre2 === "string") { + key2 = `'${value2}'`; + } else { + if ( + value2?.startsWith("i") || + value2?.startsWith("d") || + value2?.startsWith("b") || + value2 === "enabled" + ) { + key2 = `\${${pre2}.${value2}}`; + } else { + key2 = `'\${${pre2}.${value2}}'`; + } + } + + if (condition === "includes") { + return `${key1}.includes(${key2})`; + } else if (condition === "!includes") { + return `!${key1}.includes(${key2})`; + } else if (condition === "empty") { + return `!${key1}`; + } else if (condition === "!empty") { + return `!!${key1}`; + } else if (condition === "trueAll") { + return `$\{${pre1}@all.${value1}.===.true\}`; + } else if (condition === "trueOne") { + return `$\{${pre1}@one.${value1}.===.true\}`; + } else if (condition === "falseAll") { + return `$\{${pre1}@all.${value1}.===.false\}`; + } else if (condition === "falseOne") { + return `$\{${pre1}@one.${value1}.===.false\}`; + } else if (condition.includes("All")) { + let conditionNew = condition.replace("All", ""); + if (conditionNew === "!empty") { + conditionNew = "!="; + } else if (conditionNew === "empty") { + conditionNew = "=="; + } + return `$\{${pre1}@all.${value1}.${conditionNew}.${value2}\}`; + } else if (condition.includes("One")) { + let conditionNew = condition.replace("One", ""); + if (conditionNew === "!empty") { + conditionNew = "!="; + } else if (conditionNew === "empty") { + conditionNew = "=="; + } + return `$\{${pre1}@one.${value1}.${conditionNew}.${value2}\}`; + } else if (pre1 === "custom") { + return value1; + } else { + return `${key1} ${condition} ${key2}`; + } + } + }) + .join(` ${type === 1 ? "&&" : "||"} `); +}; + +const convertStr2Data = (arr: any, level: number = 1) => { + const type = arr.find((item: any) => typeof item === "number"); + const restArr = arr.filter((item: any) => typeof item !== "number"); + + return { + key: shortid(), + level: level, + type, + children: restArr.map((child: any) => { + if (child.some((item: any) => typeof item === "number")) { + return convertStr2Data(child, level + 1); + } else { + return { + rowValues: { + pre1: child[0], + value1: child[1], + condition: child[2], + pre2: child[3], + value2: child[4], + }, + key: shortid(), + level: level, + }; + } + }), + }; +}; + +// 入口 +const Index = () => { + const [state, dispatch] = useReducer(reducer, initValues); + const setState = (payload: any) => { + dispatch(["saveState", payload]); + }; + + return ( + + + 指令集可视化{" "} + { + const screenWidth = window.screen.width; + const screenHeight = window.screen.height; + window.open( + location.origin + "/InsSet/指令集说明文档.html", + "指令集说明文档", + `width=${screenWidth},height=${screenHeight},left=0,top=0` + ); + }} + /> + + } + className={styles.indexCard} + > + + + + + + + + + + + + + ); +}; + +// 左侧列表区域 +const InstructionSetList = () => { + const { tableName, sFieldName, baseList, funList, btnsList, instructionList, setState } = + useContext(myContext); + + const addInstruction = (item: any) => { + instructionList.push({ ...item, type: item.key, key: shortid(), mode: "easy" }); + setState({ instructionList }); + }; + + const ListItem = (item: any) => { + return ( + + {item.title} + + ); + }; + + let items = []; + + if (tableName === "master" && sFieldName === "sInstruct") { + items = [ + { + key: "3", + label: "按钮指令集", + children: ListItem(item)} />, + className: styles.collapseItem, + }, + ]; + } else { + items = [ + { + key: "1", + label: " 基础指令集", + children: ListItem(item)} />, + className: styles.collapseItem, + }, + { + key: "2", + label: "功能指令集", + children: ListItem(item)} />, + className: styles.collapseItem, + }, + ]; + } + + return ( + + ); +}; + +const getTargetParentAndIndex = ( + arr: InstructionItem[], + path: number[] +): { parentArr: InstructionItem[]; targetIndex: number; targetItem: InstructionItem } | null => { + let current: any = { children: arr }; + for (let i = 0; i < path.length - 1; i++) { + const index = path[i]; + if (!Array.isArray(current.children) || !current.children[index]) return null; + current = current.children[index]; + } + const targetIndex = path[path.length - 1]; + const parentArr = current.children || []; + const targetItem = parentArr[targetIndex]; + return { parentArr, targetIndex, targetItem }; +}; + +const updateInstructionListByMove = ( + instructionList: InstructionItem[], + fromPath: number[], // 被移动项的原始路径,如 [0, 1, 1] + toPath: number[], // 目标插入位置路径,如 [0, 1, 2] + insertIndex: number // 插入到该层级下的哪个索引 +): InstructionItem[] => { + const deepClone = cloneDeep(instructionList) as InstructionItem[]; + + // Step 1: 获取要删除的节点及其父级数组和索引 + const deleteInfo = getTargetParentAndIndex(deepClone, fromPath); + + if (!deleteInfo) return instructionList; + + const { parentArr: deleteParent, targetIndex: deleteIndex, targetItem } = deleteInfo; + + // Step 2: 删除节点 + const deletedItem = deleteParent.splice(deleteIndex, 1)[0]; + + // Step 3: 获取插入位置的父级数组 + const insertInfo = getTargetParentAndIndex(deepClone, toPath); + if (!insertInfo) return instructionList; + + const { parentArr: insertParent } = insertInfo; + + // Step 4: 插入节点到指定位置 + insertParent.splice(insertIndex, 0, deletedItem); + + return deepClone; +}; + +const InstructionContent = () => { + const { instructionList, setState } = useContext(myContext); + + const [treeData, setTreeData] = useState([]); + useEffect(() => { + const treeData = instructionList.map(item => { + // 递归处理子节点 + const processChildren = (nodeItem: any): any => { + const treeNode: any = { + title: , + key: nodeItem.key, + // 只有特定类型的节点才允许添加子节点,比如"条件判断" + bDropTo: nodeItem.title === "条件判断" || nodeItem.type === "ifdo", + }; + + // 如果有子节点,递归处理 + if (nodeItem.children && nodeItem.children.length > 0) { + treeNode.children = nodeItem.children.map((child: any) => processChildren(child)); + } + + return treeNode; + }; + + return processChildren(item); + }) as any; + + setTreeData(treeData); + }, [JSON.stringify(instructionList)]); + + const [expandedKeys, setExpandedKeys] = useState([]); + const onDrop = (info: any) => { + const dropKey = info.node.key; + const dragKey = info.dragNode.key; + const dropPos = info.node.pos.split("-"); + const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]); + + // 如果节点被放入另一个节点内部,则将其加入展开列表 + if (!info.dropToGap) { + setExpandedKeys(prev => [...new Set([...prev, dropKey])]); + } + + // 克隆当前 instructionList + const newData = cloneDeep(instructionList); + + // 查找拖拽节点和目标节点 + let dragItem: any = null; + let dragParent: any[] = newData; + let dragIndex = -1; + + const findDragItem = (items: any[], parent: any[], index: number) => { + for (let i = 0; i < items.length; i++) { + if (items[i].key === dragKey) { + dragItem = items[i]; + dragParent = parent; + dragIndex = i; + return true; + } + if (items[i].children) { + if (findDragItem(items[i].children, items[i].children, i)) { + return true; + } + } + } + return false; + }; + + findDragItem(newData, newData, -1); + + // 从原位置删除拖拽节点 + if (dragItem) { + dragParent.splice(dragIndex, 1); + } + + // 查找目标节点并插入 + if (!info.dropToGap) { + // 插入为子节点 + const insertIntoChildren = (items: any[]) => { + for (let i = 0; i < items.length; i++) { + if (items[i].key === dropKey) { + if (!items[i].children) { + items[i].children = []; + } + items[i].children.unshift(dragItem); + return true; + } + if (items[i].children) { + if (insertIntoChildren(items[i].children)) { + return true; + } + } + } + return false; + }; + + insertIntoChildren(newData); + } else { + // 插入为兄弟节点 + const insertAsSibling = (items: any[]) => { + for (let i = 0; i < items.length; i++) { + if (items[i].key === dropKey) { + const parent = items === newData ? newData : items; + const dropIndex = parent.indexOf(items[i]); + const insertIndex = dropPosition === -1 ? dropIndex : dropIndex + 1; + parent.splice(insertIndex, 0, dragItem); + return true; + } + if (items[i].children) { + if (insertAsSibling(items[i].children)) { + return true; + } + } + } + return false; + }; + + insertAsSibling(newData); + } + + // 更新 instructionList + setState({ instructionList: newData }); + }; + + return ( + { + // 根据节点的自定义属性判断 + if (info.dropPosition === 0) { + const { bDropTo } = info.dropNode; + return !!bDropTo; + } + return true; + }} + blockNode + showLine + onDrop={onDrop} + treeData={treeData} + /> + ); +}; + +// 中间内容区域 +const InstructionContent1 = () => { + const { instructionList, setState } = useContext(myContext); + + const listRef = useRef(null); + const instructionListRef = useRef(null); + + useEffect(() => { + instructionListRef.current = instructionList; + }, [JSON.stringify(instructionList)]); + + useEffect(() => { + const oDom = listRef.current as HTMLElement; + new Sortable(oDom, { + group: "instructionGroup", // 分组 + animation: 150, // 动画时间 + ghostClass: styles.draggableItemSelected, // 移动行样式 + handle: ".ant-collapse-header", + draggable: ".draggable-item", + onEnd: evt => { + const { from, to, oldIndex, newIndex, item } = evt; + + // 根据item的data-id获取数据并删除 + const dataId = item.getAttribute("data-id") as String; + const fromPath = dataId + .split("-") + .filter((_, index) => index > 0) + .map(Number); + + // 根据to的data-id获取数据并添加到newIndex位置 + const toDataId = to.getAttribute("data-id") as String; + const toPath = toDataId.split("-").map(Number); + + const instructionListNew = updateInstructionListByMove( + instructionListRef.current, + fromPath, + toPath, + newIndex as number + ); + setState({ instructionList: instructionListNew }); + }, + }); + }, []); + + const RecursiveItem = ({ item, level, index }: { item: any; level: number; index: number }) => { + const currentLevelClass = `draggable-item lv${level}`; + const dataId = `${level - 1}-${index}`; + + return ( +
+ + {item.children && item.children.length > 0 && ( +
+ {item.children.map((child: any, index1: number) => ( + + ))} +
+ )} +
+ ); + }; + + return ( +
+ {instructionList.map((item: any, index) => ( + + ))} +
+ ); +}; + +// 中间内容区域-具体组件 +const InstructionDetail = (props: any) => { + const { item, dataId } = props; + + const contentData = useContext(myContext); + const { instructionList, setState } = contentData; + + const [activeKey, setActiveKey] = useState(oThis.activeJson[item.key] || [item.key]); + const setInstructionMode = (value: string) => { + const { instructionListNew, targetItem } = handleGetChangeData({ ...contentData, ...props }); + targetItem.mode = value; + setState({ instructionList: instructionListNew }); + }; + let lableTitle = item.content?.desDataset || item.content?.srcDataset; + if (item.type === "print") { + lableTitle = `${item.content?.reportName || ""}${item.content?.reportType || ""}`; + } + let label = `${item.title}${lableTitle ? `【${lableTitle}】` : ""}`; + + if (item.type === "opensql") { + label = `${item.title}${ + item.content?.newDataset ? `-> 保存到【${item.content.newDataset}】` : "" + }`; + } + + return ( +
+ { + setTimeout(() => { + if (oThis.changeMode) { + oThis.changeMode = false; + return; + } + setActiveKey(keys); + oThis.activeJson[item.key] = keys; + }, 10); + }} + items={[ + { + key: item.key, + label, + extra: ( + + {item.bFullMode && ( + { + oThis.changeMode = true; + setInstructionMode(e.target.value); + }} + /> + )} + + + + ), + children: item.component(props), + }, + ]} + /> +
+ ); +}; + +// 右侧结果区域 +const InstructionResult = () => { + const { + instructionList, + setState, + baseList, + funList, + btnsList, + configList = [], + srcModelsList = [], + } = useContext(myContext); + + const outputContent = instructionList + .filter(item => item.content) + .map(item => { + if (item.children && item.children.length > 0) { + const processChildren = (children: any[]): any[] => { + return children + .map(child => { + if (child.content) { + if (child.children && child.children.length > 0) { + return { + ...child.content, + conditions: [ + { + condition: child.content.condition, + commands: processChildren(child.children), + }, + ], + }; + } + return child.content; + } + return null; + }) + .filter(Boolean); + }; + + return { + ...item.content, + conditions: [ + { + condition: item.content.condition, + commands: processChildren(item.children), + }, + ], + }; + } + + return item.content; + }); + + useEffect(() => { + if (!configList.length) return; + + const configOptions = configList.map((item: any) => ({ + label: item.showName, + value: item.tableName, + tableName: item.sTbName, + })); + const configValueOptions = configList.reduce((pre: any, cur: any) => { + pre[cur.tableName] = cur.gdsconfigformslave + .filter((x: any) => x.sName && x.showName && !x.sControlName?.startsWith("Btn")) + .map((x: any) => ({ label: x.showName, value: x.sName })); + return pre; + }, {}); + + const propsOptions = [ + { + label: "是否可编辑", + value: "enabled", + }, + { + label: "模块id", + value: "sSrcModelsId", + }, + ]; + + configValueOptions.props = propsOptions; + + let srcModelsOptions = []; + if (srcModelsList.length) { + const showKey = Object.keys(srcModelsList[0])[0]; + srcModelsOptions = srcModelsList.map((x: any) => ({ + label: x[showKey], + value: x.sId, + })); + } + + setState({ configOptions, configValueOptions, srcModelsOptions }); + }, [configList.length]); + + const onReceiveData = (event: any) => { + // 验证来源 + if (!document.referrer.includes(event.origin)) { + return; + } + + // 处理接收到的命令 + if (event.data.command === "initData") { + const value = event.data.value || []; + + // 执行相应操作 + setState({ + tableName: event.data.tableName, + sFieldName: event.data.sFieldName, + slave0Data: event.data.slave0Data, + configList: event.data.configList, + srcModelsList: event.data.srcModelsList, + instructionList: value.map((item: any) => { + const allList = [...baseList, ...funList, ...btnsList]; + const config = allList.find(listItem => listItem.key === item.opr); + // const bFullMode = item.bFullMode; + // delete item.bFullMode; + const result = { + ...config, + type: config?.key, + key: shortid(), + mode: "full", + content: item, + }; + // if (bFullMode) { + // result.bFullMode = true; + // } + return result; + }), + }); + } + }; + + useEffect(() => { + window.addEventListener("message", onReceiveData); + try { + window.parent.postMessage( + { + command: "initData", + }, + document.referrer + ); + } catch (error) {} + return () => { + window.removeEventListener("message", onReceiveData); + }; + }, []); + // 复制到剪贴板 + const handleCopy = (bZip: boolean) => { + const value = bZip ? JSON.stringify(outputContent) : JSON.stringify(outputContent, null, 2); + navigator.clipboard.writeText(value); + }; + + const handleSave = () => { + window.parent.postMessage( + { + command: "saveData", + data: outputContent, + }, + document.referrer + ); + }; + + return ( +
+ + + + {/* */} + + +
+ ); +}; + +const FormIfdo = (props: any) => { + const [formProps, commonProps] = useFormCommon(props); + const { form } = commonProps; + const conditionType = Form.useWatch("conditionType", form) || "0"; + + return ( + <> +
+ + + + {conditionType === "0" && } + {conditionType === "0" ? ( + + ) : conditionType === "1" ? ( + + ) : ( + + )} + + + + ); +}; + +// 新增 +const FormAdd = (props: any) => { + const [formProps, commonProps] = useFormCommon(props); + return ( +
+ + + + + + ); +}; + +// 编辑 +const FormEdit = (props: any) => { + const [formProps, commonProps] = useFormCommon(props); + const bFullMode = props.item.mode === "full"; + return ( +
+ + + {bFullMode && } + + + + ); +}; + +// 删除 +const FormDel = (props: any) => { + const [formProps, commonProps] = useFormCommon(props); + const bFullMode = props.item.mode === "full"; + return ( +
+ + {bFullMode && } + {bFullMode && } + + + ); +}; + +// 复制 +const FormCopy = (props: any) => { + const [formProps, commonProps] = useFormCommon(props); + const bFullMode = props.item.mode === "full"; + return ( +
+ + + {bFullMode && } + {bFullMode && } + + + ); +}; + +// 保存 +const FormSave = (props: any) => { + const [formProps, commonProps] = useFormCommon(props); + const { form, configOptions = [] } = commonProps; + const saveType = Form.useWatch("saveType", form); + const data = Form.useWatch("data", form) || []; + + return ( +
+ + + + {saveType === "saveCustom" && ( + <> + + {(fields, { add, remove }) => ( + <> + {fields.map(field => { + const srcDataset = data[field.name]?.srcDataset; + const selectValue = configOptions.some((item: any) => item.value === srcDataset) + ? srcDataset + : "custom"; + return ( + + + { + // 给Input赋值 + form.setFieldsValue({ + data: form.getFieldValue("data").map((item: any, index: number) => + index === field.name + ? { + ...item, + srcDataset: value === "custom" ? "" : value, + tablename: option.tableName || "", + } + : item + ), + }); + }} + /> + } + /> + + + + + remove(field.name)} /> + + ); + })} + + + + + + )} + + + + + + )} + + + ); +}; + +// 过滤 +const FormFilter = (props: any) => { + const [formProps, commonProps] = useFormCommon(props); + const bFullMode = props.item.mode === "full"; + return ( +
+ + + {bFullMode && } + {bFullMode && } + + + ); +}; + +// 创建新数据集 +const FormNewempty = (props: any) => { + const [formProps, commonProps] = useFormCommon(props); + const radioValue = + Form.useWatch("radioValue", formProps.form) || + (props.item.content?.desDataset ? "desDataset" : "") || + "srcDataset"; + return ( +
+ + { + formProps.form.setFieldValue("radioValue", e.target.value); + }} + /> + + + {radioValue === "srcDataset" ? ( + + ) : ( + + )} + + + ); +}; + +// 清空数据集 +const FormEmptyAll = (props: any) => { + const [formProps, commonProps] = useFormCommon(props); + return ( +
+ + + + ); +}; + +// 刷新数据集 +const FormRefresh = (props: any) => { + const [formProps, commonProps] = useFormCommon(props); + return ( +
+ + + + ); +}; + +// 清空选中行 +const FormClearRowKey = (props: any) => { + const [formProps, commonProps] = useFormCommon(props); + return ( +
+ + + + ); +}; + +// 选中表格第一行 +const FormSelectFirstLine = (props: any) => { + const [formProps, commonProps] = useFormCommon(props); + return ( +
+ + + + ); +}; + +// 打印 +const FormPrint = (props: any) => { + const [formProps, commonProps] = useFormCommon({ + ...props, + formPreFuc: (values: any) => { + return { + ...values, + srcDataset: values.srcDataset?.split(",").filter((item: any) => item), + }; + }, + }); + return ( +
+ + + + + + + ); +}; + +// 查询sql +const FormOpenSql = (props: any) => { + const [formProps, commonProps] = useFormCommon(props); + return ( +
+ + + + + + + ); +}; + +// 执行sql +const FormExesql = (props: any) => { + const [formProps, commonProps] = useFormCommon(props); + return ( +
+ + + + + ); +}; + +// 消息提示 +const FormMsg = (props: any) => { + const [formProps, commonProps] = useFormCommon(props); + const { form } = commonProps; + const codeValue = Form.useWatch("code", form); + + return ( +
+ + { + form.submit(); + }} + /> + + + + + + } + > + + + + + + + } + > + + + + ))} + + + + + + )} + + + + ); +}; + +const SettingModal = () => { + const { setState, settingPorps } = useContext(myContext); + const { open, index, name, conditionData } = settingPorps; + + if (!open) return ""; + + const initData = { + key: shortid(), + level: 1, + type: 1, + children: [ + { + rowValues: INIT_ROW_VALUES, + key: shortid(), + level: 1, + }, + ], + }; + + const [data, setData] = useState( + conditionData ? convertStr2Data(JSON.parse(conditionData)) : initData + ); + const onCancel = () => { + setState({ settingPorps: { open: false } }); + }; + + const onOk = () => { + const condition = convertData2Str(data, false); + + const conditionData = JSON.stringify(convertData2Str(data, true)); + setState({ settingPorps: { open: false, condition, conditionData, index, name } }); + }; + + return ( + + + + + } + onCancel={onCancel} + > + } + value={data} + onChange={(value: any) => { + let valueNew = cloneDeep(value); + if (!valueNew) { + valueNew = initData; + } else if (!valueNew.children) { + valueNew = { + key: shortid(), + level: 1, + type: 1, + children: [value], + }; + } else if (!valueNew.children.length) { + valueNew = initData; + } + setData(valueNew); + }} + initValues={INIT_ROW_VALUES} + notEmpty={{ data: false }} + /> + + ); +}; + +const useFormCommon = (props: any) => { + const { ...rest } = useContext(myContext); + const [form] = Form.useForm(); + useEffect(() => { + const { item, formPreFuc } = props; + const { content = {} } = item; + const { dataset, data } = content; + let initValue = { + ...content, + dataset: dataset?.split(",").filter((item: any) => item), + }; + if (data?.length) { + initValue.data = data.map((item: any) => { + if (item.name && typeof item.name === "string") { + return { ...item, name: item.name.split(",").filter((item: any) => item) }; + } + return item; + }); + } + if (formPreFuc) { + initValue = formPreFuc(initValue); + } + form.setFieldsValue(initValue); + }, []); + + const commonProps = { + ...props, + ...rest, + form, + }; + const onFinish = () => { + handleUpdateData({ ...commonProps }); + }; + + const formProps = { + form, + labelCol: { flex: "150px" }, + wrapperCol: { flex: "auto" }, + autoComplete: "off", + onFinish, + }; + return [formProps, commonProps]; +}; + +const CommonInput = (props: any) => { + const { + form, + sName = "desDataset", + sLabel = "数据集名称", + bMuti, + bFilter, + bArea, + noAddonBefore, + extraProps = {}, + configOptions = [], + } = props; + + let inputValue = Form.useWatch(sName, form) || []; + inputValue = inputValue.toString() || ""; + + const [valueFilter, afterValue = ""] = inputValue.split("@"); + + return ( + <> + {bMuti && ( + + {">>"}}> + { + let result = valueFilter; + if (value) { + result += `@${value}`; + } + form.setFieldValue(sName, result); + }} + /> + )} + + ) + } + // addonAfter={ + + // } + {...extraProps} + /> + )} + + + ); +}; + +const CommonInputNumber = (props: any) => { + const { sName = "time", sLabel = "时间", bMust = false, extraProps = {} } = props; + return ( + + + + ); +}; + +const CommonCheckBox = (props: any) => { + const { sName = "", sLabel = "", extraProps = {} } = props; + return ( + + {sLabel} + + ); +}; + +const CommonSelect = (props: any) => { + const { sName = "reportType", sLabel = "报表类型", options = [] } = props; + return ( + + setSearchValue(value)} + onChange={() => { + setSearchValue(""); + }} + options={options} + filterSort={(optionA: any, optionB: any) => { + const valueA = optionA.value.split("@")[0]; + const valueB = optionB.value.split("@")[0]; + const bType1 = option0.some((item: any) => item.value === valueA); + const bType2 = option0.some((item: any) => item.value === valueB); + + if (bType1 && !bType2) { + return -1; + } + + if (bType2 && !bType1) { + return 1; + } + + if (bType1 && bType2) { + return ( + option0.findIndex((item: any) => item.value === valueA) - + option0.findIndex((item: any) => item.value === valueB) + ); + } + + if (!bType1 && !bType2) { + return ( + selectedValues.findIndex((item: any) => item === optionA.value) - + selectedValues.findIndex((item: any) => item === optionB.value) + ); + } + + return 1; + }} + optionRender={option => { + const value0 = option.value as string; + const [label, type = ""] = value0.split("@"); + const labelNew = + option0.find((item: { value: string }) => item.value === label)?.label || label; + + return ( + +
{labelNew}
+ {SIMPLE_DATASET_FILTER_OPTIONS.filter(item => !onlyAllData || !item.value) + .map(item => ({ + title: item.label, + type: item.value, + })) + .map(item => ( + + ))} +
+ ); + }} + /> +
+ ); +}; + +const CommonSValue = (props: any) => { + const { form } = props; + + const dataset = Form.useWatch("dataset", form); + const datasetList = dataset + ? dataset.map((item: any) => ({ + value: item.split("@")[0], + label: item.split("@")[0], + })) + : []; + + const sValue = Form.useWatch("sValue", form); + const tableData = sValue + ? sValue.split(",").map((item: any, index: number) => { + if (item === "*") { + return { + iRowNum: index + 1, + sFieldNameNew: "", + sFieldNameOldPre: "*", + sFieldNameOld: "", + }; + } + + if (item.includes(".*")) { + const sFieldNameOldPre = item.split(".*")[0]; + return { + iRowNum: index + 1, + sFieldNameNew: "", + sFieldNameOldPre, + sFieldNameOld: "*", + }; + } + + const [sFieldNameNew, sFieldNameOld0 = ""] = item.split(":"); + let [sFieldNameOldPre, sFieldNameOld] = [undefined as any, ""]; + if (sFieldNameOld0.includes("$") || sFieldNameOld0.includes("var")) { + [sFieldNameOldPre, sFieldNameOld] = ["var", sFieldNameOld0]; + } else if (sFieldNameOld0.includes(".")) { + [sFieldNameOldPre, sFieldNameOld] = sFieldNameOld0.split("."); + } else if (sFieldNameOld0.includes("'")) { + [sFieldNameOldPre, sFieldNameOld] = ["string", sFieldNameOld0.replace(/'/g, "")]; + } else if (sFieldNameOld0 !== "") { + [sFieldNameOldPre, sFieldNameOld] = ["number", sFieldNameOld0]; + } else { + [sFieldNameOldPre, sFieldNameOld] = [undefined, ""]; + } + + return { + iRowNum: index + 1, + sFieldNameNew, + sFieldNameOldPre, + sFieldNameOld, + }; + }) + : []; + + const handleChangeValue = (record: any) => { + const sValueList = sValue.split(","); + const { sFieldNameOldPre, index } = record; + + if (sFieldNameOldPre === "*") { + sValueList[index] = "*"; + } else if (sFieldNameOldPre === "number") { + sValueList[index] = `${record.sFieldNameNew || ""}:${Number(record.sFieldNameOld) || 0}`; + } else if (sFieldNameOldPre === "string") { + sValueList[index] = `${record.sFieldNameNew || ""}:'${record.sFieldNameOld || ""}'`; + } else if (sFieldNameOldPre === "var") { + sValueList[index] = `${record.sFieldNameNew || ""}:${record.sFieldNameOld || "${}"}`; + } else if (sFieldNameOldPre) { + sValueList[index] = `${record.sFieldNameNew || ""}${ + record.sFieldNameOld !== "*" ? ":" : "" + }${sFieldNameOldPre}.${record.sFieldNameOld || ""}`; + } else { + sValueList[index] = `${record.sFieldNameNew || ""}:`; + } + form.setFieldValue("sValue", sValueList.toString()); + }; + + return ( + <> + + + + + { + return ( + { + handleChangeValue({ ...record, sFieldNameNew: event.target.value, index }); + }} + /> + ); + }, + }, + { + title: "源字段", + width: "auto", + dataIndex: "sFieldNameOld", + render: (text: string, record: any, index: number) => { + return ( + { + handleChangeValue({ ...record, sFieldNameOld: event.target.value, index }); + }} + addonBefore={ + { + return ( + + {label}({value}) + + ); + }} + value={pre1} + showSearch + filterOption={(inputValue, option) => { + const condition1 = + option?.value?.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1; + const condition2 = + option?.label?.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1; + return condition1 || condition2; + }} + onChange={value => handleChangeValue(value, "pre1")} + /> + } + addonAfter={ + !bCustom && ( + { + const condition1 = + option?.value?.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1; + const condition2 = + option?.label?.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1; + return condition1 || condition2; + }} + onChange={value => handleChangeValue(value, "condition")} + /> + handleChangeValue(value, "pre2")} + /> + } + value={value2} + onChange={e => handleChangeValue(e.target.value, "value2")} + {...(() => { + if (bModelsId) { + return { + addonAfter: ( +