chore: initial import

This commit is contained in:
2026-04-19 14:05:40 +08:00
commit 89e9eae36e
81 changed files with 37363 additions and 0 deletions
+262
View File
@@ -0,0 +1,262 @@
const express = require('express');
const router = express.Router();
const db = require('../db');
const { verifyToken } = require('../middleware/auth');
// 获取统计数据 (所有登录用户均可访问)
router.get('/', verifyToken, async (req, res) => {
try {
const { role } = req.user;
// 权限控制:
// 1. 业务统计图表(雷达图、趋势图、部门分布等):统一只统计“已通过”的数据,反映真实有效的成果。
// 2. 状态分布图:管理员可以看到所有状态,普通用户只能看到已通过。
const approvedCondition = "status = 'approved'";
let allStatusCondition = "status = 'approved'";
if (['super_admin', 'maintainer'].includes(role)) {
allStatusCondition = "1=1"; // 允许所有状态
}
// 1. 按类型统计 (雷达图) - 仅统计已通过
const typeStats = await db.query(`
SELECT type, COUNT(*) as count
FROM achievements
WHERE ${approvedCondition}
GROUP BY type
`);
// 2. 按状态统计 (饼图) - 管理员看全量,用户看已通过
const statusStats = await db.query(`
SELECT status, COUNT(*) as count
FROM achievements
WHERE ${allStatusCondition}
GROUP BY status
`);
// 3. 按部门统计成果总数 (部门排名) - 仅统计已通过
// 口径:每条成果只归属一个部门(优先首个非院领导部门,否则回退首个部门)
const departmentStats = await db.query(`
WITH leader_depts AS (
SELECT name FROM dict_leader_departments
),
leader_dept_array AS (
SELECT COALESCE(array_agg(name::text), ARRAY[]::text[]) AS names FROM leader_depts
),
department_scope AS (
SELECT d.name AS department
FROM departments d, leader_dept_array lda
WHERE d.name::text <> ALL(lda.names)
),
achievement_owner AS (
SELECT
a.id,
COALESCE(non_leader.dept, first_any.dept) AS owner_department
FROM achievements a
CROSS JOIN leader_dept_array lda
LEFT JOIN LATERAL (
SELECT u.dept
FROM unnest(COALESCE(a.assigned_departments::text[], ARRAY[]::text[])) WITH ORDINALITY AS u(dept, ord)
WHERE u.dept IS NOT NULL
AND BTRIM(u.dept) <> ''
AND u.dept <> ALL(lda.names)
ORDER BY u.ord
LIMIT 1
) non_leader ON TRUE
LEFT JOIN LATERAL (
SELECT u.dept
FROM unnest(COALESCE(a.assigned_departments::text[], ARRAY[]::text[])) WITH ORDINALITY AS u(dept, ord)
WHERE u.dept IS NOT NULL
AND BTRIM(u.dept) <> ''
ORDER BY u.ord
LIMIT 1
) first_any ON TRUE
WHERE ${approvedCondition}
)
SELECT ds.department, COUNT(ao.id)::int as count
FROM department_scope ds
LEFT JOIN achievement_owner ao ON ds.department = ao.owner_department
GROUP BY ds.department
ORDER BY count DESC
`);
// 4. 部门成果种类交叉统计 (堆叠柱状图) - 仅统计已通过
const deptTypeStats = await db.query(`
WITH leader_depts AS (
SELECT name FROM dict_leader_departments
),
leader_dept_array AS (
SELECT COALESCE(array_agg(name::text), ARRAY[]::text[]) AS names FROM leader_depts
),
department_scope AS (
SELECT d.name AS department
FROM departments d, leader_dept_array lda
WHERE d.name::text <> ALL(lda.names)
),
achievement_owner AS (
SELECT
a.id,
a.type,
a.achievement_date,
COALESCE(non_leader.dept, first_any.dept) AS owner_department
FROM achievements a
CROSS JOIN leader_dept_array lda
LEFT JOIN LATERAL (
SELECT u.dept
FROM unnest(COALESCE(a.assigned_departments::text[], ARRAY[]::text[])) WITH ORDINALITY AS u(dept, ord)
WHERE u.dept IS NOT NULL
AND BTRIM(u.dept) <> ''
AND u.dept <> ALL(lda.names)
ORDER BY u.ord
LIMIT 1
) non_leader ON TRUE
LEFT JOIN LATERAL (
SELECT u.dept
FROM unnest(COALESCE(a.assigned_departments::text[], ARRAY[]::text[])) WITH ORDINALITY AS u(dept, ord)
WHERE u.dept IS NOT NULL
AND BTRIM(u.dept) <> ''
ORDER BY u.ord
LIMIT 1
) first_any ON TRUE
WHERE ${approvedCondition}
)
SELECT
ds.department as department,
ao.type,
EXTRACT(YEAR FROM ao.achievement_date) as year,
COUNT(*)::int as count
FROM department_scope ds
JOIN achievement_owner ao ON ds.department = ao.owner_department
WHERE ao.achievement_date IS NOT NULL
GROUP BY ds.department, ao.type, EXTRACT(YEAR FROM ao.achievement_date)
ORDER BY ds.department
`);
// 5. 全单位月度趋势统计 (累计折线图) - 仅统计已通过
// 前端会进行累计计算,后端只需返回每月增量
const trendStats = await db.query(`
SELECT TO_CHAR(achievement_date, 'YYYY-MM') as month, COUNT(*) as count
FROM achievements
WHERE ${approvedCondition} AND achievement_date IS NOT NULL
GROUP BY month
ORDER BY month
`);
// 6. 各部门月度趋势统计 (累计面积图) - 仅统计已通过
// 前端会进行累计计算,后端只需返回每月增量
const deptTrendStats = await db.query(`
WITH leader_depts AS (
SELECT name FROM dict_leader_departments
),
leader_dept_array AS (
SELECT COALESCE(array_agg(name::text), ARRAY[]::text[]) AS names FROM leader_depts
),
department_scope AS (
SELECT d.name AS department
FROM departments d, leader_dept_array lda
WHERE d.name::text <> ALL(lda.names)
),
achievement_owner AS (
SELECT
a.id,
a.achievement_date,
COALESCE(non_leader.dept, first_any.dept) AS owner_department
FROM achievements a
CROSS JOIN leader_dept_array lda
LEFT JOIN LATERAL (
SELECT u.dept
FROM unnest(COALESCE(a.assigned_departments::text[], ARRAY[]::text[])) WITH ORDINALITY AS u(dept, ord)
WHERE u.dept IS NOT NULL
AND BTRIM(u.dept) <> ''
AND u.dept <> ALL(lda.names)
ORDER BY u.ord
LIMIT 1
) non_leader ON TRUE
LEFT JOIN LATERAL (
SELECT u.dept
FROM unnest(COALESCE(a.assigned_departments::text[], ARRAY[]::text[])) WITH ORDINALITY AS u(dept, ord)
WHERE u.dept IS NOT NULL
AND BTRIM(u.dept) <> ''
ORDER BY u.ord
LIMIT 1
) first_any ON TRUE
WHERE ${approvedCondition}
)
SELECT
TO_CHAR(ao.achievement_date, 'YYYY-MM') as month,
ds.department as department,
COUNT(*)::int as count
FROM department_scope ds
JOIN achievement_owner ao ON ds.department = ao.owner_department
WHERE ao.achievement_date IS NOT NULL
GROUP BY TO_CHAR(ao.achievement_date, 'YYYY-MM'), ds.department
ORDER BY month
`);
// 7. 按部门统计“独立完成 / 合作项目”
// 当前口径下每条成果仅归属一个部门,因此合作计数恒为 0。
const projectModeStats = await db.query(`
WITH leader_depts AS (
SELECT name FROM dict_leader_departments
),
leader_dept_array AS (
SELECT COALESCE(array_agg(name::text), ARRAY[]::text[]) AS names FROM leader_depts
),
department_scope AS (
SELECT d.name AS department
FROM departments d, leader_dept_array lda
WHERE d.name::text <> ALL(lda.names)
),
achievement_owner AS (
SELECT
a.id,
COALESCE(non_leader.dept, first_any.dept) AS owner_department
FROM achievements a
CROSS JOIN leader_dept_array lda
LEFT JOIN LATERAL (
SELECT u.dept
FROM unnest(COALESCE(a.assigned_departments::text[], ARRAY[]::text[])) WITH ORDINALITY AS u(dept, ord)
WHERE u.dept IS NOT NULL
AND BTRIM(u.dept) <> ''
AND u.dept <> ALL(lda.names)
ORDER BY u.ord
LIMIT 1
) non_leader ON TRUE
LEFT JOIN LATERAL (
SELECT u.dept
FROM unnest(COALESCE(a.assigned_departments::text[], ARRAY[]::text[])) WITH ORDINALITY AS u(dept, ord)
WHERE u.dept IS NOT NULL
AND BTRIM(u.dept) <> ''
ORDER BY u.ord
LIMIT 1
) first_any ON TRUE
WHERE ${approvedCondition}
)
SELECT
ds.department,
COUNT(ao.id)::int AS independent_count,
0::int AS collaboration_count,
COUNT(ao.id)::int AS total_count
FROM department_scope ds
LEFT JOIN achievement_owner ao ON ao.owner_department = ds.department
GROUP BY ds.department
ORDER BY total_count DESC, ds.department
`);
res.json({
byType: typeStats.rows,
byStatus: statusStats.rows,
byDepartment: departmentStats.rows,
deptTypeDetails: deptTypeStats.rows,
byMonth: trendStats.rows,
deptTrendDetails: deptTrendStats.rows,
projectModeByDepartment: projectModeStats.rows
});
} catch (err) {
console.error(err);
res.status(500).json({ message: '服务器错误' });
}
});
module.exports = router;