feat: add checkins page with dark mode support
Add new checkin stations page for marking attendance with dark mode CSS variables integration
This commit is contained in:
parent
286862d1a0
commit
85a20baf5a
238
app/pages/checkins.vue
Normal file
238
app/pages/checkins.vue
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
<template>
|
||||||
|
<div class="checkins-container">
|
||||||
|
<el-card>
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span>机位到位打卡</span>
|
||||||
|
<el-button type="primary" @click="showAddDialog = true">添加打卡</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-form :inline="true" class="filter-form">
|
||||||
|
<!-- 机位号筛选 -->
|
||||||
|
<el-form-item label="机位号">
|
||||||
|
<el-select v-model="filters.position_number" placeholder="全部" clearable @change="loadCheckins">
|
||||||
|
<el-option v-for="p in positionOptions" :key="p.value" :label="p.label" :value="p.value"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- 状态筛选 -->
|
||||||
|
<el-form-item label="状态">
|
||||||
|
<el-select v-model="filters.status" placeholder="全部" clearable @change="loadCheckins">
|
||||||
|
<el-option v-for="s in statusOptions" :key="s.value" :label="s.label" :value="s.value"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<el-table :data="checkins" border stripe class="checkins-table">
|
||||||
|
<el-table-column prop="id" label="ID" width="80"></el-table-column>
|
||||||
|
<el-table-column prop="position_number" label="机位号" width="100"></el-table-column>
|
||||||
|
<el-table-column prop="status" label="状态" width="120">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag :type="getStatusType(row.status)">{{ row.status }}</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="created_at" label="打卡时间">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ formatDate(row.created_at) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="notes" label="备注"></el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-dialog v-model="showAddDialog" title="添加打卡" width="500px">
|
||||||
|
<el-form :model="form" label-width="100px">
|
||||||
|
<el-form-item label="机位号">
|
||||||
|
<el-select v-model="form.position_number" placeholder="请选择机位号">
|
||||||
|
<el-option v-for="p in positionOptions" :key="p.value" :label="p.label" :value="p.value"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="状态">
|
||||||
|
<el-select v-model="form.status" placeholder="请选择状态">
|
||||||
|
<el-option v-for="s in statusOptions" :key="s.value" :label="s.label" :value="s.value"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="备注">
|
||||||
|
<el-input v-model="form.notes" type="textarea" placeholder="请输入备注(可选)"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="showAddDialog = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="addCheckin">确定</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
|
||||||
|
const checkins = ref([])
|
||||||
|
const showAddDialog = ref(false)
|
||||||
|
|
||||||
|
// 机位选项:1-6号
|
||||||
|
const positionOptions = [
|
||||||
|
{ value: 1, label: '1号心晴空间固定机位' },
|
||||||
|
{ value: 2, label: '2号AB栋固定机位' },
|
||||||
|
{ value: 3, label: '3号游走机位' },
|
||||||
|
{ value: 4, label: '4号游走机位' },
|
||||||
|
{ value: 5, label: '5号游走机位' },
|
||||||
|
{ value: 6, label: '6号游走机位' }
|
||||||
|
]
|
||||||
|
|
||||||
|
// 状态选项
|
||||||
|
const statusOptions = [
|
||||||
|
{ value: '到位', label: '到位' },
|
||||||
|
{ value: '离开', label: '离开' },
|
||||||
|
{ value: '休息/轮换', label: '休息/轮换' },
|
||||||
|
{ value: '异常', label: '异常' }
|
||||||
|
]
|
||||||
|
|
||||||
|
const filters = ref({
|
||||||
|
position_number: null as number | null,
|
||||||
|
status: '' as string
|
||||||
|
})
|
||||||
|
|
||||||
|
const form = ref({
|
||||||
|
position_number: null as number | null,
|
||||||
|
status: '',
|
||||||
|
notes: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const loadCheckins = async () => {
|
||||||
|
try {
|
||||||
|
const params = new URLSearchParams()
|
||||||
|
if (filters.value.position_number !== null && filters.value.position_number !== undefined) {
|
||||||
|
params.append('position_number', filters.value.position_number.toString())
|
||||||
|
}
|
||||||
|
if (filters.value.status) {
|
||||||
|
params.append('status', filters.value.status)
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await $fetch(`/api/checkins?${params}`)
|
||||||
|
checkins.value = res.data
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('加载数据失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const addCheckin = async () => {
|
||||||
|
if (!form.value.position_number || !form.value.status) {
|
||||||
|
ElMessage.error('请填写完整信息')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await $fetch('/api/checkins', {
|
||||||
|
method: 'POST',
|
||||||
|
body: {
|
||||||
|
position_number: form.value.position_number,
|
||||||
|
status: form.value.status,
|
||||||
|
notes: form.value.notes || ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
ElMessage.success('添加成功')
|
||||||
|
showAddDialog.value = false
|
||||||
|
form.value = { position_number: null, status: '', notes: '' }
|
||||||
|
loadCheckins()
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('添加失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatDate = (dateStr: string) => {
|
||||||
|
return new Date(dateStr).toLocaleString('zh-CN')
|
||||||
|
}
|
||||||
|
|
||||||
|
const getStatusType = (status: string) => {
|
||||||
|
const types: Record<string, string> = {
|
||||||
|
'到位': 'success',
|
||||||
|
'离开': 'info',
|
||||||
|
'休息/轮换': 'warning',
|
||||||
|
'异常': 'danger'
|
||||||
|
}
|
||||||
|
return types[status] || 'info'
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadCheckins()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.checkins-container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header span {
|
||||||
|
color: var(--header-text);
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-form {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 确保表格和表单在暗色模式下文字清晰 */
|
||||||
|
:deep(.el-card) {
|
||||||
|
background-color: var(--header-bg);
|
||||||
|
color: var(--header-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-card .el-card__header) {
|
||||||
|
border-bottom-color: var(--header-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-form-item__label) {
|
||||||
|
color: var(--header-text) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table) {
|
||||||
|
color: var(--header-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table th) {
|
||||||
|
background-color: var(--header-bg);
|
||||||
|
color: var(--header-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table tr) {
|
||||||
|
background-color: var(--header-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table td) {
|
||||||
|
color: var(--header-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.card-header {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-form :deep(.el-form-item) {
|
||||||
|
margin-right: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-form :deep(.el-select) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkins-table :deep(.col-notes) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
x
Reference in New Issue
Block a user