@posx/core 5.5.510 → 5.5.512
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 +21 -21
- package/README.md +85 -85
- package/build/index.d.ts +14 -1
- package/build/index.js +1 -1
- package/build/index.js.map +1 -0
- package/package.json +86 -2
- package/AGENTS.md +0 -24
- package/CLAUDE.md +0 -24
- package/jest.config.cjs +0 -36
- package/jest.setup.cjs +0 -80
- package/memo/technical-docs/01_ARCHITECTURE.md +0 -147
- package/memo/technical-docs/02_CORE_BUSINESS.md +0 -292
- package/memo/technical-docs/03_UI_COMPONENTS.md +0 -59
- package/memo/technical-docs/04_VIEWS.md +0 -82
- package/memo/technical-docs/05_DATA_LAYER.md +0 -375
- package/memo/technical-docs/06_CROSS_PLATFORM.md +0 -246
- package/memo/technical-docs/07_SIMILARITY_INDEX.md +0 -195
- package/memo/technical-docs/CHECKPOINT.md +0 -46
- package/memo/technical-docs/PROJECT_OVERVIEW.md +0 -122
- package/memo/technical-docs/TECHNICAL_DOCS_PLAN.md +0 -77
- package/package.publish.json +0 -121
- package/tsdown.config.ts +0 -21
- package/vite.config.ts +0 -86
package/package.json
CHANGED
|
@@ -1,15 +1,90 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@posx/core",
|
|
3
|
-
"version": "5.5.
|
|
3
|
+
"version": "5.5.512",
|
|
4
4
|
"description": "POSX core libraries",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"main": "./build/index.js",
|
|
7
|
+
"module": "./build/index.js",
|
|
8
|
+
"types": "./build/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./build/index.js",
|
|
12
|
+
"types": "./build/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"build"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"up": "node ./scripts/upload-to-s3.cjs --trace-warnings",
|
|
20
|
+
"start": "tsdown --watch",
|
|
21
|
+
"build": "tsdown",
|
|
22
|
+
"build:dts": "tsdown --dts-only",
|
|
23
|
+
"post:build": "node ./scripts/clean-build.cjs",
|
|
24
|
+
"mvm": "mv build/*.map scripts/sourcemaps/ && mv build/**/*.map scripts/sourcemaps/ && find build -name '*.map' -type f -delete",
|
|
25
|
+
"build:demo": "vite build --mode demo",
|
|
26
|
+
"test": "jest --maxWorkers=2",
|
|
27
|
+
"test:watch": "jest --watch",
|
|
28
|
+
"publish": "node ./scripts/publish.cjs",
|
|
29
|
+
"p": "pnpm i && npm test && npm run up:p && npm run build && npm run post:build && npm run publish && rm -rf build",
|
|
30
|
+
"debug": "npm run build && npm run post:build",
|
|
31
|
+
"coverage": "jest --coverage",
|
|
32
|
+
"trypublish": "npm publish || true",
|
|
33
|
+
"gen:index": "node ./scriptswc/generateIndex.cjs",
|
|
34
|
+
"up:p": "npm version patch && git push",
|
|
35
|
+
"up:m": "npm version minor && git push",
|
|
36
|
+
"docs": "typedoc --out docs src --excludePrivate --exclude '**/demo/**/*' --exclude '**/*+(interface|function|enum).ts'",
|
|
37
|
+
"see": "node ./scripts/lookup-sm.cjs",
|
|
38
|
+
"escpos": "node ./scripts/generate-escpos-bytes.mjs"
|
|
39
|
+
},
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git"
|
|
42
|
+
},
|
|
6
43
|
"author": "Steven Lee",
|
|
7
44
|
"license": "UNLICENSED",
|
|
45
|
+
"bugs": {
|
|
46
|
+
"url": ""
|
|
47
|
+
},
|
|
48
|
+
"homepage": "",
|
|
8
49
|
"keywords": [
|
|
9
50
|
"library",
|
|
10
51
|
"starter",
|
|
11
52
|
"es6"
|
|
12
53
|
],
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@capacitor/core": "5.4.2",
|
|
56
|
+
"@litepos/autoquery": "5.0.10",
|
|
57
|
+
"@types/bcryptjs": "2.4.6",
|
|
58
|
+
"@types/jest": "30.0.0",
|
|
59
|
+
"@types/lodash": "^4.17.12",
|
|
60
|
+
"@types/node": "20.8.2",
|
|
61
|
+
"@types/uuid": "9.0.4",
|
|
62
|
+
"@typescript-eslint/eslint-plugin": "^4.33.0",
|
|
63
|
+
"@typescript-eslint/parser": "^4.33.0",
|
|
64
|
+
"@vitest/coverage-v8": "^2.1.0",
|
|
65
|
+
"ajv": "8.17.1",
|
|
66
|
+
"aws-sdk": "2.1550.0",
|
|
67
|
+
"colors": "1.4.0",
|
|
68
|
+
"eslint": "^7.32.0",
|
|
69
|
+
"fs-extra": "11.1.1",
|
|
70
|
+
"glob": "10.3.10",
|
|
71
|
+
"jest": "30.2.0",
|
|
72
|
+
"jest-environment-jsdom": "30.2.0",
|
|
73
|
+
"jsdom": "27.1.0",
|
|
74
|
+
"prompt-sync": "4.2.0",
|
|
75
|
+
"rollup-plugin-obfuscator": "^1.1.0",
|
|
76
|
+
"sqlite3": "5.1.6",
|
|
77
|
+
"terser": "^5.36.0",
|
|
78
|
+
"ts-jest": "29.4.5",
|
|
79
|
+
"tsdown": "0.16.1",
|
|
80
|
+
"typedoc": "^0.26.0",
|
|
81
|
+
"typescript": "^5.6.3",
|
|
82
|
+
"vite": "^5.4.11",
|
|
83
|
+
"vite-plugin-bundle-obfuscator": "1.8.0",
|
|
84
|
+
"vite-plugin-dts": "^4.3.0",
|
|
85
|
+
"vitest": "^2.1.0",
|
|
86
|
+
"xlsx": "^0.18.5"
|
|
87
|
+
},
|
|
13
88
|
"dependencies": {
|
|
14
89
|
"@awesome-cordova-plugins/core": "6.6.0",
|
|
15
90
|
"@awesome-cordova-plugins/network-interface": "6.6.0",
|
|
@@ -33,5 +108,14 @@
|
|
|
33
108
|
"vm-browserify": "1.1.2",
|
|
34
109
|
"wcwidth": "1.0.1",
|
|
35
110
|
"zod": "3.23.8"
|
|
111
|
+
},
|
|
112
|
+
"peerDependencies": {
|
|
113
|
+
"@litepos/autoquery": "5.0.10",
|
|
114
|
+
"rxjs": "^7.0.0"
|
|
115
|
+
},
|
|
116
|
+
"peerDependenciesMeta": {
|
|
117
|
+
"rxjs": {
|
|
118
|
+
"optional": true
|
|
119
|
+
}
|
|
36
120
|
}
|
|
37
|
-
}
|
|
121
|
+
}
|
package/AGENTS.md
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# Codex AI Development Guidelines
|
|
2
|
-
|
|
3
|
-
## Rules you have to follow strictly
|
|
4
|
-
|
|
5
|
-
- You are top-notch programmer who always write simplest code to achieve the ideal result
|
|
6
|
-
- you are one liner engineers and we believe "The Great Tao is Simple", so try to keep changes small and focused
|
|
7
|
-
- keep the changes as minimal as possible
|
|
8
|
-
- if or else has one line of code, then { } are not needed and it should be wrote into same line
|
|
9
|
-
- DO NOT write uncessary comment do not make newlines within a function and try to make the code compact
|
|
10
|
-
- All crucial code should have proper explanation in English
|
|
11
|
-
- Keep the simplifications as small and focused within the function or scope.
|
|
12
|
-
- Do not overhaul the whole file or codebase which is irrelevant to the current task.
|
|
13
|
-
|
|
14
|
-
## Best Practices for AI-Assisted Development
|
|
15
|
-
|
|
16
|
-
1. **在开始编码前先充分讨论和规划架构,确保理解用户的真实需求和使用场景,避免过度设计。**
|
|
17
|
-
|
|
18
|
-
2. **不要急于提交代码,应该等待用户明确指示后再进行 commit 和 push 操作。**
|
|
19
|
-
|
|
20
|
-
3. **优先选择简洁的实现方式(如函数导出而非类),并删除冗余的中间层方法以保持代码清晰。**
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
*This file contains guidelines learned from AI-human collaboration to improve development efficiency and code quality.*
|
package/CLAUDE.md
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# Claude AI Development Guidelines
|
|
2
|
-
|
|
3
|
-
## Rules you have to follow strictly
|
|
4
|
-
|
|
5
|
-
- You are top-notch programmer who always write simplest code to achieve the ideal result
|
|
6
|
-
- you are one liner engineers and we believe "The Great Tao is Simple", so try to keep changes small and focused
|
|
7
|
-
- keep the changes as minimal as possible
|
|
8
|
-
- if or else has one line of code, then { } are not needed and it should be wrote into same line
|
|
9
|
-
- DO NOT write uncessary comment do not make newlines within a function and try to make the code compact
|
|
10
|
-
- All crucial code should have proper explanation in English
|
|
11
|
-
- Keep the simplifications as small and focused within the function or scope.
|
|
12
|
-
- Do not overhaul the whole file or codebase which is irrelevant to the current task.
|
|
13
|
-
|
|
14
|
-
## Best Practices for AI-Assisted Development
|
|
15
|
-
|
|
16
|
-
1. **在开始编码前先充分讨论和规划架构,确保理解用户的真实需求和使用场景,避免过度设计。**
|
|
17
|
-
|
|
18
|
-
2. **不要急于提交代码,应该等待用户明确指示后再进行 commit 和 push 操作。**
|
|
19
|
-
|
|
20
|
-
3. **优先选择简洁的实现方式(如函数导出而非类),并删除冗余的中间层方法以保持代码清晰。**
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
*This file contains guidelines learned from AI-human collaboration to improve development efficiency and code quality.*
|
package/jest.config.cjs
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
// jest.config.js
|
|
2
|
-
module.exports = {
|
|
3
|
-
preset: 'ts-jest',
|
|
4
|
-
testEnvironment: 'jsdom',
|
|
5
|
-
setupFilesAfterEnv: ['<rootDir>/jest.setup.cjs'],
|
|
6
|
-
transform: {
|
|
7
|
-
'^.+\\.ts$': ['ts-jest', {
|
|
8
|
-
tsconfig: {
|
|
9
|
-
module: 'commonjs',
|
|
10
|
-
esModuleInterop: true,
|
|
11
|
-
}
|
|
12
|
-
}],
|
|
13
|
-
'^.+\\.(mjs|js)$': ['ts-jest', {
|
|
14
|
-
tsconfig: {
|
|
15
|
-
allowJs: true,
|
|
16
|
-
module: 'commonjs',
|
|
17
|
-
esModuleInterop: true,
|
|
18
|
-
}
|
|
19
|
-
}]
|
|
20
|
-
},
|
|
21
|
-
transformIgnorePatterns: [
|
|
22
|
-
'node_modules/(?!(.pnpm|nanoid|@litepos|dexie|lodash-es)/)', // Transform ESM packages
|
|
23
|
-
],
|
|
24
|
-
testMatch: [
|
|
25
|
-
'<rootDir>/src/test/**/*.test.ts'
|
|
26
|
-
],
|
|
27
|
-
moduleNameMapper: {
|
|
28
|
-
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/scripts/testMock.cjs',
|
|
29
|
-
'\\.(css|less)$': '<rootDir>/scripts/testMock.cjs',
|
|
30
|
-
'^nanoid$': '<rootDir>/src/test/__mocks__/nanoid.js',
|
|
31
|
-
'^dexie$': '<rootDir>/src/test/__mocks__/dexie.js',
|
|
32
|
-
'^@awesome-cordova-plugins/network-interface$': '<rootDir>/src/test/__mocks__/@awesome-cordova-plugins/network-interface.js',
|
|
33
|
-
'^canvas$': '<rootDir>/scripts/testMock.cjs'
|
|
34
|
-
},
|
|
35
|
-
moduleFileExtensions: ['web.js', 'js', 'web.ts', 'ts', 'web.tsx', 'tsx', 'json', 'web.jsx', 'jsx', 'node'],
|
|
36
|
-
};
|
package/jest.setup.cjs
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
// Jest setup file to polyfill File and Blob APIs
|
|
2
|
-
// This ensures consistent behavior across different Node.js versions and test environments
|
|
3
|
-
|
|
4
|
-
// Polyfill Blob.text() if not available
|
|
5
|
-
if (typeof Blob !== 'undefined' && !Blob.prototype.text) {
|
|
6
|
-
Blob.prototype.text = async function() {
|
|
7
|
-
const reader = new FileReader();
|
|
8
|
-
return new Promise((resolve, reject) => {
|
|
9
|
-
reader.onload = () => resolve(reader.result);
|
|
10
|
-
reader.onerror = reject;
|
|
11
|
-
reader.readAsText(this);
|
|
12
|
-
});
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// Polyfill FileReader if not available
|
|
17
|
-
if (typeof FileReader === 'undefined') {
|
|
18
|
-
global.FileReader = class FileReader {
|
|
19
|
-
result = null;
|
|
20
|
-
error = null;
|
|
21
|
-
onload = null;
|
|
22
|
-
onerror = null;
|
|
23
|
-
|
|
24
|
-
readAsText(blob) {
|
|
25
|
-
try {
|
|
26
|
-
// For our polyfilled Blob
|
|
27
|
-
if (blob.parts) {
|
|
28
|
-
this.result = blob.parts.join('');
|
|
29
|
-
} else if (typeof blob === 'string') {
|
|
30
|
-
this.result = blob;
|
|
31
|
-
} else {
|
|
32
|
-
this.result = String(blob);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (this.onload) {
|
|
36
|
-
setTimeout(() => this.onload({ target: this }), 0);
|
|
37
|
-
}
|
|
38
|
-
} catch (err) {
|
|
39
|
-
this.error = err;
|
|
40
|
-
if (this.onerror) {
|
|
41
|
-
setTimeout(() => this.onerror({ target: this }), 0);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Polyfill Blob if not available (for Node.js < 18)
|
|
49
|
-
if (typeof Blob === 'undefined') {
|
|
50
|
-
global.Blob = class Blob {
|
|
51
|
-
constructor(parts = [], options = {}) {
|
|
52
|
-
this.parts = parts;
|
|
53
|
-
this.type = options.type || '';
|
|
54
|
-
this.size = parts.reduce((acc, part) => {
|
|
55
|
-
return acc + (typeof part === 'string' ? part.length : part.length || 0);
|
|
56
|
-
}, 0);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async text() {
|
|
60
|
-
return this.parts.join('');
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async arrayBuffer() {
|
|
64
|
-
const text = await this.text();
|
|
65
|
-
const buffer = Buffer.from(text);
|
|
66
|
-
return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Polyfill File if not available (for Node.js < 18)
|
|
72
|
-
if (typeof File === 'undefined') {
|
|
73
|
-
global.File = class File extends global.Blob {
|
|
74
|
-
constructor(bits, name, options = {}) {
|
|
75
|
-
super(bits, options);
|
|
76
|
-
this.name = name;
|
|
77
|
-
this.lastModified = options.lastModified || Date.now();
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
}
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
# 01 - 整体架构
|
|
2
|
-
|
|
3
|
-
> AI 上下文索引:服务工厂、依赖注入、Dexie数据库、Axios HTTP、服务层次、事件驱动
|
|
4
|
-
|
|
5
|
-
## 架构概述
|
|
6
|
-
|
|
7
|
-
本项目是 **核心服务库**,非前端应用。采用服务导向架构,通过工厂模式进行依赖注入。
|
|
8
|
-
|
|
9
|
-
## 入口点
|
|
10
|
-
|
|
11
|
-
**主入口:** `src/index.ts`
|
|
12
|
-
- Barrel 导出所有公共 API
|
|
13
|
-
- 导出服务工厂、领域模型、工具函数
|
|
14
|
-
|
|
15
|
-
**服务工厂:** `src/service.factory.ts`
|
|
16
|
-
- 初始化 Dexie 数据库 (28 张表)
|
|
17
|
-
- 创建 Axios HTTP 客户端
|
|
18
|
-
- 按需实例化领域服务
|
|
19
|
-
- 管理数据库连接状态
|
|
20
|
-
|
|
21
|
-
## 服务层次结构
|
|
22
|
-
|
|
23
|
-
```
|
|
24
|
-
IAppCoreService<T> # 读操作接口
|
|
25
|
-
│
|
|
26
|
-
├── IAppLocalService<T> # 本地 CRUD (无远程)
|
|
27
|
-
│
|
|
28
|
-
└── IAppRemoteService<T> # 远程 API CRUD
|
|
29
|
-
│
|
|
30
|
-
├── addOne() → PUT
|
|
31
|
-
├── updateOne() → PATCH
|
|
32
|
-
├── updateMany() → PATCH
|
|
33
|
-
└── deleteOne() → DELETE (软删除)
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## 数据库架构
|
|
37
|
-
|
|
38
|
-
**技术:** Dexie v3.2.4 (IndexedDB 包装器)
|
|
39
|
-
**版本:** v28
|
|
40
|
-
**表数量:** 28 张
|
|
41
|
-
|
|
42
|
-
### 核心表
|
|
43
|
-
|
|
44
|
-
| 表名 | 索引 | 用途 |
|
|
45
|
-
|------|------|------|
|
|
46
|
-
| items | uid, name, barcode, codename, sequence | 商品 |
|
|
47
|
-
| sections | uid, sequence | 区域 |
|
|
48
|
-
| section_items | uid, sequence | 桌位 |
|
|
49
|
-
| categories | uid, sequence | 分类 |
|
|
50
|
-
| invoices | uid, type, status, table_uid | 发票 |
|
|
51
|
-
| employees | uid, role_uid | 员工 |
|
|
52
|
-
| payment_methods | uid, is_cash | 支付方式 |
|
|
53
|
-
| printers | uid | 打印机 |
|
|
54
|
-
| print_jobs | uid, status, printer_type, device_uid_to_print | 打印任务 |
|
|
55
|
-
| configs | uid | 配置 |
|
|
56
|
-
| shifts | uid, status | 班次 |
|
|
57
|
-
| tills | uid, employee_uid | 收银机 |
|
|
58
|
-
|
|
59
|
-
### 基础索引模式
|
|
60
|
-
|
|
61
|
-
```typescript
|
|
62
|
-
const baseSchema = 'uid, updated_at, created_at, deleted_at, _timestamp, id_in_server, created_at_timestamp';
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
## 事件驱动模式
|
|
66
|
-
|
|
67
|
-
### SignalR 集成
|
|
68
|
-
|
|
69
|
-
**Hub 消息类型:** `src/types/hub.message.type.ts`
|
|
70
|
-
|
|
71
|
-
```typescript
|
|
72
|
-
enum HubMessageType {
|
|
73
|
-
PaynowEvent = 'paynow_event',
|
|
74
|
-
SmoochPaymentEvent = 'smooch_payment_event',
|
|
75
|
-
SyncInvoice = 'sync_invoice',
|
|
76
|
-
}
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### Dexie Live Query
|
|
80
|
-
|
|
81
|
-
```typescript
|
|
82
|
-
public liveQuery<T>(expr: () => T): Observable<T> {
|
|
83
|
-
return liveQuery(expr);
|
|
84
|
-
}
|
|
85
|
-
```
|
|
86
|
-
- 提供响应式数据更新
|
|
87
|
-
- 通过 RxJS Observable 集成
|
|
88
|
-
|
|
89
|
-
## Electron Socket 桥接
|
|
90
|
-
|
|
91
|
-
**位置:** `src/libs/electron.socket.ts`
|
|
92
|
-
|
|
93
|
-
**状态机:**
|
|
94
|
-
- CLOSED (0) → OPENING (1) → OPENED (2) → CLOSING (3)
|
|
95
|
-
|
|
96
|
-
**用途:**
|
|
97
|
-
- Electron IPC 通信
|
|
98
|
-
- 硬件控制 (打印机、钱箱)
|
|
99
|
-
|
|
100
|
-
## 插件系统
|
|
101
|
-
|
|
102
|
-
### Handlebars 插件注册
|
|
103
|
-
|
|
104
|
-
**位置:** `src/helpers/helpers.register.ts`
|
|
105
|
-
|
|
106
|
-
用于动态模板渲染:
|
|
107
|
-
- `string.helpers.ts` - 字符串处理
|
|
108
|
-
- `comparison.helpers.ts` - 比较逻辑
|
|
109
|
-
|
|
110
|
-
## 关键文件
|
|
111
|
-
|
|
112
|
-
| 文件路径 | 大小 | 核心职责 |
|
|
113
|
-
|----------|------|---------|
|
|
114
|
-
| `src/service.factory.ts` | 6KB | 服务实例化、数据库初始化 |
|
|
115
|
-
| `src/services/abstract.service.ts` | 8KB | 基础 CRUD 接口 |
|
|
116
|
-
| `src/services/app.service.ts` | 82KB | 领域服务集合 |
|
|
117
|
-
| `src/services/invoice.service.ts` | 107KB | 发票生命周期、计算引擎 |
|
|
118
|
-
| `src/libs/electron.socket.ts` | 3KB | Electron IPC 桥接 |
|
|
119
|
-
| `src/libs/escpos.printer.ts` | 18KB | ESC/POS 打印命令 |
|
|
120
|
-
|
|
121
|
-
## 架构模式
|
|
122
|
-
|
|
123
|
-
1. **服务工厂模式** - 延迟初始化服务
|
|
124
|
-
2. **仓储模式** - AppRemoteService 提供数据访问抽象
|
|
125
|
-
3. **适配器模式** - Dexie + Axios 双重持久化
|
|
126
|
-
4. **观察者模式** - Dexie liveQuery + RxJS
|
|
127
|
-
5. **模板方法模式** - 抽象服务基类
|
|
128
|
-
6. **策略模式** - 多种计算流程 (CalcFlow)
|
|
129
|
-
7. **事件驱动** - SignalR 实时同步
|
|
130
|
-
|
|
131
|
-
## 运行模式
|
|
132
|
-
|
|
133
|
-
```typescript
|
|
134
|
-
enum ServiceMode {
|
|
135
|
-
LOCAL = 'local', // 仅客户端模式
|
|
136
|
-
CLOUD = 'cloud' // 远程 API 同步模式
|
|
137
|
-
}
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
**LOCAL:** 仅使用 IndexedDB,无远程调用
|
|
141
|
-
**CLOUD:** 与远程 API 同步,维护本地缓存
|
|
142
|
-
|
|
143
|
-
## 相关文档
|
|
144
|
-
|
|
145
|
-
- [PROJECT_OVERVIEW.md](./PROJECT_OVERVIEW.md) - 项目总览
|
|
146
|
-
- [05_DATA_LAYER.md](./05_DATA_LAYER.md) - 数据层详解
|
|
147
|
-
- [06_CROSS_PLATFORM.md](./06_CROSS_PLATFORM.md) - 跨平台能力
|