Преглед на файлове

fix: fix lint && typecheck

xingyu4j преди 3 седмици
родител
ревизия
0c1b737325
променени са 23 файла, в които са добавени 190 реда и са изтрити 215 реда
  1. 0 5
      .changeset/element-plus-theme-switch.md
  2. 0 5
      .changeset/page-auto-content-height.md
  3. 0 5
      .changeset/small-moons-hunt.md
  4. 0 5
      .changeset/tree-default-value.md
  5. 44 48
      packages/@core/base/shared/src/cache/README.md
  6. 17 17
      packages/@core/base/shared/src/cache/__tests__/storage-manager.test.ts
  7. 8 8
      packages/@core/base/shared/src/cache/indexeddb-driver.ts
  8. 6 6
      packages/@core/base/shared/src/cache/local-storage-driver.ts
  9. 3 3
      packages/@core/base/shared/src/cache/memory-storage-driver.ts
  10. 5 5
      packages/@core/base/shared/src/cache/storage-manager.ts
  11. 2 2
      packages/@core/base/shared/src/cache/types.ts
  12. 3 1
      packages/@core/base/shared/src/utils/__tests__/state-handler.test.ts
  13. 4 2
      packages/@core/base/shared/src/utils/__tests__/util.test.ts
  14. 2 2
      packages/@core/base/shared/src/utils/state-handler.ts
  15. 2 6
      packages/@core/preferences/src/preferences.ts
  16. 6 3
      packages/effects/common-ui/src/components/page/page.vue
  17. 36 35
      packages/effects/plugins/src/tiptap/extensions.ts
  18. 1 1
      packages/effects/plugins/src/vxe-table/api.ts
  19. 20 20
      packages/effects/plugins/src/vxe-table/types.ts
  20. 17 16
      packages/effects/plugins/src/vxe-table/use-viewed-row.ts
  21. 3 3
      packages/effects/plugins/src/vxe-table/use-vxe-grid.vue
  22. 9 15
      packages/effects/request/src/request-client/request-client.test.ts
  23. 2 2
      playground/src/views/demos/features/preferences-extension/index.vue

+ 0 - 5
.changeset/element-plus-theme-switch.md

@@ -1,5 +0,0 @@
----
-"@vben/layouts": patch
----
-
-fix: update primary color when toggling dark/light mode with custom theme

+ 0 - 5
.changeset/page-auto-content-height.md

@@ -1,5 +0,0 @@
----
-"@vben/common-ui": patch
----
-
-fix: skip fixed footer height in auto-content-height calculation

+ 0 - 5
.changeset/small-moons-hunt.md

@@ -1,5 +0,0 @@
----
-"@vben/icons": patch
----
-
-fix: guard svg icon loading during docs SSR

+ 0 - 5
.changeset/tree-default-value.md

@@ -1,5 +0,0 @@
----
-"@vben-core/shadcn-ui": patch
----
-
-fix: preserve tree default value when treeData starts empty

+ 44 - 48
packages/@core/base/shared/src/cache/README.md

@@ -1,7 +1,6 @@
 # Cache 模块
 
-基于**策略模式**的异步存储管理方案,支持多种存储后端(localStorage、IndexedDB、Memory),提供统一的 API
-接口。
+基于**策略模式**的异步存储管理方案,支持多种存储后端(localStorage、IndexedDB、Memory),提供统一的 API 接口。
 
 ## 架构设计
 
@@ -22,11 +21,11 @@
 
 **分层职责:**
 
-| 层级               | 职责                         |
-|------------------|----------------------------|
+| 层级             | 职责                                         |
+| ---------------- | -------------------------------------------- |
 | `StorageManager` | 命名空间前缀隔离、TTL 过期检查、统一对外 API |
-| `IStorageDriver` | 纯粹的 KV 存取抽象接口              |
-| 各 Driver 实现      | 对接具体存储引擎,不感知前缀和 TTL        |
+| `IStorageDriver` | 纯粹的 KV 存取抽象接口                       |
+| 各 Driver 实现   | 对接具体存储引擎,不感知前缀和 TTL           |
 
 ---
 
@@ -35,9 +34,9 @@
 ### 基本使用(默认 localStorage)
 
 ```typescript
-import {StorageManager} from '@vben-core/shared/cache';
+import { StorageManager } from '@vben-core/shared/cache';
 
-const cache = new StorageManager({prefix: 'myapp'});
+const cache = new StorageManager({ prefix: 'myapp' });
 // 使用 IndexedDB
 //new StorageManager({ driver: new IndexedDBDriver(), prefix: 'app' });
 
@@ -48,14 +47,14 @@ const cache = new StorageManager({prefix: 'myapp'});
 //new StorageManager({ driver: new MemoryStorageDriver(), prefix: 'test' });
 
 // 存储数据
-await cache.setItem('user', {name: '张三', age: 28});
+await cache.setItem('user', { name: '张三', age: 28 });
 
 // 读取数据
 const user = await cache.getItem('user');
 // => { name: '张三', age: 28 }
 
 // 带默认值读取
-const settings = await cache.getItem('settings', {theme: 'light'});
+const settings = await cache.getItem('settings', { theme: 'light' });
 // 如果不存在,返回 { theme: 'light' }
 
 // 删除数据
@@ -68,7 +67,7 @@ await cache.clear();
 ### 带 TTL 过期
 
 ```typescript
