@lacqjs/nuxt-dict 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026-PRESENT miaozhongfei
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -0,0 +1,80 @@
1
+
2
+ <p align="center">
3
+ <h1 align="center">@lacqjs/nuxt-dict</h1>
4
+ </p>
5
+
6
+ <p align="center">
7
+ <a href="https://npmjs.com/package/@lacqjs/nuxt-dict"><img src="https://img.shields.io/npm/v/@lacqjs/nuxt-dict?style=flat-square&colorA=202128&colorB=36936A" alt="Version"></a>
8
+ <a href="https://npmjs.com/package/@lacqjs/nuxt-dict"><img src="https://img.shields.io/npm/dm/@lacqjs/nuxt-dict?style=flat-square&colorA=202128&colorB=36936A" alt="Downloads"></a>
9
+ <a href="https://github.com/miaozhongfei/nuxt-dict/blob/main/LICENSE"><img src="https://img.shields.io/github/license/miaozhongfei/nuxt-dict?style=flat-square&colorA=202128&colorB=36936A" alt="License"></a>
10
+ <a href="https://miaozhongfei.github.io/nuxt-dict/"><img src="https://img.shields.io/badge/Docs-202128?style=flat-square&logo=gitbook&logoColor=DDDDD4" alt="Docs"></a>
11
+ </p>
12
+
13
+ > Nuxt 数据字典模块,提供扁平 / 树形字典翻译、多语言国际化、三级缓存与 SSR 预取。
14
+
15
+ ## 快速开始
16
+
17
+ ### 安装
18
+
19
+ ```bash
20
+ pnpm add @lacqjs/nuxt-dict
21
+ ```
22
+
23
+ ### 注册模块
24
+
25
+ ```ts
26
+ // nuxt.config.ts
27
+ export default defineNuxtConfig({
28
+ modules: ['@lacqjs/nuxt-dict'],
29
+ })
30
+ ```
31
+
32
+ ```vue
33
+ <template>
34
+ <el-select v-model="value" placeholder="请选择">
35
+ <el-option v-for="o in options" :key="o.value" :label="o.label" :value="o.value" />
36
+ </el-select>
37
+ </template>
38
+
39
+ <script setup lang="ts">
40
+ const { data: options } = useDict('gender')
41
+ const value = ref('')
42
+ </script>
43
+ ```
44
+
45
+ ## 特性
46
+
47
+ - **扁平字典** — `useDict(type)` 自动加载,返回 `[{ value, label }]`,直接绑定 UI 组件
48
+ - **树形字典** — `useDictTree(type)` 支持任意深度树形结构 + `findPath()` 路径回溯
49
+ - **多语言** — `useLocale()` 切换语言,所有活跃字典实例自动重新请求
50
+ - **多仓库** — 通过 `stores` 配置从不同 API 端点加载,实现数据隔离
51
+ - **三级缓存** — 内存 LRU → IndexedDB → 网络(版本校验),最大化减少请求
52
+ - **SSR 预取** — `ssr.prefetch` 配置服务端预加载,加速首屏渲染
53
+ - **自定义适配器** — 实现 `DictAdapter` 接口即可对接任意数据源
54
+ - **同步翻译** — `$dict.translate()` / `$dict.translatePath()` / `$dict.translateData()` 全场景覆盖
55
+
56
+ 完整用法与配置请查看 → [文档](https://miaozhongfei.github.io/nuxt-dict/)
57
+
58
+ ## 开发
59
+
60
+ ```bash
61
+ pnpm dev # 启动开发服务器
62
+ pnpm prepack # 构建产物
63
+ pnpm lint # 代码检查
64
+ pnpm typecheck # 类型检查
65
+ pnpm e2e # E2E 测试
66
+ ```
67
+
68
+ ## 感谢 / 致谢
69
+
70
+ 本项目受益于以下优秀开源项目:
71
+
72
+ - [Nuxt](https://nuxt.com/) — Vue 全栈框架
73
+ - [@nuxt/kit](https://github.com/nuxt/nuxt) — Nuxt 模块开发工具包
74
+ - [defu](https://github.com/unjs/defu) — 深度合并配置
75
+ - [consola](https://github.com/unjs/consola) — 日志工具
76
+ - [compare-versions](https://github.com/omichelsen/compare-versions) — 版本比较
77
+
78
+ ## 许可证
79
+
80
+ [MIT](./LICENSE) License © 2026-PRESENT [miaozhongfei](https://github.com/miaozhongfei)
package/dist/module.d.mts CHANGED
@@ -1,7 +1,9 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
2
  import * as __runtime_types from '../dist/runtime/types/index.js';
3
3
  import { ModuleOptions } from '../dist/runtime/types/index.js';
4
- export { ModuleOptions } from '../dist/runtime/types/index.js';
4
+ export { DictItem, DictTranslator, GetDictItemOptions, ModuleOptions, TranslateOptions, TranslatePathOptions, TreeNode } from '../dist/runtime/types/index.js';
5
+ export { DictManager } from '../dist/runtime/core/dict-manager.js';
6
+ export { createDictTranslator } from '../dist/runtime/utils/dict-translator.js';
5
7
 
6
8
  /**
7
9
  * Nuxt Dict 模块入口。
package/dist/module.d.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
2
  import * as __runtime_types from '../dist/runtime/types/index.js';
3
3
  import { ModuleOptions } from '../dist/runtime/types/index.js';
4
- export { ModuleOptions } from '../dist/runtime/types/index.js';
4
+ export { DictItem, DictTranslator, GetDictItemOptions, ModuleOptions, TranslateOptions, TranslatePathOptions, TreeNode } from '../dist/runtime/types/index.js';
5
+ export { DictManager } from '../dist/runtime/core/dict-manager.js';
6
+ export { createDictTranslator } from '../dist/runtime/utils/dict-translator.js';
5
7
 
6
8
  /**
7
9
  * Nuxt Dict 模块入口。
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lacqjs/nuxt-dict",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "configKey": "dict",
5
5
  "compatibility": {
6
6
  "nuxt": "^4.4.8"
package/dist/module.mjs CHANGED
@@ -2,9 +2,10 @@ import { fileURLToPath } from 'url';
2
2
  import { defineNuxtModule, useLogger, createResolver, addPlugin, addImportsDir, addTypeTemplate } from '@nuxt/kit';
3
3
  import { defaultOptions } from '../dist/runtime/options.js';
4
4
  import { createLogger } from '../dist/runtime/utils/logger.js';
5
+ export { createDictTranslator } from '../dist/runtime/utils/dict-translator.js';
5
6
 
6
7
  const name = "@lacqjs/nuxt-dict";
7
- const version = "0.0.2";
8
+ const version = "0.0.3";
8
9
  const devDependencies = {
9
10
  nuxt: "^4.4.8"};
10
11
  const pkg = {
@@ -15,17 +16,139 @@ const pkg = {
15
16
  function registerTypeTemplates(resolver, stores) {
16
17
  addTypeTemplate({
17
18
  filename: "types/nuxt-dict.d.ts",
19
+ // eslint-disable max-lines-per-function
18
20
  getContents: () => `
19
- import type { DictManager } from '${pkg.name}'
21
+ import type { StoreKey } from '#build/types/nuxt-dict-store-names'
20
22
 
21
23
  declare module '#app' {
22
24
  interface NuxtApp {
23
- $dict: ReturnType<typeof import('${pkg.name}').createDictTranslator>
24
- $dictManager: DictManager
25
- }
26
- }
25
+ $dict: {
26
+ /**
27
+ * \u540C\u6B65\u7FFB\u8BD1\u5B57\u5178\u7F16\u7801 \u2192 \u6587\u672C\u3002
28
+ * @description \u540C\u6B65\u7FFB\u8BD1\u5B57\u5178\u7F16\u7801 \u2192 \u6587\u672C\u3002\u4ECE\u5168\u5C40\u5185\u5B58\u7F13\u5B58\u4E2D\u67E5\u627E\u7F16\u7801\u5BF9\u5E94\u7684\u6587\u672C\uFF0C\u7F13\u5B58\u672A\u547D\u4E2D\u65F6\u8FD4\u56DE code \u539F\u6837\u3002\u5148\u901A\u8FC7 useDict \u7B49\u52A0\u8F7D\u6570\u636E\u540E\u8C03\u7528\u3002
29
+ * @param type - \u5B57\u5178\u7C7B\u578B\u540D\uFF0C\u5982 'gender'
30
+ * @param code - \u7F16\u7801\u503C
31
+ * @param opts - \u53EF\u9009\u914D\u7F6E\u5BF9\u8C61
32
+ * @param {StoreKey} [opts.storeName] - \u6307\u5B9A\u4ED3\u5E93\u540D
33
+ * @param {string} [opts.field] - \u6307\u5B9A\u53D6\u503C\u5B57\u6BB5\uFF0C\u9ED8\u8BA4 'label'
34
+ * @returns {string} \u7FFB\u8BD1\u6587\u672C\uFF0C\u7F13\u5B58\u672A\u547D\u4E2D\u65F6\u8FD4\u56DE code \u539F\u6837
35
+ * @example
36
+ * $dict.translate('gender', 'male')
37
+ * $dict.translate('gender', 'male', { storeName: 'dicts2' })
38
+ */
39
+ translate(type: string, code: string | number, opts?: { storeName?: StoreKey; field?: string }): string
40
+ /**
41
+ * \u6811\u5F62\u5B57\u5178\u4E2D\u67E5\u627E\u7F16\u7801\u7684\u5B8C\u6574\u5C42\u7EA7\u8DEF\u5F84\u3002
42
+ * @description \u6811\u5F62\u5B57\u5178\u4E2D\u67E5\u627E\u7F16\u7801\u7684\u5B8C\u6574\u5C42\u7EA7\u8DEF\u5F84\u3002\u4ECE\u5185\u5B58\u7F13\u5B58\u4E2D\u52A0\u8F7D\u7684\u6811\u5F62\u5B57\u5178\u6570\u636E\u91CC\uFF0C\u901A\u8FC7 DFS \u67E5\u627E\u76EE\u6807\u7F16\u7801\u5E76\u56DE\u6EAF\u5B8C\u6574\u8DEF\u5F84\uFF0C\u7528\u5206\u9694\u7B26\u62FC\u63A5\u540E\u8FD4\u56DE\u3002
43
+ * @param type - \u6811\u5F62\u5B57\u5178\u7C7B\u578B\u540D\uFF0C\u5982 'region'
44
+ * @param code - \u53F6\u5B50\u8282\u70B9\u7F16\u7801\u503C
45
+ * @param opts - \u53EF\u9009\u914D\u7F6E\u5BF9\u8C61
46
+ * @param {StoreKey} [opts.storeName] - \u6307\u5B9A\u4ED3\u5E93\u540D
47
+ * @param {string} [opts.field] - \u6307\u5B9A\u8282\u70B9\u53D6\u503C\u5B57\u6BB5\uFF0C\u9ED8\u8BA4 'label'
48
+ * @param {string} [opts.separator] - \u5C42\u7EA7\u8DEF\u5F84\u5206\u9694\u7B26\uFF0C\u9ED8\u8BA4 ' / '
49
+ * @returns {string} \u7528\u5206\u9694\u7B26\u8FDE\u63A5\u7684\u5B8C\u6574\u5C42\u7EA7\u8DEF\u5F84\uFF0C\u7F13\u5B58\u672A\u547D\u4E2D\u65F6\u8FD4\u56DE code \u539F\u6837
50
+ * @example
51
+ * $dict.translatePath('region', '440104')
52
+ * $dict.translatePath('region', '440104', { separator: ' \u2192 ' })
53
+ */
54
+ translatePath(type: string, code: string | number, opts?: { storeName?: StoreKey; field?: string; separator?: string }): string
55
+ /**
56
+ * \u6279\u91CF\u7FFB\u8BD1\u6570\u636E\u5BF9\u8C61\u4E2D\u7684\u591A\u4E2A\u7F16\u7801\u5B57\u6BB5\u3002
57
+ * @description \u6279\u91CF\u7FFB\u8BD1\u6570\u636E\u5BF9\u8C61\u4E2D\u7684\u591A\u4E2A\u7F16\u7801\u5B57\u6BB5\u3002\u4F20\u5165\u4E00\u4E2A\u6570\u636E\u5BF9\u8C61\u548C\u5B57\u6BB5\u2192\u5B57\u5178\u7C7B\u578B\u6620\u5C04\u8868\uFF0C\u8FD4\u56DE\u8FFD\u52A0\u4E86\u7FFB\u8BD1\u5B57\u6BB5\u7684\u65B0\u5BF9\u8C61\uFF08\u4E0D\u4FEE\u6539\u539F\u5BF9\u8C61\uFF09\u3002
58
+ * @param data - \u9700\u8981\u7FFB\u8BD1\u7684\u6570\u636E\u5BF9\u8C61\uFF0C\u5982 { gender: 'male', status: 1 }
59
+ * @param mapping - \u5B57\u6BB5\u2192\u5B57\u5178\u7C7B\u578B\u6620\u5C04\u8868\uFF0C\u503C\u4E3A string\uFF08\u9ED8\u8BA4\u4ED3\u5E93\uFF09\u6216 { type, storeName? }\uFF08\u6307\u5B9A\u4ED3\u5E93\uFF09
60
+ * @param suffix - \u7FFB\u8BD1\u5B57\u6BB5\u540E\u7F00\uFF0C\u9ED8\u8BA4 '_label'\uFF0C\u7ED3\u679C\u5199\u5165 \u539F\u5B57\u6BB5\u540D + suffix
61
+ * @returns {Record<string, unknown>} \u65B0\u5BF9\u8C61\uFF0C\u5305\u542B\u539F\u6570\u636E\u6240\u6709\u5B57\u6BB5 + \u4EE5 suffix \u4E3A\u540E\u7F00\u7684\u7FFB\u8BD1\u5B57\u6BB5
62
+ * @example
63
+ * $dict.translateData(
64
+ * { gender: 'male', status: 1, name: '\u5F20\u4E09' },
65
+ * { gender: 'gender', status: 'status' }
66
+ * )
67
+ * // \u2192 { ..., gender_label: '\u7537', status_label: '\u7981\u7528', ... }
68
+ */
69
+ translateData(data: Record<string, unknown>, mapping: Record<string, string | { type: string; storeName?: StoreKey }>, suffix?: string): Record<string, unknown>
70
+ /**
71
+ * \u4ECE\u5185\u5B58\u7F13\u5B58\u4E2D\u67E5\u627E\u7F16\u7801\u5BF9\u5E94\u7684\u5B8C\u6574\u5B57\u5178\u9879\u5BF9\u8C61\u3002
72
+ * @description \u4ECE\u5DF2\u52A0\u8F7D\u7684\u7F13\u5B58\u4E2D\u67E5\u627E\u7F16\u7801\u5BF9\u5E94\u7684\u5B8C\u6574 DictItem \u5BF9\u8C61\uFF08\u975E\u5B57\u7B26\u4E32\u7FFB\u8BD1\uFF09\u3002\u7F13\u5B58\u672A\u547D\u4E2D\u65F6\u8FD4\u56DE undefined\u3002
73
+ * @param type - \u5B57\u5178\u7C7B\u578B\u540D\uFF0C\u5982 'gender'
74
+ * @param code - \u7F16\u7801\u503C
75
+ * @param opts - \u53EF\u9009\u914D\u7F6E\u5BF9\u8C61
76
+ * @param {StoreKey} [opts.storeName] - \u6307\u5B9A\u4ED3\u5E93\u540D
77
+ * @returns {DictItem | undefined} \u5B8C\u6574\u7684\u5B57\u5178\u9879\u5BF9\u8C61\uFF0C\u7F13\u5B58\u672A\u547D\u4E2D\u65F6\u8FD4\u56DE undefined
78
+ * @example
79
+ * $dict.getDictItem('gender', 'male')
80
+ * $dict.getDictItem('gender', 'male', { storeName: 'dicts2' })
81
+ */
82
+ getDictItem(type: string, code: string | number, opts?: { storeName?: StoreKey }): DictItem | undefined
83
+ }
84
+ }
85
+ }
86
+
87
+ declare module '@vue/runtime-core' {
88
+ interface ComponentCustomProperties {
89
+ $dict: {
90
+ /**
91
+ * \u540C\u6B65\u7FFB\u8BD1\u5B57\u5178\u7F16\u7801 \u2192 \u6587\u672C\u3002
92
+ * @description \u540C\u6B65\u7FFB\u8BD1\u5B57\u5178\u7F16\u7801 \u2192 \u6587\u672C\u3002\u4ECE\u5168\u5C40\u5185\u5B58\u7F13\u5B58\u4E2D\u67E5\u627E\u7F16\u7801\u5BF9\u5E94\u7684\u6587\u672C\uFF0C\u7F13\u5B58\u672A\u547D\u4E2D\u65F6\u8FD4\u56DE code \u539F\u6837\u3002
93
+ * @param type - \u5B57\u5178\u7C7B\u578B\u540D\uFF0C\u5982 'gender'
94
+ * @param code - \u7F16\u7801\u503C
95
+ * @param opts - \u53EF\u9009\u914D\u7F6E\u5BF9\u8C61
96
+ * @param {StoreKey} [opts.storeName] - \u6307\u5B9A\u4ED3\u5E93\u540D
97
+ * @param {string} [opts.field] - \u6307\u5B9A\u53D6\u503C\u5B57\u6BB5\uFF0C\u9ED8\u8BA4 'label'
98
+ * @returns {string} \u7FFB\u8BD1\u6587\u672C\uFF0C\u7F13\u5B58\u672A\u547D\u4E2D\u65F6\u8FD4\u56DE code \u539F\u6837
99
+ * @example
100
+ * $dict.translate('gender', 'male')
101
+ * $dict.translate('gender', 'male', { storeName: 'dicts2' })
102
+ */
103
+ translate(type: string, code: string | number, opts?: { storeName?: StoreKey; field?: string }): string
104
+ /**
105
+ * \u6811\u5F62\u5B57\u5178\u4E2D\u67E5\u627E\u7F16\u7801\u7684\u5B8C\u6574\u5C42\u7EA7\u8DEF\u5F84\u3002
106
+ * @description \u6811\u5F62\u5B57\u5178\u4E2D\u67E5\u627E\u7F16\u7801\u7684\u5B8C\u6574\u5C42\u7EA7\u8DEF\u5F84\u3002\u901A\u8FC7 DFS \u67E5\u627E\u76EE\u6807\u7F16\u7801\u5E76\u56DE\u6EAF\u5B8C\u6574\u8DEF\u5F84\uFF0C\u7528\u5206\u9694\u7B26\u62FC\u63A5\u540E\u8FD4\u56DE\u3002
107
+ * @param type - \u6811\u5F62\u5B57\u5178\u7C7B\u578B\u540D\uFF0C\u5982 'region'
108
+ * @param code - \u53F6\u5B50\u8282\u70B9\u7F16\u7801\u503C
109
+ * @param opts - \u53EF\u9009\u914D\u7F6E\u5BF9\u8C61
110
+ * @param {StoreKey} [opts.storeName] - \u6307\u5B9A\u4ED3\u5E93\u540D
111
+ * @param {string} [opts.field] - \u6307\u5B9A\u8282\u70B9\u53D6\u503C\u5B57\u6BB5\uFF0C\u9ED8\u8BA4 'label'
112
+ * @param {string} [opts.separator] - \u5C42\u7EA7\u8DEF\u5F84\u5206\u9694\u7B26\uFF0C\u9ED8\u8BA4 ' / '
113
+ * @returns {string} \u7528\u5206\u9694\u7B26\u8FDE\u63A5\u7684\u5B8C\u6574\u5C42\u7EA7\u8DEF\u5F84\uFF0C\u7F13\u5B58\u672A\u547D\u4E2D\u65F6\u8FD4\u56DE code \u539F\u6837
114
+ * @example
115
+ * $dict.translatePath('region', '440104')
116
+ * $dict.translatePath('region', '440104', { separator: ' \u2192 ' })
117
+ */
118
+ translatePath(type: string, code: string | number, opts?: { storeName?: StoreKey; field?: string; separator?: string }): string
119
+ /**
120
+ * \u6279\u91CF\u7FFB\u8BD1\u6570\u636E\u5BF9\u8C61\u4E2D\u7684\u591A\u4E2A\u7F16\u7801\u5B57\u6BB5\u3002
121
+ * @description \u6279\u91CF\u7FFB\u8BD1\u6570\u636E\u5BF9\u8C61\u4E2D\u7684\u591A\u4E2A\u7F16\u7801\u5B57\u6BB5\u3002\u4F20\u5165\u5B57\u6BB5\u2192\u5B57\u5178\u7C7B\u578B\u6620\u5C04\u8868\uFF0C\u8FD4\u56DE\u542B\u7FFB\u8BD1\u5B57\u6BB5\u7684\u65B0\u5BF9\u8C61\uFF08\u4E0D\u4FEE\u6539\u539F\u5BF9\u8C61\uFF09\u3002
122
+ * @param data - \u9700\u8981\u7FFB\u8BD1\u7684\u6570\u636E\u5BF9\u8C61\uFF0C\u5982 { gender: 'male', status: 1 }
123
+ * @param mapping - \u5B57\u6BB5\u2192\u5B57\u5178\u7C7B\u578B\u6620\u5C04\u8868\uFF0C\u503C\u4E3A string\uFF08\u9ED8\u8BA4\u4ED3\u5E93\uFF09\u6216 { type, storeName? }\uFF08\u6307\u5B9A\u4ED3\u5E93\uFF09
124
+ * @param suffix - \u7FFB\u8BD1\u5B57\u6BB5\u540E\u7F00\uFF0C\u9ED8\u8BA4 '_label'
125
+ * @returns {Record<string, unknown>} \u65B0\u5BF9\u8C61\uFF0C\u5305\u542B\u539F\u6570\u636E\u6240\u6709\u5B57\u6BB5 + \u4EE5 suffix \u4E3A\u540E\u7F00\u7684\u7FFB\u8BD1\u5B57\u6BB5
126
+ * @example
127
+ * $dict.translateData(
128
+ * { gender: 'male', status: 1, name: '\u5F20\u4E09' },
129
+ * { gender: 'gender', status: 'status' }
130
+ * )
131
+ * // \u2192 { ..., gender_label: '\u7537', status_label: '\u7981\u7528', ... }
132
+ */
133
+ translateData(data: Record<string, unknown>, mapping: Record<string, string | { type: string; storeName?: StoreKey }>, suffix?: string): Record<string, unknown>
134
+ /**
135
+ * \u4ECE\u5185\u5B58\u7F13\u5B58\u4E2D\u67E5\u627E\u7F16\u7801\u5BF9\u5E94\u7684\u5B8C\u6574\u5B57\u5178\u9879\u5BF9\u8C61\u3002
136
+ * @description \u4ECE\u5DF2\u52A0\u8F7D\u7684\u7F13\u5B58\u4E2D\u67E5\u627E\u7F16\u7801\u5BF9\u5E94\u7684\u5B8C\u6574 DictItem \u5BF9\u8C61\uFF08\u975E\u5B57\u7B26\u4E32\u7FFB\u8BD1\uFF09\u3002\u7F13\u5B58\u672A\u547D\u4E2D\u65F6\u8FD4\u56DE undefined\u3002
137
+ * @param type - \u5B57\u5178\u7C7B\u578B\u540D\uFF0C\u5982 'gender'
138
+ * @param code - \u7F16\u7801\u503C
139
+ * @param opts - \u53EF\u9009\u914D\u7F6E\u5BF9\u8C61
140
+ * @param {StoreKey} [opts.storeName] - \u6307\u5B9A\u4ED3\u5E93\u540D
141
+ * @returns {DictItem | undefined} \u5B8C\u6574\u7684\u5B57\u5178\u9879\u5BF9\u8C61\uFF0C\u7F13\u5B58\u672A\u547D\u4E2D\u65F6\u8FD4\u56DE undefined
142
+ * @example
143
+ * $dict.getDictItem('gender', 'male')
144
+ * $dict.getDictItem('gender', 'male', { storeName: 'dicts2' })
145
+ */
146
+ getDictItem(type: string, code: string | number, opts?: { storeName?: StoreKey }): DictItem | undefined
147
+ }
148
+ }
149
+ }
27
150
 
28
- export {}
151
+ export {}
29
152
  `
30
153
  });
31
154
  addTypeTemplate({
@@ -4,6 +4,12 @@ import type { UseDictReturn, StoreKey } from '../types/index.js';
4
4
  * 组件挂载时自动加载,卸载时自动清理引用。
5
5
  * 返回翻译函数、加载状态和手动刷新方法。
6
6
  *
7
+ * @description 从字典管理器获取扁平字典数据,挂载后自动触发网络请求(或缓存)。
8
+ * @param {string} type - 字典类型名(如 'gender'),一参形式:useDict(type),使用默认仓库 'dicts'
9
+ * @param {StoreKey} storeName - 仓库名(如 'dicts2'),二参形式:useDict(storeName, type)
10
+ * @param {string} type - 字典类型名,二参形式时作为第二参数传入
11
+ * @returns {UseDictReturn} 包含 data(字典项数组)、translate(翻译函数)、loading、error、refresh
12
+ *
7
13
  * @example
8
14
  * // 默认存储库 'dicts'
9
15
  * const { data, translate } = useDict('gender')
@@ -2,12 +2,18 @@ import { shallowRef, ref, watch, onMounted, onBeforeUnmount } from "vue";
2
2
  import { useNuxtApp } from "#imports";
3
3
  import { DEFAULT_STORE_NAME } from "../core/cache/indexeddb-cache.js";
4
4
  const activeInstances = /* @__PURE__ */ new Map();
5
- async function fetchDictData(manager, dictType, storeName, data, loading, error, mode = "load") {
5
+ async function fetchDictData(manager, dictType, storeName, data, loading, error, mode = "load", itemMap) {
6
6
  loading.value = true;
7
7
  error.value = null;
8
8
  try {
9
9
  const entry = await (mode === "refresh" ? manager.refresh(dictType, storeName) : manager.getDict(dictType, storeName));
10
10
  data.value = entry.items;
11
+ if (itemMap) {
12
+ itemMap.clear();
13
+ for (const item of entry.items) {
14
+ itemMap.set(String(item.value), item);
15
+ }
16
+ }
11
17
  } catch (e) {
12
18
  error.value = e instanceof Error ? e.message : String(e);
13
19
  } finally {
@@ -35,25 +41,41 @@ export function useDict(storeOrType, maybeType) {
35
41
  const storeName = maybeType === void 0 ? DEFAULT_STORE_NAME : storeOrType;
36
42
  const dictType = maybeType ?? storeOrType;
37
43
  const data = shallowRef(null);
44
+ const itemMap = /* @__PURE__ */ new Map();
38
45
  const loading = ref(false);
39
46
  const error = ref(null);
40
47
  const instanceId = Symbol(dictType);
41
48
  const trackKey = `${storeName}:${dictType}`;
42
49
  trackInstance(trackKey, instanceId);
43
- function translate(code) {
44
- return manager.translate(dictType, code, storeName);
50
+ function translate(value, opts) {
51
+ const targetStore = opts?.storeName ?? storeName;
52
+ const field = opts?.field ?? "label";
53
+ if (targetStore !== storeName) {
54
+ return manager.translate(dictType, value, { storeName: targetStore, field });
55
+ }
56
+ if (!data.value) return String(value);
57
+ const item = itemMap.get(String(value));
58
+ if (!item) return String(value);
59
+ return item[field] ?? item.label;
60
+ }
61
+ function getDictItem(value, opts) {
62
+ if (opts?.storeName && opts.storeName !== storeName) {
63
+ return manager.getDictItem(dictType, value, opts);
64
+ }
65
+ if (!data.value) return void 0;
66
+ return itemMap.get(String(value));
45
67
  }
46
68
  async function refresh() {
47
- await fetchDictData(manager, dictType, storeName, data, loading, error, "refresh");
69
+ await fetchDictData(manager, dictType, storeName, data, loading, error, "refresh", itemMap);
48
70
  }
49
71
  onMounted(() => {
50
- fetchDictData(manager, dictType, storeName, data, loading, error, "load");
72
+ fetchDictData(manager, dictType, storeName, data, loading, error, "load", itemMap);
51
73
  });
52
74
  watch(
53
75
  () => manager.locale.value,
54
76
  () => {
55
- fetchDictData(manager, dictType, storeName, data, loading, error, "load");
77
+ fetchDictData(manager, dictType, storeName, data, loading, error, "load", itemMap);
56
78
  }
57
79
  );
58
- return { data, translate, loading, error, refresh };
80
+ return { data, translate, getDictItem, loading, error, refresh };
59
81
  }
@@ -3,6 +3,12 @@ import type { UseDictTreeReturn, StoreKey } from '../types/index.js';
3
3
  * 使用树形字典数据,支持翻译和路径查找。
4
4
  * 组件挂载时自动加载,适用于区域选择器等级联场景。
5
5
  *
6
+ * @description 从字典管理器获取树形字典数据,挂载后自动触发网络请求(或缓存)。
7
+ * @param {string} type - 字典类型名(如 'region'),一参形式:useDictTree(type),使用默认仓库 'dicts'
8
+ * @param {StoreKey} storeName - 仓库名(如 'dicts2'),二参形式:useDictTree(storeName, type)
9
+ * @param {string} type - 字典类型名,二参形式时作为第二参数传入
10
+ * @returns {UseDictTreeReturn} 包含 tree(树节点数组)、translate(翻译函数)、findPath(路径回溯)、loading、refresh
11
+ *
6
12
  * @example
7
13
  * // 默认存储库 'dicts'
8
14
  * const { tree, translate } = useDictTree('region')
@@ -7,19 +7,30 @@ export function useDictTree(storeOrType, maybeType) {
7
7
  const storeName = maybeType === void 0 ? DEFAULT_STORE_NAME : storeOrType;
8
8
  const dictType = maybeType ?? storeOrType;
9
9
  const tree = shallowRef(null);
10
+ const nodeMap = /* @__PURE__ */ new Map();
11
+ const pathMap = /* @__PURE__ */ new Map();
10
12
  const loading = ref(false);
11
- function translate(code) {
12
- return manager.translate(dictType, code, storeName);
13
+ function translate(value, opts) {
14
+ const targetStore = opts?.storeName ?? storeName;
15
+ const field = opts?.field ?? "label";
16
+ if (targetStore !== storeName) {
17
+ return manager.translate(dictType, value, { storeName: targetStore, field });
18
+ }
19
+ if (!tree.value) return String(value);
20
+ const node = nodeMap.get(String(value));
21
+ if (!node) return String(value);
22
+ return node[field] ?? node.label;
13
23
  }
14
- function findPath(code) {
24
+ function findPath(value) {
15
25
  if (!tree.value) return [];
16
- return findPathInTree(tree.value, code);
26
+ return pathMap.get(String(value)) ?? [];
17
27
  }
18
28
  async function load() {
19
29
  loading.value = true;
20
30
  try {
21
31
  const entry = await manager.getDict(dictType, storeName);
22
32
  tree.value = entry.tree ?? null;
33
+ if (entry.tree) buildMaps(entry.tree, nodeMap, pathMap);
23
34
  } finally {
24
35
  loading.value = false;
25
36
  }
@@ -29,6 +40,7 @@ export function useDictTree(storeOrType, maybeType) {
29
40
  try {
30
41
  const entry = await manager.refresh(dictType, storeName);
31
42
  tree.value = entry.tree ?? null;
43
+ if (entry.tree) buildMaps(entry.tree, nodeMap, pathMap);
32
44
  } finally {
33
45
  loading.value = false;
34
46
  }
@@ -37,17 +49,14 @@ export function useDictTree(storeOrType, maybeType) {
37
49
  watch(() => manager.locale.value, load);
38
50
  return { tree, translate, findPath, loading, refresh };
39
51
  }
40
- function findPathInTree(nodes, targetCode) {
52
+ function buildMaps(nodes, nodeMap, pathMap, ancestors = []) {
41
53
  for (const node of nodes) {
42
- if (node.code === targetCode) {
43
- return [node.label];
44
- }
54
+ const code = String(node.value);
55
+ const path = [...ancestors, node.label];
56
+ nodeMap.set(code, node);
57
+ pathMap.set(code, path);
45
58
  if (node.children && node.children.length > 0) {
46
- const childPath = findPathInTree(node.children, targetCode);
47
- if (childPath.length > 0) {
48
- return [node.label, ...childPath];
49
- }
59
+ buildMaps(node.children, nodeMap, pathMap, path);
50
60
  }
51
61
  }
52
- return [];
53
62
  }
@@ -2,6 +2,20 @@
2
2
  * 获取/切换当前语言。
3
3
  * 切换语言时会同步更新 cookie(客户端)并通知 DictManager 刷新缓存。
4
4
  * locale 为 DictManager 上的响应式 ref,语言切换后所有 useDict / useDictTree 组件自动重取。
5
+ *
6
+ * @description 从 DictManager 获取当前语言信息,提供切换语言并持久化到 cookie 的能力。
7
+ * @returns {{ locale: Ref<string>, setLocale: (newLocale: string) => void, locales: string[] }} 当前语言 ref、语言切换函数、支持的语言列表
8
+ *
9
+ * @example
10
+ * const { locale, setLocale } = useLocale()
11
+ *
12
+ * // 切换语言
13
+ * setLocale('en-US') // 切换到英文
14
+ * console.log(locale.value) // 'en-US'
15
+ *
16
+ * // 模板中直接使用
17
+ * // <p>当前语言:{{ locale }}</p>
18
+ * // <button @click="setLocale('zh-CN')">中文</button>
5
19
  */
6
20
  export declare function useLocale(): {
7
21
  locale: import("vue").ShallowRef<string, string>;
@@ -1,5 +1,16 @@
1
1
  import type { DictAdapter } from '../types/index.js';
2
- /** 创建默认适配器所需的配置参数 */
2
+ /**
3
+ * 创建默认适配器所需的配置参数。
4
+ *
5
+ * @example
6
+ * const adapter = createDefaultAdapter({
7
+ * baseURL: '/api',
8
+ * dictEndpoint: '/dict/list',
9
+ * versionEndpoint: '/dict/version',
10
+ * paramKey: 'lang',
11
+ * apiHeaderKey: 'X-Locale',
12
+ * })
13
+ */
3
14
  export interface DefaultAdapterOptions {
4
15
  baseURL: string;
5
16
  dictEndpoint: string;
@@ -13,5 +24,20 @@ export interface DefaultAdapterOptions {
13
24
  * 创建默认的 REST 字典适配器。
14
25
  * 底层使用原生 fetch,兼容浏览器和 Node.js 18+(Nuxt 4 要求)。
15
26
  * SSR 侧由 resolveBaseURL() 保证 baseURL 为绝对 origin,客户端相对路径由浏览器处理。
27
+ *
28
+ * @param {DefaultAdapterOptions} options - 适配器配置参数(baseURL、dictEndpoint、versionEndpoint、paramKey、apiHeaderKey)
29
+ * @returns {DictAdapter} 实现了 fetchDict / fetchVersion 方法的 DictAdapter 实例
30
+ *
31
+ * @example
32
+ * const adapter = createDefaultAdapter({
33
+ * baseURL: 'https://api.example.com',
34
+ * dictEndpoint: '/v1/dict/list',
35
+ * versionEndpoint: '/v1/dict/version',
36
+ * paramKey: 'lang',
37
+ * apiHeaderKey: 'X-Locale',
38
+ * })
39
+ *
40
+ * // 用于 ModuleOptions.api.adapter
41
+ * // 或 stores.<storeName>.adapter
16
42
  */
17
43
  export declare function createDefaultAdapter(options: DefaultAdapterOptions): DictAdapter;
@@ -1,5 +1,17 @@
1
1
  import { IndexedDBCache } from './cache/indexeddb-cache.js';
2
- import type { DictAdapter, DictEntry } from '../types/index.js';
2
+ import type { DictAdapter, DictEntry, DictItem, TranslateOptions, TranslatePathOptions, GetDictItemOptions } from '../types/index.js';
3
+ /**
4
+ * DictManager 构造参数。
5
+ *
6
+ * @example
7
+ * const manager = new DictManager({
8
+ * adapters: new Map([['dicts', createDefaultAdapter({ ... })]),
9
+ * indexedDB: new IndexedDBCache('nuxt-dict'),
10
+ * memoryMax: 200,
11
+ * ttl: 0,
12
+ * versionStorageKey: '__NUXT_DICT_VERSION__',
13
+ * })
14
+ */
3
15
  export interface DictManagerOptions {
4
16
  /** 仓库名 → DictAdapter 映射表。至少包含默认仓库 'dicts' 的 adapter */
5
17
  adapters: Map<string, DictAdapter>;
@@ -14,6 +26,13 @@ export interface DictManagerOptions {
14
26
  *
15
27
  * 缓存策略:内存缓存 → IndexedDB 持久缓存 → 网络请求
16
28
  * 请求去重:对同一 key 的并发请求合并为单次网络调用(pendingRequests)
29
+ *
30
+ * @example
31
+ * // 通常由插件自动创建,无需手动实例化
32
+ * // 在组件中通过 useNuxtApp().$dictManager 访问
33
+ * const { $dictManager: manager } = useNuxtApp()
34
+ * const entry = await manager.getDict('gender')
35
+ * const label = manager.translate('gender', 'male')
17
36
  */
18
37
  export declare class DictManager {
19
38
  private memoryCache;
@@ -33,8 +52,18 @@ export declare class DictManager {
33
52
  private buildKey;
34
53
  /** 根据 storeName 获取对应的 adapter。找不到时回退到默认仓库 'dicts' 的 adapter */
35
54
  private getAdapter;
36
- /** 切换语言,清空内存缓存和待处理请求 */
55
+ /**
56
+ * 切换语言,清空内存缓存和待处理请求。
57
+ * 语言变更后所有 useDict / useDictTree 组件通过 watch 自动重取数据。
58
+ *
59
+ * @param {string} locale - 目标语言代码,如 'zh-CN'、'en-US'
60
+ */
37
61
  setLocale(locale: string): void;
62
+ /**
63
+ * 获取当前语言。
64
+ *
65
+ * @returns {string} 当前语言代码,如 'zh-CN'
66
+ */
38
67
  getLocale(): string;
39
68
  /**
40
69
  * 惰性版本检查:首次访问该仓库时检查版本变更,按需清理缓存。
@@ -44,6 +73,10 @@ export declare class DictManager {
44
73
  /**
45
74
  * 获取字典数据。
46
75
  * 优先级:内存缓存 → 合并中的请求 → IndexedDB → 网络请求
76
+ *
77
+ * @param {string} type - 字典类型名,如 'gender'
78
+ * @param {string} storeName - 仓库名,默认 'dicts'
79
+ * @returns {Promise<DictEntry>} 包含 items 和可选 tree 的字典条目
47
80
  */
48
81
  getDict(type: string, storeName?: string): Promise<DictEntry>;
49
82
  /** 执行实际的数据获取与缓存写入 */
@@ -51,24 +84,59 @@ export declare class DictManager {
51
84
  /**
52
85
  * 强制刷新指定字典:跳过缓存,直接从网络获取最新数据。
53
86
  * 适用于用户手动刷新、数据变更通知等场景。
87
+ *
88
+ * @param {string} type - 字典类型名,如 'gender'
89
+ * @param {string} storeName - 仓库名,默认 'dicts'
90
+ * @returns {Promise<DictEntry>} 最新的字典条目
54
91
  */
55
92
  refresh(type: string, storeName?: string): Promise<DictEntry>;
56
- /** 翻译 code → label,未命中时回退原样 */
57
- translate(type: string, code: string | number, storeName?: string): string;
58
- /** 树形字典中查找 code 的完整层级路径 */
59
- translatePath(type: string, code: string | number, separator?: string, storeName?: string): string;
60
- /** DFS 在树形字典中查找目标编码的路径 */
93
+ /**
94
+ * 同步翻译 value label,未命中缓存时回退原样返回。
95
+ *
96
+ * @param {string} type - 字典类型名,如 'gender'
97
+ * @param {string | number} value - 字典编码值
98
+ * @param {TranslateOptions} opts - 可选配置(storeName 指定仓库,field 指定取值字段,默认 'label')
99
+ * @returns {string} 翻译后的文本,缓存未命中时返回 value 的字符串形式
100
+ */
101
+ translate(type: string, value: string | number, opts?: TranslateOptions): string;
102
+ /**
103
+ * 从内存缓存中查找编码对应的完整字典项对象。
104
+ * 参数与 translate 一致,但返回整个 DictItem 而非提取字段。
105
+ *
106
+ * @param {string} type - 字典类型名,如 'gender'
107
+ * @param {string | number} value - 字典编码值
108
+ * @param {GetDictItemOptions} opts - 可选配置(storeName 指定仓库)
109
+ * @returns {DictItem | undefined} 完整的字典项对象,缓存未命中时返回 undefined
110
+ */
111
+ getDictItem(type: string, value: string | number, opts?: GetDictItemOptions): DictItem | undefined;
112
+ /**
113
+ * 树形字典中查找 value 的完整层级路径。
114
+ *
115
+ * @param {string} type - 字典类型名,如 'region'
116
+ * @param {string | number} value - 叶子节点编码值
117
+ * @param {TranslatePathOptions} opts - 可选配置(storeName 指定仓库,field 指定取值字段,separator 指定分隔符,默认 ' / ')
118
+ * @returns {string} 用分隔符连接的完整层级路径,未命中时返回 value 字符串
119
+ */
120
+ translatePath(type: string, value: string | number, opts?: TranslatePathOptions): string;
121
+ /** DFS 在树形字典中查找目标编码的路径,每节点取指定字段 */
61
122
  private findPathInTree;
62
123
  /**
63
124
  * code 比对 —— 统一转字符串比较。
64
125
  * 避免字典配置中数字/字符串编码不一致导致的匹配失败。
65
126
  */
66
127
  private codeMatch;
67
- /** 初始化:版本检查已改为惰性执行,在首次访问仓库时触发 */
128
+ /**
129
+ * 初始化管理器。
130
+ * 版本检查已改为惰性执行,在首次 getDict() 调用时触发,避免全量串行请求。
131
+ *
132
+ * @returns {Promise<void>}
133
+ */
68
134
  initialize(): Promise<void>;
69
135
  /**
70
136
  * 失效缓存数据。
71
- * @param storeName 指定要失效的存储库,不传则清空所有存储库及内存缓存
137
+ *
138
+ * @param {string} storeName - 指定要失效的仓库,不传则清空所有仓库及内存缓存
139
+ * @returns {Promise<void>}
72
140
  */
73
141
  invalidateAll(storeName?: string): Promise<void>;
74
142
  }