Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
B
basisProjectPlatform
Overview
Overview
Details
Activity
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
yiyuan_database
basisProjectPlatform
Commits
80bbcc19
Commit
80bbcc19
authored
Jun 03, 2026
by
PC-20251223ZVQQ\Administrator
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
工时导出模板
parent
ab867f5b
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
56 additions
and
35 deletions
+56
-35
工时导出模板.xlsx
backend/src/config/工时导出模板.xlsx
+0
-0
workhour.controller.ts
backend/src/controllers/workhour.controller.ts
+56
-35
No files found.
backend/src/config/工时导出模板.xlsx
0 → 100644
View file @
80bbcc19
File added
backend/src/controllers/workhour.controller.ts
View file @
80bbcc19
import
{
Request
,
Response
}
from
'express'
;
import
{
Request
,
Response
}
from
'express'
;
import
path
from
'path'
;
import
ExcelJS
from
'exceljs'
;
import
ExcelJS
from
'exceljs'
;
import
pool
from
'../config/database'
;
import
pool
from
'../config/database'
;
import
{
AuthRequest
}
from
'../middleware/auth'
;
import
{
AuthRequest
}
from
'../middleware/auth'
;
...
@@ -188,7 +189,7 @@ export const getWorkHourStats = async (req: AuthRequest, res: Response): Promise
...
@@ -188,7 +189,7 @@ export const getWorkHourStats = async (req: AuthRequest, res: Response): Promise
}
}
};
};
// 导出工时到 Excel
// 导出工时到 Excel
(基于模板)
export
const
exportWorkhours
=
async
(
req
:
AuthRequest
,
res
:
Response
):
Promise
<
void
>
=>
{
export
const
exportWorkhours
=
async
(
req
:
AuthRequest
,
res
:
Response
):
Promise
<
void
>
=>
{
try
{
try
{
const
{
employee_id
,
project_id
,
start_date
,
end_date
}
=
req
.
query
;
const
{
employee_id
,
project_id
,
start_date
,
end_date
}
=
req
.
query
;
...
@@ -209,50 +210,70 @@ export const exportWorkhours = async (req: AuthRequest, res: Response): Promise<
...
@@ -209,50 +210,70 @@ export const exportWorkhours = async (req: AuthRequest, res: Response): Promise<
if
(
start_date
)
{
where
+=
' AND w.work_date >= ?'
;
params
.
push
(
start_date
);
}
if
(
start_date
)
{
where
+=
' AND w.work_date >= ?'
;
params
.
push
(
start_date
);
}
if
(
end_date
)
{
where
+=
' AND w.work_date <= ?'
;
params
.
push
(
end_date
);
}
if
(
end_date
)
{
where
+=
' AND w.work_date <= ?'
;
params
.
push
(
end_date
);
}
// 多表联合查询:工时表 + 员工表 + 项目表 + 加班表 + 日志表(审核人)
const
[
rows
]
=
await
pool
.
execute
(
const
[
rows
]
=
await
pool
.
execute
(
`SELECT w.*, e.name as employee_name, p.project_name
`SELECT w.id as workhour_id, w.work_date, w.hours, w.description,
e.id as employee_id, e.name as employee_name, e.role as employee_role, e.department,
p.id as project_id, p.project_name, p.project_no,
pm.name as manager_name,
o.id as overtime_id, o.hours as overtime_hours, o.description as overtime_description,
(SELECT COUNT(DISTINCT wh2.work_date)
FROM workhours wh2
WHERE wh2.employee_id = w.employee_id
AND wh2.project_id = w.project_id
${
start_date
?
' AND wh2.work_date >= ?'
:
''
}
${
end_date
?
' AND wh2.work_date <= ?'
:
''
}
) as work_day_count,
(SELECT ol.operator_name
FROM operation_logs ol
WHERE ol.module = '加班管理'
AND ol.rx_action LIKE CONCAT('%', o.id, '%')
AND o.id IS NOT NULL
ORDER BY ol.created_at DESC
LIMIT 1
) as auditor1
FROM workhours w
FROM workhours w
LEFT JOIN employees e ON w.employee_id = e.id
LEFT JOIN employees e ON w.employee_id = e.id
LEFT JOIN projects p ON w.project_id = p.id
LEFT JOIN projects p ON w.project_id = p.id
${
where
}
ORDER BY w.work_date DESC`
,
LEFT JOIN employees pm ON p.manager_id = pm.id
LEFT JOIN overtimes o ON w.employee_id = o.employee_id AND w.work_date = o.overtime_date AND o.status = '已批准'
${
where
}
ORDER BY w.employee_id, w.work_date`
,
params
params
)
as
any
[];
)
as
any
[];
// 生成 Excel
// 加载模板文件
const
templatePath
=
path
.
join
(
__dirname
,
'../config/工时导出模板.xlsx'
);
const
workbook
=
new
ExcelJS
.
Workbook
();
const
workbook
=
new
ExcelJS
.
Workbook
();
const
sheet
=
workbook
.
addWorksheet
(
'工时记录'
);
await
workbook
.
xlsx
.
readFile
(
templatePath
);
const
sheet
=
workbook
.
getWorksheet
(
1
);
// 表头
if
(
!
sheet
)
{
sheet
.
columns
=
[
res
.
status
(
500
).
json
({
code
:
500
,
message
:
'模板文件格式错误'
});
{
header
:
'员工'
,
key
:
'employee_name'
,
width
:
14
},
return
;
{
header
:
'项目'
,
key
:
'project_name'
,
width
:
22
},
{
header
:
'工作日期'
,
key
:
'work_date'
,
width
:
14
},
{
header
:
'工时(h)'
,
key
:
'hours'
,
width
:
10
},
{
header
:
'工作描述'
,
key
:
'description'
,
width
:
40
},
{
header
:
'是否外出'
,
key
:
'is_outside'
,
width
:
10
},
];
// 样式:表头加粗居中
const
headerRow
=
sheet
.
getRow
(
1
);
headerRow
.
font
=
{
bold
:
true
};
headerRow
.
alignment
=
{
horizontal
:
'center'
,
vertical
:
'middle'
};
headerRow
.
height
=
22
;
// 填充数据
for
(
const
row
of
rows
as
any
[])
{
sheet
.
addRow
({
employee_name
:
row
.
employee_name
,
project_name
:
row
.
project_name
,
work_date
:
row
.
work_date
?
new
Date
(
row
.
work_date
).
toISOString
().
slice
(
0
,
10
)
:
''
,
hours
:
row
.
hours
,
description
:
row
.
description
||
''
,
is_outside
:
row
.
is_outside
?
'外出'
:
'在司'
,
});
}
}
// 数据行对齐
// 从第2行开始填充数据(第1行是表头)
for
(
let
i
=
2
;
i
<=
sheet
.
rowCount
;
i
++
)
{
for
(
const
row
of
rows
as
any
[])
{
sheet
.
getRow
(
i
).
alignment
=
{
vertical
:
'middle'
};
const
workDate
=
row
.
work_date
?
new
Date
(
row
.
work_date
)
:
null
;
sheet
.
addRow
([
String
(
row
.
workhour_id
),
// 派工单编号
workDate
?
workDate
.
getFullYear
()
:
''
,
// 年
workDate
?
workDate
.
getMonth
()
+
1
:
''
,
// 月份
workDate
?
workDate
.
getDate
()
:
''
,
// 日
row
.
employee_role
||
''
,
// 职务
row
.
employee_name
||
''
,
// 员工姓名
row
.
department
||
''
,
// 员工所属部门
row
.
project_name
||
''
,
// 项目名称
row
.
project_no
||
''
,
// 项目编号
row
.
manager_name
||
''
,
// 项目经理
row
.
description
||
''
,
// 工作内容
row
.
overtime_description
||
''
,
// 加班内容
row
.
overtime_hours
!=
null
?
Number
(
row
.
overtime_hours
)
:
''
,
// 员工加班
row
.
auditor1
||
''
,
// 审核人1
''
,
// 审核人2(暂留空)
row
.
hours
!=
null
?
Number
(
row
.
hours
)
:
''
,
// 实际工作量
row
.
overtime_hours
!=
null
?
Number
(
row
.
overtime_hours
)
:
''
,
// 实际加班
row
.
work_day_count
||
''
,
// 实际工作天数
]);
}
}
// 设置响应头
// 设置响应头
...
...
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