subscribe支持注册相同的Event,增加moduleName

This commit is contained in:
Xu Chang 2024-05-17 19:40:13 +08:00
parent 85e3696e99
commit 34c77d6d68
23 changed files with 152 additions and 79 deletions

View File

@ -21,5 +21,6 @@ declare const _default: <ED2 extends ED, T2 extends keyof ED2>(props: ReactCompo
scrollToFirstRowOnChange?: boolean | undefined;
}) | undefined;
locale?: import("antd/es/table/interface").TableLocale | undefined;
opWidth?: number | undefined;
}>) => React.ReactElement;
export default _default;

View File

@ -17,6 +17,7 @@ export default OakComponent({
size: 'large',
scroll: undefined,
locale: undefined,
opWidth: undefined,
},
formData({ props }) {
const { converter } = this.state;

View File

@ -9,7 +9,7 @@ import { TableContext } from '../listPro';
export default function Render(props) {
const { methods, data: oakData } = props;
const { t, getColor } = methods;
const { loading, entity, schema, extraActions, data, disabledOp = false, tablePagination, onAction, rowSelection, attributes, i18n, hideHeader, disableSerialNumber, judgeAttributes, size = 'large', scroll, locale,opWidth } = oakData;
const { loading, entity, schema, extraActions, data, disabledOp = false, tablePagination, onAction, rowSelection, attributes, i18n, hideHeader, disableSerialNumber, judgeAttributes, size = 'large', scroll, locale, opWidth, } = oakData;
const [tableColumns, setTableColumns] = useState([]);
const { tableAttributes, setSchema } = useContext(TableContext);
// 为了i18更新时能够重新渲染

View File

@ -14,7 +14,7 @@ export const TableContext = createContext({
onReset: undefined,
});
const ProList = (props) => {
const { buttonGroup, entity, extraActions, onAction, disabledOp, attributes, data, loading, tablePagination, rowSelection, onReload, disableSerialNumber, title, hideDefaultButtons = false, extraContent, size = 'large', scroll, locale,opWidth } = props;
const { buttonGroup, entity, extraActions, onAction, disabledOp, attributes, data, loading, tablePagination, rowSelection, onReload, disableSerialNumber, title, hideDefaultButtons = false, extraContent, size = 'large', scroll, locale, opWidth, } = props;
const [tableAttributes, setTableAttributes] = useState([]);
const [schema, setSchema] = useState(undefined);
const width = useWidth();
@ -45,7 +45,7 @@ const ProList = (props) => {
<div className={Style.container}>
{!isMobile && !hideDefaultButtons && (<ToolBar title={title} extraContent={extraContent} buttonGroup={buttonGroup} reload={onReload}/>)}
{isMobile && <ButtonGroup items={buttonGroup}/>}
<List entity={entity} extraActions={extraActions} onAction={onAction} disabledOp={disabledOp} attributes={attributes} scroll={scroll} locale={locale} data={data} loading={loading} size={size} tablePagination={tablePagination} rowSelection={rowSelection} disableSerialNumber={disableSerialNumber} opWidth={opWidth} />
<List entity={entity} extraActions={extraActions} onAction={onAction} disabledOp={disabledOp} attributes={attributes} scroll={scroll} locale={locale} data={data} loading={loading} size={size} tablePagination={tablePagination} rowSelection={rowSelection} disableSerialNumber={disableSerialNumber} opWidth={opWidth}/>
</div>
</TableContext.Provider>);
};

View File

@ -17,7 +17,7 @@ export declare class Locales<ED extends EntityDict & BaseEntityDict> extends Fea
constructor(cache: Cache<ED>, localStorage: LocalStorage, environment: Environment, defaultLng: string);
private detectLanguange;
private reloadDataset;
loadServerData;
loadServerData(nss: string[]): Promise<void>;
/**
* key缺失时i18n数据i18n缓存数据的行为优化放在cache中统一进行
* @param ns

View File

@ -4,6 +4,7 @@ import { Cache } from './cache';
import { Message } from './message';
import { Feature } from '../types/Feature';
type SubscribeEvent = 'connect' | 'disconnect';
type Callback<ED extends EntityDict & BaseEntityDict> = (event: string, records: OpRecord<ED>[]) => void;
export declare class SubScriber<ED extends EntityDict & BaseEntityDict> extends Feature {
private cache;
private message;
@ -23,8 +24,8 @@ export declare class SubScriber<ED extends EntityDict & BaseEntityDict> extends
private emit;
private initSocketPoint;
private connect;
sub(events: string[], callback?: (event: string, opRecords: OpRecord<ED>[]) => void): Promise<void>;
unsub(events: string[]): Promise<void>;
sub(events: string[], moduleName: string, callback?: Callback<ED>): Promise<void>;
unsub(events: string[], moduleName: string): Promise<void>;
getSubscriberId(): string | undefined;
}
export {};

View File

@ -72,9 +72,11 @@ export class SubScriber extends Feature {
}
});
socket.on('data', (opRecords, event) => {
const callback = this.eventMap[event];
if (callback) {
callback(event, opRecords);
const registered = this.eventMap[event];
if (registered) {
for (const moduleName in registered) {
registered[moduleName] && registered[moduleName](event, opRecords);
}
}
this.cache.sync(opRecords);
});
@ -112,17 +114,28 @@ export class SubScriber extends Feature {
socket.connect();
});
}
async sub(events, callback) {
async sub(events, moduleName, callback) {
const newEvents = [];
events.forEach((event) => {
assert(!this.eventMap.hasOwnProperty(event), `[subscriber]注册回调的id${event}发生重复`);
this.eventMap[event] = callback;
const registered = this.eventMap[event];
if (registered) {
assert(!registered.hasOwnProperty(moduleName), `[subscriber]注册回调的事件${event}和moduleName${moduleName}发生重复`);
registered[moduleName] = callback;
}
else {
this.eventMap[event] = {
[moduleName]: callback,
};
newEvents.push(event);
}
;
});
if (this.socketState === 'unconnected') {
return this.connect();
}
else if (this.socketState === 'connected') {
else if (this.socketState === 'connected' && newEvents.length > 0) {
return new Promise((resolve, reject) => {
this.socket.emit('sub', events, (result) => {
this.socket.emit('sub', newEvents, (result) => {
if (result) {
this.message.setMessage({
type: 'error',
@ -138,8 +151,17 @@ export class SubScriber extends Feature {
});
}
}
async unsub(events) {
events.forEach((event) => unset(this.eventMap, event));
async unsub(events, moduleName) {
const emptyEvents = [];
events.forEach((event) => {
const registered = this.eventMap[event];
assert(registered.hasOwnProperty(moduleName));
unset(registered, moduleName);
if (Object.keys(registered).length === 0) {
emptyEvents.push(event);
}
});
emptyEvents.forEach(event => unset(this.eventMap, event));
if (this.socketState === 'connected') {
this.socket.emit('unsub', events);
if (Object.keys(this.eventMap).length === 0) {

View File

@ -472,11 +472,11 @@ const oakBehavior = Behavior({
loadMissedLocales(key) {
this.features.locales.loadMissedLocale(key);
},
subDataEvents(events, callback) {
return this.features.subscriber.sub(events, callback);
subDataEvents(events, moduleName, callback) {
return this.features.subscriber.sub(events, moduleName, callback);
},
unsubDataEvents(events) {
return this.features.subscriber.unsub(events);
unsubDataEvents(events, moduleName) {
return this.features.subscriber.unsub(events, moduleName);
},
},
observers: {

4
es/page.react.d.ts vendored
View File

@ -99,8 +99,8 @@ export declare function createComponent<IsList extends boolean, ED extends Entit
getPagination(path?: string | undefined): import(".").Pagination | undefined;
setPageSize(pageSize: number, path?: string | undefined): void;
setCurrentPage(currentPage: number, path?: string | undefined): void;
subDataEvents(events: string[], callback: (event: string, opRecords: OpRecord<ED>[]) => void): Promise<void>;
unsubDataEvents(events: string[]): Promise<void>;
subDataEvents(events: string[], moduleName: string, callback: (event: string, opRecords: OpRecord<ED>[]) => void): Promise<void>;
unsubDataEvents(events: string[], moduleName: string): Promise<void>;
context: unknown;
setState<K extends keyof TData | keyof FormedData | keyof import("./types/Page").OakComponentData<ED, T>>(state: ComponentData<ED, T, FormedData, TData> | ((prevState: Readonly<ComponentData<ED, T, FormedData, TData>>, props: Readonly<ComponentProps<ED, T, TProperty>>) => ComponentData<ED, T, FormedData, TData> | Pick<ComponentData<ED, T, FormedData, TData>, K> | null) | Pick<ComponentData<ED, T, FormedData, TData>, K> | null, callback?: (() => void) | undefined): void;
forceUpdate(callback?: (() => void) | undefined): void;

View File

@ -371,11 +371,11 @@ class OakComponentBase extends React.PureComponent {
this.features.runningTree.setCurrentPage(path2, currentPage);
}
}
subDataEvents(events, callback) {
return this.features.subscriber.sub(events, callback);
subDataEvents(events, moduleName, callback) {
return this.features.subscriber.sub(events, moduleName, callback);
}
unsubDataEvents(events) {
return this.features.subscriber.unsub(events);
unsubDataEvents(events, moduleName) {
return this.features.subscriber.unsub(events, moduleName);
}
}
function translateListeners(listeners) {

4
es/types/Page.d.ts vendored
View File

@ -175,8 +175,8 @@ export type OakCommonComponentMethods<ED extends EntityDict & BaseEntityDict, T
}[] | undefined;
refresh: () => Promise<void>;
aggregate: (aggregation: ED[T]['Aggregation']) => Promise<AggregationResult<ED[T]['Schema']>>;
subDataEvents: (events: string[], callback?: (event: string, opRecords: OpRecord<ED>[]) => void) => Promise<void>;
unsubDataEvents: (events: string[]) => Promise<void>;
subDataEvents: (events: string[], moduleName: string, callback?: (event: string, opRecords: OpRecord<ED>[]) => void) => Promise<void>;
unsubDataEvents: (events: string[], moduleName: string) => Promise<void>;
};
export type OakSingleComponentMethods<ED extends EntityDict & BaseEntityDict, T extends keyof ED> = {
setId: (id: string) => void;

View File

@ -17,7 +17,7 @@ export declare class Locales<ED extends EntityDict & BaseEntityDict> extends Fea
constructor(cache: Cache<ED>, localStorage: LocalStorage, environment: Environment, defaultLng: string);
private detectLanguange;
private reloadDataset;
private loadServerData;
loadServerData(nss: string[]): Promise<void>;
/**
* key缺失时i18n数据i18n缓存数据的行为优化放在cache中统一进行
* @param ns

View File

@ -4,6 +4,7 @@ import { Cache } from './cache';
import { Message } from './message';
import { Feature } from '../types/Feature';
type SubscribeEvent = 'connect' | 'disconnect';
type Callback<ED extends EntityDict & BaseEntityDict> = (event: string, records: OpRecord<ED>[]) => void;
export declare class SubScriber<ED extends EntityDict & BaseEntityDict> extends Feature {
private cache;
private message;
@ -23,8 +24,8 @@ export declare class SubScriber<ED extends EntityDict & BaseEntityDict> extends
private emit;
private initSocketPoint;
private connect;
sub(events: string[], callback?: (event: string, opRecords: OpRecord<ED>[]) => void): Promise<void>;
unsub(events: string[]): Promise<void>;
sub(events: string[], moduleName: string, callback?: Callback<ED>): Promise<void>;
unsub(events: string[], moduleName: string): Promise<void>;
getSubscriberId(): string | undefined;
}
export {};

View File

@ -76,9 +76,11 @@ class SubScriber extends Feature_1.Feature {
}
});
socket.on('data', (opRecords, event) => {
const callback = this.eventMap[event];
if (callback) {
callback(event, opRecords);
const registered = this.eventMap[event];
if (registered) {
for (const moduleName in registered) {
registered[moduleName] && registered[moduleName](event, opRecords);
}
}
this.cache.sync(opRecords);
});
@ -116,17 +118,28 @@ class SubScriber extends Feature_1.Feature {
socket.connect();
});
}
async sub(events, callback) {
async sub(events, moduleName, callback) {
const newEvents = [];
events.forEach((event) => {
(0, assert_1.assert)(!this.eventMap.hasOwnProperty(event), `[subscriber]注册回调的id${event}发生重复`);
this.eventMap[event] = callback;
const registered = this.eventMap[event];
if (registered) {
(0, assert_1.assert)(!registered.hasOwnProperty(moduleName), `[subscriber]注册回调的事件${event}和moduleName${moduleName}发生重复`);
registered[moduleName] = callback;
}
else {
this.eventMap[event] = {
[moduleName]: callback,
};
newEvents.push(event);
}
;
});
if (this.socketState === 'unconnected') {
return this.connect();
}
else if (this.socketState === 'connected') {
else if (this.socketState === 'connected' && newEvents.length > 0) {
return new Promise((resolve, reject) => {
this.socket.emit('sub', events, (result) => {
this.socket.emit('sub', newEvents, (result) => {
if (result) {
this.message.setMessage({
type: 'error',
@ -142,8 +155,17 @@ class SubScriber extends Feature_1.Feature {
});
}
}
async unsub(events) {
events.forEach((event) => (0, lodash_1.unset)(this.eventMap, event));
async unsub(events, moduleName) {
const emptyEvents = [];
events.forEach((event) => {
const registered = this.eventMap[event];
(0, assert_1.assert)(registered.hasOwnProperty(moduleName));
(0, lodash_1.unset)(registered, moduleName);
if (Object.keys(registered).length === 0) {
emptyEvents.push(event);
}
});
emptyEvents.forEach(event => (0, lodash_1.unset)(this.eventMap, event));
if (this.socketState === 'connected') {
this.socket.emit('unsub', events);
if (Object.keys(this.eventMap).length === 0) {

View File

@ -475,11 +475,11 @@ const oakBehavior = Behavior({
loadMissedLocales(key) {
this.features.locales.loadMissedLocale(key);
},
subDataEvents(events, callback) {
return this.features.subscriber.sub(events, callback);
subDataEvents(events, moduleName, callback) {
return this.features.subscriber.sub(events, moduleName, callback);
},
unsubDataEvents(events) {
return this.features.subscriber.unsub(events);
unsubDataEvents(events, moduleName) {
return this.features.subscriber.unsub(events, moduleName);
},
},
observers: {

4
lib/page.react.d.ts vendored
View File

@ -99,8 +99,8 @@ export declare function createComponent<IsList extends boolean, ED extends Entit
getPagination(path?: string | undefined): import(".").Pagination | undefined;
setPageSize(pageSize: number, path?: string | undefined): void;
setCurrentPage(currentPage: number, path?: string | undefined): void;
subDataEvents(events: string[], callback: (event: string, opRecords: OpRecord<ED>[]) => void): Promise<void>;
unsubDataEvents(events: string[]): Promise<void>;
subDataEvents(events: string[], moduleName: string, callback: (event: string, opRecords: OpRecord<ED>[]) => void): Promise<void>;
unsubDataEvents(events: string[], moduleName: string): Promise<void>;
context: unknown;
setState<K extends keyof TData | keyof FormedData | keyof import("./types/Page").OakComponentData<ED, T>>(state: ComponentData<ED, T, FormedData, TData> | ((prevState: Readonly<ComponentData<ED, T, FormedData, TData>>, props: Readonly<ComponentProps<ED, T, TProperty>>) => ComponentData<ED, T, FormedData, TData> | Pick<ComponentData<ED, T, FormedData, TData>, K> | null) | Pick<ComponentData<ED, T, FormedData, TData>, K> | null, callback?: (() => void) | undefined): void;
forceUpdate(callback?: (() => void) | undefined): void;

View File

@ -376,11 +376,11 @@ class OakComponentBase extends react_1.default.PureComponent {
this.features.runningTree.setCurrentPage(path2, currentPage);
}
}
subDataEvents(events, callback) {
return this.features.subscriber.sub(events, callback);
subDataEvents(events, moduleName, callback) {
return this.features.subscriber.sub(events, moduleName, callback);
}
unsubDataEvents(events) {
return this.features.subscriber.unsub(events);
unsubDataEvents(events, moduleName) {
return this.features.subscriber.unsub(events, moduleName);
}
}
function translateListeners(listeners) {

4
lib/types/Page.d.ts vendored
View File

@ -175,8 +175,8 @@ export type OakCommonComponentMethods<ED extends EntityDict & BaseEntityDict, T
}[] | undefined;
refresh: () => Promise<void>;
aggregate: (aggregation: ED[T]['Aggregation']) => Promise<AggregationResult<ED[T]['Schema']>>;
subDataEvents: (events: string[], callback?: (event: string, opRecords: OpRecord<ED>[]) => void) => Promise<void>;
unsubDataEvents: (events: string[]) => Promise<void>;
subDataEvents: (events: string[], moduleName: string, callback?: (event: string, opRecords: OpRecord<ED>[]) => void) => Promise<void>;
unsubDataEvents: (events: string[], moduleName: string) => Promise<void>;
};
export type OakSingleComponentMethods<ED extends EntityDict & BaseEntityDict, T extends keyof ED> = {
setId: (id: string) => void;

View File

@ -121,6 +121,7 @@ export default OakComponent({
size?: 'large' | 'middle' | 'small';
scroll?: TableProps<RowWithActions<ED2, T2>>['scroll'];
locale?: TableProps<RowWithActions<ED2, T2>>['locale'];
opWidth?: number;
}
>
) => React.ReactElement;

View File

@ -9,6 +9,8 @@ import { Feature } from '../types/Feature';
type SubscribeEvent = 'connect' | 'disconnect';
type Callback<ED extends EntityDict & BaseEntityDict> = (event: string, records: OpRecord<ED>[]) => void;
export class SubScriber<ED extends EntityDict & BaseEntityDict> extends Feature {
private cache: Cache<ED>;
private message: Message;
@ -16,8 +18,8 @@ export class SubScriber<ED extends EntityDict & BaseEntityDict> extends Feature
url: string;
path: string;
}>;
private eventMap: Record<string, ((event: string, records: OpRecord<ED>[]) => void) | undefined> = {};
private eventMap: Record<string, Record<string, Callback<ED> | undefined>> = {};
private url?: string;
private path?: string;
private socket?: Socket;
@ -105,9 +107,11 @@ export class SubScriber<ED extends EntityDict & BaseEntityDict> extends Feature
socket.on(
'data',
(opRecords: OpRecord<ED>[], event: string) => {
const callback = this.eventMap[event];
if (callback) {
callback(event, opRecords);
const registered = this.eventMap[event];
if (registered) {
for (const moduleName in registered) {
registered[moduleName] && registered[moduleName]!(event, opRecords);
}
}
this.cache.sync(opRecords);
}
@ -150,22 +154,29 @@ export class SubScriber<ED extends EntityDict & BaseEntityDict> extends Feature
});
}
async sub(events: string[], callback?: (event: string, opRecords: OpRecord<ED>[]) => void): Promise<void> {
async sub(events: string[], moduleName: string, callback?: Callback<ED>): Promise<void> {
const newEvents: string[] = [];
events.forEach((event) => {
assert(
!this.eventMap.hasOwnProperty(event),
`[subscriber]注册回调的id${event}发生重复`
);
this.eventMap[event] = callback;
const registered = this.eventMap[event];
if (registered) {
assert(!registered.hasOwnProperty(moduleName), `[subscriber]注册回调的事件${event}和moduleName${moduleName}发生重复`);
registered[moduleName] = callback;
}
else {
this.eventMap[event] = {
[moduleName]: callback,
};
newEvents.push(event);
};
});
if (this.socketState === 'unconnected') {
return this.connect();
}
else if (this.socketState === 'connected') {
}
else if (this.socketState === 'connected' && newEvents.length > 0) {
return new Promise(
(resolve, reject) => {
this.socket!.emit('sub', events, (result: string) => {
this.socket!.emit('sub', newEvents, (result: string) => {
if (result) {
this.message.setMessage({
type: 'error',
@ -183,8 +194,21 @@ export class SubScriber<ED extends EntityDict & BaseEntityDict> extends Feature
}
}
async unsub(events: string[]) {
events.forEach((event) => unset(this.eventMap, event));
async unsub(events: string[], moduleName: string) {
const emptyEvents: string[] = [];
events.forEach(
(event) => {
const registered = this.eventMap[event];
assert(registered!.hasOwnProperty(moduleName));
unset(registered, moduleName);
if (Object.keys(registered).length === 0) {
emptyEvents.push(event);
}
}
);
emptyEvents.forEach(
event => unset(this.eventMap, event)
);
if (this.socketState === 'connected') {
this.socket!.emit('unsub', events);

View File

@ -684,12 +684,12 @@ const oakBehavior = Behavior<
this.features.locales.loadMissedLocale(key);
},
subDataEvents(events, callback) {
return this.features.subscriber.sub(events, callback);
subDataEvents(events, moduleName, callback) {
return this.features.subscriber.sub(events, moduleName, callback);
},
unsubDataEvents(events) {
return this.features.subscriber.unsub(events);
unsubDataEvents(events, moduleName) {
return this.features.subscriber.unsub(events, moduleName);
},
},
observers: {

View File

@ -601,12 +601,12 @@ abstract class OakComponentBase<
}
}
subDataEvents(events: string[], callback: (event: string, opRecords: OpRecord<ED>[]) => void) {
return this.features.subscriber.sub(events, callback);
subDataEvents(events: string[], moduleName: string, callback: (event: string, opRecords: OpRecord<ED>[]) => void) {
return this.features.subscriber.sub(events, moduleName, callback);
}
unsubDataEvents(events: string[]) {
return this.features.subscriber.unsub(events);
unsubDataEvents(events: string[], moduleName: string) {
return this.features.subscriber.unsub(events, moduleName);
}
}

View File

@ -399,8 +399,8 @@ export type OakCommonComponentMethods<
aggregate: (
aggregation: ED[T]['Aggregation']
) => Promise<AggregationResult<ED[T]['Schema']>>;
subDataEvents: (events: string[], callback?: (event: string, opRecords: OpRecord<ED>[]) => void) => Promise<void>;
unsubDataEvents: (events: string[]) => Promise<void>;
subDataEvents: (events: string[], moduleName: string, callback?: (event: string, opRecords: OpRecord<ED>[]) => void) => Promise<void>;
unsubDataEvents: (events: string[], moduleName: string) => Promise<void>;
};
export type OakSingleComponentMethods<ED extends EntityDict & BaseEntityDict, T extends keyof ED> = {