Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
ZhaoBingyu committed Aug 4, 2023
2 parents bb0c6f1 + aed2e00 commit f5e6c0e
Show file tree
Hide file tree
Showing 11 changed files with 394 additions and 34 deletions.
13 changes: 9 additions & 4 deletions clients/components/form-builder/form-renderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useState } from 'react';
import { SchemaForm, setValidationLanguage, IForm, createFormActions, IFormValidateResult } from '@formily/antd';
import { ConfigProvider } from 'antd';
import zhCN from 'antd/lib/locale/zh_CN';
import { parse, resolve, findVariables } from 'qxp-formula';
import { parse, findVariables } from 'qxp-formula';
import { omit } from 'ramda';

import logger from '@lib/logger';
Expand All @@ -18,6 +18,8 @@ import calculationFormulaEffect from './linkages/calculation-formula';
import statisticalAssociationEffect from './linkages/statistical-association';
import { wrapSchemaByMegaLayout, schemaPermissionTransformer } from './utils';
import { INVALID_READONLY_LEGACY, INVISIBLE_NO_WRITE, PERMISSION, READONLY_NO_WRITE } from './constants';
import resolve from './resolve';
import { toast } from '@one-for-all/ui';

setValidationLanguage('zh');

Expand Down Expand Up @@ -73,19 +75,22 @@ function FormRenderer({

if (missingValueField) {
actions.getFieldState(missingValueField, (state) => {
setErrorMessage(`字段 ${state.props.title} 必填。`);
// setErrorMessage(`字段 ${state.props.title} 必填。`);
toast.error(`字段 ${state.props.title} 必填。`);
});
return false;
}

const isValid = resolve(ast, values);
if (!isValid) {
setErrorMessage(message || '校验不通过,请修改。');
// setErrorMessage(message || '校验不通过,请修改。');
toast.error(message || '校验不通过,请修改。');
logger.debug('get false result of formula:', formula, 'with values:', values);
return false;
}
} catch (err) {
setErrorMessage('表单校验失败,请修改表单值或联系管理员。');
// setErrorMessage('表单校验失败,请修改表单值或联系管理员。');
toast.error('表单校验失败,请修改表单值或联系管理员。');
logger.warn('failed to resolve formula:', err);
return false;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-param-reassign */
/* eslint-disable max-len */
/* eslint-disable no-empty */
/* eslint-disable no-console */
Expand All @@ -17,7 +18,7 @@ import schemaToFields, { schemaToMap } from '@lib/schema-convert';
import { ISchemaFieldComponentProps } from '@formily/react-schema-renderer';

import SelectRecordsModal from './select-records-modal';
import { fetchFormDataList } from '@lib/http-client-form';
import { fetchFormDataList, fetchOneFormDataWithSchema } from '@lib/http-client-form';
import { toEs } from '@c/data-filter/utils';
import moment from 'moment';
import { useFormEffects } from '@formily/antd';
Expand Down Expand Up @@ -249,9 +250,15 @@ function AssociatedRecordsFields(props: Partial<ISchemaFieldComponentProps>): JS
const associatedTable = p['x-component-props']?.associatedTable ||
p.props['x-component-props'].associatedTable;
const _fields = schemaToFields(associatedTable);
const dateSourceSchema = _fields?.find(({ id }: any)=>id === dataSource);
let arr = dataRows.map((item: any)=>{
let val: any = item?.[dataSource];
const _dataSourceArr = dataSource.split('.');
const dateSourceSchema = _dataSourceArr?.length > 1 ?
_fields?.find(({ id }: any)=>id === _dataSourceArr?.[0]) :
_fields?.find(({ id }: any)=>id === dataSource);
// 关联记录
const componentProps = dateSourceSchema?.['x-component-props'];
const { appID, associationTableID } = componentProps || {};
let arr: any = [];
const formatVal = (val: any)=>{
if (isObject(val) && !isArray(val)) {
val = val?.label;
}
Expand All @@ -266,9 +273,29 @@ function AssociatedRecordsFields(props: Partial<ISchemaFieldComponentProps>): JS
val = moment(val).format(format);
}
return val;
})?.filter((item: any)=>!!item);
arr = arr.flat();
state.value = uniqueShow ? [...new Set([...arr])]?.join(',') : arr?.join(',');
};
if (associationTableID) {
const arrAll: any = [];
dataRows?.map(async (item: any)=>{
arrAll.push(()=>{
return fetchOneFormDataWithSchema(appID, associationTableID, item?.[_dataSourceArr?.[0]]?.value);
});
});
Promise.all(dataRows?.map((item: any) => {
return fetchOneFormDataWithSchema(appID, associationTableID, item?.[_dataSourceArr?.[0]]?.value).then(({ record }: any)=>formatVal(record?.[_dataSourceArr?.[1]]));
}) || [])?.then((res)=>{
arr = res?.flat()?.filter((item)=>!!item);
setFieldState(`${relativePath}.${dataTarget}`, (state: any) => {
state.value = uniqueShow ? [...new Set([...arr])]?.join(',') : arr?.join(',');
});
}).catch((err)=>{});
} else {
arr = dataRows.map((item: any)=>{
return formatVal(item?.[dataSource]);
})?.filter((item: any)=>!!item);
arr = arr.flat();
state.value = uniqueShow ? [...new Set([...arr])]?.join(',') : arr?.join(',');
}
});
} catch (error) {
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable react/prop-types */
import React, { useEffect, useState } from 'react';
import { Cascader } from 'antd';

const DataSelect = (pro: any)=> {
const { value, props, mutators } = pro || {};
const enumArr = JSON.parse(JSON.stringify(props?.enum || []));
const { componentName, appID, tableID } = enumArr.find((item: any)=>item?.value === value) || {};
const { rulesOptions = [] } = props?.['x-component-props'] || {};
const showSelect = componentName !== 'associateddata';
const [options, setOptions] = useState([]);
const [defaultValue, setDefaultValue] = useState([]);

useEffect(()=>{
setOptions(rulesOptions.sort((a: any, b: any)=>a.index - b.index));
}, [rulesOptions]);

useEffect(()=>{
const _arr = value?.split('.');
const _defaultValue: any = [];
const item: any = options?.find((item: any)=>{
return item.value === _arr?.[0];
});
item && _defaultValue.push(item?.label);
if (_arr?.length === 2) {
const child = item?.children?.find((child: any)=>{
return child.value === _arr?.[1];
});
child && _defaultValue.push(child?.label);
}
setDefaultValue(_defaultValue);
}, [value, options]);

const handleChange = (value: any) => {
mutators?.change(value.join('.'));
};

return (
<>
<Cascader options = {options} value={defaultValue} allowClear={false} onChange={handleChange} />
</>
);
};

DataSelect.isFieldComponent = true;

export default DataSelect;
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@
max-width: 12px;
min-width: 12px;
}

