|
@ -6,141 +6,145 @@ |
|
|
<div class="table-head-item">晚</div> |
|
|
<div class="table-head-item">晚</div> |
|
|
<div class="table-head-item" style="width: 30%">审核人</div> |
|
|
<div class="table-head-item" style="width: 30%">审核人</div> |
|
|
</div> |
|
|
</div> |
|
|
<div v-if="clockInfos && clockInfos.length"> |
|
|
<div id="scrollTo"> |
|
|
<div v-for="(list, listIndex) in clockInfos" :key="listIndex" class="teble-box"> |
|
|
<div v-if="clockInfos && clockInfos.length"> |
|
|
<div class="table-time px-2">{{ list.dateTime }}</div> |
|
|
<div v-for="(list, listIndex) in clockInfos" :key="listIndex" class="teble-box"> |
|
|
<a-table :pagination="false" :show-header="false" :columns="columns" :data-source="list.recordList"> |
|
|
<div class="table-time px-2">{{ list.dateTime }}</div> |
|
|
<!-- 早 --> |
|
|
<a-table :pagination="false" :show-header="false" :columns="columns" :data-source="list.recordList"> |
|
|
<template slot="morning" slot-scope="text, record, index"> |
|
|
<!-- 早 --> |
|
|
<div v-if="!record.isMine && !record.isChecker"> |
|
|
<template slot="morning" slot-scope="text, record, index"> |
|
|
<span v-if="record.morningStatus">{{ $moment(record.morning - 0).format('HH:mm') }}</span> |
|
|
<div v-if="!record.isMine && !record.isChecker"> |
|
|
<span v-else>未打卡</span> |
|
|
<span v-if="record.morningStatus">{{ $moment(record.morning - 0).format('HH:mm') }}</span> |
|
|
</div> |
|
|
<span v-else>未打卡</span> |
|
|
|
|
|
|
|
|
<div v-else> |
|
|
|
|
|
<div v-if="record.isMine"> |
|
|
|
|
|
<span v-if="record.morningStatus" class="baseColor font-bold"> |
|
|
|
|
|
{{ $moment(record.morning - 0).format('HH:mm') }} |
|
|
|
|
|
</span> |
|
|
|
|
|
<a-button |
|
|
|
|
|
v-else |
|
|
|
|
|
type="primary" |
|
|
|
|
|
size="small" |
|
|
|
|
|
@click="checkTime(listIndex, index, 0, record.id, record.memberId, record.checkerId)" |
|
|
|
|
|
> |
|
|
|
|
|
打卡 |
|
|
|
|
|
</a-button> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div v-if="record.isChecker"> |
|
|
<div v-else> |
|
|
<div v-if="record.morningStatus && !showMorningTime"> |
|
|
<div v-if="record.isMine"> |
|
|
<a-popconfirm |
|
|
<span v-if="record.morningStatus" class="baseColor font-bold"> |
|
|
ok-text="取消" |
|
|
{{ $moment(record.morning - 0).format('HH:mm') }} |
|
|
cancel-text="修改" |
|
|
</span> |
|
|
ok-type="" |
|
|
<a-button |
|
|
@confirm="cancel" |
|
|
v-else |
|
|
:visible="morningVisible" |
|
|
type="primary" |
|
|
@cancel="changeStatus(record.id, 0, 'morning')" |
|
|
size="small" |
|
|
|
|
|
:loading="morningLoading" |
|
|
|
|
|
@click="checkTime(listIndex, index, 0, record.id, record.memberId, record.checkerId, list.dateTime)" |
|
|
> |
|
|
> |
|
|
<a-icon slot="icon" type="" /> |
|
|
打卡 |
|
|
<a-button slot="title" size="small" @click="rejectStatus(record.id, 1, 'morning', record.morning)">驳回</a-button> |
|
|
</a-button> |
|
|
<span |
|
|
</div> |
|
|
class="font-bold" |
|
|
|
|
|
:class="record.morningStatus === 2 ? 'line-through red--text' : 'green--text'" |
|
|
<div v-if="record.isChecker"> |
|
|
@click="changeVisible(record.morningStatus, 'morningVisible')" |
|
|
<div v-if="record.morningStatus && !showMorningTime"> |
|
|
|
|
|
<a-popconfirm |
|
|
|
|
|
ok-text="取消" |
|
|
|
|
|
cancel-text="修改" |
|
|
|
|
|
ok-type="" |
|
|
|
|
|
@confirm="cancel" |
|
|
|
|
|
:visible="morningVisible" |
|
|
|
|
|
@cancel="changeStatus(record.id, 0, 'morning')" |
|
|
> |
|
|
> |
|
|
{{ $moment(record.morning - 0).format('HH:mm') }} |
|
|
<a-icon slot="icon" type="" /> |
|
|
</span> |
|
|
<a-button slot="title" size="small" @click="rejectStatus(record.id, 1, 'morning', record.morning)">驳回</a-button> |
|
|
</a-popconfirm> |
|
|
<span |
|
|
|
|
|
class="font-bold" |
|
|
|
|
|
:class="record.morningStatus === 2 ? 'line-through red--text' : 'green--text'" |
|
|
|
|
|
@click="changeVisible(record.morningStatus, 'morningVisible')" |
|
|
|
|
|
> |
|
|
|
|
|
{{ $moment(record.morning - 0).format('HH:mm') }} |
|
|
|
|
|
</span> |
|
|
|
|
|
</a-popconfirm> |
|
|
|
|
|
</div> |
|
|
|
|
|
<div v-if="!record.morningStatus && !showMorningTime">未打卡</div> |
|
|
|
|
|
<!-- 修改时间 --> |
|
|
|
|
|
<a-time-picker |
|
|
|
|
|
placeholder="请选择" |
|
|
|
|
|
style="width: 100%" |
|
|
|
|
|
v-if="showMorningTime" |
|
|
|
|
|
format="HH:mm" |
|
|
|
|
|
class="px-2" |
|
|
|
|
|
@change="timeChange" |
|
|
|
|
|
@openChange="openChange($event, 'morning')" |
|
|
|
|
|
/> |
|
|
</div> |
|
|
</div> |
|
|
<div v-if="!record.morningStatus && !showMorningTime">未打卡</div> |
|
|
|
|
|
<!-- 修改时间 --> |
|
|
|
|
|
<a-time-picker |
|
|
|
|
|
placeholder="请选择" |
|
|
|
|
|
style="width: 100%" |
|
|
|
|
|
v-if="showMorningTime" |
|
|
|
|
|
format="HH:mm" |
|
|
|
|
|
class="px-2" |
|
|
|
|
|
@change="timeChange" |
|
|
|
|
|
@openChange="openChange($event, 'morning')" |
|
|
|
|
|
/> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</template> |
|
|
</template> |
|
|
<!-- 晚 --> |
|
|
<!-- 晚 --> |
|
|
<template slot="night" slot-scope="text, record, index"> |
|
|
<template slot="night" slot-scope="text, record, index"> |
|
|
<div v-if="!record.isMine && !record.isChecker"> |
|
|
<div v-if="!record.isMine && !record.isChecker"> |
|
|
<span v-if="record.nightStatus">{{ $moment(record.night - 0).format('HH:mm') }}</span> |
|
|
<span v-if="record.nightStatus">{{ $moment(record.night - 0).format('HH:mm') }}</span> |
|
|
<span v-else>未打卡</span> |
|
|
<span v-else>未打卡</span> |
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<div v-else> |
|
|
|
|
|
<div v-if="record.isMine"> |
|
|
|
|
|
<span v-if="record.nightStatus" class="baseColor font-bold"> |
|
|
|
|
|
{{ $moment(record.night - 0).format('HH:mm') }} |
|
|
|
|
|
</span> |
|
|
|
|
|
<a-button |
|
|
|
|
|
v-else |
|
|
|
|
|
type="primary" |
|
|
|
|
|
size="small" |
|
|
|
|
|
@click="checkTime(listIndex, index, 1, record.id, record.memberId, record.checkerId)" |
|
|
|
|
|
> |
|
|
|
|
|
打卡 |
|
|
|
|
|
</a-button> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div v-if="record.isChecker"> |
|
|
<div v-else> |
|
|
<div v-if="record.nightStatus && !showNightTime"> |
|
|
<div v-if="record.isMine"> |
|
|
<a-popconfirm |
|
|
<span v-if="record.nightStatus" class="baseColor font-bold"> |
|
|
ok-text="取消" |
|
|
{{ $moment(record.night - 0).format('HH:mm') }} |
|
|
cancel-text="修改" |
|
|
</span> |
|
|
ok-type="" |
|
|
<a-button |
|
|
@confirm="cancel" |
|
|
v-else |
|
|
:visible="visible" |
|
|
type="primary" |
|
|
@cancel="changeStatus(record.id, 0, 'night')" |
|
|
size="small" |
|
|
|
|
|
:loading="nightLoading" |
|
|
|
|
|
@click="checkTime(listIndex, index, 1, record.id, record.memberId, record.checkerId, list.dateTime)" |
|
|
> |
|
|
> |
|
|
<a-icon slot="icon" type="" /> |
|
|
打卡 |
|
|
<a-button slot="title" size="small" @click="rejectStatus(record.id, 1, 'night', record.night)">驳回</a-button> |
|
|
</a-button> |
|
|
<span |
|
|
</div> |
|
|
class="font-bold" |
|
|
|
|
|
:class="record.nightStatus === 2 ? 'line-through red--text' : 'green--text'" |
|
|
<div v-if="record.isChecker"> |
|
|
@click="changeVisible(record.nightStatus, 'visible')" |
|
|
<div v-if="record.nightStatus && !showNightTime"> |
|
|
|
|
|
<a-popconfirm |
|
|
|
|
|
ok-text="取消" |
|
|
|
|
|
cancel-text="修改" |
|
|
|
|
|
ok-type="" |
|
|
|
|
|
@confirm="cancel" |
|
|
|
|
|
:visible="visible" |
|
|
|
|
|
@cancel="changeStatus(record.id, 0, 'night')" |
|
|
> |
|
|
> |
|
|
{{ $moment(record.night - 0).format('HH:mm') }} |
|
|
<a-icon slot="icon" type="" /> |
|
|
</span> |
|
|
<a-button slot="title" size="small" @click="rejectStatus(record.id, 1, 'night', record.night)">驳回</a-button> |
|
|
</a-popconfirm> |
|
|
<span |
|
|
|
|
|
class="font-bold" |
|
|
|
|
|
:class="record.nightStatus === 2 ? 'line-through red--text' : 'green--text'" |
|
|
|
|
|
@click="changeVisible(record.nightStatus, 'visible')" |
|
|
|
|
|
> |
|
|
|
|
|
{{ $moment(record.night - 0).format('HH:mm') }} |
|
|
|
|
|
</span> |
|
|
|
|
|
</a-popconfirm> |
|
|
|
|
|
</div> |
|
|
|
|
|
<div v-if="!record.nightStatus && !showNightTime">未打卡</div> |
|
|
|
|
|
<!-- 修改时间 --> |
|
|
|
|
|
<a-time-picker |
|
|
|
|
|
placeholder="请选择" |
|
|
|
|
|
style="width: 100%" |
|
|
|
|
|
v-if="showNightTime" |
|
|
|
|
|
format="HH:mm" |
|
|
|
|
|
class="px-2" |
|
|
|
|
|
@change="timeChange" |
|
|
|
|
|
@openChange="openChange($event, 'night')" |
|
|
|
|
|
/> |
|
|
</div> |
|
|
</div> |
|
|
<div v-if="!record.nightStatus && !showNightTime">未打卡</div> |
|
|
|
|
|
<!-- 修改时间 --> |
|
|
|
|
|
<a-time-picker |
|
|
|
|
|
placeholder="请选择" |
|
|
|
|
|
style="width: 100%" |
|
|
|
|
|
v-if="showNightTime" |
|
|
|
|
|
format="HH:mm" |
|
|
|
|
|
class="px-2" |
|
|
|
|
|
@change="timeChange" |
|
|
|
|
|
@openChange="openChange($event, 'night')" |
|
|
|
|
|
/> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</template> |
|
|
</template> |
|
|
<!-- 审核人 --> |
|
|
<!-- 审核人 --> |
|
|
<template slot="checkerName" slot-scope="text, record"> |
|
|
<template slot="checkerName" slot-scope="text, record"> |
|
|
<div class="px-2"> |
|
|
<div class="px-2"> |
|
|
<div v-if="!record.isMine || (record.isMine && record.morningStatus && record.nightStatus)"> |
|
|
<div v-if="!record.isMine || (record.isMine && record.morningStatus && record.nightStatus)"> |
|
|
{{ record.checkerName || members[0].name }} |
|
|
{{ record.checkerName || members[0].name }} |
|
|
</div> |
|
|
|
|
|
<a-select v-else :default-value="record.checkerId || members[0].memberId" style="width: 100%" @change="chooseChecker"> |
|
|
|
|
|
<a-select-option :value="member.memberId" v-for="member in members" :key="member.memberId"> |
|
|
|
|
|
{{ member.name }} |
|
|
|
|
|
</a-select-option> |
|
|
|
|
|
</a-select> |
|
|
</div> |
|
|
</div> |
|
|
<a-select v-else :default-value="record.checkerId || members[0].memberId" style="width: 100%" @change="chooseChecker"> |
|
|
</template> |
|
|
<a-select-option :value="member.memberId" v-for="member in members" :key="member.memberId"> |
|
|
</a-table> |
|
|
{{ member.name }} |
|
|
</div> |
|
|
</a-select-option> |
|
|
|
|
|
</a-select> |
|
|
|
|
|
</div> |
|
|
|
|
|
</template> |
|
|
|
|
|
</a-table> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<a-empty class="mt-8 mb-8" description="暂无打卡信息" v-else /> |
|
|
</div> |
|
|
</div> |
|
|
<a-empty class="mt-8 mb-8" description="暂无打卡信息" v-else /> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
</template> |
|
|
</template> |
|
|
|
|
|
|
|
@ -178,16 +182,26 @@ export default { |
|
|
showMorningTime: false, |
|
|
showMorningTime: false, |
|
|
chooseTime: '', |
|
|
chooseTime: '', |
|
|
auditOptions: null, |
|
|
auditOptions: null, |
|
|
|
|
|
morningLoading: false, |
|
|
|
|
|
nightLoading: false, |
|
|
|
|
|
startTime: '', |
|
|
|
|
|
endTime: '', |
|
|
}; |
|
|
}; |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
computed: mapState('home', ['projectId', 'members']), |
|
|
computed: mapState('home', ['projectId', 'members']), |
|
|
|
|
|
|
|
|
mounted() { |
|
|
mounted() { |
|
|
this.timer = setInterval(() => { |
|
|
this.timer = setInterval(async () => { |
|
|
if (this.projectId) { |
|
|
if (this.projectId) { |
|
|
clearInterval(this.timer); |
|
|
clearInterval(this.timer); |
|
|
this.setParams(); |
|
|
await this.setParams(); |
|
|
|
|
|
|
|
|
|
|
|
// 自动移动到目标位置 |
|
|
|
|
|
document.querySelector('#scrollTo').scrollIntoView({ |
|
|
|
|
|
behavior: 'smooth', // 平滑过渡 |
|
|
|
|
|
block: 'start', // 上边框与视窗顶部平齐。默认值 |
|
|
|
|
|
}); |
|
|
} |
|
|
} |
|
|
}, 300); |
|
|
}, 300); |
|
|
}, |
|
|
}, |
|
@ -196,10 +210,10 @@ export default { |
|
|
async setParams(options) { |
|
|
async setParams(options) { |
|
|
const { projectId } = this; |
|
|
const { projectId } = this; |
|
|
const time = this.$moment(Date.now()).format('YYYY-MM-DD'); |
|
|
const time = this.$moment(Date.now()).format('YYYY-MM-DD'); |
|
|
const startTime = (options && options.startTime) || this.$moment(`${time} 00:00`).format('x') - 0; |
|
|
this.startTime = (options && options.startTime) || this.$moment(`${time} 00:00`).format('x') - 0; |
|
|
const endTime = (options && options.endTime) || this.$moment(`${time} 23:59`).format('x') - 0; |
|
|
this.endTime = (options && options.endTime) || this.$moment(`${time} 23:59`).format('x') - 0; |
|
|
const memberIdList = (options && options.memberIdList) || this.memberIdList; |
|
|
this.memberIdList = (options && options.memberIdList) || []; |
|
|
const params = { param: { projectId, memberIdList, startTime, endTime } }; |
|
|
const params = { param: { projectId, memberIdList: this.memberIdList, startTime: this.startTime, endTime: this.endTime } }; |
|
|
await this.getClockQuery(params); |
|
|
await this.getClockQuery(params); |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
@ -231,7 +245,7 @@ export default { |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
// 打卡 |
|
|
// 打卡 |
|
|
checkTime(listIndex, index, clockType, id, memberId, checkerId) { |
|
|
checkTime(listIndex, index, clockType, id, memberId, checkerId, clockTime) { |
|
|
const time = Date.now(); |
|
|
const time = Date.now(); |
|
|
const selectTime = this.$moment(time).format('HH:mm'); |
|
|
const selectTime = this.$moment(time).format('HH:mm'); |
|
|
if (clockType === 0) { |
|
|
if (clockType === 0) { |
|
@ -239,7 +253,7 @@ export default { |
|
|
} else { |
|
|
} else { |
|
|
this.clockInfos[listIndex].recordList[index].night = selectTime; |
|
|
this.clockInfos[listIndex].recordList[index].night = selectTime; |
|
|
} |
|
|
} |
|
|
const dateTime = this.$moment(time).format('x') - 0; |
|
|
const dateTime = this.$moment(`${clockTime} ${selectTime}`).format('x') - 0; |
|
|
const params = { param: { checkerId: this.checkerId || checkerId || this.members[0].memberId, clockType, dateTime, id, memberId } }; |
|
|
const params = { param: { checkerId: this.checkerId || checkerId || this.members[0].memberId, clockType, dateTime, id, memberId } }; |
|
|
this.handleClockPunch(params); |
|
|
this.handleClockPunch(params); |
|
|
}, |
|
|
}, |
|
@ -254,16 +268,32 @@ export default { |
|
|
*/ |
|
|
*/ |
|
|
async handleClockPunch(params) { |
|
|
async handleClockPunch(params) { |
|
|
try { |
|
|
try { |
|
|
|
|
|
if (params.param.clockType === 0) { |
|
|
|
|
|
this.morningLoading = true; |
|
|
|
|
|
} else { |
|
|
|
|
|
this.nightLoading = true; |
|
|
|
|
|
} |
|
|
const res = await clockPunch(params); |
|
|
const res = await clockPunch(params); |
|
|
const { code, msg } = res.data; |
|
|
const { code, msg } = res.data; |
|
|
if (code === 200) { |
|
|
if (code === 200) { |
|
|
this.$message.success('打卡成功'); |
|
|
this.$message.success('打卡成功'); |
|
|
this.setParams(); |
|
|
const options = { startTime: this.startTime, endTime: this.endTime, memberIdList: this.memberIdList }; |
|
|
|
|
|
this.setParams(options); |
|
|
} else { |
|
|
} else { |
|
|
this.$message.error(msg || '打卡失败'); |
|
|
this.$message.error(msg || '打卡失败'); |
|
|
throw msg; |
|
|
throw msg; |
|
|
} |
|
|
} |
|
|
|
|
|
if (params.param.clockType === 0) { |
|
|
|
|
|
this.morningLoading = false; |
|
|
|
|
|
} else { |
|
|
|
|
|
this.nightLoading = false; |
|
|
|
|
|
} |
|
|
} catch (error) { |
|
|
} catch (error) { |
|
|
|
|
|
if (params.param.clockType === 0) { |
|
|
|
|
|
this.morningLoading = false; |
|
|
|
|
|
} else { |
|
|
|
|
|
this.nightLoading = false; |
|
|
|
|
|
} |
|
|
throw error || '打卡失败'; |
|
|
throw error || '打卡失败'; |
|
|
} |
|
|
} |
|
|
}, |
|
|
}, |
|
@ -336,7 +366,8 @@ export default { |
|
|
this.showNightTime = false; |
|
|
this.showNightTime = false; |
|
|
this.showMorningTime = false; |
|
|
this.showMorningTime = false; |
|
|
this.auditOptions = null; |
|
|
this.auditOptions = null; |
|
|
this.setParams(); |
|
|
const options = { startTime: this.startTime, endTime: this.endTime, memberIdList: this.memberIdList }; |
|
|
|
|
|
this.setParams(options); |
|
|
} else { |
|
|
} else { |
|
|
this.$message.error(msg || '审核失败'); |
|
|
this.$message.error(msg || '审核失败'); |
|
|
throw msg; |
|
|
throw msg; |
|
@ -359,9 +390,10 @@ export default { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
.table-time { |
|
|
.table-time { |
|
|
height: 36px; |
|
|
height: 30px; |
|
|
line-height: 36px; |
|
|
line-height: 30px; |
|
|
border-bottom: 1px solid #e8e8e8; |
|
|
border-bottom: 1px solid #e8e8e8; |
|
|
|
|
|
background: #fafafa; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
.table-head-item { |
|
|
.table-head-item { |
|
|