chore: initial import
This commit is contained in:
@@ -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;
|
||||
Reference in New Issue
Block a user