@complex-suite/data
Advanced tools
+24
-0
@@ -0,1 +1,25 @@ | ||
| <!-- | ||
| 版本规则: | ||
| - 顶部 `### current` 记录当前未发版的改动(可能为空)。 | ||
| - 版本升级发版时,将 `current` 更替为本次发版版本号(如 `### 5.0.15`),并在其上方新建一个空的 `### current`。 | ||
| - 这样每次发版后,顶部始终保留一个 `### current`(可能为空)用于记录后续改动。 | ||
| --> | ||
| ### current | ||
| ### 5.0.15 | ||
| - fix(module): `DictionaryData.sortPageList` handler 内增加 findIndex + splice 先移除自身当前位置,再重新查找对标位置后插入,与 `sortObserveList` 的 handler 行为对齐,消除链式排序时元素重复。 | ||
| - fix(data): `DefaultData` 构造函数中创建 `$storage` 后注册 `onLife('beforeDestroy', handler)`,handler 内调用 `this.$storage.stop()` 停止定时写入。 | ||
| - fix(data): `BaseData.$onDependLoaded` 注册的处理器改为 `(lifeValue) => { lifeValue.destroy(); next() }`,执行后自动销毁监听。 | ||
| - fix(core): `SelectData` 新增 `destroy()` 方法,依次调用 `this.$storage?.stop()`、`this.$pagination?.destroy()`、`this.destroyLife()`。 | ||
| - docs(pagination): `PaginationData` 的 `setCount` 和 `setSize` 方法增加注释,说明多次触发 `_syncData` 是预期行为,实现方应在接收端通过 nextTick/Promise.then 合并请求,可考虑合并多个请求。 | ||
| - fix(pagination): `setPage` 返回 `boolean`(实际变化为真),`setSize` 新增 `this.size.data !== size` 变化守卫并返回 `boolean`,`setPageAndSize` 返回 `{ page: boolean, size: boolean, changed: boolean }`,`changed` 为真才 `triggerLife`。配合 `PaginationView` 消除 `_fromSizeChange` 标志位机制。 | ||
| - fix(search): `SearchData.init` 保存 `runtime` 局部引用,`then/catch/finally` 回调中 `if (this.$runtime !== runtime) return`,防止重复 `init` 时旧 Promise 链操作已过期 `$runtime`。 | ||
| - fix(module): `DependData` 新增 `private unbindList` 字段;`$bindDepend` 增加可选 `collector` 参数,收集 `lifeDict` 对应的 `offLife` 闭包;`buildDependValue` 将 `this.unbindList` 传入 `DependValue` 构造器;`destroy(force)` 遍历调用所有 `unbind` 并清空数组,确保强制销毁时清理 `depend` 上的 `onLife` 监听器。 | ||
| - fix(complex): `ComplexData.setPageAndSize` 补充 `return`,透传 `PaginationData.setPageAndSize` 的 `{ page, size, changed }` 返回值。 | ||
| - fix(reset): `ResetData._parseForceTrigger` 配置缺失时 `return false` 而非 `undefined`,避免 `reset(undefined)` 误判为非 false 而执行重置。 | ||
| - fix(dictionary): `DefaultSelectEdit` 构造函数开头 `const option = { ...initOption }` 浅拷贝入参,后续操作 option,避免复用同一 initOption 创建多实例时污染调用方原对象。 | ||
| - feat(locale): `UpdateData.next` 中硬编码 `'stop update!'` 改为 `dataLocale.t('update.stop')`,新增 `update.stop` 翻译键(zh: '停止更新!' / en: 'Stop update!'),同步更新 `locale/zh.ts` 和 `locale/en.ts`。 | ||
| - refactor(dictionary): `DictionaryData.getObserveList` 内层变量 `observeList`(L328)重命名为 `childObserveList`,消除对外层同名变量的遮蔽,提升可读性。逻辑行为不变。 | ||
| ### `5.0.14` | ||
@@ -2,0 +26,0 @@ - fix(dictionary): `SimpleDateEdit` 泛型约束 `R extends Boolean` 修正为 `R extends boolean`,共 4 处(T5)。`Boolean` 是对象包装类型,`boolean` 是原始类型。 |
+3
-3
| { | ||
| "name": "@complex-suite/data", | ||
| "version": "5.0.14", | ||
| "version": "5.0.15", | ||
| "description": "a complex data", | ||
@@ -15,4 +15,4 @@ "type": "module", | ||
| "dependencies": { | ||
| "@complex-suite/utils": "3.0.14", | ||
| "@complex-suite/plugin": "5.0.14" | ||
| "@complex-suite/utils": "3.0.15", | ||
| "@complex-suite/plugin": "5.0.15" | ||
| }, | ||
@@ -19,0 +19,0 @@ "devDependencies": { |
@@ -121,2 +121,11 @@ import { Life } from '@complex-suite/utils' | ||
| } | ||
| destroy() { | ||
| if (this.$storage) { | ||
| this.$storage.stop() | ||
| } | ||
| if (this.$pagination) { | ||
| this.$pagination.destroy() | ||
| } | ||
| this.destroyLife() | ||
| } | ||
| /* --- life end --- */ | ||
@@ -123,0 +132,0 @@ loadData(force?: { ing?: boolean }, ...args: unknown[]) { |
@@ -284,3 +284,7 @@ import { getComplexProp, isPromise } from '@complex-suite/utils' | ||
| this.onLife('dependLoaded', { | ||
| handler: next | ||
| handler: (lifeValue) => { | ||
| // 执行后立即销毁监听,避免 dependLoaded 被多次触发时 handler 重复执行 | ||
| lifeValue.destroy() | ||
| next() | ||
| } | ||
| }) | ||
@@ -287,0 +291,0 @@ } |
@@ -254,3 +254,3 @@ import BaseData from "./BaseData" | ||
| setPageAndSize(...args: Parameters<PaginationData['setPageAndSize']>) { | ||
| this.$module.pagination?.setPageAndSize(...args) | ||
| return this.$module.pagination?.setPageAndSize(...args) | ||
| } | ||
@@ -257,0 +257,0 @@ resetPagination(option?: boolean) { |
@@ -43,2 +43,9 @@ import { Life, upperCaseFirstChar } from '@complex-suite/utils' | ||
| }) | ||
| this.onLife('beforeDestroy', { | ||
| handler: () => { | ||
| if (this.$storage) { | ||
| this.$storage.stop() | ||
| } | ||
| } | ||
| }) | ||
| } | ||
@@ -45,0 +52,0 @@ this._triggerCreateLife('DefaultData', true, initOption) |
@@ -29,26 +29,28 @@ import PaginationData from "../module/PaginationData" | ||
| constructor(initOption: DefaultSelectEditInitOption<C, D, M>, parent?: DictionaryValue, modName?: string) { | ||
| if (initOption.select && initOption.select instanceof SelectData) { | ||
| // 浅拷贝入参,避免修改 initOption 污染调用方原对象(复用同一 initOption 创建多实例时异常) | ||
| const option = { ...initOption } | ||
| if (option.select && option.select instanceof SelectData) { | ||
| // 当select为SelectData时,额外初始化 | ||
| initOption.reload ??= initOption.select.$reload | ||
| if (initOption.pagination == undefined && initOption.select.$pagination) { | ||
| initOption.pagination = initOption.select.$pagination | ||
| option.reload ??= option.select.$reload | ||
| if (option.pagination == undefined && option.select.$pagination) { | ||
| option.pagination = option.select.$pagination | ||
| } | ||
| initOption.getData ??= function(...args) { | ||
| return (initOption.select as unknown as SelectData).loadData(...args) | ||
| option.getData ??= function(...args) { | ||
| return (option.select as unknown as SelectData).loadData(...args) | ||
| } | ||
| } | ||
| super(initOption, parent, modName) | ||
| this.cascader = initOption.cascader | ||
| super(option, parent, modName) | ||
| this.cascader = option.cascader | ||
| if (this.cascader == undefined) { | ||
| this.$select = (initOption.select ? (initOption.select instanceof SelectValue ? initOption.select : new SelectValue(initOption.select)) : new SelectValue({}))as unknown as (C extends undefined ? SelectValue<D> : CascaderValue<C, D>) | ||
| this.$select = (option.select ? (option.select instanceof SelectValue ? option.select : new SelectValue(option.select)) : new SelectValue({}))as unknown as (C extends undefined ? SelectValue<D> : CascaderValue<C, D>) | ||
| } else { | ||
| this.$select = (initOption.select ? (initOption.select instanceof CascaderValue ? initOption.select : new CascaderValue(initOption.select as CascaderValueInitOption<C>)) : new CascaderValue({ | ||
| this.$select = (option.select ? (option.select instanceof CascaderValue ? option.select : new CascaderValue(option.select as CascaderValueInitOption<C>)) : new CascaderValue({ | ||
| cascader: this.cascader | ||
| })) as unknown as (C extends undefined ? SelectValue<D> : CascaderValue<C, D>) | ||
| } | ||
| if (initOption.filter) { | ||
| this.$filter = initOption.filter | ||
| if (option.filter) { | ||
| this.$filter = option.filter | ||
| } | ||
| if (initOption.pagination) { | ||
| this.$pagination = initOption.pagination instanceof PaginationData ? initOption.pagination : new PaginationData(initOption.pagination) | ||
| if (option.pagination) { | ||
| this.$pagination = option.pagination instanceof PaginationData ? option.pagination : new PaginationData(option.pagination) | ||
| } | ||
@@ -55,0 +57,0 @@ } |
+1
-0
@@ -18,2 +18,3 @@ import type { LocalePack } from '@complex-suite/utils' | ||
| 'update.notDefined': 'Update function is not defined!', | ||
| 'update.stop': 'Stop update!', | ||
| 'track.noPoints': 'No track points available, cannot generate track!', | ||
@@ -20,0 +21,0 @@ 'track.insufficientPoints': (params) => |
+1
-0
@@ -18,2 +18,3 @@ import type { LocalePack } from '@complex-suite/utils' | ||
| 'update.notDefined': '触发更新函数未定义!', | ||
| 'update.stop': '停止更新!', | ||
| 'track.noPoints': '当前无轨迹点,无法生成轨迹!', | ||
@@ -20,0 +21,0 @@ 'track.insufficientPoints': (params: { minSize: number, size: number }) => `轨迹生成至少需要${params.minSize}个点,当前轨迹点仅为${params.size}个,无法生成轨迹!`, |
+21
-16
@@ -29,3 +29,3 @@ import { upperCaseFirstChar } from "@complex-suite/utils" | ||
| args: unknown[] | ||
| constructor(initOption: DependValueInitOption<D>, target: BaseData) { | ||
| constructor(initOption: DependValueInitOption<D>, target: BaseData, unbindCollector?: (() => void)[]) { | ||
| if (initOption instanceof Data) { | ||
@@ -40,3 +40,3 @@ this.data = initOption | ||
| if (initOption.bind) { | ||
| DependData.$bindDepend(target, initOption.data, initOption.bind.data, initOption.bind) | ||
| DependData.$bindDepend(target, initOption.data, initOption.bind.data, initOption.bind, unbindCollector) | ||
| } | ||
@@ -60,2 +60,3 @@ } | ||
| static $created = true | ||
| private unbindCollector: (() => void)[] = [] | ||
| // 基于激活状态绑定依赖 | ||
@@ -86,6 +87,6 @@ static $bindDependByActive(target: BaseData, depend: dependDataType, bind: dependBind, from: string, success: boolean, life: bindLife, unbind: () => void, active?: boolean) { | ||
| active, // 是否只在激活状态下触发 | ||
| }: dependBindOption = {}) { | ||
| }: dependBindOption = {}, unbind: dependUnbind) { | ||
| const simple = '$load' in depend | ||
| if (simple && life === 'update') { | ||
| return | ||
| return // simple 模式没有 update 生命周期 | ||
| } | ||
@@ -99,9 +100,2 @@ if (active == undefined && target.$active.auto) { | ||
| const currentStatus = simple ? depend.getLoad() : depend.getStatus(life) | ||
| const unbind: dependUnbind = function(lifeList?: string[]) { | ||
| for (const lifeName in lifeDict) { | ||
| if (lifeList == undefined || lifeList.includes(lifeName)) { | ||
| depend.offLife(lifeName, lifeDict[lifeName]) | ||
| } | ||
| } | ||
| } | ||
| lifeDict[successLifeName] = depend.onLife(successLifeName, { | ||
@@ -123,6 +117,16 @@ handler: () => { | ||
| } | ||
| static $bindDepend(target: BaseData, depend: dependDataType, bind: dependBind, option: dependBindOption = {}) { | ||
| static $bindDepend(target: BaseData, depend: dependDataType, bind: dependBind, option: dependBindOption = {}, unbindCollector?: (() => void)[]) { | ||
| const lifeDict: Record<string, string> = {} | ||
| this.$bindDependByLife(target, depend, bind, 'load', lifeDict, option) | ||
| this.$bindDependByLife(target, depend, bind, 'update', lifeDict, option) | ||
| const unbind: dependUnbind = function(lifeList?: string[]) { | ||
| for (const lifeName in lifeDict) { | ||
| if (lifeList == undefined || lifeList.includes(lifeName)) { | ||
| depend.offLife(lifeName, lifeDict[lifeName]) | ||
| } | ||
| } | ||
| } | ||
| this.$bindDependByLife(target, depend, bind, 'load', lifeDict, option, unbind) | ||
| this.$bindDependByLife(target, depend, bind, 'update', lifeDict, option, unbind) | ||
| if (unbindCollector) { | ||
| unbindCollector.push(unbind) | ||
| } | ||
| } | ||
@@ -141,3 +145,3 @@ order?: boolean | ||
| protected buildDependValue(valueInitOption: DependValueInitOption, target: BaseData): DependValue { | ||
| return new DependValue(valueInitOption, target) | ||
| return new DependValue(valueInitOption, target, this.unbindCollector) | ||
| } | ||
@@ -189,3 +193,4 @@ // 依序加载依赖 | ||
| if (option === true) { | ||
| // 此处后续考虑数据的解绑操作 | ||
| this.unbindCollector.forEach(unbind => unbind()) | ||
| this.unbindCollector = [] | ||
| } | ||
@@ -192,0 +197,0 @@ } |
@@ -129,2 +129,8 @@ import { Life } from "@complex-suite/utils" | ||
| handler(_lifeValue, beforeIndex: number) { | ||
| // 先移除自身当前位置,避免链式排序时重复插入 | ||
| const currentIndex = pageList.findIndex(value => value.$prop === orderValue.prop) | ||
| if (currentIndex > -1) { | ||
| pageList.splice(currentIndex, 1) | ||
| } | ||
| beforeIndex = pageList.findIndex(value => value.$prop === beforeProp) | ||
| life.trigger(orderValue.prop, beforeIndex) | ||
@@ -146,2 +152,8 @@ pageList.splice(beforeIndex, 0, targetValue) | ||
| handler(_lifeValue, afterIndex: number) { | ||
| // 先移除自身当前位置,避免链式排序时重复插入 | ||
| const currentIndex = pageList.findIndex(value => value.$prop === orderValue.prop) | ||
| if (currentIndex > -1) { | ||
| pageList.splice(currentIndex, 1) | ||
| } | ||
| afterIndex = pageList.findIndex(value => value.$prop === afterProp) | ||
| life.trigger(orderValue.prop, afterIndex + 1) | ||
@@ -330,7 +342,7 @@ pageList.splice(afterIndex + 1, 0, targetValue) | ||
| const dictionaryList = dictionaryValue.dictionary.getList(modName) | ||
| const observeList = dictionaryValue.dictionary.getObserveList(modName, dictionaryList, observe) | ||
| const childObserveList = dictionaryValue.dictionary.getObserveList(modName, dictionaryList, observe) | ||
| if (mod instanceof FormEdit) { | ||
| mod.$runtime.dictionary = dictionaryValue.dictionary | ||
| mod.$runtime.dictionaryList = dictionaryList | ||
| mod.$runtime.observeList = observeList | ||
| mod.$runtime.observeList = childObserveList | ||
| mod.$runtime.type = modName | ||
@@ -342,3 +354,3 @@ mod.$runtime.form = new FormValue() | ||
| mod.$runtime.dictionaryList = dictionaryList | ||
| mod.$runtime.observeList = observeList | ||
| mod.$runtime.observeList = childObserveList | ||
| mod.$runtime.type = modName | ||
@@ -345,0 +357,0 @@ mod.$runtime.formList = [] |
@@ -76,2 +76,5 @@ import { getNum } from '@complex-suite/utils' | ||
| * 设置总数 | ||
| * 注意: 此方法可能多次触发 _syncData(setCount 自身 + _autoCountTotal 内部 + 可能的 setPage), | ||
| * 这是预期行为。_syncData 的实现方应在接收端统一通过 nextTick/Promise.then 合并多次同步请求, | ||
| * 避免冗余渲染。 | ||
| * @param {number} num 总数 | ||
@@ -112,3 +115,3 @@ */ | ||
| */ | ||
| setPage(current: number, unTriggerCurrentLife?: boolean) { | ||
| setPage(current: number, unTriggerCurrentLife?: boolean): boolean { | ||
| const total = this.getTotal() | ||
@@ -126,3 +129,5 @@ if (current < 1) { | ||
| } | ||
| return true | ||
| } | ||
| return false | ||
| } | ||
@@ -138,14 +143,20 @@ /** | ||
| * 更改页面条数 | ||
| * 注意: 此方法可能多次触发 _syncData(setSize 自身 + _autoCountTotal 内部), | ||
| * 这是预期行为。_syncData 的实现方应在接收端统一通过 nextTick/Promise.then 合并多次同步请求。 | ||
| * @param {number} size size参数 | ||
| */ | ||
| setSize(size: number, unCountCurrent?: boolean, unTriggerSizeLife?: boolean) { | ||
| this.size.data = size | ||
| this._autoCountTotal(unCountCurrent, true) | ||
| if (!unTriggerSizeLife) { | ||
| this.triggerLife('change', this, 'size', { | ||
| size: size, | ||
| page: this.getPage() | ||
| }) | ||
| setSize(size: number, unCountCurrent?: boolean, unTriggerSizeLife?: boolean): boolean { | ||
| if (this.size.data !== size) { | ||
| this.size.data = size | ||
| this._autoCountTotal(unCountCurrent, true) | ||
| if (!unTriggerSizeLife) { | ||
| this.triggerLife('change', this, 'size', { | ||
| size: size, | ||
| page: this.getPage() | ||
| }) | ||
| } | ||
| this._syncData(true, 'setSize') | ||
| return true | ||
| } | ||
| this._syncData(true, 'setSize') | ||
| return false | ||
| } | ||
@@ -164,8 +175,10 @@ /** | ||
| */ | ||
| setPageAndSize(data: { page: number, size: number }, unTriggerCurrentAndSizeLife?: boolean) { | ||
| this.setSize(data.size, true) | ||
| this.setPage(data.page) | ||
| if (!unTriggerCurrentAndSizeLife) { | ||
| setPageAndSize(data: { page: number, size: number }, unTriggerCurrentAndSizeLife?: boolean): { page: boolean, size: boolean, changed: boolean } { | ||
| const sizeChanged = this.setSize(data.size, true) | ||
| const pageChanged = this.setPage(data.page) | ||
| const changed = sizeChanged || pageChanged | ||
| if (!unTriggerCurrentAndSizeLife && changed) { | ||
| this.triggerLife('change', this, 'currentAndSize', data) | ||
| } | ||
| return { page: pageChanged, size: sizeChanged, changed } | ||
| } | ||
@@ -172,0 +185,0 @@ /** |
@@ -75,3 +75,4 @@ import Data from '../data/Data' | ||
| } | ||
| return undefined | ||
| // 配置缺失时返回 false 而非 undefined,避免 reset(undefined) 中 undefined !== false 为 true 导致意外执行重置 | ||
| return false | ||
| } | ||
@@ -78,0 +79,0 @@ /** |
@@ -190,4 +190,4 @@ import { deepCloneData, getType } from "@complex-suite/utils" | ||
| const form = new FormValue() | ||
| this.$runtime = { | ||
| ing: true, | ||
| const runtime = { | ||
| ing: true as true | undefined, | ||
| dictionary: dictionaryList, | ||
@@ -197,10 +197,14 @@ list: observeList, | ||
| } | ||
| this.$runtime = runtime | ||
| // 初始化form | ||
| this.parseData(dictionaryList, form, this.$type, undefined, 'init').then(() => { | ||
| delete this.$runtime?.ing | ||
| if (this.$runtime !== runtime) return | ||
| delete runtime.ing | ||
| this.triggerLife('inited', this, true) | ||
| }).catch((error) => { | ||
| delete this.$runtime?.ing | ||
| if (this.$runtime !== runtime) return | ||
| delete runtime.ing | ||
| this.triggerLife('inited', this, false, error) | ||
| }).finally(() => { | ||
| if (this.$runtime !== runtime) return | ||
| // 因为检索不能作为强关联关系,因此失败也进行赋值操作 | ||
@@ -207,0 +211,0 @@ if (this.$observe) { |
@@ -173,3 +173,3 @@ import { isPromise } from '@complex-suite/utils' | ||
| }).catch(err => { | ||
| this.$exportMsg('stop update!', 'log') | ||
| this.$exportMsg(dataLocale.t('update.stop'), 'log') | ||
| console.error(err) | ||
@@ -176,0 +176,0 @@ this.clear() |
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
368488
1.71%7599
0.78%+ Added
+ Added
- Removed
- Removed
Updated
Updated