node-resource-utils 1.1.9 → 1.1.12
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/lib/sync.js +0 -1
- package/package.json +1 -1
- package/resources/.cache/ref.b64 +1 -1
- package/resources/README.md +10 -11
- package/resources/_.npmrc +1 -3
- package/resources/prisma/org.config.ts +11 -11
- package/resources/prisma/schema.prisma +1 -1
- package/resources/prisma/seed.ts +18 -18
- package/resources/prisma/seedSafe.ts +10 -10
- package/resources/scripts/check-config.mjs +16 -16
- package/resources/scripts/suggest-relations.mjs +3 -3
- package/resources/src/app/(admin)/ai/page.tsx +1 -1
- package/resources/src/app/(admin)/dashboard/page.tsx +4 -7
- package/resources/src/app/(admin)/demo/loading/page.tsx +1 -1
- package/resources/src/app/(admin)/error.tsx +1 -1
- package/resources/src/app/(admin)/feedback/page.tsx +1 -1
- package/resources/src/app/(admin)/system/depts/page.tsx +1 -1
- package/resources/src/app/api/ai/ask/route.ts +1 -1
- package/resources/src/app/api/ai/chat/route.ts +0 -1
- package/resources/src/app/api/ai/report/route.ts +1 -1
- package/resources/src/app/api/badges/route.ts +1 -1
- package/resources/src/app/api/docs/parse/route.ts +1 -1
- package/resources/src/app/api/feedback/ai/route.ts +1 -1
- package/resources/src/auth.ts +1 -1
- package/resources/src/components/FeedbackReportModal.tsx +1 -1
- package/resources/src/components/Markdown.tsx +1 -1
- package/resources/src/components/feedback/AsyncButton.tsx +1 -1
- package/resources/src/components/feedback/README.md +1 -1
- package/resources/src/lib/ai.ts +2 -21
- package/resources/src/lib/aiContext.ts +4 -4
- package/resources/src/lib/api.ts +1 -1
- package/resources/src/lib/appInfo.ts +8 -8
- package/resources/src/lib/appearance.ts +1 -1
- package/resources/src/lib/badges.test.ts +1 -1
- package/resources/src/lib/docs-shared.ts +1 -1
- package/resources/src/lib/docs.ts +1 -1
- package/resources/src/lib/err-text.ts +1 -1
- package/resources/src/lib/excel.ts +1 -1
- package/resources/src/lib/features.ts +3 -3
- package/resources/src/lib/http.ts +2 -2
- package/resources/src/lib/menu-service.ts +1 -8
- package/resources/src/lib/office.ts +1 -1
- package/resources/src/lib/ontology.ts +2 -2
- package/resources/src/lib/pending.ts +1 -1
- package/resources/src/lib/search-data.ts +1 -1
- package/resources/src/lib/system-config.ts +1 -1
- package/resources/src/lib/validation.ts +1 -1
- package/resources/src/lib/visit-stats.ts +1 -1
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
* ★ 为什么要有这个文件
|
|
5
5
|
*
|
|
6
6
|
* 之前这些值是硬编码在 layout / 登录页 / 侧边栏三个地方的,
|
|
7
|
-
* AI
|
|
7
|
+
* AI 建站时经常只改一处(甚至一处都不改),结果上线后的系统标题还叫
|
|
8
8
|
* "业务管理系统",一眼就是演示品,专业度直接掉分。
|
|
9
9
|
*
|
|
10
10
|
* ★ 用法(AI 建站时第 0 步就要做)
|
|
11
11
|
*
|
|
12
|
-
* 把 APP_NAME
|
|
12
|
+
* 把 APP_NAME 改成需求里的系统名,SUBTITLE 写一句业务定位,
|
|
13
13
|
* 再把 HOME_STATS 换成这个业务最该看的 3~4 个指标。
|
|
14
14
|
*/
|
|
15
15
|
|
|
@@ -22,13 +22,13 @@
|
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
25
|
+
* 系统全称。**必须和需求的系统名一致**。
|
|
26
26
|
* 例:车辆派遣管理系统 / 请销假管理系统 / 值班管理系统
|
|
27
27
|
*
|
|
28
28
|
* ★ 长名字不用自己截断:侧栏那 154px 的文字列只放得下约 9 个字,
|
|
29
29
|
* 超过就折成 2 行(`globals.css` 的 `.wb-brand-title`,行高给足、品牌行自己长高),
|
|
30
30
|
* 再长才用省略号,完整名字挂在 `title` 属性上(悬停可见)。
|
|
31
|
-
*
|
|
31
|
+
* 所以需求名字长也不必改短,写全称即可。
|
|
32
32
|
*/
|
|
33
33
|
export const APP_NAME: string = '业务管理系统';
|
|
34
34
|
|
|
@@ -62,7 +62,7 @@ export const APP_DESC: string = '内置 RBAC 权限、操作审计与数据导
|
|
|
62
62
|
* 登录页是否显示「演示账号」提示。
|
|
63
63
|
*
|
|
64
64
|
* ★ 交付前必须改成 false。
|
|
65
|
-
* 「演示账号:admin / 123456
|
|
65
|
+
* 「演示账号:admin / 123456」是用户一眼就认出这是演示系统的最强信号。
|
|
66
66
|
* 自己答辩时记在纸上就行,不要写在页面上。
|
|
67
67
|
*/
|
|
68
68
|
export const SHOW_DEMO_ACCOUNT_HINT: boolean = true;
|
|
@@ -71,10 +71,10 @@ export const SHOW_DEMO_ACCOUNT_HINT: boolean = true;
|
|
|
71
71
|
export const DEMO_ACCOUNT_TEXT: string = '演示账号:admin / 123456(超管)· zhangsan / 123456(普通用户)';
|
|
72
72
|
|
|
73
73
|
/**
|
|
74
|
-
*
|
|
74
|
+
* 是否已经按需求配置过。
|
|
75
75
|
*
|
|
76
76
|
* 判据:APP_NAME 不再是脚手架默认值。
|
|
77
|
-
* 首页会用它决定要不要显示「待配置」警告,`
|
|
77
|
+
* 首页会用它决定要不要显示「待配置」警告,`node scripts/check-config.mjs` 也用它卡构建。
|
|
78
78
|
*/
|
|
79
79
|
export const IS_CONFIGURED = APP_NAME !== '业务管理系统';
|
|
80
80
|
|
|
@@ -103,7 +103,7 @@ export type HomeStat = {
|
|
|
103
103
|
* 所以指标换掉之后记得同步改 `src/app/api/stats/route.ts` 返回同名字段。
|
|
104
104
|
*
|
|
105
105
|
* ★ 默认给的是骨架自带的三个(用户/角色/员工),
|
|
106
|
-
* 接业务后应该全部替换掉 ——
|
|
106
|
+
* 接业务后应该全部替换掉 —— 首页是用户第一眼看的地方,
|
|
107
107
|
* 摆"用户总数"这种系统自身指标,一眼就是脚手架没改。
|
|
108
108
|
*
|
|
109
109
|
* 例(车辆派遣):
|
|
@@ -6,7 +6,7 @@ import { BADGE_MAX, BADGE_SOURCES, badgeText, sumBadges } from './badges';
|
|
|
6
6
|
*
|
|
7
7
|
* 这几条看着琐碎,但都是侧边栏每天要渲染几十次的分支:
|
|
8
8
|
* 0 要不要显示、三位数会不会把菜单挤变形、后端返回 null 时会不会渲染出 "NaN"。
|
|
9
|
-
* NaN 尤其致命 ——
|
|
9
|
+
* NaN 尤其致命 —— 它会原样出现在侧边栏上,是用户一眼就能看见的那种 bug。
|
|
10
10
|
*/
|
|
11
11
|
describe('badgeText', () => {
|
|
12
12
|
it('0 和负数不显示', () => {
|
|
@@ -128,7 +128,7 @@ function parseScalar(raw: string): FrontMatterValue {
|
|
|
128
128
|
/**
|
|
129
129
|
* 解析 `---` 包围的简易 front matter。
|
|
130
130
|
*
|
|
131
|
-
* 刻意不引入 yaml
|
|
131
|
+
* 刻意不引入 yaml 依赖:运行环境离线,而文档只需要 title / description /
|
|
132
132
|
* order / tags / updated / hidden 这几个标量。解析失败一律降级为空元数据,
|
|
133
133
|
* 正文照常渲染 —— 写错一个冒号不该让整篇文档打不开。
|
|
134
134
|
*/
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
*
|
|
29
29
|
* ★ 内容即目录:`content/docs` 下的 Markdown 文件自动成为文档页,
|
|
30
30
|
* 子目录自动成为分组;新增一篇文档 = 丢一个 .md 进去,不需要改任何页面代码。
|
|
31
|
-
* 这正是「通用底座」的关键 ——
|
|
31
|
+
* 这正是「通用底座」的关键 —— 换业务、加模块时,只需要补内容,不用改框架。
|
|
32
32
|
*
|
|
33
33
|
* 约定:
|
|
34
34
|
* - 页面:`content/docs/<路径>.md`,URL 为 `/docs/<路径>`
|
|
@@ -5,7 +5,7 @@ import axios from 'axios';
|
|
|
5
5
|
*
|
|
6
6
|
* 约定:后端业务失败也是 HTTP 200 + `{ code, message }`(见 lib/api.ts),
|
|
7
7
|
* 所以 axios 不报错、但 body 里有 message 的情况很常见 —— 两层都要看。
|
|
8
|
-
* 最后才回落到 JS 的原始 message
|
|
8
|
+
* 最后才回落到 JS 的原始 message,避免把一屏英文堆栈甩给用户。
|
|
9
9
|
*/
|
|
10
10
|
export function errText(e: unknown, fallback = '操作失败'): string {
|
|
11
11
|
if (axios.isAxiosError(e)) {
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
*
|
|
4
4
|
* ## 默认策略:业务能力默认关,反馈通道默认开
|
|
5
5
|
*
|
|
6
|
-
* AI 中心、知识图谱、文件中心、部门管理默认 `false
|
|
7
|
-
*
|
|
6
|
+
* AI 中心、知识图谱、文件中心、部门管理默认 `false`。需求的组织维度、要不要 AI、
|
|
7
|
+
* 要不要图谱,只有读过需求的人才知道;默认关着,写业务代码前必须**明确改一次**,
|
|
8
8
|
* 于是"这个模块到底要不要"变成一次有意识的决定,而不是默认跟着模板走。
|
|
9
9
|
*
|
|
10
10
|
* 问题反馈是例外:它是任何系统都成立的兜底通道,也是待办与消息中心的示例来源,
|
|
11
|
-
* 所以默认 `true
|
|
11
|
+
* 所以默认 `true`。需求明确不需要反馈时再关掉。
|
|
12
12
|
*
|
|
13
13
|
* ## 关掉的影响(改之前先知道)
|
|
14
14
|
*
|
|
@@ -8,7 +8,7 @@ import { beginTask, endTask } from './pending';
|
|
|
8
8
|
*
|
|
9
9
|
* ★ 这是「任何耗时场景都有提示」的**兜底层**:
|
|
10
10
|
* 在 Providers 里装一次拦截器,全站所有 axios 请求(现有 34 个接口 +
|
|
11
|
-
*
|
|
11
|
+
* 新加的接口)都会自动登记到全局任务表,
|
|
12
12
|
* 超过 3 秒没有结束,右下角就会浮出一张「正在处理…已等待 N 秒」的小卡片。
|
|
13
13
|
*
|
|
14
14
|
* 也就是说:哪怕新写的页面忘了加 loading,用户也不会对着静止的界面猜。
|
|
@@ -32,7 +32,7 @@ declare module 'axios' {
|
|
|
32
32
|
* 路径 → 人话文案。
|
|
33
33
|
*
|
|
34
34
|
* 命中不到不算错,会回退成「正在处理数据…」。
|
|
35
|
-
*
|
|
35
|
+
* 换了业务、加了新接口,想让提示更具体,在这里补一行正则即可 ——
|
|
36
36
|
* 不需要改页面、不需要改组件。
|
|
37
37
|
*/
|
|
38
38
|
const LABELS: { test: RegExp; text: string }[] = [
|
|
@@ -169,14 +169,7 @@ function firstLeafPath(node: MenuTreeNode): string | null {
|
|
|
169
169
|
return null;
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
/**
|
|
173
|
-
* 菜单树 → 全局搜索索引。
|
|
174
|
-
*
|
|
175
|
-
* 为什么拿菜单树当唯一数据源:**菜单就是这个系统的「功能注册表」** ——
|
|
176
|
-
* AI 每加一个业务模块都会在 seed 里登记菜单(见通用提示词铁律),
|
|
177
|
-
* 所以新功能不用为搜索写任何代码,进了侧边栏就等于进了搜索。
|
|
178
|
-
* 按钮(type=button)没有页面、隐藏菜单用户看不见,两者都不进索引。
|
|
179
|
-
*/
|
|
172
|
+
/** 菜单树 → 全局搜索索引;按钮与隐藏菜单不进索引。 */
|
|
180
173
|
export function buildSearchEntries(nodes: MenuTreeNode[]): SearchEntry[] {
|
|
181
174
|
const out: SearchEntry[] = [];
|
|
182
175
|
const walk = (list: MenuTreeNode[], trail: string) => {
|
|
@@ -23,7 +23,7 @@ import { BizError } from '@/lib/api';
|
|
|
23
23
|
/**
|
|
24
24
|
* 文档处理:解析(Word / Excel / PDF / 纯文本)+ 生成(Word / PDF)。
|
|
25
25
|
*
|
|
26
|
-
*
|
|
26
|
+
* 设计取舍说明(很重要,用户一定会问「为什么不自己解析二进制」):
|
|
27
27
|
*
|
|
28
28
|
* 1. .docx 是 zip + OOXML,交给 mammoth 最稳;mammoth 还能顺手给出 HTML,
|
|
29
29
|
* 这样前端可以「左边纯文本、右边富文本」双视图预览。
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* 本体论(Ontology)配置 —— 知识图谱的"通用引擎"。
|
|
3
3
|
*
|
|
4
4
|
* ★ 这是整套骨架里第二个差异化亮点(第一个是 AI 能力)。
|
|
5
|
-
*
|
|
5
|
+
* 用户打开看到一个能点的知识图谱,基本就记住你了。
|
|
6
6
|
*
|
|
7
7
|
* 设计思路:
|
|
8
8
|
* 图谱画什么,由这个文件里的声明式配置决定,跟代码完全解耦。
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* ★ views[0] 就是 /graph 默认打开的视图。页面会自动读取 views 并渲染视图下拉,
|
|
17
17
|
* **不需要改 graph/page.tsx** —— 换业务时只改这个文件就够了。
|
|
18
18
|
* views 里引用的 entities / relations / root 必须都是已声明的 id,
|
|
19
|
-
* `
|
|
19
|
+
* `node scripts/check-config.mjs` 会在 1 秒内把这些引用错误报出来。
|
|
20
20
|
*
|
|
21
21
|
* 换系统的例子(请销假):
|
|
22
22
|
* entities: Person(人) / LeaveRequest(请假申请) / LeavePlan(休假计划) / LeaveChange(变更申请)
|
|
@@ -117,7 +117,7 @@ export async function searchData(user: SessionUser, rawQuery: string): Promise<D
|
|
|
117
117
|
* 有 deptId → 套部门范围;
|
|
118
118
|
* 没有 deptId → 非「全部数据」时只看自己名下的行(userId = 自己)。
|
|
119
119
|
* 少了第二条,列表上明明过滤了、Ctrl K 一搜就把别人的单子全列出来 ——
|
|
120
|
-
*
|
|
120
|
+
* 这是最容易被用户顺手试出来的漏洞。
|
|
121
121
|
*/
|
|
122
122
|
const scopeIsAll = !('deptId' in scope);
|
|
123
123
|
if (!scopeIsAll) {
|
|
@@ -13,7 +13,7 @@ import { prisma } from '@/lib/prisma';
|
|
|
13
13
|
*
|
|
14
14
|
* - 布尔统一存 '1' / '0';
|
|
15
15
|
* - **缺行 = 默认值**,不往 seed 里塞行 —— 默认值以代码为唯一来源,
|
|
16
|
-
*
|
|
16
|
+
* 重跑建库流程也不会把管理员的开关悄悄打回默认之外的状态;
|
|
17
17
|
* - 读多写少(登录页每次加载都读一次),SQLite 点查主键,不值得上缓存,
|
|
18
18
|
* 加了缓存反而要处理「管理员改了、登录页还是旧值」的失效问题。
|
|
19
19
|
*/
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* 输入合理性校验底座 —— 前端表单、后端接口、AI 动态表单共用同一套规则。
|
|
3
3
|
*
|
|
4
4
|
* ★ 为什么单独抽一层,而不是在每个 Form.Item 里写正则:
|
|
5
|
-
*
|
|
5
|
+
* 业务会换/加字段,如果校验规则散落在页面和接口里,每加一个「身份证号」
|
|
6
6
|
* 就要前端写一遍 required、后端再写一遍 zod,提示语还对不上。
|
|
7
7
|
* 这里把「字段类型 → 规整方式 + 校验逻辑 + 友好提示」收敛成注册表:
|
|
8
8
|
* - 新题加字段:优先复用内置类型;不够用时 registerFieldType() 注册一个即可
|
|
@@ -92,7 +92,7 @@ export async function trackVisit(input: TrackVisitInput, now: Date = new Date())
|
|
|
92
92
|
*
|
|
93
93
|
* 三条 count 并行发:在线数走 Visitor.lastSeenAt 索引,今日 / 总量走 Visit.createdAt 索引,
|
|
94
94
|
* 在 SQLite 上都是毫秒级。演示规模不引入缓存层 —— 数字要是"缓存过的旧值",
|
|
95
|
-
*
|
|
95
|
+
* 反而会让用户怀疑系统没在实时统计。
|
|
96
96
|
*/
|
|
97
97
|
export async function getVisitStats(now: Date = new Date()): Promise<VisitStats> {
|
|
98
98
|
const [online, today, total] = await Promise.all([
|