.ml-210{
margin-left: 210px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import RulesConfig from './rules-config';
import AssociativeRuleList from './rule-list';

import './index.scss';
import { SUPPORT_COMPONENT, getTableFieldsToOptions } from '../config';

function AssociativeConfig({ props, value, mutators }: ISchemaFieldComponentProps): JSX.Element {
const [visible, setVisible] = useState(false);
const [rules, setRules] = useState<FormBuilder.DataAssignment[]>();
const { currentFormFields, sourceTableFields, associativeRules } = props?.['x-component-props'] ?? {};

const [rulesOptions, setRulesOptions] = useState<any>([]);
function onSubmit(value: Record<string, FormBuilder.DataAssignment[]>): void {
mutators.change(value);
setVisible(false);
Expand All @@ -27,7 +28,7 @@ function AssociativeConfig({ props, value, mutators }: ISchemaFieldComponentProp
return fieldName === dataTarget;
})?.title;

return { dataSource: sourceValue, match, dataTarget: targetValue };
return { dataSource: sourceValue, match, dataTarget: targetValue, dataSourceID: dataSource };
});
}

Expand All @@ -38,16 +39,36 @@ function AssociativeConfig({ props, value, mutators }: ISchemaFieldComponentProp
associativeRules && setRules(mapAssociativeRules(associativeRules));
}, [associativeRules]);

