Compare commits
No commits in common. "054f05af7074411842c9ab5e5f287e311353706c" and "d1681ee08cba449902c12cc5171180e55bc97b32" have entirely different histories.
054f05af70
...
d1681ee08c
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"name" : "SEC_Warehouse",
|
"name" : "smarthome",
|
||||||
"appid" : "",
|
"appid" : "",
|
||||||
"description" : "",
|
"description" : "",
|
||||||
"versionName" : "1.0.0",
|
"versionName" : "1.0.0",
|
||||||
|
|
|
||||||
12
pages.json
12
pages.json
|
|
@ -57,21 +57,15 @@
|
||||||
"list": [
|
"list": [
|
||||||
{
|
{
|
||||||
"pagePath": "pages/index/index",
|
"pagePath": "pages/index/index",
|
||||||
"text": "首页",
|
"text": "首页"
|
||||||
"iconPath": "static/tabbar/home.png",
|
|
||||||
"selectedIconPath": "static/tabbar/home-active.png"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pagePath": "pages/event/index",
|
"pagePath": "pages/event/index",
|
||||||
"text": "事件",
|
"text": "事件"
|
||||||
"iconPath": "static/tabbar/event.png",
|
|
||||||
"selectedIconPath": "static/tabbar/event-active.png"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pagePath": "pages/mine/index",
|
"pagePath": "pages/mine/index",
|
||||||
"text": "我的",
|
"text": "我的"
|
||||||
"iconPath": "static/tabbar/mine.png",
|
|
||||||
"selectedIconPath": "static/tabbar/mine-active.png"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -4,794 +4,41 @@
|
||||||
<up-navbar title="事件" :fixed="false" :safe-area-inset-top="true" :border="false" left-icon="" />
|
<up-navbar title="事件" :fixed="false" :safe-area-inset-top="true" :border="false" left-icon="" />
|
||||||
|
|
||||||
<view class="filters">
|
<view class="filters">
|
||||||
<view class="filter-cell" @click="openDrawer('scene')">
|
<view><up-button size="mini" type="primary" plain text="全部场所" /></view>
|
||||||
<view class="filter-trigger" :class="{ 'filter-trigger--active': filters.sceneId !== 0 }">
|
<view><up-button size="mini" type="primary" plain text="全部状态" /></view>
|
||||||
<text class="filter-text">{{ sceneLabel }}</text>
|
<view><up-button size="mini" type="primary" plain text="时间" /></view>
|
||||||
<up-icon name="arrow-down" size="13" :color="filters.sceneId !== 0 ? '#12a37a' : '#909399'" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="filter-cell" @click="openDrawer('status')">
|
|
||||||
<view class="filter-trigger" :class="{ 'filter-trigger--active': filters.status !== 0 }">
|
|
||||||
<text class="filter-text">{{ statusLabel }}</text>
|
|
||||||
<up-icon name="arrow-down" size="13" :color="filters.status !== 0 ? '#12a37a' : '#909399'" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="filter-cell" @click="openDrawer('time')">
|
|
||||||
<view class="filter-trigger" :class="{ 'filter-trigger--active': !!filters.startDate }">
|
|
||||||
<text class="filter-text">{{ filters.timeText || '时间' }}</text>
|
|
||||||
<up-icon name="arrow-down" size="13" :color="filters.startDate ? '#12a37a' : '#909399'" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 数据层:筛选栏以下区域;三个下拉抽屉都锚定在这层顶部(筛选栏下缘)展开 -->
|
<view class="empty-area">
|
||||||
<view class="content-area">
|
<up-empty mode="message" text="暂无事件数据" />
|
||||||
<view class="content-body">
|
|
||||||
<view class="empty-area">
|
|
||||||
<up-empty mode="message" text="暂无事件数据" />
|
|
||||||
</view>
|
|
||||||
<view class="empty-hint">
|
|
||||||
<text>调整筛选条件后的事件列表将在此展示</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 遮罩:盖住筛选栏以下全部内容 -->
|
|
||||||
<view v-if="drawer" class="content-mask" @click="closeDrawer" @touchmove.stop.prevent="noop" />
|
|
||||||
|
|
||||||
<!-- 场所抽屉:从筛选栏下缘展开 -->
|
|
||||||
<view v-if="drawer === 'scene'" class="drop-panel drop-panel--options">
|
|
||||||
<view class="option-drawer-header">
|
|
||||||
<text class="option-drawer-title">选择场所</text>
|
|
||||||
<view class="option-drawer-close" @click="closeDrawer">
|
|
||||||
<up-icon name="close" size="20" color="#909399" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="option-drawer-list">
|
|
||||||
<view
|
|
||||||
v-for="opt in sceneOptions"
|
|
||||||
:key="opt.id"
|
|
||||||
class="option-drawer-item"
|
|
||||||
:class="{ 'option-drawer-item--active': filters.sceneId === opt.id }"
|
|
||||||
@click="selectScene(opt.id)"
|
|
||||||
>
|
|
||||||
<text class="option-drawer-item__text">{{ opt.name }}</text>
|
|
||||||
<up-icon v-if="filters.sceneId === opt.id" name="checkmark" size="16" color="#2CCB98" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 状态抽屉:从筛选栏下缘展开 -->
|
|
||||||
<view v-if="drawer === 'status'" class="drop-panel drop-panel--options">
|
|
||||||
<view class="option-drawer-header">
|
|
||||||
<text class="option-drawer-title">选择状态</text>
|
|
||||||
<view class="option-drawer-close" @click="closeDrawer">
|
|
||||||
<up-icon name="close" size="20" color="#909399" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="option-drawer-list">
|
|
||||||
<view
|
|
||||||
v-for="opt in statusOptions"
|
|
||||||
:key="opt.id"
|
|
||||||
class="option-drawer-item"
|
|
||||||
:class="{ 'option-drawer-item--active': filters.status === opt.id }"
|
|
||||||
@click="selectStatus(opt.id)"
|
|
||||||
>
|
|
||||||
<text class="option-drawer-item__text">{{ opt.name }}</text>
|
|
||||||
<up-icon v-if="filters.status === opt.id" name="checkmark" size="16" color="#2CCB98" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 时间抽屉:从筛选栏下缘展开(滚动式日历:懒渲染,窗口外月份占位) -->
|
|
||||||
<view v-if="drawer === 'time'" class="drop-panel drop-panel--calendar">
|
|
||||||
<view class="time-drawer-header">
|
|
||||||
<text class="time-drawer-title">选择时间范围</text>
|
|
||||||
<view class="time-drawer-close" @click="closeDrawer">
|
|
||||||
<up-icon name="close" size="20" color="#909399" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 快捷范围:点选直接填满起止 -->
|
|
||||||
<view class="quick-row">
|
|
||||||
<view
|
|
||||||
v-for="q in quickRanges"
|
|
||||||
:key="q.label"
|
|
||||||
class="quick-chip"
|
|
||||||
:class="{ 'quick-chip--active': activeQuick === q.label }"
|
|
||||||
@click="applyQuick(q)"
|
|
||||||
>
|
|
||||||
<text>{{ q.label }}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 星期行:钉在滚动区上方 -->
|
|
||||||
<view class="cal-weekdays">
|
|
||||||
<text v-for="w in weekdayLabels" :key="w" class="cal-weekday">{{ w }}</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 滚动日历:scroll-view 纵向滚月,懒渲染(窗口外月份只渲染占位高度) -->
|
|
||||||
<view class="cal-scroll-wrap">
|
|
||||||
<scroll-view
|
|
||||||
class="cal-scroll"
|
|
||||||
scroll-y
|
|
||||||
:scroll-into-view="calAnchorId"
|
|
||||||
scroll-anchoring
|
|
||||||
@scroll="onCalScroll"
|
|
||||||
>
|
|
||||||
<view
|
|
||||||
v-for="m in renderedMonths"
|
|
||||||
:key="m.key"
|
|
||||||
:id="m.key"
|
|
||||||
class="cal-month"
|
|
||||||
:style="m.placeholder ? { height: m.height + 'rpx' } : {}"
|
|
||||||
>
|
|
||||||
<template v-if="!m.placeholder">
|
|
||||||
<view class="cal-month-title">
|
|
||||||
<text>{{ m.title }}</text>
|
|
||||||
</view>
|
|
||||||
<view class="cal-grid">
|
|
||||||
<view
|
|
||||||
v-for="(cell, i) in m.cells"
|
|
||||||
:key="i"
|
|
||||||
class="cal-cell"
|
|
||||||
:class="cell.cls"
|
|
||||||
@click="pickDate(cell)"
|
|
||||||
>
|
|
||||||
<view v-if="cell.day" class="cal-day" :class="cell.dayCls">
|
|
||||||
<text class="cal-day-num">{{ cell.day }}</text>
|
|
||||||
<text v-if="cell.tag" class="cal-day-tag">{{ cell.tag }}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
</view>
|
|
||||||
</scroll-view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="time-drawer-footer">
|
|
||||||
<up-button
|
|
||||||
shape="circle"
|
|
||||||
:text="rangeReady ? '确定' : '请选择起止日期'"
|
|
||||||
color="#2CCB98"
|
|
||||||
:disabled="!rangeReady"
|
|
||||||
@click="onConfirmClick"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { getSceneList } from '@/api/scene'
|
// 当前为静态页占位,不包含交互逻辑。
|
||||||
|
export default {}
|
||||||
// 日历可回溯的年数(仅约束可翻到的最早月份,不影响性能)
|
|
||||||
const CALENDAR_YEARS_BACK = 10
|
|
||||||
const WEEKDAY_LABELS = ['一', '二', '三', '四', '五', '六', '日']
|
|
||||||
|
|
||||||
const pad2 = (n) => String(n).padStart(2, '0')
|
|
||||||
// Date -> 'YYYY-MM-DD'(本地时区)
|
|
||||||
const fmtDate = (d) => `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`
|
|
||||||
// 'YYYY-MM-DD' -> 当日零点 Date
|
|
||||||
const parseDate = (s) => {
|
|
||||||
const [y, m, d] = s.split('-').map(Number)
|
|
||||||
return new Date(y, m - 1, d)
|
|
||||||
}
|
|
||||||
// 生成快捷范围选项:近 N 天(含今天)
|
|
||||||
const quickRange = (days) => {
|
|
||||||
const end = new Date()
|
|
||||||
const start = new Date()
|
|
||||||
start.setDate(start.getDate() - (days - 1))
|
|
||||||
return { label: `近${days}天`, start: fmtDate(start), end: fmtDate(end) }
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
drawer: '', // '' | 'scene' | 'status' | 'time'
|
|
||||||
windowWidth: 375, // 窗口宽(px),onLoad 时取系统信息,用于 px→rpx 换算
|
|
||||||
calScroll: 0, // 当前滚动位置(rpx 近似,用于懒渲染窗口判定)
|
|
||||||
calAnchorId: '', // scroll-into-view 定位的月份锚点
|
|
||||||
pendingStart: '', // 临时起点
|
|
||||||
pendingEnd: '', // 临时终点
|
|
||||||
activeQuick: '',
|
|
||||||
weekdayLabels: WEEKDAY_LABELS,
|
|
||||||
quickRanges: [quickRange(7), quickRange(30), quickRange(90)],
|
|
||||||
filters: {
|
|
||||||
sceneId: 0, // 0 表示全部
|
|
||||||
status: 0,
|
|
||||||
startDate: '',
|
|
||||||
endDate: '',
|
|
||||||
timeText: ''
|
|
||||||
},
|
|
||||||
sceneOptions: [{ id: 0, name: '全部' }],
|
|
||||||
statusOptions: [
|
|
||||||
{ id: 0, name: '全部' },
|
|
||||||
{ id: 1, name: '未处理' },
|
|
||||||
{ id: 2, name: '已处理' },
|
|
||||||
{ id: 3, name: '已忽略' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
sceneLabel() {
|
|
||||||
const hit = this.sceneOptions.find((o) => o.id === this.filters.sceneId)
|
|
||||||
return hit ? hit.name : '全部场所'
|
|
||||||
},
|
|
||||||
statusLabel() {
|
|
||||||
const hit = this.statusOptions.find((o) => o.id === this.filters.status)
|
|
||||||
return hit ? hit.name : '全部状态'
|
|
||||||
},
|
|
||||||
// 可选范围边界
|
|
||||||
minLimit() {
|
|
||||||
const d = new Date()
|
|
||||||
d.setFullYear(d.getFullYear() - CALENDAR_YEARS_BACK)
|
|
||||||
d.setDate(1)
|
|
||||||
return fmtDate(d)
|
|
||||||
},
|
|
||||||
maxLimit() {
|
|
||||||
return fmtDate(new Date())
|
|
||||||
},
|
|
||||||
// 全部月份元数据:从最早月到当月,含每月份的估算高度(用于占位与滚动定位)
|
|
||||||
monthMetas() {
|
|
||||||
const metas = []
|
|
||||||
const start = parseDate(this.minLimit)
|
|
||||||
const now = new Date()
|
|
||||||
const endY = now.getFullYear()
|
|
||||||
const endM = now.getMonth()
|
|
||||||
let y = start.getFullYear()
|
|
||||||
let m = start.getMonth()
|
|
||||||
let top = 0
|
|
||||||
while (y < endY || (y === endY && m <= endM)) {
|
|
||||||
const weeks = this.monthWeeks(y, m)
|
|
||||||
// 标题行 + 周数×行高(格子 aspect 决定行高≈格子宽×1.15,按 750rpx/7 估算)
|
|
||||||
const height = 96 + weeks * Math.round((750 / 7) * 1.15) + 16
|
|
||||||
metas.push({
|
|
||||||
key: `m-${y}-${m}`,
|
|
||||||
year: y,
|
|
||||||
month: m,
|
|
||||||
title: `${y}年${pad2(m + 1)}月`,
|
|
||||||
top,
|
|
||||||
height
|
|
||||||
})
|
|
||||||
top += height
|
|
||||||
if (m === 11) {
|
|
||||||
y += 1
|
|
||||||
m = 0
|
|
||||||
} else {
|
|
||||||
m += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return metas
|
|
||||||
},
|
|
||||||
// 懒渲染:只渲染滚动窗口(±4 个月)内的月份,窗口外用等高占位
|
|
||||||
renderedMonths() {
|
|
||||||
// 滚动位置近似映射到月份索引:找 top 包含 calScroll 的月份
|
|
||||||
const viewRpx = 1400 // 滚动窗口可视高度近似(rpx)
|
|
||||||
const buffer = 3000 // 窗口前后缓冲(rpx)
|
|
||||||
const lo = this.calScroll - buffer
|
|
||||||
const hi = this.calScroll + viewRpx + buffer
|
|
||||||
return this.monthMetas.map((meta) => {
|
|
||||||
const inWindow = meta.top + meta.height > lo && meta.top < hi
|
|
||||||
if (!inWindow) {
|
|
||||||
return { ...meta, placeholder: true, cells: [] }
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...meta,
|
|
||||||
placeholder: false,
|
|
||||||
cells: this.buildMonthCells(meta.year, meta.month)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// 起止都已选定
|
|
||||||
rangeReady() {
|
|
||||||
return !!this.pendingStart && !!this.pendingEnd
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onLoad() {
|
|
||||||
// px→rpx 换算基准
|
|
||||||
const info = uni.getWindowInfo ? uni.getWindowInfo() : uni.getSystemInfoSync()
|
|
||||||
this.windowWidth = info.windowWidth || 375
|
|
||||||
this.loadScenes()
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
// 单格数据:区间内/端点/禁用态一次性算好,模板零逻辑
|
|
||||||
buildCell(dateStr, day) {
|
|
||||||
const disabled = dateStr < this.minLimit || dateStr > this.maxLimit
|
|
||||||
let dayCls = ''
|
|
||||||
let tag = ''
|
|
||||||
if (!disabled) {
|
|
||||||
if (this.pendingStart && dateStr === this.pendingStart) {
|
|
||||||
dayCls = 'cal-day--start'
|
|
||||||
tag = this.pendingStart === this.pendingEnd ? '起/止' : '开始'
|
|
||||||
} else if (this.pendingEnd && dateStr === this.pendingEnd) {
|
|
||||||
dayCls = 'cal-day--end'
|
|
||||||
tag = '结束'
|
|
||||||
} else if (
|
|
||||||
this.pendingStart &&
|
|
||||||
this.pendingEnd &&
|
|
||||||
dateStr > this.pendingStart &&
|
|
||||||
dateStr < this.pendingEnd
|
|
||||||
) {
|
|
||||||
dayCls = 'cal-day--in'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return { day, date: dateStr, disabled, cls: { 'cal-cell--disabled': disabled }, dayCls, tag }
|
|
||||||
},
|
|
||||||
// 某年某月的格子(含前置空格)
|
|
||||||
buildMonthCells(y, m) {
|
|
||||||
const firstDay = new Date(y, m, 1)
|
|
||||||
const lead = (firstDay.getDay() + 6) % 7
|
|
||||||
const daysInMonth = new Date(y, m + 1, 0).getDate()
|
|
||||||
const cells = []
|
|
||||||
for (let i = 0; i < lead; i++) cells.push({ day: 0 })
|
|
||||||
for (let d = 1; d <= daysInMonth; d++) {
|
|
||||||
cells.push(this.buildCell(`${y}-${pad2(m + 1)}-${pad2(d)}`, d))
|
|
||||||
}
|
|
||||||
return cells
|
|
||||||
},
|
|
||||||
// 某月占满的周数(1 个前置空格也占一行)
|
|
||||||
monthWeeks(y, m) {
|
|
||||||
const firstDay = new Date(y, m, 1)
|
|
||||||
const lead = (firstDay.getDay() + 6) % 7
|
|
||||||
const daysInMonth = new Date(y, m + 1, 0).getDate()
|
|
||||||
return Math.ceil((lead + daysInMonth) / 7)
|
|
||||||
},
|
|
||||||
// 动态加载场所列表:复用场景接口,后端 /scene/list 就绪后自动走真实请求。
|
|
||||||
// 失败时保留"全部"选项不阻塞筛选(toast 由请求封装统一弹出)。
|
|
||||||
async loadScenes() {
|
|
||||||
try {
|
|
||||||
const data = await getSceneList()
|
|
||||||
const list = Array.isArray(data) ? data : []
|
|
||||||
this.sceneOptions = [{ id: 0, name: '全部' }, ...list]
|
|
||||||
} catch (error) {
|
|
||||||
this.sceneOptions = [{ id: 0, name: '全部' }]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
noop() {},
|
|
||||||
openDrawer(name) {
|
|
||||||
if (name === 'time') {
|
|
||||||
// 回显已提交的起止;无提交时默认定位当月
|
|
||||||
this.pendingStart = this.filters.startDate
|
|
||||||
this.pendingEnd = this.filters.endDate
|
|
||||||
this.activeQuick = ''
|
|
||||||
const focus = this.filters.startDate || fmtDate(new Date())
|
|
||||||
const d = parseDate(focus)
|
|
||||||
const meta = this.monthMetas.find(
|
|
||||||
(mm) => mm.year === d.getFullYear() && mm.month === d.getMonth()
|
|
||||||
)
|
|
||||||
this.calScroll = meta ? meta.top : 0
|
|
||||||
// scroll-into-view 需要值变化才生效:先清空再在下个循环赋值
|
|
||||||
this.calAnchorId = ''
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.calAnchorId = meta ? meta.key : ''
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.drawer = name
|
|
||||||
},
|
|
||||||
closeDrawer() {
|
|
||||||
this.drawer = ''
|
|
||||||
},
|
|
||||||
// 场所/状态抽屉点选:写入筛选值并收起抽屉。
|
|
||||||
selectScene(id) {
|
|
||||||
this.filters.sceneId = id
|
|
||||||
this.closeDrawer()
|
|
||||||
this.handle()
|
|
||||||
},
|
|
||||||
selectStatus(id) {
|
|
||||||
this.filters.status = id
|
|
||||||
this.closeDrawer()
|
|
||||||
this.handle()
|
|
||||||
},
|
|
||||||
// 下拉选项变化:触发筛选回调,便于后续接事件列表接口。
|
|
||||||
handle() {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log('[event filters]', { ...this.filters })
|
|
||||||
},
|
|
||||||
// 滚动:把 px 滚动值换算回 rpx(750 / 窗口宽),驱动懒渲染窗口移动
|
|
||||||
onCalScroll(e) {
|
|
||||||
const px = e.detail.scrollTop || 0
|
|
||||||
const rpx = px * (750 / this.windowWidth)
|
|
||||||
// 跨过一定占位高度差再更新,减少 computed 重算频率
|
|
||||||
if (Math.abs(rpx - this.calScroll) > 200) {
|
|
||||||
this.calScroll = rpx
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 点击日期:第一击定起点,第二击定终点(早于起点则重定起点),选满后再点重选
|
|
||||||
pickDate(cell) {
|
|
||||||
if (!cell.day || cell.disabled) return
|
|
||||||
const date = cell.date
|
|
||||||
if (!this.pendingStart || (this.pendingStart && this.pendingEnd)) {
|
|
||||||
this.pendingStart = date
|
|
||||||
this.pendingEnd = ''
|
|
||||||
this.activeQuick = ''
|
|
||||||
} else if (date < this.pendingStart) {
|
|
||||||
this.pendingStart = date
|
|
||||||
this.activeQuick = ''
|
|
||||||
} else {
|
|
||||||
this.pendingEnd = date
|
|
||||||
this.activeQuick = ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 快捷范围:直接填满起止并定位到起点月
|
|
||||||
applyQuick(q) {
|
|
||||||
this.pendingStart = q.start
|
|
||||||
this.pendingEnd = q.end
|
|
||||||
this.activeQuick = q.label
|
|
||||||
const d = parseDate(q.start)
|
|
||||||
const meta = this.monthMetas.find(
|
|
||||||
(mm) => mm.year === d.getFullYear() && mm.month === d.getMonth()
|
|
||||||
)
|
|
||||||
this.calAnchorId = ''
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.calAnchorId = meta ? meta.key : ''
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// 确定按钮:提交临时起止并写入筛选值
|
|
||||||
onConfirmClick() {
|
|
||||||
if (!this.rangeReady) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.filters.startDate = this.pendingStart
|
|
||||||
this.filters.endDate = this.pendingEnd
|
|
||||||
this.filters.timeText = `${this.pendingStart} 至 ${this.pendingEnd}`
|
|
||||||
this.closeDrawer()
|
|
||||||
this.handle()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '@/styles/common.css';
|
@import '@/styles/common.css';
|
||||||
|
|
||||||
/* 页面容器:纵向 flex,让数据层撑满筛选栏以下的全部剩余视口 */
|
|
||||||
.page {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filters {
|
.filters {
|
||||||
flex-shrink: 0;
|
> view + view {
|
||||||
display: flex;
|
margin-left: 18rpx;
|
||||||
align-items: stretch;
|
}
|
||||||
min-height: 96rpx;
|
min-height: 96rpx;
|
||||||
padding: 16rpx 24rpx;
|
padding: 16rpx 24rpx;
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
border-top: 1rpx solid #ededed;
|
border-top: 1rpx solid #ededed;
|
||||||
}
|
|
||||||
|
|
||||||
.filter-cell {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
|
||||||
|
|
||||||
+ .filter-cell {
|
|
||||||
margin-left: 18rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-trigger {
|
|
||||||
height: 100%;
|
|
||||||
min-height: 64rpx;
|
|
||||||
padding: 0 20rpx;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
|
||||||
background: #f5f6f8;
|
|
||||||
border: 1rpx solid transparent;
|
|
||||||
border-radius: 12rpx;
|
|
||||||
color: #606266;
|
|
||||||
font-size: 26rpx;
|
|
||||||
transition: background-color 0.2s, border-color 0.2s;
|
|
||||||
|
|
||||||
&--active {
|
|
||||||
background: #e9fff3;
|
|
||||||
border-color: #2ccb98;
|
|
||||||
color: #12a37a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-text {
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-area {
|
.empty-area {
|
||||||
min-height: 720rpx;
|
min-height: 880rpx;
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
justify-content: center;
|
|
||||||
padding-top: 120rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty-hint {
|
|
||||||
margin-top: -40rpx;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #b5b9c0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 数据层:撑满筛选栏以下全部视口,是三个下拉抽屉的定位锚点 */
|
|
||||||
.content-area {
|
|
||||||
position: relative;
|
|
||||||
flex: 1;
|
|
||||||
min-height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 遮罩:盖住筛选栏以下内容,点击关闭 */
|
|
||||||
.content-mask {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
background: rgba(0, 0, 0, 0.35);
|
|
||||||
z-index: 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 下拉面板:从数据层顶部(筛选栏下缘)展开 */
|
|
||||||
.drop-panel {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
background: #ffffff;
|
|
||||||
box-shadow: 0 12rpx 40rpx rgba(0, 0, 0, 0.08);
|
|
||||||
z-index: 11;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
border-bottom-left-radius: 24rpx;
|
|
||||||
border-bottom-right-radius: 24rpx;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 场所/状态选项面板:内容自适应高度 */
|
|
||||||
.drop-panel--options {
|
|
||||||
max-height: 60vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 时间面板:日历占剩余空间,但不超过数据层高度(时间抽屉时遮罩仍完整盖住剩余空间) */
|
|
||||||
.drop-panel--calendar {
|
|
||||||
height: 66vh;
|
|
||||||
max-height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.option-drawer-header {
|
|
||||||
padding: 28rpx 32rpx;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
border-bottom: 1rpx solid #f0f1f3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.option-drawer-title {
|
|
||||||
font-size: 32rpx;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #2a2d33;
|
|
||||||
}
|
|
||||||
|
|
||||||
.option-drawer-close {
|
|
||||||
width: 56rpx;
|
|
||||||
height: 56rpx;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.option-drawer-list {
|
|
||||||
padding: 12rpx 24rpx 24rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.option-drawer-item {
|
|
||||||
min-height: 96rpx;
|
|
||||||
padding: 0 28rpx;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
border-radius: 14rpx;
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background: #f7f8fa;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--active {
|
|
||||||
background: #e9fff3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.option-drawer-item__text {
|
|
||||||
font-size: 30rpx;
|
|
||||||
color: #2a2d33;
|
|
||||||
}
|
|
||||||
|
|
||||||
.option-drawer-item--active .option-drawer-item__text {
|
|
||||||
color: #2CCB98;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 时间面板头/底部(面板已锚定在筛选栏下方,不再 fixed) */
|
|
||||||
.time-drawer-header {
|
|
||||||
padding: 20rpx 32rpx;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
border-bottom: 1rpx solid #f0f1f3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.time-drawer-title {
|
|
||||||
font-size: 30rpx;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #2a2d33;
|
|
||||||
}
|
|
||||||
|
|
||||||
.time-drawer-close {
|
|
||||||
width: 56rpx;
|
|
||||||
height: 56rpx;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 快捷范围行 */
|
|
||||||
.quick-row {
|
|
||||||
display: flex;
|
|
||||||
padding: 20rpx 24rpx 4rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.quick-chip {
|
|
||||||
flex: 1;
|
|
||||||
margin-right: 16rpx;
|
|
||||||
height: 60rpx;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
background: #f5f6f8;
|
|
||||||
border: 1rpx solid transparent;
|
|
||||||
border-radius: 999rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #606266;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--active {
|
|
||||||
background: #e9fff3;
|
|
||||||
border-color: #2ccb98;
|
|
||||||
color: #12a37a;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 星期行:钉在滚动区上方 */
|
|
||||||
.cal-weekdays {
|
|
||||||
display: flex;
|
|
||||||
padding: 0 16rpx;
|
|
||||||
border-bottom: 1rpx solid #f0f1f3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cal-weekday {
|
|
||||||
flex: 1;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #909399;
|
|
||||||
line-height: 48rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 滚动日历容器:占满抽屉剩余空间 */
|
|
||||||
.cal-scroll-wrap {
|
|
||||||
flex: 1;
|
|
||||||
min-height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cal-scroll {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 月份块 */
|
|
||||||
.cal-month {
|
|
||||||
padding: 8rpx 16rpx 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cal-month-title {
|
|
||||||
height: 72rpx;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: 28rpx;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #2a2d33;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 日期网格:固定 42 格(前置空格 + 当月天),节点数恒定 */
|
|
||||||
.cal-grid {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cal-cell {
|
|
||||||
width: calc(100% / 7);
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 4rpx;
|
|
||||||
aspect-ratio: 1 / 1.15;
|
|
||||||
display: flex;
|
|
||||||
align-items: stretch;
|
|
||||||
|
|
||||||
&--disabled {
|
|
||||||
opacity: 0.3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.cal-day {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
border-radius: 12rpx;
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background: #f2f3f5;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--start,
|
|
||||||
&--end {
|
|
||||||
background: #2ccb98;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--start.cal-day--end {
|
|
||||||
background: #2ccb98;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--in {
|
|
||||||
background: #e9fff3;
|
|
||||||
border-radius: 0;
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background: #ddf6ec;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.cal-day-num {
|
|
||||||
font-size: 28rpx;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #2a2d33;
|
|
||||||
line-height: 40rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cal-day--start .cal-day-num,
|
|
||||||
.cal-day--end .cal-day-num {
|
|
||||||
color: #ffffff;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cal-day--in .cal-day-num {
|
|
||||||
color: #12a37a;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 开始/结束小字标注 */
|
|
||||||
.cal-day-tag {
|
|
||||||
font-size: 18rpx;
|
|
||||||
line-height: 24rpx;
|
|
||||||
color: rgba(255, 255, 255, 0.9);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 起止回显:只占内容高度,不与日历滚动区平分空间 */
|
|
||||||
.range-preview {
|
|
||||||
flex-shrink: 0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #6b6f76;
|
|
||||||
min-height: 56rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.time-drawer-footer {
|
|
||||||
flex-shrink: 0;
|
|
||||||
padding: 16rpx 24rpx calc(16rpx + env(safe-area-inset-bottom));
|
|
||||||
border-top: 1rpx solid #f0f1f3;
|
|
||||||
background: #ffffff;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,11 @@
|
||||||
|
|
||||||
<up-cell-group :border="false" custom-style="margin: 24rpx; border-radius: 24rpx; overflow: hidden; background: #ffffff;">
|
<up-cell-group :border="false" custom-style="margin: 24rpx; border-radius: 24rpx; overflow: hidden; background: #ffffff;">
|
||||||
<up-cell title="设备配置" is-link @click="goConfig" />
|
<up-cell title="设备配置" is-link @click="goConfig" />
|
||||||
|
<up-cell title="分享的设备" is-link />
|
||||||
<up-cell title="场所管理" is-link />
|
<up-cell title="场所管理" is-link />
|
||||||
|
<up-cell title="接警人管理" is-link />
|
||||||
<up-cell title="手机号" :value="phoneText" is-link />
|
<up-cell title="手机号" :value="phoneText" is-link />
|
||||||
|
<up-cell title="语音广播" is-link />
|
||||||
<up-cell title="当前版本" value="2.8.44" />
|
<up-cell title="当前版本" value="2.8.44" />
|
||||||
<up-cell title="退出登录" @click="logout" />
|
<up-cell title="退出登录" @click="logout" />
|
||||||
</up-cell-group>
|
</up-cell-group>
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 361 B |
Binary file not shown.
|
Before Width: | Height: | Size: 351 B |
Binary file not shown.
|
Before Width: | Height: | Size: 559 B |
Binary file not shown.
|
Before Width: | Height: | Size: 590 B |
Binary file not shown.
|
Before Width: | Height: | Size: 1.0 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 KiB |
Loading…
Reference in New Issue