From a5f8b8039fb75b69c74c0e7b455059521c7dec27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E9=85=92?= Date: Thu, 10 Oct 2024 14:53:07 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E7=9B=91=E5=90=AC=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E5=8F=98=E6=9B=B4=E6=8B=86=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 4 +- packages/pages-vm-api/package.json | 2 +- .../src/decl/master/custom.model.service.ts | 22 ++++ .../src/decl/master/design.service.ts | 11 ++ .../src/decl/master/event.service.ts | 24 +++++ .../src/decl/{ => master}/export.service.ts | 2 +- .../{ => master}/fitting.design.service.ts | 2 +- .../src/decl/{ => master}/index.ts | 3 + .../src/decl/{ => master}/toast.service.ts | 2 +- packages/pages-vm-api/src/decl/slave/index.ts | 1 + .../src/decl/slave/timer.service.ts | 12 +++ packages/pages-vm-api/src/index.ts | 3 +- packages/vm/package.json | 2 +- packages/vm/src/environment-hack/hack.ts | 14 +++ packages/vm/src/environment-hack/index.ts | 1 + packages/vm/src/environment-hack/timer.ts | 80 ++++++++++++++ .../vm/src/impl/custom.model.service.impl.ts | 15 +++ packages/vm/src/impl/design.service.impl.ts | 9 ++ packages/vm/src/impl/event.service.impl.ts | 9 ++ packages/vm/src/impl/index.ts | 17 ++- packages/vm/src/index.ts | 24 +++-- packages/vm/src/master/index.ts | 23 +++- packages/vm/src/util/create-defer.ts | 43 ++++++++ packages/vm/src/util/get-global.ts | 15 +++ pages/appPage/index.ts | 2 +- pages/appPage/src/core/index.ts | 7 +- pages/appPage/src/salve/impl/index.ts | 9 ++ .../src/salve/impl/timer-impl.service.ts | 11 ++ pages/appPage/src/salve/index.ts | 9 +- pages/appPage/src/store/modelList/action.ts | 10 ++ pages/appPage/src/store/modelList/constant.ts | 1 + pages/appPage/src/store/modelList/reducers.ts | 30 ++++++ pages/appPage/src/store/reducers.ts | 2 + pages/appPage/src/util/actionHelper.ts | 62 +++++++++++ pages/appPage/src/util/customModelRecorder.ts | 71 ++++++++++++ pages/appPage/src/util/vmapi.ts | 21 +++- pages/appPage/src/views/App.tsx | 2 + pages/appPage/src/views/leftPanel/index.tsx | 68 ++++-------- .../src/views/listener/index.module.scss | 19 ++++ pages/appPage/src/views/listener/index.tsx | 101 ++++++++++++++++++ .../src/views/rightPanelV2/baseInfo/index.tsx | 39 ++----- yarn.lock | 64 ++++++----- 42 files changed, 736 insertions(+), 132 deletions(-) create mode 100644 packages/pages-vm-api/src/decl/master/custom.model.service.ts create mode 100644 packages/pages-vm-api/src/decl/master/design.service.ts create mode 100644 packages/pages-vm-api/src/decl/master/event.service.ts rename packages/pages-vm-api/src/decl/{ => master}/export.service.ts (88%) rename packages/pages-vm-api/src/decl/{ => master}/fitting.design.service.ts (89%) rename packages/pages-vm-api/src/decl/{ => master}/index.ts (50%) rename packages/pages-vm-api/src/decl/{ => master}/toast.service.ts (70%) create mode 100644 packages/pages-vm-api/src/decl/slave/index.ts create mode 100644 packages/pages-vm-api/src/decl/slave/timer.service.ts create mode 100644 packages/vm/src/environment-hack/hack.ts create mode 100644 packages/vm/src/environment-hack/index.ts create mode 100644 packages/vm/src/environment-hack/timer.ts create mode 100644 packages/vm/src/impl/custom.model.service.impl.ts create mode 100644 packages/vm/src/impl/design.service.impl.ts create mode 100644 packages/vm/src/impl/event.service.impl.ts create mode 100644 packages/vm/src/util/create-defer.ts create mode 100644 packages/vm/src/util/get-global.ts create mode 100644 pages/appPage/src/salve/impl/index.ts create mode 100644 pages/appPage/src/salve/impl/timer-impl.service.ts create mode 100644 pages/appPage/src/store/modelList/action.ts create mode 100644 pages/appPage/src/store/modelList/constant.ts create mode 100644 pages/appPage/src/store/modelList/reducers.ts create mode 100644 pages/appPage/src/util/actionHelper.ts create mode 100644 pages/appPage/src/util/customModelRecorder.ts create mode 100644 pages/appPage/src/views/listener/index.module.scss create mode 100644 pages/appPage/src/views/listener/index.tsx diff --git a/package.json b/package.json index ca46740..4adcb6b 100644 --- a/package.json +++ b/package.json @@ -99,10 +99,10 @@ "workbox-webpack-plugin": "5.1.4", "memoizee": "^0.4.15", "@types/memoizee": "^0.4.5", - "message-lite": "0.0.1", + "message-lite": "0.10.5-alpha.2", "@manycore/custom-miniapp-sdk": "^0.20.18", "@manycore/custom-sdk": "^3.1.6", - "@manycore/idp-sdk": "^1.38.0" + "@manycore/idp-sdk": "^1.53.0" }, "workspaces": [ "packages/*" diff --git a/packages/pages-vm-api/package.json b/packages/pages-vm-api/package.json index 7cb9048..a3c962c 100644 --- a/packages/pages-vm-api/package.json +++ b/packages/pages-vm-api/package.json @@ -7,6 +7,6 @@ "license": "ISC", "scripts": {}, "dependencies": { - "message-lite": "0.0.1" + "message-lite": "0.10.5-alpha.2" } } diff --git a/packages/pages-vm-api/src/decl/master/custom.model.service.ts b/packages/pages-vm-api/src/decl/master/custom.model.service.ts new file mode 100644 index 0000000..7507f9f --- /dev/null +++ b/packages/pages-vm-api/src/decl/master/custom.model.service.ts @@ -0,0 +1,22 @@ +import { ApiDecl, ApiDeclApi, ApiUnSupport, MBaseService as BaseService } from 'message-lite'; + + +export type IGetTopModelsLiteInfoAsyncFuncType = typeof IDP.Custom.Design.CustomModel.getTopModelsLiteInfoAsync; +export type IGetTopModelsLiteInfoAsyncParameters = Parameters[0]; +export type IGetTopModelsLiteInfoAsyncResult = ReturnType; +export type ICustomModel = IDP.Custom.Design.CustomModel.CustomModel; + +@ApiDecl({ + name: 'miniapp.custom.model.service', +}) +export class CustomModelService extends BaseService { + @ApiDeclApi() + getTopModelsLiteInfoAsync(options?: IGetTopModelsLiteInfoAsyncParameters): IGetTopModelsLiteInfoAsyncResult { + return ApiUnSupport(); + } + + @ApiDeclApi() + getCustomModelByModelIdAsync(id: string): Promise { + return ApiUnSupport(); + } +} diff --git a/packages/pages-vm-api/src/decl/master/design.service.ts b/packages/pages-vm-api/src/decl/master/design.service.ts new file mode 100644 index 0000000..d9c30f5 --- /dev/null +++ b/packages/pages-vm-api/src/decl/master/design.service.ts @@ -0,0 +1,11 @@ +import { ApiDecl, ApiDeclApi, ApiUnSupport, MBaseService as BaseService } from 'message-lite'; + +@ApiDecl({ + name: 'miniapp.design.service', +}) +export class DesignService extends BaseService { + @ApiDeclApi() + save() { + return ApiUnSupport(); + } +} diff --git a/packages/pages-vm-api/src/decl/master/event.service.ts b/packages/pages-vm-api/src/decl/master/event.service.ts new file mode 100644 index 0000000..3bae25a --- /dev/null +++ b/packages/pages-vm-api/src/decl/master/event.service.ts @@ -0,0 +1,24 @@ +import { ApiDecl, ApiDeclEvent, IEventer, MBaseService as BaseService } from 'message-lite'; + +export type ElementId = IDP.DB.Types.ElementId; +export type OrderModel = IDP.EventTypes['IDP.Integration.FOP.OrderMode.OrderModel.Update'] + +@ApiDecl({ + name: 'miniapp.event.service', +}) +export class EventService extends BaseService { + @ApiDeclEvent() + customModelAdded!: IEventer; + + @ApiDeclEvent() + customModelUpdate!: IEventer; + + @ApiDeclEvent() + customModelDelete!: IEventer; + + @ApiDeclEvent() + designSaved!: IEventer; + + @ApiDeclEvent() + orderModelUpdate!: IEventer; +} diff --git a/packages/pages-vm-api/src/decl/export.service.ts b/packages/pages-vm-api/src/decl/master/export.service.ts similarity index 88% rename from packages/pages-vm-api/src/decl/export.service.ts rename to packages/pages-vm-api/src/decl/master/export.service.ts index e7c13a3..d6a31f6 100644 --- a/packages/pages-vm-api/src/decl/export.service.ts +++ b/packages/pages-vm-api/src/decl/master/export.service.ts @@ -1,4 +1,4 @@ -import { ApiDecl, ApiDeclApi, ApiUnSupport, BaseService } from 'message-lite'; +import { ApiDecl, ApiDeclApi, ApiUnSupport, MBaseService as BaseService } from 'message-lite'; export type IGetFittingDataFromAuxiliaryFuncType = typeof IDP.Custom.Design.Export.getFittingDataFromAuxiliaryAsync; export type IGetFittingDataFromAuxiliaryParams = Parameters; diff --git a/packages/pages-vm-api/src/decl/fitting.design.service.ts b/packages/pages-vm-api/src/decl/master/fitting.design.service.ts similarity index 89% rename from packages/pages-vm-api/src/decl/fitting.design.service.ts rename to packages/pages-vm-api/src/decl/master/fitting.design.service.ts index ff1ead3..0dc8925 100644 --- a/packages/pages-vm-api/src/decl/fitting.design.service.ts +++ b/packages/pages-vm-api/src/decl/master/fitting.design.service.ts @@ -1,4 +1,4 @@ -import { ApiDecl, ApiDeclApi, ApiUnSupport, BaseService } from 'message-lite'; +import { ApiDecl, ApiDeclApi, ApiUnSupport, MBaseService as BaseService } from 'message-lite'; export type IPutDesignDataAsyncFuncType = typeof IDP.Custom.FittingDesignV2.putDesignDataAsync; export type IPutFittingDesignDataParameters = Parameters; diff --git a/packages/pages-vm-api/src/decl/index.ts b/packages/pages-vm-api/src/decl/master/index.ts similarity index 50% rename from packages/pages-vm-api/src/decl/index.ts rename to packages/pages-vm-api/src/decl/master/index.ts index ad3ebe8..47e612a 100644 --- a/packages/pages-vm-api/src/decl/index.ts +++ b/packages/pages-vm-api/src/decl/master/index.ts @@ -1,3 +1,6 @@ export * from './toast.service'; export * from './export.service'; export * from './fitting.design.service'; +export * from './event.service'; +export * from './custom.model.service'; +export * from './design.service'; diff --git a/packages/pages-vm-api/src/decl/toast.service.ts b/packages/pages-vm-api/src/decl/master/toast.service.ts similarity index 70% rename from packages/pages-vm-api/src/decl/toast.service.ts rename to packages/pages-vm-api/src/decl/master/toast.service.ts index 3143639..dac3c6a 100644 --- a/packages/pages-vm-api/src/decl/toast.service.ts +++ b/packages/pages-vm-api/src/decl/master/toast.service.ts @@ -1,4 +1,4 @@ -import { ApiDecl, ApiDeclApi, ApiUnSupport, BaseService } from 'message-lite'; +import { ApiDecl, ApiDeclApi, ApiUnSupport, MBaseService as BaseService } from 'message-lite'; @ApiDecl({ name: 'miniapp.toast.service', diff --git a/packages/pages-vm-api/src/decl/slave/index.ts b/packages/pages-vm-api/src/decl/slave/index.ts new file mode 100644 index 0000000..599d80d --- /dev/null +++ b/packages/pages-vm-api/src/decl/slave/index.ts @@ -0,0 +1 @@ +export * from './timer.service'; \ No newline at end of file diff --git a/packages/pages-vm-api/src/decl/slave/timer.service.ts b/packages/pages-vm-api/src/decl/slave/timer.service.ts new file mode 100644 index 0000000..8f3e599 --- /dev/null +++ b/packages/pages-vm-api/src/decl/slave/timer.service.ts @@ -0,0 +1,12 @@ +import { ApiDecl, ApiDeclApi, ApiUnSupport, MBaseService } from 'message-lite'; + +@ApiDecl({ + name: 'com.custom.test.timer', +}) +export class TimerService extends MBaseService { + + @ApiDeclApi() + timeout(time?: number): Promise { + return ApiUnSupport(); + } +} diff --git a/packages/pages-vm-api/src/index.ts b/packages/pages-vm-api/src/index.ts index 1b15026..e34eceb 100644 --- a/packages/pages-vm-api/src/index.ts +++ b/packages/pages-vm-api/src/index.ts @@ -1 +1,2 @@ -export * from './decl'; +export * from './decl/master'; +export * from './decl/slave'; diff --git a/packages/vm/package.json b/packages/vm/package.json index 8dce11a..00af24a 100644 --- a/packages/vm/package.json +++ b/packages/vm/package.json @@ -7,7 +7,7 @@ "license": "ISC", "dependencies": { "@manycore/idp-sdk": "1.38.0", - "message-lite": "0.0.1", + "message-lite": "0.10.5-alpha.2", "@manycore/pages-vm-api": "1.9.1" }, "scripts": {} diff --git a/packages/vm/src/environment-hack/hack.ts b/packages/vm/src/environment-hack/hack.ts new file mode 100644 index 0000000..e846a97 --- /dev/null +++ b/packages/vm/src/environment-hack/hack.ts @@ -0,0 +1,14 @@ +import { getGlobalObject } from "../util/get-global"; +import { globalTimer } from "./timer"; + +/** 全局对象 */ +export const global = getGlobalObject(); + +if (typeof global.setTimeout === 'undefined') { + global.setTimeout = globalTimer.setTimeout; + global.clearTimeout = globalTimer.clearTimeout; +} +if (typeof global.setImmediate === 'undefined') { + global.setImmediate = global.setTimeout; + global.clearImmediate = global.clearTimeout; +} diff --git a/packages/vm/src/environment-hack/index.ts b/packages/vm/src/environment-hack/index.ts new file mode 100644 index 0000000..ebabc1e --- /dev/null +++ b/packages/vm/src/environment-hack/index.ts @@ -0,0 +1 @@ +import './hack'; diff --git a/packages/vm/src/environment-hack/timer.ts b/packages/vm/src/environment-hack/timer.ts new file mode 100644 index 0000000..b2455da --- /dev/null +++ b/packages/vm/src/environment-hack/timer.ts @@ -0,0 +1,80 @@ +import { IPromiseDefer, createDefer } from "../util/create-defer"; + +export interface ITimer { + defer: IPromiseDefer; + time: number; + uid: number; + started: boolean; +} + +export class Timer { + + protected uid = 0; + + protected readonly timer = new Map(); + + protected _sleep!: ((time: number) => Promise) | null; + + protected runJob = () => { + if (this.timer.size) { + // 触发立即执行 + Array.from(this.timer).forEach(([uid, iTask]) => { + if (this._sleep && !iTask.started) { + iTask.defer.resolve(this._sleep(iTask.time)); + iTask.started = true; + } + }) + } + } + + public setSleepFn = (sleep: null | ((time: number) => Promise)) => { + this._sleep = sleep; + this.runJob(); + } + + public wrapFn(uid: number, fn: Function, ...args: any): () => any { + let timer = this.timer; + return function () { + if (timer.has(uid)) { + try { + const currentTask = timer.get(uid)!; + currentTask.started = true; + fn(...args); + } finally { + timer.delete(uid); + timer = null!; + } + } + }; + } + + public setTimeout = (fn: Function, time: number = 0, ...args: any[]) => { + const val = ++this.uid; + const defer = createDefer(); + defer.promise.then(this.wrapFn(val, fn, ...args)); + this.timer.set(val, { + defer, + uid: val, + time, + started: false, + }); + this.runJob(); + return val; + } + + public clearTimeout = (uid: any) => { + if (typeof uid === 'number' && this.timer.has(uid)) { + this.timer.delete(uid); + } + } + + public setInterval = () => { + + } + + public clearInterval = () => { + + } +} + +export const globalTimer = new Timer(); diff --git a/packages/vm/src/impl/custom.model.service.impl.ts b/packages/vm/src/impl/custom.model.service.impl.ts new file mode 100644 index 0000000..fd102a3 --- /dev/null +++ b/packages/vm/src/impl/custom.model.service.impl.ts @@ -0,0 +1,15 @@ +import { ApiImpl } from 'message-lite'; +import { + CustomModelService, IGetTopModelsLiteInfoAsyncParameters, +} from '@manycore/pages-vm-api'; + +@ApiImpl() +export class CustomModelServiceImpl extends CustomModelService { + getTopModelsLiteInfoAsync(option: IGetTopModelsLiteInfoAsyncParameters) { + return IDP.Custom.Design.CustomModel.getTopModelsLiteInfoAsync(option); + } + + getCustomModelByModelIdAsync(id: string) { + return IDP.Custom.Design.CustomModel.getCustomModelByModelIdAsync(id); + } +} diff --git a/packages/vm/src/impl/design.service.impl.ts b/packages/vm/src/impl/design.service.impl.ts new file mode 100644 index 0000000..c11bf90 --- /dev/null +++ b/packages/vm/src/impl/design.service.impl.ts @@ -0,0 +1,9 @@ +import { ApiImpl } from 'message-lite'; +import { DesignService } from '@manycore/pages-vm-api'; + +@ApiImpl() +export class DesignServiceImpl extends DesignService { + save() { + return IDP.Design.save(); + } +} diff --git a/packages/vm/src/impl/event.service.impl.ts b/packages/vm/src/impl/event.service.impl.ts new file mode 100644 index 0000000..5667e69 --- /dev/null +++ b/packages/vm/src/impl/event.service.impl.ts @@ -0,0 +1,9 @@ +import { ApiImpl } from 'message-lite'; +import { + EventService, +} from '@manycore/pages-vm-api'; + +@ApiImpl() +export class EventServiceImpl extends EventService { + +} diff --git a/packages/vm/src/impl/index.ts b/packages/vm/src/impl/index.ts index d9d3251..3cd4220 100644 --- a/packages/vm/src/impl/index.ts +++ b/packages/vm/src/impl/index.ts @@ -1,7 +1,10 @@ -import { ToastService, ExportService, FittingDesignService } from '@manycore/pages-vm-api'; +import { ToastService, ExportService, FittingDesignService, EventService, CustomModelService, DesignService } from '@manycore/pages-vm-api'; import { ToastServiceImpl } from './toast.service.impl'; import { ExportServiceImpl } from './export.service.impl'; import { FittingDesignServiceImpl } from './fitting.design.service.impl'; +import { EventServiceImpl } from './event.service.impl'; +import { CustomModelServiceImpl } from './custom.model.service.impl'; +import { DesignServiceImpl } from './design.service.impl'; export const services = [ { @@ -16,4 +19,16 @@ export const services = [ decl: FittingDesignService, impl: FittingDesignServiceImpl, }, + { + decl: EventService, + impl: EventServiceImpl, + }, + { + decl: CustomModelService, + impl: CustomModelServiceImpl, + }, + { + decl: DesignService, + impl: DesignServiceImpl, + }, ]; diff --git a/packages/vm/src/index.ts b/packages/vm/src/index.ts index 73243ab..44db6ac 100644 --- a/packages/vm/src/index.ts +++ b/packages/vm/src/index.ts @@ -1,24 +1,32 @@ +import { EventService } from '@manycore/pages-vm-api'; import { master } from './master'; +import './environment-hack'; IDP.Miniapp.view.defaultFrame.mount(IDP.Miniapp.view.mountPoints.main); // 小屏展示 IDP.Miniapp.view.setContainerOptions(IDP.Miniapp.view.defaultFrame, { - windowMode: 'windowed', - draggable: true, + minimizable: true, + isMinimized: true }); -IDP.Miniapp.view.defaultFrame.resize(100, 100); - Promise.all([ // 等待内部连接 - master.opening({ - clientId: 'miniapp-app', - }), + master.start(), // 打开对接2.0通信通道 IDP.Custom.Common.openTerminalAsync(), -]).catch(() => { +]).then(() => { + IDP.Events.on('IDP.Custom.Design.CustomModel.AddV2', master.getService(EventService)!.customModelAdded.emit) + IDP.Events.on('IDP.Custom.Design.CustomModel.DeleteV2', master.getService(EventService)!.customModelDelete.emit); + IDP.Events.on('IDP.Custom.Design.CustomModel.UpdateV2',master.getService(EventService)!.customModelUpdate.emit); + IDP.Events.on('IDP.Design.Saved', master.getService(EventService)!.designSaved.emit); + IDP.Events.on('IDP.Integration.FOP.OrderMode.OrderModel.Update', master.getService(EventService)!.orderModelUpdate.emit); +}).catch((e) => { IDP.Miniapp.view.defaultFrame.unmount(); IDP.Custom.Common.closeTerminalAsync(); }); + + + + diff --git a/packages/vm/src/master/index.ts b/packages/vm/src/master/index.ts index 1f7db56..f8175e5 100644 --- a/packages/vm/src/master/index.ts +++ b/packages/vm/src/master/index.ts @@ -1,14 +1,31 @@ -import { Master } from 'message-lite'; +import { CONNECTED, IConnectSession, Master } from 'message-lite'; import { services } from '../impl'; +import { globalTimer } from '../environment-hack/timer'; +import { TimerService } from '@manycore/pages-vm-api'; export const master = new Master({ - sendMessage(message: any) { + createSender: (origin) => (message: any) => { IDP.Miniapp.view.defaultFrame.postMessage(message); }, listenMessage(fn: (message: any) => void) { IDP.Miniapp.view.defaultFrame.onMessageReceive(fn); }, - unListenMessage(fn: (message: any) => void) {}, + unListenMessage(fn: (message: any) => void) { }, + transformMessage: (message) => { + return message; + }, }); master.addService(services); + +master.on(CONNECTED, (session: IConnectSession) => { + if (session.getName() === 'mini-app') { + globalTimer.setSleepFn((time) => { + const service = session.getService(TimerService); + return service.timeout(time); + }); + session.closed.finally(() => { + globalTimer.setSleepFn(null); + }); + } +}); \ No newline at end of file diff --git a/packages/vm/src/util/create-defer.ts b/packages/vm/src/util/create-defer.ts new file mode 100644 index 0000000..7366d7c --- /dev/null +++ b/packages/vm/src/util/create-defer.ts @@ -0,0 +1,43 @@ +/** + * Promise的defer内容 + */ +export interface IPromiseDefer { + // 对应的promise方法 + promise: Promise; + // 对应的resolve方法 + resolve: (it?: T | PromiseLike) => void; + // reject的错误信息 + reject: (it?: any) => void; +} + +/** + * 生成promise的defer对象 + */ +export function createDefer(): IPromiseDefer { + let resolve: (value?: T | PromiseLike) => void; + let reject: (it?: any) => void; + let timer: any; + const wrapResolveOrReject = function (fn: (...args: any) => any) { + return function (this: any, ...args: any[]) { + if (typeof timer !== 'undefined') { + clearTimeout(timer); + timer = undefined; + } + fn.call(this, ...args); + }; + }; + const promise = new Promise((r, j) => { + resolve = wrapResolveOrReject(r); + reject = wrapResolveOrReject(j); + }); + + return { + promise, + // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // @ts-ignore + resolve, + // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // @ts-ignore + reject, + }; +} \ No newline at end of file diff --git a/packages/vm/src/util/get-global.ts b/packages/vm/src/util/get-global.ts new file mode 100644 index 0000000..ae50af8 --- /dev/null +++ b/packages/vm/src/util/get-global.ts @@ -0,0 +1,15 @@ + +/** + * 获取全局对象 + */ +export const getGlobalObject = function () { + if (typeof window === 'object') { + return window; + } + if (typeof globalThis === 'object') { + return globalThis; + } + return {} as any; +} + + diff --git a/pages/appPage/index.ts b/pages/appPage/index.ts index d7a5e75..50a894f 100644 --- a/pages/appPage/index.ts +++ b/pages/appPage/index.ts @@ -1 +1 @@ -import './src'; +import './src'; \ No newline at end of file diff --git a/pages/appPage/src/core/index.ts b/pages/appPage/src/core/index.ts index bf71eaf..b9833a2 100644 --- a/pages/appPage/src/core/index.ts +++ b/pages/appPage/src/core/index.ts @@ -5,9 +5,10 @@ export async function bootstrap() { const application = getApplication(); await application.start(); - (await application.isInCustomMiniAppMode()) + const isInCustomMiniAppMode = await application.isInCustomMiniAppMode(); + await (isInCustomMiniAppMode ? Promise.resolve() : createSlave(application).connect({ - clientId: 'miniapp-app', - }); + name: 'mini-app' + })) } diff --git a/pages/appPage/src/salve/impl/index.ts b/pages/appPage/src/salve/impl/index.ts new file mode 100644 index 0000000..1bbe6ca --- /dev/null +++ b/pages/appPage/src/salve/impl/index.ts @@ -0,0 +1,9 @@ +import { TimerService } from "@manycore/pages-vm-api"; +import { TimerImplService } from "./timer-impl.service"; + +export const ALL_SERVICE = [ + { + decl: TimerService, + impl: TimerImplService, + }, +] \ No newline at end of file diff --git a/pages/appPage/src/salve/impl/timer-impl.service.ts b/pages/appPage/src/salve/impl/timer-impl.service.ts new file mode 100644 index 0000000..9514519 --- /dev/null +++ b/pages/appPage/src/salve/impl/timer-impl.service.ts @@ -0,0 +1,11 @@ +import { TimerService } from '@manycore/pages-vm-api'; +import { ApiImpl } from 'message-lite'; + +@ApiImpl() +export class TimerImplService extends TimerService { + timeout(time = 0): Promise { + return new Promise((resolve) => { + setTimeout(resolve, time); + }); + } +} diff --git a/pages/appPage/src/salve/index.ts b/pages/appPage/src/salve/index.ts index 2d2e0a0..b8f12cb 100644 --- a/pages/appPage/src/salve/index.ts +++ b/pages/appPage/src/salve/index.ts @@ -1,5 +1,6 @@ import { Application } from '@manycore/custom-sdk'; import { Slave } from 'message-lite'; +import { ALL_SERVICE } from './impl'; export let slave: Slave; @@ -8,7 +9,7 @@ export const createSlave = (app: Application) => { throw new Error('slave只允许被创建一次!'); } slave = new Slave({ - sendMessage: (message: any) => { + createSender: (data: any) => (message: any) => { app.getHost().postMessage(message, '*'); }, listenMessage: (f: (message: any) => void) => { @@ -17,7 +18,11 @@ export const createSlave = (app: Application) => { }; app.getHost().onMessageReceive(fn); }, - unListenMessage: (f: (message: any) => void) => {}, + unListenMessage: (f: (message: any) => void) => { }, + transformMessage(message: MessageEvent) { + return message; + }, }); + slave.addService(ALL_SERVICE); return slave; }; diff --git a/pages/appPage/src/store/modelList/action.ts b/pages/appPage/src/store/modelList/action.ts new file mode 100644 index 0000000..4decdc0 --- /dev/null +++ b/pages/appPage/src/store/modelList/action.ts @@ -0,0 +1,10 @@ +import { Action } from 'redux'; +import { APP_MODEL_LIST_CHANGE } from './constant'; +import { IAppModelList } from './reducers'; + +export function actionUpdateModelList(modelList: Partial = {}) { + return { + type: APP_MODEL_LIST_CHANGE, + value: modelList, + }; +} diff --git a/pages/appPage/src/store/modelList/constant.ts b/pages/appPage/src/store/modelList/constant.ts new file mode 100644 index 0000000..01f0c3e --- /dev/null +++ b/pages/appPage/src/store/modelList/constant.ts @@ -0,0 +1 @@ +export const APP_MODEL_LIST_CHANGE = 'APP_MODEL_LIST_CHANGE'; diff --git a/pages/appPage/src/store/modelList/reducers.ts b/pages/appPage/src/store/modelList/reducers.ts new file mode 100644 index 0000000..d69e0f3 --- /dev/null +++ b/pages/appPage/src/store/modelList/reducers.ts @@ -0,0 +1,30 @@ +import { actionUpdateModelList } from './action'; +import { APP_MODEL_LIST_CHANGE } from './constant'; + +export interface IAppModelList { + modelList?: { + id: string; + name: string; + }[]; + modelPicMap: Map; +} + +export const initialState: IAppModelList = { + modelList: undefined, + modelPicMap: new Map() +}; + +export function modelListReducers( + state = initialState, + action: ReturnType +) { + switch (action.type) { + case APP_MODEL_LIST_CHANGE: { + return { + ...state, + ...action.value, + }; + } + } + return state; +} diff --git a/pages/appPage/src/store/reducers.ts b/pages/appPage/src/store/reducers.ts index 982589e..2f455c5 100644 --- a/pages/appPage/src/store/reducers.ts +++ b/pages/appPage/src/store/reducers.ts @@ -2,11 +2,13 @@ import { combineReducers } from 'redux'; import { intersectedReducer as splitOrderData } from './splitOrderData/reducers'; import { selectionReducers as selection } from './selection/reducers'; import { viewedModelReducers as viewedModel } from './viewed/reducers'; +import { modelListReducers as modelList } from './modelList/reducers'; const allState = { selection, splitOrderData, viewedModel, + modelList }; // 初始状态值 diff --git a/pages/appPage/src/util/actionHelper.ts b/pages/appPage/src/util/actionHelper.ts new file mode 100644 index 0000000..2c60ec0 --- /dev/null +++ b/pages/appPage/src/util/actionHelper.ts @@ -0,0 +1,62 @@ +import type { Dispatch } from 'redux'; +import { ModelService } from '@manycore/custom-sdk'; +import { getApplication } from '../core/app'; +import { actionUpdateModelList } from '../store/modelList/action'; +import { IRootState } from '../store/reducers'; +import { getFittingDataFromAuxiliary, getModelJson, getTopModelsLiteInfoAsync } from './vmapi'; +import { actionSetSplitOrderData } from '../store/splitOrderData/action'; + +export function actionInitModelListAsync(dispatch: Dispatch, getState: () => IRootState) { + return async function (changedIds?: string[]) { + const { data: models } = await getTopModelsLiteInfoAsync({ size: -1 }); + dispatch(actionUpdateModelList({ modelList: models.map(({ id, name }) => ({ id, name })) })); + + const modelService = getApplication().getService(ModelService); + models.forEach(async (m) => { + const { modelPicMap } = getState().modelList; + if (changedIds && !changedIds.includes(m.id)) { + return; + } + + const [selectedModelImgData] = await modelService.getParamModelPhotoById(m.id); + modelPicMap.set(selectedModelImgData.modelId, selectedModelImgData.imgData) + dispatch(actionUpdateModelList({ modelPicMap: new Map(modelPicMap) })); + }); + return models; + } +} + +export function actionInitSplitDataAsync(dispatch: Dispatch, getState: () => IRootState) { + return async function (modelId: string) { + async function getIntersectedData(id: string) { + const modelService = getApplication().getService(ModelService); + try { + const intersected = await modelService.getParamIntersected({ + modelId: id, + tolerance: 0.1, + faceDistTol: 0.1, + bodyDistTol: 0.1, + }); + return intersected!; + } catch (err) { + console.log('eder 加载交接数据失败', err); + } + } + const [jsonData, intersectData, fittingFromAuxiliary] = await Promise.all([ + getModelJson(modelId), + getIntersectedData(modelId), + getFittingDataFromAuxiliary({ modelId }), + ]); + + dispatch(actionSetSplitOrderData({ + intersectData: intersectData, + jsonData: jsonData, + fittingFromAuxiliary: fittingFromAuxiliary, + })); + return { + jsonData, + intersectData, + fittingFromAuxiliary + } + } +} \ No newline at end of file diff --git a/pages/appPage/src/util/customModelRecorder.ts b/pages/appPage/src/util/customModelRecorder.ts new file mode 100644 index 0000000..d7a47ed --- /dev/null +++ b/pages/appPage/src/util/customModelRecorder.ts @@ -0,0 +1,71 @@ +import { getCustomModelAddedEvent, getCustomModelDeleteEvent, getCustomModelUpdateEvent } from "./vmapi"; +import { EventEmitter } from 'eventemitter3'; + +const addedModelIds = new Set(); +const deleteModelIds = new Set(); +const updateModelIds = new Set(); +const emitter = new EventEmitter(); + +let isStart: boolean = false; +const changedEvent = Symbol('changed'); + +function startRecord() { + if (isStart) { + return; + } + isStart = true; + const handleCustomModelAdded = (elementIds: IDP.DB.Types.ElementId[]) => { + elementIds.forEach(({ id }) => { + addedModelIds.add(id); + }); + emitter.emit(changedEvent); + } + const handleCustomModelUpdate = (elementIds: IDP.DB.Types.ElementId[]) => { + elementIds.forEach(({ id }) => { + updateModelIds.add(id); + }); + emitter.emit(changedEvent); + } + const handleCustomModelDelete = (elementIds: IDP.DB.Types.ElementId[]) => { + elementIds.forEach(({ id }) => { + deleteModelIds.add(id); + }); + emitter.emit(changedEvent); + } + getCustomModelAddedEvent().on(handleCustomModelAdded); + getCustomModelUpdateEvent().on(handleCustomModelUpdate); + getCustomModelDeleteEvent().on(handleCustomModelDelete); +}; + + +function flush(callback: (changed: { + addedModels: string[]; + deleteModels: string[]; + updateModels: string[]; +}) => void) { + const changed = getChanged(); + addedModelIds.clear(); + deleteModelIds.clear(); + updateModelIds.clear(); + callback(changed); +} + +function getChanged() { + // TODO: 简化 + return { + addedModels: [...addedModelIds], + deleteModels: [...deleteModelIds], + updateModels: [...updateModelIds] + } +} + +function onChange(func: () => void) { + emitter.on(changedEvent, func); +} + +export default { + startRecord, + flush, + onChange, + getChanged +} \ No newline at end of file diff --git a/pages/appPage/src/util/vmapi.ts b/pages/appPage/src/util/vmapi.ts index 901a471..5906274 100644 --- a/pages/appPage/src/util/vmapi.ts +++ b/pages/appPage/src/util/vmapi.ts @@ -1,7 +1,8 @@ import { slave } from '../salve'; -import { ExportService, FittingDesignService } from '@manycore/pages-vm-api'; +import { EventService, ExportService, FittingDesignService, CustomModelService, IGetTopModelsLiteInfoAsyncParameters, DesignService } from '@manycore/pages-vm-api'; import { IFittingDesignDataV2, IGrooveDataV2, IHoleDataV2 } from '@manycore/custom-sdk'; + /** * 自定义属性数据 */ @@ -83,3 +84,21 @@ export const findDesignDataAsync = async (ids: string[]): Promise => { return slave.getService(FittingDesignService)!.deleteDesignDataAsync(ids); }; + +export const getTopModelsLiteInfoAsync = async (option: IGetTopModelsLiteInfoAsyncParameters) => { + return slave.getService(CustomModelService)!.getTopModelsLiteInfoAsync(option); +}; + +export const getCustomModelByModelIdAsync = async (id: string) => { + return slave.getService(CustomModelService)!.getCustomModelByModelIdAsync(id); +}; + +export const saveDesign = async () => { + return slave.getService(DesignService)!.save(); +}; + +export const getCustomModelAddedEvent = () => slave.getService(EventService)!.customModelAdded; +export const getCustomModelUpdateEvent = () => slave.getService(EventService)!.customModelUpdate; +export const getCustomModelDeleteEvent = () => slave.getService(EventService)!.customModelDelete; +export const getDesignSavedEvent = () => slave.getService(EventService)!.designSaved; +export const getOrderModelUpdateEvent = () => slave.getService(EventService)!.orderModelUpdate; \ No newline at end of file diff --git a/pages/appPage/src/views/App.tsx b/pages/appPage/src/views/App.tsx index 9461788..6d87cc3 100644 --- a/pages/appPage/src/views/App.tsx +++ b/pages/appPage/src/views/App.tsx @@ -2,10 +2,12 @@ import { Provider } from 'react-redux'; import { store } from '../store'; import './global.scss'; import Main from './main'; +import { CustomModelListener } from './listener'; function App() { return ( +
); diff --git a/pages/appPage/src/views/leftPanel/index.tsx b/pages/appPage/src/views/leftPanel/index.tsx index e380503..d7b1f4e 100644 --- a/pages/appPage/src/views/leftPanel/index.tsx +++ b/pages/appPage/src/views/leftPanel/index.tsx @@ -1,29 +1,28 @@ -import { ITopParamModelList, ModelService } from '@manycore/custom-sdk'; -import { useEffect, useState } from 'react'; +import { useEffect } from 'react'; import { getApplication } from '../../core/app'; import Spin from 'antd/es/spin'; import style from './index.module.scss'; import { Card } from '../../components/Card'; -import { connect } from 'react-redux'; +import { connect, useDispatch, useStore } from 'react-redux'; import { actionUpdateViewed } from '../../store/viewed/action'; import { actionSetSplitOrderData } from '../../store/splitOrderData/action'; import { initialState as splitInitState } from '../../store/splitOrderData/reducers'; import { actionUpdateSelected } from '../../store/selection/action'; import { initialState as selectionInitState } from '../../store/selection/reducers'; import { MiniAppSelectModelService } from '@manycore/custom-miniapp-sdk'; +import { actionInitModelListAsync } from '../../util/actionHelper'; interface IProps { + models?: { id: string; name: string }[]; + modelPicMap: Map; updateActiveModel: (id: string) => void; activeModelId?: string; } -const modelService = getApplication().getService(ModelService); const DEFAULT_LOADING_IMG = '//qhstaticssl.kujiale.com/image/png/1701690031959/A52587539A84579724C2E87B59176BD3.png'; function LeftPanel(props: IProps) { - const { activeModelId, updateActiveModel } = props; - const [models, setModels] = useState(); - const [modelPic, setModelPic] = useState>(new Map()); + const { activeModelId, updateActiveModel, models, modelPicMap } = props; useEffect(() => { const selectedService = @@ -35,55 +34,28 @@ function LeftPanel(props: IProps) { }); }, []); - useEffect(() => { - const getAllTopModelsList = async () => { - let num = 1; - const pageSize = 20; - let models: ITopParamModelList[] = []; - while (true) { - const { hasMore, result } = await modelService.getTopParamModels({ - pageNum: num, - pageSize, - }); - models.push(...result); - if (hasMore) { - num++; - } else { - break; - } - } - return models; - }; - - getAllTopModelsList().then((models) => { - setModels(models); + const dispatch = useDispatch(); + const store = useStore(); - models.forEach(async (m) => { - const [selectedModelImgData] = await modelService.getParamModelPhotoById(m.id); - setModelPic((prev) => { - const newModelPicMap = new Map(prev.entries()); - newModelPicMap.set(m.id, selectedModelImgData.imgData); - return newModelPicMap; - }); - }); - }); + useEffect(() => { + actionInitModelListAsync(dispatch, store.getState)(); }, []); - const handleViewModel = (model: ITopParamModelList) => { - updateActiveModel(model.id); + const handleViewModel = (id: string) => { + updateActiveModel(id); }; return models === undefined ? ( ) : (
- {models?.map((model) => ( + {models?.map(({ id, name }) => ( handleViewModel(model)} - active={model.id === activeModelId} - img={modelPic.get(model.id) || DEFAULT_LOADING_IMG} - title={model.name} + key={id} + onClick={() => handleViewModel(id)} + active={id === activeModelId} + img={modelPicMap.get(id) || DEFAULT_LOADING_IMG} + title={name} /> ))}
@@ -94,6 +66,8 @@ export default connect( (state) => { return { activeModelId: state.viewedModel.viewedModelId, + models: state.modelList.modelList, + modelPicMap: state.modelList.modelPicMap }; }, (dispatch, props) => { @@ -107,7 +81,7 @@ export default connect( viewedModelId: id, }) ); - }, + } }; } )(LeftPanel); diff --git a/pages/appPage/src/views/listener/index.module.scss b/pages/appPage/src/views/listener/index.module.scss new file mode 100644 index 0000000..452f605 --- /dev/null +++ b/pages/appPage/src/views/listener/index.module.scss @@ -0,0 +1,19 @@ +.maskContainer { + position: fixed; + left: 0; + right: 0; + top: 0; + bottom: 0; + z-index: 999; + background-color: rgba(0,0,0,0.7); + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + + color: #fff; + + > * { + margin-bottom: 20px; + } +} \ No newline at end of file diff --git a/pages/appPage/src/views/listener/index.tsx b/pages/appPage/src/views/listener/index.tsx new file mode 100644 index 0000000..79d4a72 --- /dev/null +++ b/pages/appPage/src/views/listener/index.tsx @@ -0,0 +1,101 @@ +import style from './index.module.scss'; +import Button from 'antd/es/button/button'; +import Message from 'antd/es/message'; +import { useEffect, useState } from 'react'; +import { getDesignSavedEvent, getOrderModelUpdateEvent, saveDesign } from '../../util'; +import { debounce } from 'lodash'; +import customModelRecorder from '../../util/customModelRecorder'; +import { useDispatch, useStore } from 'react-redux'; +import { actionInitModelListAsync, actionInitSplitDataAsync } from '../../util/actionHelper'; +import { getApplication } from '../../core/app'; +import { FittingViewerService, ModelViewerService } from '@manycore/custom-sdk'; +import { actionUpdateViewed } from '../../store/viewed/action'; + +export function CustomModelListener() { + const [changed, setChanged] = useState(false); + const [loading, setLoading] = useState(false); + const dispatch = useDispatch(); + const store = useStore(); + + useEffect(() => { + customModelRecorder.startRecord(); + customModelRecorder.onChange(() => { + setChanged(true); + }); + + const handleModelChanged = debounce(() => { + customModelRecorder.flush(async ({ + addedModels, deleteModels, updateModels + }) => { + if (addedModels.length === 0 && deleteModels.length === 0 && updateModels.length === 0) { + return; + } + try { + // 说明有模型变化,需要针对性清除孔槽、重新获取JSON等等可能会影响到拆单的操作 + setLoading(true); + const viewedModelId = store.getState().viewedModel.viewedModelId; + const app = getApplication(); + + // 刷新产品列表 + 缩略图 + await actionInitModelListAsync(dispatch, store.getState)([...addedModels, ...deleteModels, ...updateModels]); + if (addedModels.length) { + // 新增: 1、刷新产品列表 2、其他影响拆单数据刷新 + } + if (deleteModels.length) { + // 删除: 1、刷新产品列表 2、移除被删除模型的拆单数据 3、其他影响拆单数据刷新 + deleteModels.forEach(delId => { + // TODO: 清除这些被删除的拆单数据 + }); + + // 当前拆单展示的模型被删除,需要将当前展示对象设置成空 + if (viewedModelId && deleteModels.includes(viewedModelId)) { + dispatch(actionUpdateViewed({ viewedModelId: undefined })); + await app.getService(ModelViewerService).refreshModel(); + } + + } + if (updateModels.length) { + // 变化:1、清除变化模型的“缓存”数据(JSON、交界面) 2、重新获取JSON和交界面 3、其他影响拆单数据刷新 + updateModels.forEach(updateId => { + // TODO: 处理这些被更新的拆单数据 + }); + + // 当前拆单展示的模型更新,需要将当前展示数据进行还原刷新 + if (viewedModelId && updateModels.includes(viewedModelId)) { + // 清空临时孔槽、交界面数据 + await app.getService(FittingViewerService).clearFitting(); + await app.getService(FittingViewerService).clearHardware(); + // 刷新展示数据 + await app.getService(ModelViewerService).refreshModel(); + // 重新获取交界面、JSON等 + await actionInitSplitDataAsync(dispatch, store.getState)(viewedModelId); + } + } + const currentChanged = customModelRecorder.getChanged(); + if (currentChanged.addedModels.length === 0 && currentChanged.deleteModels.length === 0 && currentChanged.updateModels.length === 0) { + setChanged(false); + } + Message.success('刷新拆单数据成功'); + } catch (err) { + Message.error('刷新拆单数据失败'); + console.error(err); + } finally { + setLoading(false); + } + }); + }, 1000); + + getDesignSavedEvent().on(handleModelChanged); + getOrderModelUpdateEvent().on(handleModelChanged); + }, []); + + const refresh = () => { + setLoading(true); + saveDesign(); + } + + return changed ?
+ 模型数据发生变化,请保存方案或者点击下方按钮刷新拆单数据 + +
: null; +} diff --git a/pages/appPage/src/views/rightPanelV2/baseInfo/index.tsx b/pages/appPage/src/views/rightPanelV2/baseInfo/index.tsx index 44a2158..1c11608 100644 --- a/pages/appPage/src/views/rightPanelV2/baseInfo/index.tsx +++ b/pages/appPage/src/views/rightPanelV2/baseInfo/index.tsx @@ -1,22 +1,20 @@ -import { - FittingViewerService, - IGetModelIntersectedOption, - ModelService, -} from '@manycore/custom-sdk'; +import { FittingViewerService } from '@manycore/custom-sdk'; import Divider from 'antd/es/divider'; import { Fragment, PureComponent } from 'react'; +import type { Dispatch } from 'redux'; import { connect } from 'react-redux'; import { getApplication } from '../../../core/app'; import { store } from '../../../store'; import { actionSetSplitOrderData } from '../../../store/splitOrderData/action'; -import { findDesignDataAsync, getFittingDataFromAuxiliary, getModelJson } from '../../../util'; +import { findDesignDataAsync } from '../../../util'; import AuxiliaryInfo from './auxiliaryInfo'; import FittingDataWrap from './fittingDataWrap'; import IntersectInfo from './interscetedInfo'; import ModelBaseInfo from './modelBaseInfo'; import ModelSplitOrderInfo from './splitOrderInfo'; +import { actionInitSplitDataAsync } from '../../../util/actionHelper'; -export interface IBaseInfoState {} +export interface IBaseInfoState { } export interface IBaseInfoProps { viewModelId: string; @@ -31,41 +29,18 @@ export class BaseInfo extends PureComponent { private init = async (id: string) => { // 准备拆单数据 - const [jsonData, intersected, fittingFromAuxiliary, [fittingDataV2]] = await Promise.all([ - getModelJson(id), - this.getIntersected({ modelId: id }), - getFittingDataFromAuxiliary({ modelId: id }), - findDesignDataAsync([id]), - ]); - + const [fittingDataV2] = await findDesignDataAsync([id]); store.dispatch( actionSetSplitOrderData({ - intersectData: intersected, - jsonData: jsonData, - fittingFromAuxiliary: fittingFromAuxiliary, fittingDesignDataV2: fittingDataV2, }) ); - // 将fittingDesign渲染到场景中 fittingDataV2?.fittingDesign.forEach((fittingData) => { getApplication().getService(FittingViewerService).addFitting(fittingData); }); - }; - private getIntersected = async (option: IGetModelIntersectedOption) => { - const modelService = getApplication().getService(ModelService); - try { - const intersected = await modelService.getParamIntersected({ - ...option, - tolerance: option.tolerance ?? 0.1, - faceDistTol: option.faceDistTol ?? 0.1, - bodyDistTol: option.bodyDistTol ?? 0.1, - }); - return intersected!; - } catch (err) { - console.log('eder 加载交接数据失败', err); - } + actionInitSplitDataAsync(store.dispatch as Dispatch, store.getState)(id); }; render() { diff --git a/yarn.lock b/yarn.lock index 9404f65..6d6c808 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1242,7 +1242,7 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": version "7.14.6" resolved "https://registry.nlark.com/@babel/runtime/download/@babel/runtime-7.14.6.tgz#535203bc0892efc7dec60bdc27b2ecf6e409062d" integrity sha1-U1IDvAiS78fexgvcJ7Ls9uQJBi0= @@ -1256,6 +1256,13 @@ dependencies: regenerator-runtime "^0.14.0" +"@babel/runtime@^7.15.4": + version "7.25.7" + resolved "https://r.cnpmjs.org/@babel/runtime/-/runtime-7.25.7.tgz#7ffb53c37a8f247c8c4d335e89cdf16a2e0d0fb6" + integrity sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/template@^7.10.4", "@babel/template@^7.14.5", "@babel/template@^7.3.3": version "7.14.5" resolved "https://registry.nlark.com/@babel/template/download/@babel/template-7.14.5.tgz?cache=0&sync_timestamp=1623280386138&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Ftemplate%2Fdownload%2F%40babel%2Ftemplate-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4" @@ -1574,11 +1581,16 @@ resolved "https://r.cnpmjs.org/@manycore/custom-sdk/-/custom-sdk-3.1.6.tgz#2b7be2d8c743d974a76b999a9769fc4dd68da0f9" integrity sha512-DLwtOFm0e3UL/E5Yk9jWwSVipbzPvHPHB0nG/0wKzFfSkc5iT+ougv0dvKd0x7Nv+D5SmeS7y+0jWRLosCqzwQ== -"@manycore/idp-sdk@1.38.0", "@manycore/idp-sdk@^1.38.0": +"@manycore/idp-sdk@1.38.0": version "1.38.0" resolved "https://r.cnpmjs.org/@manycore/idp-sdk/-/idp-sdk-1.38.0.tgz#6ad441a2b8660dbf64dc2864404c8c895b861b2c" integrity sha512-A4AlwRlZIna/NxkSm8phSlH0N0TYND5yHLECk8mWHEGCLU7VPjRP9ba2l/GYQ6fm6WFfJ2SuaB5oS3OuzUVS5w== +"@manycore/idp-sdk@^1.53.0": + version "1.53.0" + resolved "https://r.cnpmjs.org/@manycore/idp-sdk/-/idp-sdk-1.53.0.tgz#ab03a1ee1220f561ae6c5953a6716ebd43344ad2" + integrity sha512-b9s+1s8y7F1AufiRbTPSgnbOnVanq5EVik4S5v/TnTD/1h7Ltw9U7QEIwzk84xEj0mfwWgYQRVYXpuryzxM4OQ== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.nlark.com/@nodelib/fs.scandir/download/@nodelib/fs.scandir-2.1.5.tgz?cache=0&sync_timestamp=1622792738877&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40nodelib%2Ffs.scandir%2Fdownload%2F%40nodelib%2Ffs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -1903,9 +1915,9 @@ "@types/node" "*" "@types/hoist-non-react-statics@^3.3.0": - version "3.3.1" - resolved "https://registry.nlark.com/@types/hoist-non-react-statics/download/@types/hoist-non-react-statics-3.3.1.tgz?cache=0&sync_timestamp=1621241339435&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fhoist-non-react-statics%2Fdownload%2F%40types%2Fhoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" - integrity sha1-ESSq/lEYy1kZd66xzqrtEHDrA58= + version "3.3.5" + resolved "https://r.cnpmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz#dab7867ef789d87e2b4b0003c9d65c49cc44a494" + integrity sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg== dependencies: "@types/react" "*" hoist-non-react-statics "^3.3.0" @@ -2004,10 +2016,10 @@ dependencies: "@types/react" "*" -"@types/react-redux@^7.1.16": - version "7.1.18" - resolved "https://registry.nlark.com/@types/react-redux/download/@types/react-redux-7.1.18.tgz#2bf8fd56ebaae679a90ebffe48ff73717c438e04" - integrity sha1-K/j9Vuuq5nmpDr/+SP9zcXxDjgQ= +"@types/react-redux@^7.1.20": + version "7.1.34" + resolved "https://r.cnpmjs.org/@types/react-redux/-/react-redux-7.1.34.tgz#83613e1957c481521e6776beeac4fd506d11bd0e" + integrity sha512-GdFaVjEbYv4Fthm2ZLvj1VSCedV7TqE5y1kNwnjSdBOTXuRSgowux6J8TAct15T3CKBr63UMk+2CO7ilRhyrAQ== dependencies: "@types/hoist-non-react-statics" "^3.3.0" "@types/react" "*" @@ -6307,8 +6319,8 @@ hmac-drbg@^1.0.1: hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: version "3.3.2" - resolved "https://registry.nlark.com/hoist-non-react-statics/download/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" - integrity sha1-7OCsr3HWLClpwuxZ/v9CpLGoW0U= + resolved "https://r2.cnpmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== dependencies: react-is "^16.7.0" @@ -8102,10 +8114,10 @@ merge2@^1.3.0: resolved "https://registry.npm.taobao.org/merge2/download/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha1-Q2iJL4hekHRVpv19xVwMnUBJkK4= -message-lite@0.0.1: - version "0.0.1" - resolved "https://r2.cnpmjs.org/message-lite/-/message-lite-0.0.1.tgz#c8235ffc005edc467299a4f57596add5fbb40fcd" - integrity sha512-QO2EY/qGWFaFI4szED2y1f5Gb86IksUQ9XcNKLoSsNeH4gp2v9IuNcxgDo/e8RgHtHPBqO2XEee9UnTP+aYnzg== +message-lite@0.10.5-alpha.2: + version "0.10.5-alpha.2" + resolved "https://r.cnpmjs.org/message-lite/-/message-lite-0.10.5-alpha.2.tgz#dd54d05e7d2229e5f805bef7248ac12411f6258b" + integrity sha512-1sb83h6yKlzt3tmX9bIzGJxM1is7OU2Tcnpje9o/OPcfmNYJasvERHK/mwL3gdwJpAS0/Pi8pYMsIZUXW/XmSg== methods@~1.1.2: version "1.1.2" @@ -10504,12 +10516,12 @@ react-error-overlay@^6.0.9: resolved "https://registry.nlark.com/react-error-overlay/download/react-error-overlay-6.0.9.tgz?cache=0&sync_timestamp=1618847933355&other_urls=https%3A%2F%2Fregistry.nlark.com%2Freact-error-overlay%2Fdownload%2Freact-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a" integrity sha1-PHQwEMk1lgjDdezWvHbzXZOZWwo= -react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.1: +react-is@^16.7.0, react-is@^16.8.1: version "16.13.1" resolved "https://registry.nlark.com/react-is/download/react-is-16.13.1.tgz?cache=0&sync_timestamp=1626193121951&other_urls=https%3A%2F%2Fregistry.nlark.com%2Freact-is%2Fdownload%2Freact-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha1-eJcppNw23imZ3BVt1sHZwYzqVqQ= -react-is@^17.0.1: +react-is@^17.0.1, react-is@^17.0.2: version "17.0.2" resolved "https://registry.nlark.com/react-is/download/react-is-17.0.2.tgz?cache=0&sync_timestamp=1626193121951&other_urls=https%3A%2F%2Fregistry.nlark.com%2Freact-is%2Fdownload%2Freact-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha1-5pHUqOnHiTZWVVOas3J2Kw77VPA= @@ -10520,16 +10532,16 @@ react-is@^18.2.0: integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== react-redux@^7.2.1: - version "7.2.4" - resolved "https://registry.nlark.com/react-redux/download/react-redux-7.2.4.tgz#1ebb474032b72d806de2e0519cd07761e222e225" - integrity sha1-HrtHQDK3LYBt4uBRnNB3YeIi4iU= + version "7.2.9" + resolved "https://r.cnpmjs.org/react-redux/-/react-redux-7.2.9.tgz#09488fbb9416a4efe3735b7235055442b042481d" + integrity sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ== dependencies: - "@babel/runtime" "^7.12.1" - "@types/react-redux" "^7.1.16" + "@babel/runtime" "^7.15.4" + "@types/react-redux" "^7.1.20" hoist-non-react-statics "^3.3.2" loose-envify "^1.4.0" prop-types "^15.7.2" - react-is "^16.13.1" + react-is "^17.0.2" react-refresh@^0.8.3: version "0.8.3" @@ -10635,9 +10647,9 @@ redent@^3.0.0: strip-indent "^3.0.0" redux@^4.0.0, redux@^4.0.5: - version "4.1.0" - resolved "https://registry.nlark.com/redux/download/redux-4.1.0.tgz?cache=0&sync_timestamp=1619286844146&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fredux%2Fdownload%2Fredux-4.1.0.tgz#eb049679f2f523c379f1aff345c8612f294c88d4" - integrity sha1-6wSWefL1I8N58a/zRchhLylMiNQ= + version "4.2.1" + resolved "https://r.cnpmjs.org/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197" + integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w== dependencies: "@babel/runtime" "^7.9.2" -- Gitee From d14ceff0634ca692caf58b66d2b29b05cd5377f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E9=85=92?= Date: Fri, 11 Oct 2024 15:26:36 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E6=9B=B4=E6=96=B0record=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/appPage/src/util/customModelRecorder.ts | 93 ++++++++++++++----- pages/appPage/src/views/listener/index.tsx | 33 ++++--- 2 files changed, 90 insertions(+), 36 deletions(-) diff --git a/pages/appPage/src/util/customModelRecorder.ts b/pages/appPage/src/util/customModelRecorder.ts index d7a47ed..4c9d339 100644 --- a/pages/appPage/src/util/customModelRecorder.ts +++ b/pages/appPage/src/util/customModelRecorder.ts @@ -1,13 +1,27 @@ import { getCustomModelAddedEvent, getCustomModelDeleteEvent, getCustomModelUpdateEvent } from "./vmapi"; import { EventEmitter } from 'eventemitter3'; -const addedModelIds = new Set(); -const deleteModelIds = new Set(); -const updateModelIds = new Set(); -const emitter = new EventEmitter(); +enum EChangedType { + Added = 'added', + Deleted = 'deleted', + Updated = 'updated' +} -let isStart: boolean = false; +type IChangedElements = Record; + +const emitter = new EventEmitter(); const changedEvent = Symbol('changed'); +const changedDocument = new Map(); +let isStart: boolean = false; + +function transactChange(id: string, type: EChangedType) { + const changeQueue = changedDocument.get(id); + if (changeQueue) { + changeQueue.push(type); + } else { + changedDocument.set(id, [type]); + } +} function startRecord() { if (isStart) { @@ -16,19 +30,19 @@ function startRecord() { isStart = true; const handleCustomModelAdded = (elementIds: IDP.DB.Types.ElementId[]) => { elementIds.forEach(({ id }) => { - addedModelIds.add(id); + transactChange(id, EChangedType.Added); }); emitter.emit(changedEvent); } const handleCustomModelUpdate = (elementIds: IDP.DB.Types.ElementId[]) => { elementIds.forEach(({ id }) => { - updateModelIds.add(id); + transactChange(id, EChangedType.Updated); }); emitter.emit(changedEvent); } const handleCustomModelDelete = (elementIds: IDP.DB.Types.ElementId[]) => { elementIds.forEach(({ id }) => { - deleteModelIds.add(id); + transactChange(id, EChangedType.Deleted); }); emitter.emit(changedEvent); } @@ -38,25 +52,60 @@ function startRecord() { }; -function flush(callback: (changed: { - addedModels: string[]; - deleteModels: string[]; - updateModels: string[]; -}) => void) { +function flush(callback: (changed: IChangedElements) => void) { const changed = getChanged(); - addedModelIds.clear(); - deleteModelIds.clear(); - updateModelIds.clear(); callback(changed); + changedDocument.clear(); } -function getChanged() { - // TODO: 简化 - return { - addedModels: [...addedModelIds], - deleteModels: [...deleteModelIds], - updateModels: [...updateModelIds] +function getChanged(): IChangedElements { + const changed: IChangedElements = { + added: [], + deleted: [], + updated: [] } + + changedDocument.forEach((changedQueue, id) => { + if (!changedQueue.length) { + return; + } + const length = changedQueue.length; + if (length === 1) { + changed[changedQueue[0]].push(id); + return; + } + const first = changedQueue[0]; + const last = changedQueue[length - 1]; + const middle = changedQueue.slice(1, -1); + if (first === EChangedType.Added) { + // 新增的模型最后仍然存在 + if (last !== EChangedType.Deleted) { + changed[EChangedType.Added].push(id); + } + return; + } + if (first === EChangedType.Updated) { + if (last === EChangedType.Deleted) { + changed[EChangedType.Deleted].push(id); + } else { + changed[EChangedType.Updated].push(id); + } + return; + } + if (first === EChangedType.Deleted) { + if (last === EChangedType.Deleted) { + changed[EChangedType.Deleted].push(id); + } else { + const isUpdated = [...middle, ...last].includes(EChangedType.Updated); + if (isUpdated) { + changed[EChangedType.Updated].push(id); + } + } + return; + } + }); + + return changed; } function onChange(func: () => void) { diff --git a/pages/appPage/src/views/listener/index.tsx b/pages/appPage/src/views/listener/index.tsx index 79d4a72..8f15910 100644 --- a/pages/appPage/src/views/listener/index.tsx +++ b/pages/appPage/src/views/listener/index.tsx @@ -23,11 +23,19 @@ export function CustomModelListener() { setChanged(true); }); + function checkRecordEmpty() { + const currentChanged = customModelRecorder.getChanged(); + if (currentChanged.added.length === 0 && currentChanged.deleted.length === 0 && currentChanged.updated.length === 0) { + setChanged(false); + } + } + const handleModelChanged = debounce(() => { customModelRecorder.flush(async ({ - addedModels, deleteModels, updateModels + added, deleted, updated }) => { - if (addedModels.length === 0 && deleteModels.length === 0 && updateModels.length === 0) { + if (added.length === 0 && deleted.length === 0 && updated.length === 0) { + checkRecordEmpty(); return; } try { @@ -37,31 +45,31 @@ export function CustomModelListener() { const app = getApplication(); // 刷新产品列表 + 缩略图 - await actionInitModelListAsync(dispatch, store.getState)([...addedModels, ...deleteModels, ...updateModels]); - if (addedModels.length) { + await actionInitModelListAsync(dispatch, store.getState)([...added, ...deleted, ...updated]); + if (added.length) { // 新增: 1、刷新产品列表 2、其他影响拆单数据刷新 } - if (deleteModels.length) { + if (deleted.length) { // 删除: 1、刷新产品列表 2、移除被删除模型的拆单数据 3、其他影响拆单数据刷新 - deleteModels.forEach(delId => { + deleted.forEach(delId => { // TODO: 清除这些被删除的拆单数据 }); // 当前拆单展示的模型被删除,需要将当前展示对象设置成空 - if (viewedModelId && deleteModels.includes(viewedModelId)) { + if (viewedModelId && deleted.includes(viewedModelId)) { dispatch(actionUpdateViewed({ viewedModelId: undefined })); await app.getService(ModelViewerService).refreshModel(); } } - if (updateModels.length) { + if (updated.length) { // 变化:1、清除变化模型的“缓存”数据(JSON、交界面) 2、重新获取JSON和交界面 3、其他影响拆单数据刷新 - updateModels.forEach(updateId => { + updated.forEach(updateId => { // TODO: 处理这些被更新的拆单数据 }); // 当前拆单展示的模型更新,需要将当前展示数据进行还原刷新 - if (viewedModelId && updateModels.includes(viewedModelId)) { + if (viewedModelId && updated.includes(viewedModelId)) { // 清空临时孔槽、交界面数据 await app.getService(FittingViewerService).clearFitting(); await app.getService(FittingViewerService).clearHardware(); @@ -71,10 +79,7 @@ export function CustomModelListener() { await actionInitSplitDataAsync(dispatch, store.getState)(viewedModelId); } } - const currentChanged = customModelRecorder.getChanged(); - if (currentChanged.addedModels.length === 0 && currentChanged.deleteModels.length === 0 && currentChanged.updateModels.length === 0) { - setChanged(false); - } + checkRecordEmpty(); Message.success('刷新拆单数据成功'); } catch (err) { Message.error('刷新拆单数据失败'); -- Gitee From eaed376e69f441bccfb520035f01283b949c8adc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E9=85=92?= Date: Tue, 14 Jan 2025 14:52:42 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=8B=86=E5=8D=95?= =?UTF-8?q?=E5=88=B7=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/vm/src/impl/design.service.impl.ts | 22 ++- .../src/views/header/index.module.scss | 14 ++ pages/appPage/src/views/header/index.tsx | 73 ++++++++- pages/appPage/src/views/leftPanel/index.tsx | 37 +++++ .../src/views/listener/index.module.scss | 19 --- pages/appPage/src/views/listener/index.tsx | 152 ++++++------------ pages/appPage/src/views/main/index.tsx | 26 --- 7 files changed, 195 insertions(+), 148 deletions(-) create mode 100644 pages/appPage/src/views/header/index.module.scss delete mode 100644 pages/appPage/src/views/listener/index.module.scss diff --git a/packages/vm/src/impl/design.service.impl.ts b/packages/vm/src/impl/design.service.impl.ts index c11bf90..b161f95 100644 --- a/packages/vm/src/impl/design.service.impl.ts +++ b/packages/vm/src/impl/design.service.impl.ts @@ -3,7 +3,25 @@ import { DesignService } from '@manycore/pages-vm-api'; @ApiImpl() export class DesignServiceImpl extends DesignService { - save() { - return IDP.Design.save(); + async save() { + const orderId = IDP.Integration.FOP.OrderMode.getOrderId(); + // FOP订单模式下 + if (!!orderId) { + const isEditable = IDP.Integration.FOP.OrderMode.getEditable(); + // 具备可编辑的权限 + if (isEditable) { + await Promise.all([ + // 方案保存 + IDP.Design.save(), + // 订单模型范围变更 + new Promise((res, rej) => { + IDP.Events.once('IDP.Integration.FOP.OrderMode.OrderModel.Update', res) + }) + ]) + await IDP.Design.save(); + return; + } + } + await IDP.Design.save(); } } diff --git a/pages/appPage/src/views/header/index.module.scss b/pages/appPage/src/views/header/index.module.scss new file mode 100644 index 0000000..a19f2de --- /dev/null +++ b/pages/appPage/src/views/header/index.module.scss @@ -0,0 +1,14 @@ +.headerContainer { + position: relative; + + .headerButtonGroup { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + + :not(:first-child) { + margin-left: 10px; + } + } +} \ No newline at end of file diff --git a/pages/appPage/src/views/header/index.tsx b/pages/appPage/src/views/header/index.tsx index f2b815a..a04b911 100644 --- a/pages/appPage/src/views/header/index.tsx +++ b/pages/appPage/src/views/header/index.tsx @@ -1,3 +1,74 @@ +import Button from "antd/es/button"; +import { useEffect, useState } from "react"; +import { useDispatch, useStore } from "react-redux"; +import { getApplication } from "../../core/app"; +import { DetectionService, ModelViewerService } from "@manycore/custom-sdk"; +import message from "antd/es/message"; +import style from './index.module.scss'; +import { saveDesign } from "../../util"; +import { actionInitSplitDataAsync } from "../../util/actionHelper"; + +const DEFAULT_PASS_STATE = false; export function Header() { - return
小程序演示
; + const dispatch = useDispatch(); + const store = useStore(); + + const [isPass, setIsPass] = useState(DEFAULT_PASS_STATE); + const [loading, setLoading] = useState(false) + const viewModelById = store.getState().viewedModel.viewedModelId; + + useEffect(() => { + setIsPass(DEFAULT_PASS_STATE); + }, [viewModelById]) + + /** 开启检测相关 */ + useEffect(() => { + const detectionService = getApplication().getService(DetectionService); + // 设置检测面板 + detectionService.setDetectionUI({ + message: '模型数据更新提示', + description: '设计方案中的模型数据已更新,建议完成模型数据更新后继续操作', + defaultPosition: { + x: window.innerWidth - 372, + y: 12 + } + }); + // 开启检测 + detectionService.enableDetection(); + // 监听检测结果 + detectionService.onAfterDetect((detectResult) => { + const { productId, result } = detectResult; + if (productId === store.getState().viewedModel.viewedModelId) { + setIsPass(result); + } + }); + }, []); + + const handleRefresh = async () => { + try { + if (!viewModelById) { + return; + } + setLoading(true); + await saveDesign(); + const app = getApplication(); + // 刷新展示数据 + await app.getService(ModelViewerService).refreshModel(); + // 重新获取交界面、JSON等 + await actionInitSplitDataAsync(dispatch, store.getState)(viewModelById); + message.success('刷新成功'); + } catch (err) { + message.error('刷新失败'); + } finally { + setLoading(false); + } + } + + return
+ 小程序演示 + {viewModelById && + + + } +
; } diff --git a/pages/appPage/src/views/leftPanel/index.tsx b/pages/appPage/src/views/leftPanel/index.tsx index d7b1f4e..74cdd8c 100644 --- a/pages/appPage/src/views/leftPanel/index.tsx +++ b/pages/appPage/src/views/leftPanel/index.tsx @@ -11,6 +11,10 @@ import { actionUpdateSelected } from '../../store/selection/action'; import { initialState as selectionInitState } from '../../store/selection/reducers'; import { MiniAppSelectModelService } from '@manycore/custom-miniapp-sdk'; import { actionInitModelListAsync } from '../../util/actionHelper'; +import customModelRecorder from '../../util/customModelRecorder'; +import { getDesignSavedEvent, getOrderModelUpdateEvent } from '../../util'; +import { debounce } from 'lodash'; +import { ModelViewerService } from '@manycore/custom-sdk'; interface IProps { models?: { id: string; name: string }[]; @@ -41,6 +45,39 @@ function LeftPanel(props: IProps) { actionInitModelListAsync(dispatch, store.getState)(); }, []); + + useEffect(() => { + // 保存自动刷新左侧列表 + const handleModelChanged = debounce(() => { + customModelRecorder.flush(async ({ + added, deleted, updated + }) => { + if (added.length === 0 && deleted.length === 0 && updated.length === 0) { + return; + } + try { + // 刷新产品列表 + 缩略图 + await actionInitModelListAsync(dispatch, store.getState)([...added, ...deleted, ...updated]); + + if (deleted.length) { + // 当前拆单展示的模型被删除,需要将当前展示对象设置成空 + const viewedModelId = store.getState().viewedModel.viewedModelId; + if (viewedModelId && deleted.includes(viewedModelId)) { + dispatch(actionUpdateViewed({ viewedModelId: undefined })); + const app = getApplication(); + await app.getService(ModelViewerService).refreshModel(); + } + } + } catch (err) { + } finally { + } + }); + }, 1000); + customModelRecorder.startRecord(); + getDesignSavedEvent().on(handleModelChanged); + getOrderModelUpdateEvent().on(handleModelChanged); + }, []) + const handleViewModel = (id: string) => { updateActiveModel(id); }; diff --git a/pages/appPage/src/views/listener/index.module.scss b/pages/appPage/src/views/listener/index.module.scss deleted file mode 100644 index 452f605..0000000 --- a/pages/appPage/src/views/listener/index.module.scss +++ /dev/null @@ -1,19 +0,0 @@ -.maskContainer { - position: fixed; - left: 0; - right: 0; - top: 0; - bottom: 0; - z-index: 999; - background-color: rgba(0,0,0,0.7); - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; - - color: #fff; - - > * { - margin-bottom: 20px; - } -} \ No newline at end of file diff --git a/pages/appPage/src/views/listener/index.tsx b/pages/appPage/src/views/listener/index.tsx index ae0691f..9aa8366 100644 --- a/pages/appPage/src/views/listener/index.tsx +++ b/pages/appPage/src/views/listener/index.tsx @@ -2,7 +2,7 @@ import style from './index.module.scss'; import Button from 'antd/es/button/button'; import Message from 'antd/es/message'; import { useEffect, useState } from 'react'; -import { getDesignSavedEvent, getOrderModelUpdateEvent, saveDesign } from '../../util'; +import { getCustomModelAddedEvent, getCustomModelDeleteEvent, getCustomModelUpdateEvent, getDesignSavedEvent, getOrderModelUpdateEvent, saveDesign } from '../../util'; import { debounce } from 'lodash'; import customModelRecorder from '../../util/customModelRecorder'; import { useDispatch, useStore } from 'react-redux'; @@ -11,100 +11,6 @@ import { getApplication } from '../../core/app'; import { FittingViewerService, ModelViewerService } from '@manycore/custom-sdk'; import { actionUpdateViewed } from '../../store/viewed/action'; -export function CustomModelListener() { - const [changed, setChanged] = useState(false); - const [loading, setLoading] = useState(false); - const dispatch = useDispatch(); - const store = useStore(); - - useEffect(() => { - customModelRecorder.startRecord(); - customModelRecorder.onChange(() => { - setChanged(true); - }); - - function checkRecordEmpty() { - const currentChanged = customModelRecorder.getChanged(); - if (currentChanged.added.length === 0 && currentChanged.deleted.length === 0 && currentChanged.updated.length === 0) { - setChanged(false); - } - } - - const handleModelChanged = debounce(() => { - customModelRecorder.flush(async ({ - added, deleted, updated - }) => { - if (added.length === 0 && deleted.length === 0 && updated.length === 0) { - checkRecordEmpty(); - return; - } - try { - // 说明有模型变化,需要针对性清除孔槽、重新获取JSON等等可能会影响到拆单的操作 - setLoading(true); - const viewedModelId = store.getState().viewedModel.viewedModelId; - const app = getApplication(); - - // 刷新产品列表 + 缩略图 - await actionInitModelListAsync(dispatch, store.getState)([...added, ...deleted, ...updated]); - if (added.length) { - // 新增: 1、刷新产品列表 2、其他影响拆单数据刷新 - } - if (deleted.length) { - // 删除: 1、刷新产品列表 2、移除被删除模型的拆单数据 3、其他影响拆单数据刷新 - deleted.forEach(delId => { - // TODO: 清除这些被删除的拆单数据 - }); - - // 当前拆单展示的模型被删除,需要将当前展示对象设置成空 - if (viewedModelId && deleted.includes(viewedModelId)) { - dispatch(actionUpdateViewed({ viewedModelId: undefined })); - await app.getService(ModelViewerService).refreshModel(); - } - - } - if (updated.length) { - // 变化:1、清除变化模型的“缓存”数据(JSON、交界面) 2、重新获取JSON和交界面 3、其他影响拆单数据刷新 - updated.forEach(updateId => { - // TODO: 处理这些被更新的拆单数据 - }); - - // 当前拆单展示的模型更新,需要将当前展示数据进行还原刷新 - if (viewedModelId && updated.includes(viewedModelId)) { - // 清空临时孔槽、交界面数据 - await app.getService(FittingViewerService).clearFitting(); - await app.getService(FittingViewerService).clearHardware(); - // 刷新展示数据 - await app.getService(ModelViewerService).refreshModel(); - // 重新获取交界面、JSON等 - await actionInitSplitDataAsync(dispatch, store.getState)(viewedModelId); - } - } - checkRecordEmpty(); - Message.success('刷新拆单数据成功'); - } catch (err) { - Message.error('刷新拆单数据失败'); - console.error(err); - } finally { - setLoading(false); - } - }); - }, 1000); - - getDesignSavedEvent().on(handleModelChanged); - getOrderModelUpdateEvent().on(handleModelChanged); - }, []); - - const refresh = () => { - setLoading(true); - saveDesign(); - } - - return changed ?
- 模型数据发生变化,请保存方案或者点击下方按钮刷新拆单数据 - -
: null; -} - // export function CustomModelListener() { // const [changed, setChanged] = useState(false); // const [loading, setLoading] = useState(false); @@ -112,9 +18,17 @@ export function CustomModelListener() { // const store = useStore(); // useEffect(() => { -// getCustomModelAddedEvent().on(handleCustomModelAdded); -// getCustomModelUpdateEvent().on(handleCustomModelUpdate); -// getCustomModelDeleteEvent().on(handleCustomModelDelete); +// customModelRecorder.startRecord(); +// customModelRecorder.onChange(() => { +// setChanged(true); +// }); + +// function checkRecordEmpty() { +// const currentChanged = customModelRecorder.getChanged(); +// if (currentChanged.added.length === 0 && currentChanged.deleted.length === 0 && currentChanged.updated.length === 0) { +// setChanged(false); +// } +// } // const handleModelChanged = debounce(() => { // customModelRecorder.flush(async ({ @@ -180,5 +94,43 @@ export function CustomModelListener() { // getOrderModelUpdateEvent().on(handleModelChanged); // }, []); -// return null; -// } \ No newline at end of file +// const refresh = () => { +// setLoading(true); +// saveDesign(); +// } + +// return changed ?
+// 模型数据发生变化,请保存方案或者点击下方按钮刷新拆单数据 +// +//
: null; +// } + +export function CustomModelListener() { + const [changed, setChanged] = useState(false); + const [loading, setLoading] = useState(false); + const dispatch = useDispatch(); + const store = useStore(); + + useEffect(() => { + // const handleModelChanged = debounce(() => { + // customModelRecorder.flush(async ({ + // added, deleted, updated + // }) => { + // if (added.length === 0 && deleted.length === 0 && updated.length === 0) { + // return; + // } + // try { + // // 刷新产品列表 + 缩略图 + // await actionInitModelListAsync(dispatch, store.getState)([...added, ...deleted, ...updated]); + // } catch (err) { + // } finally { + // } + // }); + // }, 1000); + // customModelRecorder.startRecord(); + // getDesignSavedEvent().on(handleModelChanged); + // getOrderModelUpdateEvent().on(handleModelChanged); + }, []); + + return null; +} \ No newline at end of file diff --git a/pages/appPage/src/views/main/index.tsx b/pages/appPage/src/views/main/index.tsx index 33276b8..32c5421 100644 --- a/pages/appPage/src/views/main/index.tsx +++ b/pages/appPage/src/views/main/index.tsx @@ -1,5 +1,4 @@ import { - DetectionService, ECameraMoveDirection, EElementType, FittingDesignService, @@ -10,7 +9,6 @@ import { ModelViewerSelectionV2Service, ModelViewerService, } from '@manycore/custom-sdk'; -import message from 'antd/es/message'; import { castArray } from 'lodash'; import { useCallback, useEffect } from 'react'; import { connect } from 'react-redux'; @@ -108,30 +106,6 @@ export function Main(props: IMainProps) { }); }, []); - /** 开启检测相关 */ - useEffect(() => { - const detectionService = getApplication().getService(DetectionService); - // 设置检测面板 - detectionService.setDetectionUI({ - message: '模型数据更新提示', - description: '设计方案中的模型数据已更新,建议完成模型数据更新后继续操作', - defaultPosition: { - x: window.innerWidth - 372, - y: 12 - } - }); - // 开启检测 - detectionService.enableDetection(); - // 监听检测结果 - detectionService.onAfterDetect((detectResult) => { - const { productId, result } = detectResult; - const tips = result - ? `产品:${productId}检测通过` - : `产品:${productId}检测未通过,请检查是否保存方案/获取最新产品数据`; - message.info(tips); - }); - }, []); - return ( Date: Wed, 15 Jan 2025 16:37:07 +0800 Subject: [PATCH 4/4] add tip --- pages/appPage/src/views/header/index.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pages/appPage/src/views/header/index.tsx b/pages/appPage/src/views/header/index.tsx index a04b911..3b40d72 100644 --- a/pages/appPage/src/views/header/index.tsx +++ b/pages/appPage/src/views/header/index.tsx @@ -38,6 +38,10 @@ export function Header() { // 监听检测结果 detectionService.onAfterDetect((detectResult) => { const { productId, result } = detectResult; + const tips = result + ? `产品:${productId}检测通过` + : `产品:${productId}检测未通过,请检查是否保存方案/获取最新产品数据`; + message.info(tips); if (productId === store.getState().viewedModel.viewedModelId) { setIsPass(result); } -- Gitee