|
@@ -0,0 +1,257 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <view class="px3 pb-3">
|
|
|
|
|
+ <!-- 月份切换:默认看当月,可往前翻历史月份 -->
|
|
|
|
|
+ <view class="d-flex a-center j-between bg-color-white p2 mt-2" style="border-radius: 16rpx">
|
|
|
|
|
+ <view class="month-btn" @tap="changeMonth(-1)">‹ 上一月</view>
|
|
|
|
|
+ <view class="f-size-32 f-weight-bold text-color-3">{{ monthLabel }}</view>
|
|
|
|
|
+ <view class="month-btn" @tap="changeMonth(1)">下一月 ›</view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 当月汇总 -->
|
|
|
|
|
+ <view class="p2 mt-2 bg-color-white" style="border-radius: 16rpx">
|
|
|
|
|
+ <view class="d-flex a-center">
|
|
|
|
|
+ <text class="f-size-28 text-color-3">本月已点检</text>
|
|
|
|
|
+ <text class="f-size-36 f-weight-bold count-text mx2">{{ calendar.finishDays || 0 }}</text>
|
|
|
|
|
+ <text class="f-size-28 text-color-3">天,共 {{ calendar.finishNum || 0 }} 项任务</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="f-size-26 text-color-6 mt-1">最后一次点检:{{ lastFinishText }}</view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 日历:已完成的日期标绿打勾 -->
|
|
|
|
|
+ <view class="p2 mt-2 bg-color-white" style="border-radius: 16rpx">
|
|
|
|
|
+ <view class="d-flex">
|
|
|
|
|
+ <view class="day-cell week-head" v-for="(week, index) in weeks" :key="'week' + index">{{ week }}</view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="d-flex f-wrap">
|
|
|
|
|
+ <view v-for="(cell, index) in cells" :key="index"
|
|
|
|
|
+ class="day-cell"
|
|
|
|
|
+ :class="{ 'day-checked': cell.checked, 'day-today': cell.today }"
|
|
|
|
|
+ @tap="handleDay(cell)">
|
|
|
|
|
+ <text v-if="!cell.blank" class="day-num">{{ cell.day }}</text>
|
|
|
|
|
+ <text v-if="cell.checked" class="day-mark">√</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="d-flex a-center mt-2 f-size-24 text-color-6">
|
|
|
|
|
+ <text class="legend legend-checked"></text>
|
|
|
|
|
+ <text class="ml-1">已点检</text>
|
|
|
|
|
+ <text class="legend legend-normal ml-3"></text>
|
|
|
|
|
+ <text class="ml-1">未点检</text>
|
|
|
|
|
+ <text class="legend legend-today ml-3"></text>
|
|
|
|
|
+ <text class="ml-1">今天</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <view class="f-size-24 text-color-9 mt-2">
|
|
|
|
|
+ 数据来源为本设备的保养(点检)任务,绿色打勾表示当天有已完成记录;点击任意日期可查看当天的任务名称、执行人与完成时间。
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <u-popup v-model="dayShow" mode="bottom" border-radius="20">
|
|
|
|
|
+ <view class="p3">
|
|
|
|
|
+ <view class="f-size-30 f-weight-bold text-center">{{ selectedDate }} 点检记录</view>
|
|
|
|
|
+ <view v-if="selectedJobs.length === 0" class="f-size-28 text-color-9 mt-3">该日无已完成记录</view>
|
|
|
|
|
+ <view v-for="(job, index) in selectedJobs" :key="index" class="job-item p2 mt-2">
|
|
|
|
|
+ <view class="f-size-28 text-color-3">{{ job.name || job.standardName || '保养任务' }}</view>
|
|
|
|
|
+ <view class="f-size-24 text-color-6 mt-1">
|
|
|
|
|
+ 执行人:{{ job.actualUser || job.checkUserName || job.checkDeptName || '-' }}
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="f-size-24 text-color-6 mt-1">完成时间:{{ job.actualEndTime || '-' }}</view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <u-button type="primary" @click="dayShow = false" style="margin-top: 20rpx">关闭</u-button>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </u-popup>
|
|
|
|
|
+ </view>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script>
|
|
|
|
|
+export default {
|
|
|
|
|
+ data() {
|
|
|
|
|
+ return {
|
|
|
|
|
+ sbId: '',
|
|
|
|
|
+ // 设备详情页带过来的“上次保养完成时间”,当月无记录时兜底展示
|
|
|
|
|
+ deviceLastFinish: '',
|
|
|
|
|
+ month: '',
|
|
|
|
|
+ weeks: ['日', '一', '二', '三', '四', '五', '六'],
|
|
|
|
|
+ cells: [],
|
|
|
|
|
+ calendar: {},
|
|
|
|
|
+ dayShow: false,
|
|
|
|
|
+ selectedDate: '',
|
|
|
|
|
+ selectedJobs: []
|
|
|
|
|
+ };
|
|
|
|
|
+ },
|
|
|
|
|
+ computed: {
|
|
|
|
|
+ monthLabel() {
|
|
|
|
|
+ if (!this.month) {
|
|
|
|
|
+ return '';
|
|
|
|
|
+ }
|
|
|
|
|
+ const parts = this.month.split('-');
|
|
|
|
|
+ return parts[0] + '年' + Number(parts[1]) + '月';
|
|
|
|
|
+ },
|
|
|
|
|
+ lastFinishText() {
|
|
|
|
|
+ // 优先显示当月最后一次完成时间,当月没做过则显示设备上的历史最近时间
|
|
|
|
|
+ return this.calendar.lastFinishTime || this.deviceLastFinish || '暂无';
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ onLoad(options) {
|
|
|
|
|
+ this.sbId = options.sbId || options.detailId;
|
|
|
|
|
+ this.deviceLastFinish = options.last ? decodeURIComponent(options.last) : '';
|
|
|
|
|
+ this.month = this.currentMonth();
|
|
|
|
|
+ this.loadData();
|
|
|
|
|
+ },
|
|
|
|
|
+ methods: {
|
|
|
|
|
+ pad(value) {
|
|
|
|
|
+ return value < 10 ? '0' + value : '' + value;
|
|
|
|
|
+ },
|
|
|
|
|
+ currentMonth() {
|
|
|
|
|
+ const now = new Date();
|
|
|
|
|
+ return now.getFullYear() + '-' + this.pad(now.getMonth() + 1);
|
|
|
|
|
+ },
|
|
|
|
|
+ changeMonth(offset) {
|
|
|
|
|
+ const parts = this.month.split('-');
|
|
|
|
|
+ const target = new Date(Number(parts[0]), Number(parts[1]) - 1 + offset, 1);
|
|
|
|
|
+ const now = new Date();
|
|
|
|
|
+ // 未来月份没有意义,直接拦掉,避免现场误判为“漏保养”
|
|
|
|
|
+ if (
|
|
|
|
|
+ target.getFullYear() > now.getFullYear() ||
|
|
|
|
|
+ (target.getFullYear() === now.getFullYear() && target.getMonth() + 1 > now.getMonth() + 1)
|
|
|
|
|
+ ) {
|
|
|
|
|
+ uni.showToast({ title: '暂不支持查看未来月份', icon: 'none' });
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ this.month = target.getFullYear() + '-' + this.pad(target.getMonth() + 1);
|
|
|
|
|
+ this.loadData();
|
|
|
|
|
+ },
|
|
|
|
|
+ loadData() {
|
|
|
|
|
+ this.$Http
|
|
|
|
|
+ .getSbCheckCalendarIgnores({
|
|
|
|
|
+ sbId: this.sbId,
|
|
|
|
|
+ month: this.month
|
|
|
|
|
+ })
|
|
|
|
|
+ .then((res) => {
|
|
|
|
|
+ this.calendar = res.data || {};
|
|
|
|
|
+ this.buildCells(res.data && res.data.dayList);
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ // 按月历格子生成:前置空格对齐星期,末尾补空格凑满整行
|
|
|
|
|
+ buildCells(dayList) {
|
|
|
|
|
+ const parts = this.month.split('-');
|
|
|
|
|
+ const year = Number(parts[0]);
|
|
|
|
|
+ const month = Number(parts[1]);
|
|
|
|
|
+ const finishedMap = {};
|
|
|
|
|
+ (dayList || []).forEach((item) => {
|
|
|
|
|
+ finishedMap[item.date] = item;
|
|
|
|
|
+ });
|
|
|
|
|
+ const todayStr = this.formatDate(new Date());
|
|
|
|
|
+ const cells = [];
|
|
|
|
|
+ const firstWeekday = new Date(year, month - 1, 1).getDay();
|
|
|
|
|
+ for (let i = 0; i < firstWeekday; i++) {
|
|
|
|
|
+ cells.push({ blank: true });
|
|
|
|
|
+ }
|
|
|
|
|
+ const daysOfMonth = new Date(year, month, 0).getDate();
|
|
|
|
|
+ for (let day = 1; day <= daysOfMonth; day++) {
|
|
|
|
|
+ const date = year + '-' + this.pad(month) + '-' + this.pad(day);
|
|
|
|
|
+ const finished = finishedMap[date];
|
|
|
|
|
+ cells.push({
|
|
|
|
|
+ blank: false,
|
|
|
|
|
+ date: date,
|
|
|
|
|
+ day: day,
|
|
|
|
|
+ checked: !!finished,
|
|
|
|
|
+ today: date === todayStr,
|
|
|
|
|
+ jobList: finished ? finished.jobList : []
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ while (cells.length % 7 !== 0) {
|
|
|
|
|
+ cells.push({ blank: true });
|
|
|
|
|
+ }
|
|
|
|
|
+ this.cells = cells;
|
|
|
|
|
+ },
|
|
|
|
|
+ formatDate(date) {
|
|
|
|
|
+ return date.getFullYear() + '-' + this.pad(date.getMonth() + 1) + '-' + this.pad(date.getDate());
|
|
|
|
|
+ },
|
|
|
|
|
+ handleDay(cell) {
|
|
|
|
|
+ if (cell.blank) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ this.selectedDate = cell.date;
|
|
|
|
|
+ this.selectedJobs = cell.jobList || [];
|
|
|
|
|
+ this.dayShow = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style lang="less">
|
|
|
|
|
+.month-btn {
|
|
|
|
|
+ font-size: 26rpx;
|
|
|
|
|
+ color: #0f6fb9;
|
|
|
|
|
+ padding: 6rpx 16rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.count-text {
|
|
|
|
|
+ color: #19be6b;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.day-cell {
|
|
|
|
|
+ width: 14.2857%;
|
|
|
|
|
+ height: 92rpx;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ font-size: 26rpx;
|
|
|
|
|
+ color: #333333;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.week-head {
|
|
|
|
|
+ height: 50rpx;
|
|
|
|
|
+ font-size: 24rpx;
|
|
|
|
|
+ color: #999999;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.day-num {
|
|
|
|
|
+ line-height: 34rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.day-mark {
|
|
|
|
|
+ font-size: 22rpx;
|
|
|
|
|
+ line-height: 24rpx;
|
|
|
|
|
+ color: #ffffff;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 已点检:绿底白字打勾 */
|
|
|
|
|
+.day-checked {
|
|
|
|
|
+ background-color: #19be6b;
|
|
|
|
|
+ border-radius: 10rpx;
|
|
|
|
|
+ color: #ffffff;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.day-today {
|
|
|
|
|
+ border: 2rpx solid #0f6fb9;
|
|
|
|
|
+ border-radius: 10rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.legend {
|
|
|
|
|
+ display: inline-block;
|
|
|
|
|
+ width: 24rpx;
|
|
|
|
|
+ height: 24rpx;
|
|
|
|
|
+ border-radius: 6rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.legend-checked {
|
|
|
|
|
+ background-color: #19be6b;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.legend-normal {
|
|
|
|
|
+ background-color: #f2f3f5;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.legend-today {
|
|
|
|
|
+ background-color: #ffffff;
|
|
|
|
|
+ border: 2rpx solid #0f6fb9;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.job-item {
|
|
|
|
|
+ background-color: #f7f8fa;
|
|
|
|
|
+ border-radius: 12rpx;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|