diff --git a/packages/plugins/@hera/plugin-core/src/client/features/field-appends/index.ts b/packages/plugins/@hera/plugin-core/src/client/features/field-appends/index.ts
index bcd689bad..e3fb946a7 100644
--- a/packages/plugins/@hera/plugin-core/src/client/features/field-appends/index.ts
+++ b/packages/plugins/@hera/plugin-core/src/client/features/field-appends/index.ts
@@ -1,12 +1,16 @@
import { Plugin } from '@tachybase/client';
-import { SCFormula, ShowFieldFormulaInterface } from './show-formula/Formula.interface';
+import { ShowFieldCodeInterface } from './show-code/Code.interface';
+import { ViewCode } from './show-code/Code.view';
+import { ShowFieldFormulaInterface } from './show-formula/Formula.interface';
+import { ViewFormula } from './show-formula/Formula.view';
export class PluginFieldAppends extends Plugin {
- async afterAdd() {
- this.app.pm.add(SCFormula);
- }
async load() {
- this.app.dataSourceManager.addFieldInterfaces([ShowFieldFormulaInterface]);
+ this.app.addComponents({
+ Viewformula: ViewFormula,
+ ViewCode: ViewCode,
+ });
+ this.app.dataSourceManager.addFieldInterfaces([ShowFieldFormulaInterface, ShowFieldCodeInterface]);
}
}
diff --git a/packages/plugins/@hera/plugin-core/src/client/features/field-appends/show-code/Code.interface.ts b/packages/plugins/@hera/plugin-core/src/client/features/field-appends/show-code/Code.interface.ts
index e69de29bb..c956fc751 100644
--- a/packages/plugins/@hera/plugin-core/src/client/features/field-appends/show-code/Code.interface.ts
+++ b/packages/plugins/@hera/plugin-core/src/client/features/field-appends/show-code/Code.interface.ts
@@ -0,0 +1,75 @@
+import { CollectionFieldInterface, interfacesProperties, Plugin } from '@tachybase/client';
+
+const { defaultProps } = interfacesProperties;
+
+export interface CodeFieldProps {
+ // 代码字符串
+ jsCode: string;
+ // 前缀
+ prefix: string;
+ // 后缀
+ suffix: string;
+ // 精度
+ decimal: string;
+}
+
+export class ShowFieldCodeInterface extends CollectionFieldInterface {
+ name = 'codeShow';
+ type = 'object';
+ group = 'advanced';
+ title = 'jsCode(显示)';
+ description = '通过jsCode, 用于定制化显示用户界面内容';
+ sortable = true;
+ default = {
+ type: 'virtual',
+ uiSchema: {
+ type: 'string',
+ 'x-component': 'ViewCode',
+ 'x-component-props': {
+ jsCode: '',
+ prefix: '',
+ suffix: '',
+ decimal: '',
+ } as CodeFieldProps,
+ 'x-read-pretty': true,
+ },
+ };
+ properties = {
+ ...defaultProps,
+ 'uiSchema.x-component-props.prefix': {
+ type: 'string',
+ title: '前缀',
+ 'x-decorator': 'FormItem',
+ 'x-component': 'Input',
+ },
+ 'uiSchema.x-component-props.suffix': {
+ type: 'string',
+ title: '后缀',
+ 'x-decorator': 'FormItem',
+ 'x-component': 'Input',
+ },
+ 'uiSchema.x-component-props.decimal': {
+ type: 'string',
+ title: '{{t("Precision")}}',
+ 'x-component': 'Select',
+ 'x-decorator': 'FormItem',
+ default: '0',
+ enum: [
+ { value: '0', label: '1' },
+ { value: '1', label: '1.0' },
+ { value: '2', label: '1.00' },
+ { value: '3', label: '1.000' },
+ { value: '4', label: '1.0000' },
+ { value: '5', label: '1.00000' },
+ ],
+ },
+ 'uiSchema.x-component-props.jsCode': {
+ type: 'string',
+ title: 'JSCode',
+ 'x-decorator': 'FormItem',
+ 'x-component': 'Input.TextArea',
+ default: '',
+ required: true,
+ },
+ };
+}
diff --git a/packages/plugins/@hera/plugin-core/src/client/features/field-appends/show-code/Code.view.tsx b/packages/plugins/@hera/plugin-core/src/client/features/field-appends/show-code/Code.view.tsx
new file mode 100644
index 000000000..20185b3cd
--- /dev/null
+++ b/packages/plugins/@hera/plugin-core/src/client/features/field-appends/show-code/Code.view.tsx
@@ -0,0 +1,109 @@
+import React, { useEffect, useState } from 'react';
+import { Input } from '@tachybase/client';
+import { useField, useFieldSchema, useForm } from '@tachybase/schema';
+
+import { Descriptions } from 'antd';
+import _ from 'lodash';
+
+import { CodeFieldProps } from './Code.interface';
+
+export const ViewCode = (props: CodeFieldProps) => {
+ const resultShowValue = useAction(props);
+ if (typeof resultShowValue === 'string') {
+ return ;
+ } else {
+ return <>{resultShowValue}>;
+ }
+};
+
+const ShowValue = React.memo((props: { value: string }) => {
+ const { value } = props;
+ return ;
+});
+
+function useAction(props: CodeFieldProps): string | React.ReactNode {
+ const form = useForm();
+ const fieldSchema = useFieldSchema();
+ const field = useField();
+ const { jsCode, prefix, suffix, decimal } = props;
+
+ const path: any = field.path.entire;
+ const fieldPath = path?.replace(`.${fieldSchema.name}`, '');
+ const recordData = _.chain(form.values).get(fieldPath).value();
+
+ const [result, setResult] = useState({
+ items: [],
+ childrenType: '',
+ });
+
+ const formatFunc = (value: string | number): string => {
+ let main = value;
+ if (typeof value === 'number') {
+ main = isNaN(value) ? value : Number(value).toFixed(+decimal || 0);
+ }
+ return `${prefix}${main}${suffix}`;
+ };
+ useEffect(() => {
+ dynamicCode({ jsCode, form, path, recordData, result }, { setResult, formatFunc });
+ }, []);
+
+ const showItems = result.items.map((item) => {
+ return {
+ label: item.label,
+ children: {item.children}
,
+ };
+ });
+
+ if (result.childrenType === 'normal') {
+ return ;
+ } else if (result.childrenType === 'jsx') {
+ return <>{result?.items?.map((item) => item.children)}>;
+ } else {
+ return result.items?.[0]?.children;
+ }
+}
+
+async function dynamicCode({ jsCode, form, path, recordData, result }, { setResult, formatFunc }) {
+ try {
+ eval(jsCode);
+ // NOTE: 示例代码, 仿照此例配置即可
+ // {
+ // import('dayjs')
+ // .then((module) => {
+ // // 使用加载的模块
+ // const dayjs = module.default; // 假设模块默认导出了一个函数
+ // const localeSetting = { invalidDate: '-' };
+ // dayjs.updateLocale('en', localeSetting);
+ // const date_pay = form.getValuesIn(path.replace('.date_fix', '.date_pay'));
+
+ // const date_receive = form.getValuesIn(path.replace('.date_fix', '.date_receive'));
+ // const date_show = date_pay || date_receive;
+
+ // const formartedDate = dayjs(date_show ?? '-').format('YYYY-MM-DD');
+ // setResult({
+ // childrenType: 'jsx',
+ // items: [
+ // {
+ // children: formartedDate,
+ // },
+ // ],
+ // });
+ // })
+ // .catch((error) => {
+ // // 处理加载模块时的错误
+ // console.error('Failed to load module:', error);
+ // });
+ // }
+ } catch (error) {
+ setResult({
+ childrenType: '',
+ items: [
+ {
+ key: '1',
+ label: '数据异常',
+ children: '请检查字段配置内容,error:' + error,
+ },
+ ],
+ });
+ }
+}
diff --git a/packages/plugins/@hera/plugin-core/src/client/features/field-appends/show-formula/Formula.interface.ts b/packages/plugins/@hera/plugin-core/src/client/features/field-appends/show-formula/Formula.interface.ts
index 34ad534e3..9b9aa4d0c 100644
--- a/packages/plugins/@hera/plugin-core/src/client/features/field-appends/show-formula/Formula.interface.ts
+++ b/packages/plugins/@hera/plugin-core/src/client/features/field-appends/show-formula/Formula.interface.ts
@@ -1,6 +1,4 @@
-import { CollectionFieldInterface, interfacesProperties, Plugin } from '@tachybase/client';
-
-import { ViewFormula } from './Formula.view';
+import { CollectionFieldInterface, interfacesProperties } from '@tachybase/client';
const { defaultProps } = interfacesProperties;
@@ -15,14 +13,6 @@ export interface FormulaProps {
decimal: string;
}
-export class SCFormula extends Plugin {
- async load() {
- this.app.addComponents({
- Viewformula: ViewFormula,
- });
- }
-}
-
export class ShowFieldFormulaInterface extends CollectionFieldInterface {
name = 'formulaShow';
type = 'object';
diff --git a/packages/plugins/@hera/plugin-core/src/client/features/field-appends/show-formula/Formula.view.tsx b/packages/plugins/@hera/plugin-core/src/client/features/field-appends/show-formula/Formula.view.tsx
index 293bde3cf..448a1a090 100644
--- a/packages/plugins/@hera/plugin-core/src/client/features/field-appends/show-formula/Formula.view.tsx
+++ b/packages/plugins/@hera/plugin-core/src/client/features/field-appends/show-formula/Formula.view.tsx
@@ -3,100 +3,122 @@ import { Input } from '@tachybase/client';
import { evaluators } from '@tachybase/evaluators/client';
import { useField, useFieldSchema, useForm } from '@tachybase/schema';
+import _ from 'lodash';
+
import { FormulaProps } from './Formula.interface';
export const ViewFormula = (props: FormulaProps) => {
const { resultShowValue } = useAction(props);
- return ;
+ return ;
};
+const ShowValue = React.memo((props: { value: string }) => {
+ const { value } = props;
+ return ;
+});
+
function useAction(props: FormulaProps) {
const form = useForm();
const fieldSchema = useFieldSchema();
const field = useField();
+
const { formulaString, prefix, suffix, decimal } = props;
const path: any = field.path.entire;
const fieldPath = path?.replace(`.${fieldSchema.name}`, '');
+ const recordData = _.chain(form.values).get(fieldPath).value();
+
+ const formulaArry = transformFormula(formulaString);
+
+ const evaluateArray = getEvaluateArray(formulaArry, recordData);
+ if (!evaluateArray) {
+ return { resultShowValue: '' };
+ } else {
+ const resultShowValue = getResultShowValue(evaluateArray, { prefix, suffix, decimal });
+ return { resultShowValue };
+ }
+}
+
+function transformFormula(formula: string) {
+ if (!formula) {
+ return [];
+ }
+ const formulaArray = formula.split(/([+\-*/?:()%])/).filter((item) => item);
+ return formulaArray;
+}
+
+function getEvaluateArray(formulaArry, recordData): [string, object] {
+ if (formulaArry.length < 1) {
+ return;
+ }
+
+ let varIndex = 0;
+ const calculateData = [];
+ const scopes = {};
+
+ for (let i = 0; i < formulaArry.length; i++) {
+ const item = formulaArry[i];
+
+ if (!item) continue;
+
+ const isNumber = isNumberFunc(item);
+ const isSymbol = isSymbolFunc(item);
+
+ if (!isNumber && !isSymbol) {
+ // NOTE: item 是字段的情况
+ let value;
+ // 举例: ${fieldObj}.fieldName
+ const pattern = /\${(.*?)}/g;
+ if (item.match(pattern)?.length) {
+ // NOTE: 关系字段
+ const target = item.match(pattern)[0].replace(/\${|}/g, '');
+ // 以.分割字符串
+ const targetField = item.split('.')[1];
+ const targetObj = _.chain(recordData).get(target).value();
+ value = _.chain(targetObj).get(targetField, 0).value();
+ } else {
+ // NOTE: 普通字段
+ value = _.chain(recordData).get(item, 0).value();
+ }
+
+ const varName = `var${varIndex++}`;
+ const varValue = value ?? 0;
+
+ calculateData.push(`{{${varName}}}`);
+ scopes[varName] = varValue;
+ } else {
+ // NOTE: item 是数字或者符号的情况
+ calculateData.push(item);
+ }
+ }
+
+ return [calculateData.join(''), scopes];
+}
+
+function getResultShowValue(formulaArray, { prefix, suffix, decimal }): string {
const engine = evaluators.get('math.js');
const evaluate = engine.evaluate.bind(engine);
- const transformFormulaArray = transformFormula(formulaString);
-
- let calculateData = [];
-
- const newFormulaArray = (data): [string, object] => {
- calculateData = [];
- let count = 0;
- const scopes = {};
- if (transformFormulaArray.length === 0) return;
- for (let i = 0; i < transformFormulaArray.length; i++) {
- const item = transformFormulaArray[i];
- if (!item) continue;
- const isNumber = !isNaN(Number(item));
- const symbol = ['+', '-', '*', '/', '?', ':', '(', ')', '%'].includes(item);
- if (!isNumber && !symbol) {
- let value;
- // 举例: ${fieldObj}.fieldName
- const pattern = /\${(.*?)}/g;
- if (item.match(pattern)?.length) {
- const target = item.match(pattern)[0].replace(/\${|}/g, '');
- // 以.分割字符串
- const targetField = item.split('.')[1];
-
- if (path === fieldPath) {
- // @ts-ignore
- value = _.chain(data).get(target).get(targetField, 0).value();
- } else {
- // @ts-ignore
- value = _.chain(data).get(fieldPath).get(target).get(targetField, 0).value();
- }
- } else {
- if (path === fieldPath) {
- // @ts-ignore
- value = _.chain(data).get(item, 0).value();
- } else {
- // @ts-ignore
- value = _.chain(data).get(fieldPath).get(item, 0).value();
- }
- }
- if (!value) {
- value = 0;
- }
- count += 1;
- const varName = 'var' + count;
- const varValue = value;
- scopes[varName] = varValue;
- calculateData.push('{{' + varName + '}}');
- } else {
- calculateData.push(item);
- }
- }
- return [calculateData.join(''), scopes];
- };
-
- const formulaArray = newFormulaArray(form.values);
-
- if (!formulaArray) {
- return {};
- }
const [code, scopes] = formulaArray;
+
let resultShowValue;
+
try {
- const pre = prefix || '';
- const suf = suffix || '';
const res = evaluate(code, scopes);
- const main = isNaN(res) ? res : Number(res).toFixed(+decimal || 0);
- resultShowValue = pre + main + suf;
+ const mainRes = isNaN(res) ? res : Number(res).toFixed(+decimal || 0);
+ resultShowValue = `${prefix}${mainRes}${suffix}`;
} catch (error) {
resultShowValue = `${code}`;
console.warn('code: ', code, ' scopes: ', scopes, 'error: ', resultShowValue, ' error message ', error.message);
}
- return { resultShowValue };
+ return resultShowValue;
}
-function transformFormula(formula: string) {
- if (!formula) return [];
- const formulaArray = formula.split(/([+\-*/?:()%])/).filter((item) => item);
- return formulaArray;
+// utils
+function isNumberFunc(value) {
+ return typeof value === 'number' && !isNaN(value);
+}
+
+function isSymbolFunc(value) {
+ return ['+', '-', '*', '/', '?', ':', '(', ')', '%'].includes(value);
}