From c02c56797579e0751e3eb21512cd5915c016b4f8 Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Thu, 4 Sep 2025 14:17:49 +0800 Subject: [PATCH 01/24] =?UTF-8?q?feature:=20=E9=9B=86=E6=88=90=E8=BF=90?= =?UTF-8?q?=E8=A1=8C=E6=A1=86=E6=9E=B6=E4=B8=8A=E4=B8=8B=E6=96=87=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=EF=BC=8C=E6=94=AF=E6=8C=81=E8=8E=B7=E5=8F=96=E5=BD=93?= =?UTF-8?q?=E5=89=8D=E7=99=BB=E5=BD=95=E7=94=A8=E6=88=B7=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E5=8F=8A=E8=AF=AD=E8=A8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/command-services/lib/index.ts | 1 + packages/command-services/lib/providers.ts | 7 +- .../lib/runtime-framework-context.service.ts | 73 +++++++++++++++++++ packages/devkit/lib/common/tokens.ts | 6 +- packages/devkit/lib/common/types.ts | 37 ++++++++++ packages/devkit/lib/module/module.ts | 12 ++- 6 files changed, 128 insertions(+), 8 deletions(-) create mode 100644 packages/command-services/lib/runtime-framework-context.service.ts diff --git a/packages/command-services/lib/index.ts b/packages/command-services/lib/index.ts index a5fe36b6f..0d9942614 100644 --- a/packages/command-services/lib/index.ts +++ b/packages/command-services/lib/index.ts @@ -45,6 +45,7 @@ export * from './controller.service'; export * from './verify-detail.service'; export * from './locale'; export * from './print.service'; +export * from './runtime-framework-context.service'; export * from './providers'; export * from './types'; export * from './tokens'; diff --git a/packages/command-services/lib/providers.ts b/packages/command-services/lib/providers.ts index 7e1952e44..84b149174 100644 --- a/packages/command-services/lib/providers.ts +++ b/packages/command-services/lib/providers.ts @@ -1,4 +1,4 @@ -import { ViewModel, StaticProvider, Injector, EXCEPTION_HANDLER_TOKEN, HttpClient } from '@farris/devkit-vue'; +import { ViewModel, StaticProvider, Injector, EXCEPTION_HANDLER_TOKEN, HttpClient, RUNTIME_FRAMEWORK_CONTEXT_TOKEN } from '@farris/devkit-vue'; import { EntityStateService } from './devkit-services/index'; import { LoadDataService, CreateDataService, RemoveDataService, SaveDataService, @@ -47,7 +47,8 @@ import { VerifyDetailService, AttachmentDataService, PrintService, - TranslateService + TranslateService, + RuntimeFrameworkContextService } from './index'; import { UploadDialogService, DownloadService } from '@gsp-svc/formdoc-upload-vue'; import { FileViewerService } from '@gsp-svc/file-viewer-vue'; @@ -57,6 +58,8 @@ const commandServicesDevkitProviders: StaticProvider[] = [ { provide: RuntimeFrameworkService, useClass: RuntimeFrameworkService, deps: [QuerystringService] }, { provide: NavigationHistoryService, useClass: NavigationHistoryService, deps: [] }, { provide: NavigationEventService, useClass: NavigationEventService, deps: [RuntimeFrameworkService, QuerystringService, NavigationHistoryService] }, + { provide: RuntimeFrameworkContextService, useClass: RuntimeFrameworkContextService, deps: [RuntimeFrameworkService]}, + { provide: RUNTIME_FRAMEWORK_CONTEXT_TOKEN, useFactory:(runtimeFrameworkContextService: RuntimeFrameworkContextService)=> runtimeFrameworkContextService.runtimeFrameworkContext , deps: [RuntimeFrameworkContextService]} ]; diff --git a/packages/command-services/lib/runtime-framework-context.service.ts b/packages/command-services/lib/runtime-framework-context.service.ts new file mode 100644 index 000000000..1f6037f58 --- /dev/null +++ b/packages/command-services/lib/runtime-framework-context.service.ts @@ -0,0 +1,73 @@ +import { RuntimeFrameworkService } from './rtf.service'; +import { RuntimeFrameworkContext } from '@farris/devkit-vue'; +import { GspFramework } from './types'; + +/** + * 运行框架上下文服务 + */ +export class RuntimeFrameworkContextService { + public runtimeFrameworkContext: RuntimeFrameworkContext | null = null; + constructor(private frameworkService: RuntimeFrameworkService) { + if (this.frameworkService) { + const userInfo = this.frameworkService.userInfo; + this.runtimeFrameworkContext = this.buildRuntimeFrameworkContext(userInfo); + } + } + /** + * 当前用户id + */ + public get userId() { + return this.runtimeFrameworkContext && this.runtimeFrameworkContext.userId; + } + /** + * 当前用户code + */ + public get userCode() { + return this.runtimeFrameworkContext && this.runtimeFrameworkContext.userCode; + } + /** + * 当前用户name + */ + public get userName() { + return this.runtimeFrameworkContext && this.runtimeFrameworkContext.userName; + } + /** + * 所属组织id + */ + public get orgId() { + return this.runtimeFrameworkContext && this.runtimeFrameworkContext.orgId; + } + /** + * 所属组织名称 + */ + public get orgName() { + return this.runtimeFrameworkContext && this.runtimeFrameworkContext.orgName; + } + /** + * 单位id + */ + public get unitId() { + return this.runtimeFrameworkContext && this.runtimeFrameworkContext.unitId; + } + /** + * 单位名称 + */ + public get unitName() { + return this.runtimeFrameworkContext && this.runtimeFrameworkContext.unitName; + } + private buildRuntimeFrameworkContext(userInfo: GspFramework.UserInfo | null): RuntimeFrameworkContext | null { + if (!userInfo) { + return null; + } + return { + userId: userInfo.id, + userCode: userInfo.code, + unitId: userInfo.unitId, + unitName: userInfo.unitName, + userName: userInfo.name, + orgId: userInfo.orgId, + orgName: userInfo.orgName, + languageId: userInfo.languageId + }; + } +} diff --git a/packages/devkit/lib/common/tokens.ts b/packages/devkit/lib/common/tokens.ts index 35252cf52..c07a00f32 100644 --- a/packages/devkit/lib/common/tokens.ts +++ b/packages/devkit/lib/common/tokens.ts @@ -1,5 +1,5 @@ import { InjectionToken } from "./di/injection-token"; -import { ExceptionHandler, RenderEngine, FormValidator, Translate } from "./types"; +import { ExceptionHandler, RenderEngine, FormValidator, Translate, RuntimeFrameworkContext } from "./types"; export const EXCEPTION_HANDLER_TOKEN = new InjectionToken('@farris/exception_handler_token'); @@ -18,4 +18,6 @@ export const LOCALE_TOKEN = new InjectionToken('@farris/locale_id_token' /** * 国际化 */ -export const TRANSLATE_TOKEN = new InjectionToken('@farris/translate_token'); \ No newline at end of file +export const TRANSLATE_TOKEN = new InjectionToken('@farris/translate_token'); + +export const RUNTIME_FRAMEWORK_CONTEXT_TOKEN = new InjectionToken('@farris/runtime_framework_context_token'); diff --git a/packages/devkit/lib/common/types.ts b/packages/devkit/lib/common/types.ts index 092ba1b9e..3de7bbacd 100644 --- a/packages/devkit/lib/common/types.ts +++ b/packages/devkit/lib/common/types.ts @@ -75,3 +75,40 @@ export const DEFAULT_LOCALE = 'zh-CHS'; export interface Translate { transform(key: string, defaultValue?: string): string; } +/** + * 运行框架上下文 + */ +export interface RuntimeFrameworkContext { + /** + * 用户Id + */ + userId: string; + /** + * 语言 + */ + languageId: string; + /** + * 用户Code + */ + userCode: string; + /** + * 用户Name + */ + userName: string; + /** + * 隶属组织Id + */ + orgId: string; + /** + * 隶属组织Name + */ + orgName: string; + /** + * 单位Id + */ + unitId: string; + /** + * 单位名称 + */ + unitName: string; +} \ No newline at end of file diff --git a/packages/devkit/lib/module/module.ts b/packages/devkit/lib/module/module.ts index e08f0d766..af50d065e 100644 --- a/packages/devkit/lib/module/module.ts +++ b/packages/devkit/lib/module/module.ts @@ -1,4 +1,4 @@ -import { DEFAULT_LOCALE, EventBus,IDisposable, Injector } from '../common/index'; +import { DEFAULT_LOCALE, EventBus, IDisposable, Injector, RUNTIME_FRAMEWORK_CONTEXT_TOKEN, RuntimeFrameworkContext } from '../common/index'; import { Devkit, useDevkit } from '../devkit'; import { Entity, EntityState, EntityStore, UIState, UIStore, @@ -18,7 +18,7 @@ const MODULE_INJECTION_TOKEN = Symbol('Module'); /** * 模块定义 */ -class Module implements IDisposable{ +class Module implements IDisposable { /** * 模块ID */ @@ -86,7 +86,11 @@ class Module implements IDisposable{ /** * 可释放对象 */ - private disposables: IDisposable[] + private disposables: IDisposable[]; + + public get runtimeFrameworkContext(): RuntimeFrameworkContext | null { + return this.injector && this.injector.get(RUNTIME_FRAMEWORK_CONTEXT_TOKEN, null); + } /** * 构造函数 @@ -454,7 +458,7 @@ class Module implements IDisposable{ * 当前语言 * @returns */ - public getLocale(){ + public getLocale() { return this.locale; } -- Gitee From c7fc43605286a92d820cb3c539c03ddf430ddb46 Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Thu, 4 Sep 2025 18:57:07 +0800 Subject: [PATCH 02/24] =?UTF-8?q?chore:=20=E6=96=B0=E5=A2=9E=E5=A4=A7?= =?UTF-8?q?=E6=95=B0=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/devkit/lib/common/types.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/devkit/lib/common/types.ts b/packages/devkit/lib/common/types.ts index 3de7bbacd..d50a882d9 100644 --- a/packages/devkit/lib/common/types.ts +++ b/packages/devkit/lib/common/types.ts @@ -111,4 +111,6 @@ export interface RuntimeFrameworkContext { * 单位名称 */ unitName: string; -} \ No newline at end of file +} + +export const BigNumberType = 'BigNumber'; \ No newline at end of file -- Gitee From cdc56142548ef39d14d6ce77426ca4bde913f8c8 Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Fri, 5 Sep 2025 13:59:42 +0800 Subject: [PATCH 03/24] =?UTF-8?q?feature:=20=E5=89=8D=E7=AB=AF=E6=9C=80?= =?UTF-8?q?=E5=A4=A7=E5=80=BC=E3=80=81=E6=9C=80=E5=B0=8F=E5=80=BC=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E6=94=AF=E6=8C=81=E5=A4=A7=E6=95=B0=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/devkit/lib/common/types.ts | 2 +- .../configs/entity-store-config.ts | 1 + .../store/entity-store/entity-data-loader.ts | 9 +++-- .../store/entity-store/entity-data-peeker.ts | 10 ++++-- .../entity-schema/entity-field-schema.ts | 7 ++-- .../entity-schema/entity-schema-creator.ts | 3 +- .../devkit/lib/store/form/validation/types.ts | 1 + .../validators/max-value-validator.ts | 34 +++++++++++-------- .../validators/min-value-validator.ts | 33 ++++++++++-------- .../entity-store-config-builder.ts | 8 +++-- .../form/validation-rule-creator.ts | 4 +-- 11 files changed, 69 insertions(+), 43 deletions(-) diff --git a/packages/devkit/lib/common/types.ts b/packages/devkit/lib/common/types.ts index d50a882d9..d16cb2fe1 100644 --- a/packages/devkit/lib/common/types.ts +++ b/packages/devkit/lib/common/types.ts @@ -113,4 +113,4 @@ export interface RuntimeFrameworkContext { unitName: string; } -export const BigNumberType = 'BigNumber'; \ No newline at end of file +export const BigNumberType = 'BigNumericType'; \ No newline at end of file diff --git a/packages/devkit/lib/store/entity-store/configs/entity-store-config.ts b/packages/devkit/lib/store/entity-store/configs/entity-store-config.ts index b1d8bc1e8..3b152e984 100644 --- a/packages/devkit/lib/store/entity-store/configs/entity-store-config.ts +++ b/packages/devkit/lib/store/entity-store/configs/entity-store-config.ts @@ -18,6 +18,7 @@ interface FieldConfig { interface PrimitiveFieldConfig extends FieldConfig { type: 'Primitive'; multiLanguage?: boolean; + bigNumber?: boolean; } /** diff --git a/packages/devkit/lib/store/entity-store/entity-data-loader.ts b/packages/devkit/lib/store/entity-store/entity-data-loader.ts index 2cf6918d3..09d29e028 100644 --- a/packages/devkit/lib/store/entity-store/entity-data-loader.ts +++ b/packages/devkit/lib/store/entity-store/entity-data-loader.ts @@ -43,7 +43,7 @@ class EntityDataLoader { const entity = this.entity as any; const fieldSchemas = this.entitySchema.getFieldSchemasByType(FieldType.Primitive); fieldSchemas.forEach((fieldSchema) => { - const multiLanguage = fieldSchema.multiLanguage; + const { bigNumber, multiLanguage } = fieldSchema; const dataField = multiLanguage ? `${fieldSchema.name}_MULTILANGUAGE` : fieldSchema.name; const propName = fieldSchema.name; const localeId = Locale.getLocaleId(); @@ -59,7 +59,12 @@ class EntityDataLoader { } } } else { - entity[propName] = entityData[propName]; + const propertyValue = entityData[propName]; + if (bigNumber) { + entity[propName] = propertyValue === null ? null : propertyValue && propertyValue.toString() || ''; + } else { + entity[propName] = entityData[propName]; + } } }); diff --git a/packages/devkit/lib/store/entity-store/entity-data-peeker.ts b/packages/devkit/lib/store/entity-store/entity-data-peeker.ts index a355eaa43..a2fd15099 100644 --- a/packages/devkit/lib/store/entity-store/entity-data-peeker.ts +++ b/packages/devkit/lib/store/entity-store/entity-data-peeker.ts @@ -46,7 +46,8 @@ class EntityDataPeeker { // const dataField = fieldSchema.multiLanguage ? `${fieldSchema.name}_MULTILANGUAGE` : fieldSchema.name; const propName = fieldSchema.name; const value = entity[propName]; - if (fieldSchema.multiLanguage === true) { + const { multiLanguage, bigNumber = false } = fieldSchema; + if (multiLanguage === true) { const localeId = Locale.getLocaleId(); if (typeof value === 'object') { entityData[propName] = entity[propName]; @@ -57,7 +58,12 @@ class EntityDataPeeker { } } else { - entityData[propName] = entity[propName]; + const propertyValue = entity[propName]; + if (!bigNumber) { + entityData[propName] = propertyValue; + } else { + entityData[propName] = propertyValue && propertyValue.toString() || null; + } } }); } diff --git a/packages/devkit/lib/store/entity-store/entity-schema/entity-field-schema.ts b/packages/devkit/lib/store/entity-store/entity-schema/entity-field-schema.ts index 4ccf0a2db..94747c757 100644 --- a/packages/devkit/lib/store/entity-store/entity-schema/entity-field-schema.ts +++ b/packages/devkit/lib/store/entity-store/entity-schema/entity-field-schema.ts @@ -24,7 +24,6 @@ enum FieldType { * 字段信息 */ interface FieldSchema { - /** * 字段名称 */ @@ -39,7 +38,6 @@ interface FieldSchema { * 简单字段 */ interface PrimitiveFieldSchema extends FieldSchema { - /** * 字段类型 */ @@ -48,13 +46,16 @@ interface PrimitiveFieldSchema extends FieldSchema { * 是否多语字段 */ multiLanguage?: boolean; + /** + * 大数字 + */ + bigNumber?: boolean; } /** * 实体字段 */ interface EntityFieldSchema extends FieldSchema { - /** * 字段类型 */ diff --git a/packages/devkit/lib/store/entity-store/entity-schema/entity-schema-creator.ts b/packages/devkit/lib/store/entity-store/entity-schema/entity-schema-creator.ts index 411f4033b..92397947d 100644 --- a/packages/devkit/lib/store/entity-store/entity-schema/entity-schema-creator.ts +++ b/packages/devkit/lib/store/entity-store/entity-schema/entity-schema-creator.ts @@ -75,7 +75,8 @@ class EntitySchemaCreator { const fieldSchema: PrimitiveFieldSchema = { type: FieldType.Primitive, name: fieldConfig.name, - multiLanguage: fieldConfig.multiLanguage + multiLanguage: fieldConfig.multiLanguage, + bigNumber: fieldConfig.bigNumber }; this.entitySchema.addFieldSchema(fieldSchema); } diff --git a/packages/devkit/lib/store/form/validation/types.ts b/packages/devkit/lib/store/form/validation/types.ts index f98965156..ed1e37c23 100644 --- a/packages/devkit/lib/store/form/validation/types.ts +++ b/packages/devkit/lib/store/form/validation/types.ts @@ -6,6 +6,7 @@ interface ValidationRule { name: string; message?: string; multiLanguage?: boolean; + bigNumber?: boolean; [key: string]: any; } diff --git a/packages/devkit/lib/store/form/validation/validators/max-value-validator.ts b/packages/devkit/lib/store/form/validation/validators/max-value-validator.ts index ce9314e5a..574593ef5 100644 --- a/packages/devkit/lib/store/form/validation/validators/max-value-validator.ts +++ b/packages/devkit/lib/store/form/validation/validators/max-value-validator.ts @@ -1,12 +1,12 @@ import { ValidationError, MaxValueValidationRule } from '../types'; import { ValidatorUtil } from './validator-util'; import { BaseValidator } from './base-validator'; +import { BigNumber } from 'bignumber.js'; /** * 数值最大值验证器 */ class MaxValueValidator extends BaseValidator { - /** * 名称 */ @@ -29,22 +29,26 @@ class MaxValueValidator extends BaseValidator { if (!ValidatorUtil.isNumberLike(value)) { return null; } - - // 如果是字符串先转换成数字,再比较 - if (typeof value !== 'number') { - value = parseFloat(value); - } - - // 转换后值为NaN时,无法比较,不触发校验 - // https://www.w3.org/TR/html5/forms.html#attr-input-max - if (isNaN(value) === true) { - return null; - } - - const { name, maxValue } = rule; + const { bigNumber = false, name, maxValue } = rule; const message = rule.message || `输入的值不应大于${maxValue}`; const error = { name, message, maxValue, actualValue: value }; - return value > maxValue ? error : null; + if (!bigNumber) { + // 如果是字符串先转换成数字,再比较 + if (typeof value !== 'number') { + value = parseFloat(value); + } + + // 转换后值为NaN时,无法比较,不触发校验 + // https://www.w3.org/TR/html5/forms.html#attr-input-max + if (isNaN(value) === true) { + return null; + } + return value > maxValue ? error : null; + } else { + const currentValue = new BigNumber(value); + const targetMaxValue = new BigNumber(maxValue); + return currentValue.isLessThanOrEqualTo(targetMaxValue) ? null : error; + } } /** diff --git a/packages/devkit/lib/store/form/validation/validators/min-value-validator.ts b/packages/devkit/lib/store/form/validation/validators/min-value-validator.ts index 6fe9959dd..0e50959cb 100644 --- a/packages/devkit/lib/store/form/validation/validators/min-value-validator.ts +++ b/packages/devkit/lib/store/form/validation/validators/min-value-validator.ts @@ -1,7 +1,7 @@ import { ValidationError, MinValueValidationRule } from '../types'; import { ValidatorUtil } from './validator-util'; import { BaseValidator } from './base-validator'; - +import { BigNumber } from 'bignumber.js'; /** * 数值最小值验证器 */ @@ -29,23 +29,26 @@ class MinValueValidator extends BaseValidator { if (!ValidatorUtil.isNumberLike(value)) { return null; } - - // 如果是字符串先转换成数字,再比较 - if (typeof value !== 'number') { - value = parseFloat(value); - } - - // 转换后值为NaN时,无法比较,不触发校验 - // https://www.w3.org/TR/html5/forms.html#attr-input-max - if (isNaN(value) === true) { - return null; - } - - const { name, minValue } = rule; + const { bigNumber = false, name, minValue } = rule; const message = rule.message || `输入的值不应小于${minValue}`; const error = { name, message, minValue, actualValue: value }; + if (!bigNumber) { + // 如果是字符串先转换成数字,再比较 + if (typeof value !== 'number') { + value = parseFloat(value); + } - return value < minValue ? error : null; + // 转换后值为NaN时,无法比较,不触发校验 + // https://www.w3.org/TR/html5/forms.html#attr-input-max + if (isNaN(value) === true) { + return null; + } + return value < minValue ? error : null; + } else { + const currentValue = new BigNumber(value); + const targetMinValue = new BigNumber(minValue); + return currentValue.isGreaterThanOrEqualTo(targetMinValue) ? null : error; + } } /** diff --git a/packages/renderer/src/config-builders/entity-store-config-builder.ts b/packages/renderer/src/config-builders/entity-store-config-builder.ts index 3b0ec4b1b..ae4eb8d8e 100644 --- a/packages/renderer/src/config-builders/entity-store-config-builder.ts +++ b/packages/renderer/src/config-builders/entity-store-config-builder.ts @@ -1,6 +1,7 @@ import { FieldConfig, PrimitiveFieldConfig, EntityFieldConfig, EntityListFieldConfig, EntityConfig, - EntityStateConfig, EntityStoreConfig + EntityStateConfig, EntityStoreConfig, + BigNumberType } from '@farris/devkit-vue'; import { ENTITY_STORE_SUFFIX } from '../types'; @@ -95,10 +96,13 @@ class EntityStoreConfigBuilder { * 构造简单字段配置 */ private buildPrimitiveFieldConfig(fieldSchemaNode: any): PrimitiveFieldConfig { + const { type } = fieldSchemaNode; + const typeName = type && type.$type; const fieldConfig: PrimitiveFieldConfig = { type: 'Primitive', name: fieldSchemaNode.label, - multiLanguage: fieldSchemaNode.multiLanguage + multiLanguage: fieldSchemaNode.multiLanguage, + bigNumber: typeName === BigNumberType }; return fieldConfig; diff --git a/packages/renderer/src/config-builders/form/validation-rule-creator.ts b/packages/renderer/src/config-builders/form/validation-rule-creator.ts index 452b90059..be90c3934 100644 --- a/packages/renderer/src/config-builders/form/validation-rule-creator.ts +++ b/packages/renderer/src/config-builders/form/validation-rule-creator.ts @@ -108,7 +108,7 @@ class ValidationRuleCreator { const originalMessage = LocaleService.translate('maxValue'); const message = originalMessage.replace(/\$property/g, displayName).replace(/\$constraint1/g, maxValue); - return { name: 'maxValue', maxValue, message }; + return { name: 'maxValue', maxValue, message, bigNumber: controlNode.bigNumber || false }; } /** @@ -124,7 +124,7 @@ class ValidationRuleCreator { const originalMessage = LocaleService.translate('minValue'); const message = originalMessage.replace(/\$property/g, displayName).replace(/\$constraint1/g, minValue); - return { name: 'minValue', minValue: minValue, message }; + return { name: 'minValue', minValue: minValue, message, bigNumber: controlNode.bigNumber || false }; } /** -- Gitee From b8ad9284bc5f74e41b02db196f05e9a44a74ac56 Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Fri, 5 Sep 2025 14:35:29 +0800 Subject: [PATCH 04/24] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8DBigNumber?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E4=B8=BAundefined=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../form/validation/validators/max-value-validator.ts | 2 +- .../form/validation/validators/min-value-validator.ts | 2 +- .../src/config-builders/form/validation-rule-creator.ts | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/devkit/lib/store/form/validation/validators/max-value-validator.ts b/packages/devkit/lib/store/form/validation/validators/max-value-validator.ts index 574593ef5..1cbacb58c 100644 --- a/packages/devkit/lib/store/form/validation/validators/max-value-validator.ts +++ b/packages/devkit/lib/store/form/validation/validators/max-value-validator.ts @@ -1,7 +1,7 @@ import { ValidationError, MaxValueValidationRule } from '../types'; import { ValidatorUtil } from './validator-util'; import { BaseValidator } from './base-validator'; -import { BigNumber } from 'bignumber.js'; +import BigNumber from 'bignumber.js'; /** * 数值最大值验证器 diff --git a/packages/devkit/lib/store/form/validation/validators/min-value-validator.ts b/packages/devkit/lib/store/form/validation/validators/min-value-validator.ts index 0e50959cb..cade71e94 100644 --- a/packages/devkit/lib/store/form/validation/validators/min-value-validator.ts +++ b/packages/devkit/lib/store/form/validation/validators/min-value-validator.ts @@ -1,7 +1,7 @@ import { ValidationError, MinValueValidationRule } from '../types'; import { ValidatorUtil } from './validator-util'; import { BaseValidator } from './base-validator'; -import { BigNumber } from 'bignumber.js'; +import BigNumber from 'bignumber.js'; /** * 数值最小值验证器 */ diff --git a/packages/renderer/src/config-builders/form/validation-rule-creator.ts b/packages/renderer/src/config-builders/form/validation-rule-creator.ts index be90c3934..4156ebd40 100644 --- a/packages/renderer/src/config-builders/form/validation-rule-creator.ts +++ b/packages/renderer/src/config-builders/form/validation-rule-creator.ts @@ -99,7 +99,7 @@ class ValidationRuleCreator { * 最大值 */ public maxValue(controlNode: any): MaxValueValidationRule | undefined { - const { max: maxValue } = controlNode.editor; + const { max: maxValue, bigNumber = false } = controlNode.editor; if (!this.isValidValue(maxValue)) { return; } @@ -108,14 +108,14 @@ class ValidationRuleCreator { const originalMessage = LocaleService.translate('maxValue'); const message = originalMessage.replace(/\$property/g, displayName).replace(/\$constraint1/g, maxValue); - return { name: 'maxValue', maxValue, message, bigNumber: controlNode.bigNumber || false }; + return { name: 'maxValue', maxValue, message, bigNumber }; } /** * 最小值 */ public minValue(controlNode: any): MinValueValidationRule | undefined { - const { min: minValue } = controlNode.editor; + const { min: minValue, bigNumber = false } = controlNode.editor; if (!this.isValidValue(minValue)) { return; } @@ -124,7 +124,7 @@ class ValidationRuleCreator { const originalMessage = LocaleService.translate('minValue'); const message = originalMessage.replace(/\$property/g, displayName).replace(/\$constraint1/g, minValue); - return { name: 'minValue', minValue: minValue, message, bigNumber: controlNode.bigNumber || false }; + return { name: 'minValue', minValue: minValue, message, bigNumber }; } /** -- Gitee From 5ea75f5eda0e57dfee6733ee0dcc5a87d8f85af9 Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Sat, 6 Sep 2025 10:27:32 +0800 Subject: [PATCH 05/24] =?UTF-8?q?chore:=20=E9=99=84=E4=BB=B6=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0=E3=80=81=E6=89=B9=E9=87=8F=E4=B8=8A=E4=BC=A0=E5=B9=B6?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=A1=8C=E6=94=AF=E6=8C=81=E5=A4=9A=E9=99=84?= =?UTF-8?q?=E4=BB=B6=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/attachment/attachment.service.ts | 106 +++++++++++++++++- 1 file changed, 104 insertions(+), 2 deletions(-) diff --git a/packages/command-services/lib/attachment/attachment.service.ts b/packages/command-services/lib/attachment/attachment.service.ts index 622d53d42..971309e12 100644 --- a/packages/command-services/lib/attachment/attachment.service.ts +++ b/packages/command-services/lib/attachment/attachment.service.ts @@ -89,7 +89,70 @@ export class AttachmentService { return updatePromise; } - public uploadAndUpdateRowWithPropertyName(attachmentInfoFieldPath: string, rootDirId?: string, parentDirName?: string, fileType?: string, id?: string) { } + public uploadAndUpdateRowWithPropertyName(attachmentInfoFieldPath: string, rootDirId?: string, parentDirName?: string, fileType?: string, id?: string) { + const rootId = rootDirId ? rootDirId : this.defaultRootDirId; + const formId = parentDirName ? parentDirName : this.defaultParentDirName; + if (!rootId || !formId) { + throw new Error('rootDirId和parentDirName不能为空,请填写'); + } + + const uploadLimit: UploadLimit = new UploadLimit(); + uploadLimit.fileCount = 1; + if (fileType) { + uploadLimit.fileType = fileType; + } + + // 获取老的附件id数组 + const attachmentIdList: string[] = []; + let currentItem = null; + if (id) { + // 修正当前行 + const entityList = this.getEntityList(); + const currentEntity = entityList?.getCurrentEntity(); + if (currentEntity?.idValue !== id) { + entityList?.setCurrentId(id); + } + // 如果指定了id则获取指定id的行 + currentItem = this.getSpecialRow(attachmentInfoFieldPath, id); + } else { + // 没有指定则使用当前行,可能存在当前行和事件行不一致的情况,此时应该在命令中传递id参数 + currentItem = this.getSpecialRow(attachmentInfoFieldPath); + } + if (currentItem && currentItem.idValue) { + const attachmentIds = this.getAttachmentIdsByPathAndDataIds(attachmentInfoFieldPath, [currentItem.idValue]); + if (attachmentIds && attachmentIds.length > 0) { + attachmentIdList.push.apply(attachmentIdList, attachmentIds); + } + } else { + this.formNotifyService.warning(LocaleService.translate('pleaseSelectUpdateRow')); + return Promise.reject(); + } + + const uploadFileWithLimitPromise = this.uploadDialogService.uploadFileWithLimit(formId, rootId, uploadLimit, attachmentIdList); + const updatePromise = uploadFileWithLimitPromise.then((fileInfos: any) => { + if (!fileInfos || fileInfos.length === 0) { + this.formNotifyService.warning(LocaleService.translate('pleaseUploadFirst')); + return Promise.reject(); + } + // 过滤出state为新增的附件 + fileInfos = fileInfos.filter((fileInfo: UploadFileInfo) => { + if (fileInfo.hasOwnProperty('state')) { + return fileInfo.state === FileState.New; + } + return true; + }); + if (fileInfos.length === 0) { + return Promise.resolve(); + } + // 是否上传判断 + const attachmentInfos = AttachmentUtil.convertToAttachmentInfos(fileInfos); + const firstAttachmentInfo = AttachmentUtil.getFirstAttachmentInfo(attachmentInfos); + return this.attachmentDataService.updateRowWithPropertyName(attachmentInfoFieldPath, firstAttachmentInfo); + } + ); + + return updatePromise; + } public uploadAndBatchAddRows(attachmentInfoFieldPath: string, rootDirId?: string, parentDirName?: string, fileType?: string) { const rootId = rootDirId ? rootDirId : this.defaultRootDirId; @@ -125,7 +188,46 @@ export class AttachmentService { return updatePromise; } - public uploadAndBatchAddRowsWithPropertyName(attachmentInfoFieldPath: string, rootDirId?: string, parentDirName?: string, fileType?: string, id?: string) { } + public uploadAndBatchAddRowsWithPropertyName(attachmentInfoFieldPath: string, rootDirId?: string, parentDirName?: string, fileType?: string, id?: string) { + const rootId = rootDirId ? rootDirId : this.defaultRootDirId; + const formId = parentDirName ? parentDirName : this.defaultParentDirName; + if (!rootId || !formId) { + throw new Error('rootDirId和parentDirName不能为空,请填写'); + } + const uploadLimit: UploadLimit = new UploadLimit(); + if (fileType) { + uploadLimit.fileType = fileType; + } + if (id) { + // 修正当前行 + const bindingList: BindingList = this.frameContext.bindingData.getList(); + if (bindingList.currentId !== id) { + bindingList.setCurrentId(id, true, true); + } + } + const dialog$ = from(this.uploadDialogService.uploadFileWithLimit(formId, rootId, uploadLimit)); + const result$ = dialog$.pipe( + switchMap((fileInfos: UploadFileInfo[]) => { + if (!fileInfos || fileInfos.length === 0) { + this.notifyService.warning(this.languageService.plsUploadFirst, { hideTitle: true }); + return EMPTY; + } + // 过滤出state为新增的附件 + fileInfos = fileInfos.filter((fileInfo: UploadFileInfo) => { + if (fileInfo.hasOwnProperty('state')) { + return fileInfo.state === FileState.New; + } + return true; + }); + if (fileInfos.length === 0) { + return of(true); + } + const attachmentInfos = AttachmentUtil.convertToAttachmentInfos(fileInfos); + return this.attachDataService.updateRowsWithPropertyName(attachmentInfoFieldPath, attachmentInfos); + }) + ); + return result$; + } public download(attachId: string, rootId?: string) { if (!attachId) { -- Gitee From 96f7de76868a969b59c6cb8cea038b849fbcd4a4 Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Mon, 8 Sep 2025 12:00:37 +0800 Subject: [PATCH 06/24] =?UTF-8?q?chore:=20=E7=BB=84=E4=BB=B6=E4=BA=8B?= =?UTF-8?q?=E4=BB=B6=E7=BB=93=E6=9E=84=E5=A2=9E=E5=8A=A0payload=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=EF=BC=8C=E6=96=B9=E4=BE=BF=E5=BC=80=E5=8F=91=E4=BA=BA?= =?UTF-8?q?=E5=91=98=E8=8E=B7=E5=8F=96=E4=BA=8B=E4=BB=B6=E4=B8=8A=E4=B8=8B?= =?UTF-8?q?=E6=96=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/renderer/src/event/use-event.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/renderer/src/event/use-event.ts b/packages/renderer/src/event/use-event.ts index 5de8a78ae..213fef232 100644 --- a/packages/renderer/src/event/use-event.ts +++ b/packages/renderer/src/event/use-event.ts @@ -38,7 +38,7 @@ function useEvent(module: Module) { function appendCommunicationBinding(eventContext: any, eventBinding: string): string { const { type, payload, componentSchema, viewModel, isCallback } = eventContext; const module = viewModel.getModule(); - const communicationConfigs = getCommunicationConfigs(type, payload, componentSchema, module, isCallback); + const communicationConfigs = getCommunicationConfigs(type, payload, componentSchema, module, isCallback); if (!Array.isArray(communicationConfigs)) { return eventBinding; } @@ -97,7 +97,7 @@ function useEvent(module: Module) { if (!viewModel) { throw new Error(`ViewModel(id=${componentId}) does not exist`); } - + const callbackContext: EventContext = { type: callbackType, payload: callbackArgs, @@ -125,7 +125,10 @@ function useEvent(module: Module) { function dispatchEvent(event: any): void { // 转发事件 - const { name, type: componentType, schema: componentSchema } = event; + const { name, type: componentType, schema: componentSchema, payloads } = event; + if (!Object.prototype.hasOwnProperty.call(event, 'payload')) { + event.payload = Array.isArray(payloads) ? payloads[0] : payloads; + } eventEmitter.emit(name, event); // 获取绑定处理器 -- Gitee From 29cbb0fb0756051b46104368ddb883627a0e5342 Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Mon, 8 Sep 2025 14:07:53 +0800 Subject: [PATCH 07/24] =?UTF-8?q?feature:=20=E6=94=AF=E6=8C=81=E6=8C=89?= =?UTF-8?q?=E5=B1=9E=E6=80=A7=E6=89=B9=E9=87=8F=E4=B8=8A=E4=BC=A0=E5=B9=B6?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/attachment/attachment.service.ts | 51 +++++++++---------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/packages/command-services/lib/attachment/attachment.service.ts b/packages/command-services/lib/attachment/attachment.service.ts index 971309e12..e184e5eb1 100644 --- a/packages/command-services/lib/attachment/attachment.service.ts +++ b/packages/command-services/lib/attachment/attachment.service.ts @@ -93,7 +93,7 @@ export class AttachmentService { const rootId = rootDirId ? rootDirId : this.defaultRootDirId; const formId = parentDirName ? parentDirName : this.defaultParentDirName; if (!rootId || !formId) { - throw new Error('rootDirId和parentDirName不能为空,请填写'); + throw new Error('根目录及子目录不能为空,请填写'); } const uploadLimit: UploadLimit = new UploadLimit(); @@ -192,7 +192,7 @@ export class AttachmentService { const rootId = rootDirId ? rootDirId : this.defaultRootDirId; const formId = parentDirName ? parentDirName : this.defaultParentDirName; if (!rootId || !formId) { - throw new Error('rootDirId和parentDirName不能为空,请填写'); + throw new Error('根目录及子目录不能为空,请填写'); } const uploadLimit: UploadLimit = new UploadLimit(); if (fileType) { @@ -200,33 +200,32 @@ export class AttachmentService { } if (id) { // 修正当前行 - const bindingList: BindingList = this.frameContext.bindingData.getList(); - if (bindingList.currentId !== id) { - bindingList.setCurrentId(id, true, true); + const entityList = this.getEntityList(); + const currentEntity = entityList?.getCurrentEntity(); + if (currentEntity?.idValue !== id) { + entityList?.setCurrentId(id); } } - const dialog$ = from(this.uploadDialogService.uploadFileWithLimit(formId, rootId, uploadLimit)); - const result$ = dialog$.pipe( - switchMap((fileInfos: UploadFileInfo[]) => { - if (!fileInfos || fileInfos.length === 0) { - this.notifyService.warning(this.languageService.plsUploadFirst, { hideTitle: true }); - return EMPTY; - } - // 过滤出state为新增的附件 - fileInfos = fileInfos.filter((fileInfo: UploadFileInfo) => { - if (fileInfo.hasOwnProperty('state')) { - return fileInfo.state === FileState.New; - } - return true; - }); - if (fileInfos.length === 0) { - return of(true); + const uploadFileWithLimitPromise = this.uploadDialogService.uploadFileWithLimit(formId, rootId, uploadLimit); + const updatePromise = uploadFileWithLimitPromise.then((fileInfos: any) => { + if (!fileInfos || fileInfos.length === 0) { + this.formNotifyService.warning(LocaleService.translate('pleaseUploadFirst')); + return Promise.reject(); + } + // 过滤出state为新增的附件 + fileInfos = fileInfos.filter((fileInfo: UploadFileInfo) => { + if (fileInfo.hasOwnProperty('state')) { + return fileInfo.state === FileState.New; } - const attachmentInfos = AttachmentUtil.convertToAttachmentInfos(fileInfos); - return this.attachDataService.updateRowsWithPropertyName(attachmentInfoFieldPath, attachmentInfos); - }) - ); - return result$; + return true; + }); + if (fileInfos.length === 0) { + return Promise.resolve(); + } + const attachmentInfos = AttachmentUtil.convertToAttachmentInfos(fileInfos); + return this.attachmentDataService.updateRowsWithPropertyName(attachmentInfoFieldPath, attachmentInfos); + }); + return updatePromise; } public download(attachId: string, rootId?: string) { -- Gitee From 1959667163b113264583f7a302585d517061a03e Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Mon, 8 Sep 2025 14:14:49 +0800 Subject: [PATCH 08/24] =?UTF-8?q?chore:=20=E9=99=84=E4=BB=B6=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=E5=99=A8=E5=A2=9E=E5=8A=A0=E9=80=9A=E8=BF=87=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E5=90=8D=E4=B8=8A=E4=BC=A0=E5=B9=B6=E6=89=B9=E9=87=8F?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=A1=8C=E3=80=81=E9=80=9A=E8=BF=87=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E5=90=8D=E4=B8=8A=E4=BC=A0=E5=B9=B6=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E8=A1=8C=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../supported-controllers/pc-supported-controller.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/designer/src/components/composition/command/supported-controllers/pc-supported-controller.json b/packages/designer/src/components/composition/command/supported-controllers/pc-supported-controller.json index 9d748bc10..832500d04 100644 --- a/packages/designer/src/components/composition/command/supported-controllers/pc-supported-controller.json +++ b/packages/designer/src/components/composition/command/supported-controllers/pc-supported-controller.json @@ -548,10 +548,18 @@ "id": "2a84e28f-7202-d858-1466-748a8040c1f9", "code": "UploadAndUpdateRow" }, + { + "id": "0f98c9b8-a01b-55d4-3115-269a73f7ccff", + "code": "uploadAndUpdateRowWithPropertyName" + }, { "id": "e6fc25ca-853b-0b2d-76c9-a1f7a253679b", "code": "UploadAndBatchAddRows" }, + { + "id": "e00b70db-9de3-8e3e-eb59-1c550a255fec", + "code": "uploadAndBatchAddRowsWithPropertyName" + }, { "id": "be2a6cc1-9357-9374-cc8e-5665e6bc1bdc", "code": "download" -- Gitee From 3a9d42b7e5428efb0ae78819db6f9a1d92d03ede Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Wed, 10 Sep 2025 09:27:23 +0800 Subject: [PATCH 09/24] =?UTF-8?q?chore:=20bef=E4=BB=A3=E7=90=86=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=90=AF=E7=94=A8=E3=80=81=E5=81=9C=E7=94=A8=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/bef/lib/bef-proxy.ts | 30 ++++++++++++++++++++++++++++++ packages/bef/lib/bef-repository.ts | 6 +++--- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/packages/bef/lib/bef-proxy.ts b/packages/bef/lib/bef-proxy.ts index 2103e3ddc..67eef0ec3 100644 --- a/packages/bef/lib/bef-proxy.ts +++ b/packages/bef/lib/bef-proxy.ts @@ -342,6 +342,36 @@ export class BefProxy { return this.request(HttpMethods.POST, url, requestConfig); }); } + /** + * 启用 + * @param id 数据id + * @returns + */ + public enable(id: string): Promise { + return this.wrapAsync(() => { + const url = `${this.baseUrl}/service/enable`; + const bodyWithRequestInfo = this.proxyExtend.extendBody({ dataId: id }); + const requestConfig: HttpRequestConfig = { + body: bodyWithRequestInfo + }; + return this.request(HttpMethods.PUT, url, requestConfig); + }); + } + /** + * 停用 + * @param id 数据id + * @returns + */ + public disable(id: string): Promise { + return this.wrapAsync(() => { + const url = `${this.baseUrl}/service/disable`; + const bodyWithRequestInfo = this.proxyExtend.extendBody({ dataId: id }); + const requestConfig: HttpRequestConfig = { + body: bodyWithRequestInfo + }; + return this.request(HttpMethods.PUT, url, requestConfig); + }); + } /** * 父节点分级方式新增同级 * @param id diff --git a/packages/bef/lib/bef-repository.ts b/packages/bef/lib/bef-repository.ts index 9e4c5113b..340cc4b1b 100644 --- a/packages/bef/lib/bef-repository.ts +++ b/packages/bef/lib/bef-repository.ts @@ -69,7 +69,7 @@ class BefRepository extends Repository { if (config.isDynamic) { this.apiProxy = this.injector.get(BefProxy); this.apiProxy.init(config.baseUrl); - + } else { this.apiProxy = this.injector.get(config.apiProxyType); } @@ -277,8 +277,8 @@ class BefRepository extends Repository { * @param ids * @returns */ - public removeEntitiesAndSave(ids: string[]){ - const removePromise = this.apiProxy.batchDeleteAndSave(ids).then(()=>{ + public removeEntitiesAndSave(ids: string[]) { + const removePromise = this.apiProxy.batchDeleteAndSave(ids).then(() => { return true; }); return removePromise; -- Gitee From a950e56d9dccfa59a1abbc5bd047af96e2977cf8 Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Wed, 10 Sep 2025 11:58:32 +0800 Subject: [PATCH 10/24] =?UTF-8?q?chore:=20=E6=96=B0=E5=A2=9E=E6=A0=91?= =?UTF-8?q?=E8=A1=A8=E6=A0=BC=E8=8A=82=E7=82=B9=E5=B1=95=E5=BC=80=E4=BA=8B?= =?UTF-8?q?=E4=BB=B6=E5=A4=84=E7=90=86=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/renderer/src/event-handler/index.ts | 1 + .../renderer/src/event-handler/providers.ts | 4 +- .../tree-grid-expand-node-event-handler.ts | 53 +++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 packages/renderer/src/event-handler/tree-grid-expand-node-event-handler.ts diff --git a/packages/renderer/src/event-handler/index.ts b/packages/renderer/src/event-handler/index.ts index 3a1fef748..864d882d5 100644 --- a/packages/renderer/src/event-handler/index.ts +++ b/packages/renderer/src/event-handler/index.ts @@ -9,4 +9,5 @@ export * from './data-grid-page-size-change-event-handler'; export * from './data-grid-selection-change-event-handler'; export * from './query-solution-condition-change-event-handler'; export * from './data-grid-double-click-row-event-handler'; +export * from './tree-grid-expand-node-event-handler'; export * from './providers'; diff --git a/packages/renderer/src/event-handler/providers.ts b/packages/renderer/src/event-handler/providers.ts index ebed75a3b..74fc44bb3 100644 --- a/packages/renderer/src/event-handler/providers.ts +++ b/packages/renderer/src/event-handler/providers.ts @@ -13,6 +13,7 @@ import { DataGridSelectionChangeEventHandler } from "./data-grid-selection-chang import { QuerySolutionConditionChangeEventHandler } from "./query-solution-condition-change-event-handler"; import { DataGridDoubleClickRowEventHandler } from './data-grid-double-click-row-event-handler'; import { ModalClosedEventHandler } from './modal-closed-event-handler'; +import { TreeGridExpandNodeEventHandler } from "./tree-grid-expand-node-event-handler"; export const eventHanderProviders: StaticProvider[] = [ { provide: EVENT_HANDLERS_TOKEN, useClass: LookupDataMappingEventHandler, deps: [EventEmitter, FormMetadataService, Module, Injector], multi: true }, @@ -25,5 +26,6 @@ export const eventHanderProviders: StaticProvider[] = [ { provide: EVENT_HANDLERS_TOKEN, useClass: DataGridSelectionChangeEventHandler, deps: [EventEmitter, FormMetadataService, Module, Injector], multi: true }, { provide: EVENT_HANDLERS_TOKEN, useClass: QuerySolutionConditionChangeEventHandler, deps: [EventEmitter, FormMetadataService, Module, Injector], multi: true }, { provide: EVENT_HANDLERS_TOKEN, useClass: DataGridDoubleClickRowEventHandler, deps: [EventEmitter, FormMetadataService, Module, Injector], multi: true }, - { provide: EVENT_HANDLERS_TOKEN, useClass: ModalClosedEventHandler, deps: [EventEmitter, FormMetadataService, Module, Injector], multi: true } + { provide: EVENT_HANDLERS_TOKEN, useClass: ModalClosedEventHandler, deps: [EventEmitter, FormMetadataService, Module, Injector], multi: true }, + { provide: EVENT_HANDLERS_TOKEN, useClass: TreeGridExpandNodeEventHandler, deps: [EventEmitter, FormMetadataService, Module, Injector], multi: true } ]; diff --git a/packages/renderer/src/event-handler/tree-grid-expand-node-event-handler.ts b/packages/renderer/src/event-handler/tree-grid-expand-node-event-handler.ts new file mode 100644 index 000000000..6a850b194 --- /dev/null +++ b/packages/renderer/src/event-handler/tree-grid-expand-node-event-handler.ts @@ -0,0 +1,53 @@ +import { Injector, Module, ViewModel, ViewModelState } from "@farris/devkit-vue"; +import { EventEmitter } from "../common"; +import { FormMetadataService } from "../service"; +import { ViewEvent } from "../types"; +import { EventHandler } from "./types"; +import { DataSourceResolver } from "../resolvers"; + +export class TreeGridExpandNodeEventHandler implements EventHandler { + constructor(private emitter: EventEmitter, private formMetadataService: FormMetadataService, private module: Module, private injector: Injector) { + } + + bind(): void { + this.emitter.on('expandNode', (payload: ViewEvent) => this.onExpandNode(payload)); + } + + dispose(): void { + this.emitter.on('expandNode', (payload: ViewEvent) => this.onExpandNode(payload)); + } + + private onExpandNode(event: ViewEvent) { + if (!event) { + return; + } + const { token, type } = event; + if (type !== 'tree-grid' || !token) { + return; + } + const component = this.formMetadataService.getMetadataById(token); + if (!component) { + return; + } + const { id, dataSource } = component; + if (!id || !dataSource) { + return; + } + const relatedComponent = this.formMetadataService.getRelatedComponent(id); + if (!relatedComponent) { + return; + } + const viewModel = this.module.getViewModel(relatedComponent.id); + if (!viewModel) { + return; + } + const { payload } = event; + const resolvedEntity = DataSourceResolver.resolve(this.formMetadataService.getEntity(), dataSource); + if (!resolvedEntity) { + return; + } + const idKey = resolvedEntity.primaryKey; + const rootViewModel = viewModel.getRoot() as ViewModel; + rootViewModel.uiStore?.setValue('__TREE_LATEST_EXPANDED_ID__', payload[idKey]); + } +} -- Gitee From 51fc83607336b4de683b50e18d53e989032a285d Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Wed, 10 Sep 2025 13:45:17 +0800 Subject: [PATCH 11/24] =?UTF-8?q?chore:=20=E6=A0=91=E8=A1=A8=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E5=A2=9E=E5=8A=A0=E5=8A=A0=E8=BD=BD=E5=AE=8C=E6=95=B4?= =?UTF-8?q?=E6=A0=91=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/data-services/tree-data.service.ts | 79 ++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/packages/command-services/lib/data-services/tree-data.service.ts b/packages/command-services/lib/data-services/tree-data.service.ts index 787866d1c..c6e605d37 100644 --- a/packages/command-services/lib/data-services/tree-data.service.ts +++ b/packages/command-services/lib/data-services/tree-data.service.ts @@ -36,7 +36,80 @@ export class TreeDataService extends BaseDataService { return loadPromise; } public loadByLevel(filters?: string, sorts?: string, frozenCurrentRow?: boolean | string) { } - public loadFullTree(virtualPropertyName: string, fullTreeType: string, loadType: string, filters: string, frozenCurrentRow?: boolean | string) { } + public loadFullTree(virtualPropertyName: string, fullTreeType: string, loadType: string, filters: string, frozenCurrentRow?: boolean | string) { + if (typeof fullTreeType !== 'string') { + throw new Error('ArgumentError: fullTreeType 不能为空且必须为字符串。'); + } + if (typeof loadType !== 'string') { + throw new Error('ArgumentError: loadType 不能为空且必须为字符串。'); + } + if (frozenCurrentRow === undefined) { + frozenCurrentRow = false; + } + if (typeof frozenCurrentRow !== 'boolean') { + frozenCurrentRow = frozenCurrentRow === 'true' ? true : false; + } + const virtualRootFrameContext = this.virtualRootFrameContext; + // 还原上次设置的结果集 + virtualRootFrameContext.params.delete('_DEVKIT_expandRowIds'); + virtualRootFrameContext.params.delete('_DEVKIT_selectedRowId'); + virtualRootFrameContext.uiState.setPropertyValue('__DEVKIT__selectedRow', null); + const filtersArray = this.parseConditions(filters); + const parentId = this.getIdToExpand(); + const correctSelectedNode = this.repository.entityCollection.count() === 0; + const hierarchyType = this.getHierarchyType(); + const repository = TreeRepositoryFactory.getInstance(hierarchyType); + + if (repository === null) { + return EMPTY; + } + const loadingTimerId = this.loadingService.showLoadingWithDelay(500); + const context = { + frameContext: this.frameContext, + frozenCurrentRow + }; + // tslint:disable-next-line: max-line-length + const query$ = repository.loadFullTree(this.repository, this.hierarchyInfoKey, parentId, virtualPropertyName, fullTreeType, loadType, filtersArray, context); + return query$.pipe( + tap( + (entities: Entity[]) => { + const selectedRowId = virtualRootFrameContext.params.get('_DEVKIT_selectedRowId'); + // 纠正选中节点 + if (correctSelectedNode === true) { + const treeNodeUtil = TreeUtilFactory.getInstance(hierarchyType); + if (treeNodeUtil !== null) { + const computedFirstRowId = selectedRowId || treeNodeUtil.selectFirstRootNode(this.bindingData, this.hierarchyInfoKey); + if (computedFirstRowId) { + virtualRootFrameContext.uiState.setPropertyValue('__DEVKIT__selectedRow', computedFirstRowId); + } + } + } + if (frozenCurrentRow && parentId) { + const currentRowId = this.bindingData.list.currentItem.primaryKeyValue; + // 冻结当前行启用时则不再关心后端返回的选中行 + virtualRootFrameContext.uiState.setPropertyValue('__DEVKIT__selectedRow', null); + // 如果上一次选中行为本次加载数据中的一条,则应该重新选中该行 + const containsCurrentRow = entities.find((item) => item.primaryValue === currentRowId); + if (containsCurrentRow) { + this.setCurrentId(currentRowId); + } + // 原来的当前行不在已经加载的数据中,如展开到第三级,将第三级的某行设为当前行,全部收起,展开第一级 + if (!this.repository.entityCollection.getEntityById(currentRowId) && entities && entities.length > 0) { + const firstChildId = entities && Array.isArray(entities) && entities.length > 0 && entities[0].primaryValue || null; + if (firstChildId) { + this.setCurrentId(firstChildId); + } + } + } + this.loadingService.hideDelayLoading(loadingTimerId); + }, + (error) => { + this.loadingService.hideDelayLoading(loadingTimerId); + this.errorService.exception(this.languageService.loadFailed, error); + } + ) + ); + } public addSibling(id: string) { id = id ? id : this.viewModel.entityStore?.getCurrentEntity().idValue; // 参数检查 @@ -253,4 +326,8 @@ export class TreeDataService extends BaseDataService { const conditionsString = (!conditions || conditions === '') ? '[]' : conditions; return JSON.parse(conditionsString); } + private getIdToExpand() { + const rootViewModel = this.viewModel.getRoot() as ViewModel; + return rootViewModel.uiStore?.getValue('__TREE_LATEST_EXPANDED_ID__'); + } } \ No newline at end of file -- Gitee From 0a4e170241b4969f9fd8ccdf1eaf270adab4a16e Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Wed, 10 Sep 2025 14:50:24 +0800 Subject: [PATCH 12/24] =?UTF-8?q?chore:=20=E5=BC=80=E6=94=BE=E9=99=84?= =?UTF-8?q?=E4=BB=B6=E6=8E=A7=E5=88=B6=E5=99=A8=E4=B8=AD=E9=A2=84=E8=A7=88?= =?UTF-8?q?=E7=9B=AE=E5=BD=95=E4=B8=8B=E6=8C=87=E5=AE=9A=E7=B4=A2=E5=BC=95?= =?UTF-8?q?=E7=9A=84=E9=99=84=E4=BB=B6=E7=AD=89=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pc-supported-controller.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/designer/src/components/composition/command/supported-controllers/pc-supported-controller.json b/packages/designer/src/components/composition/command/supported-controllers/pc-supported-controller.json index 7ec241d2a..b64db625e 100644 --- a/packages/designer/src/components/composition/command/supported-controllers/pc-supported-controller.json +++ b/packages/designer/src/components/composition/command/supported-controllers/pc-supported-controller.json @@ -583,6 +583,18 @@ { "id": "b707e9c2-61c7-01d8-bd0e-aac222271602", "code": "PreviewBySubDirName" + }, + { + "id": "d1a96164-0eb7-c321-1d25-f61ffd3ec603", + "code": "PreviewByAttachmentInfoFieldPath" + }, + { + "id": "5340b0fe-def2-77df-6c0c-016f45e988e9", + "code": "previewBySubDirNameWithIndex" + }, + { + "id": "8a6cbbfd-052f-6197-cd9e-49a9ad1c2cd6", + "code": "previewByAttachmentInfoFieldPathWithIndex" } ] } \ No newline at end of file -- Gitee From c081b66951305d416ac4ee4408c6db50705219be Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Thu, 11 Sep 2025 14:34:35 +0800 Subject: [PATCH 13/24] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=A2=84?= =?UTF-8?q?=E8=A7=88=E9=99=84=E4=BB=B6=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../command-services/lib/attachment/attachment.service.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/command-services/lib/attachment/attachment.service.ts b/packages/command-services/lib/attachment/attachment.service.ts index e184e5eb1..cb0c79a08 100644 --- a/packages/command-services/lib/attachment/attachment.service.ts +++ b/packages/command-services/lib/attachment/attachment.service.ts @@ -356,8 +356,9 @@ export class AttachmentService { const attachmentFieldName = propertyPaths?.pop(); const path = `/${entityPaths.join('/')}`; const bindingList = this.viewModel.entityStore?.getEntityListByPath(path); - const currentItem = bindingList?.getCurrentEntity().toJSON(); - if (currentItem && currentItem.idValue) { + const currentEntity = bindingList?.getCurrentEntity(); + const currentItem = currentEntity?.toJSON(); + if (currentItem && currentEntity?.idValue) { return currentItem[attachmentFieldName] && currentItem[attachmentFieldName]['attachmentId'] || null; } else { return null; -- Gitee From 428035012eecb67faa0abee415d8fad85e43d165 Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Fri, 12 Sep 2025 11:07:37 +0800 Subject: [PATCH 14/24] =?UTF-8?q?chore:=20=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E6=9E=84=E4=BB=B6=E5=9F=BA=E7=B1=BB=E4=B8=AD=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?context=E8=81=9A=E5=90=88=E6=96=B9=E6=B3=95=EF=BC=8C=E6=96=B9?= =?UTF-8?q?=E4=BE=BF=E5=BC=80=E5=8F=91=E4=BA=BA=E5=91=98=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/controller.service.ts | 144 +++++++++++++++++- .../lib/form-loading.service.ts | 2 +- packages/command-services/lib/types.ts | 83 +++++++++- .../lib/command/dynamic-command-handler.ts | 28 ++-- 4 files changed, 241 insertions(+), 16 deletions(-) diff --git a/packages/command-services/lib/controller.service.ts b/packages/command-services/lib/controller.service.ts index c95a0b6f3..248c68aba 100644 --- a/packages/command-services/lib/controller.service.ts +++ b/packages/command-services/lib/controller.service.ts @@ -1,5 +1,5 @@ -import { Entity, Injector, ViewModel, ViewModelState } from '@farris/devkit-vue'; -import { BefProxy, BefRepository } from '@farris/bef-vue'; +import { Entity, HttpMethod, HttpMethods, HttpRequestConfig, Injector, ViewModel, ViewModelState } from '@farris/devkit-vue'; +import { BefProxy, BefRepository, RequestInfoUtil } from '@farris/bef-vue'; import { RenderEngineService } from './render-engine.service'; import { TemplateService } from './template.service'; import { FormLoadingService } from './form-loading.service'; @@ -8,6 +8,9 @@ import { FormNotifyService } from './form-notify.service'; import { CommandService } from './command.service'; import { CardDataService, ListDataService } from './data-services'; import { ContextService } from './devkit-services/index'; +import { ApiClientContext, ControllerContext, I18nContext, UIContext } from './types'; +import { TranslateService } from './locale'; +import { DialogService } from './dialog.service'; export class ControllerService { protected injector: Injector; @@ -22,6 +25,10 @@ export class ControllerService { protected cardDataService: CardDataService; protected repository: BefRepository; protected apiProxy: BefProxy; + protected translateService: TranslateService; + protected dialogService: DialogService; + + public context: ControllerContext; constructor(protected viewModel: ViewModel) { this.injector = this.viewModel.getInjector(); @@ -36,6 +43,9 @@ export class ControllerService { this.cardDataService = this.injector.get(CardDataService); this.repository = this.viewModel.repository as BefRepository; this.apiProxy = this.repository?.apiProxy; + this.translateService = this.injector.get(TranslateService); + this.dialogService = this.injector.get(DialogService); + this.context = this.buildContext(); } /** @@ -52,9 +62,135 @@ export class ControllerService { public getEventParams(): any { const context = (this as any)['context'] as any; if (context && context.command && context.command.eventParams) { - return context.command.eventParams + return context.command.eventParams; } - + return null; } + private buildContext(): ControllerContext { + return { + apiClient: this.buildApiClientContext(), + ui: this.buildUIContext(), + i18n: this.buildI18nContext() + }; + } + private buildUIContext(): UIContext { + return { + showLoading: this.formLoadingService.show.bind(this.formLoadingService), + hideLoading: this.formLoadingService.hide.bind(this.formLoadingService), + showLoadingWithDelay: this.formLoadingService.showLoadingWithDelay.bind(this.formLoadingService), + hideDelayLoading: this.formLoadingService.hideDelayLoading.bind(this.formLoadingService), + showNotify: (content, type) => { + switch (type) { + case 'info': this.formNotifyService.info(content); + case 'success': this.formNotifyService.success(content); + case 'warning': this.formNotifyService.warning(content); + case 'error': this.formNotifyService.error(content); + default: this.formNotifyService.info(content); + } + }, + showMessage: (content, type) => { + switch (type) { + case 'info': this.formMessageService.info(content); + case 'success': this.formMessageService.success(content); + case 'warning': this.formMessageService.warning(content); + case 'error': this.formMessageService.error(content); + default: this.formMessageService.info(content); + } + }, + openModal: this.dialogService.openModal.bind(this.dialogService), + openLookup: this.dialogService.openLookup.bind(this.dialogService) + }; + } + private buildApiClientContext(): ApiClientContext { + return { + /** + * 使用GET方法调用后端接口 + * @param url api地址 + * @param requestConfig requestConfig + * @returns + * @description 该接口仅用于调用表单后端接口,会自动组装requestInfo,如调用非表单接口(框架接口、外部接口)请使用HttpClient,否则可能会导致变更丢失问题。 + */ + get: (url: string, requestConfig?) => { + return this.apiProxy.request(HttpMethods.GET, url, requestConfig); + }, + /** + * 使用POST方法调用后端接口 + * @param url api地址 + * @param body 除requestInfo外的自定义参数 + * @param requestConfig + * @returns + * @description 该接口仅用于调用表单后端接口,会自动组装requestInfo,如调用非表单接口(框架接口、外部接口)请使用HttpClient,否则可能会导致变更丢失问题。 + */ + post: (url: string, body?: any, requestConfig?: HttpRequestConfig,) => { + requestConfig = this.extendRequestConfig(requestConfig, body); + return this.apiProxy.request(HttpMethods.POST, url, requestConfig); + }, + /** + * 使用PATCH方法调用后端接口 + * @param url api地址 + * @param body 除requestInfo外的自定义参数 + * @param requestConfig requestConfig + * @returns + * @description 该接口仅用于调用表单后端接口,会自动组装requestInfo,如调用非表单接口(框架接口、外部接口)请使用HttpClient,否则可能会导致变更丢失问题。 + */ + patch: (url: string, body?: any, requestConfig?: HttpRequestConfig) => { + requestConfig = this.extendRequestConfig(requestConfig, body); + return this.apiProxy.request(HttpMethods.PATCH, url, requestConfig); + }, + /** + * 使用PUT方法调用后端接口 + * @param url api地址 + * @param body 除requestInfo外的自定义参数 + * @param requestConfig requestConfig + * @returns + * @description 该接口仅用于调用表单后端接口,会自动组装requestInfo,如调用非表单接口(框架接口、外部接口)请使用HttpClient,否则可能会导致变更丢失问题。 + */ + put: (url: string, body?: any, requestConfig?: HttpRequestConfig) => { + requestConfig = this.extendRequestConfig(requestConfig, body); + return this.apiProxy.request(HttpMethods.PUT, url, requestConfig); + }, + /** + * 使用DELETE方法调用后端接口 + * @param url api地址 + * @param requestConfig requestConfig + * @returns + * @description 该接口仅用于调用表单后端接口,会自动组装requestInfo,如调用非表单接口(框架接口、外部接口)请使用HttpClient,否则可能会导致变更丢失问题。 + */ + delete: (url: string, requestConfig?: HttpRequestConfig) => { + return this.apiProxy.request(HttpMethods.DELETE, url, requestConfig); + }, + /** + * 调用后端接口 + * @param url api地址 + * @param method HttpMethod + * @param requestConfig requestConfig + * @returns + * @description 该接口仅用于调用表单后端接口,会自动组装requestInfo,如调用非表单接口(框架接口、外部接口)请使用HttpClient,否则可能会导致变更丢失问题。 + */ + request: (url: string, method: HttpMethod, requestConfig?: HttpRequestConfig) => { + requestConfig = this.extendRequestConfig(requestConfig); + return this.apiProxy.request(method, url, requestConfig); + }, + }; + } + private extendRequestConfig(requestConfig?: HttpRequestConfig, body?: any): HttpRequestConfig { + requestConfig = requestConfig || { body: {} }; + const requestInfo = RequestInfoUtil.buildRequestInfo(this.repository); + requestConfig.body = { + requestInfo, + ...requestConfig.body, + ...(body || {}) + }; + if (Object.keys(requestConfig.body).length === 1 && 'requestInfo' in requestConfig.body) { + requestConfig.body = requestConfig.body.requestInfo; + } + return requestConfig; + } + private buildI18nContext(): I18nContext { + return { + locale: this.viewModel.getModule().getLocale(), + translate: this.translateService.transform.bind(this.translateService) + }; + } } \ No newline at end of file diff --git a/packages/command-services/lib/form-loading.service.ts b/packages/command-services/lib/form-loading.service.ts index 806d7a738..519e712ed 100644 --- a/packages/command-services/lib/form-loading.service.ts +++ b/packages/command-services/lib/form-loading.service.ts @@ -12,7 +12,7 @@ export class FormLoadingService { * @param configOrMessage * @returns */ - public show(configOrMessage?: any): number | undefined | null { + public show(configOrMessage?: any): number | undefined { if (this.loadingService) { const config = this.buildConfig(configOrMessage); const loadingComponent = this.loadingService.show(config); diff --git a/packages/command-services/lib/types.ts b/packages/command-services/lib/types.ts index 0c1d787b0..009da8d28 100644 --- a/packages/command-services/lib/types.ts +++ b/packages/command-services/lib/types.ts @@ -1,4 +1,6 @@ import { RequestInfo } from '@farris/bef-vue'; +import { HttpMethod, HttpRequestConfig } from '@farris/devkit-vue'; +import { LookupConfig, ModalConfig } from './dialog.service'; export const AppType = { App: 'app', @@ -34,7 +36,7 @@ export const TAB_EVENT = { */ export interface TabClosingConfirmResult { confirmResult: boolean; - confirmType: 'User' | 'NoChange' + confirmType: 'User' | 'NoChange'; } export const TAB_QUERY_STRING = { @@ -129,3 +131,82 @@ export interface BuildFrameworkTabIdOptions { funcId?: string; tabId?: string; } + +export interface ApiClientContext { + /** + * 发送get请求 + * @param url 请求地址 + * @param requestConfig requestConfig + */ + get(url: string, requestConfig?: HttpRequestConfig): Promise; + /** + * 发送POST请求 + * @param url 请求地址 + * @param body 请求体 + * @param requestConfig requestConfig + */ + post(url: string, body: any, requestConfig?: HttpRequestConfig): Promise; + /** + * 发送PUT请求 + * @param url 请求地址 + * @param body 请求体 + * @param requestConfig + */ + put(url: string, body: any, requestConfig?: HttpRequestConfig): Promise; + /** + * 发送PATCH请求 + * @param url 请求地址 + * @param body 请求体 + * @param requestConfig requestConfig + */ + patch(url: string, body: any, requestConfig?: HttpRequestConfig): Promise; + /** + * 发送DELETE请求 + * @param url 请求地址 + * @param requestConfig requestConfig + */ + delete(url: string, requestConfig?: HttpRequestConfig): Promise; + /** + * 发送请求 + * @param url 请求地址 + * @param method 请求方法 + * @param requestConfig requestConfig + */ + request(url: string, method: HttpMethod, requestConfig?: HttpRequestConfig): Promise; +} +export interface I18nContext { + /** + * 多语翻译 + * @param key + * @param defaultValue + */ + translate(key: string, defaultValue?: string): string; + /** + * 当前语言 + */ + readonly locale: string; +} +export interface UIContext { + showLoading(configOrMessage?: any): number | undefined; + hideLoading(loadingId: number): void; + showLoadingWithDelay(delayTime: number, configOrMessage?: any): number; + hideDelayLoading(timerId: number): void; + showNotify(content: string, type: 'info' | 'success' | 'warning' | 'error'): void; + showMessage(content: string, type: 'info' | 'success' | 'warning' | 'error'): void; + openModal(config: string | ModalConfig, modalId: string, params: string | Record, callback?: (modalRef: any) => any): void; + openLookup(config: string | LookupConfig, lookupId: string): void; +} +export interface ControllerContext { + /** + * api客户端 + */ + apiClient: ApiClientContext; + /** + * 多语 + */ + i18n: I18nContext; + /** + * 界面上下文 + */ + ui: UIContext; +} diff --git a/packages/devkit/lib/command/dynamic-command-handler.ts b/packages/devkit/lib/command/dynamic-command-handler.ts index 28b36ed3a..a7faa784e 100644 --- a/packages/devkit/lib/command/dynamic-command-handler.ts +++ b/packages/devkit/lib/command/dynamic-command-handler.ts @@ -70,20 +70,28 @@ class DynamicCommandHandler extends CommandHandler { const serviceInstancePromise = this.getServiceInstance(taskConfig, taskFlowContext.commandContext); if (TypeUtil.isPromise(serviceInstancePromise)) { - return serviceInstancePromise.then((serviceInstance) => { - serviceInstance['context'] = taskFlowContext.commandContext; + return serviceInstancePromise.then((serviceInstance) => { + this.extendService(serviceInstance, taskFlowContext.commandContext); return serviceInstance[methodName](...methodParams); }); } else { const serviceInstance = serviceInstancePromise; - serviceInstance['context'] = taskFlowContext.commandContext; + this.extendService(serviceInstance, taskFlowContext.commandContext); return serviceInstance[methodName](...methodParams); } }; return taskFunc; } - + private extendService(serviceInstance: any, commandContext: CommandContext) { + serviceInstance.context = serviceInstance.context || {}; + serviceInstance.context.command = commandContext.command; + serviceInstance.context.viewModel = commandContext.viewModel; + serviceInstance.context.getEventParam = commandContext.getEventParam.bind(commandContext); + serviceInstance.context.getVariableParseService = commandContext.getVariableParseService.bind(commandContext); + serviceInstance.context.getViewModel = commandContext.getViewModel.bind(commandContext); + serviceInstance.context.getViewModelInjector = commandContext.getViewModelInjector.bind(commandContext); + } /** * 获取服务实例 */ @@ -111,7 +119,7 @@ class DynamicCommandHandler extends CommandHandler { provide: serviceClass, useClass: serviceClass, deps: serviceDeps - } + }; const injector = createInjector([provider], parentInjector); const serviceInstance = injector.get(serviceClass); @@ -166,7 +174,7 @@ class DynamicCommandHandler extends CommandHandler { const taskLinkFunc = this.createTaskLinkFunc(taskLinkConfig.conditions); const taskLink = new TaskLink(nextTaskName, taskLinkFunc); taskLinks.push(taskLink); - }) + }); return taskLinks; } @@ -179,24 +187,24 @@ class DynamicCommandHandler extends CommandHandler { if (typeof conditions === 'boolean') { linkFunc = () => { return true; - } + }; } else if (typeof conditions === 'string') { linkFunc = (taskFlowContext: TaskFlowContext) => { const variableParserService = this.getVariableParseService(taskFlowContext); const variableParseContext = this.getVariableParseContext(taskFlowContext); return variableParserService.evaluate(conditions, variableParseContext); - } + }; } else if (Array.isArray(conditions)) { linkFunc = (taskFlowContext: TaskFlowContext) => { const variableParseContext = this.getVariableParseContext(taskFlowContext); const conditionEvaluator = new ConditionEvaluator(variableParseContext); return conditionEvaluator.evaluate(conditions); - } + }; } else { linkFunc = () => { return false; - } + }; } return linkFunc; -- Gitee From d8e4f51661b8ee1c8ff056a42483bbd2ea715e48 Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Fri, 12 Sep 2025 11:55:07 +0800 Subject: [PATCH 15/24] =?UTF-8?q?chore:=20=E4=BF=AE=E6=94=B9context?= =?UTF-8?q?=E4=B8=8A=E4=B8=8B=E6=96=87=E5=B1=9E=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/controller.service.ts | 68 ++-------- .../lib/data-services/tree-data.service.ts | 118 +++++++++--------- packages/command-services/lib/types.ts | 93 ++++++++++---- 3 files changed, 142 insertions(+), 137 deletions(-) diff --git a/packages/command-services/lib/controller.service.ts b/packages/command-services/lib/controller.service.ts index 248c68aba..9b01b3f53 100644 --- a/packages/command-services/lib/controller.service.ts +++ b/packages/command-services/lib/controller.service.ts @@ -8,7 +8,7 @@ import { FormNotifyService } from './form-notify.service'; import { CommandService } from './command.service'; import { CardDataService, ListDataService } from './data-services'; import { ContextService } from './devkit-services/index'; -import { ApiClientContext, ControllerContext, I18nContext, UIContext } from './types'; +import { ApiClientContext, ControllerContext, I18nContext, UtilContext } from './types'; import { TranslateService } from './locale'; import { DialogService } from './dialog.service'; @@ -70,11 +70,11 @@ export class ControllerService { private buildContext(): ControllerContext { return { apiClient: this.buildApiClientContext(), - ui: this.buildUIContext(), + util: this.buildUtilContext(), i18n: this.buildI18nContext() }; } - private buildUIContext(): UIContext { + private buildUtilContext(): UtilContext { return { showLoading: this.formLoadingService.show.bind(this.formLoadingService), hideLoading: this.formLoadingService.hide.bind(this.formLoadingService), @@ -82,19 +82,19 @@ export class ControllerService { hideDelayLoading: this.formLoadingService.hideDelayLoading.bind(this.formLoadingService), showNotify: (content, type) => { switch (type) { - case 'info': this.formNotifyService.info(content); - case 'success': this.formNotifyService.success(content); - case 'warning': this.formNotifyService.warning(content); - case 'error': this.formNotifyService.error(content); + case 'info': this.formNotifyService.info(content); break; + case 'success': this.formNotifyService.success(content); break; + case 'warning': this.formNotifyService.warning(content); break; + case 'error': this.formNotifyService.error(content); break; default: this.formNotifyService.info(content); } }, showMessage: (content, type) => { switch (type) { - case 'info': this.formMessageService.info(content); - case 'success': this.formMessageService.success(content); - case 'warning': this.formMessageService.warning(content); - case 'error': this.formMessageService.error(content); + case 'info': this.formMessageService.info(content); break; + case 'success': this.formMessageService.success(content); break; + case 'warning': this.formMessageService.warning(content); break; + case 'error': this.formMessageService.error(content); break; default: this.formMessageService.info(content); } }, @@ -104,70 +104,24 @@ export class ControllerService { } private buildApiClientContext(): ApiClientContext { return { - /** - * 使用GET方法调用后端接口 - * @param url api地址 - * @param requestConfig requestConfig - * @returns - * @description 该接口仅用于调用表单后端接口,会自动组装requestInfo,如调用非表单接口(框架接口、外部接口)请使用HttpClient,否则可能会导致变更丢失问题。 - */ get: (url: string, requestConfig?) => { return this.apiProxy.request(HttpMethods.GET, url, requestConfig); }, - /** - * 使用POST方法调用后端接口 - * @param url api地址 - * @param body 除requestInfo外的自定义参数 - * @param requestConfig - * @returns - * @description 该接口仅用于调用表单后端接口,会自动组装requestInfo,如调用非表单接口(框架接口、外部接口)请使用HttpClient,否则可能会导致变更丢失问题。 - */ post: (url: string, body?: any, requestConfig?: HttpRequestConfig,) => { requestConfig = this.extendRequestConfig(requestConfig, body); return this.apiProxy.request(HttpMethods.POST, url, requestConfig); }, - /** - * 使用PATCH方法调用后端接口 - * @param url api地址 - * @param body 除requestInfo外的自定义参数 - * @param requestConfig requestConfig - * @returns - * @description 该接口仅用于调用表单后端接口,会自动组装requestInfo,如调用非表单接口(框架接口、外部接口)请使用HttpClient,否则可能会导致变更丢失问题。 - */ patch: (url: string, body?: any, requestConfig?: HttpRequestConfig) => { requestConfig = this.extendRequestConfig(requestConfig, body); return this.apiProxy.request(HttpMethods.PATCH, url, requestConfig); }, - /** - * 使用PUT方法调用后端接口 - * @param url api地址 - * @param body 除requestInfo外的自定义参数 - * @param requestConfig requestConfig - * @returns - * @description 该接口仅用于调用表单后端接口,会自动组装requestInfo,如调用非表单接口(框架接口、外部接口)请使用HttpClient,否则可能会导致变更丢失问题。 - */ put: (url: string, body?: any, requestConfig?: HttpRequestConfig) => { requestConfig = this.extendRequestConfig(requestConfig, body); return this.apiProxy.request(HttpMethods.PUT, url, requestConfig); }, - /** - * 使用DELETE方法调用后端接口 - * @param url api地址 - * @param requestConfig requestConfig - * @returns - * @description 该接口仅用于调用表单后端接口,会自动组装requestInfo,如调用非表单接口(框架接口、外部接口)请使用HttpClient,否则可能会导致变更丢失问题。 - */ delete: (url: string, requestConfig?: HttpRequestConfig) => { return this.apiProxy.request(HttpMethods.DELETE, url, requestConfig); }, - /** - * 调用后端接口 - * @param url api地址 - * @param method HttpMethod - * @param requestConfig requestConfig - * @returns - * @description 该接口仅用于调用表单后端接口,会自动组装requestInfo,如调用非表单接口(框架接口、外部接口)请使用HttpClient,否则可能会导致变更丢失问题。 - */ request: (url: string, method: HttpMethod, requestConfig?: HttpRequestConfig) => { requestConfig = this.extendRequestConfig(requestConfig); return this.apiProxy.request(method, url, requestConfig); diff --git a/packages/command-services/lib/data-services/tree-data.service.ts b/packages/command-services/lib/data-services/tree-data.service.ts index c6e605d37..b7f5faa20 100644 --- a/packages/command-services/lib/data-services/tree-data.service.ts +++ b/packages/command-services/lib/data-services/tree-data.service.ts @@ -49,66 +49,66 @@ export class TreeDataService extends BaseDataService { if (typeof frozenCurrentRow !== 'boolean') { frozenCurrentRow = frozenCurrentRow === 'true' ? true : false; } - const virtualRootFrameContext = this.virtualRootFrameContext; - // 还原上次设置的结果集 - virtualRootFrameContext.params.delete('_DEVKIT_expandRowIds'); - virtualRootFrameContext.params.delete('_DEVKIT_selectedRowId'); - virtualRootFrameContext.uiState.setPropertyValue('__DEVKIT__selectedRow', null); - const filtersArray = this.parseConditions(filters); - const parentId = this.getIdToExpand(); - const correctSelectedNode = this.repository.entityCollection.count() === 0; - const hierarchyType = this.getHierarchyType(); - const repository = TreeRepositoryFactory.getInstance(hierarchyType); + // const virtualRootFrameContext = this.virtualRootFrameContext; + // // 还原上次设置的结果集 + // virtualRootFrameContext.params.delete('_DEVKIT_expandRowIds'); + // virtualRootFrameContext.params.delete('_DEVKIT_selectedRowId'); + // virtualRootFrameContext.uiState.setPropertyValue('__DEVKIT__selectedRow', null); + // const filtersArray = this.parseConditions(filters); + // const parentId = this.getIdToExpand(); + // const correctSelectedNode = this.repository.entityCollection.count() === 0; + // const hierarchyType = this.getHierarchyType(); + // const repository = TreeRepositoryFactory.getInstance(hierarchyType); - if (repository === null) { - return EMPTY; - } - const loadingTimerId = this.loadingService.showLoadingWithDelay(500); - const context = { - frameContext: this.frameContext, - frozenCurrentRow - }; - // tslint:disable-next-line: max-line-length - const query$ = repository.loadFullTree(this.repository, this.hierarchyInfoKey, parentId, virtualPropertyName, fullTreeType, loadType, filtersArray, context); - return query$.pipe( - tap( - (entities: Entity[]) => { - const selectedRowId = virtualRootFrameContext.params.get('_DEVKIT_selectedRowId'); - // 纠正选中节点 - if (correctSelectedNode === true) { - const treeNodeUtil = TreeUtilFactory.getInstance(hierarchyType); - if (treeNodeUtil !== null) { - const computedFirstRowId = selectedRowId || treeNodeUtil.selectFirstRootNode(this.bindingData, this.hierarchyInfoKey); - if (computedFirstRowId) { - virtualRootFrameContext.uiState.setPropertyValue('__DEVKIT__selectedRow', computedFirstRowId); - } - } - } - if (frozenCurrentRow && parentId) { - const currentRowId = this.bindingData.list.currentItem.primaryKeyValue; - // 冻结当前行启用时则不再关心后端返回的选中行 - virtualRootFrameContext.uiState.setPropertyValue('__DEVKIT__selectedRow', null); - // 如果上一次选中行为本次加载数据中的一条,则应该重新选中该行 - const containsCurrentRow = entities.find((item) => item.primaryValue === currentRowId); - if (containsCurrentRow) { - this.setCurrentId(currentRowId); - } - // 原来的当前行不在已经加载的数据中,如展开到第三级,将第三级的某行设为当前行,全部收起,展开第一级 - if (!this.repository.entityCollection.getEntityById(currentRowId) && entities && entities.length > 0) { - const firstChildId = entities && Array.isArray(entities) && entities.length > 0 && entities[0].primaryValue || null; - if (firstChildId) { - this.setCurrentId(firstChildId); - } - } - } - this.loadingService.hideDelayLoading(loadingTimerId); - }, - (error) => { - this.loadingService.hideDelayLoading(loadingTimerId); - this.errorService.exception(this.languageService.loadFailed, error); - } - ) - ); + // if (repository === null) { + // return EMPTY; + // } + // const loadingTimerId = this.loadingService.showLoadingWithDelay(500); + // const context = { + // frameContext: this.frameContext, + // frozenCurrentRow + // }; + // // tslint:disable-next-line: max-line-length + // const query$ = repository.loadFullTree(this.repository, this.hierarchyInfoKey, parentId, virtualPropertyName, fullTreeType, loadType, filtersArray, context); + // return query$.pipe( + // tap( + // (entities: Entity[]) => { + // const selectedRowId = virtualRootFrameContext.params.get('_DEVKIT_selectedRowId'); + // // 纠正选中节点 + // if (correctSelectedNode === true) { + // const treeNodeUtil = TreeUtilFactory.getInstance(hierarchyType); + // if (treeNodeUtil !== null) { + // const computedFirstRowId = selectedRowId || treeNodeUtil.selectFirstRootNode(this.bindingData, this.hierarchyInfoKey); + // if (computedFirstRowId) { + // virtualRootFrameContext.uiState.setPropertyValue('__DEVKIT__selectedRow', computedFirstRowId); + // } + // } + // } + // if (frozenCurrentRow && parentId) { + // const currentRowId = this.bindingData.list.currentItem.primaryKeyValue; + // // 冻结当前行启用时则不再关心后端返回的选中行 + // virtualRootFrameContext.uiState.setPropertyValue('__DEVKIT__selectedRow', null); + // // 如果上一次选中行为本次加载数据中的一条,则应该重新选中该行 + // const containsCurrentRow = entities.find((item) => item.primaryValue === currentRowId); + // if (containsCurrentRow) { + // this.setCurrentId(currentRowId); + // } + // // 原来的当前行不在已经加载的数据中,如展开到第三级,将第三级的某行设为当前行,全部收起,展开第一级 + // if (!this.repository.entityCollection.getEntityById(currentRowId) && entities && entities.length > 0) { + // const firstChildId = entities && Array.isArray(entities) && entities.length > 0 && entities[0].primaryValue || null; + // if (firstChildId) { + // this.setCurrentId(firstChildId); + // } + // } + // } + // this.loadingService.hideDelayLoading(loadingTimerId); + // }, + // (error) => { + // this.loadingService.hideDelayLoading(loadingTimerId); + // this.errorService.exception(this.languageService.loadFailed, error); + // } + // ) + // ); } public addSibling(id: string) { id = id ? id : this.viewModel.entityStore?.getCurrentEntity().idValue; diff --git a/packages/command-services/lib/types.ts b/packages/command-services/lib/types.ts index 009da8d28..2d36cc16f 100644 --- a/packages/command-services/lib/types.ts +++ b/packages/command-services/lib/types.ts @@ -134,43 +134,55 @@ export interface BuildFrameworkTabIdOptions { export interface ApiClientContext { /** - * 发送get请求 - * @param url 请求地址 + * 使用GET方法调用后端接口 + * @param url api地址 * @param requestConfig requestConfig + * @returns + * @description 该接口仅用于调用表单后端接口,会自动组装requestInfo,如调用非表单接口(框架接口、外部接口)请使用HttpClient,否则可能会导致变更丢失问题。 */ get(url: string, requestConfig?: HttpRequestConfig): Promise; /** - * 发送POST请求 - * @param url 请求地址 - * @param body 请求体 - * @param requestConfig requestConfig + * 使用POST方法调用后端接口 + * @param url api地址 + * @param body 除requestInfo外的自定义参数 + * @param requestConfig + * @returns + * @description 该接口仅用于调用表单后端接口,会自动组装requestInfo,如调用非表单接口(框架接口、外部接口)请使用HttpClient,否则可能会导致变更丢失问题。 */ post(url: string, body: any, requestConfig?: HttpRequestConfig): Promise; /** - * 发送PUT请求 - * @param url 请求地址 - * @param body 请求体 - * @param requestConfig + * 使用PUT方法调用后端接口 + * @param url api地址 + * @param body 除requestInfo外的自定义参数 + * @param requestConfig requestConfig + * @returns + * @description 该接口仅用于调用表单后端接口,会自动组装requestInfo,如调用非表单接口(框架接口、外部接口)请使用HttpClient,否则可能会导致变更丢失问题。 */ put(url: string, body: any, requestConfig?: HttpRequestConfig): Promise; /** - * 发送PATCH请求 - * @param url 请求地址 - * @param body 请求体 + * 使用PATCH方法调用后端接口 + * @param url api地址 + * @param body 除requestInfo外的自定义参数 * @param requestConfig requestConfig + * @returns + * @description 该接口仅用于调用表单后端接口,会自动组装requestInfo,如调用非表单接口(框架接口、外部接口)请使用HttpClient,否则可能会导致变更丢失问题。 */ patch(url: string, body: any, requestConfig?: HttpRequestConfig): Promise; /** - * 发送DELETE请求 - * @param url 请求地址 + * 使用DELETE方法调用后端接口 + * @param url api地址 * @param requestConfig requestConfig + * @returns + * @description 该接口仅用于调用表单后端接口,会自动组装requestInfo,如调用非表单接口(框架接口、外部接口)请使用HttpClient,否则可能会导致变更丢失问题。 */ delete(url: string, requestConfig?: HttpRequestConfig): Promise; /** - * 发送请求 - * @param url 请求地址 - * @param method 请求方法 + * 调用后端接口 + * @param url api地址 + * @param method HttpMethod * @param requestConfig requestConfig + * @returns + * @description 该接口仅用于调用表单后端接口,会自动组装requestInfo,如调用非表单接口(框架接口、外部接口)请使用HttpClient,否则可能会导致变更丢失问题。 */ request(url: string, method: HttpMethod, requestConfig?: HttpRequestConfig): Promise; } @@ -186,14 +198,53 @@ export interface I18nContext { */ readonly locale: string; } -export interface UIContext { +export interface UtilContext { + /** + * 展示加载提示 + * @param configOrMessage 提示消息或Loading配置 + * @returns loading标识 + */ showLoading(configOrMessage?: any): number | undefined; + /** + * 隐藏加载提示 + * @param loadingId loading标识 + */ hideLoading(loadingId: number): void; + /** + * 延迟显示加载提示 + * @param delayTime 延迟的时间,单位毫秒 + * @param configOrMessage 提示消息或Loading配置 + */ showLoadingWithDelay(delayTime: number, configOrMessage?: any): number; + /** + * 隐藏延迟加载的提示 + * @param timerId loading标识 + */ hideDelayLoading(timerId: number): void; + /** + * 显示提示信息 + * @param content 提示文本 + * @param type 提示类型 + */ showNotify(content: string, type: 'info' | 'success' | 'warning' | 'error'): void; + /** + * 弹出消息提示 + * @param content 提示文本 + * @param type 提示类型 + */ showMessage(content: string, type: 'info' | 'success' | 'warning' | 'error'): void; - openModal(config: string | ModalConfig, modalId: string, params: string | Record, callback?: (modalRef: any) => any): void; + /** + * 打开弹窗 + * @param config 弹窗配置 + * @param modalId 弹窗标识 + * @param params 参数 + */ + openModal(config: string | ModalConfig, modalId: string, params: string | Record): void; + /** + * 打开隐藏帮助 + * @param config 帮助配置 + * @param lookupId 帮助标识 + */ openLookup(config: string | LookupConfig, lookupId: string): void; } export interface ControllerContext { @@ -208,5 +259,5 @@ export interface ControllerContext { /** * 界面上下文 */ - ui: UIContext; + util: UtilContext; } -- Gitee From b46cf8b3d1a7a7465ba62267e553ae48a08e75fc Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Fri, 12 Sep 2025 15:46:37 +0800 Subject: [PATCH 16/24] =?UTF-8?q?chore:=20=E5=AE=8C=E5=96=84context?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/controller.service.ts | 79 ++++++++++- packages/command-services/lib/types.ts | 124 +++++++++++++++++- 2 files changed, 196 insertions(+), 7 deletions(-) diff --git a/packages/command-services/lib/controller.service.ts b/packages/command-services/lib/controller.service.ts index 9b01b3f53..1819ce40e 100644 --- a/packages/command-services/lib/controller.service.ts +++ b/packages/command-services/lib/controller.service.ts @@ -1,4 +1,4 @@ -import { Entity, HttpMethod, HttpMethods, HttpRequestConfig, Injector, ViewModel, ViewModelState } from '@farris/devkit-vue'; +import { Entity, EntityPath, HttpMethod, HttpMethods, HttpRequestConfig, Injector, ViewModel, ViewModelState } from '@farris/devkit-vue'; import { BefProxy, BefRepository, RequestInfoUtil } from '@farris/bef-vue'; import { RenderEngineService } from './render-engine.service'; import { TemplateService } from './template.service'; @@ -8,9 +8,10 @@ import { FormNotifyService } from './form-notify.service'; import { CommandService } from './command.service'; import { CardDataService, ListDataService } from './data-services'; import { ContextService } from './devkit-services/index'; -import { ApiClientContext, ControllerContext, I18nContext, UtilContext } from './types'; +import { ApiClientContext, ComponentContext, ControllerContext, EntityStoreContext, I18nContext, MethodContext, ServiceContext, UtilContext } from './types'; import { TranslateService } from './locale'; import { DialogService } from './dialog.service'; +import { StateMachineService } from './state-machine.service'; export class ControllerService { protected injector: Injector; @@ -27,6 +28,7 @@ export class ControllerService { protected apiProxy: BefProxy; protected translateService: TranslateService; protected dialogService: DialogService; + protected stateMachineService: StateMachineService; public context: ControllerContext; @@ -45,6 +47,7 @@ export class ControllerService { this.apiProxy = this.repository?.apiProxy; this.translateService = this.injector.get(TranslateService); this.dialogService = this.injector.get(DialogService); + this.stateMachineService = this.injector.get(StateMachineService); this.context = this.buildContext(); } @@ -71,7 +74,14 @@ export class ControllerService { return { apiClient: this.buildApiClientContext(), util: this.buildUtilContext(), - i18n: this.buildI18nContext() + i18n: this.buildI18nContext(), + entityStore: this.buildEntityStoreContext(), + uiStore: this.viewModel.uiStore, + component: this.buildComponentContext(), + eventParams: this.getEventParams.bind(this), + service: this.buildServiceContext(), + method: this.buildMethodContext(), + repository: this.repository }; } private buildUtilContext(): UtilContext { @@ -102,6 +112,10 @@ export class ControllerService { openLookup: this.dialogService.openLookup.bind(this.dialogService) }; } + /** + * 构造接口客户端上下文 + * @returns + */ private buildApiClientContext(): ApiClientContext { return { get: (url: string, requestConfig?) => { @@ -141,10 +155,69 @@ export class ControllerService { } return requestConfig; } + /** + * 构造国际化上下文 + * @returns + */ private buildI18nContext(): I18nContext { return { locale: this.viewModel.getModule().getLocale(), translate: this.translateService.transform.bind(this.translateService) }; } + /** + * 构造组件上下文 + * @returns + */ + private buildComponentContext(): ComponentContext { + return { + get: this.renderEngineService.getComponentById.bind(this.renderEngineService), + getProps: this.renderEngineService.getProps.bind(this.renderEngineService), + setProps: this.renderEngineService.setProps.bind(this.renderEngineService), + getValue: this.renderEngineService.getControlValue.bind(this.renderEngineService) + }; + } + /** + * 构造服务上下文 + * @returns + */ + private buildServiceContext(): ServiceContext { + return { + get: this.getService.bind(this), + stateMachineService: this.stateMachineService + }; + } + /** + * 构造方法上下文 + * @returns + */ + private buildMethodContext(): MethodContext { + return { + execute: this.commandService.execute.bind(this.commandService) + }; + } + /** + * 构造实体仓库上下文 + * @returns + */ + private buildEntityStoreContext(): EntityStoreContext { + return { + getValue: (path: string | EntityPath) => { + return this.viewModel.entityStore?.getValueByPath(path); + }, + setValue: (path, value) => { + this.viewModel.entityStore?.setValueByPath(path, value); + }, + currentEntity: this.viewModel.entityStore?.getCurrentEntity(), + currentId: this.viewModel.entityStore?.getCurrentEntity().idValue, + entities: this.viewModel.entityStore?.getEntities(), + entityList: this.viewModel.entityStore?.getEntityList(), + getEntityById: (id: string) => { + return this.viewModel.entityStore?.getEntityById(id); + }, + updateEntityById: (id, data) => { + this.viewModel.entityStore?.updateEntityById(id, data); + }, + }; + } } \ No newline at end of file diff --git a/packages/command-services/lib/types.ts b/packages/command-services/lib/types.ts index 2d36cc16f..fa228ceac 100644 --- a/packages/command-services/lib/types.ts +++ b/packages/command-services/lib/types.ts @@ -1,6 +1,7 @@ -import { RequestInfo } from '@farris/bef-vue'; -import { HttpMethod, HttpRequestConfig } from '@farris/devkit-vue'; +import { BefRepository, RequestInfo } from '@farris/bef-vue'; +import { Entity, EntityList, EntityPath, EntityState, EntityStore, HttpMethod, HttpRequestConfig, UIState, UIStore } from '@farris/devkit-vue'; import { LookupConfig, ModalConfig } from './dialog.service'; +import { StateMachineService } from './state-machine.service'; export const AppType = { App: 'app', @@ -247,17 +248,132 @@ export interface UtilContext { */ openLookup(config: string | LookupConfig, lookupId: string): void; } +export interface ComponentContext { + /** + * 获取组件实例 + * @param id 组件标识 + */ + get(id: string): any; + /** + * 更新组件属性 + * @param id 组件标识 + * @param props 组件属性 + */ + setProps(id: string, props: Record): void; + /** + * 获取组件属性 + * @param id 组件标识 + */ + getProps(id: string): Record; + /** + * 获取组件对应的值 + * @param id 组件标识 + */ + getValue(id: string): any; +} +export interface MethodContext { + /** + * 执行目标组件的指定方法 + * @param commandName + * @param componentId + */ + execute(methodName: string, componentId: string): Promise; +} + +export interface ServiceContext { + /** + * 获取服务实例 + * @param token + * @param defaultValue + */ + get(token: any, defaultValue?: any): T; + /** + * 状态机服务 + */ + stateMachineService: StateMachineService; +} +export interface EntityStoreContext { + /** + * 根据路径获取字段值 + * @param path 字段路径 + * @description 字段路径已/开头,如/id + */ + getValue(path: string | EntityPath): any; + /** + * 给实体字段赋值 + * @param path 字段路径 + * @param value 字段值 + * @description 字段路径已/开头,如/id + */ + setValue(path: string | EntityPath, value: any): void; + /** + * 获取指定主键的实体 + * @param id 主键 + */ + getEntityById(id: string): Entity | undefined; + /** + * 更新指定实体数据 + * @param id + * @param data + */ + updateEntityById(id: string, data: any): void; + /** + * 当前行主键 + */ + readonly currentId: string | undefined; + /** + * 当前行对应的实体 + */ + readonly currentEntity: Entity | undefined; + /** + * 所有实体 + */ + readonly entities: Entity[] | undefined; + /** + * 实体列表对象 + */ + readonly entityList: EntityList | undefined; + +} export interface ControllerContext { /** * api客户端 */ apiClient: ApiClientContext; /** - * 多语 + * 多语上下文 */ i18n: I18nContext; /** - * 界面上下文 + * 工具上下文 */ util: UtilContext; + /** + * 实体上下文 + */ + entityStore: EntityStoreContext | null; + /** + * 界面状态仓库上下文 + */ + uiStore: UIStore | null; + /** + * 表单组件上下文 + */ + component: ComponentContext; + /** + * 服务上下文 + */ + service: ServiceContext; + /** + * 事件上下文 + */ + eventParams?: any; + /** + * 方法上下文 + */ + method: MethodContext; + /** + * 实体仓库上下文 + */ + repository: BefRepository; } -- Gitee From 80aa15a98ddf063b4d4c86b5b8c8b8a2d66ec53f Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Fri, 12 Sep 2025 16:07:10 +0800 Subject: [PATCH 17/24] =?UTF-8?q?chore:=20=E5=A2=9E=E5=8A=A0dataService?= =?UTF-8?q?=E4=B8=8A=E4=B8=8B=E6=96=87=EF=BC=8C=E6=96=B9=E4=BE=BF=E5=BC=80?= =?UTF-8?q?=E5=8F=91=E8=80=85=E6=9B=B4=E6=96=B0=E5=AE=9E=E4=BD=93=E6=95=B0?= =?UTF-8?q?=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/controller.service.ts | 22 +++++++++++++++++-- packages/command-services/lib/types.ts | 14 ++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/packages/command-services/lib/controller.service.ts b/packages/command-services/lib/controller.service.ts index 1819ce40e..dae40d3e1 100644 --- a/packages/command-services/lib/controller.service.ts +++ b/packages/command-services/lib/controller.service.ts @@ -8,7 +8,7 @@ import { FormNotifyService } from './form-notify.service'; import { CommandService } from './command.service'; import { CardDataService, ListDataService } from './data-services'; import { ContextService } from './devkit-services/index'; -import { ApiClientContext, ComponentContext, ControllerContext, EntityStoreContext, I18nContext, MethodContext, ServiceContext, UtilContext } from './types'; +import { ApiClientContext, ComponentContext, ControllerContext, DataServiceContext, EntityStoreContext, I18nContext, MethodContext, ServiceContext, UtilContext } from './types'; import { TranslateService } from './locale'; import { DialogService } from './dialog.service'; import { StateMachineService } from './state-machine.service'; @@ -81,7 +81,8 @@ export class ControllerService { eventParams: this.getEventParams.bind(this), service: this.buildServiceContext(), method: this.buildMethodContext(), - repository: this.repository + repository: this.repository, + dataService: this.buildDataServiceContext(), }; } private buildUtilContext(): UtilContext { @@ -220,4 +221,21 @@ export class ControllerService { }, }; } + private buildDataServiceContext(): DataServiceContext { + return { + update: (id?: string) => { + id = id || this.viewModel.entityStore?.getCurrentEntity().idValue; + if (!id) { + return Promise.reject(); + } + const timerId = this.formLoadingService.showLoadingWithDelay(); + return this.repository.getEntityById(id).then((newEntity: Entity) => { + const newEntityData = newEntity.data; + this.viewModel.entityStore?.updateEntityById(id, newEntityData); + }).finally(() => { + this.formLoadingService.hideDelayLoading(timerId); + }); + } + }; + } } \ No newline at end of file diff --git a/packages/command-services/lib/types.ts b/packages/command-services/lib/types.ts index fa228ceac..f41695300 100644 --- a/packages/command-services/lib/types.ts +++ b/packages/command-services/lib/types.ts @@ -335,6 +335,15 @@ export interface EntityStoreContext { readonly entityList: EntityList | undefined; } + +export interface DataServiceContext { + /** + * 从后端获取实体数据并更新前端实体仓库中对应的实体 + * @param id 可选,默认为当前行数据的主键 + * @description 适用于卡片、列卡等字典场景,类似`CardDataService`中的`update`方法 + */ + update(id?: string): Promise; +} export interface ControllerContext { /** * api客户端 @@ -374,6 +383,11 @@ export interface ControllerContext { method: MethodContext; /** * 实体仓库上下文 + * @description 仓库,负责与后端接口进行交互,不会主动更新本地仓库数据,如需自动更新请使用`dataService` */ repository: BefRepository; + /** + * 数据服务 + */ + dataService: DataServiceContext; } -- Gitee From a942b568885f4724a581175c945c02a62bf02c0c Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Fri, 12 Sep 2025 16:29:04 +0800 Subject: [PATCH 18/24] =?UTF-8?q?chore:=20=E5=AE=8C=E5=96=84=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=9C=8D=E5=8A=A1=EF=BC=8C=E6=96=B0=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=E5=88=97=E8=A1=A8=E6=95=B0=E6=8D=AE=E3=80=81=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E6=95=B0=E6=8D=AE=E3=80=81=E4=BF=9D=E5=AD=98=E3=80=81?= =?UTF-8?q?=E5=8F=96=E6=B6=88=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/controller.service.ts | 28 ++++++++++------ packages/command-services/lib/types.ts | 32 +++++++++++++++++++ 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/packages/command-services/lib/controller.service.ts b/packages/command-services/lib/controller.service.ts index dae40d3e1..866f2a64d 100644 --- a/packages/command-services/lib/controller.service.ts +++ b/packages/command-services/lib/controller.service.ts @@ -6,7 +6,7 @@ import { FormLoadingService } from './form-loading.service'; import { FormMessageService } from './form-message.service'; import { FormNotifyService } from './form-notify.service'; import { CommandService } from './command.service'; -import { CardDataService, ListDataService } from './data-services'; +import { CancelDataService, CardDataService, ListDataService, LoadDataService, RemoveDataService, SaveDataService, UpdateDataService } from './data-services'; import { ContextService } from './devkit-services/index'; import { ApiClientContext, ComponentContext, ControllerContext, DataServiceContext, EntityStoreContext, I18nContext, MethodContext, ServiceContext, UtilContext } from './types'; import { TranslateService } from './locale'; @@ -29,6 +29,11 @@ export class ControllerService { protected translateService: TranslateService; protected dialogService: DialogService; protected stateMachineService: StateMachineService; + protected updateDataService: UpdateDataService; + protected loadDataService: LoadDataService; + protected removeDataService: RemoveDataService; + protected saveDataService: SaveDataService; + protected cancelDataService: CancelDataService; public context: ControllerContext; @@ -48,6 +53,12 @@ export class ControllerService { this.translateService = this.injector.get(TranslateService); this.dialogService = this.injector.get(DialogService); this.stateMachineService = this.injector.get(StateMachineService); + this.updateDataService = this.injector.get(UpdateDataService); + this.loadDataService = this.injector.get(LoadDataService); + this.removeDataService = this.injector.get(RemoveDataService); + this.saveDataService = this.injector.get(SaveDataService); + this.cancelDataService = this.injector.get(CancelDataService); + this.context = this.buildContext(); } @@ -228,14 +239,13 @@ export class ControllerService { if (!id) { return Promise.reject(); } - const timerId = this.formLoadingService.showLoadingWithDelay(); - return this.repository.getEntityById(id).then((newEntity: Entity) => { - const newEntityData = newEntity.data; - this.viewModel.entityStore?.updateEntityById(id, newEntityData); - }).finally(() => { - this.formLoadingService.hideDelayLoading(timerId); - }); - } + return this.updateDataService.update(id); + }, + load: this.loadDataService.load.bind(this.loadDataService), + remove: this.removeDataService.remove.bind(this.removeDataService), + removeRows: this.removeDataService.removeRows.bind(this.removeDataService), + save: this.saveDataService.save.bind(this.saveDataService), + cancel: this.cancelDataService.cancel.bind(this.cancelDataService) }; } } \ No newline at end of file diff --git a/packages/command-services/lib/types.ts b/packages/command-services/lib/types.ts index f41695300..e53779fbd 100644 --- a/packages/command-services/lib/types.ts +++ b/packages/command-services/lib/types.ts @@ -343,6 +343,37 @@ export interface DataServiceContext { * @description 适用于卡片、列卡等字典场景,类似`CardDataService`中的`update`方法 */ update(id?: string): Promise; + /** + * 加载数据 + * @param filters 可选,过滤条件 + * @param sorts 可选,排序条件 + * @param pageSize 可选,分页大小 + * @param pageIndex 可选,页码 + */ + load(filters?: string | string[], sorts?: string | string[], pageSize?: number | null, pageIndex?: number | null): Promise; + /** + * 删除数据 + * @param id 可选,要删除的数据主键,默认为当前行数据的主键 + * @param ifSave 可选,删除后是否应用变更,默认保存 + * @param successMessage 删除成功后的提示信息 + */ + remove(id?: string, ifSave?: boolean | string, successMessage?: string): Promise | undefined; + /** + * 批量删除数据 + * @param ids 主键数组 + * @param ifSave 可选,是否保存,默认删除后保存 + * @param successMessage 可选,删除成功后的提示信息 + */ + removeRows(ids: string[] | string, ifSave?: boolean | string, successMessage?: string): Promise; + /** + * 保存 + */ + save(): Promise; + /** + * 取消变更 + * @param showConfirm 可选,当存在未保存的变更时是否进行提示,默认提示 + */ + cancel(showConfirm?: boolean): Promise; } export interface ControllerContext { /** @@ -388,6 +419,7 @@ export interface ControllerContext { repository: BefRepository; /** * 数据服务 + * @description 数据服务是对repository和entityStore的封装,即调用后端接口并更新本地数据仓库 */ dataService: DataServiceContext; } -- Gitee From a405cc3698df8fe113f5c76741dc7748d20e3221 Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Mon, 15 Sep 2025 14:20:15 +0800 Subject: [PATCH 19/24] =?UTF-8?q?fix:=20=E5=AE=8C=E6=95=B4=E6=A0=91?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E6=96=B9=E6=B3=95=E5=8F=82=E6=95=B0=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E6=8F=90=E7=A4=BA=E4=BF=A1=E6=81=AF=E6=9C=AA=E5=A4=9A?= =?UTF-8?q?=E8=AF=AD=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/data-services/tree-data.service.ts | 4 ++-- .../lib/locale/locales/en.json | 4 +++- .../lib/locale/locales/zh-CHS.json | 4 +++- .../lib/locale/locales/zh-CHT.json | 18 ++++++++++-------- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/packages/command-services/lib/data-services/tree-data.service.ts b/packages/command-services/lib/data-services/tree-data.service.ts index b7f5faa20..f1b69f328 100644 --- a/packages/command-services/lib/data-services/tree-data.service.ts +++ b/packages/command-services/lib/data-services/tree-data.service.ts @@ -38,10 +38,10 @@ export class TreeDataService extends BaseDataService { public loadByLevel(filters?: string, sorts?: string, frozenCurrentRow?: boolean | string) { } public loadFullTree(virtualPropertyName: string, fullTreeType: string, loadType: string, filters: string, frozenCurrentRow?: boolean | string) { if (typeof fullTreeType !== 'string') { - throw new Error('ArgumentError: fullTreeType 不能为空且必须为字符串。'); + throw new Error(LocaleService.translate('fullTreeType')); } if (typeof loadType !== 'string') { - throw new Error('ArgumentError: loadType 不能为空且必须为字符串。'); + throw new Error(LocaleService.translate('fullTreeLoadType')); } if (frozenCurrentRow === undefined) { frozenCurrentRow = false; diff --git a/packages/command-services/lib/locale/locales/en.json b/packages/command-services/lib/locale/locales/en.json index 51a2bb2f2..3cde8d7dc 100644 --- a/packages/command-services/lib/locale/locales/en.json +++ b/packages/command-services/lib/locale/locales/en.json @@ -40,5 +40,7 @@ "noParentData": "Please select the parent data.", "appOrFuncIdRequired": "No menu or application parameters are configured, please configure them in the designer.", "validate": "'$property' calibration failed", - "dataPicking": "Failed to verify the expression before help" + "dataPicking": "Failed to verify the expression before help", + "fullTreeType": "The fullTreeType parameter cannot be empty and must be a string.", + "fullTreeLoadType":"The complete tree loading method parameter (loadType) cannot be empty and must be a string." } \ No newline at end of file diff --git a/packages/command-services/lib/locale/locales/zh-CHS.json b/packages/command-services/lib/locale/locales/zh-CHS.json index 5476841d7..1b302e535 100644 --- a/packages/command-services/lib/locale/locales/zh-CHS.json +++ b/packages/command-services/lib/locale/locales/zh-CHS.json @@ -40,5 +40,7 @@ "noParentData":"请选择上级数据!", "appOrFuncIdRequired":"未配置菜单或应用参数,请在设计器中配置。", "validate": "'$property'校验不通过", - "dataPicking": "帮助前表达式校验不通过" + "dataPicking": "帮助前表达式校验不通过", + "fullTreeType": "完整树类型参数(fullTreeType)不能为空且必须为字符串。", + "fullTreeLoadType":"完整树加载方式参数(loadType)不能为空且必须为字符串。" } \ No newline at end of file diff --git a/packages/command-services/lib/locale/locales/zh-CHT.json b/packages/command-services/lib/locale/locales/zh-CHT.json index 8f049c184..1b1e45fce 100644 --- a/packages/command-services/lib/locale/locales/zh-CHT.json +++ b/packages/command-services/lib/locale/locales/zh-CHT.json @@ -32,13 +32,15 @@ "errorTypeVertifyMessages": "錯填", "emptyTypeVertifyMessages": "漏填", "verifyMessageWithRowIndex": "第 $constraint1 行", - "pleaseSelectUpdateRow":"請選擇更新附件的行!", - "pleaseUploadFirst":"請先上傳附件!", - "pleaseSelectDownloadAttachment":"請選擇要下載的附件!", - "noDownloadAttachment":"找不到要下載的附件!", - "noAttachment":"沒有可以預覽的附件。", - "noParentData":"請選擇上級數據!", - "appOrFuncIdRequired":"未配置菜單或應用參數,請在設計器中配置。", + "pleaseSelectUpdateRow": "請選擇更新附件的行!", + "pleaseUploadFirst": "請先上傳附件!", + "pleaseSelectDownloadAttachment": "請選擇要下載的附件!", + "noDownloadAttachment": "找不到要下載的附件!", + "noAttachment": "沒有可以預覽的附件。", + "noParentData": "請選擇上級數據!", + "appOrFuncIdRequired": "未配置菜單或應用參數,請在設計器中配置。", "validate": "'$property'校驗不通過", - "dataPicking": "幫助前表達式校驗不通過" + "dataPicking": "幫助前表達式校驗不通過", + "fullTreeType": "完整樹類型參數(fullTreeType)不能爲空且必須爲字符串。", + "fullTreeLoadType":"完整樹加載方式參數(loadType)不能爲空且必須爲字符串。" } \ No newline at end of file -- Gitee From ff7fef0a6459e3b30a6d2c33d2011fac0d21f8d8 Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Tue, 16 Sep 2025 17:19:08 +0800 Subject: [PATCH 20/24] =?UTF-8?q?feature:=20=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E6=9E=84=E4=BB=B6=E4=B8=8A=E4=B8=8B=E6=96=87=E6=94=AF=E6=8C=81?= =?UTF-8?q?viewModel=E3=80=81module=EF=BC=8C=E6=96=B9=E4=BE=BF=E5=BC=80?= =?UTF-8?q?=E5=8F=91=E8=80=85=E5=BF=AB=E9=80=9F=E5=88=87=E6=8D=A2=E8=A7=86?= =?UTF-8?q?=E5=9B=BE=E6=A8=A1=E5=9E=8B=E3=80=81=E5=8F=98=E9=87=8F=E4=BB=93?= =?UTF-8?q?=E5=BA=93=E3=80=81=E7=BB=84=E5=90=88=E8=A1=A8=E5=8D=95=E7=AD=89?= =?UTF-8?q?=E5=AF=B9=E8=B1=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/command-services/lib/controller.service.ts | 1 + packages/command-services/lib/types.ts | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/command-services/lib/controller.service.ts b/packages/command-services/lib/controller.service.ts index 866f2a64d..ac9954003 100644 --- a/packages/command-services/lib/controller.service.ts +++ b/packages/command-services/lib/controller.service.ts @@ -94,6 +94,7 @@ export class ControllerService { method: this.buildMethodContext(), repository: this.repository, dataService: this.buildDataServiceContext(), + module: this.viewModel.getModule() }; } private buildUtilContext(): UtilContext { diff --git a/packages/command-services/lib/types.ts b/packages/command-services/lib/types.ts index e53779fbd..10d83d04d 100644 --- a/packages/command-services/lib/types.ts +++ b/packages/command-services/lib/types.ts @@ -1,5 +1,5 @@ import { BefRepository, RequestInfo } from '@farris/bef-vue'; -import { Entity, EntityList, EntityPath, EntityState, EntityStore, HttpMethod, HttpRequestConfig, UIState, UIStore } from '@farris/devkit-vue'; +import { Entity, EntityList, EntityPath, EntityState, EntityStore, HttpMethod, HttpRequestConfig, Module, UIState, UIStore, ViewModel, ViewModelState } from '@farris/devkit-vue'; import { LookupConfig, ModalConfig } from './dialog.service'; import { StateMachineService } from './state-machine.service'; @@ -422,4 +422,14 @@ export interface ControllerContext { * @description 数据服务是对repository和entityStore的封装,即调用后端接口并更新本地数据仓库 */ dataService: DataServiceContext; + /** + * 视图模型上下文 + * @description 可以快速切换视图模型,获取entityStore、uiStore等对象 + */ + viewModel?: ViewModel; + /** + * 表单上下文 + * @description 模块,代表表单,可以使用模块快速切换视图模型、变量仓库 + */ + module: Module; } -- Gitee From aa08aa4f8451827100cf97b4e02a80e7c9dcbef1 Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Tue, 16 Sep 2025 17:27:50 +0800 Subject: [PATCH 21/24] =?UTF-8?q?feature:=20module=E5=A2=9E=E5=8A=A0getRoo?= =?UTF-8?q?tUIStore=E6=96=B9=E6=B3=95=EF=BC=8C=E7=AE=80=E5=8C=96=E5=BC=80?= =?UTF-8?q?=E5=8F=91=E4=BA=BA=E5=91=98=E8=8E=B7=E5=8F=96=E6=A0=B9=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E5=8F=98=E9=87=8F=E4=BB=93=E5=BA=93=E7=9A=84=E5=86=99?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/devkit/lib/module/module.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/devkit/lib/module/module.ts b/packages/devkit/lib/module/module.ts index af50d065e..77b1d7d5e 100644 --- a/packages/devkit/lib/module/module.ts +++ b/packages/devkit/lib/module/module.ts @@ -187,7 +187,13 @@ class Module implements IDisposable { public getEntityStores(): EntityStore>[] { return Array.from(this.entityStores.values()); } - + /** + * 获取根组件对应的变量仓库 + * @returns + */ + public getRootUIStore() { + return this.getRootViewModel().uiStore; + } /** * 获取UI仓库 */ -- Gitee From b74675755a8578f63114dc1fbbb16afa0f55b46e Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Sat, 20 Sep 2025 15:36:40 +0800 Subject: [PATCH 22/24] =?UTF-8?q?feature:=20=E6=9E=84=E4=BB=B6=E4=B8=8A?= =?UTF-8?q?=E4=B8=8B=E6=96=87=E6=96=B0=E5=A2=9EhttpClient=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E9=9B=86=E5=90=88=EF=BC=8C=E6=96=B9=E4=BE=BF=E5=BC=80?= =?UTF-8?q?=E5=8F=91=E4=BA=BA=E5=91=98=E5=8F=91=E9=80=81=E8=AF=B7=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/controller.service.ts | 20 ++++++++++++++++--- packages/command-services/lib/types.ts | 17 ++++++++++++++-- packages/devkit/lib/http/http-client.ts | 10 +++++----- packages/devkit/lib/http/http-util.ts | 2 +- 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/packages/command-services/lib/controller.service.ts b/packages/command-services/lib/controller.service.ts index ac9954003..49cd2b695 100644 --- a/packages/command-services/lib/controller.service.ts +++ b/packages/command-services/lib/controller.service.ts @@ -1,4 +1,4 @@ -import { Entity, EntityPath, HttpMethod, HttpMethods, HttpRequestConfig, Injector, ViewModel, ViewModelState } from '@farris/devkit-vue'; +import { Entity, EntityPath, HttpClient, HttpMethod, HttpMethods, HttpRequestConfig, Injector, ViewModel, ViewModelState } from '@farris/devkit-vue'; import { BefProxy, BefRepository, RequestInfoUtil } from '@farris/bef-vue'; import { RenderEngineService } from './render-engine.service'; import { TemplateService } from './template.service'; @@ -8,7 +8,7 @@ import { FormNotifyService } from './form-notify.service'; import { CommandService } from './command.service'; import { CancelDataService, CardDataService, ListDataService, LoadDataService, RemoveDataService, SaveDataService, UpdateDataService } from './data-services'; import { ContextService } from './devkit-services/index'; -import { ApiClientContext, ComponentContext, ControllerContext, DataServiceContext, EntityStoreContext, I18nContext, MethodContext, ServiceContext, UtilContext } from './types'; +import { ApiClientContext, ComponentContext, ControllerContext, DataServiceContext, EntityStoreContext, HttpClientContext, I18nContext, MethodContext, ServiceContext, UtilContext } from './types'; import { TranslateService } from './locale'; import { DialogService } from './dialog.service'; import { StateMachineService } from './state-machine.service'; @@ -34,6 +34,7 @@ export class ControllerService { protected removeDataService: RemoveDataService; protected saveDataService: SaveDataService; protected cancelDataService: CancelDataService; + protected httpClient: HttpClient; public context: ControllerContext; @@ -58,7 +59,7 @@ export class ControllerService { this.removeDataService = this.injector.get(RemoveDataService); this.saveDataService = this.injector.get(SaveDataService); this.cancelDataService = this.injector.get(CancelDataService); - + this.httpClient = this.injector.get(HttpClient); this.context = this.buildContext(); } @@ -83,6 +84,7 @@ export class ControllerService { } private buildContext(): ControllerContext { return { + httpClient: this.buildHttpClientContext(), apiClient: this.buildApiClientContext(), util: this.buildUtilContext(), i18n: this.buildI18nContext(), @@ -125,6 +127,18 @@ export class ControllerService { openLookup: this.dialogService.openLookup.bind(this.dialogService) }; } + private buildHttpClientContext(): HttpClientContext { + return { + get: this.httpClient.get.bind(this.httpClient), + post: this.httpClient.post.bind(this.httpClient), + put: this.httpClient.put.bind(this.httpClient), + patch: this.httpClient.patch.bind(this.httpClient), + delete: this.httpClient.delete.bind(this.httpClient), + request: (url: string, method: HttpMethod, requestConfig?: HttpRequestConfig) => { + return this.httpClient.request(method, url, requestConfig); + }, + }; + } /** * 构造接口客户端上下文 * @returns diff --git a/packages/command-services/lib/types.ts b/packages/command-services/lib/types.ts index 10d83d04d..7e375108c 100644 --- a/packages/command-services/lib/types.ts +++ b/packages/command-services/lib/types.ts @@ -132,8 +132,7 @@ export interface BuildFrameworkTabIdOptions { funcId?: string; tabId?: string; } - -export interface ApiClientContext { +export interface HttpClientContext { /** * 使用GET方法调用后端接口 * @param url api地址 @@ -187,6 +186,8 @@ export interface ApiClientContext { */ request(url: string, method: HttpMethod, requestConfig?: HttpRequestConfig): Promise; } +export interface ApiClientContext extends HttpClientContext { +} export interface I18nContext { /** * 多语翻译 @@ -376,16 +377,25 @@ export interface DataServiceContext { cancel(showConfirm?: boolean): Promise; } export interface ControllerContext { + /** + * http请求库 + * @description 该请求库用于向非表单接口发送请求,发送请求时不会携带表单变更集 + */ + httpClient: HttpClientContext; /** * api客户端 + * @description 用于调用表单后端接口,请求时会自动携带变更,不需要开发者手动构造变更集 + * @summary 请不要使用apiClient请求非表单接口,会导致变更集丢失,请求非表单资源请使用httpClient */ apiClient: ApiClientContext; /** * 多语上下文 + * @description 用于获取当前语言环境,翻译多语key为适配当前语言环境的文本 */ i18n: I18nContext; /** * 工具上下文 + * @description 工具方法集合,如展示或关闭加载动画、展示提示消息等 */ util: UtilContext; /** @@ -394,6 +404,7 @@ export interface ControllerContext { entityStore: EntityStoreContext | null; /** * 界面状态仓库上下文 + * @description 常用实体操作方法 */ uiStore: UIStore | null; /** @@ -402,6 +413,7 @@ export interface ControllerContext { component: ComponentContext; /** * 服务上下文 + * @description 获取组件实例、更新组件属性等 */ service: ServiceContext; /** @@ -410,6 +422,7 @@ export interface ControllerContext { eventParams?: any; /** * 方法上下文 + * @description 用于命令转调等 */ method: MethodContext; /** diff --git a/packages/devkit/lib/http/http-client.ts b/packages/devkit/lib/http/http-client.ts index b5f40ed3b..2bbb310e6 100644 --- a/packages/devkit/lib/http/http-client.ts +++ b/packages/devkit/lib/http/http-client.ts @@ -24,14 +24,14 @@ class HttpClient { /** * 发送GET请求 */ - public get(url: string, requestConfig: HttpRequestConfig): Promise { + public get(url: string, requestConfig?: HttpRequestConfig): Promise { return this.request('GET', url, requestConfig); } /** * 发送POST请求 */ - public post(url: string, body: any, requestConfig: HttpRequestConfig): Promise { + public post(url: string, body: any, requestConfig?: HttpRequestConfig): Promise { requestConfig = HttpUtil.appendBodyToRequestConfig(body, requestConfig); return this.request('POST', url, requestConfig); } @@ -39,7 +39,7 @@ class HttpClient { /** * 发送PUT请求 */ - public put(url: string, body: any, requestConfig: HttpRequestConfig): Promise { + public put(url: string, body: any, requestConfig?: HttpRequestConfig): Promise { requestConfig = HttpUtil.appendBodyToRequestConfig(body, requestConfig); return this.request('PUT', url, requestConfig); } @@ -47,7 +47,7 @@ class HttpClient { /** * 发送PATCH请求 */ - public patch(url: string, body: any, requestConfig: HttpRequestConfig): Promise { + public patch(url: string, body: any, requestConfig?: HttpRequestConfig): Promise { requestConfig = HttpUtil.appendBodyToRequestConfig(body, requestConfig); return this.request('PATCH', url, requestConfig); } @@ -62,7 +62,7 @@ class HttpClient { /** * 发送请求 */ - public request(method: HttpMethod, url: string, requestConfig: HttpRequestConfig): Promise { + public request(method: HttpMethod, url: string, requestConfig?: HttpRequestConfig): Promise { const axiosRequestConfig = HttpUtil.buildAxiosRequestConfig(method, url, requestConfig); const responsePromise = this.axiosInstance.request(axiosRequestConfig).then((axiosResponse: AxiosResponse) => { const httpResponse = HttpUtil.buildHttpResponse(axiosResponse); diff --git a/packages/devkit/lib/http/http-util.ts b/packages/devkit/lib/http/http-util.ts index a6d958edb..7e0998ac0 100644 --- a/packages/devkit/lib/http/http-util.ts +++ b/packages/devkit/lib/http/http-util.ts @@ -26,7 +26,7 @@ class HttpUtil { /** * 构造AxiosReqeustConfig */ - public static buildAxiosRequestConfig(method: HttpMethod, url: string, requestConfig: HttpRequestConfig): AxiosRequestConfig { + public static buildAxiosRequestConfig(method: HttpMethod, url: string, requestConfig?: HttpRequestConfig): AxiosRequestConfig { requestConfig = requestConfig || {}; const axiosRequestConfig: AxiosRequestConfig = { -- Gitee From 341772e08ff03cfc1fcfa73de65fee855447e05a Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Sat, 20 Sep 2025 15:57:19 +0800 Subject: [PATCH 23/24] =?UTF-8?q?feature:=20=E6=B8=B2=E6=9F=93=E5=BC=95?= =?UTF-8?q?=E6=93=8E=E6=94=AF=E6=8C=81=E5=8A=A8=E6=80=81=E5=8A=A0=E8=BD=BD?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=E3=80=81=E6=A0=B7=E5=BC=8F=E8=B5=84=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/renderer/src/composition/index.ts | 1 + .../renderer/src/composition/use-resource.ts | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 packages/renderer/src/composition/use-resource.ts diff --git a/packages/renderer/src/composition/index.ts b/packages/renderer/src/composition/index.ts index db0d73fda..c3c626f11 100644 --- a/packages/renderer/src/composition/index.ts +++ b/packages/renderer/src/composition/index.ts @@ -23,3 +23,4 @@ export * from './use-custom-component-renders'; export * from './use-translate'; export * from './use-custom-css'; export * from './use-rich-editor-provide'; +export * from './use-resource'; diff --git a/packages/renderer/src/composition/use-resource.ts b/packages/renderer/src/composition/use-resource.ts new file mode 100644 index 000000000..4cb282833 --- /dev/null +++ b/packages/renderer/src/composition/use-resource.ts @@ -0,0 +1,28 @@ +import { Ref } from "vue"; + +export function useResource(metadataRef: Ref) { + const { resources } = metadataRef.value.form.content.module; + if(!resources || resources.length<1){ + return; + } + function loadScriptFile(jsFilePath: string) { + const script = document.createElement('script'); + script.type = 'text/javascript'; + script.src = jsFilePath; + document.head.appendChild(script); + } + function loadStyleFile(cssFilePath: string) { + const link = document.createElement('link'); + link.rel = 'stylesheet'; + link.type = 'text/css'; + link.href = cssFilePath; + document.head.appendChild(link); + } + resources.forEach((item: any) => { + if (item.type === 'js' && item.path) { + loadScriptFile(item.path); + } else if (item.type === 'css' && item.path) { + loadStyleFile(item.path); + } + }); +} -- Gitee From 82ac3a30621f77541119ebb3314e19e4c9d5dd32 Mon Sep 17 00:00:00 2001 From: aalizzwell Date: Sat, 20 Sep 2025 16:10:39 +0800 Subject: [PATCH 24/24] =?UTF-8?q?feature:=20=E6=94=AF=E6=8C=81=E7=BB=99?= =?UTF-8?q?=E8=99=9A=E6=8B=9F=E5=AD=97=E6=AE=B5=E8=B5=8B=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/store/entity-store/entity-state-updater.ts | 7 +++++-- .../devkit/lib/store/entity-store/entity-store.ts | 13 ++++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/packages/devkit/lib/store/entity-store/entity-state-updater.ts b/packages/devkit/lib/store/entity-store/entity-state-updater.ts index 5c0e03770..4e10a2d01 100644 --- a/packages/devkit/lib/store/entity-store/entity-state-updater.ts +++ b/packages/devkit/lib/store/entity-store/entity-state-updater.ts @@ -138,8 +138,11 @@ class EntityStateUpdater { /** * 根据属性Path,更新属性值 + * @param path 属性路径 + * @param newValue 新值 + * @param persistent 是否持久化变更,默认true */ - public setValueByPath(path: EntityPath, newValue: any): void { + public setValueByPath(path: EntityPath, newValue: any, persistent = true): void { const parentPath = path.getParentEntityPath(); const entity = this.entityQuery.getEntityByPath(parentPath) as any; @@ -166,7 +169,7 @@ class EntityStateUpdater { oldValue, newValue }; - this.entityStore.triggerChange(change); + this.entityStore.triggerChange(change, persistent); } /** diff --git a/packages/devkit/lib/store/entity-store/entity-store.ts b/packages/devkit/lib/store/entity-store/entity-store.ts index b0413f5fa..f8bf8c031 100644 --- a/packages/devkit/lib/store/entity-store/entity-store.ts +++ b/packages/devkit/lib/store/entity-store/entity-store.ts @@ -234,8 +234,11 @@ class EntityStore> extends Store { /** * 根据path更新字段值 + * @param path 字段路径 + * @param value 字段值 + * @param persistent 是否持久化变更,默认true。持久化变更会将变更记录到变更集中,并提交给后端进行持久化,不持久化变更只更新前端界面 */ - public setValueByPath(path: string | EntityPath, value: any): void { + public setValueByPath(path: string | EntityPath, value: any, persistent = true): void { const entityPath = this.createPath(path); this.entityUpdater.setValueByPath(entityPath, value); } @@ -325,10 +328,14 @@ class EntityStore> extends Store { /** * 触发变更 + * @param change 变更信息 + * @param recordChange 是否记录变更历史,默认true */ - public triggerChange(change: any) { + public triggerChange(change: any, recordChange: boolean = true) { this.refreshState(); - this.entityChangeHistory.addChange(change); + if (recordChange) { + this.entityChangeHistory.addChange(change); + } super.triggerChange(change as any); } -- Gitee