-const cache = new StorageManager({prefix: 'session'});
+const cache = new StorageManager({ prefix: 'session' });
 
 // 设置 5 分钟后过期(TTL 单位为毫秒)
 await cache.setItem('token', 'abc123', 5 * 60 * 1000);
@@ -191,20 +190,20 @@ const cache = new StorageManager({
 new StorageManager(options?: StorageManagerOptions)
 ```
 
-| 参数       | 类型               | 默认值                        | 说明           |
-|----------|------------------|----------------------------|--------------|
-| `driver` | `IStorageDriver` | `new LocalStorageDriver()` | 存储驱动实例       |
-| `prefix` | `string`         | `''`                       | 键前缀,用于命名空间隔离 |
+| 参数 | 类型 | 默认值 | 说明 |
+| --- | --- | --- | --- |
+| `driver` | `IStorageDriver` | `new LocalStorageDriver()` | 存储驱动实例 |
+| `prefix` | `string` | `''` | 键前缀,用于命名空间隔离 |
 
 #### 方法
 
-| 方法                  | 签名                                                                      | 说明                |
-|---------------------|-------------------------------------------------------------------------|-------------------|
-| `getItem`           | `getItem<T>(key: string, defaultValue?: T \| null): Promise<T \| null>` | 获取存储项,过期或不存在返回默认值 |
-| `setItem`           | `setItem<T>(key: string, value: T, ttl?: number): Promise<void>`        | 设置存储项,可选 TTL(毫秒)  |
-| `removeItem`        | `removeItem(key: string): Promise<void>`                                | 删除指定存储项           |
-| `clear`             | `clear(): Promise<void>`                                                | 清除当前前缀下所有存储项      |
-| `clearExpiredItems` | `clearExpiredItems(): Promise<void>`                                    | 主动清理所有过期项         |
+| 方法 | 签名 | 说明 |
+| --- | --- | --- |
+| `getItem` | `getItem<T>(key: string, defaultValue?: T \| null): Promise<T \| null>` | 获取存储项,过期或不存在返回默认值 |
+| `setItem` | `setItem<T>(key: string, value: T, ttl?: number): Promise<void>` | 设置存储项,可选 TTL(毫秒) |
+| `removeItem` | `removeItem(key: string): Promise<void>` | 删除指定存储项 |
+| `clear` | `clear(): Promise<void>` | 清除当前前缀下所有存储项 |
+| `clearExpiredItems` | `clearExpiredItems(): Promise<void>` | 主动清理所有过期项 |
 
 ---
 
@@ -233,7 +232,7 @@ interface IStorageDriver {
 ### 自定义 Driver
 
 ```typescript
-import type {IStorageDriver} from '@vben-core/shared/cache';
+import type { IStorageDriver } from '@vben-core/shared/cache';
 
 class CookieStorageDriver implements IStorageDriver {
   async getItem<T>(key: string): Promise<null | T> {
@@ -301,11 +300,11 @@ function createStorageManager(prefix: string) {
 
 ```typescript
 // 不同模块使用不同前缀,互不干扰
-const userCache = new StorageManager({prefix: 'user'});
-const configCache = new StorageManager({prefix: 'config'});
+const userCache = new StorageManager({ prefix: 'user' });
+const configCache = new StorageManager({ prefix: 'config' });
 
-await userCache.setItem('profile', {name: '张三'});
-await configCache.setItem('profile', {theme: 'dark'});
+await userCache.setItem('profile', { name: '张三' });
+await configCache.setItem('profile', { theme: 'dark' });
 
 // 各自独立
 await userCache.getItem('profile'); // => { name: '张三' }
@@ -356,24 +355,24 @@ interface StorageItem<T> {
 
 采用**惰性删除 + 主动清理**双重策略:
 
-| 策略   | 触发时机                     | 说明                  |
-|------|--------------------------|---------------------|
-| 惰性删除 | 调用 `getItem` 时           | 读取时检查过期,过期则删除并返回默认值 |
+| 策略 | 触发时机 | 说明 |
+| --- | --- | --- |
+| 惰性删除 | 调用 `getItem` 时 | 读取时检查过期,过期则删除并返回默认值 |
 | 主动清理 | 调用 `clearExpiredItems` 时 | 遍历所有带前缀的 key,删除已过期项 |
 
 ---
 
 ## 各 Driver 对比
 
-| 特性    | LocalStorageDriver | IndexedDBDriver | MemoryStorageDriver |
-|-------|--------------------|-----------------|---------------------|
-| 持久化   | ✅                  | ✅               | ❌                   |
-| 容量    | 5-10 MB            | 数百 MB+          | 受内存限制               |
-| 速度    | 快(同步)              | 中等(异步 I/O)      | 最快                  |
-| 数据类型  | 仅 JSON 可序列化        | 结构化克隆           | 任意 JS 对象            |
-| 浏览器支持 | 所有现代浏览器            | 所有现代浏览器         | 任意环境                |
-| 阻塞主线程 | 是                  | 否               | 否                   |
-| 适用场景  | 配置、Token、小数据       | 离线缓存、大数据        | 测试、SSR              |
+| 特性       | LocalStorageDriver  | IndexedDBDriver  | MemoryStorageDriver |
+| ---------- | ------------------- | ---------------- | ------------------- |
+| 持久化     | ✅                  | ✅               | ❌                  |
+| 容量       | 5-10 MB             | 数百 MB+         | 受内存限制          |
+| 速度       | 快(同步)          | 中等(异步 I/O) | 最快                |
+| 数据类型   | 仅 JSON 可序列化    | 结构化克隆       | 任意 JS 对象        |
+| 浏览器支持 | 所有现代浏览器      | 所有现代浏览器   | 任意环境            |
+| 阻塞主线程 | 是                  | 否               | 否                  |
+| 适用场景   | 配置、Token、小数据 | 离线缓存、大数据 | 测试、SSR           |
 
 ---
 
@@ -388,12 +387,12 @@ class PreferenceManager {
 
   constructor() {
     this.cache = new StorageManager();
-    this.state = reactive<Preferences>({...defaultPreferences});
+    this.state = reactive<Preferences>({ ...defaultPreferences });
   }
 
-  initPreferences = async ({namespace}) => {
+  initPreferences = async ({ namespace }) => {
     // 用应用命名空间重新初始化
-    this.cache = new StorageManager({prefix: namespace});
+    this.cache = new StorageManager({ prefix: namespace });
 
     // 从缓存加载偏好设置
     const cached = await this.cache.getItem<Preferences>('preferences');
@@ -406,8 +405,7 @@ class PreferenceManager {
 
 ## 注意事项
 
-1. **所有方法都是异步的** — 即使底层是同步的 localStorage,API 也返回 Promise,确保切换 Driver
-   时无需改动调用方。
+1. **所有方法都是异步的** — 即使底层是同步的 localStorage,API 也返回 Promise,确保切换 Driver 时无需改动调用方。
 
 2. **TTL 单位是毫秒** — `setItem('key', value, 60000)` 表示 60 秒后过期。
 
@@ -415,8 +413,6 @@ class PreferenceManager {
 
 4. **前缀隔离是逻辑隔离** — `clear()` 只清除当前前缀下的数据,不影响其他前缀或无前缀的数据。
 
-5. **错误处理** — LocalStorageDriver 在 JSON 解析失败时自动清除损坏数据;
-   `PreferenceManager.saveToCache` 内部 try-catch 防止未捕获异常。
+5. **错误处理** — LocalStorageDriver 在 JSON 解析失败时自动清除损坏数据; `PreferenceManager.saveToCache` 内部 try-catch 防止未捕获异常。
 
-6. **IndexedDB 版本升级** — 如果需要修改 objectStore 结构,需要递增 `dbVersion`。当前实现在
-   `upgradeneeded` 事件中自动创建 objectStore。
+6. **IndexedDB 版本升级** — 如果需要修改 objectStore 结构,需要递增 `dbVersion`。当前实现在 `upgradeneeded` 事件中自动创建 objectStore。

+ 17 - 17
packages/@core/base/shared/src/cache/__tests__/storage-manager.test.ts

@@ -1,6 +1,6 @@
 import { beforeEach, describe, expect, it, vi } from 'vitest';
 
-import {MemoryStorageDriver} from '../memory-storage-driver';
+import { MemoryStorageDriver } from '../memory-storage-driver';
 import { StorageManager } from '../storage-manager';
 
 describe('storageManager', () => {
@@ -15,7 +15,7 @@ describe('storageManager', () => {
   });
 
   it('should set and get an item', async () => {
-    await storageManager.setItem('user', {age: 30, name: 'John Doe'});
+    await storageManager.setItem('user', { age: 30, name: 'John Doe' });
     const user = await storageManager.getItem('user');
     expect(user).toEqual({ age: 30, name: 'John Doe' });
   });
@@ -29,22 +29,22 @@ describe('storageManager', () => {
   });
 
   it('should remove an item', async () => {
-    await storageManager.setItem('user', {age: 30, name: 'John Doe'});
+    await storageManager.setItem('user', { age: 30, name: 'John Doe' });
     await storageManager.removeItem('user');
     const user = await storageManager.getItem('user');
     expect(user).toBeNull();
   });
 
   it('should clear all items with the prefix', async () => {
-    await storageManager.setItem('user1', {age: 30, name: 'John Doe'});
-    await storageManager.setItem('user2', {age: 25, name: 'Jane Doe'});
+    await storageManager.setItem('user1', { age: 30, name: 'John Doe' });
+    await storageManager.setItem('user2', { age: 25, name: 'Jane Doe' });
     await storageManager.clear();
     expect(await storageManager.getItem('user1')).toBeNull();
     expect(await storageManager.getItem('user2')).toBeNull();
   });
 
   it('should clear expired items', async () => {
-    await storageManager.setItem('user', {age: 30, name: 'John Doe'}, 1000); // 1秒过期
+    await storageManager.setItem('user', { age: 30, name: 'John Doe' }, 1000); // 1秒过期
     vi.advanceTimersByTime(1001); // 快进时间
     await storageManager.clearExpiredItems();
     const user = await storageManager.getItem('user');
@@ -52,7 +52,7 @@ describe('storageManager', () => {
   });
 
   it('should not clear non-expired items', async () => {
-    await storageManager.setItem('user', {age: 30, name: 'John Doe'}, 10_000); // 10秒过期
+    await storageManager.setItem('user', { age: 30, name: 'John Doe' }, 10_000); // 10秒过期
     vi.advanceTimersByTime(5000); // 快进时间
     await storageManager.clearExpiredItems();
     const user = await storageManager.getItem('user');
@@ -65,36 +65,36 @@ describe('storageManager', () => {
   });
 
   it('should overwrite existing items', async () => {
-    await storageManager.setItem('user', {age: 30, name: 'John Doe'});
-    await storageManager.setItem('user', {age: 25, name: 'Jane Doe'});
+    await storageManager.setItem('user', { age: 30, name: 'John Doe' });
+    await storageManager.setItem('user', { age: 25, name: 'Jane Doe' });
     const user = await storageManager.getItem('user');
     expect(user).toEqual({ age: 25, name: 'Jane Doe' });
   });
 
   it('should handle items without expiry correctly', async () => {
-    await storageManager.setItem('user', {age: 30, name: 'John Doe'});
+    await storageManager.setItem('user', { age: 30, name: 'John Doe' });
     vi.advanceTimersByTime(5000);
     const user = await storageManager.getItem('user');
     expect(user).toEqual({ age: 30, name: 'John Doe' });
   });
 
   it('should remove expired items when accessed', async () => {
-    await storageManager.setItem('user', {age: 30, name: 'John Doe'}, 1000); // 1秒过期
+    await storageManager.setItem('user', { age: 30, name: 'John Doe' }, 1000); // 1秒过期
     vi.advanceTimersByTime(1001); // 快进时间
     const user = await storageManager.getItem('user');
     expect(user).toBeNull();
   });
 
   it('should not remove non-expired items when accessed', async () => {
-    await storageManager.setItem('user', {age: 30, name: 'John Doe'}, 10_000); // 10秒过期
+    await storageManager.setItem('user', { age: 30, name: 'John Doe' }, 10_000); // 10秒过期
     vi.advanceTimersByTime(5000); // 快进时间
     const user = await storageManager.getItem('user');
     expect(user).toEqual({ age: 30, name: 'John Doe' });
   });
 
   it('should handle multiple items with different expiry times', async () => {
-    await storageManager.setItem('user1', {age: 30, name: 'John Doe'}, 1000); // 1秒过期
-    await storageManager.setItem('user2', {age: 25, name: 'Jane Doe'}, 2000); // 2秒过期
+    await storageManager.setItem('user1', { age: 30, name: 'John Doe' }, 1000); // 1秒过期
+    await storageManager.setItem('user2', { age: 25, name: 'Jane Doe' }, 2000); // 2秒过期
     vi.advanceTimersByTime(1500); // 快进时间
     await storageManager.clearExpiredItems();
     const user1 = await storageManager.getItem('user1');
@@ -104,7 +104,7 @@ describe('storageManager', () => {
   });
 
   it('should handle items with no expiry', async () => {
-    await storageManager.setItem('user', {age: 30, name: 'John Doe'});
+    await storageManager.setItem('user', { age: 30, name: 'John Doe' });
     vi.advanceTimersByTime(10_000); // 快进时间
     await storageManager.clearExpiredItems();
     const user = await storageManager.getItem('user');
@@ -112,8 +112,8 @@ describe('storageManager', () => {
   });
 
   it('should clear all items correctly', async () => {
-    await storageManager.setItem('user1', {age: 30, name: 'John Doe'});
-    await storageManager.setItem('user2', {age: 25, name: 'Jane Doe'});
+    await storageManager.setItem('user1', { age: 30, name: 'John Doe' });
+    await storageManager.setItem('user2', { age: 25, name: 'Jane Doe' });
     await storageManager.clear();
     const user1 = await storageManager.getItem('user1');
     const user2 = await storageManager.getItem('user2');

+ 8 - 8
packages/@core/base/shared/src/cache/indexeddb-driver.ts

@@ -1,4 +1,4 @@
-import type {IStorageDriver} from './types';
+import type { IStorageDriver } from './types';
 
 interface IndexedDBDriverOptions {
   /** 数据库名称 */
@@ -20,10 +20,10 @@ class IndexedDBDriver implements IStorageDriver {
   private storeName: string;
 
   constructor({
-                dbName = 'vben-storage',
-                dbVersion = 1,
-                storeName = 'kv-store',
-              }: IndexedDBDriverOptions = {}) {
+    dbName = 'vben-storage',
+    dbVersion = 1,
+    storeName = 'kv-store',
+  }: IndexedDBDriverOptions = {}) {
     this.dbName = dbName;
     this.dbVersion = dbVersion;
     this.storeName = storeName;
@@ -87,7 +87,7 @@ class IndexedDBDriver implements IStorageDriver {
     });
   }
 
-  async setItem<T>(key: string, value: T): Promise<void> {
+  async setItem(key: string, value: unknown): Promise<void> {
     const db = await this.getDB();
     return new Promise((resolve, reject) => {
       const tx = db.transaction(this.storeName, 'readwrite');
@@ -133,5 +133,5 @@ class IndexedDBDriver implements IStorageDriver {
   }
 }
 
-export {IndexedDBDriver};
-export type {IndexedDBDriverOptions};
+export { IndexedDBDriver };
+export type { IndexedDBDriverOptions };

+ 6 - 6
packages/@core/base/shared/src/cache/local-storage-driver.ts

@@ -1,4 +1,4 @@
-import type {IStorageDriver} from './types';
+import type { IStorageDriver } from './types';
 
 type StorageType = 'localStorage' | 'sessionStorage';
 
@@ -15,8 +15,8 @@ class LocalStorageDriver implements IStorageDriver {
   private storage: Storage;
 
   constructor({
-                storageType = 'localStorage',
-              }: LocalStorageDriverOptions = {}) {
+    storageType = 'localStorage',
+  }: LocalStorageDriverOptions = {}) {
     if (typeof window === 'undefined') {
       // eslint-disable-next-line unicorn/prefer-type-error -- not a type check, it's an environment check
       throw new Error(
@@ -62,10 +62,10 @@ class LocalStorageDriver implements IStorageDriver {
     this.storage.removeItem(key);
   }
 
-  async setItem<T>(key: string, value: T): Promise<void> {
+  async setItem(key: string, value: unknown): Promise<void> {
     this.storage.setItem(key, JSON.stringify(value));
   }
 }
 
-export {LocalStorageDriver};
-export type {LocalStorageDriverOptions};
+export { LocalStorageDriver };
+export type { LocalStorageDriverOptions };

+ 3 - 3
packages/@core/base/shared/src/cache/memory-storage-driver.ts

@@ -1,4 +1,4 @@
-import type {IStorageDriver} from './types';
+import type { IStorageDriver } from './types';
 
 /**
  * 内存存储驱动
@@ -24,9 +24,9 @@ class MemoryStorageDriver implements IStorageDriver {
     this.store.delete(key);
   }
 
-  async setItem<T>(key: string, value: T): Promise<void> {
+  async setItem(key: string, value: unknown): Promise<void> {
     this.store.set(key, value);
   }
 }
 
-export {MemoryStorageDriver};
+export { MemoryStorageDriver };

+ 5 - 5
packages/@core/base/shared/src/cache/storage-manager.ts

@@ -4,8 +4,8 @@ import type {
   StorageManagerOptions,
 } from './types';
 
-import {LocalStorageDriver} from './local-storage-driver';
-import {MemoryStorageDriver} from './memory-storage-driver';
+import { LocalStorageDriver } from './local-storage-driver';
+import { MemoryStorageDriver } from './memory-storage-driver';
 
 /**
  * 存储管理器(策略模式)
@@ -17,7 +17,7 @@ class StorageManager {
   private driver: IStorageDriver;
   private prefix: string;
 
-  constructor({driver, prefix = ''}: StorageManagerOptions = {}) {
+  constructor({ driver, prefix = '' }: StorageManagerOptions = {}) {
     this.driver = driver || this.createDefaultDriver();
     this.prefix = prefix;
     if (!this.prefix && this.driver instanceof LocalStorageDriver) {
@@ -106,10 +106,10 @@ class StorageManager {
    * @param value 值
    * @param ttl 存活时间(毫秒)
    */
-  async setItem<T>(key: string, value: T, ttl?: number): Promise<void> {
+  async setItem(key: string, value: unknown, ttl?: number): Promise<void> {
     const fullKey = this.getFullKey(key);
     const expiry = ttl ? Date.now() + ttl : undefined;
-    const item: StorageItem<T> = { expiry, value };
+    const item: StorageItem<unknown> = { expiry, value };
     await this.driver.setItem(fullKey, item);
   }
 

+ 2 - 2
packages/@core/base/shared/src/cache/types.ts

@@ -17,7 +17,7 @@ interface IStorageDriver {
   removeItem(key: string): Promise<void>;
 
   /** 设置存储项 */
-  setItem<T>(key: string, value: T): Promise<void>;
+  setItem(key: string, value: unknown): Promise<void>;
 }
 
 /**
@@ -36,4 +36,4 @@ interface StorageManagerOptions {
   prefix?: string;
 }
 
-export type {IStorageDriver, StorageItem, StorageManagerOptions};
+export type { IStorageDriver, StorageItem, StorageManagerOptions };

+ 3 - 1
packages/@core/base/shared/src/utils/__tests__/state-handler.test.ts

@@ -34,7 +34,9 @@ describe('stateHandler', () => {
     }, 10);
 
     // 等待过程中,期望 Promise 被 reject
-    await expect(handler.waitForCondition()).rejects.toThrow();
+    await expect(handler.waitForCondition()).rejects.toThrow(
+      'Condition was set to false',
+    );
     expect(handler.isConditionTrue()).toBe(false);
   });
 

+ 4 - 2
packages/@core/base/shared/src/utils/__tests__/util.test.ts

@@ -138,8 +138,10 @@ describe('getNestedValue', () => {
     expect(result).toBe(2);
   });
 
-  it('should return the entire object if path is empty', () => {
-    expect(() => getNestedValue(data, '')()).toThrow();
+  it('should throw if path is empty', () => {
+    expect(() => getNestedValue(data, '')).toThrow(
+      'Path must be a non-empty string',
+    );
   });
 
   it('should handle paths with array indexes', () => {

+ 2 - 2
packages/@core/base/shared/src/utils/state-handler.ts

@@ -1,6 +1,6 @@
 export class StateHandler {
   private condition: boolean = false;
-  private rejectCondition: (() => void) | null = null;
+  private rejectCondition: ((reason?: Error) => void) | null = null;
   private resolveCondition: (() => void) | null = null;
 
   isConditionTrue(): boolean {
@@ -16,7 +16,7 @@ export class StateHandler {
   setConditionFalse() {
     this.condition = false;
     if (this.rejectCondition) {
-      this.rejectCondition();
+      this.rejectCondition(new Error('Condition was set to false'));
       this.clearPromises();
     }
   }

+ 2 - 6
packages/@core/preferences/src/preferences.ts

@@ -43,7 +43,7 @@ class PreferenceManager {
     this.cache = new StorageManager();
     // 构造函数不再同步读取缓存,使用默认值初始化
     // 真正的缓存加载在 initPreferences 中完成(已经是 async)
-    this.state = reactive<Preferences>({...defaultPreferences});
+    this.state = reactive<Preferences>({ ...defaultPreferences });
     this.debouncedSave = useDebounceFn(() => this.saveToCache(), 150);
   }
 
@@ -180,11 +180,7 @@ class PreferenceManager {
    * 更新扩展偏好设置
    * @param updates - 要更新的扩展偏好设置
    */
-  updateCustomPreferences = <
-    TCustomPreferences extends object = CustomPreferencesRecord,
-  >(
-    updates: DeepPartial<TCustomPreferences>,
-  ) => {
+  updateCustomPreferences = (updates: DeepPartial<object>) => {
     if (!this.customPreferencesExtension) {
       return;
     }

+ 6 - 3
packages/effects/common-ui/src/components/page/page.vue

@@ -12,8 +12,11 @@ defineOptions({
   name: 'Page',
 });
 
-const { autoContentHeight = false, heightOffset = 0, footerFixed = false } =
-  defineProps<PageProps>();
+const {
+  autoContentHeight = false,
+  heightOffset = 0,
+  footerFixed = false,
+} = defineProps<PageProps>();
 
 const headerHeight = ref(0);
 const footerHeight = ref(0);
@@ -40,7 +43,7 @@ async function calcContentHeight() {
   await nextTick();
   headerHeight.value = headerRef.value?.offsetHeight || 0;
 
-  footerHeight.value = footerFixed ? 0 : (footerRef.value?.offsetHeight || 0);
+  footerHeight.value = footerFixed ? 0 : footerRef.value?.offsetHeight || 0;
 
   setTimeout(() => {
     shouldAutoHeight.value = true;

+ 36 - 35
packages/effects/plugins/src/tiptap/extensions.ts

@@ -66,6 +66,7 @@ function findPlaceholderPos(doc: ProseMirrorNode, blobUrl: string): number {
       found = offset;
       return false;
     }
+    return true;
   });
   return found;
 }
@@ -272,30 +273,30 @@ function createCustomImage(
         ...this.parent?.(),
         uploadImage:
           () =>
-            ({ editor: cmdEditor }: { editor: CoreEditor }) => {
-              const input = document.createElement('input');
-              input.type = 'file';
-              input.accept = imageUpload.accept ?? DEFAULT_ACCEPT;
-              input.style.display = 'none';
-
-              input.addEventListener('change', () => {
-                const file = input.files?.[0];
-                if (!file) return;
-
-                const error = validateFile(file, imageUpload);
-                if (error) {
-                  handleUploadError(new Error(error), imageUpload);
-                  return;
-                }
+          ({ editor: cmdEditor }: { editor: CoreEditor }) => {
+            const input = document.createElement('input');
+            input.type = 'file';
+            input.accept = imageUpload.accept ?? DEFAULT_ACCEPT;
+            input.style.display = 'none';
 
-                createUploadProcess(cmdEditor, file, imageUpload, blobUrlTracker);
-                input.remove();
-              });
+            input.addEventListener('change', () => {
+              const file = input.files?.[0];
+              if (!file) return;
 
-              document.body.append(input);
-              input.click();
-              return true;
-            },
+              const error = validateFile(file, imageUpload);
+              if (error) {
+                handleUploadError(new Error(error), imageUpload);
+                return;
+              }
+
+              createUploadProcess(cmdEditor, file, imageUpload, blobUrlTracker);
+              input.remove();
+            });
+
+            document.body.append(input);
+            input.click();
+            return true;
+          },
       };
     },
 
@@ -428,20 +429,20 @@ export function createDefaultTiptapExtensions(
     }),
     options.imageUpload
       ? createCustomImage(
-        options.imageUpload,
-        options._blobUrlTracker,
-      ).configure({
-        allowBase64: true,
-        HTMLAttributes: {
-          class: 'vben-tiptap__image',
-        },
-      })
+          options.imageUpload,
+          options._blobUrlTracker,
+        ).configure({
+          allowBase64: true,
+          HTMLAttributes: {
+            class: 'vben-tiptap__image',
+          },
+        })
       : Image.configure({
-        allowBase64: true,
-        HTMLAttributes: {
-          class: 'vben-tiptap__image',
-        },
-      }),
+          allowBase64: true,
+          HTMLAttributes: {
+            class: 'vben-tiptap__image',
+          },
+        }),
     Placeholder.configure({
       placeholder: options.placeholder ?? $t('ui.tiptap.placeholder'),
     }),

+ 1 - 1
packages/effects/plugins/src/vxe-table/api.ts

@@ -6,7 +6,7 @@ import type {
 } from '@vben-core/form-ui';
 
 import type { VxeGridProps } from './types';
-import type {ViewedRowHelper} from './use-viewed-row';
+import type { ViewedRowHelper } from './use-viewed-row';
 
 import { toRaw } from 'vue';
 

+ 20 - 20
packages/effects/plugins/src/vxe-table/types.ts

@@ -75,29 +75,29 @@ interface ViewedRowPersistBase {
  */
 export type ViewedRowPersistOptions =
   | ({
-  /** IndexedDB 数据库名称,默认 'viewed-table-db' */
-  dbName?: string;
-  /** IndexedDB 数据库版本,默认 1 */
-  dbVersion?: number;
-  /** 存储 key / prefix(必传) */
-  key: string;
-  /** IndexedDB 对象存储名称,默认 'viewed-table-row' */
-  storeName?: string;
-  type: 'indexedDB';
-} & ViewedRowPersistBase)
+      /** IndexedDB 数据库名称,默认 'viewed-table-db' */
+      dbName?: string;
+      /** IndexedDB 数据库版本,默认 1 */
+      dbVersion?: number;
+      /** 存储 key / prefix(必传) */
+      key: string;
+      /** IndexedDB 对象存储名称,默认 'viewed-table-row' */
+      storeName?: string;
+      type: 'indexedDB';
+    } & ViewedRowPersistBase)
   | ({
-  /** 存储 key(必传) */
-  key: string;
-  type: 'localStorage' | 'sessionStorage';
-} & ViewedRowPersistBase)
+      /** 存储 key(必传) */
+      key: string;
+      type: 'localStorage' | 'sessionStorage';
+    } & ViewedRowPersistBase)
   | ({
-  /** 自定义存储适配器(必传) */
-  storage: ViewedRowStorageAdapter;
-  type: 'custom';
-} & ViewedRowPersistBase)
+      /** 自定义存储适配器(必传) */
+      storage: ViewedRowStorageAdapter;
+      type: 'custom';
+    } & ViewedRowPersistBase)
   | (ViewedRowPersistBase & {
-  type: 'memory';
-});
+      type: 'memory';
+    });
 
 /**
  * 已查看row设置

+ 17 - 16
packages/effects/plugins/src/vxe-table/use-viewed-row.ts

@@ -1,4 +1,5 @@
-import type {VxeGridProps as VxeTableGridProps} from 'vxe-table';
+/* eslint-disable unicorn/no-nested-ternary */
+import type { VxeGridProps as VxeTableGridProps } from 'vxe-table';
 
 import type {
   ViewedRowOptions,
@@ -6,9 +7,9 @@ import type {
   ViewedRowStorageAdapter,
 } from './types';
 
-import {isRef, shallowRef, toRaw, triggerRef, watch} from 'vue';
+import { isRef, shallowRef, toRaw, triggerRef, watch } from 'vue';
 
-import {isBoolean, isFunction} from '@vben/utils';
+import { isBoolean, isFunction } from '@vben/utils';
 
 import {
   IndexedDBDriver,
@@ -16,7 +17,7 @@ import {
   StorageManager,
 } from '@vben-core/shared/cache';
 
-import {useDebounceFn} from '@vueuse/core';
+import { useDebounceFn } from '@vueuse/core';
 
 const DEFAULT_VIEWED_CLASS = 'vxe-row--viewed';
 
@@ -32,7 +33,7 @@ function createWebStorageAdapter(
   ttl?: number,
 ): ViewedRowStorageAdapter {
   const manager = new StorageManager({
-    driver: new LocalStorageDriver({storageType}),
+    driver: new LocalStorageDriver({ storageType }),
   });
 
   return {
@@ -183,9 +184,9 @@ export function useViewedRow<T = any>(
 ) {
   // ========== 解析持久化配置 ==========
   const persistOpts: null | ViewedRowPersistOptions = options.persist
-    ? (typeof options.persist === 'string'
-      ? {key: options.persist, type: 'localStorage'}
-      : options.persist)
+    ? typeof options.persist === 'string'
+      ? { key: options.persist, type: 'localStorage' }
+      : options.persist
     : null;
 
   const adapter = createStorageAdapter(options.persist);
@@ -341,7 +342,7 @@ export function useViewedRow<T = any>(
   function getRowClassName(params: any): string {
     if (!isViewed(params.row)) return '';
 
-    const {rowClassName} = options;
+    const { rowClassName } = options;
     if (rowClassName === undefined || rowClassName === null) {
       return DEFAULT_VIEWED_CLASS;
     }
@@ -358,7 +359,7 @@ export function useViewedRow<T = any>(
   function getRowStyle(params: any): any {
     if (!isViewed(params.row)) return undefined;
 
-    const {rowStyle} = options;
+    const { rowStyle } = options;
     if (rowStyle === undefined || rowStyle === null) {
       return undefined;
     }
@@ -415,11 +416,11 @@ function wrapColumnsForViewedRow(
   return columns.map((column) => {
     if (!column || typeof column !== 'object') return column;
 
-    const nextColumn = {...column};
+    const nextColumn = { ...column };
 
     if (nextColumn.cellRender?.name === 'CellOperation') {
-      const cellRender = {...nextColumn.cellRender};
-      const attrs = {...cellRender.attrs};
+      const cellRender = { ...nextColumn.cellRender };
+      const attrs = { ...cellRender.attrs };
       const originalOnClick = attrs.onClick;
 
       attrs.onClick = (params: { code: string; row: any }) => {
@@ -515,15 +516,15 @@ export function applyViewedRowOptions(
     if (!viewedStyle && !originalStyle) return undefined;
     if (!originalStyle) return viewedStyle;
     if (!viewedStyle) return originalStyle;
-    return {...originalStyle, ...viewedStyle};
+    return { ...originalStyle, ...viewedStyle };
   };
 
   // 拦截 CellOperation columns
   const actionCodes =
     !isBoolean(viewedRowConfig) && viewedRowConfig.actionCodes
-      ? (Array.isArray(viewedRowConfig.actionCodes)
+      ? Array.isArray(viewedRowConfig.actionCodes)
         ? viewedRowConfig.actionCodes
-        : [viewedRowConfig.actionCodes])
+        : [viewedRowConfig.actionCodes]
       : [];
 
   if (actionCodes.length > 0 && Array.isArray(mergedOptions.columns)) {

+ 3 - 3
packages/effects/plugins/src/vxe-table/use-vxe-grid.vue

@@ -44,7 +44,7 @@ import { VxeGrid, VxeUI } from 'vxe-table';
 
 import { extendProxyOptions } from './extends';
 import { useTableForm } from './init';
-import {applyViewedRowOptions, useViewedRow} from './use-viewed-row';
+import { applyViewedRowOptions, useViewedRow } from './use-viewed-row';
 
 import 'vxe-table/styles/cssvar.scss';
 import 'vxe-pc-ui/styles/cssvar.scss';
@@ -93,10 +93,10 @@ watch(
     if (!cfg) return;
 
     const keyField = (gridOptions.value?.rowConfig as any)?.keyField || 'id';
-    const resolved = isBoolean(cfg) ? {keyField} : {keyField, ...cfg};
+    const resolved = isBoolean(cfg) ? { keyField } : { keyField, ...cfg };
     gridApi.viewedRowHelper = useViewedRow(resolved);
   },
-  {immediate: true},
+  { immediate: true },
 );
 
 const { isMobile } = usePreferences();

+ 9 - 15
packages/effects/request/src/request-client/request-client.test.ts

@@ -50,24 +50,18 @@ describe('requestClient', () => {
 
   it('should handle network errors', async () => {
     mock.onGet('/test/error').networkError();
-    try {
-      await requestClient.get('/test/error');
-      expect(true).toBe(false);
-    } catch (error: any) {
-      expect(error.isAxiosError).toBe(true);
-      expect(error.message).toBe('Network Error');
-    }
+    await expect(requestClient.get('/test/error')).rejects.toMatchObject({
+      isAxiosError: true,
+      message: 'Network Error',
+    });
   });
 
   it('should handle timeout', async () => {
     mock.onGet('/test/timeout').timeout();
-    try {
-      await requestClient.get('/test/timeout');
-      expect(true).toBe(false);
-    } catch (error: any) {
-      expect(error.isAxiosError).toBe(true);
-      expect(error.code).toBe('ECONNABORTED');
-    }
+    await expect(requestClient.get('/test/timeout')).rejects.toMatchObject({
+      isAxiosError: true,
+      code: 'ECONNABORTED',
+    });
   });
 
   it('should successfully upload a file', async () => {
@@ -92,7 +86,7 @@ describe('requestClient', () => {
 
     mock.onGet('/test/download').reply(200, mockFileContent);
 
-    const res = await requestClient.download('/test/download');
+    const res = await requestClient.download<any>('/test/download');
 
     expect(res.data).toBeInstanceOf(Blob);
   });

+ 2 - 2
playground/src/views/demos/features/preferences-extension/index.vue

@@ -105,7 +105,7 @@ function applyPreset(type: 'compact' | 'focus' | 'review') {
     },
   };
 
-  updateCustomPreferences<PlaygroundPreferencesExtension>(presetMap[type]);
+  updateCustomPreferences(presetMap[type]);
 }
 
 function getPriorityColor(priority: DemoTaskItem['priority']) {
@@ -136,7 +136,7 @@ function getPriorityColor(priority: DemoTaskItem['priority']) {
       :title="$t('demos.preferencesExtensionDemo.currentConfig')"
     >
       <Alert :type="toneConfig.alertType" show-icon>
-        <template #message>
+        <template #title>
           {{
             $t('demos.preferencesExtensionDemo.currentTitle', {
               title: playgroundPreferences.reportTitle,