584 lines
16 KiB
Vue
584 lines
16 KiB
Vue
|
|
<template>
|
||
|
|
<div class="factory-calendar-page app-container" v-loading="loading">
|
||
|
|
<div class="toolbar-row">
|
||
|
|
<el-form :inline="true" size="small" class="filter-row">
|
||
|
|
<el-form-item label="年份">
|
||
|
|
<el-date-picker
|
||
|
|
v-model="query.year"
|
||
|
|
type="year"
|
||
|
|
value-format="yyyy"
|
||
|
|
placeholder="选择年份"
|
||
|
|
style="width: 120px"
|
||
|
|
/>
|
||
|
|
</el-form-item>
|
||
|
|
<el-form-item>
|
||
|
|
<el-button type="primary" icon="el-icon-search" @click="handleRefresh">查询</el-button>
|
||
|
|
<el-button icon="el-icon-refresh" @click="handleRefresh">刷新</el-button>
|
||
|
|
</el-form-item>
|
||
|
|
</el-form>
|
||
|
|
|
||
|
|
<div class="month-strip">
|
||
|
|
<el-button
|
||
|
|
v-for="m in monthOptions"
|
||
|
|
:key="`m-${m}`"
|
||
|
|
size="mini"
|
||
|
|
:type="query.monthNum === m ? 'primary' : 'default'"
|
||
|
|
plain
|
||
|
|
class="month-btn"
|
||
|
|
@click="selectMonth(m)"
|
||
|
|
>
|
||
|
|
{{ m }}月
|
||
|
|
</el-button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="stats-row">
|
||
|
|
<div class="stat-card">
|
||
|
|
<div class="k"><i class="el-icon-s-operation" />任务总数</div>
|
||
|
|
<div class="v">{{ overview.taskCount }}</div>
|
||
|
|
</div>
|
||
|
|
<div class="stat-card">
|
||
|
|
<div class="k"><i class="el-icon-data-line" />活跃产线</div>
|
||
|
|
<div class="v">{{ overview.activeLineCount }} / {{ overview.totalLineCount }}</div>
|
||
|
|
</div>
|
||
|
|
<div class="stat-card">
|
||
|
|
<div class="k"><i class="el-icon-time" />排产总工时</div>
|
||
|
|
<div class="v">{{ overview.totalHours }}</div>
|
||
|
|
</div>
|
||
|
|
<div class="stat-card">
|
||
|
|
<div class="k"><i class="el-icon-date" />峰值日</div>
|
||
|
|
<div class="v">{{ overview.peakDayText }}</div>
|
||
|
|
</div>
|
||
|
|
<div class="stat-card">
|
||
|
|
<div class="k"><i class="el-icon-s-flag" />最忙产线</div>
|
||
|
|
<div class="v">{{ overview.busiestLineText }}</div>
|
||
|
|
</div>
|
||
|
|
<div class="stat-card">
|
||
|
|
<div class="k"><i class="el-icon-collection-tag" />最忙产线-班组</div>
|
||
|
|
<div class="v">{{ overview.busiestLineShiftText }}</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="calendar-block">
|
||
|
|
<div class="block-head">
|
||
|
|
<div class="block-title">产线日历</div>
|
||
|
|
<div class="legend">
|
||
|
|
<span class="legend-item"><i class="dot work" />工作日</span>
|
||
|
|
<span class="legend-item"><i class="dot rest" />休息日</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<el-tabs v-model="activeLineTab" type="card" class="sub-tabs" v-if="lineRows.length">
|
||
|
|
<el-tab-pane
|
||
|
|
v-for="line in lineRows"
|
||
|
|
:key="`line-tab-${line.lineId}`"
|
||
|
|
:name="String(line.lineId)"
|
||
|
|
:label="line.lineName"
|
||
|
|
>
|
||
|
|
<div class="calendar-full">
|
||
|
|
<div class="week-head">
|
||
|
|
<span v-for="w in weekLabels" :key="`line-week-${line.lineId}-${w}`">{{ w }}</span>
|
||
|
|
</div>
|
||
|
|
<div class="month-grid">
|
||
|
|
<div
|
||
|
|
v-for="cell in monthCells"
|
||
|
|
:key="`line-${line.lineId}-${cell.key}`"
|
||
|
|
class="day-cell"
|
||
|
|
:class="[cell.isCurrentMonth ? 'cur' : 'other', lineDayClass(line.lineId, cell.date), dayExtraClass(cell)]"
|
||
|
|
>
|
||
|
|
<div class="day-no">{{ cell.day }}</div>
|
||
|
|
<template v-if="cell.isCurrentMonth">
|
||
|
|
<div class="task-count">{{ getLineDay(line.lineId, cell.date).taskCount }} 单</div>
|
||
|
|
<div
|
||
|
|
v-for="(t, idx) in tasksByLineDate(line.lineId, cell.date).slice(0, 3)"
|
||
|
|
:key="`line-${line.lineId}-${cell.date}-${idx}`"
|
||
|
|
class="task-item"
|
||
|
|
:title="taskLabel(t)"
|
||
|
|
>
|
||
|
|
{{ shortTaskWithShift(t) }}
|
||
|
|
</div>
|
||
|
|
<div class="more" v-if="getLineDay(line.lineId, cell.date).taskCount > 3">+{{ getLineDay(line.lineId, cell.date).taskCount - 3 }}</div>
|
||
|
|
</template>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</el-tab-pane>
|
||
|
|
</el-tabs>
|
||
|
|
<el-empty v-else description="暂无产线数据" />
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="calendar-block">
|
||
|
|
<div class="block-head">
|
||
|
|
<div class="block-title">产线-班组日历</div>
|
||
|
|
<div class="legend">
|
||
|
|
<span class="legend-item"><i class="dot work" />工作日</span>
|
||
|
|
<span class="legend-item"><i class="dot rest" />休息日</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<el-tabs v-model="activeLineShiftTab" type="card" class="sub-tabs" v-if="lineShiftRows.length">
|
||
|
|
<el-tab-pane
|
||
|
|
v-for="item in lineShiftRows"
|
||
|
|
:key="`ls-tab-${item.lineId}-${item.shiftId}`"
|
||
|
|
:name="`${item.lineId}-${item.shiftId}`"
|
||
|
|
:label="`${item.lineName} · ${item.shiftName}`"
|
||
|
|
>
|
||
|
|
<div class="calendar-full">
|
||
|
|
<div class="week-head">
|
||
|
|
<span v-for="w in weekLabels" :key="`ls-week-${item.lineId}-${item.shiftId}-${w}`">{{ w }}</span>
|
||
|
|
</div>
|
||
|
|
<div class="month-grid">
|
||
|
|
<div
|
||
|
|
v-for="cell in monthCells"
|
||
|
|
:key="`ls-${item.lineId}-${item.shiftId}-${cell.key}`"
|
||
|
|
class="day-cell"
|
||
|
|
:class="[cell.isCurrentMonth ? 'cur' : 'other', lineShiftDayClass(item.lineId, item.shiftId, cell.date), dayExtraClass(cell)]"
|
||
|
|
>
|
||
|
|
<div class="day-no">{{ cell.day }}</div>
|
||
|
|
<template v-if="cell.isCurrentMonth">
|
||
|
|
<div class="task-count">{{ getLineShiftDay(item.lineId, item.shiftId, cell.date).taskCount }} 单</div>
|
||
|
|
<div
|
||
|
|
v-for="(t, idx) in tasksByLineShiftDate(item.lineId, item.shiftId, cell.date).slice(0, 3)"
|
||
|
|
:key="`ls-${item.lineId}-${item.shiftId}-${cell.date}-${idx}`"
|
||
|
|
class="task-item"
|
||
|
|
:title="taskLabel(t)"
|
||
|
|
>
|
||
|
|
{{ shortTask(t) }}
|
||
|
|
</div>
|
||
|
|
<div class="more" v-if="getLineShiftDay(item.lineId, item.shiftId, cell.date).taskCount > 3">+{{ getLineShiftDay(item.lineId, item.shiftId, cell.date).taskCount - 3 }}</div>
|
||
|
|
</template>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</el-tab-pane>
|
||
|
|
</el-tabs>
|
||
|
|
<el-empty v-else description="暂无产线-班组数据" />
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script>
|
||
|
|
import { fetchFactoryCalendar } from '@/api/aps/aps'
|
||
|
|
|
||
|
|
export default {
|
||
|
|
name: 'ApsFactoryCalendarPage',
|
||
|
|
data() {
|
||
|
|
return {
|
||
|
|
loading: false,
|
||
|
|
query: { year: String(new Date().getFullYear()), monthNum: new Date().getMonth() + 1 },
|
||
|
|
monthOptions: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
|
||
|
|
weekLabels: ['日', '一', '二', '三', '四', '五', '六'],
|
||
|
|
activeLineTab: '',
|
||
|
|
activeLineShiftTab: '',
|
||
|
|
payload: {
|
||
|
|
overview: {},
|
||
|
|
dateList: [],
|
||
|
|
lineNameMap: {},
|
||
|
|
shiftNameMap: {},
|
||
|
|
lineDayMap: {},
|
||
|
|
lineShiftDayMap: {}
|
||
|
|
},
|
||
|
|
legendVisible: true
|
||
|
|
}
|
||
|
|
},
|
||
|
|
computed: {
|
||
|
|
monthText() {
|
||
|
|
return `${this.query.year}-${`${this.query.monthNum}`.padStart(2, '0')}`
|
||
|
|
},
|
||
|
|
lineRows() {
|
||
|
|
return Object.keys(this.payload.lineNameMap || {}).map(id => ({ lineId: String(id), lineName: this.payload.lineNameMap[id] }))
|
||
|
|
},
|
||
|
|
lineShiftRows() {
|
||
|
|
const rows = []
|
||
|
|
Object.keys(this.payload.lineNameMap || {}).forEach(lineId => {
|
||
|
|
Object.keys(this.payload.shiftNameMap || {}).forEach(shiftId => {
|
||
|
|
rows.push({
|
||
|
|
lineId: String(lineId),
|
||
|
|
lineName: this.payload.lineNameMap[lineId],
|
||
|
|
shiftId: String(shiftId),
|
||
|
|
shiftName: this.payload.shiftNameMap[shiftId]
|
||
|
|
})
|
||
|
|
})
|
||
|
|
})
|
||
|
|
return rows
|
||
|
|
},
|
||
|
|
monthRange() {
|
||
|
|
const y = Number((this.query.year || '').toString())
|
||
|
|
const m = Number(this.query.monthNum || 0)
|
||
|
|
if (!y || !m) return { start: '', end: '' }
|
||
|
|
const start = new Date(y, m - 1, 1)
|
||
|
|
const end = new Date(y, m, 0)
|
||
|
|
return { start: this.formatDate(start), end: this.formatDate(end) }
|
||
|
|
},
|
||
|
|
monthCells() {
|
||
|
|
const { start, end } = this.monthRange
|
||
|
|
if (!start || !end) return []
|
||
|
|
const startDate = new Date(`${start} 00:00:00`)
|
||
|
|
const endDate = new Date(`${end} 00:00:00`)
|
||
|
|
const firstWeekDay = startDate.getDay()
|
||
|
|
const cells = []
|
||
|
|
const prefixStart = new Date(startDate.getTime())
|
||
|
|
prefixStart.setDate(prefixStart.getDate() - firstWeekDay)
|
||
|
|
const totalDays = Math.ceil((endDate.getTime() - prefixStart.getTime()) / 86400000) + 1
|
||
|
|
const totalCells = Math.ceil(totalDays / 7) * 7
|
||
|
|
for (let i = 0; i < totalCells; i++) {
|
||
|
|
const d = new Date(prefixStart.getTime())
|
||
|
|
d.setDate(prefixStart.getDate() + i)
|
||
|
|
const date = this.formatDate(d)
|
||
|
|
cells.push({ key: `${date}-${i}`, date, day: d.getDate(), isCurrentMonth: date >= start && date <= end })
|
||
|
|
}
|
||
|
|
return cells
|
||
|
|
},
|
||
|
|
overview() {
|
||
|
|
return this.payload.overview || {
|
||
|
|
taskCount: 0,
|
||
|
|
activeLineCount: 0,
|
||
|
|
totalLineCount: 0,
|
||
|
|
totalHours: '0.0',
|
||
|
|
peakDayText: '-',
|
||
|
|
busiestLineText: '-',
|
||
|
|
busiestLineShiftText: '-'
|
||
|
|
}
|
||
|
|
}
|
||
|
|
},
|
||
|
|
created() {
|
||
|
|
this.handleRefresh()
|
||
|
|
},
|
||
|
|
methods: {
|
||
|
|
selectMonth(m) {
|
||
|
|
this.query.monthNum = m
|
||
|
|
this.handleRefresh()
|
||
|
|
},
|
||
|
|
formatDate(d) {
|
||
|
|
const y = d.getFullYear()
|
||
|
|
const m = `${d.getMonth() + 1}`.padStart(2, '0')
|
||
|
|
const day = `${d.getDate()}`.padStart(2, '0')
|
||
|
|
return `${y}-${m}-${day}`
|
||
|
|
},
|
||
|
|
async handleRefresh() {
|
||
|
|
const { start, end } = this.monthRange
|
||
|
|
if (!start || !end) {
|
||
|
|
this.$message.warning('请先选择月份')
|
||
|
|
return
|
||
|
|
}
|
||
|
|
this.loading = true
|
||
|
|
try {
|
||
|
|
const res = await fetchFactoryCalendar({ queryStart: `${start} 00:00:00`, queryEnd: `${end} 23:59:59` })
|
||
|
|
this.payload = res.data || {
|
||
|
|
overview: {}, dateList: [], lineNameMap: {}, shiftNameMap: {}, lineDayMap: {}, lineShiftDayMap: {}
|
||
|
|
}
|
||
|
|
if (this.lineRows.length && !this.lineRows.find(i => String(i.lineId) === this.activeLineTab)) {
|
||
|
|
this.activeLineTab = String(this.lineRows[0].lineId)
|
||
|
|
}
|
||
|
|
if (this.lineShiftRows.length && !this.lineShiftRows.find(i => `${i.lineId}-${i.shiftId}` === this.activeLineShiftTab)) {
|
||
|
|
this.activeLineShiftTab = `${this.lineShiftRows[0].lineId}-${this.lineShiftRows[0].shiftId}`
|
||
|
|
}
|
||
|
|
} finally {
|
||
|
|
this.loading = false
|
||
|
|
}
|
||
|
|
},
|
||
|
|
getLineDay(lineId, date) {
|
||
|
|
const key = `${String(lineId)}|${date}`
|
||
|
|
const m = this.payload.lineDayMap || {}
|
||
|
|
const found = m[key]
|
||
|
|
return found || { taskCount: 0, shiftCount: 0, tasks: [] }
|
||
|
|
},
|
||
|
|
getLineShiftDay(lineId, shiftId, date) {
|
||
|
|
const key = `${String(lineId)}|${String(shiftId)}|${date}`
|
||
|
|
const m = this.payload.lineShiftDayMap || {}
|
||
|
|
const found = m[key]
|
||
|
|
return found || { taskCount: 0, lineCount: 0, tasks: [] }
|
||
|
|
},
|
||
|
|
tasksByLineDate(lineId, date) {
|
||
|
|
return this.getLineDay(lineId, date).tasks || []
|
||
|
|
},
|
||
|
|
tasksByLineShiftDate(lineId, shiftId, date) {
|
||
|
|
return this.getLineShiftDay(lineId, shiftId, date).tasks || []
|
||
|
|
},
|
||
|
|
taskLabel(task) {
|
||
|
|
return task && task.title ? task.title : '-'
|
||
|
|
},
|
||
|
|
shortTask(task) {
|
||
|
|
return task && task.label ? task.label : '-'
|
||
|
|
},
|
||
|
|
shortTaskWithShift(task) {
|
||
|
|
return this.shortTask(task)
|
||
|
|
},
|
||
|
|
lineDayClass(lineId, date) {
|
||
|
|
const day = this.getLineDay(lineId, date)
|
||
|
|
if (day.dayStatus === 1) return 'workday'
|
||
|
|
if (day.dayStatus === 0) return 'restday'
|
||
|
|
return day.taskCount > 0 ? 'workday' : 'neutral'
|
||
|
|
},
|
||
|
|
lineShiftDayClass(lineId, shiftId, date) {
|
||
|
|
const day = this.getLineShiftDay(lineId, shiftId, date)
|
||
|
|
if (day.dayStatus === 1) return 'workday'
|
||
|
|
if (day.dayStatus === 0) return 'restday'
|
||
|
|
return day.taskCount > 0 ? 'workday' : 'neutral'
|
||
|
|
},
|
||
|
|
dayExtraClass(cell) {
|
||
|
|
const classes = []
|
||
|
|
const d = new Date(`${cell.date} 00:00:00`)
|
||
|
|
const week = d.getDay()
|
||
|
|
if (week === 0 || week === 6) classes.push('is-weekend')
|
||
|
|
const today = this.formatDate(new Date())
|
||
|
|
if (cell.date === today) classes.push('is-today')
|
||
|
|
return classes.join(' ')
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style scoped lang="scss">
|
||
|
|
.factory-calendar-page {
|
||
|
|
padding: 12px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.toolbar-row {
|
||
|
|
background: #fff;
|
||
|
|
border: 1px solid #e9edf3;
|
||
|
|
border-radius: 10px;
|
||
|
|
padding: 10px 12px;
|
||
|
|
margin-bottom: 10px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.filter-row {
|
||
|
|
margin: 0 0 10px;
|
||
|
|
}
|
||
|
|
|
||
|
|
::v-deep .filter-row .el-date-editor.el-input,
|
||
|
|
::v-deep .filter-row .el-date-editor.el-input__inner {
|
||
|
|
width: 120px !important;
|
||
|
|
}
|
||
|
|
|
||
|
|
::v-deep .filter-row .el-input__inner {
|
||
|
|
border-radius: 8px;
|
||
|
|
border-color: #d7deea;
|
||
|
|
}
|
||
|
|
|
||
|
|
::v-deep .filter-row .el-input__inner:focus {
|
||
|
|
border-color: #7aa9ff;
|
||
|
|
}
|
||
|
|
|
||
|
|
.month-strip {
|
||
|
|
display: flex;
|
||
|
|
flex-wrap: wrap;
|
||
|
|
gap: 8px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.month-btn {
|
||
|
|
min-width: 56px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.stats-row {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: repeat(6, minmax(140px, 1fr));
|
||
|
|
gap: 10px;
|
||
|
|
margin-bottom: 12px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.stat-card {
|
||
|
|
padding: 10px 12px;
|
||
|
|
border: 1px solid #e9edf3;
|
||
|
|
border-radius: 10px;
|
||
|
|
background: #fff;
|
||
|
|
}
|
||
|
|
|
||
|
|
.stat-card .k {
|
||
|
|
font-size: 12px;
|
||
|
|
color: #8b95a7;
|
||
|
|
}
|
||
|
|
|
||
|
|
.stat-card .v {
|
||
|
|
margin-top: 6px;
|
||
|
|
font-size: 18px;
|
||
|
|
line-height: 1.2;
|
||
|
|
font-weight: 700;
|
||
|
|
color: #1f2d3d;
|
||
|
|
}
|
||
|
|
|
||
|
|
.calendar-block {
|
||
|
|
margin-bottom: 14px;
|
||
|
|
background: #fff;
|
||
|
|
border: 1px solid #e9edf3;
|
||
|
|
border-radius: 10px;
|
||
|
|
padding: 10px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.block-head {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: space-between;
|
||
|
|
margin-bottom: 8px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.block-title {
|
||
|
|
font-size: 14px;
|
||
|
|
color: #1f2d3d;
|
||
|
|
font-weight: 700;
|
||
|
|
}
|
||
|
|
|
||
|
|
.legend {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 12px;
|
||
|
|
font-size: 12px;
|
||
|
|
color: #6b7280;
|
||
|
|
}
|
||
|
|
|
||
|
|
.legend-item {
|
||
|
|
display: inline-flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 6px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.dot {
|
||
|
|
width: 10px;
|
||
|
|
height: 10px;
|
||
|
|
border-radius: 2px;
|
||
|
|
display: inline-block;
|
||
|
|
border: 1px solid #e5e7eb;
|
||
|
|
}
|
||
|
|
|
||
|
|
.dot.work {
|
||
|
|
background: #edf8ee;
|
||
|
|
}
|
||
|
|
|
||
|
|
.dot.rest {
|
||
|
|
background: #fff2e6;
|
||
|
|
}
|
||
|
|
|
||
|
|
::v-deep .sub-tabs .el-tabs__header {
|
||
|
|
margin-bottom: 10px;
|
||
|
|
border: none;
|
||
|
|
}
|
||
|
|
|
||
|
|
::v-deep .sub-tabs .el-tabs__nav-wrap,
|
||
|
|
::v-deep .sub-tabs .el-tabs__nav-scroll,
|
||
|
|
::v-deep .sub-tabs .el-tabs__nav {
|
||
|
|
border: none !important;
|
||
|
|
background: transparent;
|
||
|
|
}
|
||
|
|
|
||
|
|
::v-deep .sub-tabs .el-tabs__item {
|
||
|
|
border-radius: 16px;
|
||
|
|
margin-right: 8px;
|
||
|
|
border: 1px solid #dbe3ef !important;
|
||
|
|
background: #fff;
|
||
|
|
height: 30px;
|
||
|
|
line-height: 30px;
|
||
|
|
padding: 0 12px;
|
||
|
|
color: #4a5668;
|
||
|
|
transition: all .2s;
|
||
|
|
}
|
||
|
|
|
||
|
|
::v-deep .sub-tabs .el-tabs__item:hover {
|
||
|
|
color: #2f7df6;
|
||
|
|
border-color: #b8d3ff !important;
|
||
|
|
}
|
||
|
|
|
||
|
|
::v-deep .sub-tabs .el-tabs__item.is-active {
|
||
|
|
color: #2f7df6;
|
||
|
|
background: #eef5ff;
|
||
|
|
border-color: #bfd8ff !important;
|
||
|
|
font-weight: 600;
|
||
|
|
}
|
||
|
|
|
||
|
|
::v-deep .sub-tabs .el-tabs__item:last-child {
|
||
|
|
margin-right: 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
::v-deep .sub-tabs .el-tabs__nav-wrap::after,
|
||
|
|
::v-deep .sub-tabs .el-tabs__active-bar {
|
||
|
|
display: none !important;
|
||
|
|
}
|
||
|
|
|
||
|
|
.calendar-full {
|
||
|
|
width: 100%;
|
||
|
|
}
|
||
|
|
|
||
|
|
.week-head {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: repeat(7, 1fr);
|
||
|
|
border: 1px solid #edf1f6;
|
||
|
|
border-bottom: none;
|
||
|
|
border-radius: 8px 8px 0 0;
|
||
|
|
overflow: hidden;
|
||
|
|
}
|
||
|
|
|
||
|
|
.week-head span {
|
||
|
|
text-align: center;
|
||
|
|
padding: 8px 0;
|
||
|
|
font-size: 12px;
|
||
|
|
color: #7d8797;
|
||
|
|
background: #fafcff;
|
||
|
|
border-right: 1px solid #edf1f6;
|
||
|
|
}
|
||
|
|
|
||
|
|
.week-head span:last-child {
|
||
|
|
border-right: none;
|
||
|
|
}
|
||
|
|
|
||
|
|
.month-grid {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: repeat(7, 1fr);
|
||
|
|
border-left: 1px solid #edf1f6;
|
||
|
|
border-top: 1px solid #edf1f6;
|
||
|
|
}
|
||
|
|
|
||
|
|
.day-cell {
|
||
|
|
height: 120px;
|
||
|
|
padding: 8px;
|
||
|
|
border-right: 1px solid #edf1f6;
|
||
|
|
border-bottom: 1px solid #edf1f6;
|
||
|
|
box-sizing: border-box;
|
||
|
|
background: #fff;
|
||
|
|
}
|
||
|
|
|
||
|
|
.day-cell.other {
|
||
|
|
background: #fafbfd;
|
||
|
|
color: #c4cad4;
|
||
|
|
}
|
||
|
|
|
||
|
|
.day-cell.cur.workday {
|
||
|
|
background: #edf8ee;
|
||
|
|
}
|
||
|
|
|
||
|
|
.day-cell.cur.restday {
|
||
|
|
background: #fff2e6;
|
||
|
|
}
|
||
|
|
|
||
|
|
.day-cell.is-today {
|
||
|
|
box-shadow: inset 0 0 0 2px #7aa9ff;
|
||
|
|
}
|
||
|
|
|
||
|
|
.day-cell.is-weekend .day-no {
|
||
|
|
color: #5f84c9;
|
||
|
|
}
|
||
|
|
|
||
|
|
.day-no {
|
||
|
|
font-size: 11px;
|
||
|
|
color: #8f99aa;
|
||
|
|
margin-bottom: 6px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.task-count {
|
||
|
|
font-size: 12px;
|
||
|
|
color: #1f2d3d;
|
||
|
|
font-weight: 700;
|
||
|
|
margin-bottom: 4px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.task-item {
|
||
|
|
font-size: 11px;
|
||
|
|
color: #4c596d;
|
||
|
|
line-height: 1.35;
|
||
|
|
white-space: nowrap;
|
||
|
|
overflow: hidden;
|
||
|
|
text-overflow: ellipsis;
|
||
|
|
}
|
||
|
|
|
||
|
|
.more {
|
||
|
|
font-size: 10px;
|
||
|
|
color: #9aa5b5;
|
||
|
|
margin-top: 3px;
|
||
|
|
}</style>
|