fix(ui): 调整表格列宽、优化下拉框及标签样式、修复时间选择器交互问题
- 调整人员管理角色列宽度以适应内容
- 优化下拉选择框的标签容器内边距和高度,移除冗余悬停样式
- 在考勤统计角色列使用标签组件显示,增强视觉区分
- 统一详情页统计数字的字体粗细
- 为班次管理的时间选择器添加“现在”操作按钮并修复选择后关闭逻辑
- 优化员工详情页的字体大小、行高和按钮样式,移除多余边框
| | |
| | | // 下拉框的样式 tag 样式 |
| | | |
| | | .n-base-selection-tags { |
| | | padding: 4px !important; |
| | | padding: 4px 26px 4px 4px !important; |
| | | gap: 4px !important; |
| | | |
| | | .n-base-selection-tag-wrapper { |
| | |
| | | color: rgba(23, 31, 38, 0.8) !important; |
| | | background-color: transparent !important; |
| | | padding: 0 !important; |
| | | height: 16px !important; |
| | | } |
| | | |
| | | .n-tag__border { |
| | |
| | | background-color: rgba(23, 31, 38, 0.05) !important; |
| | | } |
| | | |
| | | .n-base-select-option:not(.n-base-select-option--selected).n-base-select-option--pending:hover::before { |
| | | background-color: rgba(23, 31, 38, 0.05) !important; |
| | | } |
| | | // .n-base-select-option:not(.n-base-select-option--selected).n-base-select-option--pending:hover::before { |
| | | // background-color: rgba(23, 31, 38, 0.05) !important; |
| | | // } |
| | | |
| | | .n-base-select-option--selected:hover { |
| | | &::before { |
| | |
| | | const openEdit = (data: any) => { |
| | | formModel.value = { ...data } |
| | | } |
| | | function closeTimePicker() { |
| | | if (document.activeElement) { |
| | | (document.activeElement as HTMLElement).blur() |
| | | } |
| | | } |
| | | |
| | | defineExpose({ |
| | | openEdit, |
| | |
| | | </n-form-item> --> |
| | | |
| | | <n-form-item label="开始时间" path="startTime"> |
| | | <n-time-picker v-model:formatted-value="formModel.startTime" format="HH:mm" value-format="HH:mm" placeholder="--:--" clearable style="width: 100%" /> |
| | | <n-time-picker v-model:formatted-value="formModel.startTime" |
| | | format="HH:mm" value-format="HH:mm" |
| | | :actions="['now']" |
| | | @update:value="() => { closeTimePicker();}" |
| | | placeholder="--:--" clearable style="width: 100%" /> |
| | | </n-form-item> |
| | | |
| | | <n-form-item label="结束时间" path="endTime"> |
| | | <n-time-picker v-model:formatted-value="formModel.endTime" format="HH:mm" value-format="HH:mm" placeholder="--:--" clearable style="width: 100%" /> |
| | | <n-time-picker v-model:formatted-value="formModel.endTime" |
| | | format="HH:mm" value-format="HH:mm" |
| | | :actions="['now']" |
| | | @update:value="() => { closeTimePicker();}" |
| | | placeholder="--:--" clearable style="width: 100%" /> |
| | | </n-form-item> |
| | | |
| | | <n-form-item label="是否中途休息" path="isRest"> |
| | | <n-form-item label="是否中途休息" path="isRest" label-placement="left"> |
| | | <n-switch v-model:value="formModel.isRest" /> |
| | | </n-form-item> |
| | | |
| | | <template v-if="formModel.isRest"> |
| | | <n-form-item label="开始休息时间" path="restStartTime"> |
| | | <n-time-picker v-model:formatted-value="formModel.restStartTime" format="HH:mm" value-format="HH:mm" placeholder="--:--" clearable style="width: 100%" /> |
| | | <n-time-picker v-model:formatted-value="formModel.restStartTime" |
| | | format="HH:mm" value-format="HH:mm" |
| | | :actions="['now']" |
| | | @update:value="() => { closeTimePicker();}" |
| | | placeholder="--:--" clearable style="width: 100%" /> |
| | | </n-form-item> |
| | | |
| | | <n-form-item label="结束时间" path="restEndTime"> |
| | | <n-time-picker v-model:formatted-value="formModel.restEndTime" format="HH:mm" value-format="HH:mm" placeholder="--:--" clearable style="width: 100%" /> |
| | | <n-time-picker v-model:formatted-value="formModel.restEndTime" |
| | | format="HH:mm" value-format="HH:mm" |
| | | :actions="['now']" |
| | | @update:value="() => { closeTimePicker();}" |
| | | placeholder="--:--" clearable style="width: 100%" /> |
| | | </n-form-item> |
| | | </template> |
| | | </div> |
| | |
| | | <template #header> |
| | | <n-flex justify="space-between"> |
| | | <div class="flex items-center gap-16px text-sm"> |
| | | <span style="color:rgba(23, 31, 38, 0.6);font-size: 13px;">应打卡次数:<span style="color:#171F26">{{ statistics.shouldClockInDays }}次</span></span> |
| | | <span style="color:rgba(23, 31, 38, 0.6);font-size: 13px;">正常:<span style="color:#171F26">{{ statistics.clockInDays }}次</span></span> |
| | | <span style="color:rgba(23, 31, 38, 0.6);font-size: 13px;">迟到/早退:<span style="color:#171F26">{{ statistics.lateEarly }}次</span></span> |
| | | <span style="color:rgba(23, 31, 38, 0.6);font-size: 13px;">缺卡:<span style="color:#171F26">{{ statistics.notClockInDays }}次</span></span> |
| | | <span style="color:rgba(23, 31, 38, 0.6);font-size: 13px;font-weight: 400;">应打卡次数:<span style="color:#171F26">{{ statistics.shouldClockInDays }}次</span></span> |
| | | <span style="color:rgba(23, 31, 38, 0.6);font-size: 13px;font-weight: 400;">正常:<span style="color:#171F26">{{ statistics.clockInDays }}次</span></span> |
| | | <span style="color:rgba(23, 31, 38, 0.6);font-size: 13px;font-weight: 400;">迟到/早退:<span style="color:#171F26">{{ statistics.lateEarly }}次</span></span> |
| | | <span style="color:rgba(23, 31, 38, 0.6);font-size: 13px;font-weight: 400;">缺卡:<span style="color:#171F26">{{ statistics.notClockInDays }}次</span></span> |
| | | </div> |
| | | <div class="flex gap-2"> |
| | | <n-button |
| | |
| | | import type { DataTableColumns } from 'naive-ui' |
| | | import { exportClockInStatistics, getClockInStatisticsList } from '@/service/api/attendance' |
| | | import { fetchRoleList } from '@/service/api/fleet' |
| | | import { NButton } from 'naive-ui' |
| | | import { NButton ,NTag} from 'naive-ui' |
| | | import { downloadFile } from '@/utils' |
| | | import SearchPanel from '@/components/custom/SearchPanel.vue' |
| | | import dayjs from 'dayjs' |
| | |
| | | const columns = computed<DataTableColumns<any>>(() => [ |
| | | { title: '序号', key: 'serialNumber', width: 80, align: 'left', resizable: true, fixed: 'left' }, |
| | | { title: '人员', key: 'name', width: 140, align: 'left', resizable: true, fixed: 'left' }, |
| | | { title: '角色', key: 'roleName', width: 140, align: 'left', resizable: true }, |
| | | { title: '角色', key: 'roleName', width: 140, align: 'left', resizable: true,render: row => ( |
| | | |
| | | row.roleName&&<NTag type="primary" bordered={false} size="small" style={{ borderRadius: '4px' }}>{row.roleName}</NTag> |
| | | ), }, |
| | | { title: '所属队伍', key: 'teamName', width: 160, align: 'left', resizable: true }, |
| | | { title: '应打卡天数', key: 'shouldClockInDays', width: 120, align: 'left', resizable: true }, |
| | | { title: '正常', key: 'clockInDays', width: 120, align: 'left', resizable: true }, |
| | |
| | | </script> |
| | | |
| | | <template> |
| | | <div v-if="personnelInfo?.nickName" class="h-full flex flex-col overflow-y-auto"> |
| | | <div v-if="personnelInfo?.nickName" class="h-full flex flex-col overflow-y-auto roboTaxi"> |
| | | <n-card :bordered="false" class="rounded-6px h-full" content-style="padding: 20px 24px"> |
| | | <div class="flex items-center justify-between mb-24px"> |
| | | <div class="head"> |
| | | 员工详情 |
| | | </div> |
| | | <n-button type="primary" secondary style="border: 1px solid #7ABDFF;" class="w-84px h-32px" @click="handleEdit"> |
| | | <n-button type="primary" secondary @click="handleEdit"> |
| | | 编辑 |
| | | </n-button> |
| | | </div> |
| | |
| | | </div> |
| | | <div class="flex flex-col gap-4px"> |
| | | <span class="text-16px text-[#171F26]">{{ personnelInfo.nickName }}</span> |
| | | <div class="text-14px text-[#919191]"> |
| | | <div class="text-13px text-[#171F26]"> |
| | | 编号:{{ personnelInfo.uniqueNumber }} |
| | | </div> |
| | | </div> |
| | |
| | | |
| | | <div class="grid grid-cols-3 gap-24px mb-16px line-bottom"> |
| | | <div class="flex items-center"> |
| | | <span class="text-14px label-color w-42px">电话:</span> |
| | | <span class="text-14px text-[#171F26]">{{ personnelInfo.phoneNumber }}</span> |
| | | <span class="text-13px label-color w-42px">电话:</span> |
| | | <span class="text-13px text-[#171F26]">{{ personnelInfo.phoneNumber }}</span> |
| | | </div> |
| | | <div class="flex"> |
| | | <span class="text-14px label-color w-42px flex-shrink-0">角色:</span> |
| | | <span class="text-13px label-color w-42px flex-shrink-0">角色:</span> |
| | | <div class="flex gap-8px flex-wrap"> |
| | | <span v-for="item in personnelInfo.sysRoles" :key="item.roleId" class="text-14px text-[#171F26]">{{ item.roleName }}</span> |
| | | <span v-for="item in personnelInfo.sysRoles" :key="item.roleId" class="text-13px text-[#171F26]">{{ item.roleName }}</span> |
| | | </div> |
| | | </div> |
| | | <div class="flex items-center"> |
| | | <span class="text-14px label-color w-42px">备注:</span> |
| | | <span class="text-14px text-[#171F26]">{{ personnelInfo.remarks || '-' }}</span> |
| | | <span class="text-13px label-color w-42px">备注:</span> |
| | | <span class="text-13px text-[#171F26]">{{ personnelInfo.remarks || '-' }}</span> |
| | | </div> |
| | | </div> |
| | | <div class="mb-16px"> |
| | | <div class="text-14px font-600 text-[#171F26] mb-12px"> |
| | | <div class="text-14px text-[#171F26] mb-12px"> |
| | | 身份证: |
| | | </div> |
| | | <div v-if="personnelInfo.idCardFrontUrl || personnelInfo.idCardBackUrl" class="flex gap-16px"> |
| | |
| | | </div> |
| | | |
| | | <div class="mb-16px"> |
| | | <div class="text-14px font-600 text-[#171F26] mb-12px"> |
| | | <div class="text-14px text-[#171F26] mb-12px"> |
| | | 驾驶证: |
| | | </div> |
| | | <n-image |
| | |
| | | </div> |
| | | |
| | | <div> |
| | | <div class="text-14px font-600 text-[#171F26] mb-12px"> |
| | | <div class="text-14px text-[#171F26] mb-12px"> |
| | | 无犯罪记录证明: |
| | | </div> |
| | | <n-image |
| | |
| | | width: 12px; |
| | | height: 12px; |
| | | } |
| | | .text-13px { |
| | | font-size: 13px; |
| | | line-height: 18px; |
| | | color: #171F26; |
| | | } |
| | | .text-14px { |
| | | font-size: 14px; |
| | | line-height: 18px; |
| | | line-height: 20px; |
| | | font-weight: 500; |
| | | color: #171F26; |
| | | } |
| | | .line-bottom { |
| | |
| | | .head { |
| | | font-family: PingFang SC; |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | font-weight: 500; |
| | | line-height: 24px; |
| | | letter-spacing: normal; |
| | | color: #171F26; |
| | |
| | | { |
| | | title: '角色', |
| | | key: 'sysRoles', |
| | | width: 360, |
| | | width: 220, |
| | | resizable: true, |
| | | align: 'left', |
| | | ellipsis: true, |