请假 巡检
Some checks failed
Uniapp 自动化打包 CI/CD / 打包 Uniapp 项目 (push) Has been cancelled

This commit is contained in:
2025-09-12 09:24:59 +08:00
parent 9ed827a227
commit 57fe929080
14 changed files with 973 additions and 499 deletions

View File

@@ -0,0 +1,420 @@
<template>
<view class="page-container">
<!-- 表单区域 -->
<view class="form-section">
<view class="form-item">
<text class="form-label">补卡时间</text>
<picker mode="date" :value="form.date" @change="onDateChange">
<view class="picker">{{ form.date }} {{ form.time }}</view>
</picker>
</view>
<view class="tip-text">
<text>本月已补卡{{ usedTimes }}剩余{{ remainTimes }}</text>
</view>
<view class="form-item">
<text class="form-label">补卡说明</text>
<textarea v-model="form.remark" placeholder="请输入" class="textarea" />
</view>
<view class="form-item">
<text class="form-label">附件</text>
<!-- 如果没有图片显示上传按钮 -->
<view class="custom-upload-btn" @click="chooseImage" v-if="!selectedImage">
<image class="image" src="/static/ic_camera.png"></image>
<text class="text">上传图片</text>
</view>
<!-- 已选图片预览 -->
<view class="preview-item" v-else>
<image class="preview-img" :src="selectedImage" mode="aspectFill" @click="previewImage"></image>
<view class="delete-btn" @click.stop="deletePic"></view>
</view>
</view>
</view>
<!-- 审批记录 -->
<view class="record-section">
<text class="section-title">审批记录</text>
<view class="timeline">
<view v-for="(item, index) in records" :key="index" class="timeline-item">
<!-- -->
<view class="timeline-dot"></view>
<!-- 节点内容 -->
<view class="timeline-content">
<text class="end-text">{{ item.node }}</text>
<view class="record-row" v-if="item.status !== '结束'">
<image class="avatar" :src="item.avatar" mode="aspectFill" />
<view class="name-node-container">
<text class="name">{{ item.name }}</text>
<text class="status" :class="statusClass(item.status)">{{ item.status }}</text>
</view>
<text class="time2">{{ item.time }}</text>
</view>
<text v-else class="time">{{ item.time }}</text>
</view>
</view>
</view>
</view>
<!-- 提交按钮 -->
<view class="footer">
<button class="submit-btn" type="primary" @click="submit">提交</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
usedTimes: 0,
remainTimes: 5,
selectedImage: '',
form: {
date: '2025-07-13',
time: '09:00',
remark: ''
},
records: [{
node: '提交',
name: '于永乐',
status: '已提交',
time: '07-12 18:28:22',
avatar: '/static/avatar1.png'
},
{
node: '审批',
name: '张桂花',
status: '已同意',
time: '07-12 18:30:12',
avatar: '/static/avatar2.png'
},
{
node: '审批',
name: '张桂花',
status: '已拒绝',
time: '07-12 19:12:45',
avatar: '/static/avatar2.png'
},
{
node: '结束',
name: '',
status: '结束',
time: '07-12 20:00:00',
avatar: ''
}
]
}
},
methods: {
onDateChange(e) {
this.form.date = e.detail.value
},
chooseImage() {
uni.chooseImage({
count: 1,
success: (res) => {
this.selectedImage = res.tempFilePaths[0]
}
})
},
// 预览图片
previewImage() {
uni.previewImage({
current: this.selectedImage,
urls: [this.selectedImage]
})
},
// 删除图片
deletePic(event) {
this.selectedImage = ''
},
submit() {
uni.showToast({
title: '提交成功',
icon: 'success'
})
},
statusClass(status) {
if (status === '已提交') return 'blue'
if (status === '已同意') return 'green'
if (status === '已拒绝') return 'orange'
if (status === '结束') return 'gray'
return ''
}
}
}
</script>
<style scoped>
.page-container {
background: #f5f5f5;
min-height: 100vh;
display: flex;
flex-direction: column;
}
.form-section {
background: #fff;
margin: 20rpx;
padding: 20rpx;
border-radius: 12rpx;
}
.form-item {
margin-bottom: 20rpx;
}
.form-label {
font-size: 24rpx;
color: #737373;
margin-bottom: 10rpx;
display: block;
}
.tip-text {
height: 73rpx;
line-height: 73rpx;
background: #F7F7F7;
color: #808080;
font-size: 24rpx;
border-radius: 10rpx;
padding-left: 16rpx;
}
.textarea {
width: 100%;
height: 160rpx;
border: 2rpx solid #ddd;
border-radius: 8rpx;
padding: 12rpx;
font-size: 24rpx;
}
.upload-box {
border: 2rpx dashed #aaa;
border-radius: 12rpx;
padding: 40rpx;
text-align: center;
color: #888;
}
.upload-icon {
width: 60rpx;
height: 60rpx;
margin-bottom: 12rpx;
}
/* 审批记录 */
.record-section {
background: #fff;
border-radius: 25rpx;
margin-left: 32rpx;
margin-right: 32rpx;
padding: 35rpx 25rpx 35rpx 25rpx;
}
.section-title {
font-size: 30rpx;
font-weight: bold;
margin-bottom: 20rpx;
color: #333;
}
/* timeline 方法二:每个节点自己画线 */
.timeline {
position: relative;
margin-left: 12rpx;
margin-top: 45rpx;
}
.timeline-item {
position: relative;
padding-left: 40rpx;
padding-bottom: 50rpx;
}
.timeline-item::before {
content: "";
position: absolute;
top: 0;
bottom: 0;
left: -2rpx;
width: 2rpx;
background: #ddd;
}
/* 第一个节点:去掉上半段 */
.timeline-item:first-child::before {
top: 20rpx;
}
/* 最后一个节点:去掉下半段 */
.timeline-item:last-child::before {
bottom: auto;
height: 20rpx;
}
/* 状态点 */
.timeline-dot {
position: absolute;
left: -12rpx;
top: 10rpx;
width: 20rpx;
height: 20rpx;
border: 1rpx solid #10AF7F;
border-radius: 50%;
background: #fff;
}
.timeline-content {
margin-left: -20rpx;
}
.record-row {
display: flex;
align-items: center;
margin-bottom: 8rpx;
}
.avatar {
width: 54rpx;
height: 54rpx;
border-radius: 50%;
margin-right: 15rpx;
background: #688CFF;
}
.name-node-container {
display: flex;
flex-direction: column;
align-items: flex-start;
}
.name {
font-size: 28rpx;
color: #000;
}
.status {
font-size: 22rpx;
font-weight: 500;
}
.status.blue {
color: #007aff;
}
.status.green {
color: #4caf50;
}
.status.orange {
color: #ff6b35;
}
.status.gray {
color: #999;
}
.end-text {
font-size: 24rpx;
color: #000;
font-weight: bold;
}
.time {
font-size: 24rpx;
color: #626262;
float: right;
margin-right: 40rpx;
}
.time2 {
font-size: 24rpx;
color: #626262;
position: absolute;
right: 40rpx;
bottom: 70rpx;
}
.footer {
padding: 20rpx;
}
.submit-btn {
width: 100%;
height: 90rpx;
line-height: 90rpx;
border-radius: 50rpx;
background: #007aff;
color: #fff;
font-size: 32rpx;
}
.text {
color: #000000;
font-size: 24rpx;
margin-left: 10rpx;
font-weight: 400;
}
.image {
width: 55rpx;
height: 42rpx;
}
.custom-upload-btn {
width: auto;
margin-left: 0rpx;
margin-right: 0rpx;
margin-top: 24rpx;
height: 244rpx;
background: #f6f6f6;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: 16rpx;
}
.preview-item {
position: relative;
width: auto;
/* 宽度自动 */
margin-left: 40rpx;
margin-right: 40rpx;
height: 244rpx;
margin-top: 24rpx;
/* 固定高度 */
display: flex;
justify-content: center;
/* 水平居中 */
align-items: center;
/* 垂直居中 */
overflow: hidden;
/* 裁剪超出部分 */
border-radius: 10rpx;
/* 可选:圆角 */
}
.delete-btn {
position: absolute;
top: 0;
right: 0;
width: 40rpx;
height: 40rpx;
line-height: 40rpx;
text-align: center;
border-radius: 50%;
background: rgba(0, 0, 0, 0.6);
color: #fff;
font-size: 24rpx;
}
</style>

View File

@@ -1,18 +1,6 @@
<template>
<view class="my-record-container">
<!-- 月份标题和切换 -->
<view class="month-header">
<view class="month-nav">
<view class="month-arrow" @click="prevMonth">
<image class="arrow-icon" src="/static/ic_arrow_gray.webp" mode="aspectFit" style="transform: rotate(180deg)" />
</view>
<text class="month-title">{{ currentYear }}{{ currentMonth }}</text>
<view class="month-arrow" @click="nextMonth">
<image class="arrow-icon" src="/static/ic_arrow_gray.webp" mode="aspectFit" />
</view>
</view>
</view>
<text class="month-title">{{ selectedDate.substring(0,4) }}{{ selectedDate.substring(5,7) }}</text>
<!-- 考勤统计 -->
<view class="attendance-stats">
@@ -36,248 +24,83 @@
<!-- 日历 -->
<view class="calendar">
<view class="weekdays">
<text v-for="day in weekdays" :key="day" class="weekday">{{ day }}</text>
</view>
<view class="dates" v-if="calendarExpanded">
<view
v-for="(date, index) in allDates"
:key="index"
:class="getDateClass(date)"
@click="selectDate(date)"
>
<text v-if="date.value" class="date-text">{{ date.value }}</text>
<view v-if="date.hasRecord" class="record-dot"></view>
</view>
</view>
<view class="dates" v-else>
<view
v-for="(date, index) in currentWeekDates"
:key="index"
:class="getDateClass(date)"
@click="selectDate(date)"
>
<text v-if="date.value" class="date-text">{{ date.value }}</text>
<view v-if="date.hasRecord" class="record-dot"></view>
</view>
</view>
<CommonCalendar ref="calendarComponent" :initial-date="selectedDate" :allowWeekSwitch='true' :initialMode='mode' @dateChange="handleDateSelected" @modeChange="handleModeChange" />
<!-- 展开/收缩按钮 -->
<view class="calendar-toggle" @click="toggleCalendar">
<image v-if="calendarExpanded" class='image_zk' src="/static/ic_exp.png"></image>
<view class="calendar-toggle" @click="toggleCalendarMode">
<image v-if="mode == 'month'" class='image_zk' src="/static/ic_exp.png"></image>
<image v-else class='image_sq' src="/static/ic_sq.png"></image>
</view>
</view>
<!-- 固定班次 -->
<view class="fixed-shifts">
<text class="shifts-title">固定班次</text>
<view class="shift-item">
<view class="shift-time">
<view class="time-dot"></view>
<text class="time-text">应上班 09:00</text>
</view>
<view class="record leave-record">
<text class="record-text">已请假 09:0012:00</text>
</view>
</view>
<view class="shift-item">
<view class="shift-time">
<view class="time-dot"></view>
<text class="time-text">应下班 18:00</text>
</view>
<view class="record clock-record">
<text class="record-text">已打卡 18:02:18</text>
<text class="location">@某综合服务中心1栋</text>
</view>
</view>
</view>
<!-- 固定班次 -->
<view class="fixed-shifts">
<text class="shifts-title">固定班次</text>
<PunchInfo/>
<PunchInfo/>
</view>
</view>
</template>
<script>
import CommonCalendar from '@/components/CommonCalendar.vue'
import PunchInfo from '@/components/punchInfo.vue'
export default {
components: {
CommonCalendar,
PunchInfo
},
data() {
return {
weekdays: ['日', '一', '二', '三', '四', '五', '六'],
calendarExpanded: true,
selectedDate: 8,
currentYear: 2025,
currentMonth: 7,
allDates: [],
prevMonthDates: [],
nextMonthDates: [],
swiperCurrent: 1,
touchStartX: 0,
touchStartY: 0
selectedDate: this.getCurrentDate(), // 默认选中的日期
mode: 'month'
};
},
created() {
this.generateCalendarDates();
},
computed: {
currentWeekDates() {
const selectedIndex = this.allDates.findIndex(date => date.selected);
if (selectedIndex === -1) return this.allDates.slice(0, 7);
const startOfWeek = Math.floor(selectedIndex / 7) * 7;
return this.allDates.slice(startOfWeek, startOfWeek + 7);
}
},
methods: {
toggleCalendar() {
this.calendarExpanded = !this.calendarExpanded;
},
selectDate(date) {
if (!date.value) return;
this.allDates.forEach(d => d.selected = false);
date.selected = true;
this.selectedDate = date.value;
},
getDateClass(date) {
return {
'date-item': true,
'selected': date.selected,
'has-record': date.hasRecord,
'empty': !date.value
};
},
prevMonth() {
if (this.currentMonth === 1) {
this.currentYear--;
this.currentMonth = 12;
} else {
this.currentMonth--;
}
this.generateCalendarDates();
},
nextMonth() {
if (this.currentMonth === 12) {
this.currentYear++;
this.currentMonth = 1;
} else {
this.currentMonth++;
}
this.generateCalendarDates();
},
generateCalendarDates() {
this.allDates = this.buildMonthDates(this.currentYear, this.currentMonth);
let prevY = this.currentYear, prevM = this.currentMonth - 1;
if (prevM === 0) { prevM = 12; prevY--; }
this.prevMonthDates = this.buildMonthDates(prevY, prevM);
let nextY = this.currentYear, nextM = this.currentMonth + 1;
if (nextM === 13) { nextM = 1; nextY++; }
this.nextMonthDates = this.buildMonthDates(nextY, nextM);
},
buildMonthDates(year, month) {
const firstDay = new Date(year, month - 1, 1).getDay();
const daysInMonth = new Date(year, month, 0).getDate();
let dates = [];
for (let i = 0; i < firstDay; i++) dates.push({ value: null });
for (let i = 1; i <= daysInMonth; i++) {
dates.push({ value: i, hasRecord: i <= 20, selected: i === this.selectedDate });
}
const remaining = 7 - (dates.length % 7);
if (remaining < 7) for (let i = 0; i < remaining; i++) dates.push({ value: null });
return dates;
},
isInCurrentWeek(date) {
if (!date.value) return false;
const index = this.allDates.findIndex(d => d.value === this.selectedDate);
if (index === -1) return false;
const start = Math.floor(index / 7) * 7;
const week = this.allDates.slice(start, start + 7);
return week.includes(date);
},
onTouchStart(e) {
this.touchStartX = e.changedTouches[0].clientX;
this.touchStartY = e.changedTouches[0].clientY;
},
onTouchEnd(e) {
const endX = e.changedTouches[0].clientX;
const endY = e.changedTouches[0].clientY;
const deltaX = endX - this.touchStartX;
const deltaY = endY - this.touchStartY;
// 上下滑切换月/周视图
if (Math.abs(deltaY) > Math.abs(deltaX)) {
if (deltaY < -50 && this.calendarExpanded) this.calendarExpanded = false;
else if (deltaY > 50 && !this.calendarExpanded) this.calendarExpanded = true;
}
},
onSwiperChange(e) {
const current = e.detail.current;
if (current === 0) { this.prevMonth(); this.swiperCurrent = 1; }
else if (current === 2) { this.nextMonth(); this.swiperCurrent = 1; }
}
// 获取当前日期
getCurrentDate() {
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, '0');
const day = String(today.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
},
// 处理日期选择
handleDateSelected(date) {
this.selectedDate = date;
},
// 处理日历模式变化
handleModeChange(mode) {
this.mode = mode;
},
// 切换日历模式
toggleCalendarMode() {
// 调用日历组件的toggleMode方法
if (this.$refs.calendarComponent) {
this.$refs.calendarComponent.toggleMode();
}
}
}
};
</script>
<style scoped>
.my-record-container {
display: flex;
flex-direction: column;
min-height: 100vh;
background-color: #fff;
}
/* 顶部导航栏 */
.header {
display: flex;
align-items: center;
padding: 20rpx 30rpx;
background-color: #fff;
position: relative;
}
.back-btn {
width: 40rpx;
height: 40rpx;
margin-right: 20rpx;
}
.page-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
position: absolute;
left: 50%;
transform: translateX(-50%);
}
/* 月份标题和导航 */
.month-header {
padding: 20rpx 30rpx;
margin-left: 180rpx;
margin-right: 180rpx;
background-color: #fff;
}
.month-nav {
display: flex;
align-items: center;
justify-content: space-between;
}
.month-arrow {
width: 40rpx;
height: 40rpx;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.arrow-icon {
width: 32rpx;
height: 32rpx;
}
.month-title {
font-size: 32rpx;
font-weight: bold;
font-size: 28rpx;
font-weight: 600;
margin-left: 35rpx;
color: #333;
}
@@ -286,7 +109,7 @@ export default {
display: flex;
justify-content: space-around;
padding: 40rpx 30rpx;
margin: 20rpx 30rpx;
margin: 28rpx 30rpx 15rpx 30rpx;
background-color: #f7f7f7;
border-radius: 10rpx;
@@ -315,90 +138,28 @@ export default {
}
/* 日历样式 */
.calendar { overflow: hidden; margin-left: 20rpx; margin-right: 20rpx}
.weekdays { display: flex; padding: 20rpx 0; }
.weekday { flex: 1; text-align: center; font-size: 28rpx; color: #666; }
.dates { display: flex; flex-wrap: wrap; padding: 20rpx 0; }
.date-item { width: 14.28%; height: 70rpx; display: flex; align-items: center; justify-content: center; position: relative; margin-bottom: 20rpx; }
.date-item.empty { color: #ccc; }
.date-item.selected { background-color: #007aff; border-radius: 50%; width: 60rpx; height: 60rpx; margin: 10rpx auto; }
.date-item.selected .date-text { color: #fff; }
.date-text { font-size: 28rpx; color: #333; }
.record-dot { position: absolute; bottom: 8rpx; left: 50%; transform: translateX(-50%); width: 8rpx; height: 8rpx; background-color: #007aff; border-radius: 50%; }
.date-item.selected .record-dot { background-color: #fff; }
.calendar { overflow: hidden; margin-left: 10rpx; margin-right: 10rpx}
.calendar-toggle { text-align: center; background-color: #fff; margin-top: -30rpx;}
.calendar-toggle { text-align: center; background-color: #fff;}
.image_sq { width: 37rpx; height: 6rpx; }
.image_zk { width: 52rpx; height: 19rpx; }
/* 固定班次 */
.fixed-shifts {
margin: 20rpx 30rpx;
flex: 1;
background-color: #f5f5f5;
border-radius: 16rpx;
padding: 30rpx;
overflow: auto;
}
.shifts-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
font-size: 28rpx;
color: #737373;
margin-bottom: 30rpx;
}
.shift-item {
margin-bottom: 40rpx;
}
.shift-item:last-child {
margin-bottom: 0;
}
.shift-time {
margin-top: 7rpx;
display: flex;
align-items: center;
margin-bottom: 20rpx;
justify-content: center;
}
.time-dot {
width: 12rpx;
height: 12rpx;
background-color: #ff6b35;
border-radius: 50%;
margin-right: 16rpx;
}
.time-text {
font-size: 28rpx;
color: #333;
}
.record {
border: 2rpx dashed #e0e0e0;
border-radius: 12rpx;
padding: 24rpx;
margin-left: 28rpx;
}
.leave-record {
background-color: #fff7f0;
border-color: #ffb366;
}
.clock-record {
background-color: #f0f9ff;
border-color: #66b3ff;
}
.record-text {
font-size: 28rpx;
color: #333;
margin-bottom: 8rpx;
}
.location {
font-size: 24rpx;
color: #007aff;
display: block;
}
</style>

View File

@@ -34,7 +34,7 @@
<image class="ins-line-image" src="/static/ic_my_repair_03.png" />
<view class="ins-info">巡检人{{ item.actUserName || '' }}</view>
<view class="ins-info">计划完成时间{{ item.planInsTime || '' }}</view>
<view class="ins-info">实际完成时间{{ item.location || '' }}</view>
<view class="ins-info">实际完成时间{{ item.compleTime || '' }}</view>
<view class="ins-info">巡检进度{{ item.inspectionProgress || '' }}</view>
</view>

View File

@@ -56,13 +56,13 @@
</view>
<!-- 操作区宽度跟随标题块内部居中 -->
<view class="ops" v-if="item.inspectionState ==0">
<view class="ops" v-if="item.inspectionState == 0">
<view class="btn-outline" @click="startTask(item)">立即巡检</view>
</view>
<view class="status" v-else v-if="item.inspectionResults == 1" @click="goDetail(item)">
<view class="status" v-else-if="item.inspectionResults == 1" @click="goDetail(item)">
<view>完成巡检</view>
<view class="badge" :class="item.inspectionResults ==1 ? 'badge-success' : 'badge-warn'">
<view class="badge" :class="item.inspectionResults == 1 ? 'badge-success' : 'badge-warn'">
{{ item.inspectionResults == 1 ? '正常' : '异常' }}
</view>
</view>

View File

@@ -20,23 +20,23 @@
<!-- 请假类型 -->
<view class="form-row">
<text class="label required">请假类型</text>
<view class="picker" @click="openLeaveTypePopup">
<text
:class="leaveTypeIndex === 0 ? 'placeholder' : ''">{{ leaveTypes[leaveTypeIndex] || '请选择' }}</text>
<image class="right-arrow" src="/static/ic_right_arrow_g.png" />
<text class="label required">请假类型</text>
<view class="picker" @click="openLeaveTypePopup">
<text
:class="leaveTypeIndex === 0 ? 'placeholder' : ''">{{ leaveTypes[leaveTypeIndex] || '请选择' }}</text>
<image class="right-arrow" src="/static/ic_right_arrow_g.png" />
</view>
</view>
<!-- 开始时间 -->
<view class="form-row">
<text class="label required">开始时间</text>
<picker mode="date" @change="startDateChange">
<view class="picker">
<!-- <picker mode="date" @change="startDateChange"> -->
<view class="picker" @click="startDateSelect">
<text :class="!startDate ? 'placeholder' : ''">{{ startDate || '请选择' }}</text>
<image class="right-arrow" src="/static/ic_right_arrow_g.png" />
</view>
</picker>
<!-- </picker> -->
</view>
<!-- 结束时间 -->
@@ -63,8 +63,8 @@
</view>
<!-- 上传图片 -->
<u-upload class="upload-style" :fileList="selectedImages" @on-list-change="onListChange" @delete="deletePic" name="upload"
multiple maxCount="3" width="180" height="180" :autoUpload="false"></u-upload>
<u-upload class="upload-style" :fileList="selectedImages" @on-list-change="onListChange" @delete="deletePic"
name="upload" multiple maxCount="3" width="180" height="180" :autoUpload="false"></u-upload>
<!-- 提交按钮 -->
<button class="submit-btn" @click="submitLeave">提交</button>
@@ -113,13 +113,8 @@
<view class="popup-content">
<view class="popup-title">请假类型</view>
<view class="popup-options">
<view
v-for="(type, index) in leaveTypes"
:key="index"
class="popup-option"
:class="{ 'selected': leaveTypeIndex === index }"
@click="selectLeaveType(index)"
>
<view v-for="(type, index) in leaveTypes" :key="index" class="popup-option"
:class="{ selected: leaveTypeIndex === index }" @click="selectLeaveType(index)">
{{ type }}
</view>
</view>
@@ -127,127 +122,133 @@
</view>
</u-popup>
<SelectCalendarDialog :visible.sync="showCalendarDialog" @confirm="onConfirm" />
</view>
</template>
<script>
export default {
data() {
return {
tabs: ['发起申请', '请假记录', '已完成'],
activeTab: 0,
leaveTypes: ['事假', '调休', '病假', '年假', '产假', '陪产假', '婚假', '例假', '丧假', '哺乳假', '其他'],
leaveTypeIndex: -1, // 初始化为-1表示未选择
startDate: '',
endDate: '',
hours: '',
reason: '',
selectedImages: [],
leaveRecords: [],
loading: false,
hasMore: true,
refreshing: false,
pageNum: 1,
pageSize: 10,
showLeaveTypePopup: false,
}
},
methods: {
changeTab(idx) {
this.activeTab = idx;
},
bindPickerChange(e) {
this.leaveTypeIndex = e.detail.value;
},
startDateChange(e) {
this.startDate = e.detail.value;
},
endDateChange(e) {
this.endDate = e.detail.value;
},
submitLeave() {
// 提交请假逻辑
},
deletePic(event) {
this.selectedImages.splice(event.index, 1);
},
onListChange(list) {
this.selectedImages = list;
},
goToDetail(item) {
// 跳转到详情页逻辑
},
async onRefresh() {
this.refreshing = true;
this.pageNum = 1;
await this.loadLeaveRecords();
this.refreshing = false;
},
async onLoadMore() {
if (!this.hasMore || this.loading) return;
this.pageNum++;
await this.loadLeaveRecords();
},
async loadLeaveRecords() {
this.loading = true;
let data = [
{
type: '请假',
leaveType: '病假',
status: '已通过',
statusClass: 'green',
startTime: '2025-07-13',
endTime: '2025-07-15',
userName: '余永乐',
avatarText: '余',
avatarColor: '#4B7BF5',
dateTime: '07-12 18:28:22'
},
{
type: '请假',
leaveType: '病假',
status: '待审核',
statusClass: 'orange',
startTime: '2025-07-13',
endTime: '2025-07-15',
userName: '余永乐',
avatarText: '余',
avatarColor: '#4B7BF5',
dateTime: '07-12 18:28:22'
}
];
const start = (this.pageNum - 1) * this.pageSize;
const end = start + this.pageSize;
const pageData = data.slice(start, end);
await new Promise(res => setTimeout(res, 300));
if (this.pageNum === 1) {
this.leaveRecords = pageData;
} else {
this.leaveRecords = [...this.leaveRecords, ...pageData];
import SelectCalendarDialog from '@/components/SelectCalendarDialog.vue'
export default {
components: { SelectCalendarDialog },
data() {
return {
tabs: ['发起申请', '请假记录', '已完成'],
activeTab: 0,
leaveTypes: ['事假', '调休', '病假', '年假', '产假', '陪产假', '婚假', '例假', '丧假', '哺乳假', '其他'],
leaveTypeIndex: -1, // 初始化为-1表示未选择
startDate: '',
endDate: '',
hours: '',
reason: '',
selectedImages: [],
leaveRecords: [],
loading: false,
hasMore: true,
refreshing: false,
pageNum: 1,
pageSize: 10,
showLeaveTypePopup: false,
showCalendarDialog: false,
}
this.hasMore = end < data.length;
this.loading = false;
},
openLeaveTypePopup() {
this.showLeaveTypePopup = true;
},
selectLeaveType(index) {
this.leaveTypeIndex = index;
},
confirmLeaveType() {
if (this.leaveTypeIndex !== -1) {
this.showLeaveTypePopup = false;
// 更新表单中的请假类型
this.leaveType = this.leaveTypes[this.leaveTypeIndex];
} else {
uni.showToast({
title: '请选择请假类型',
icon: 'none'
});
methods: {
changeTab(idx) {
this.activeTab = idx;
},
bindPickerChange(e) {
this.leaveTypeIndex = e.detail.value;
},
startDateSelect() {
this.showCalendarDialog = true
},
onConfirm(selectedDate){
this.startDate = selectedDate
},
endDateChange(e) {
this.endDate = e.detail.value;
},
submitLeave() {
// 提交请假逻辑
},
deletePic(event) {
this.selectedImages.splice(event.index, 1);
},
onListChange(list) {
this.selectedImages = list;
},
goToDetail(item) {
// 跳转到详情页逻辑
},
async onRefresh() {
this.refreshing = true;
this.pageNum = 1;
await this.loadLeaveRecords();
this.refreshing = false;
},
async onLoadMore() {
if (!this.hasMore || this.loading) return;
this.pageNum++;
await this.loadLeaveRecords();
},
async loadLeaveRecords() {
this.loading = true;
let data = [{
type: '请假',
leaveType: '病假',
status: '已通过',
statusClass: 'green',
startTime: '2025-07-13',
endTime: '2025-07-15',
userName: '余永乐',
avatarText: '余',
avatarColor: '#4B7BF5',
dateTime: '07-12 18:28:22'
},
{
type: '请假',
leaveType: '病假',
status: '待审核',
statusClass: 'orange',
startTime: '2025-07-13',
endTime: '2025-07-15',
userName: '余永乐',
avatarText: '余',
avatarColor: '#4B7BF5',
dateTime: '07-12 18:28:22'
}
];
const start = (this.pageNum - 1) * this.pageSize;
const end = start + this.pageSize;
const pageData = data.slice(start, end);
await new Promise(res => setTimeout(res, 300));
if (this.pageNum === 1) {
this.leaveRecords = pageData;
} else {
this.leaveRecords = [...this.leaveRecords, ...pageData];
}
this.hasMore = end < data.length;
this.loading = false;
},
openLeaveTypePopup() {
this.showLeaveTypePopup = true;
},
selectLeaveType(index) {
this.leaveTypeIndex = index;
},
confirmLeaveType() {
if (this.leaveTypeIndex !== -1) {
this.showLeaveTypePopup = false;
// 更新表单中的请假类型
this.leaveType = this.leaveTypes[this.leaveTypeIndex];
} else {
uni.showToast({
title: '请选择请假类型',
icon: 'none'
});
}
}
}
}
}
</script>
<style scoped>
@@ -513,7 +514,8 @@ export default {
font-size: 28rpx;
color: #999;
}
.upload-style{
.upload-style {
margin-left: 15rpx;
margin-right: 15rpx;
}
@@ -548,22 +550,21 @@ export default {
}
.popup-options {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
display: grid;
grid-template-columns: repeat(3, 1fr);
/* 三列可改成2/4列 */
gap: 20rpx;
/* 行列间距 */
padding: 20rpx;
}
.popup-option {
width: 30%;
height: 80rpx;
background-color: #f7f7f7;
text-align: center;
padding: 20rpx 0;
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
background-color: #f5f5f5;
font-size: 28rpx;
color: #333;
margin-bottom: 20rpx;
}
.popup-option.selected {
@@ -580,4 +581,4 @@ export default {
color: #fff;
margin-top: 40rpx;
}
</style>
</style>

View File

@@ -74,11 +74,11 @@
text: '报事报修',
url:'/pages/sys/user/myRepair/myRepair'
},
// {
// icon: 'https://picsum.photos/80/80?random=3',
// text: '工作巡检',
// url:'/pages/sys/workbench/inspection/inspection'
// },
{
icon: 'https://picsum.photos/80/80?random=3',
text: '工作巡检',
url:'/pages/sys/workbench/inspection/inspection'
},
// {
// icon: 'https://picsum.photos/80/80?random=3',
// text: '通讯录',