diff --git a/packages/plugins/@hera/plugin-core/src/client/schema-components/blocks/GroupBlock.tsx b/packages/plugins/@hera/plugin-core/src/client/schema-components/blocks/GroupBlock.tsx
index db3223c63..d8b485011 100644
--- a/packages/plugins/@hera/plugin-core/src/client/schema-components/blocks/GroupBlock.tsx
+++ b/packages/plugins/@hera/plugin-core/src/client/schema-components/blocks/GroupBlock.tsx
@@ -1,9 +1,10 @@
import { useField, useFieldSchema } from '@formily/react';
import { findFilterTargets, useAPIClient, useBlockRequestContext, useFilterBlock } from '@nocobase/client';
-import { Descriptions, DescriptionsProps, Spin } from 'antd';
+import { Descriptions, DescriptionsProps, Space, Spin } from 'antd';
import { transformers } from './GroupBlockConfigure/transformers';
-import React, { useState } from 'react';
+import React, { useEffect, useState } from 'react';
import { useAsyncEffect } from 'ahooks';
+import { GroupConfigure } from './GroupBlockConfigure/GroupConfigure';
type DataItem = {
labels: string[];
@@ -20,11 +21,8 @@ export const GroupBlock = (props) => {
const params = fieldSchema.parent['x-decorator-props'].params;
const { resource, service } = useBlockRequestContext();
const { getDataBlocks } = useFilterBlock();
- const { targets = [], uid } = findFilterTargets(fieldSchema);
- const api = useAPIClient();
- const [result, setResult] = useState([]);
- const items: DescriptionsProps['items'] = [];
const Blocks = getDataBlocks();
+ const [group, setGroup] = useState([]);
if (!service.params.length) {
getDataBlocks().map((block) => {
if (Object.keys(block.defaultFilter).length) {
@@ -37,84 +35,35 @@ export const GroupBlock = (props) => {
});
}
- useAsyncEffect(async () => {
- const filter = service?.params[0] ? service.params[0].filter : service?.params;
- setResult(
- await Promise.all(
- params?.config?.request?.map(async (requeatItem) => {
- return [
- await api.request({
- url: requeatItem.fieldFormat.requestUrl,
- method: 'POST',
- data: {
- filter: { ...filter },
- collection: params.collection,
- },
- }),
- requeatItem,
- ];
- }) ?? [],
- ),
- );
- }, [Blocks, service.params, service.params[0]]);
-
if (service.loading && !field.loaded) {
return ;
}
- const data = service.data?.data[0] ? { ...service.data?.data[0] } : {};
-
- params?.config?.measures?.forEach((measuresItem) => {
- const value = measuresItem.fieldFormat.fieldValue;
- if (!data[value]) data[value] = 0;
- data[value] = fieldTransformers(measuresItem, data[value], api);
- });
-
- for (const key in data) {
- params?.config?.measures?.forEach((value) => {
- if (value.field[0] === key) {
- if (value.display) {
- items.push({
- key: key,
- label: value.label,
- children: data[key],
- });
+ return (
+ <>
+
汇总:
+ {params?.config.map((configItem, index) => {
+ if (configItem) {
+ return ;
}
- }
- });
- }
-
- result.forEach(([data, requeatItem]) => {
- data?.data?.data?.forEach((requestData: requestData) => {
- const dataItem = { key: requestData.label, label: requestData.label, children: '' };
- if (typeof requestData.value === 'object') {
- requestData.value.labels.forEach((labelItem, index) => {
- dataItem.children =
- dataItem.children +
- ` ${labelItem} ${fieldTransformers(requeatItem, requestData.value['values'][index], api)}`;
- });
- } else {
- dataItem.children = fieldTransformers(requeatItem, requestData.value.toString(), api);
- }
- items.push(dataItem);
- });
- });
- return ;
+ })}
+ >
+ );
};
-const fieldTransformers = (item, data, api) => {
+export const fieldTransformers = (item, data, api) => {
const { option: tOption } = transformers;
const locale = api.auth.getLocale();
- if (item.fieldFormat) {
- const option = item.fieldFormat.option;
- const decimal = item.fieldFormat.decimal;
- if (option && option !== 'decimal') {
- const component = tOption.filter((tValue) => tValue.value === option)[0].component;
+ if (item) {
+ const format = item.format;
+ const digits = item?.digits;
+ if (format && format !== 'decimal') {
+ const component = tOption.find((tValue) => tValue.value === format).component;
data = String(data).includes(',') ? String(data).replace(/,/g, '') : data;
return component(data, locale);
- } else if (option && option === 'decimal') {
+ } else if (format && format === 'decimal' && digits) {
const component = tOption
.filter((tValue) => tValue.value === 'decimal')[0]
- .childrens.filter((decimalOption) => decimalOption.value === decimal)[0].component;
+ .childrens.filter((decimalOption) => decimalOption.value === digits)[0].component;
data = String(data).includes(',') ? String(data).replace(/,/g, '') : data;
return component(data);
}
diff --git a/packages/plugins/@hera/plugin-core/src/client/schema-components/blocks/GroupBlockConfigure/GroupBlockConfigure.tsx b/packages/plugins/@hera/plugin-core/src/client/schema-components/blocks/GroupBlockConfigure/GroupBlockConfigure.tsx
index 7c4fcd866..2f2475711 100644
--- a/packages/plugins/@hera/plugin-core/src/client/schema-components/blocks/GroupBlockConfigure/GroupBlockConfigure.tsx
+++ b/packages/plugins/@hera/plugin-core/src/client/schema-components/blocks/GroupBlockConfigure/GroupBlockConfigure.tsx
@@ -1,21 +1,205 @@
-import { SchemaSettingsItem } from '@nocobase/client';
+import {
+ SchemaComponentOptions,
+ SchemaSettingsItem,
+ SchemaSettingsModalItem,
+ useBlockRequestContext,
+ useDesignable,
+} from '@nocobase/client';
import React, { useContext } from 'react';
import { useTranslation } from '../../../locale';
-import { Modal } from 'antd';
import { GroupBlockContext } from '../../../schema-initializer/blocks/GroupBlockInitializer';
+import { transformers } from './transformers';
+import { ISchema, connect, useFieldSchema } from '@formily/react';
+import { ArrayItems, FormItem, Space } from '@formily/antd-v5';
+import { PullRequestOutlined } from '@ant-design/icons';
-export const GroupBlockConfigure = (props) => {
+export const GroupBlockConfigure = connect((props) => {
const { t } = useTranslation();
- const { setVisible, visible } = useContext(GroupBlockContext);
+ const fieldSchema = useFieldSchema();
+ const { dn } = useDesignable();
+ const { service } = useBlockRequestContext();
+
+ const params = fieldSchema['x-decorator-props']?.params;
+ const measures = params?.measures;
+ const decimal = transformers.option.filter((item) => item.value === 'decimal')[0].childrens;
+ const valueOption = measures.map((item) => {
+ return {
+ label: item.label,
+ value: item.field[0],
+ };
+ });
+ const { scope } = useContext(GroupBlockContext);
+ const schema = modalSchema(t, params, valueOption, decimal);
return (
- {
- setVisible(true);
- }}
- >
- {t('Configure')}
-
+
+ {
+ fieldSchema['x-decorator-props'].params['config'] = [...fieldOptionItem.configField];
+ dn.emit('patch', {
+ schema: {
+ 'x-uid': fieldSchema['x-uid'],
+ 'x-decorator-props': fieldSchema['x-decorator-props'],
+ },
+ });
+ dn.refresh();
+ service?.refresh();
+ }}
+ schema={schema as ISchema}
+ />
+
);
+});
+
+const fieldType = [
+ {
+ label: '字段配置',
+ value: 'field',
+ },
+ {
+ label: '请求配置',
+ value: 'custom',
+ },
+];
+
+const styleOption = [
+ {
+ label: '描述',
+ value: 'describe',
+ },
+ {
+ label: '表格',
+ value: 'table',
+ },
+];
+
+const modalSchema = (t, params, valueOption, decimal) => {
+ const schema = {
+ title: t('Configure Group'),
+ type: 'object',
+ properties: {
+ configField: {
+ title: 'Config Field',
+ type: 'array',
+ 'x-decorator': 'FormItem',
+ 'x-component': 'ArrayItems',
+ default: params.config,
+ items: {
+ type: 'object',
+ 'x-decorator': 'ArrayItems.Item',
+ properties: {
+ space: {
+ type: 'void',
+ 'x-component': 'Space',
+ properties: {
+ sort: {
+ type: 'void',
+ 'x-decorator': 'FormItem',
+ 'x-component': 'ArrayItems.SortHandle',
+ },
+ type: {
+ type: 'string',
+ 'x-decorator': 'FormItem',
+ 'x-component': 'Select',
+ 'x-component-props': {
+ placeholder: '{{t("type")}}',
+ },
+ enum: fieldType,
+ require: true,
+ },
+ field: {
+ type: 'string',
+ 'x-decorator': 'FormItem',
+ 'x-component': 'Select',
+ 'x-component-props': {
+ placeholder: '{{t("field")}}',
+ },
+ 'x-visbile': false,
+ enum: valueOption,
+ 'x-reactions': {
+ dependencies: ['.type'],
+ fulfill: {
+ schema: {
+ 'x-visible': "{{$deps[0]==='field'}}",
+ },
+ },
+ },
+ },
+ reqUrl: {
+ type: 'string',
+ 'x-decorator': 'FormItem',
+ 'x-component': 'Input',
+ 'x-component-props': {
+ placeholder: '{{t("reqUrl")}}',
+ addonBefore: ,
+ },
+ 'x-visible': false,
+ 'x-reactions': {
+ dependencies: ['.type'],
+ fulfill: {
+ schema: {
+ 'x-visible': "{{$deps[0]==='custom'}}",
+ },
+ },
+ },
+ },
+ format: {
+ type: 'string',
+ 'x-decorator': 'FormItem',
+ 'x-component': 'Select',
+ 'x-component-props': {
+ placeholder: '{{t("format")}}',
+ },
+ enum: transformers.option,
+ require: true,
+ },
+ digits: {
+ type: 'string',
+ 'x-decorator': 'FormItem',
+ 'x-component': 'Select',
+ 'x-component-props': {
+ placeholder: '{{t("digits")}}',
+ },
+ enum: decimal,
+ 'x-visible': false,
+ 'x-reactions': {
+ dependencies: ['.format'],
+ fulfill: {
+ schema: {
+ 'x-visible': "{{$deps[0]==='decimal'}}",
+ },
+ },
+ },
+ },
+ style: {
+ type: 'string',
+ 'x-decorator': 'FormItem',
+ 'x-component': 'Select',
+ 'x-component-props': {
+ placeholder: '{{t("style")}}',
+ },
+ enum: styleOption,
+ require: true,
+ },
+ remove: {
+ type: 'void',
+ 'x-decorator': 'FormItem',
+ 'x-component': 'ArrayItems.Remove',
+ },
+ },
+ },
+ },
+ },
+ properties: {
+ add: {
+ type: 'void',
+ title: 'Add',
+ 'x-component': 'ArrayItems.Addition',
+ },
+ },
+ },
+ },
+ };
+ return schema;
};
diff --git a/packages/plugins/@hera/plugin-core/src/client/schema-components/blocks/GroupBlockConfigure/GroupConfigure.tsx b/packages/plugins/@hera/plugin-core/src/client/schema-components/blocks/GroupBlockConfigure/GroupConfigure.tsx
index 3f7a3f391..639f05448 100644
--- a/packages/plugins/@hera/plugin-core/src/client/schema-components/blocks/GroupBlockConfigure/GroupConfigure.tsx
+++ b/packages/plugins/@hera/plugin-core/src/client/schema-components/blocks/GroupBlockConfigure/GroupConfigure.tsx
@@ -1,231 +1,132 @@
import { useField, useFieldSchema } from '@formily/react';
-import { useDesignable, useFieldNames, useFilterBlock } from '@nocobase/client';
-import { App, Button, Flex, Input, Modal, Select } from 'antd';
-import React, { useContext, useEffect, useState } from 'react';
-import { useTranslation } from '../../../locale';
-import { GroupBlockContext } from '../../../schema-initializer/blocks/GroupBlockInitializer';
-import { transformers } from './transformers';
-import { DeleteOutlined, PullRequestOutlined } from '@ant-design/icons';
-import { uid } from '@formily/shared';
+import { useAPIClient, useFilterBlock, useRequest } from '@nocobase/client';
+import { Descriptions, DescriptionsProps, Spin, Table } from 'antd';
+import React, { useState } from 'react';
+import { useAsyncEffect } from 'ahooks';
+import { fieldTransformers } from '../GroupBlock';
-export type SelectedField = {
- field: string | string[];
- alias?: string;
-};
-export type fieldOptionType = {
- label: string;
- fieldFormat: {
- fieldValue: string;
- option: string;
- type: string;
- decimal?: string;
- requestUrl?: string;
- };
- aggregation?: string;
- field?: [string];
- display?: boolean;
+type reqData = {
+ labels: any[];
+ values: any[];
};
export const GroupConfigure = (props) => {
- const { visible, setVisible } = useContext(GroupBlockContext);
- const { t } = useTranslation();
- const { dn } = useDesignable();
- const { modal } = App.useApp();
+ const { configItem, service } = props;
const fieldSchema = useFieldSchema();
- const measures = fieldSchema['x-decorator-props']?.params?.measures;
- const option: fieldOptionType[] = [];
- const params = fieldSchema['x-decorator-props']?.params;
- if (params['config']) {
- if (params['config']['measures']) {
- option.push(...params['config']['measures']);
+ const field = useField();
+ const params = fieldSchema.parent['x-decorator-props'].params;
+ const [result, setResult] = useState({});
+ const { getDataBlocks } = useFilterBlock();
+ const Blocks = getDataBlocks();
+ const api = useAPIClient();
+ useAsyncEffect(async () => {
+ const filter = service?.params[0] ? service.params[0].filter : service?.params;
+ if (configItem.reqUrl) {
+ setResult(
+ (await api.request({
+ url: configItem.reqUrl,
+ method: 'POST',
+ data: {
+ filter: { ...filter },
+ collection: params.collection,
+ },
+ })) ?? {},
+ );
}
- if (params['config']['request']) {
- option.push(...params['config']['request']);
+ }, [Blocks, service.params, service.params[0]]);
+ if (configItem.style === 'describe') {
+ const item: DescriptionsProps['items'] = describeItem(configItem, result, service, params, api);
+ return ;
+ } else if (configItem.style === 'table') {
+ const { columns, options } = tableItem(configItem, result, service, params, api);
+ return ;
+ }
+};
+
+const describeItem = (configItem, result, service, params, api) => {
+ const item = [];
+ if (configItem.type === 'field') {
+ const measuresData = service.data?.data;
+ if (measuresData) {
+ let data = measuresData.map((value) => {
+ return value[configItem.field];
+ })[0];
+ data = fieldTransformers(configItem, data, api);
+ const label = params.measures.find((value) => value.field[0] === configItem.field).label;
+ item.push({
+ key: configItem.field,
+ label,
+ children: data,
+ });
+ }
+ } else if (configItem.type === 'custom') {
+ if (Object.keys(result).length && result?.['data']?.data) {
+ const data: reqData = { ...result?.['data']?.data };
+ const label = data.labels;
+ data.values.forEach((valueItem, index) => {
+ let childrenText = '';
+ label.forEach((value, index) => {
+ if (index === 0) return;
+ childrenText += `${value}${fieldTransformers(configItem, valueItem[index], api)} `;
+ });
+ item.push({
+ key: index,
+ label: valueItem[0],
+ children: childrenText,
+ });
+ });
}
}
+ return item;
+};
- const [fieldOption, setFieldOption] = useState(JSON.parse(JSON.stringify(option)));
- const fieldType = [
- {
- label: '字段配置',
- value: 'field',
- },
- {
- label: '请求配置',
- value: 'custom',
- },
- ];
- const valueOption = measures.map((item) => {
- return {
- label: item.label,
- value: item.field[0],
- };
- });
-
- const decimal = transformers.option.filter((item) => item.value === 'decimal')[0].childrens;
- useEffect(() => {
- if (!visible) {
- return;
- }
- }, [visible]);
- return (
- {
- const request = [];
- const configMeasures = [];
- fieldOption.forEach((fieldOptionItem) => {
- if (fieldOptionItem.fieldFormat.type === 'field') {
- const { measureItem, index } = measures
- .map((measureItem, index) => {
- if (measureItem.field[0] === fieldOptionItem?.fieldFormat?.fieldValue) {
- return { measureItem, index };
- } else {
- return {};
- }
- })
- .filter((value) => value.measureItem)[0];
- if (measureItem) {
- measureItem['fieldFormat'] = { ...fieldOptionItem.fieldFormat };
- configMeasures.push(measureItem);
- }
- } else if (fieldOptionItem.fieldFormat.type === 'custom') {
- request.push({ ...fieldOptionItem, label: '自定义请求', field: [uid()] });
- }
- });
- fieldSchema['x-decorator-props']['params']['config'] = {
- measures: configMeasures,
- request,
+const tableItem = (configItem, result, service, params, api) => {
+ const columns = [];
+ const options = [];
+ if (configItem.type === 'custom') {
+ if (Object.keys(result).length && result?.['data']?.data) {
+ const data: reqData = { ...result?.['data']?.data };
+ data.labels.forEach((value, index) => {
+ columns.push({ title: value, dataIndex: 'value' + index, key: index });
+ });
+ data.values.forEach((value, index) => {
+ const item = {
+ key: index,
};
- dn.emit('patch', {
- schema: fieldSchema,
+ columns.forEach((colItem, index) => {
+ const data = isNaN(value[index]) ? value[index] : fieldTransformers(configItem, value[index], api);
+ item[colItem.dataIndex] = data;
});
- setVisible(false);
- dn.refresh();
- }}
- onCancel={() => {
- modal.confirm({
- title: t('Are you sure to cancel?'),
- content: t('You changes are not saved. If you click OK, your changes will be lost.'),
- okButtonProps: {
- danger: true,
- },
- onOk: () => {
- setVisible(false);
- },
- });
- }}
- width={'30%'}
- >
-
- {fieldOption.map((item, index) => {
- return (
-
-
- );
- })}
-
-
-
- );
-};
-
-const fieldConfig = (type, fieldOption, setFieldOption, index?, record?) => {
- const option = [...fieldOption];
- if (type === 'add') {
- option.push({});
- } else if (type === 'del') {
- option.splice(index, 1);
- } else if (type === 'type') {
- option[index]['fieldFormat'] = {
- ...option[index]['fieldFormat'],
- type: record,
- };
- } else if (type === 'url') {
- option[index]['fieldFormat'] = {
- ...option[index]['fieldFormat'],
- requestUrl: record,
- };
- } else if (type === 'field') {
- option[index]['fieldFormat'] = {
- ...option[index]['fieldFormat'],
- fieldValue: record,
- };
- } else if (type === 'format') {
- option[index]['fieldFormat'] = {
- ...option[index]['fieldFormat'],
- option: record,
- };
- } else if (type === 'decimal') {
- option[index]['fieldFormat'] = {
- ...option[index]['fieldFormat'],
- decimal: record,
- };
+ options.push(item);
+ });
+ }
+ } else if (configItem.type === 'field') {
+ const measuresData = service.data?.data;
+ if (measuresData) {
+ let data = measuresData.map((value) => {
+ return value[configItem.field];
+ })[0];
+ data = fieldTransformers(configItem, data, api);
+ const label = params.measures.find((value) => value.field[0] === configItem.field).label;
+ columns.push(
+ {
+ title: '名称',
+ dataIndex: 'name',
+ key: 'name',
+ },
+ {
+ title: '数量',
+ dataIndex: 'number',
+ key: 'number',
+ },
+ );
+ options.push({
+ key: label,
+ name: label,
+ number: data,
+ });
+ }
}
- setFieldOption(option);
+
+ return { columns, options };
};
diff --git a/packages/plugins/@hera/plugin-core/src/client/schema-initializer/blocks/GroupBlockInitializer.tsx b/packages/plugins/@hera/plugin-core/src/client/schema-initializer/blocks/GroupBlockInitializer.tsx
index cd17dceab..f945d55aa 100644
--- a/packages/plugins/@hera/plugin-core/src/client/schema-initializer/blocks/GroupBlockInitializer.tsx
+++ b/packages/plugins/@hera/plugin-core/src/client/schema-initializer/blocks/GroupBlockInitializer.tsx
@@ -17,7 +17,6 @@ import React, { createContext, useState } from 'react';
import { uid } from '@nocobase/utils/client';
import { Checkbox, Spin } from 'antd';
import { GroupBlockConfigure } from '../../schema-components/blocks/GroupBlockConfigure/GroupBlockConfigure';
-import { GroupConfigure } from '../../schema-components/blocks/GroupBlockConfigure/GroupConfigure';
export const GroupBlockContext = createContext({});
@@ -43,7 +42,6 @@ const InternalGroupBlockProvider = (props) => {
}}
>
{props.children}
-
);
};
diff --git a/packages/plugins/@hera/plugin-rental/src/server/actions/records-controller.ts b/packages/plugins/@hera/plugin-rental/src/server/actions/records-controller.ts
index 3410850b4..5819c123e 100644
--- a/packages/plugins/@hera/plugin-rental/src/server/actions/records-controller.ts
+++ b/packages/plugins/@hera/plugin-rental/src/server/actions/records-controller.ts
@@ -80,15 +80,14 @@ export class RecordPreviewController {
items[product.name].total -= count;
}
});
- ctx.body = _.toArray(items)
+ const result = {
+ labels: ['名称', '出库数量', '入库数量', '小计'],
+ values: [],
+ };
+ _.toArray(items)
.sort((a, b) => a.sort - b.sort)
- .map((item) => ({
- label: item.name,
- value: {
- labels: ['出库数量', '入库数量', '小计'],
- values: [item.out, item.in, item.total],
- },
- }));
+ .forEach((item) => result.values.push([item.name, item.out, item.in, item.total]));
+ ctx.body = { ...result };
}
}
@Action('allweight')
@@ -106,15 +105,10 @@ export class RecordPreviewController {
const inNum = records.find((item) => item.movement === Movement.in)?.weight ?? 0;
const outNum = records.find((item) => item.movement === Movement.out)?.weight ?? 0;
- const data = [
- {
- label: '实际重量(吨)',
- value: {
- labels: ['出库数量(吨)', '入库数量(吨)', '小计(吨)'],
- values: [outNum, inNum, inNum - outNum],
- },
- },
- ];
+ const data = {
+ labels: ['名称', '出库数量(吨)', '入库数量(吨)', '小计(吨)'],
+ values: [['实际重量(吨)', outNum, inNum, inNum - outNum]],
+ };
ctx.body = data;
}
@Action('allprice')
@@ -132,15 +126,10 @@ export class RecordPreviewController {
const inNum = records.find((item) => item.movement === Movement.in)?.all_price ?? 0;
const outNum = records.find((item) => item.movement === Movement.out)?.all_price ?? 0;
- const data = [
- {
- label: '总金额',
- value: {
- labels: ['收入', '支出', '小计'],
- values: [outNum, inNum, outNum - inNum],
- },
- },
- ];
+ const data = {
+ labels: ['名称', '收入', '支出', '小计'],
+ values: [['总金额', outNum, inNum, outNum - inNum]],
+ };
ctx.body = data;
}