明树Git Lab
Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
J
jt_backend
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
zengfanpei
jt_backend
Commits
92a3120b
Commit
92a3120b
authored
May 16, 2026
by
zfp1
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update
parent
eb30e1dd
Pipeline
#111440
passed with stage
in 4 seconds
Changes
2
Pipelines
1
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
522 additions
and
5 deletions
+522
-5
project.js
db/model/jt/project.js
+21
-5
代码检查报告.md
代码检查报告.md
+501
-0
No files found.
db/model/jt/project.js
View file @
92a3120b
...
@@ -222,6 +222,22 @@ const Project = sequelize.define('Project', {
...
@@ -222,6 +222,22 @@ const Project = sequelize.define('Project', {
// sfgjldjq: { type: DataTypes.INTEGER, allowNull: true, comment: "是否国家领导见签" },
// sfgjldjq: { type: DataTypes.INTEGER, allowNull: true, comment: "是否国家领导见签" },
// sfjntbjgl: { type: DataTypes.INTEGER, allowNull: true, comment: "是否境内特别监管类" },
// sfjntbjgl: { type: DataTypes.INTEGER, allowNull: true, comment: "是否境内特别监管类" },
// sfydylyxgj: { type: DataTypes.INTEGER, allowNull: true, comment: "是否一带一路沿线国家" },
// sfydylyxgj: { type: DataTypes.INTEGER, allowNull: true, comment: "是否一带一路沿线国家" },
sfythzxm
:
{
type
:
DataTypes
.
STRING
(
10
),
allowNull
:
true
,
comment
:
"是否一体化子项目"
,
_mark
:
'juece'
,
zjType
:
'danxuan'
,
zjKey
:
'sf'
},
//1是 2否
sflrgzwfmqd
:
{
type
:
DataTypes
.
STRING
(
10
),
allowNull
:
true
,
comment
:
"是否列入国资委负面清单"
,
_mark
:
'juece'
,
zjType
:
'danxuan'
,
zjKey
:
'sf'
},
//1是 2否
bjfl
:
{
type
:
DataTypes
.
STRING
(
10
),
allowNull
:
true
,
comment
:
"2+9布局分类"
,
_mark
:
'juece'
,
zjType
:
'danxuan'
},
//1是 2否
"jcpfshcs"
:
{
"name"
:
"决策批复审核处室"
,
"type"
:
DataTypes
.
STRING
,
},
jcpfwj
:
{
type
:
DataTypes
.
JSON
,
comment
:
"决策批复文件"
,
},
tpbgjcsb
:
{
type
:
DataTypes
.
JSON
,
comment
:
"投评报告及测算表"
,
},
//建设规模(实物量指标)---立项表格
//建设规模(实物量指标)---立项表格
gsgllc
:
{
type
:
DataTypes
.
DECIMAL
(
20
,
8
),
allowNull
:
true
,
comment
:
"高速公路里程"
,
_mark
:
'juece'
},
gsgllc
:
{
type
:
DataTypes
.
DECIMAL
(
20
,
8
),
allowNull
:
true
,
comment
:
"高速公路里程"
,
_mark
:
'juece'
},
qtsfgllc
:
{
type
:
DataTypes
.
DECIMAL
(
20
,
8
),
allowNull
:
true
,
comment
:
"其他收费公路里程"
,
_mark
:
'juece'
},
qtsfgllc
:
{
type
:
DataTypes
.
DECIMAL
(
20
,
8
),
allowNull
:
true
,
comment
:
"其他收费公路里程"
,
_mark
:
'juece'
},
...
@@ -500,11 +516,11 @@ const Project = sequelize.define('Project', {
...
@@ -500,11 +516,11 @@ const Project = sequelize.define('Project', {
},
},
"kybzdw"
:
{
"kybzdw"
:
{
"name"
:
"可研编制单位"
,
"name"
:
"可研编制单位"
,
"type"
:
DataTypes
.
STRING
,
"type"
:
DataTypes
.
STRING
(
50
)
,
},
},
"kypsdw"
:
{
"kypsdw"
:
{
"name"
:
"可研评审单位"
,
"name"
:
"可研评审单位"
,
"type"
:
DataTypes
.
STRING
,
"type"
:
DataTypes
.
STRING
(
50
)
,
},
},
"qtzcwnbsyl"
:
{
"qtzcwnbsyl"
:
{
"name"
:
"经济可行性-全投资财务内部收益率(税前)"
,
"name"
:
"经济可行性-全投资财务内部收益率(税前)"
,
...
@@ -516,15 +532,15 @@ const Project = sequelize.define('Project', {
...
@@ -516,15 +532,15 @@ const Project = sequelize.define('Project', {
},
},
"jxjlhznf"
:
{
"jxjlhznf"
:
{
"name"
:
"经济可行性-净现金流回正年份"
,
"name"
:
"经济可行性-净现金流回正年份"
,
"type"
:
DataTypes
.
STRING
,
"type"
:
DataTypes
.
STRING
(
20
)
,
},
},
"jlrhznf"
:
{
"jlrhznf"
:
{
"name"
:
"经济可行性-净利润回正年份"
,
"name"
:
"经济可行性-净利润回正年份"
,
"type"
:
DataTypes
.
STRING
,
"type"
:
DataTypes
.
STRING
(
20
)
,
},
},
"kfplrhznf"
:
{
"kfplrhznf"
:
{
"name"
:
"经济可行性-可分配利润回正年份"
,
"name"
:
"经济可行性-可分配利润回正年份"
,
"type"
:
DataTypes
.
STRING
,
"type"
:
DataTypes
.
STRING
(
20
)
,
},
},
"cwjxz"
:
{
"cwjxz"
:
{
"name"
:
"经济可行性-财务净现值(税前)"
,
"name"
:
"经济可行性-财务净现值(税前)"
,
...
...
代码检查报告.md
0 → 100644
View file @
92a3120b
# 代码检查报告
检查时间:2026-05-15
范围:项目根目录下的 JS 代码、路由、控制器、模块、模型初始化和部分配置。
说明:本次只做检查并输出建议,未修改业务代码。
## 检查结果概览
-
全量 JS 语法检查通过:对
`rg --files -g "*.js"`
找到的所有 JS 文件执行
`node --check`
,结果为
`ALL_JS_SYNTAX_OK`
。
-
`npm run lint -- --quiet`
未能执行规则检查:当前项目使用 ESLint 9.4.0,但项目仍是
`.eslintrc.js`
配置,ESLint 9 默认要求
`eslint.config.js`
。
-
当前没有发现解析级语法错误,但存在多处会导致接口运行时报错、数据遗漏、权限边界不准或线上部署风险的问题。
## 高风险问题
### 1. 批量上传会运行时报错
位置:
`controller/fileController.js:44`
```
js
let
data
=
await
DB
.
File
.
insertMany
(
ret
);
```
`DB.File`
是 Sequelize 模型,不是 Mongo/Mongoose 模型,Sequelize 没有
`insertMany`
方法。
`/file/batch/upload`
会在保存文件记录时报
`DB.File.insertMany is not a function`
。
建议:
```
js
let
data
=
await
DB
.
File
.
bulkCreate
(
ret
);
```
并建议补充空文件判断:
```
js
if
(
!
req
.
files
||
!
req
.
files
.
length
)
{
return
res
.
sendError
(
errorMessage
.
paramsError
);
}
```
### 2. 创建用户时岗位关系字段写错
位置:
`controller/userController.js:182`
```
js
let
userPositions
=
body
.
positions
.
map
(
o
=>
{
return
{
userId
:
ret
.
id
,
roleId
:
o
&&
o
.
id
||
o
}
});
```
`system_user_position`
模型字段是
`posiId`
,不是
`roleId`
。当前创建用户时岗位关系会写不进去或写成无效字段,导致用户岗位丢失。
建议:
```
js
let
userPositions
=
body
.
positions
.
map
(
o
=>
{
return
{
userId
:
ret
.
id
,
posiId
:
o
&&
o
.
id
||
o
};
});
```
### 3. 更新用户岗位时新增岗位取错数组
位置:
`module/userModule.js:85-88`
```
js
for
(
let
index
=
0
;
index
<
positionIds
.
length
;
index
++
)
{
const
element
=
positions
[
index
];
if
(
!
dbIds
.
includes
(
element
))
{
needAddIds
.
push
(
element
);
}
}
```
这里应该遍历
`positionIds`
,但实际取的是
`positions[index]`
。结果是新增岗位时会把旧岗位对象放入
`needAddIds`
,后续
`posiId`
可能变成对象或
`undefined`
,导致岗位关系异常。
建议:
```
js
const
element
=
positionIds
[
index
];
```
### 4. 更新用户岗位后删除了错误字段
位置:
`controller/userController.js:278-282`
```
js
if
(
body
.
positions
&&
body
.
positions
.
length
)
{
const
positionIds
=
body
.
positions
.
map
(
o
=>
{
return
o
&&
o
.
id
||
o
});
await
userModule
.
setUserPosition
(
user
.
id
,
positionIds
,
user
.
positions
||
[]);
delete
body
.
roles
;
}
```
这里应该删除
`body.positions`
,否则
`DB.User.update(body)`
仍会带着
`positions`
字段更新用户表,可能导致 Sequelize 忽略无效字段,也可能引入不可预期行为。同时误删
`body.roles`
会影响同一次请求中角色字段处理后的状态。
建议:
```
js
delete
body
.
positions
;
```
### 5. 更新用户时空用户会先 `toJSON` 报错
位置:
`controller/userController.js:238-262`
```
js
let
user
=
await
DB
.
User
.
findOne
(...);
user
=
user
.
toJSON
();
if
(
!
(
user
&&
user
.
id
))
{
return
res
.
sendError
(
errorMessage
.
resourceNotFound
);
}
```
如果用户不存在,
`user`
为
`null`
,会先执行
`user.toJSON()`
并抛异常,无法返回预期的
`resourceNotFound`
。
建议:
```
js
if
(
!
(
user
&&
user
.
id
))
{
return
res
.
sendError
(
errorMessage
.
resourceNotFound
);
}
user
=
user
.
toJSON
();
```
### 6. 菜单详情接口查错模型
位置:
`controller/menuController.js:124`
```
js
const
ret
=
await
DB
.
Depart
.
findOne
({
where
:
{
id
:
req
.
body
.
id
},
raw
:
true
});
```
`getMenu`
应该查菜单表,但当前查的是部门表。菜单详情接口会返回部门数据或空数据。
建议:
```
js
const
ret
=
await
DB
.
Menu
.
findOne
({
where
:
{
id
:
req
.
body
.
id
},
raw
:
true
});
```
### 7. 部门删除前检查子部门用户时漏逗号
位置:
`controller/departController.js:105`
```
js
let
depts
=
await
DB
.
Depart
.
findAll
({
where
:
{
parentIds
:
{
[
Op
.
startsWith
]:
curNode
.
parentIds
+
curNode
.
id
}
},
attributes
:
[
'id'
],
raw
:
true
});
```
`parentIds`
的生成规则是
`父 parentIds + "," + 父 id`
。这里拼接少了逗号,比如
`40,86`
+
`100`
变成
`40,86100`
,会查不到子部门。结果是:子部门下有用户时,父部门仍可能被删除。
建议复用后面的
`parStr`
:
```
js
let
parStr
=
curNode
.
parentIds
?
`
${
curNode
.
parentIds
}
,
${
curNode
.
id
}
`
:
String
(
curNode
.
id
);
let
depts
=
await
DB
.
Depart
.
findAll
({
where
:
{
[
Op
.
or
]:
[
{
parentIds
:
parStr
},
{
parentIds
:
{
[
Op
.
startsWith
]:
`
${
parStr
}
,`
}
}
]
},
attributes
:
[
'id'
],
raw
:
true
});
```
### 8. 部门/菜单级联删除存在前缀误伤风险
位置:
-
`controller/departController.js:119`
-
`controller/menuController.js:108`
当前写法:
```
js
{
parentIds
:
{
[
Op
.
startsWith
]:
parStr
}
}
```
如果节点路径是
`40,86,10`
,另一个节点路径是
`40,86,100`
,字符串上后者也以
`40,86,10`
开头,可能误删不属于当前节点的兄弟分支。
建议使用边界匹配:
```
js
[
Op
.
or
]:
[
{
parentIds
:
parStr
},
{
parentIds
:
{
[
Op
.
startsWith
]:
`
${
parStr
}
,`
}
},
{
id
:
curNode
.
id
}
]
```
### 9. 请求鉴权中间件调用 `next(401)` 后没有 `return`
位置:
`middleware/request.js:10-29`
当前代码在以下分支调用
`next(createError(401))`
后仍会继续执行后续日志和最终
`next()`
:
```
js
next
(
createError
(
401
));
```
这可能导致未授权请求继续进入后续流程,或触发
`next()`
多次,出现重复响应、错误日志异常等问题。
建议所有错误分支都改成:
```
js
return
next
(
createError
(
401
));
```
同时 Redis 解析失败分支也应立即返回。
### 10. 项目资料更新中的 `Promise.all` 实际没有等待更新完成
位置示例:
-
`controller/projectController.js:182`
-
`controller/projectController.js:189`
-
`controller/projectController.js:196`
-
`controller/projectController.js:203`
-
`controller/projectController.js:210`
-
`controller/projectController.js:218`
-
`controller/projectController.js:225`
-
`controller/projectController.js:616-695`
同类问题
-
`controller/projectThController.js:278`
-
`controller/projectThController.js:316`
-
`controller/projectThController.js:402`
示例:
```
js
await
Promise
.
all
(
pns1
.
map
(
item
=>
{
DB
.
ProjectJsgm
.
update
(
item
,
{
where
:
{
id
:
item
.
id
}
})
}));
```
箭头函数用了
`{}`
但没有
`return`
,
`map`
返回的是
`undefined`
数组,
`Promise.all`
会立即完成,实际更新在后台执行,错误也可能丢失。接口可能提前返回,造成数据未更新完或异常无法回滚。
建议:
```
js
await
Promise
.
all
(
pns1
.
map
(
item
=>
{
return
DB
.
ProjectJsgm
.
update
(
item
,
{
where
:
{
id
:
item
.
id
}
});
}));
```
或简写:
```
js
await
Promise
.
all
(
pns1
.
map
(
item
=>
DB
.
ProjectJsgm
.
update
(
item
,
{
where
:
{
id
:
item
.
id
}
})));
```
### 11. 项目公司列表权限会漏掉挂在公司根节点上的用户
位置:
`controller/projectController.js:1331-1345`
当前逻辑查出公司下属部门后,只补了当前部门:
```
js
departs
.
push
(
curentDepart
);
let
departIds
=
departs
.
map
(
o
=>
{
return
o
.
id
});
```
当当前用户在公司下属部门时,
`pidStr`
能定位到公司根路径,但
`departIds`
没有加入公司根节点本身。如果有用户直接挂在公司根部门上,该用户创建的项目会被漏掉。
建议在计算
`pidStr`
时同时记录
`companyDepartId`
,并加入
`departIds`
:
```
js
let
companyDepartId
;
if
(
curentDepart
.
parentId
==
86
)
{
companyDepartId
=
curentDepart
.
id
;
pidStr
=
`
${
curentDepart
.
parentIds
}
,
${
curentDepart
.
id
}
`
;
}
else
{
const
index
=
parentIds
.
indexOf
(
'86'
);
const
result
=
index
!==
-
1
?
parentIds
.
slice
(
0
,
index
+
2
)
:
parentIds
;
pidStr
=
result
.
join
(
","
);
companyDepartId
=
Number
(
parentIds
[
index
+
1
]);
}
let
departIds
=
departs
.
map
(
o
=>
o
.
id
);
if
(
companyDepartId
)
departIds
.
push
(
companyDepartId
);
departIds
=
[...
new
Set
(
departIds
)];
```
### 12. `getCompanyProjectApprover` 有同类公司根节点遗漏
位置:
`module/userModule.js:153-196`
`getCompanyProjectApprover`
的部门范围计算和项目列表权限类似,也只把
`curentDepart`
加入
`departs`
,没有在“当前用户位于公司下属部门”时加入公司根节点。若角色为
`xmssdwbmz`
的用户直接挂在项目公司根节点,该审批人会漏掉。
建议和项目列表权限使用同一个公共函数,例如:
```
js
getProjectCompanyScopeDepartIds
(
userDepartId
)
```
统一返回“公司根节点 + 全部子部门”的部门 id 列表,避免两处逻辑继续分叉。
## 中风险问题
### 13. 生产环境启动仍会自动 `sync({ alter: true })`
位置:
-
`db/model/index.js:5-8`
-
多个模型文件,例如
`db/model/system/depart.js:55-58`
、
`db/model/jt/project.js:590-593`
、
`db/model/jt/rcCgqygl.js:580-583`
等。
当前 Sequelize 初始化没有按生产环境禁用模型同步,且大量模型文件在
`require`
时直接执行
`sync({ alter: true })`
。这会带来几个风险:
-
生产启动时自动 DDL,可能改表、锁表或造成字段类型变化。
-
MySQL prepared statement 元数据失效,容易出现
`Prepared statement needs to be re-prepared`
。
-
多模型并发
`alter`
时启动不稳定。
建议:
-
生产环境不要在模型文件中执行
`sync/alter`
。
-
使用迁移脚本管理表结构。
-
至少在
`db/model/index.js`
中按
`NODE_ENV === 'production'`
禁用模型级
`sync()`
。
### 14. 数据库连接配置没有读取 `port` 和 `logging`
位置:
`db/model/index.js:5-8`
`production.json`
配了
`mysql.port`
和
`mysql.logging`
,但 Sequelize 初始化没有使用:
```
js
host
:
sysConfig
.
mysql
.
host
||
'localhost'
,
dialect
:
'mysql'
,
logging
:
false
,
```
建议:
```
js
port
:
sysConfig
.
mysql
.
port
||
3306
,
logging
:
sysConfig
.
mysql
.
logging
||
false
,
```
### 15. `setRoleMenu` 的调试输出写法有误
位置:
`module/userModule.js:123`
```
js
console
.
log
(
roleId
,
"---"
,
needAddIds
.
length
,
needDelIds
),
"============"
```
`"============"`
不会被打印,只是逗号表达式的右侧值,没有实际作用。
建议:
```
js
console
.
log
(
roleId
,
"---"
,
needAddIds
.
length
,
needDelIds
,
"============"
);
```
### 16. 登录接口打印手机号和明文密码
位置:
`controller/userController.js:31`
```
js
console
.
log
(
req
.
body
.
mobile
,
req
.
body
.
password
,
"================"
)
```
这会把用户手机号和明文密码写入日志,属于敏感信息泄露。
建议删除该日志,或只记录脱敏手机号和登录结果。
### 17. 登录 AES 密钥硬编码
位置:
`controller/userController.js:27`
```
js
CryptoJS
.
AES
.
decrypt
(
req
.
body
.
encryptLogStr
,
"GFG5w5AP0Ja2rNaa"
)
```
密钥硬编码在代码中,不利于环境隔离和密钥轮换。
建议放入环境变量或配置文件,并区分 dev/production。
### 18. 请求日志记录完整 headers,可能记录 token
位置:
`middleware/request.js:45`
```
js
headers
:
JSON
.
stringify
(
req
.
headers
),
```
headers 中包含
`authorization`
,会把登录 token 写入请求日志。
建议记录前先脱敏:
```
js
const
headers
=
{
...
req
.
headers
};
delete
headers
.
authorization
;
delete
headers
.
Authorization
;
```
### 19. 文件下载路径拼接不稳
位置:
-
`controller/fileController.js:71`
-
`controller/fileController.js:111`
```
js
const
filePath
=
Path
.
join
(
__dirname
,
'../../../'
,
path
);
```
上传时保存的
`req.file.path`
在当前配置下可能是绝对路径,如
`/data/uploadfiles/...`
。
`Path.join(__dirname, '../../../', absolutePath)`
在不同平台上语义不一致,Windows/Linux 都可能出现不可预期路径。
建议:
-
如果数据库保存绝对路径,下载时直接使用该绝对路径。
-
如果要保存相对路径,上传时就统一转成相对路径。
-
使用
`Path.isAbsolute(path)`
做兼容判断。
### 20. `utils.buildTree` 对根节点判断不一致
位置:
`utils/index.js:37-49`
```
js
const
parentId
=
String
(
node
.
parentId
);
if
(
parentId
!==
null
&&
node
.
del
==
0
)
{
...
}
...
return
...
filter
(
node
=>
node
.
parentId
===
null
)
```
`String(null)`
是
`"null"`
,所以
`parentId !== null`
永远为真。当前主要依赖
`nodeMap.has(parentId)`
避免出错,但逻辑表达不准确,遇到
`undefined`
、
`0`
或字符串
`"null"`
时容易出现树根判断异常。
建议统一根节点判断:
```
js
const
parentId
=
node
.
parentId
==
null
?
null
:
String
(
node
.
parentId
);
if
(
parentId
&&
nodeMap
.
has
(
parentId
)
&&
node
.
del
==
0
)
{
...
}
return
_
.
orderBy
(
Array
.
from
(
nodeMap
.
values
()).
filter
(
node
=>
node
.
parentId
==
null
),
'order'
);
```
## 低风险/维护性问题
### 21. `npm run lint` 当前不可用
位置:
`package.json:9-10`
、
`.eslintrc.js`
项目依赖 ESLint 9.4.0,但配置仍是旧版
`.eslintrc.js`
。执行:
```
bash
npm run lint
--
--quiet
```
结果:
```
txt
ESLint couldn't find an eslint.config.(js|mjs|cjs) file.
```
建议二选一:
-
迁移到
`eslint.config.js`
。
-
或将 ESLint 降级到兼容
`.eslintrc.js`
的 v8。
### 22. 大量 `console.log` 留在接口链路中
位置示例:
-
`controller/projectController.js:1293`
-
`controller/projectController.js:1330`
-
`module/userModule.js:144`
-
`middleware/parameter.js:18`
-
`middleware/request.js:61`
这些日志会影响性能、污染生产日志,也可能输出业务数据。
建议统一接入日志工具,并按环境控制日志级别。
### 23. `server.js` 引入了未使用的中间件
位置:
`server.js:10`
```
js
const
parameter
=
require
(
'./middleware/parameter'
);
```
但后面没有
`app.use(parameter)`
。如果这是遗留代码建议删除;如果本来用于参数校验,应明确挂载。
### 24. 配置文件包含生产账号密码
位置:
`config/production.json`
生产 MySQL、Redis 密码直接保存在仓库配置文件里。虽然这不属于语法问题,但属于部署和安全风险。
建议改为环境变量注入,配置文件只保留变量名或默认值。
## 建议优先修复顺序
1.
修复会立即导致接口报错的问题:
`DB.File.insertMany`
、
`getMenu`
查错模型、用户岗位字段错误。
2.
修复权限和部门树边界:项目公司权限漏公司根节点、审批人范围复用同一套部门范围函数、部门/菜单删除前缀误伤。
3.
修复异步更新未等待:所有
`Promise.all(map(... => { DB.xxx.update(...) }))`
改为返回 Promise。
4.
修复生产启动风险:移除或生产禁用模型文件里的
`sync({ alter: true })`
。
5.
恢复 lint 能力,并把敏感日志、token 日志、明文密码日志清掉。
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment