Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
psa-web
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
高滢
psa-web
Commits
a3636c9c
Commit
a3636c9c
authored
Mar 14, 2025
by
ZhangRunSong
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat:考勤打卡
parent
38a72e42
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
1281 additions
and
0 deletions
+1281
-0
clock.js
src/api/attendance/clock.js
+71
-0
add.vue
src/views/attendance/clock/add.vue
+296
-0
draft.vue
src/views/attendance/clock/draft.vue
+350
-0
index.vue
src/views/attendance/clock/index.vue
+564
-0
No files found.
src/api/attendance/clock.js
0 → 100644
View file @
a3636c9c
import
request
from
'@/utils/request'
// 查询考勤打卡列表
export
function
listClock
(
query
)
{
return
request
({
url
:
'/psa/clock/list'
,
method
:
'get'
,
params
:
query
})
}
// 查询草稿箱列表
export
function
listDraftClock
(
query
)
{
return
request
({
url
:
'/psa/clock/draft'
,
method
:
'get'
,
params
:
query
})
}
// 查询考勤打卡详细
export
function
getClock
(
id
)
{
return
request
({
url
:
'/psa/clock/'
+
id
,
method
:
'get'
})
}
// 新增考勤打卡
export
function
addClock
(
data
)
{
return
request
({
url
:
'/psa/clock'
,
method
:
'post'
,
data
:
data
})
}
// 新增草稿箱
export
function
addClockDraft
(
data
)
{
return
request
({
url
:
'/psa/clock/draft'
,
method
:
'post'
,
data
:
data
})
}
// 修改考勤打卡
export
function
updateClock
(
data
)
{
return
request
({
url
:
'/psa/clock'
,
method
:
'put'
,
data
:
data
})
}
// 删除考勤打卡
export
function
delClock
(
id
)
{
return
request
({
url
:
'/psa/clock/'
+
id
,
method
:
'delete'
})
}
//导入方法
export
function
importData
(
file
)
{
return
request
({
data
:
file
,
url
:
'/psa/clock/import'
,
method
:
'post'
,
headers
:
{
'Content-Type'
:
'multipart/form-data'
}
})
}
src/views/attendance/clock/add.vue
0 → 100644
View file @
a3636c9c
<
template
>
<div
class=
"app-container"
>
<h1
class=
"title"
>
{{
title
}}
</h1>
<div
class=
"blue"
></div>
<el-form
class=
"form-add"
ref=
"clockRef"
:model=
"form"
:rules=
"rules"
label-width=
"100px"
>
<el-form-item
class=
"font"
label=
"姓名"
prop=
"employeeName"
>
<el-input
style=
"width: 400px ;height: 40px"
class=
"frame"
v-model=
"form.employeeName"
placeholder=
"请输入姓名"
/>
</el-form-item>
<el-form-item
class=
"font"
label=
"部门"
prop=
"departmentName"
>
<el-select
style=
"width: 400px; height: 40px;"
v-model=
"form.departmentName"
placeholder=
"请选择部门"
>
<el-option
v-for=
"item in options"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item
class=
"font"
label=
"打卡日期"
prop=
"candidateDate"
>
<el-date-picker
style=
"width: 400px ; height: 40px"
clearable
v-model=
"form.candidateDate"
type=
"date"
value-format=
"YYYY-MM-DD"
placeholder=
"请选择打卡日期"
>
</el-date-picker>
</el-form-item>
<el-form-item
class=
"font"
label=
"打卡时段"
prop=
"isClock"
>
<el-select
v-model=
"form.isClock"
placeholder=
"请选择打卡时段"
style=
"height: 50px;width: 400px"
size=
"large"
>
<el-option
v-for=
"dict in time_difference"
:key=
"dict.value"
:label=
"dict.label"
:value=
"dict.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item
class=
"font"
label=
"打卡时间"
label-class=
"label-class"
prop=
"clockTime"
>
<el-time-picker
v-model=
"form.clockTime"
placeholder=
"请选择时间"
format=
"HH:mm"
value-format=
"HH:mm"
style=
"width: 400px ;height: 40px"
>
</el-time-picker>
</el-form-item>
</el-form>
<!-- 提交和保存草稿按钮 -->
<div
class=
"buttons"
>
<el-button
class=
"button-1"
@
click=
"resets"
>
取消
</el-button>
<el-button
class=
"button-2"
type=
"primary"
@
click=
"saveDraft"
>
保存
</el-button>
<el-button
class=
"button-3"
type=
"primary"
@
click=
"submitForm"
>
确定
</el-button>
</div>
</div>
</
template
>
<
script
setup
>
import
{
useRoute
}
from
'vue-router'
;
import
{
addClock
,
updateClock
,
getClock
,
addClockDraft
}
from
"@/api/attendance/clock"
;
import
ImportTable
from
"../../tool/gen/importTable.vue"
;
const
{
proxy
}
=
getCurrentInstance
();
const
{
clock_status
,
time_difference
}
=
proxy
.
useDict
(
'clock_status'
,
'time_difference'
);
const
open
=
ref
(
false
);
const
loading
=
ref
(
true
);
const
ids
=
ref
([]);
const
single
=
ref
(
true
);
const
multiple
=
ref
(
true
);
const
total
=
ref
(
0
);
const
title
=
ref
(
""
);
const
data
=
reactive
({
form
:
{},
queryParams
:
{
pageNum
:
1
,
pageSize
:
10
,
employeeId
:
null
,
employeeName
:
null
,
departmentName
:
null
,
candidateDate
:
null
,
isClock
:
null
,
checkInStatus
:
null
,
},
});
const
options
=
[
{
value
:
'行政管理服务部'
,
label
:
'行政管理服务部'
},
{
value
:
'人才服务事业部'
,
label
:
'人才服务事业部'
},
{
value
:
'教育培训事业部'
,
label
:
'教育培训事业部'
},
{
value
:
'软件服务事业部'
,
label
:
'软件服务事业部'
},
{
value
:
'综合管理事业部'
,
label
:
'综合管理事业部'
},
{
value
:
'日本事业服务部'
,
label
:
'日本事业服务部'
},
{
value
:
'公司'
,
label
:
'公司'
},
]
const
rules
=
ref
({
employeeName
:
[
{
required
:
true
,
message
:
'姓名不能为空'
,
trigger
:
'blur'
}
],
departmentName
:
[
{
required
:
true
,
message
:
'部门不能为空'
,
trigger
:
'blur'
}
],
candidateDate
:
[
{
required
:
true
,
message
:
'打卡日期不能为空'
,
trigger
:
'blur'
}
],
isClock
:
[
{
required
:
true
,
message
:
'打卡时段不能为空'
,
trigger
:
'blur'
}
],
clockTime
:
[
{
required
:
true
,
message
:
'打卡时间不能为空'
,
trigger
:
'blur'
}
],
})
const
{
queryParams
,
form
}
=
toRefs
(
data
);
const
route
=
useRoute
();
//保存
function
submitForm
()
{
proxy
.
$refs
[
"clockRef"
].
validate
(
valid
=>
{
if
(
valid
)
{
if
(
form
.
value
.
id
!=
null
)
{
updateClock
(
form
.
value
).
then
(
response
=>
{
proxy
.
$modal
.
msgSuccess
(
"修改成功"
);
proxy
.
$router
.
push
({
path
:
'/attendance/clock'
})
});
}
else
{
addClock
(
form
.
value
).
then
(
response
=>
{
proxy
.
$modal
.
msgSuccess
(
"新增成功"
);
proxy
.
$router
.
push
({
path
:
'/attendance/clock'
})
});
}
}
});
}
// 保存草稿
const
saveDraft
=
()
=>
{
proxy
.
$refs
[
"clockRef"
].
validate
(
valid
=>
{
if
(
valid
)
{
addClockDraft
(
form
.
value
).
then
(
response
=>
{
proxy
.
$modal
.
msgSuccess
(
"已存入草稿箱"
);
proxy
.
$router
.
push
({
path
:
'/attendance/clock'
})
});
}
});
}
// 表单重置
function
reset
()
{
form
.
value
=
{
id
:
null
,
employeeId
:
null
,
userId
:
null
,
deptId
:
null
,
projectId
:
null
,
employeeName
:
null
,
departmentName
:
null
,
candidateDate
:
null
,
isClock
:
null
,
clockTime
:
null
,
checkInStatus
:
null
,
creatBy
:
null
,
creatTime
:
null
,
updateTime
:
null
,
draft
:
null
,
delFlag
:
null
};
proxy
.
resetForm
(
"clockRef"
);
}
// 返回页面
const
resets
=
()
=>
{
// 返回考勤
// resetForm()
proxy
.
$router
.
push
({
path
:
'/attendance/clock'
})
}
// 在组件挂载时执行
onMounted
(()
=>
{
const
_id
=
route
.
query
.
id
console
.
log
(
_id
)
if
(
_id
){
getClock
(
_id
).
then
(
response
=>
{
title
.
value
=
"修改考勤"
form
.
value
=
response
.
data
;
console
.
log
(
response
.
data
)
console
.
log
(
form
.
value
)
});
}
else
{
title
.
value
=
"新增考勤"
}
})
</
script
>
<
style
scoped
>
.app-container
{
height
:
400px
;
width
:
1622px
;
box-sizing
:
border-box
;
padding
:
0
;
margin
:
16px
28px
29px
20px
;
background
:
#FFFFFF
;
box-shadow
:
0
2px
2px
0
#b3b3b380
;
border-radius
:
2px
;
}
.title
{
margin
:
7px
0
8px
32px
;
width
:
72px
;
height
:
15px
;
font-weight
:
500
;
font-size
:
18px
;
color
:
#0D162A
;
letter-spacing
:
0
;
line-height
:
15px
;
}
.blue
{
margin-left
:
32px
;
width
:
72px
;
height
:
4px
;
background
:
#0062FF
;
}
.form-add
{
margin-top
:
31px
;
margin-left
:
90px
;
width
:
800px
;
height
:
500px
;
}
::v-deep
(
.el-form-item__label
)
{
width
:
64px
;
height
:
13px
;
font-weight
:
400
;
font-size
:
16px
;
color
:
#282D35
;
//
letter-spacing
:
0
;
//
text-align
:
right
;
line-height
:
47px
;
}
::v-deep
(
.custom-size
)
{
width
:
400px
!important
;
height
:
40px
!important
;
}
::v-deep
(
.custom-size
.el-input__wrapper
)
{
height
:
40px
!important
;
}
.frame
{
width
:
400px
;
height
:
40px
;
border-radius
:
2px
;
}
.font
{
height
:
50px
;
width
:
800px
;
margin
:
24px
0
0
0
;
}
.buttons
{
margin
:
150px
0px
70px
1174px
;
}
.button-1
{
width
:
116px
;
height
:
40px
;
//
border
:
1px
solid
;
}
.button-2
{
width
:
116px
;
height
:
40px
;
background
:
#0147EB
;
}
.button-3
{
width
:
116px
;
height
:
40px
;
background
:
#0147EB
;
}
</
style
>
src/views/attendance/clock/draft.vue
0 → 100644
View file @
a3636c9c
<
template
>
<div
class=
"app-container"
>
<div
class=
"formSearch"
>
<el-form
:model=
"queryParams"
ref=
"queryRef"
:inline=
"true"
v-show=
"showSearch"
label-width=
"68px"
>
<el-form-item
label=
"姓名"
prop=
"employeeName"
>
<el-input
style=
"width: 230px; "
v-model=
"queryParams.employeeName"
placeholder=
"请输入姓名"
clearable
@
keyup
.
enter=
"handleQuery"
/>
</el-form-item>
<el-form-item
label=
"部门"
prop=
"departmentName"
>
<el-select
style=
"width: 200px;"
v-model=
"form.departmentName"
placeholder=
"请选择部门"
>
<el-option
v-for=
"item in choose"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item
label=
"日期"
style=
"width: 330px"
>
<el-date-picker
v-model=
"daterangeCandidateDate"
value-format=
"YYYY-MM-DD"
type=
"daterange"
range-separator=
"-"
start-placeholder=
"开始日期"
end-placeholder=
"结束日期"
></el-date-picker>
</el-form-item>
<!-- 操作按钮 -->
<el-form-item
style=
"margin-left: 128px"
>
<el-button
@
click=
"resetQuery"
class=
"el-button-defalut"
>
<template
#
icon
>
<img
src=
"../../../assets/icons/common/reset.png"
style=
"width: 1.6em"
>
</
template
>
重置
</el-button>
<el-button
type=
"primary"
@
click=
"handleQuery"
class=
"el-button-primary"
>
<
template
#
icon
>
<img
src=
"../../../assets/icons/common/search.png"
style=
"width: 1.6em"
>
</
template
>
查询
</el-button>
<el-button
size=
"large"
type=
"text"
@
click=
"toggleSearch"
>
{{ isExpanded ? ' 收起' : ' 展开' }}
<el-icon
class=
"el-icon--right"
>
<arrow-down
/>
</el-icon>
</el-button>
</el-form-item>
<!-- 可折叠的查询条件 -->
<transition>
<div
v-if=
"isExpanded"
>
<el-form-item
label=
"时段"
prop=
"isClock"
style=
"width: 300px; margin-top: 15px"
>
<el-select
v-model=
"queryParams.isClock"
placeholder=
"请选择打卡时段"
clearable
>
<el-option
v-for=
"dict in time_difference"
:key=
"dict.value"
:label=
"dict.label"
:value=
"dict.value"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"状态"
prop=
"checkInStatus"
style=
"width: 330px; margin-top: 15px"
>
<el-select
v-model=
"queryParams.checkInStatus"
placeholder=
"请选择打卡状态"
clearable
style=
"width: 200px;"
>
<el-option
v-for=
"dict in clock_status"
:key=
"dict.value"
:label=
"dict.label"
:value=
"dict.value"
/>
</el-select>
</el-form-item>
</div>
</transition>
</el-form>
</div>
<el-row
:gutter=
"10"
class=
"mb8"
>
</el-row>
<div
class=
"contentTable"
>
<div
style=
"margin-bottom: 18px "
>
<span
class=
"bold-text"
style=
"border-bottom: 3px solid #0062FF;"
>
草稿箱
</span>
<span
style=
"padding-left: 85%"
>
<el-button
icon=
"ArrowLeft"
class=
"el-button-primary-pain"
@
click=
"resets"
>
返回
</el-button>
</span>
</div>
<el-table
border=
"border"
v-loading=
"loading"
:data=
"clockList"
@
selection-change=
"handleSelectionChange"
>
<el-table-column
label=
"姓名"
align=
"center"
prop=
"employeeName"
/>
<el-table-column
label=
"部门"
align=
"center"
prop=
"departmentName"
/>
<el-table-column
label=
"打卡日期"
align=
"center"
prop=
"candidateDate"
width=
"180"
>
<
template
#
default=
"scope"
>
<span>
{{
parseTime
(
scope
.
row
.
candidateDate
,
'{y
}
/{m
}
/{d
}
'
)
}}
<
/span
>
<
/template
>
<
/el-table-column
>
<
el
-
table
-
column
label
=
"打卡时段"
align
=
"center"
prop
=
"isClock"
>
<
template
#
default
=
"scope"
>
<
dict
-
tag
:
options
=
"time_difference"
:
value
=
"scope.row.isClock"
/>
<
/template
>
<
/el-table-column
>
<
el
-
table
-
column
label
=
"打卡时间"
align
=
"center"
prop
=
"clockTime"
width
=
"180"
>
<
template
#
default
=
"scope"
>
<
span
>
{{
scope
.
row
.
clockTime
}}
<
/span
>
<
/template
>
<
/el-table-column
>
<
el
-
table
-
column
label
=
"打卡状态"
align
=
"center"
prop
=
"checkInStatus"
>
<
template
#
default
=
"scope"
>
<
dict
-
tag
:
options
=
"clock_status"
:
value
=
"scope.row.checkInStatus"
/>
<
/template
>
<
/el-table-column
>
<
el
-
table
-
column
label
=
"操作"
align
=
"center"
class
-
name
=
"small-padding fixed-width"
fixed
=
"right"
min
-
width
=
"50"
>
<
template
#
default
=
"scope"
>
<
el
-
tooltip
content
=
"编辑"
placement
=
"top"
>
<
el
-
button
link
type
=
"text"
@
click
=
"handleUpdate(scope.row)"
v
-
hasPermi
=
"['psa:material:edit']"
>
<
img
src
=
"../../../assets/icons/common/edit.png"
height
=
"32"
width
=
"32"
/>
<
/el-button
>
<
/el-tooltip
>
<
el
-
tooltip
content
=
"删除"
placement
=
"top"
>
<
el
-
button
link
type
=
"text"
@
click
=
"handleDelete(scope.row)"
v
-
hasPermi
=
"['psa:material:edit']"
>
<
img
src
=
"../../../assets/icons/common/delete.png"
height
=
"32"
width
=
"32"
/>
<
/el-button
>
<
/el-tooltip
>
<
/template
>
<
/el-table-column
>
<
/el-table
>
<
/div
>
<
div
class
=
"pagination"
>
<
pagination
layout
=
"prev, pager, next, sizes, jumper"
v
-
show
=
"total > 0"
:
total
=
"total"
v
-
model
:
page
=
"queryParams.pageNum"
v
-
model
:
limit
=
"queryParams.pageSize"
@
pagination
=
"getList"
/>
<
/div
>
<
/div
>
<
/template
>
<
script
setup
name
=
"Clock"
>
import
{
listClock
,
delClock
,
addClock
,
updateClock
,
importData
,
listDraftClock
}
from
"@/api/attendance/clock"
;
import
{
ArrowDown
}
from
"@element-plus/icons-vue"
;
import
{
ElMessage
}
from
"element-plus"
;
const
{
proxy
}
=
getCurrentInstance
();
const
{
clock_status
,
time_difference
}
=
proxy
.
useDict
(
'clock_status'
,
'time_difference'
);
const
clockList
=
ref
([]);
const
open
=
ref
(
false
);
const
loading
=
ref
(
true
);
const
showSearch
=
ref
(
true
);
const
ids
=
ref
([]);
const
single
=
ref
(
true
);
const
multiple
=
ref
(
true
);
const
total
=
ref
(
0
);
const
title
=
ref
(
""
);
const
daterangeCandidateDate
=
ref
([]);
const
isExpanded
=
ref
(
false
);
const
data
=
reactive
({
form
:
{
}
,
queryParams
:
{
pageNum
:
1
,
pageSize
:
10
,
employeeId
:
null
,
employeeName
:
null
,
departmentName
:
null
,
candidateDate
:
null
,
isClock
:
null
,
checkInStatus
:
null
,
}
,
rules
:
{
}
}
);
const
{
queryParams
,
form
,
rules
}
=
toRefs
(
data
);
onMounted
(()
=>
{
getList
();
}
);
/** 查询草稿箱列表 */
function
getList
()
{
console
.
log
(
"getList执行了"
)
loading
.
value
=
true
;
queryParams
.
value
.
params
=
{
}
;
if
(
null
!=
daterangeCandidateDate
&&
''
!=
daterangeCandidateDate
)
{
queryParams
.
value
.
params
[
"beginCandidateDate"
]
=
daterangeCandidateDate
.
value
[
0
];
queryParams
.
value
.
params
[
"endCandidateDate"
]
=
daterangeCandidateDate
.
value
[
1
];
}
listDraftClock
(
queryParams
.
value
).
then
(
response
=>
{
clockList
.
value
=
response
.
rows
;
total
.
value
=
response
.
total
;
loading
.
value
=
false
;
}
);
}
// 表单重置
function
reset
()
{
form
.
value
=
{
id
:
null
,
employeeId
:
null
,
userId
:
null
,
deptId
:
null
,
projectId
:
null
,
employeeName
:
null
,
departmentName
:
null
,
candidateDate
:
null
,
isClock
:
null
,
clockTime
:
null
,
checkInStatus
:
null
,
creatBy
:
null
,
creatTime
:
null
,
updateTime
:
null
,
draft
:
null
,
delFlag
:
null
}
;
proxy
.
resetForm
(
"clockRef"
);
}
/** 搜索按钮操作 */
function
handleQuery
()
{
queryParams
.
value
.
pageNum
=
1
;
getList
();
}
/** 重置按钮操作 */
function
resetQuery
()
{
daterangeCandidateDate
.
value
=
[];
proxy
.
resetForm
(
"queryRef"
);
handleQuery
();
}
// 多选框选中数据
function
handleSelectionChange
(
selection
)
{
ids
.
value
=
selection
.
map
(
item
=>
item
.
id
);
single
.
value
=
selection
.
length
!=
1
;
multiple
.
value
=
!
selection
.
length
;
}
/** 新增按钮操作 */
function
handleAdd
()
{
reset
();
proxy
.
$router
.
push
({
path
:
'/attendances/clockadd'
}
);
}
/** 修改按钮操作 */
function
handleUpdate
(
row
)
{
reset
();
const
_id
=
row
.
id
proxy
.
$router
.
push
({
path
:
'/attendances/clockadd'
,
query
:
{
id
:
_id
}
}
);
}
/** 切换展开/折叠 */
const
toggleSearch
=
()
=>
{
isExpanded
.
value
=
!
isExpanded
.
value
;
}
/** 删除按钮操作 */
function
handleDelete
(
row
)
{
const
_ids
=
row
.
id
||
ids
.
value
;
proxy
.
$modal
.
confirm
(
'是否确认删除考勤打卡编号为"'
+
_ids
+
'"的草稿?'
).
then
(
function
()
{
return
delClock
(
_ids
);
}
).
then
(()
=>
{
getList
();
proxy
.
$modal
.
msgSuccess
(
"删除成功"
);
}
).
catch
(()
=>
{
}
);
}
const
resets
=
()
=>
{
// 返回考勤
// resetForm()
proxy
.
$router
.
push
({
path
:
'/attendance/clock'
}
)
}
<
/script
>
<
style
scoped
>
.
title
{
width
:
72
px
;
height
:
15
px
;
font
-
family
:
PingFangSC
-
Medium
;
font
-
weight
:
900
;
font
-
size
:
18
px
;
color
:
#
0
D162A
;
letter
-
spacing
:
0
;
line
-
height
:
15
px
;
}
.
top
-
title
{
margin
:
16
px
0
px
37
px
1200
px
;
}
.
blue
{
margin
-
top
:
8
px
;
margin
-
left
:
52
px
;
width
:
72
px
;
height
:
4
px
;
background
:
#
0062
FF
;
}
:
deep
(.
el
-
table
th
.
el
-
table__cell
)
{
background
:
#
F6F8FC
!
important
;
}
.
pagination
{
padding
-
right
:
650
px
;
}
.
file
-
list
{
border
:
1
px
solid
#
ebeef5
;
border
-
radius
:
4
px
;
padding
:
8
px
;
max
-
height
:
200
px
;
overflow
-
y
:
auto
;
}
.
file
-
item
{
display
:
flex
;
align
-
items
:
center
;
padding
:
8
px
;
transition
:
background
-
color
0.3
s
;
}
.
file
-
item
:
hover
{
background
-
color
:
#
f5f7fa
;
}
.
el
-
upload__tip
{
color
:
#
666
;
font
-
size
:
12
px
;
margin
-
top
:
8
px
;
}
.
bold
-
text
{
width
:
72
px
;
height
:
15
px
;
font
-
family
:
PingFangSC
-
Medium
;
font
-
weight
:
900
;
font
-
size
:
18
px
;
color
:
#
0
D162A
;
letter
-
spacing
:
0
;
line
-
height
:
15
px
;
}
<
/style
>
src/views/attendance/clock/index.vue
0 → 100644
View file @
a3636c9c
<
template
>
<div
class=
"app-container"
>
<div
class=
"formSearch"
>
<el-form
:model=
"queryParams"
ref=
"queryRef"
:inline=
"true"
v-show=
"showSearch"
label-width=
"68px"
>
<el-form-item
label=
"姓名"
prop=
"employeeName"
>
<el-input
style=
"width: 230px; "
v-model=
"queryParams.employeeName"
placeholder=
"请输入姓名"
clearable
@
keyup
.
enter=
"handleQuery"
/>
</el-form-item>
<el-form-item
label=
"部门"
prop=
"departmentName"
>
<el-select
style=
"width: 200px;"
v-model=
"form.departmentName"
placeholder=
"请选择部门"
>
<el-option
v-for=
"item in choose"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item
label=
"日期"
style=
"width: 330px"
>
<el-date-picker
v-model=
"daterangeCandidateDate"
value-format=
"YYYY-MM-DD"
type=
"daterange"
range-separator=
"-"
start-placeholder=
"开始日期"
end-placeholder=
"结束日期"
></el-date-picker>
</el-form-item>
<!-- 操作按钮 -->
<el-form-item
style=
"margin-left: 128px"
>
<el-button
@
click=
"resetQuery"
class=
"el-button-defalut"
>
<template
#
icon
>
<img
src=
"../../../assets/icons/common/reset.png"
style=
"width: 1.6em"
>
</
template
>
重置
</el-button>
<el-button
type=
"primary"
@
click=
"handleQuery"
class=
"el-button-primary"
>
<
template
#
icon
>
<img
src=
"../../../assets/icons/common/search.png"
style=
"width: 1.6em"
>
</
template
>
查询
</el-button>
<el-button
size=
"large"
type=
"text"
@
click=
"toggleSearch"
>
{{ isExpanded ? ' 收起' : ' 展开' }}
<el-icon
class=
"el-icon--right"
>
<arrow-down
/>
</el-icon>
</el-button>
</el-form-item>
<!-- 可折叠的查询条件 -->
<transition>
<div
v-if=
"isExpanded"
>
<el-form-item
label=
"时段"
prop=
"isClock"
style=
"width: 300px; margin-top: 15px"
>
<el-select
v-model=
"queryParams.isClock"
placeholder=
"请选择打卡时段"
clearable
>
<el-option
v-for=
"dict in time_difference"
:key=
"dict.value"
:label=
"dict.label"
:value=
"dict.value"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"状态"
prop=
"checkInStatus"
style=
"width: 330px; margin-top: 15px"
>
<el-select
v-model=
"queryParams.checkInStatus"
placeholder=
"请选择打卡状态"
clearable
style=
"width: 200px;"
>
<el-option
v-for=
"dict in clock_status"
:key=
"dict.value"
:label=
"dict.label"
:value=
"dict.value"
/>
</el-select>
</el-form-item>
</div>
</transition>
</el-form>
</div>
<div
class=
"contentTable"
>
<div
style=
"padding-left: 8px ;margin-bottom: 20px"
>
<span
class=
"title"
style=
"border-bottom: 3px solid #0062FF;"
>
考勤打卡
</span>
<span
style=
"padding-left: 65%"
>
<el-button
type=
"primary"
plain
icon=
"Plus"
@
click=
"handleAdd"
v-hasPermi=
"['psa:clock:add']"
>
新增考勤
</el-button>
<el-button
type=
"primary"
plain
icon=
"Delete"
:disabled=
"multiple"
@
click=
"handleDelete"
v-hasPermi=
"['psa:clock:remove']"
>
删除
</el-button>
<el-button
plain
@
click=
"dialogVisible = true"
type=
"primary"
icon=
"Upload"
v-hasPermi=
"['psa:clock:export']"
>
导入
</el-button>
<el-button
type=
"primary"
plain
icon=
"Download"
@
click=
"handleExport"
v-hasPermi=
"['psa:clock:export']"
>
导出
</el-button>
<el-button
title=
"草稿箱"
type=
"text"
plain
v-hasPermi=
"['system:project:draft']"
@
click=
"draft"
><img
src=
"../../../assets/icons/common/rightone.png"
height=
"30"
width=
"30"
/></el-button>
</span>
</div>
<el-table
border=
"border"
v-loading=
"loading"
:data=
"clockList"
@
selection-change=
"handleSelectionChange"
>
<el-table-column
type=
"selection"
width=
"55"
align=
"center"
/>
<el-table-column
label=
"姓名"
align=
"center"
prop=
"employeeName"
/>
<el-table-column
label=
"部门"
align=
"center"
prop=
"departmentName"
/>
<el-table-column
label=
"打卡日期"
align=
"center"
prop=
"candidateDate"
width=
"180"
>
<
template
#
default=
"scope"
>
<span>
{{
parseTime
(
scope
.
row
.
candidateDate
,
'{y
}
/{m
}
/{d
}
'
)
}}
<
/span
>
<
/template
>
<
/el-table-column
>
<
el
-
table
-
column
label
=
"打卡时段"
align
=
"center"
prop
=
"isClock"
>
<
template
#
default
=
"scope"
>
<
dict
-
tag
:
options
=
"time_difference"
:
value
=
"scope.row.isClock"
/>
<
/template
>
<
/el-table-column
>
<
el
-
table
-
column
label
=
"打卡时间"
align
=
"center"
prop
=
"clockTime"
width
=
"180"
>
<
template
#
default
=
"scope"
>
<
span
>
{{
scope
.
row
.
clockTime
}}
<
/span
>
<
/template
>
<
/el-table-column
>
<
el
-
table
-
column
label
=
"打卡状态"
align
=
"center"
prop
=
"checkInStatus"
>
<
template
#
default
=
"scope"
>
<
dict
-
tag
:
options
=
"clock_status"
:
value
=
"scope.row.checkInStatus"
/>
<
/template
>
<
/el-table-column
>
<
el
-
table
-
column
label
=
"操作"
align
=
"center"
class
-
name
=
"small-padding fixed-width"
fixed
=
"right"
min
-
width
=
"50"
>
<
template
#
default
=
"scope"
>
<
el
-
tooltip
content
=
"编辑"
placement
=
"top"
>
<
el
-
button
link
type
=
"text"
@
click
=
"handleUpdate(scope.row)"
v
-
hasPermi
=
"['psa:material:edit']"
>
<
img
src
=
"../../../assets/icons/common/edit.png"
height
=
"32"
width
=
"32"
/>
<
/el-button
>
<
/el-tooltip
>
<
el
-
tooltip
content
=
"删除"
placement
=
"top"
>
<
el
-
button
link
type
=
"text"
@
click
=
"handleDelete(scope.row)"
v
-
hasPermi
=
"['psa:material:edit']"
>
<
img
src
=
"../../../assets/icons/common/delete.png"
height
=
"32"
width
=
"32"
/>
<
/el-button
>
<
/el-tooltip
>
<
/template
>
<
/el-table-column
>
<
/el-table
>
<
div
class
=
"pagination"
>
<
pagination
layout
=
"prev, pager, next, sizes, jumper"
v
-
show
=
"total > 0"
:
total
=
"total"
v
-
model
:
page
=
"queryParams.pageNum"
v
-
model
:
limit
=
"queryParams.pageSize"
@
pagination
=
"getList"
/>
<
/div
>
<
/div
>
<!--
导入对话框
-->
<
el
-
dialog
v
-
model
=
"dialogVisible"
title
=
"导入"
width
=
"500"
@
closed
=
"handleImportClose"
>
<
div
style
=
"margin-bottom: 20px"
>
<
el
-
upload
ref
=
"uploadRef"
class
=
"upload-demo"
drag
:
auto
-
upload
=
"false"
:
limit
=
"1"
:
on
-
exceed
=
"handleExceed"
:
on
-
change
=
"handleFileChange"
:
show
-
file
-
list
=
"false"
accept
=
".xlsx,.xls,.xlsm"
>
<
el
-
icon
class
=
"el-icon--upload"
><
upload
-
filled
/><
/el-icon
>
<
div
class
=
"el-upload__text"
>
拖拽至此
或
<
em
>
点击选择
<
/em
>
<
/div
>
<
template
#
tip
>
<
div
class
=
"el-upload__tip"
>
支持上传文件格式为
:
.
xlsx
.
xls
.
xlsm
(
每次仅能上传一个文件
)
<
/div
>
<
/template
>
<
/el-upload
>
<!--
修改后的文件展示
-->
<
div
v
-
if
=
"selectedFile"
class
=
"file-list"
style
=
"margin-top: 16px"
>
<
div
class
=
"file-item"
>
<
el
-
icon
><
Document
/><
/el-icon
>
<
span
style
=
"margin-left: 8px"
>
{{
selectedFile
.
name
}}
<
/span
>
<
el
-
button
link
type
=
"danger"
@
click
=
"handleRemove"
style
=
"margin-left: auto"
>
删除
<
/el-button
>
<
/div
>
<
/div
>
<
/div
>
<
template
#
footer
>
<
div
class
=
"dialog-footer"
>
<
el
-
button
@
click
=
"dialogVisible = false"
>
取消
<
/el-button
>
<
el
-
button
type
=
"primary"
@
click
=
"submitImport"
>
导入
<
/el-button
>
<
/div
>
<
/template
>
<
/el-dialog
>
<
/div
>
<
/template
>
<
script
setup
name
=
"Clock"
>
import
{
listClock
,
delClock
,
addClock
,
updateClock
,
importData
}
from
"@/api/attendance/clock"
;
import
{
ArrowDown
,
UploadFilled
}
from
"@element-plus/icons-vue"
;
import
{
ElMessage
,
ElMessageBox
}
from
"element-plus"
;
const
{
proxy
}
=
getCurrentInstance
();
const
{
clock_status
,
time_difference
}
=
proxy
.
useDict
(
'clock_status'
,
'time_difference'
);
const
selectedFile
=
ref
(
null
);
const
dialogVisible
=
ref
(
false
)
const
clockList
=
ref
([]);
const
open
=
ref
(
false
);
const
loading
=
ref
(
true
);
const
showSearch
=
ref
(
true
);
const
ids
=
ref
([]);
const
single
=
ref
(
true
);
const
multiple
=
ref
(
true
);
const
total
=
ref
(
0
);
const
title
=
ref
(
""
);
const
daterangeCandidateDate
=
ref
([]);
const
isExpanded
=
ref
(
false
);
const
data
=
reactive
({
form
:
{
}
,
queryParams
:
{
pageNum
:
1
,
pageSize
:
10
,
employeeId
:
null
,
employeeName
:
null
,
departmentName
:
null
,
candidateDate
:
null
,
isClock
:
null
,
checkInStatus
:
null
,
}
,
rules
:
{
}
}
);
const
choose
=
[
{
value
:
'行政管理服务部'
,
label
:
'行政管理服务部'
}
,
{
value
:
'人才服务事业部'
,
label
:
'人才服务事业部'
}
,
{
value
:
'教育培训事业部'
,
label
:
'教育培训事业部'
}
,
{
value
:
'软件服务事业部'
,
label
:
'软件服务事业部'
}
,
{
value
:
'综合管理事业部'
,
label
:
'综合管理事业部'
}
,
{
value
:
'日本事业服务部'
,
label
:
'日本事业服务部'
}
,
{
value
:
'公司'
,
label
:
'公司'
}
,
]
const
{
queryParams
,
form
,
rules
}
=
toRefs
(
data
);
onMounted
(()
=>
{
getList
();
}
);
/** 查询考勤打卡列表 */
function
getList
()
{
console
.
log
(
"getList执行了"
)
loading
.
value
=
true
;
queryParams
.
value
.
params
=
{
}
;
if
(
null
!=
daterangeCandidateDate
&&
''
!=
daterangeCandidateDate
)
{
queryParams
.
value
.
params
[
"beginCandidateDate"
]
=
daterangeCandidateDate
.
value
[
0
];
queryParams
.
value
.
params
[
"endCandidateDate"
]
=
daterangeCandidateDate
.
value
[
1
];
}
listClock
(
queryParams
.
value
).
then
(
response
=>
{
clockList
.
value
=
response
.
rows
;
total
.
value
=
response
.
total
;
loading
.
value
=
false
;
}
);
}
// 取消按钮
function
cancel
()
{
open
.
value
=
false
;
reset
();
}
// 表单重置
function
reset
()
{
form
.
value
=
{
id
:
null
,
employeeId
:
null
,
userId
:
null
,
deptId
:
null
,
projectId
:
null
,
employeeName
:
null
,
departmentName
:
null
,
candidateDate
:
null
,
isClock
:
null
,
clockTime
:
null
,
checkInStatus
:
null
,
creatBy
:
null
,
creatTime
:
null
,
updateTime
:
null
,
draft
:
null
,
delFlag
:
null
}
;
proxy
.
resetForm
(
"clockRef"
);
}
/** 搜索按钮操作 */
function
handleQuery
()
{
queryParams
.
value
.
pageNum
=
1
;
getList
();
}
/** 重置按钮操作 */
function
resetQuery
()
{
daterangeCandidateDate
.
value
=
[];
proxy
.
resetForm
(
"queryRef"
);
handleQuery
();
}
// 多选框选中数据
function
handleSelectionChange
(
selection
)
{
ids
.
value
=
selection
.
map
(
item
=>
item
.
id
);
single
.
value
=
selection
.
length
!=
1
;
multiple
.
value
=
!
selection
.
length
;
}
/** 新增按钮操作 */
function
handleAdd
()
{
reset
();
/* open.value = true;
title.value = "添加考勤打卡";*/
proxy
.
$router
.
push
({
path
:
'/attendances/clockadd'
}
);
}
/** 进入草稿箱 */
function
draft
()
{
reset
();
proxy
.
$router
.
push
({
path
:
'/attendances/clockdraft'
}
);
}
/** 修改按钮操作 */
function
handleUpdate
(
row
)
{
reset
();
/* getClock(_id).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改考勤打卡";
}
);*/
const
_id
=
row
.
id
proxy
.
$router
.
push
({
path
:
'/attendances/clockadd'
,
query
:
{
id
:
_id
}
}
);
}
/** 切换展开/折叠 */
const
toggleSearch
=
()
=>
{
isExpanded
.
value
=
!
isExpanded
.
value
;
}
/** 提交按钮 */
function
submitForm
()
{
proxy
.
$refs
[
"clockRef"
].
validate
(
valid
=>
{
if
(
valid
)
{
if
(
form
.
value
.
id
!=
null
)
{
updateClock
(
form
.
value
).
then
(
response
=>
{
proxy
.
$modal
.
msgSuccess
(
"修改成功"
);
open
.
value
=
false
;
getList
();
}
);
}
else
{
addClock
(
form
.
value
).
then
(
response
=>
{
proxy
.
$modal
.
msgSuccess
(
"新增成功"
);
open
.
value
=
false
;
getList
();
}
);
}
}
}
);
}
/** 删除按钮操作 */
function
handleDelete
(
row
)
{
const
_ids
=
row
.
id
||
ids
.
value
;
proxy
.
$modal
.
confirm
(
'是否确认删除考勤打卡编号为"'
+
_ids
+
'"的数据项?'
).
then
(
function
()
{
return
delClock
(
_ids
);
}
).
then
(()
=>
{
getList
();
proxy
.
$modal
.
msgSuccess
(
"删除成功"
);
}
).
catch
(()
=>
{
}
);
}
/** 导出按钮操作 */
function
handleExport
()
{
proxy
.
download
(
'psa/clock/export'
,
{
...
queryParams
.
value
}
,
`clock_${new Date().getTime()
}
.xlsx`
)
}
/** 导入操作 */
// 修改文件处理方法
const
handleExceed
=
()
=>
{
ElMessage
.
warning
(
'每次只能上传一个文件,新文件将替换当前文件'
);
}
;
const
handleFileChange
=
(
file
)
=>
{
const
allowedExtensions
=
[
".xlsx"
,
".xls"
,
".xlsm"
];
const
fileExtension
=
file
.
name
.
slice
(
file
.
name
.
lastIndexOf
(
"."
)).
toLowerCase
();
if
(
!
allowedExtensions
.
includes
(
fileExtension
))
{
ElMessage
.
error
(
'仅支持上传 .xlsx、.xls、.xlsm 格式的文件!'
);
return
false
;
}
// 直接替换已有文件
selectedFile
.
value
=
{
...
file
,
status
:
'ready'
,
percentage
:
0
}
;
return
false
;
}
;
// 修改删除方法
const
handleRemove
=
()
=>
{
selectedFile
.
value
=
null
;
}
;
// 修改提交方法
const
submitImport
=
async
()
=>
{
if
(
!
selectedFile
.
value
)
{
ElMessage
.
warning
(
'请选择要导入的文件'
);
return
;
}
try
{
const
formData
=
new
FormData
();
formData
.
append
(
'file'
,
selectedFile
.
value
.
raw
||
selectedFile
.
value
);
// 参数名改为单数
importData
(
formData
).
then
(
response
=>
{
if
(
response
.
code
===
200
)
{
ElMessage
.
success
(
'导入成功'
);
dialogVisible
.
value
=
false
;
getList
();
}
else
{
ElMessage
.
error
(
response
.
msg
||
'导入失败'
);
}
}
)
}
catch
(
error
)
{
ElMessage
.
error
(
'导入失败:'
+
error
.
message
);
}
}
;
// 修改关闭处理方法
const
handleImportClose
=
()
=>
{
selectedFile
.
value
=
null
;
}
;
getList
();
<
/script
>
<
style
scoped
>
.
title
{
width
:
72
px
;
height
:
15
px
;
font
-
family
:
PingFangSC
-
Medium
;
font
-
weight
:
900
;
font
-
size
:
18
px
;
color
:
#
0
D162A
;
letter
-
spacing
:
0
;
line
-
height
:
15
px
;
}
.
top
-
title
{
margin
:
16
px
0
px
37
px
1200
px
;
}
.
blue
{
margin
-
top
:
8
px
;
margin
-
left
:
52
px
;
width
:
72
px
;
height
:
4
px
;
background
:
#
0062
FF
;
}
:
deep
(.
el
-
table
th
.
el
-
table__cell
)
{
background
:
#
F6F8FC
!
important
;
}
.
pagination
{
position
:
absolute
;
/* 子元素绝对定位 */
bottom
:
36
px
;
/* 距离父元素底边20px */
left
:
900
px
;
}
.
file
-
list
{
border
:
1
px
solid
#
ebeef5
;
border
-
radius
:
4
px
;
padding
:
8
px
;
max
-
height
:
200
px
;
overflow
-
y
:
auto
;
}
.
file
-
item
{
display
:
flex
;
align
-
items
:
center
;
padding
:
8
px
;
transition
:
background
-
color
0.3
s
;
}
.
file
-
item
:
hover
{
background
-
color
:
#
f5f7fa
;
}
.
el
-
upload__tip
{
color
:
#
666
;
font
-
size
:
12
px
;
margin
-
top
:
8
px
;
}
.
contentTable
{
position
:
relative
;
background
:
#
ffffff
;
box
-
shadow
:
0
2
px
2
px
0
#
b3b3b380
;
border
-
radius
:
2
px
;
flex
:
1
;
/* 占满剩余高度 */
padding
:
30
px
;
}
<
/style
>
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