useEffect(()=>{
let _rulesOptions: any = [];
sourceTableFields?.forEach((item: any, index: any) => {
let children;
const { title, id, componentName } = item;
const { appID, associationTableID: tableID } = item?.['x-component-props'] || {};
if (componentName === 'associateddata') {
getTableFieldsToOptions(appID, tableID, SUPPORT_COMPONENT).then((fields) => {
children = fields?.map(({ title, id })=> ({ label: title, value: id }));
_rulesOptions = [..._rulesOptions, { label: title, value: id, children, index }];
setRulesOptions(_rulesOptions);
});
} else {
_rulesOptions = [..._rulesOptions, { label: title, value: id, children, index }];
setRulesOptions(_rulesOptions);
}
});
}, [sourceTableFields]);

return (
<div>
{!!rules?.length && <AssociativeRuleList associativeRules={rules} />}
<div className='w-full'>
{!!rules?.length && <AssociativeRuleList associativeRules={rules} rulesOptions={rulesOptions}/>}
<Button className="mt-8" onClick={() => setVisible(true)}>设置关联赋值</Button>
{visible && (
<RulesConfig
onSubmit={onSubmit}
defaultValue={value}
currentFormFields={currentFormFields}
sourceTableFields={sourceTableFields}
rulesOptions={rulesOptions}
onClose={() => setVisible(false)}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
import { observer } from 'mobx-react';

type Props = {
associativeRules: FormBuilder.DataAssignment[],
rulesOptions: any,
}

function LinkText({ text }: { text: string | undefined }): JSX.Element {
Expand All @@ -13,22 +14,39 @@ function LinkText({ text }: { text: string | undefined }): JSX.Element {
);
}

function AssociativeRuleList({ associativeRules }: Props): JSX.Element {
function AssociativeRuleList(props: Props): JSX.Element {
const { associativeRules, rulesOptions } = props;

const [dataList, setDataList] = useState<any>([]);

useEffect(()=>{
const _dataList = associativeRules.map(({ dataTarget, match, dataSource, dataSourceID }: any) => {
const _arr = dataSourceID.split('.');
const item = rulesOptions?.find(({ value }: any) => value === _arr?.[0]);
const child = item?.children?.find(({ value }: any) => value === _arr?.[1]);
const dataSourceText = [item?.label, child?.label]?.join('/');
return {
dataTarget, match, dataSource, dataSourceID, dataSourceText,
};
});
setDataList(_dataList);
}, [associativeRules, rulesOptions]);

return (
<div className="my-8 w-full">
<div className="flex">
<span className="text-center flex-1">关联表单字段</span>
<span className="text-center mx-8 match-icon">{'=>'}</span>
<span className="text-center flex-1">当前表单字段</span>
</div>
<div className="max-h-100 overflow-auto mt-8">
{associativeRules.map(({ dataTarget, match, dataSource }) => {
<div className="overflow-auto mt-8">
{dataList.map(({ dataTarget, match, dataSource, dataSourceText }: any) => {
return (
<div
className="my-4 flex"
key={`${dataSource}_${match}_${dataTarget}`}
>
<LinkText text={dataSource} />
<LinkText text={dataSource || dataSourceText} />
<span className="text-center mx-8 match-icon">{'=>'}</span>
<LinkText text={dataTarget} />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,30 @@ import {
createFormActions,
} from '@formily/antd';
import { tap, skip, filter } from 'rxjs6/operators';
import { Input, Switch, Select, Radio } from '@formily/antd-components';
import { Input, Select, Switch, Radio } from '@formily/antd-components';

import Modal from '@c/modal';
import Button from '@c/button';
import { RulesList } from '@c/form-builder/customized-fields';

import { SCHEMA } from './schema';
import Checkbox from '@c/checkbox';
import DataSelect from './dataSelect';

type Props = {
onClose: () => void,
onSubmit: (value: Record<string, FormBuilder.DataAssignment[]>) => void
defaultValue: Record<string, FormBuilder.DataAssignment[]>,
currentFormFields: SchemaFieldItem[],
sourceTableFields: SchemaFieldItem[],
rulesOptions?: any,
}

const COMPONENTS = { Input, Select, Switch, RadioGroup: Radio.Group, RulesList };
const COMPONENTS = { Input, Select, DataSelect, Switch, RadioGroup: Radio.Group, RulesList };
const { onFieldValueChange$ } = FormEffectHooks;

function Rules({
onClose, onSubmit, defaultValue, currentFormFields, sourceTableFields,
onClose, onSubmit, defaultValue, currentFormFields, sourceTableFields, rulesOptions,
}: Props): JSX.Element {
const actions = createFormActions();
const { setFieldState, getFieldValue } = actions;
Expand All @@ -39,11 +41,19 @@ function Rules({
const sourceType = currentFormFields?.find(({ fieldName }) => fieldName === value)?.type;
props.enum = formatFieldInputAndOption(sourceType || '');
});

setFieldState('rules.*.dataSource', (state) => {
state.props.enum = sourceTableFields?.map(({ title, id }) => {
return { label: title, value: id };
state.props.enum = sourceTableFields?.map((item: any, index) => {
const { title, id, componentName } = item;
const { appID, associationTableID: tableID } = item?.['x-component-props'] || {};
return { label: title, value: id, componentName, appID, tableID, rulesOptions };
});
state.props = {
...state.props,
'x-component-props': {
...state.props?.['x-component-props'],
rulesOptions,
},
};
});
}, []);

Expand All @@ -56,9 +66,11 @@ function Rules({
}

function initDataTargetEnum({ value, name }: IFieldState): void {
const sourceType = sourceTableFields?.find(({ fieldName }) => fieldName === value)?.componentName || '';
const _value = value?.split('.');
const sourceType = sourceTableFields?.find(({ fieldName }) => fieldName === _value?.[0])?.componentName || '';
const targetPath = FormPath.transform(name, /\d/, ($1) => `rules.${$1}.dataTarget`);
setFieldState(targetPath, (state) => {
state.props.enum = formatFieldInputAndOption('input');
const WHITE_LIST = [
'input', 'numberpicker', 'userpicker', 'datepicker', 'select',
'serial', 'cascadeselector', 'organizationpicker', 'multipleselect',
Expand Down Expand Up @@ -118,7 +130,7 @@ function Rules({
</div>
<div className="flex text-14 mb-20">
<span>关联表单字段</span>
<span className="ml-100">当前表单字段</span>
<span className="ml-210">当前表单字段</span>
</div>
<SchemaForm
actions={actions}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const SCHEMA: ISchema = {
properties: {
dataSource: {
type: 'string',
'x-component': 'Select',
'x-component': 'DataSelect',
},
match: {
type: 'string',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const COMPONENTS = {
const { onFieldInputChange$ } = FormEffectHooks;
const actions = createFormActions();

async function getTableFieldsToOptions(
export async function getTableFieldsToOptions(
appID: string,
tableID: string,
filterArr?: string[],
Expand All @@ -64,7 +64,7 @@ async function getTableFieldsToOptions(
return [];
}

const SUPPORT_COMPONENT = [
export const SUPPORT_COMPONENT = [
'Input',
'NumberPicker',
'Textarea',
Expand All @@ -78,6 +78,7 @@ const SUPPORT_COMPONENT = [
'UserPicker',
'OrganizationPicker',
'Serial',
'AssociatedData',
]; // 关联记录表下支持关联表白名单
const WHITE_LIST = [
'input',
Expand Down
Loading

0 comments on commit f5e6c0e

Please sign in to comment.