|
|
|
@ -1,24 +1,24 @@ |
|
|
|
<template> |
|
|
|
<div class="task-page"> |
|
|
|
<!-- 顶部导航 --> |
|
|
|
<div class="nav-bar"> |
|
|
|
<!-- <div class="nav-bar"> |
|
|
|
<div class="nav-back" @click="onBack"> |
|
|
|
<van-icon name="arrow-left" size="20" color="#333" /> |
|
|
|
</div> |
|
|
|
<div class="nav-title">我的任务</div> |
|
|
|
<div class="nav-right"></div> |
|
|
|
</div> |
|
|
|
</div> --> |
|
|
|
|
|
|
|
<!-- 月份切换 --> |
|
|
|
<div class="month-switch"> |
|
|
|
<div class="month-arrow" @click="onPrevMonth"> |
|
|
|
<van-icon name="arrow-left" size="16" color="#2382cf" /> |
|
|
|
<van-icon name="arrow-left" size="16" color="#333333" /> |
|
|
|
</div> |
|
|
|
<div class="month-text" @click="showMonthPicker = true"> |
|
|
|
{{ currentYear }}年{{ currentMonth }}月 |
|
|
|
</div> |
|
|
|
<div class="month-arrow" @click="onNextMonth"> |
|
|
|
<van-icon name="arrow" size="16" color="#2382cf" /> |
|
|
|
<van-icon name="arrow" size="16" color="#333333" /> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
@ -28,17 +28,12 @@ |
|
|
|
<div class="week-cell" v-for="w in weekDays" :key="w">{{ w }}</div> |
|
|
|
</div> |
|
|
|
<div class="date-grid"> |
|
|
|
<div |
|
|
|
v-for="(cell, idx) in calendarCells" |
|
|
|
:key="idx" |
|
|
|
class="date-cell" |
|
|
|
:class="{ |
|
|
|
<div v-for="(cell, idx) in calendarCells" :key="idx" class="date-cell" :class="{ |
|
|
|
'other-month': !cell.isCurrentMonth, |
|
|
|
'is-today': cell.isToday, |
|
|
|
'is-selected': cell.isSelected, |
|
|
|
}" |
|
|
|
@click="onSelectDate(cell)" |
|
|
|
> |
|
|
|
'is-weekend': cell.isWeekend, |
|
|
|
}" @click="onSelectDate(cell)"> |
|
|
|
<span class="date-num">{{ cell.day }}</span> |
|
|
|
<span class="date-lunar">{{ cell.lunar }}</span> |
|
|
|
<span v-if="cell.hasDot && cell.isCurrentMonth" class="date-dot"></span> |
|
|
|
@ -60,12 +55,7 @@ |
|
|
|
<van-empty description="当天暂无任务" /> |
|
|
|
</div> |
|
|
|
<div v-else class="task-list"> |
|
|
|
<div |
|
|
|
v-for="item in taskList" |
|
|
|
:key="item.id" |
|
|
|
class="task-card" |
|
|
|
@click="onTaskClick(item)" |
|
|
|
> |
|
|
|
<div v-for="item in taskList" :key="item.id" class="task-card" @click="onTaskClick(item)"> |
|
|
|
<div class="task-time-col"> |
|
|
|
<div class="time-label">{{ getTimeLabel(item) }}</div> |
|
|
|
<div class="time-date">{{ getShortDate(item) }}</div> |
|
|
|
@ -91,7 +81,8 @@ |
|
|
|
</div> |
|
|
|
<div class="detail-row"> |
|
|
|
<div class="detail-label">执法人员:</div> |
|
|
|
<div class="detail-value">{{ formatUserInfo(item.enforceUserNames, item.enforceUserTels) }}</div> |
|
|
|
<div class="detail-value">{{ formatUserInfo(item.enforceUserNames, item.enforceUserTels) |
|
|
|
}}</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<!-- 联合执法关联计划 --> |
|
|
|
@ -107,7 +98,8 @@ |
|
|
|
</div> |
|
|
|
<div class="detail-row"> |
|
|
|
<div class="detail-label">执法人员:</div> |
|
|
|
<div class="detail-value">{{ formatUserInfo(ap.enforceUserNames, ap.enforceUserTels) }}</div> |
|
|
|
<div class="detail-value">{{ formatUserInfo(ap.enforceUserNames, ap.enforceUserTels) |
|
|
|
}}</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
@ -118,13 +110,8 @@ |
|
|
|
|
|
|
|
<!-- 月份选择弹窗 --> |
|
|
|
<van-popup v-model:show="showMonthPicker" position="bottom" round> |
|
|
|
<van-date-picker |
|
|
|
v-model="monthPickerValue" |
|
|
|
title="选择月份" |
|
|
|
:columns-type="['year', 'month']" |
|
|
|
@confirm="onMonthPickerConfirm" |
|
|
|
@cancel="showMonthPicker = false" |
|
|
|
/> |
|
|
|
<van-date-picker v-model="monthPickerValue" title="选择月份" :columns-type="['year', 'month']" |
|
|
|
@confirm="onMonthPickerConfirm" @cancel="showMonthPicker = false" /> |
|
|
|
</van-popup> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
@ -132,12 +119,13 @@ |
|
|
|
<script setup name="cpTaskMine"> |
|
|
|
import { useRouter, useRoute } from 'vue-router'; |
|
|
|
import { getMyTaskList, getMyTaskDates, getMyTaskAssociatedPlans } from '@/api/enforcement/task'; |
|
|
|
import { getLunarDay } from '@/util/lunar'; |
|
|
|
|
|
|
|
const router = useRouter(); |
|
|
|
const route = useRoute(); |
|
|
|
|
|
|
|
// ========== 日历相关 ========== |
|
|
|
const weekDays = ['日', '一', '二', '三', '四', '五', '六']; |
|
|
|
const weekDays = ['一', '二', '三', '四', '五', '六', '日']; |
|
|
|
const today = new Date(); |
|
|
|
|
|
|
|
// 从路由参数恢复年月日,若无则默认当天 |
|
|
|
@ -157,26 +145,14 @@ const monthPickerValue = ref([ |
|
|
|
String(today.getMonth() + 1).padStart(2, '0'), |
|
|
|
]); |
|
|
|
|
|
|
|
// 简易农历(仅用于展示,不做精确计算) |
|
|
|
const lunarDays = [ |
|
|
|
'', '初一', '初二', '初三', '初四', '初五', '初六', '初七', '初八', '初九', '初十', |
|
|
|
'十一', '十二', '十三', '十四', '十五', '十六', '十七', '十八', '十九', '二十', |
|
|
|
'廿一', '廿二', '廿三', '廿四', '廿五', '廿六', '廿七', '廿八', '廿九', '三十', |
|
|
|
]; |
|
|
|
|
|
|
|
const getLunarDay = (date) => { |
|
|
|
// 简化处理:使用日期的日数模拟农历显示 |
|
|
|
const d = date.getDate(); |
|
|
|
return lunarDays[d] || ''; |
|
|
|
}; |
|
|
|
|
|
|
|
// 生成日历单元格 |
|
|
|
const calendarCells = computed(() => { |
|
|
|
const year = currentYear.value; |
|
|
|
const month = currentMonth.value; |
|
|
|
const firstDay = new Date(year, month - 1, 1); |
|
|
|
const lastDay = new Date(year, month, 0); |
|
|
|
const startWeekDay = firstDay.getDay(); // 0=Sunday |
|
|
|
let startWeekDay = firstDay.getDay(); |
|
|
|
startWeekDay = (startWeekDay + 6) % 7; |
|
|
|
const totalDays = lastDay.getDate(); |
|
|
|
|
|
|
|
const cells = []; |
|
|
|
@ -186,6 +162,7 @@ const calendarCells = computed(() => { |
|
|
|
for (let i = startWeekDay - 1; i >= 0; i--) { |
|
|
|
const day = prevMonthLastDay - i; |
|
|
|
const d = new Date(year, month - 2, day); |
|
|
|
const weekDay = d.getDay(); |
|
|
|
cells.push({ |
|
|
|
day, |
|
|
|
date: d, |
|
|
|
@ -194,6 +171,7 @@ const calendarCells = computed(() => { |
|
|
|
isToday: false, |
|
|
|
isSelected: false, |
|
|
|
hasDot: false, |
|
|
|
isWeekend: weekDay === 0 || weekDay === 6, |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
@ -203,6 +181,7 @@ const calendarCells = computed(() => { |
|
|
|
const dateStr = formatDateStr(d); |
|
|
|
const isToday = dateStr === formatDateStr(today); |
|
|
|
const isSelected = dateStr === formatDateStr(selectedDate.value); |
|
|
|
const weekDay = d.getDay(); |
|
|
|
cells.push({ |
|
|
|
day, |
|
|
|
date: d, |
|
|
|
@ -211,6 +190,7 @@ const calendarCells = computed(() => { |
|
|
|
isToday, |
|
|
|
isSelected, |
|
|
|
hasDot: taskDatesSet.value.has(dateStr), |
|
|
|
isWeekend: weekDay === 0 || weekDay === 6, |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
@ -218,6 +198,7 @@ const calendarCells = computed(() => { |
|
|
|
const remaining = 42 - cells.length; |
|
|
|
for (let day = 1; day <= remaining; day++) { |
|
|
|
const d = new Date(year, month, day); |
|
|
|
const weekDay = d.getDay(); |
|
|
|
cells.push({ |
|
|
|
day, |
|
|
|
date: d, |
|
|
|
@ -226,6 +207,7 @@ const calendarCells = computed(() => { |
|
|
|
isToday: false, |
|
|
|
isSelected: false, |
|
|
|
hasDot: false, |
|
|
|
isWeekend: weekDay === 0 || weekDay === 6, |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
@ -436,8 +418,7 @@ onMounted(() => { |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
height: 100%; |
|
|
|
background: #f0f6ff; |
|
|
|
font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', sans-serif; |
|
|
|
background: #EBF4FB; |
|
|
|
} |
|
|
|
|
|
|
|
/* 导航栏 */ |
|
|
|
@ -453,11 +434,13 @@ onMounted(() => { |
|
|
|
width: 32px; |
|
|
|
cursor: pointer; |
|
|
|
} |
|
|
|
|
|
|
|
.nav-title { |
|
|
|
font-size: 18px; |
|
|
|
font-weight: 600; |
|
|
|
color: #1a1a2e; |
|
|
|
} |
|
|
|
|
|
|
|
.nav-right { |
|
|
|
width: 32px; |
|
|
|
} |
|
|
|
@ -466,12 +449,15 @@ onMounted(() => { |
|
|
|
/* 月份切换 */ |
|
|
|
.month-switch { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
gap: 20px; |
|
|
|
padding: 8px 0; |
|
|
|
// align-items: center; |
|
|
|
// justify-content: center; |
|
|
|
gap: 40px; |
|
|
|
margin: 8px 12px 0px 12px; |
|
|
|
padding: 8px; |
|
|
|
background: #fff; |
|
|
|
flex-shrink: 0; |
|
|
|
border-top-left-radius: 8px; |
|
|
|
border-top-right-radius: 8px; |
|
|
|
|
|
|
|
.month-arrow { |
|
|
|
width: 24px; |
|
|
|
@ -481,30 +467,36 @@ onMounted(() => { |
|
|
|
justify-content: center; |
|
|
|
cursor: pointer; |
|
|
|
} |
|
|
|
|
|
|
|
.month-text { |
|
|
|
font-size: 15px; |
|
|
|
font-weight: 600; |
|
|
|
color: #2382cf; |
|
|
|
font-size: 18px; |
|
|
|
font-weight: 700; |
|
|
|
color: #333; |
|
|
|
cursor: pointer; |
|
|
|
text-align: center; |
|
|
|
width: 600px; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* 日历 */ |
|
|
|
.calendar { |
|
|
|
background: #fff; |
|
|
|
padding: 0 8px 8px; |
|
|
|
padding: 0 12px 12px; |
|
|
|
flex-shrink: 0; |
|
|
|
margin: 0px 12px; |
|
|
|
border-bottom-left-radius: 8px; |
|
|
|
border-bottom-right-radius: 8px; |
|
|
|
} |
|
|
|
|
|
|
|
.week-header { |
|
|
|
display: grid; |
|
|
|
grid-template-columns: repeat(7, 1fr); |
|
|
|
text-align: center; |
|
|
|
padding: 4px 0; |
|
|
|
padding: 8px 0; |
|
|
|
|
|
|
|
.week-cell { |
|
|
|
font-size: 11px; |
|
|
|
color: #999; |
|
|
|
color: #333333; |
|
|
|
font-weight: 500; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -512,59 +504,87 @@ onMounted(() => { |
|
|
|
.date-grid { |
|
|
|
display: grid; |
|
|
|
grid-template-columns: repeat(7, 1fr); |
|
|
|
gap: 1px 0; |
|
|
|
gap: 4px 0; |
|
|
|
} |
|
|
|
|
|
|
|
.date-cell { |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
padding: 3px 0; |
|
|
|
min-height: 38px; |
|
|
|
// justify-content: center; |
|
|
|
padding: 4px 4px; |
|
|
|
cursor: pointer; |
|
|
|
position: relative; |
|
|
|
border-radius: 6px; |
|
|
|
transition: background 0.15s; |
|
|
|
border-radius: 50%; |
|
|
|
width: 47px; |
|
|
|
height: 47px; |
|
|
|
box-sizing: border-box; |
|
|
|
|
|
|
|
.date-num { |
|
|
|
font-size: 13px; |
|
|
|
font-size: 16px; |
|
|
|
font-weight: 600; |
|
|
|
color: #333; |
|
|
|
line-height: 1.3; |
|
|
|
color: #1D1F24; |
|
|
|
height: 19px; |
|
|
|
// line-height: 1.3; |
|
|
|
} |
|
|
|
|
|
|
|
.date-lunar { |
|
|
|
font-size: 9px; |
|
|
|
color: #999; |
|
|
|
line-height: 1.1; |
|
|
|
font-size: 10px; |
|
|
|
color: #666666; |
|
|
|
// line-height: 1.1; |
|
|
|
// margin-top: 2px; |
|
|
|
} |
|
|
|
|
|
|
|
.date-dot { |
|
|
|
width: 4px; |
|
|
|
height: 4px; |
|
|
|
width: 8px; |
|
|
|
height: 8px; |
|
|
|
border-radius: 50%; |
|
|
|
background: #2382cf; |
|
|
|
margin-top: 1px; |
|
|
|
background: #1978F8; |
|
|
|
margin-top: 2px; |
|
|
|
position: absolute; |
|
|
|
bottom: 2px; |
|
|
|
} |
|
|
|
|
|
|
|
&.other-month { |
|
|
|
.date-num { color: #ccc; } |
|
|
|
.date-lunar { color: #ddd; } |
|
|
|
.date-num { |
|
|
|
color: #ccc; |
|
|
|
} |
|
|
|
|
|
|
|
.date-lunar { |
|
|
|
color: #ddd; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&.is-today:not(.is-selected) { |
|
|
|
.date-num { |
|
|
|
color: #2382cf; |
|
|
|
color: #1978F8; |
|
|
|
font-weight: 700; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&.is-selected { |
|
|
|
background: #2382cf; |
|
|
|
.date-num { color: #fff; font-weight: 700; } |
|
|
|
.date-lunar { color: rgba(255,255,255,0.8); } |
|
|
|
.date-dot { background: #fff; } |
|
|
|
background: #1978F8; |
|
|
|
|
|
|
|
// width:47px; |
|
|
|
// height: 47px; |
|
|
|
.date-num { |
|
|
|
color: #fff; |
|
|
|
font-weight: 700; |
|
|
|
} |
|
|
|
|
|
|
|
.date-lunar { |
|
|
|
color: rgba(255, 255, 255, 0.8); |
|
|
|
} |
|
|
|
|
|
|
|
.date-dot { |
|
|
|
background: #fff; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&.is-weekend:not(.is-selected) { |
|
|
|
.date-num { |
|
|
|
color: #999999; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -572,13 +592,13 @@ onMounted(() => { |
|
|
|
.task-count { |
|
|
|
padding: 12px 16px 8px; |
|
|
|
font-size: 14px; |
|
|
|
color: #666; |
|
|
|
color: #999; |
|
|
|
flex-shrink: 0; |
|
|
|
|
|
|
|
.count-num { |
|
|
|
font-size: 18px; |
|
|
|
font-weight: 700; |
|
|
|
color: #2382cf; |
|
|
|
font-size: 14px; |
|
|
|
// font-weight: 700; |
|
|
|
color: #1367FE; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -616,9 +636,9 @@ onMounted(() => { |
|
|
|
padding-top: 10px; |
|
|
|
|
|
|
|
.time-label { |
|
|
|
font-size: 15px; |
|
|
|
font-size: 16px; |
|
|
|
font-weight: 700; |
|
|
|
color: #1a1a2e; |
|
|
|
color: #1D1F24; |
|
|
|
} |
|
|
|
|
|
|
|
.time-date { |
|
|
|
@ -632,41 +652,37 @@ onMounted(() => { |
|
|
|
flex: 1; |
|
|
|
min-width: 0; |
|
|
|
background: #fff; |
|
|
|
border-left: 3px solid #2382cf; |
|
|
|
border-radius: 10px; |
|
|
|
padding: 14px 16px; |
|
|
|
border-radius: 8px; |
|
|
|
padding: 12px; |
|
|
|
box-shadow: 0 2px 10px rgba(44, 116, 190, 0.07); |
|
|
|
} |
|
|
|
|
|
|
|
.task-title-row { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
gap: 6px; |
|
|
|
margin-bottom: 6px; |
|
|
|
} |
|
|
|
|
|
|
|
.task-title { |
|
|
|
font-size: 15px; |
|
|
|
font-size: 14px; |
|
|
|
font-weight: 700; |
|
|
|
color: #1a1a2e; |
|
|
|
color: #1D1F24; |
|
|
|
overflow: hidden; |
|
|
|
text-overflow: ellipsis; |
|
|
|
white-space: nowrap; |
|
|
|
flex: 1; |
|
|
|
} |
|
|
|
|
|
|
|
.union-badge { |
|
|
|
display: inline-flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
width: 22px; |
|
|
|
height: 22px; |
|
|
|
border-radius: 4px; |
|
|
|
background: #2382cf; |
|
|
|
text-align: center; |
|
|
|
line-height: 20px; |
|
|
|
width: 18px; |
|
|
|
height: 17px; |
|
|
|
border-radius: 2px; |
|
|
|
background: #1367FE; |
|
|
|
color: #fff; |
|
|
|
font-size: 12px; |
|
|
|
font-size: 10px; |
|
|
|
font-weight: 600; |
|
|
|
flex-shrink: 0; |
|
|
|
margin-left: 4px; |
|
|
|
box-sizing: border-box; |
|
|
|
} |
|
|
|
|
|
|
|
.task-time-info { |
|
|
|
@ -675,18 +691,18 @@ onMounted(() => { |
|
|
|
gap: 4px; |
|
|
|
font-size: 13px; |
|
|
|
color: #999; |
|
|
|
margin-bottom: 10px; |
|
|
|
padding: 8px 0px; |
|
|
|
} |
|
|
|
|
|
|
|
.task-divider { |
|
|
|
border-bottom: 1px dashed #999; |
|
|
|
border-bottom: 1px solid #f6f6f6; |
|
|
|
margin-bottom: 10px; |
|
|
|
} |
|
|
|
|
|
|
|
.task-detail-section { |
|
|
|
padding-bottom: 10px; |
|
|
|
margin-bottom: 10px; |
|
|
|
border-bottom: 1px dashed #999; |
|
|
|
// margin-bottom: 10px; |
|
|
|
// border-bottom: 1px dashed #999 |
|
|
|
|
|
|
|
&:last-child { |
|
|
|
border-bottom: none; |
|
|
|
@ -710,13 +726,15 @@ onMounted(() => { |
|
|
|
.detail-label { |
|
|
|
width: 72px; |
|
|
|
flex-shrink: 0; |
|
|
|
color: #222; |
|
|
|
color: #1D1F24; |
|
|
|
font-weight: 500; |
|
|
|
font-size: 12px; |
|
|
|
} |
|
|
|
|
|
|
|
.detail-value { |
|
|
|
flex: 1; |
|
|
|
color: #444; |
|
|
|
color: #666666; |
|
|
|
white-space: pre-line; |
|
|
|
font-size: 12px; |
|
|
|
} |
|
|
|
</style> |
|
|
|
|