diff --git a/src/hooks/useAsyncLoad.ts b/src/hooks/useAsyncLoad.ts index ca109cbf14704d821df3cf89ba7848cec6a6602e..0559b7fe398105a4fbabcbf0010a736886a2c572 100644 --- a/src/hooks/useAsyncLoad.ts +++ b/src/hooks/useAsyncLoad.ts @@ -3,25 +3,38 @@ import { DependencyList, useEffect, useState } from 'react'; /** * 需异步加载后执行的hooks * @param callback 在此处执行异步方法() => {return loadAsync();} - * @returns hooks 常量 + * @param _depts 可选的依赖项数组,当依赖项变化时会重新执行异步加载 + * @returns 返回一个元组,第一个元素表示是否加载完成,第二个元素是异步加载的结果 */ function useAsyncLoad( callback: () => Promise, _depts?: DependencyList, ): [boolean, T | undefined] { + // 定义加载状态,初始为false const [loaded, setLoaded] = useState(false); + // 定义异步加载的结果,初始为undefined const [result, setResult] = useState(); + + // 使用useEffect来执行异步加载 useEffect(() => { + // 重置加载状态和结果 setLoaded(false); setResult(undefined); + + // 使用setTimeout确保异步操作在下一个事件循环中执行 setTimeout(async () => { + // 执行传入的异步回调函数 const data = await callback(); + // 如果有返回数据,则设置结果 if (data) { setResult(data); } + // 标记加载完成 setLoaded(true); }, 0); - }, _depts ?? []); + }, _depts ?? []); // 如果没有提供依赖项,则使用空数组 + + // 返回加载状态和结果 return [loaded, result]; } diff --git a/src/ts/core/abstractSpace/abstractSpace.ts b/src/ts/core/abstractSpace/abstractSpace.ts index 1dd31d61c594a455a864e1f1ad34e6ae27968f72..92c5d0d5746b530a823bbffd5abc4f04a2d94b63 100644 --- a/src/ts/core/abstractSpace/abstractSpace.ts +++ b/src/ts/core/abstractSpace/abstractSpace.ts @@ -1,34 +1,57 @@ +/** + * 抽象空间模块 + * 该模块定义了抽象空间相关的接口和类,用于管理系统中的空间层级结构 + */ + import { model, schema } from '../../base'; import { ITarget } from '@/ts/core'; import { DataResource } from '@/ts/core/thing/resource'; import { StandardAbstractSpaces } from '@/ts/core/abstractSpace/standard'; import { spaceOperates } from '@/ts/core/public'; import { ISpace, IStandardSpaceInfo, StandardSpaceInfo } from './abstractSpaceInfo'; + +/** + * 抽象空间接口 + * 继承自标准空间信息接口,定义了抽象空间的基本属性和方法 + */ export interface IAbstractSpace extends IStandardSpaceInfo { /** 真实的空间Id */ abstractSpaceId: string; + /** 标准抽象空间集合 */ standard: StandardAbstractSpaces; /** 当前的用户 */ target: ITarget; /** 资源类 */ resource: DataResource; - /** 上级 */ + /** 上级空间 */ parent: IAbstractSpace | undefined; - /** 下级 */ + /** 下级空间集合 */ children: IAbstractSpace[]; /** 是否有权限 */ isAuth: boolean; - /** 空间下的内容 */ + /** 获取空间下的内容 */ content(store?: boolean): ISpace[]; /** 创建空间 */ create(data: schema.XAbstractSpace): Promise; - + /** 加载空间资源 */ loadSpaceResource(reload?: boolean): Promise; } + +/** + * 抽象空间类 + * 继承自标准空间信息类,实现了抽象空间接口 + */ export class AbstractSpace extends StandardSpaceInfo implements IAbstractSpace { + /** + * 构造函数 + * @param _metadata 空间元数据 + * @param _target 目标用户 + * @param _parent 父空间 + * @param _spaces 空间集合 + */ constructor( _metadata: schema.XAbstractSpace, _target: ITarget, @@ -46,18 +69,28 @@ export class AbstractSpace this.target = _target; this.standard = new StandardAbstractSpaces(this); } + + // 属性定义 target: ITarget; standard: StandardAbstractSpaces; parent: IAbstractSpace | undefined; + + /** 获取子空间集合 */ get children(): IAbstractSpace[] { return this.standard.abstractSpaces; } + + /** 是否为容器 */ get isContainer(): boolean { return true; } + + /** 是否为快捷方式 */ get isShortcut(): boolean { return false; } + + /** 获取分组标签 */ get groupTags(): string[] { let tags: string[] = []; if (this.parent) { @@ -67,23 +100,35 @@ export class AbstractSpace } return tags; } + + /** 获取资源 */ get resource(): DataResource { return this.target.resource; } + + /** 获取抽象空间ID */ get abstractSpaceId(): string { return this.id; } + + /** 检查权限 */ get isAuth(): boolean { if (!this._metadata.applyAuths?.length || this._metadata.applyAuths[0] === '0') return true; return this.target.hasAuthoritys(this._metadata.applyAuths); } + + /** 获取缓存标识 */ get cacheFlag(): string { return 'abstractSpaces'; } + + /** 获取上级空间 */ get superior(): ISpace { return this.parent ?? this.target.abstractSpace; } + + /** 获取ID */ get id(): string { if (!this.parent) { return this.target.id; @@ -91,11 +136,20 @@ export class AbstractSpace return super.id; } + /** + * 获取空间内容 + * @param _store 是否存储 + */ content(_store: boolean = false): ISpace[] { const cnt: ISpace[] = [...this.children]; cnt.push(...this.standard.wareHousings); return cnt.sort((a, b) => (a.metadata.updateTime < b.metadata.updateTime ? 1 : -1)); } + + /** + * 加载内容 + * @param reload 是否重新加载 + */ async loadContent(reload: boolean = false): Promise { if (reload) { await this.loadSpaceResource(reload); @@ -103,6 +157,11 @@ export class AbstractSpace await this.standard.loadStandardSpaces(reload); return true; } + + /** + * 加载空间资源 + * @param reload 是否重新加载 + */ public async loadSpaceResource(reload: boolean = false) { if (this.parent === undefined || reload) { await this.resource.preSpaceLoad(reload); @@ -110,6 +169,11 @@ export class AbstractSpace await this.standard.loadSpaces(reload); await this.standard.loadWareHousings(reload); } + + /** + * 创建空间 + * @param data 空间数据 + */ async create(data: schema.XAbstractSpace): Promise { const result = await this.resource.abstractSpaceColl.insert({ ...data, @@ -121,6 +185,9 @@ export class AbstractSpace } } + /** + * 删除空间 + */ override async delete(): Promise { if (this.parent) { await this.resource.abstractSpaceColl.delete(this.metadata); @@ -128,6 +195,10 @@ export class AbstractSpace } return false; } + + /** + * 永久删除空间 + */ override async hardDelete(): Promise { if (this.parent) { await this.resource.abstractSpaceColl.remove(this.metadata); @@ -136,6 +207,11 @@ export class AbstractSpace } return false; } + + /** + * 递归删除空间 + * @param _space 要删除的空间 + */ private async recursionDelete(_space: IAbstractSpace) { if (!this.isShortcut) { for (const child of _space.children) { @@ -144,7 +220,10 @@ export class AbstractSpace await _space.standard.delete(); } } - // 右键操作 + + /** + * 获取右键操作菜单 + */ override operates(): model.OperateModel[] { const operates: model.OperateModel[] = []; operates.push(spaceOperates.Refesh); @@ -158,6 +237,11 @@ export class AbstractSpace return operates; } + /** + * 接收操作通知 + * @param operate 操作类型 + * @param data 数据 + */ override receive(operate: string, data: schema.XAbstractSpaceStandard): boolean { console.log(operate, data); this.coll.removeCache((i) => i.id != data.id); diff --git a/src/ts/core/abstractSpace/abstractSpaceInfo.ts b/src/ts/core/abstractSpace/abstractSpaceInfo.ts index b00b1ef11573762531cfdce22ba150fbc0d0438e..66200c86e500a659be40524ab2c4ef515909d2f6 100644 --- a/src/ts/core/abstractSpace/abstractSpaceInfo.ts +++ b/src/ts/core/abstractSpace/abstractSpaceInfo.ts @@ -1,30 +1,63 @@ +/** + * 导入所需的模块和类型 + */ import { sleep } from '@/ts/base/common'; import { model, schema } from '../../base'; import { Entity, entityOperates, IEntity } from '../public'; import { XCollection } from '@/ts/core'; -/** 默认空间接口 */ +/** + * 默认空间接口 + * 继承自ISpaceInfo,使用schema.XEntity作为泛型参数 + */ export interface ISpace extends ISpaceInfo {} -/** 空间类接口 */ + +/** + * 空间类接口 + * 定义了空间的基本操作和属性 + * @template T - 继承自schema.XEntity的类型参数 + */ export interface ISpaceInfo extends IEntity { - /** 上级 */ + /** 上级空间 */ superior: ISpace; - /** 删除文件系统项 */ + /** + * 删除文件系统项 + * @param {boolean} notity - 是否发送通知,可选参数 + * @returns {Promise} 删除是否成功 + */ delete(notity?: boolean): Promise; - /** 彻底删除文件系统项 */ + /** + * 彻底删除文件系统项 + * @param {boolean} notity - 是否发送通知,可选参数 + * @returns {Promise} 删除是否成功 + */ hardDelete(notity?: boolean): Promise; /** - * 重命名 - * @param {string} name 新名称 + * 重命名空间 + * @param {string} name - 新名称 + * @returns {Promise} 重命名是否成功 */ rename(name: string): Promise; - /** 加载文件内容 */ + /** + * 加载文件内容 + * @param {boolean} reload - 是否重新加载 + * @returns {Promise} 加载是否成功 + */ loadContent(reload: boolean): Promise; - /** 目录下的内容 */ + /** + * 获取目录下的内容 + * @param {boolean} args - 参数,可选 + * @returns {ISpace[]} 空间数组 + */ content(args?: boolean): ISpace[]; } -/** 文件类抽象实现 */ + +/** + * 文件类抽象实现 + * 提供了空间信息的基本实现 + * @template T - 继承自schema.XEntity的类型参数 + */ export abstract class SpaceInfo extends Entity implements ISpaceInfo @@ -32,56 +65,106 @@ export abstract class SpaceInfo constructor(_metadata: T) { super(_metadata, [_metadata.typeName]); } + + /** 获取元数据 */ override get metadata(): T { return this._metadata; } + + /** 获取上级空间 */ get superior(): ISpace { return this; } + + /** 删除操作,需要子类实现 */ abstract delete(): Promise; + + /** 彻底删除操作,需要子类实现 */ abstract hardDelete(): Promise; + + /** 重命名实现 */ async rename(_: string): Promise { await sleep(0); return true; } + + /** 恢复实现 */ async restore(): Promise { await sleep(0); return true; } + /** 加载内容实现 */ async loadContent(reload: boolean = false): Promise { return await sleep(reload ? 10 : 0); } + + /** 获取内容实现 */ content(): ISpace[] { return []; } } +/** + * 标准空间信息接口 + * 扩展了基本的空间信息接口,添加了更多操作 + * @template T - 继承自schema.XAbstractSpaceStandard的类型参数 + */ export interface IStandardSpaceInfo< T extends schema.XAbstractSpaceStandard = schema.XAbstractSpaceStandard, > extends ISpaceInfo { - /** 设置当前元数据 */ + /** + * 设置当前元数据 + * @param {schema.XAbstractSpaceStandard} _metadata - 要设置的元数据 + */ setMetadata(_metadata: schema.XAbstractSpaceStandard): void; - /** 变更通知 */ + /** + * 变更通知 + * @param {string} operate - 操作类型 + * @param {T} data - 相关数据 + * @returns {Promise} 通知是否成功 + */ notify(operate: string, data: T): Promise; - /** 更新 */ + /** + * 更新数据 + * @param {T} data - 要更新的数据 + * @returns {Promise} 更新是否成功 + */ update(data: T): Promise; - /** 接收通知 */ + /** + * 接收通知 + * @param {string} operate - 操作类型 + * @param {schema.XAbstractSpaceStandard} data - 相关数据 + * @returns {boolean} 接收是否成功 + */ receive(operate: string, data: schema.XAbstractSpaceStandard): boolean; } + +/** 标准空间接口 */ export interface IStandard extends IStandardSpaceInfo {} + +/** + * 标准空间信息抽象实现 + * 提供了标准空间信息的基本实现 + * @template T - 继承自schema.XAbstractSpaceStandard的类型参数 + */ export abstract class StandardSpaceInfo extends SpaceInfo implements IStandardSpaceInfo { coll: XCollection; + constructor(_metadata: T, _coll: XCollection) { super(_metadata); this.coll = _coll; } + + /** 获取元数据 */ override get metadata(): T { return this._metadata; } + + /** 更新实现 */ async update(data: T): Promise { const result = await this.coll.replace({ ...this.metadata, @@ -95,6 +178,8 @@ export abstract class StandardSpaceInfo } return false; } + + /** 删除实现 */ async delete(notify: boolean = true): Promise { const data = await this.coll.delete(this.metadata); if (data && notify) { @@ -102,6 +187,8 @@ export abstract class StandardSpaceInfo } return false; } + + /** 彻底删除实现 */ async hardDelete(notify: boolean = true): Promise { const data = await this.coll.remove(this.metadata); if (data && notify) { @@ -109,20 +196,30 @@ export abstract class StandardSpaceInfo } return false; } + + /** 恢复实现 */ async restore(): Promise { return this.update({ ...this.metadata, isDeleted: false }); } + + /** 重命名实现 */ async rename(name: string): Promise { return await this.update({ ...this.metadata, name }); } + + /** 获取操作列表 */ override operates(): model.OperateModel[] { const operates: model.OperateModel[] = []; operates.unshift(entityOperates.Update, entityOperates.HardDelete); return operates; } + + /** 发送通知实现 */ async notify(operate: string, data: T): Promise { return await this.coll.notify({ data, operate }); } + + /** 接收通知实现 */ receive(operate: string, data: schema.XAbstractSpaceStandard): boolean { switch (operate) { case 'delete': diff --git a/src/ts/core/abstractSpace/standard/goodsShelvesSlot.ts b/src/ts/core/abstractSpace/standard/goodsShelvesSlot.ts index 43798d33f773197d55ef78c26b24147cb9606df3..70e2798fd9710824eccf4be8c9efe0477d20e1f0 100644 --- a/src/ts/core/abstractSpace/standard/goodsShelvesSlot.ts +++ b/src/ts/core/abstractSpace/standard/goodsShelvesSlot.ts @@ -1,3 +1,6 @@ +/** + * 导入所需的模块和类型 + */ import { schema } from '../../../base'; import { IStandardSpaceInfo, @@ -8,7 +11,11 @@ import { DataResource } from '@/ts/core/thing/resource'; import { IWareHousing } from '@/ts/core/abstractSpace/standard/warehousing'; import { logger } from '@/ts/base/common'; import { XThing } from '@/ts/base/schema'; -//库位 + +/** + * 库位接口定义 + * 继承自IStandardSpaceInfo,用于管理库位的基本信息和操作 + */ export interface IGoodsShelvesSlot extends IStandardSpaceInfo { /** 当前的用户 */ target: ITarget; @@ -22,10 +29,20 @@ export interface IGoodsShelvesSlot extends IStandardSpaceInfo; } +/** + * 库位实现类 + * 继承自StandardSpaceInfo,实现了IGoodsShelvesSlot接口 + */ export class GoodsShelvesSlot extends StandardSpaceInfo implements IGoodsShelvesSlot { + /** + * 构造函数 + * @param _metadata 库位元数据 + * @param _space 抽象空间 + * @param _wareHousing 仓库信息 + */ constructor( _metadata: schema.XGoodsShelvesSlot, _space: IAbstractSpace, @@ -39,20 +56,40 @@ export class GoodsShelvesSlot this.resource = _space.resource; //this.currentStock = this._metadata.inventory.length ?? 0; } + + // 属性定义 abstractSpace: IAbstractSpace; resource: DataResource; target: ITarget; wareHousing: IWareHousing; //currentStock: number; + + /** + * 获取库位ID + */ get id(): string { return this._metadata.id.replace('_', ''); } + + /** + * 获取上级仓库 + */ get superior(): IWareHousing { return this.wareHousing; } + + /** + * 获取缓存标识 + */ get cacheFlag(): string { return 'shelvesSlots'; } + + /** + * 判断库位容量是否足够 + * @param things 要上架的物品列表 + * @returns 容量是否足够 + */ private judgeCapacity(things: XThing[]) { if ( this._metadata.capacity < @@ -64,6 +101,11 @@ export class GoodsShelvesSlot return true; } + /** + * 判断物品是否已存在 + * @param things 要上架的物品列表 + * @returns 是否都不存在 + */ private judgeSame(things: XThing[]): boolean { const { inventory = [], name: locationName } = this._metadata; const inventorySet = new Set(inventory); @@ -76,7 +118,12 @@ export class GoodsShelvesSlot } return true; } - /** 上架 */ + + /** + * 上架物品到库位 + * @param things 要上架的物品列表 + * @returns 上架是否成功 + */ async AddToInventory(things: XThing[]): Promise { if (!this.judgeCapacity(things)) { return false; @@ -98,7 +145,12 @@ export class GoodsShelvesSlot } return false; } - /** 下架 */ + + /** + * 从库位下架物品 + * @param thingId 要下架的物品ID列表 + * @returns 下架是否成功 + */ async RemoveFromInventory(thingId: string[]): Promise { this._metadata.inventory = this._metadata.inventory.filter( (id) => !thingId.includes(id), diff --git a/src/ts/core/abstractSpace/standard/index.ts b/src/ts/core/abstractSpace/standard/index.ts index 6b3be78851ff6df8ab3e06c69d1d68238f2bf47a..579cbfe0b98b68edeb5f401a493796aa474eb89f 100644 --- a/src/ts/core/abstractSpace/standard/index.ts +++ b/src/ts/core/abstractSpace/standard/index.ts @@ -1,3 +1,7 @@ +/** + * 标准空间管理类 + * 用于管理抽象空间、仓储空间和货架库位等标准空间 + */ import { schema } from '../../../base'; import { DataResource } from '@/ts/core/thing/resource'; import { AbstractSpace, IAbstractSpace } from '@/ts/core/abstractSpace/abstractSpace'; @@ -5,38 +9,67 @@ import { IStandard } from '@/ts/core/abstractSpace/abstractSpaceInfo'; import { IWareHousing, WareHousing } from '@/ts/core/abstractSpace/standard/warehousing'; import { IGoodsShelvesSlot } from '@/ts/core/abstractSpace/standard/goodsShelvesSlot'; +/** + * 标准空间集合类 + * 管理一个抽象空间下的所有标准空间(包括子空间、仓储空间等) + */ export class StandardAbstractSpaces { /** 空间对象 */ abstractSpace: IAbstractSpace; - /** 空间 */ + /** 子空间集合 */ abstractSpaces: IAbstractSpace[] = []; + /** 仓储空间集合 */ wareHousings: IWareHousing[] = []; + /** 货架库位集合 */ goodsShelvesSlots: IGoodsShelvesSlot[] = []; - /** 加载完成标志 */ + /** 加载完成标志 - 空间 */ spaceLoaded: boolean = false; + /** 加载完成标志 - 仓储空间 */ wareHousingLoaded: boolean = false; + /** 加载完成标志 - 货架库位 */ goodsShelvesSlotLoaded: boolean = false; + + /** + * 构造函数 + * @param _abstractSpace 抽象空间对象 + */ constructor(_abstractSpace: IAbstractSpace) { this.abstractSpace = _abstractSpace; if (this.abstractSpace.parent === undefined) { subscribeNotity(this.abstractSpace); } } + + // 获取空间ID get id(): string { return this.abstractSpace.abstractSpaceId; } + + // 获取资源对象 get resource(): DataResource { return this.abstractSpace.resource; } + // 获取所有标准空间 get standardSpaces(): IStandard[] { return [...this.wareHousings, ...this.abstractSpaces]; } + /** + * 加载所有标准空间 + * @param reload 是否重新加载 + * @returns 标准空间数组 + */ async loadStandardSpaces(reload: boolean = false): Promise { await Promise.all([this.loadWareHousings(reload)]); return this.standardSpaces as IStandard[]; } + + /** + * 加载子空间 + * @param reload 是否重新加载 + * @returns 子空间数组 + */ async loadSpaces(reload: boolean = false): Promise { if (!this.spaceLoaded || reload) { this.spaceLoaded = true; @@ -52,7 +85,7 @@ export class StandardAbstractSpaces { } return this.abstractSpaces; } - + // async loadGoodsShelvesSlot(reload: boolean = false): Promise { // if (!this.goodsShelvesSlotLoaded || reload) { // this.goodsShelvesSlotLoaded = true; @@ -70,6 +103,11 @@ export class StandardAbstractSpaces { // return this.wareHousings; // } + /** + * 加载仓储空间 + * @param reload 是否重新加载 + * @returns 仓储空间数组 + */ async loadWareHousings(reload: boolean = false): Promise { if (!this.wareHousingLoaded || reload) { this.wareHousingLoaded = true; @@ -78,14 +116,15 @@ export class StandardAbstractSpaces { .map((i) => { return new WareHousing(i, this.abstractSpace); }); - // this.wareHousings = this.xWareHousings - // .filter((a) => !(a.parentId && a.parentId.length > 5)) - // .map((i) => { - // return new WareHousing(i, this.abstractSpace); - // }); } return this.wareHousings; } + + /** + * 创建仓储空间 + * @param data 仓储空间数据 + * @returns 创建的仓储空间数据 + */ async createWareHousing( data: schema.XWareHousingSpace, ): Promise { @@ -103,11 +142,16 @@ export class StandardAbstractSpaces { } } + // 删除所有标准空间 async delete() { await Promise.all(this.standardSpaces.map((item) => item.hardDelete())); } } -/** 订阅变更通知 */ + +/** + * 订阅变更通知 + * @param space 要订阅的空间对象 + */ const subscribeNotity = (space: IAbstractSpace) => { space.resource.abstractSpaceColl.subscribe([space.key], (data) => { subscribeCallback(space, '空间', data); @@ -120,7 +164,14 @@ const subscribeNotity = (space: IAbstractSpace) => { }); }; -/** 订阅回调方法 */ +/** + * 订阅回调方法 + * 处理空间变更通知 + * @param space 空间对象 + * @param typeName 空间类型名称 + * @param data 变更数据 + * @returns 是否处理成功 + */ function subscribeCallback( space: IAbstractSpace, typeName: string, @@ -169,7 +220,13 @@ function subscribeCallback( return false; } -/** 空间的变更 */ +/** + * 处理空间变更 + * @param space 空间对象 + * @param typeName 空间类型名称 + * @param operate 操作类型 + * @param data 变更数据 + */ function standardSpaceChanged( space: IAbstractSpace, typeName: string, @@ -207,7 +264,15 @@ function standardSpaceChanged( } } -/** 数组元素操作 */ +/** + * 数组元素操作 + * 处理数组元素的增删改操作 + * @param arr 目标数组 + * @param operate 操作类型 + * @param data 操作数据 + * @param create 创建新元素的函数 + * @returns 处理后的数组 + */ function ArrayChanged( arr: T[], operate: string, diff --git a/src/ts/core/abstractSpace/standard/warehousing.ts b/src/ts/core/abstractSpace/standard/warehousing.ts index 55e731f5a0f9572a7f5df2abc9a77f17777d95bf..82b33bef678e8598c29ee27af8c128d05bc40166 100644 --- a/src/ts/core/abstractSpace/standard/warehousing.ts +++ b/src/ts/core/abstractSpace/standard/warehousing.ts @@ -1,3 +1,6 @@ +/** + * 导入所需的模块和类型 + */ import { model, schema } from '../../../base'; import { ISpace, @@ -18,16 +21,27 @@ import { XThing, XProperty, } from '@/ts/base/schema'; + +/** + * 选项接口定义 + */ interface Option { value: string; label: string; children?: Option[]; } + +/** + * 库位信息接口定义 + */ interface KWInfo { id: string; kw: string; } -//仓库 + +/** + * 仓库接口定义 + */ export interface IWareHousing extends IStandardSpaceInfo { /** 当前的用户 */ target: ITarget; @@ -45,7 +59,6 @@ export interface IWareHousing extends IStandardSpaceInfo; /** 新增货架库位信息 */ addGoodsShelvesSlot(data: schema.XGoodsShelvesSlot[]): Promise; - // loadThing(slotId: string, code?: string): Promise; /** 上架 */ AddToInventory(slotId: string, things: XThing[]): Promise; /** 下架 */ @@ -60,6 +73,9 @@ export interface IWareHousing extends IStandardSpaceInfo implements IWareHousing @@ -71,12 +87,17 @@ export class WareHousing this.target = _space.target; this.resource = _space.resource; } + abstractSpace: IAbstractSpace; resource: DataResource; target: ITarget; shelves: XGoodsShelves[] = []; shelvesSlots: IGoodsShelvesSlot[] = []; private _slotsLoaded: boolean = false; + + /** + * 生成选项列表 + */ selectOpt(): Option[] { return this.shelves.flatMap((shelf) => { const slots = this.shelvesSlots.filter( @@ -89,6 +110,10 @@ export class WareHousing })); }); } + + /** + * 新增货架 + */ async addGoodsShelves(data: schema.XGoodsShelves): Promise { if (!this._metadata.goodsShelves) { this._metadata.goodsShelves = []; @@ -104,6 +129,9 @@ export class WareHousing return false; } + /** + * 更新货架信息 + */ async updateGoodsShelves(data: schema.XGoodsShelves): Promise { const index = this._metadata.goodsShelves.findIndex((shelf) => shelf.id === data.id); if (index !== -1) { @@ -119,6 +147,9 @@ export class WareHousing return false; } + /** + * 删除货架 + */ async deleteGoodsShelves(data: schema.XGoodsShelves): Promise { this._metadata.goodsShelves = this._metadata.goodsShelves.filter( (shelf) => shelf.id !== data.id, @@ -134,6 +165,9 @@ export class WareHousing return false; } + /** + * 删除库位 + */ async deleteSolts(shelfId: string) { this.shelvesSlots .filter((slot) => slot.metadata.goodsShelveId === shelfId) @@ -142,6 +176,9 @@ export class WareHousing }); } + /** + * 新增货架库位 + */ async addGoodsShelvesSlot(data: schema.XGoodsShelvesSlot[]): Promise { const extendedData = data.map((data: schema.XGoodsShelvesSlot) => ({ ...data, @@ -160,6 +197,9 @@ export class WareHousing return false; } + /** + * 物资上架 + */ async AddToInventory(slotId: string, things: XThing[]): Promise { const slot = this.shelvesSlots.find((slot) => slot.id === slotId); if (slot) { @@ -180,6 +220,9 @@ export class WareHousing } } + /** + * 物资下架 + */ async RemoveFromInventory(things: XThing[]): Promise { const records = await this.loadRecordRelationByChainId( things.map((thing) => thing.chainId), @@ -209,6 +252,9 @@ export class WareHousing } } + /** + * 更新物资信息 + */ async updateThing(thing: schema.XThing): Promise { const key = thing.__changeKey; const value = thing.__changeValue; @@ -223,6 +269,9 @@ export class WareHousing return false; } + /** + * 记录操作 + */ async record( slot: IGoodsShelvesSlot, operate: string, @@ -246,6 +295,9 @@ export class WareHousing ); } + /** + * 记录关系 + */ async recordRelation( slot: IGoodsShelvesSlot, thing: XThing, @@ -272,12 +324,14 @@ export class WareHousing //物资 goodsChainId: thing.chainId, goodsId: thing.id, - //formId: source, - //fieldCode: fieldCode, }); break; } } + + /** + * 根据链ID加载记录关系 + */ async loadRecordRelationByChainId(chainId: string[]): Promise { const res = await this.resource.goodsRelationColl.loadResult({ options: { @@ -291,6 +345,10 @@ export class WareHousing }); return res.data || []; } + + /** + * 加载库位信息 + */ async loadKWInfo(chainId: string[]): Promise { const res = await this.loadRecordRelationByChainId(chainId); return res.map((i) => { @@ -302,6 +360,10 @@ export class WareHousing } as KWInfo; }); } + + /** + * 加载库位字段 + */ async loadKwField(): Promise { const res = await this.resource.propertyColl.loadResult({ options: { @@ -315,62 +377,94 @@ export class WareHousing }); return res.data[0] || undefined; } + + /** + * 获取ID + */ get id(): string { return this._metadata.id; } + /** + * 获取上级空间 + */ get superior(): ISpace { return this.abstractSpace; } + /** + * 获取缓存标识 + */ get cacheFlag(): string { return 'wareHousings'; } + /** + * 判断是否为容器 + */ get isContainer(): boolean { return false; } - /** 库位总容量 */ + /** + * 计算库位总容量 + */ totalSlotsCapacity(): number { return this.shelvesSlots.reduce((acc, slot) => acc + slot.metadata.capacity, 0); } - /** 库位使用容量 */ + + /** + * 计算已使用库位容量 + */ usedSlotsCapacity(): number { return this.shelvesSlots.reduce( (acc, slot) => acc + (slot.metadata?.inventory?.length ?? 0), 0, ); } - /** 库位利用率 */ + + /** + * 计算库位利用率 + */ utilization(): number { return this.totalSlotsCapacity() > 0 ? Number(((this.usedSlotsCapacity() / this.totalSlotsCapacity()) * 100).toFixed(2)) : 0; } + /** + * 获取内容 + */ content(): ISpace[] { const cnt = [...this.shelvesSlots]; return cnt.sort((a, b) => (a.metadata.updateTime < b.metadata.updateTime ? 1 : -1)); } + /** + * 获取操作列表 + */ override operates(): model.OperateModel[] { const operates: model.OperateModel[] = []; operates.push( wareHousingOperates.InBound, wareHousingOperates.Outbound, - // wareHousingOperates.Inventory, ); operates.push(spaceOperates.Refesh, ...super.operates()); return operates; } + /** + * 加载内容 + */ async loadContent(reload: boolean = false): Promise { this.shelves = this.metadata.goodsShelves; await this.loadGoodsShelvesSlots(reload); return true; } + /** + * 加载物资 + */ async loadThing(ids: string[]): Promise { const res = await this.resource.thingColl.loadResult({ options: { @@ -386,6 +480,9 @@ export class WareHousing return res.data ?? []; } + /** + * 加载货架库位 + */ private async loadGoodsShelvesSlots(reload?: boolean): Promise { if (!this._slotsLoaded || reload) { const res = await this.resource.goodsShelvesSlotColl.loadResult({ @@ -408,6 +505,9 @@ export class WareHousing return this.shelvesSlots; } + /** + * 处理库位接收 + */ slotReceive(operate: string, data: schema.XGoodsShelvesSlot): boolean { switch (operate) { case 'insert': @@ -436,6 +536,9 @@ export class WareHousing return true; } + /** + * 重写接收方法 + */ override receive(operate: string, data: schema.XWareHousingSpace): boolean { if (data.shareId === this.target.id) { if (data.id === this.id) { diff --git a/src/ts/core/chat/activity.ts b/src/ts/core/chat/activity.ts index 2840e9d315e3265442058cbe0a52736750da5aa6..033c57bd4616a60fabb03ede6d326c1112190d71 100644 --- a/src/ts/core/chat/activity.ts +++ b/src/ts/core/chat/activity.ts @@ -5,10 +5,17 @@ import { XCollection } from '../public/collection'; import { IPerson } from '../target/person'; import { ISession } from './session'; import { CommentType } from '@/ts/base/model'; -/** 动态集合名 */ + +/** + * 动态集合名 + * 用于标识动态数据在数据库中的集合名称 + */ const ActivityCollName = '-resource-activity'; -/** 动态消息接口 */ +/** + * 动态消息接口 + * 定义了动态消息的基本属性和操作方法 + */ export interface IActivityMessage extends Emitter { /** 唯一标识 */ key: string; @@ -32,20 +39,28 @@ export interface IActivityMessage extends Emitter { unComment(comment: CommentType): Promise; } -/** 动态消息实现 */ +/** + * 动态消息实现类 + * 实现了IActivityMessage接口,提供动态消息的具体功能 + */ class ActivityMessage extends Emitter implements IActivityMessage { key: string; activity: IActivity; metadata: model.ActivityType; + constructor(_metadata: model.ActivityType, _activity: IActivity) { super(); this.key = generateUuid(); this.activity = _activity; this.metadata = _metadata; } + + // 获取创建时间的时间戳 get createTime(): number { return new Date(this.metadata.createTime).getTime(); } + + // 判断是否可以删除该消息 get canDelete(): boolean { return ( this.metadata.createUser === this.activity.userId || @@ -53,12 +68,16 @@ class ActivityMessage extends Emitter implements IActivityMessage { this.activity.session.target.hasRelationAuth()) ); } + + // 更新消息数据 update(data: model.ActivityType): void { if (data.id === this.metadata.id) { this.metadata = data; this.changCallback(); } } + + // 删除消息 async delete(): Promise { if (this.canDelete && (await this.activity.coll.delete(this.metadata))) { await this.activity.coll.notify({ @@ -71,6 +90,8 @@ class ActivityMessage extends Emitter implements IActivityMessage { await viewColl.delete({...this.metadata,id:this.metadata.viewId}); } } + + // 点赞或取消点赞 async like(): Promise { var newData: model.ActivityType | undefined; if (this.metadata.likes.find((i) => i === this.activity.userId)) { @@ -90,6 +111,8 @@ class ActivityMessage extends Emitter implements IActivityMessage { } return false; } + + // 添加评论 async comment(label: string, replyTo?: string): Promise { const newData = await this.activity.coll.update(this.metadata.id, { _push_: { @@ -111,6 +134,8 @@ class ActivityMessage extends Emitter implements IActivityMessage { } return false; } + + // 删除评论 async unComment(comment: CommentType): Promise { if (comment.userId === this.activity.userId && comment.id !== undefined) { const newData = await this.activity.coll.update(this.metadata.id, { @@ -131,7 +156,10 @@ class ActivityMessage extends Emitter implements IActivityMessage { } } -/** 动态接口类 */ +/** + * 动态接口类 + * 定义了动态的基本属性和操作方法 + */ export interface IActivity extends IEntity { /** 会话对象 */ session: ISession; @@ -157,12 +185,16 @@ export interface IActivity extends IEntity { load(take?: number): Promise; } -/** 动态实现 */ +/** + * 动态实现类 + * 实现了IActivity接口,提供动态的具体功能 + */ export class Activity extends Entity implements IActivity { session: ISession; activityList: IActivityMessage[]; coll: XCollection; private finished: boolean = false; + constructor(_metadata: schema.XTarget, session: ISession) { super(_metadata, ['动态']); this.session = session; @@ -179,15 +211,21 @@ export class Activity extends Entity implements IActivity { } this.subscribeNotify(); } + + // 判断是否允许发布动态 get allPublish(): boolean { return ( this.session.target.id === this.session.sessionId && this.session.target.hasRelationAuth() ); } + + // 获取相关动态列表 get activitys(): IActivity[] { return [this]; } + + // 加载动态消息 async load(take: number = 10): Promise { if (!this.finished) { const data = await this.coll.load({ @@ -210,6 +248,7 @@ export class Activity extends Entity implements IActivity { return []; } + // 发布新动态 async send( content: string, typeName: MessageType, @@ -260,6 +299,7 @@ export class Activity extends Entity implements IActivity { return false; } + // 订阅动态通知 subscribeNotify() { this.coll.subscribe( [this.key], @@ -294,12 +334,17 @@ export class Activity extends Entity implements IActivity { } } +/** + * 群组动态类 + * 用于管理多个动态源的聚合动态 + */ export class GroupActivity extends Entity implements IActivity { session: ISession; allPublish: boolean; private subscribeIds: string[] = []; private subActivitys: IActivity[]; lastTime: number = new Date().getTime(); + constructor(_user: IPerson, _activitys: IActivity[], userPublish: boolean) { super( { @@ -315,12 +360,18 @@ export class GroupActivity extends Entity implements IActivity { this.session = _user.session; this.subActivitys = _activitys; } + + // 获取所有动态源 get activitys(): IActivity[] { return [this, ...this.subActivitys]; } + + // 获取动态集合 get coll(): XCollection { return this.session.activity.coll; } + + // 获取动态列表 get activityList(): IActivityMessage[] { const more: IActivityMessage[] = []; for (const activity of this.subActivitys) { @@ -328,6 +379,8 @@ export class GroupActivity extends Entity implements IActivity { } return more.sort((a, b) => b.createTime - a.createTime); } + + // 加载动态 async load(take: number = 10): Promise { await Promise.all(this.subActivitys.map((i) => i.load(take))); const more: IActivityMessage[] = []; @@ -340,6 +393,8 @@ export class GroupActivity extends Entity implements IActivity { } return news; } + + // 发布动态 send( content: string, typeName: MessageType, @@ -349,12 +404,16 @@ export class GroupActivity extends Entity implements IActivity { ): Promise { return this.session.activity.send(content, typeName, resources, tags, linkInfo); } + + // 订阅动态更新 override subscribe(callback: (key: string, ...args: any[]) => void): string { this.subActivitys.forEach((activity) => { this.subscribeIds.push(activity.subscribe(callback, false)); }); return super.subscribe(callback); } + + // 取消订阅 public unsubscribe(id: string | string[]): void { super.unsubscribe(id); super.unsubscribe(this.subscribeIds); diff --git a/src/ts/core/chat/message.ts b/src/ts/core/chat/message.ts index 89652876d23320a5a43e9d7acd38e56bf7d009be..b5bdfbf8f63a9b6461058a4e57ff3f5c59c74fa7 100644 --- a/src/ts/core/chat/message.ts +++ b/src/ts/core/chat/message.ts @@ -3,6 +3,9 @@ import { MessageType, TargetType } from '../public'; import { IBelong } from '../target/base/belong'; import { IPerson } from '../target/person'; import { ISession } from './session'; +/** + * 消息标签接口定义 + */ export interface IMessageLabel { /** 标签名称 */ label: string; @@ -15,6 +18,10 @@ export interface IMessageLabel { /** 用户Id */ userId: string; } + +/** + * 消息标签实现类 + */ export class MessageLabel implements IMessageLabel { constructor(_matedata: model.CommentType, target: IPerson) { this.user = target.user; @@ -22,22 +29,36 @@ export class MessageLabel implements IMessageLabel { } user: IPerson; metadata: model.CommentType; + + // 获取标签名称 get label(): string { return this.metadata.label; } + + // 获取用户ID get userId(): string { return this.metadata.userId; } + + // 获取组织ID get designateId(): string { return this.metadata.designateId; } + + // 获取标签创建者信息 get labeler(): model.ShareIcon { return this.user.findShareById(this.metadata.designateId ?? this.metadata.userId); } + + // 获取标签创建时间 get time(): string { return this.metadata.time; } } + +/** + * 消息接口定义 + */ export interface IMessage { /** 消息id */ id: string; @@ -84,6 +105,10 @@ export interface IMessage { /** 会话 */ chat: ISession; } + +/** + * 消息实现类 + */ export class Message implements IMessage { constructor(_metadata: model.ChatMessageType, _chat: ISession) { this._chat = _chat; @@ -110,6 +135,7 @@ export class Message implements IMessage { this.labels.push(new MessageLabel(tag, this.user)); }); } + cite: IMessage | undefined; forward: IMessage[] = []; mentions: string[] = []; @@ -118,27 +144,43 @@ export class Message implements IMessage { _msgBody: string; labels: IMessageLabel[] = []; metadata: model.ChatMessageType; + + // 获取消息ID get id(): string { return this.metadata.id; } + + // 获取消息类型 get msgType(): string { return this.metadata.typeName; } + + // 获取创建时间 get createTime(): string { return this.metadata.createTime; } + + // 获取发送方信息 get from(): model.ShareIcon { return this.user.findShareById(this.metadata.fromId); } + + // 获取接收方信息 get to(): model.ShareIcon { return this.user.findShareById(this.metadata.toId); } + + // 判断是否为当前用户发送 get isMySend(): boolean { return this.metadata.fromId === this.user.id; } + + // 获取会话信息 get chat(): ISession { return this._chat; } + + // 判断消息是否已读 get isReaded(): boolean { return ( this.isMySend || @@ -146,6 +188,8 @@ export class Message implements IMessage { this.labels.some((i) => i.userId === this.user.id) ); } + + // 获取已读信息 get readedinfo(): string { const ids = this.readedIds; if (ids.length === 0) { @@ -159,10 +203,14 @@ export class Message implements IMessage { } return this._chat.memberCount - ids.length - 1 + '人未读'; } + + // 获取已读人员ID列表 get readedIds(): string[] { const ids = this.labels.map((v) => v.userId); return ids.filter((id, i) => ids.indexOf(id) === i); } + + // 获取未读人员信息 get unreadInfo(): IMessageLabel[] { const ids = this.readedIds; return this._chat.members @@ -181,9 +229,13 @@ export class Message implements IMessage { ), ); } + + // 获取评论数量 get comments(): number { return this.labels.filter((v) => v.label != '已读').length; } + + // 判断是否允许撤回 get allowRecall(): boolean { if (!this.isMySend) { return false; @@ -197,9 +249,13 @@ export class Message implements IMessage { return new Date().getTime() - new Date(this.createTime).getTime() < 2 * 60 * 1000; } } + + // 判断是否允许编辑 get allowEdit(): boolean { return this.isMySend && this.msgType === MessageType.Recall; } + + // 获取消息标题 get msgTitle(): string { let header = ``; if (this._chat.metadata.typeName != TargetType.Person) { @@ -225,30 +281,44 @@ export class Message implements IMessage { } return `${header}[${this.msgType}]:解析异常`; } + + // 获取消息内容 get msgBody(): string { if (this.msgType === MessageType.Recall) { return (this.isMySend ? '我' : this.from.name) + '撤回了一条消息'; } return this._msgBody; } + + // 获取源消息 get msgSource(): string { return this._msgBody; } } + +/** + * 群组消息类,继承自Message + */ export class GroupMessage extends Message { space: IBelong; constructor(_metadata: model.ChatMessageType, _chat: ISession) { super(_metadata, _chat); this.space = _chat.target.space; } + + // 判断是否为当前用户发送 get isMySend(): boolean { return ( this.metadata.fromId === this.user.id && this.metadata.designateId === this.space.id ); } + + // 判断消息是否已读 get isReaded(): boolean { return true } + + // 获取已读信息 get readedinfo(): string { const ids = this.readedIds; if (ids.length === 0) { @@ -262,12 +332,16 @@ export class GroupMessage extends Message { } return noread + '人未读'; } + + // 获取已读人员ID列表 get readedIds(): string[] { const ids = this.labels .map((v) => v.designateId) .filter((a) => a != this.metadata.designateId); return ids.filter((id, i) => ids.indexOf(id) === i); } + + // 获取未读人员信息 get unreadInfo(): IMessageLabel[] { const ids = this.readedIds; return this._chat.members diff --git a/src/ts/core/chat/session.ts b/src/ts/core/chat/session.ts index d043c7fc39a3f2d5fc78e4b1ea8d414017149526..ebd8f5830aaa323bfdeadc29fab0e521c328cdb7 100644 --- a/src/ts/core/chat/session.ts +++ b/src/ts/core/chat/session.ts @@ -1,3 +1,6 @@ +/** + * 导入所需的模块和依赖 + */ import { command, common, model, schema } from '../../base'; import { Entity, IEntity, MessageType, TargetType, orgAuth } from '../public'; import { ITarget } from '../target/base/target'; @@ -8,9 +11,14 @@ import { logger } from '@/ts/base/common'; import { sessionOperates, teamOperates } from '../public/operates'; import { ChatMessageType } from '@/ts/base/model'; import { companyTypes } from '../public/consts'; -// 空时间 + +// 空时间常量,用于初始化消息时间 const nullTime = new Date('2022-07-01').getTime(); -/** 会话接口类 */ + +/** + * 会话接口类 + * 定义了会话相关的所有属性和方法 + */ export interface ISession extends IEntity { /** 是否归属人员 */ isBelongPerson: boolean; @@ -72,14 +80,24 @@ export interface ISession extends IEntity { /** 共享信息数据集 */ export const ActivityIdSet = new Map(); -/** 会话实现 */ +/** + * 会话实现类 + * 继承自Entity并实现ISession接口 + */ export class Session extends Entity implements ISession { + // 会话ID sessionId: string; + // 会话目标对象 target: ITarget; + // 会话动态 activity: IActivity; + // 聊天数据 chatdata: model.MsgChatData; + // 指定ID designateId: string; + // 消息列表 messages: IMessage[] = []; + // 输入内容 inputContent: { imgList: { file: File; imgUrl: string }[]; message: string; @@ -91,11 +109,21 @@ export class Session extends Entity implements ISession { message: '', mentions: [], }; + // 消息通知回调 private messageNotify?: (messages: IMessage[]) => void; + + /** + * 构造函数 + * @param id 会话ID + * @param target 会话目标对象 + * @param _metadata 元数据 + * @param tags 标签 + */ constructor(id: string, target: ITarget, _metadata: schema.XTarget, tags?: string[]) { super(_metadata, tags ?? []); this.sessionId = id; this.target = target; + // 初始化聊天数据 this.chatdata = { fullId: `${target.id}_${id}`, chatName: _metadata.name, @@ -107,36 +135,51 @@ export class Session extends Entity implements ISession { labels: [], recently: false, }; + // 初始化活动对象 if (ActivityIdSet.has(_metadata.id)) { this.activity = ActivityIdSet.get(_metadata.id)!; } else { this.activity = new Activity(_metadata, this); ActivityIdSet.set(_metadata.id, this.activity); } + // 延迟加载缓存数据 setTimeout( async () => { await this.loadCacheChatData(); }, this.id === this.userId ? 100 : 0, ); + // 设置指定ID this.designateId = this.target.typeName === TargetType.Group ? this.target.space.id : this.userId; } + + // 获取徽章数量(未读消息数) get badgeCount(): number { return this.chatdata.noReadCount; } + + // 获取消息集合 get coll(): XCollection { return this.target.resource.messageColl; } + + // 获取成员列表 get members(): schema.XTarget[] { return this.isGroup ? this.target.members : []; } + + // 获取成员数量 get memberCount(): number { return this.isGroup ? this.target.memberCount : 0; } + + // 判断是否为群会话 get isGroup(): boolean { return this.target.id === this.sessionId && this.sessionId !== this.userId; } + + // 获取会话匹配条件 get sessionMatch(): any { return this.isGroup ? { toId: this.sessionId, isDeleted: false } @@ -148,11 +191,15 @@ export class Session extends Entity implements ISession { isDeleted: false, }; } + + // 判断是否归属人员 get isBelongPerson(): boolean { return ( this.metadata.belongId === this.metadata.createUser && !('stations' in this.target) ); } + + // 判断是否为我的聊天 get isMyChat(): boolean { var hasAuth: boolean = false; if (this.target.typeName === TargetType.Group) { @@ -176,18 +223,24 @@ export class Session extends Entity implements ISession { this.chatdata.noReadCount > 0 ); } + + // 判断是否为好友 get isFriend(): boolean { return ( this.metadata.typeName !== TargetType.Person || this.target.user.members.some((i) => i.id === this.sessionId) ); } + + // 获取复制ID get copyId(): string | undefined { if (this.target.id === this.userId && this.sessionId !== this.userId) { return this.sessionId; } return undefined; } + + // 获取备注信息 get remark(): string { if (this.inputContent.message.length > 0) { return '草稿:' + this.inputContent.message.replace(/]*>/gi, '[图片]'); @@ -201,18 +254,26 @@ export class Session extends Entity implements ISession { } return this.metadata.remark; } + + // 获取更新时间 get updateTime(): string { if (this.chatdata.lastMessage) { return this.chatdata.lastMessage.createTime; } return super.updateTime; } + + // 获取缓存路径 get cachePath(): string { return `session.${this.chatdata.fullId}`; } + + // 判断是否可以删除消息 get canDeleteMessage(): boolean { return this.target.id === this.userId || this.target.hasRelationAuth(); } + + // 获取群组标签 get groupTags(): string[] { var gtags: string[] = []; if (companyTypes.includes(this.typeName as TargetType)) { @@ -240,6 +301,8 @@ export class Session extends Entity implements ISession { } return [...gtags, ...this.chatdata.labels]; } + + // 获取操作模型 override operates(): model.OperateModel[] { const operates: model.OperateModel[] = []; if (this.chatdata.isToping) { @@ -258,6 +321,8 @@ export class Session extends Entity implements ISession { operates.push(sessionOperates.RemoveSession); return operates; } + + // 加载更多消息 async moreMessage(first: boolean = false): Promise { if (first === false || this.messages.length < 30) { const data = await this.coll.loadSpace({ @@ -282,9 +347,13 @@ export class Session extends Entity implements ISession { } return 0; } + + // 取消消息通知 unMessage(): void { this.messageNotify = undefined; } + + // 设置消息通知回调 onMessage(callback: (messages: IMessage[]) => void): void { this.messageNotify = callback; this.moreMessage(true).then(async () => { @@ -301,6 +370,8 @@ export class Session extends Entity implements ISession { this.messageNotify?.apply(this, [this.messages]); }); } + + // 发送消息 async sendMessage( type: MessageType, text: string, @@ -354,6 +425,8 @@ export class Session extends Entity implements ISession { } return data !== undefined; } + + // 撤回消息 async recallMessage(id: string): Promise { const data = await this.coll.update( id, @@ -366,6 +439,8 @@ export class Session extends Entity implements ISession { await this.notify('replace', [data]); } } + + // 标记消息 async tagMessage(ids: string[], tag: string): Promise { const data = await this.coll.updateMany( ids, @@ -385,6 +460,8 @@ export class Session extends Entity implements ISession { await this.notify('replace', data); } } + + // 删除消息 async deleteMessage(id: string): Promise { if (this.canDeleteMessage) { for (const item of this.messages) { @@ -405,6 +482,8 @@ export class Session extends Entity implements ISession { } return false; } + + // 清空消息 async clearMessage(): Promise { if (this.canDeleteMessage) { const success = await this.coll.deleteMatch(this.sessionMatch); @@ -419,6 +498,7 @@ export class Session extends Entity implements ISession { return false; } + // 接收消息 receiveMessage(operate: string, data: model.ChatMessageType): void { const imsg = this.buildMessage(data); if (operate === 'insert') { @@ -451,6 +531,7 @@ export class Session extends Entity implements ISession { this.messageNotify?.apply(this, [this.messages]); } + // 通知消息变更 async notify( operate: string, data: model.ChatMessageType[], @@ -468,6 +549,7 @@ export class Session extends Entity implements ISession { ); } + // 加载缓存的聊天数据 async loadCacheChatData(): Promise { const data = await this.target.user.cacheObj.get(this.cachePath); if (data && data.fullId === this.chatdata.fullId) { @@ -488,6 +570,7 @@ export class Session extends Entity implements ISession { this._subscribeMessage(); } + // 缓存聊天数据 async cacheChatData(notify: boolean = false): Promise { const data = { ...this.chatdata }; if (data.lastMessage) { @@ -501,6 +584,7 @@ export class Session extends Entity implements ISession { return success; } + // 订阅消息 private _subscribeMessage(): void { if (this.isGroup) { this.coll.subscribe( @@ -527,6 +611,7 @@ export class Session extends Entity implements ISession { } } + // 构建消息对象 private buildMessage(msg: ChatMessageType): IMessage { if (this.target.typeName === TargetType.Group) { return new GroupMessage(msg, this);