From bf9400d4198094194439214b5e90036b2f040052 Mon Sep 17 00:00:00 2001
From: wangrong <wangrong@shsening.com>
Date: 星期四, 24 九月 2026 16:03:10 +0800
Subject: [PATCH] bug修复,用真实数据
---
src/modules/base/pages/main/components/amenu.vue | 12
src/modules/base/static/css/index.scss | 4
src/modules/push/views/weight.vue | 44 +
src/modules/base/pages/main/components/topbar.vue | 48 +
src/modules/monitor/views/device.vue | 22
src/modules/report/views/joblog.vue | 13
src/plugins/view/components/group.vue | 6
src/modules/report/components/screen-map-panel.vue | 12
src/modules/report/data/screen-merge.ts | 371 ++++----------
src/modules/push/views/cameragps.vue | 9
src/modules/report/views/screen/map.vue | 77 ++
src/modules/push/views/deviceonoff.vue | 9
src/modules/report/views/screen/participation.vue | 16
src/modules/push/views/devicealarm.vue | 3
index.html | 3
src/modules/push/views/auditlog.vue | 3
src/modules/report/views/dailyvehicle.vue | 13
server.cjs | 87 +++
src/modules/ezuikit/components/ezuikit-player.vue | 5
src/modules/report/views/screen/operation.vue | 11
src/modules/report/hooks/use-screen.ts | 3
src/modules/base/pages/main/components/process.vue | 14
src/modules/operation/views/wastesale.vue | 17
src/modules/report/views/screen/overview.vue | 10
src/modules/base/pages/error/components/error-page.vue | 18
src/modules/report/views/screen/carbon.vue | 10
src/modules/report/components/panel-card.vue | 21
src/modules/report/views/dailysite.vue | 13
src/modules/base/pages/login/index.vue | 32 +
src/modules/push/views/siteweight.vue | 15
src/modules/push/views/vehiclegps.vue | 9
src/modules/base/config.ts | 1
src/modules/base/pages/main/index.vue | 6
src/modules/monitor/views/cameras.vue | 20
src/modules/maps/components/map-board.vue | 25
src/modules/base/static/css/mobile.scss | 253 +++++++++
/dev/null | 210 --------
src/modules/operation/views/traderecord.vue | 3
src/modules/report/views/dailydepartment.vue | 13
src/modules/push/views/compressionweight.vue | 3
src/modules/base/pages/main/components/views.vue | 10
src/modules/report/components/screen-shell.vue | 42 +
42 files changed, 991 insertions(+), 525 deletions(-)
diff --git a/index.html b/index.html
index 1148b64..43dfc09 100644
--- a/index.html
+++ b/index.html
@@ -7,8 +7,9 @@
<meta name="renderer" content="webkit" />
<meta
name="viewport"
- content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=0"
+ content="width=device-width, initial-scale=1, viewport-fit=cover"
/>
+ <meta name="format-detection" content="telephone=no" />
<title></title>
<link rel="icon" href="./favicon.ico" />
<style>
diff --git a/server.cjs b/server.cjs
new file mode 100644
index 0000000..7863c86
--- /dev/null
+++ b/server.cjs
@@ -0,0 +1,87 @@
+/**
+ * 鍓嶇闈欐�佹湇鍔″櫒锛圥M2 鎵樼锛屽澶� :9000锛�
+ * - 鎵樼 dist 闈欐�佽祫婧�
+ * - /api/* 杞彂鍚庣锛堝幓鎺� /api 鍓嶇紑锛�
+ * - /upload/* 杞彂鍚庣
+ * - /socket.io 杞彂鍚庣锛堟敮鎸� WebSocket锛�
+ */
+const path = require('path');
+const express = require('express');
+const { createProxyMiddleware } = require('http-proxy-middleware');
+
+const PORT = Number(process.env.PORT || 9000);
+const BACKEND = process.env.BACKEND || 'http://127.0.0.1:8001';
+const DIST = path.join(__dirname, 'dist');
+
+const onErr = (name) => (err, req, res) => {
+ console.error(`[proxy:${name}]`, err && err.message);
+ if (res && res.writeHead) {
+ res.writeHead(502, { 'Content-Type': 'application/json' });
+ res.end(JSON.stringify({ code: 502, msg: `backend unreachable: ${name}` }));
+ }
+};
+
+const app = express();
+
+// 1) 涓氬姟鎺ュ彛锛�/api/admin/xxx -> /admin/xxx
+app.use(
+ '/api',
+ createProxyMiddleware({
+ target: BACKEND,
+ changeOrigin: true,
+ pathRewrite: { '^/api': '' },
+ ws: false,
+ onError: onErr('api'),
+ })
+);
+
+// 2) 涓婁紶鏂囦欢
+app.use(
+ '/upload',
+ createProxyMiddleware({
+ target: BACKEND,
+ changeOrigin: true,
+ ws: false,
+ onError: onErr('upload'),
+ })
+);
+
+// 3) socket.io锛堝惈 WebSocket锛�
+const socketProxy = createProxyMiddleware({
+ target: BACKEND,
+ changeOrigin: true,
+ ws: true,
+ onError: onErr('socket.io'),
+});
+app.use('/socket.io', socketProxy);
+
+// 4) 鍓嶇闈欐�佽祫婧�
+app.use(
+ express.static(DIST, {
+ maxAge: '7d',
+ index: 'index.html',
+ setHeaders(res, filePath) {
+ if (filePath.endsWith('index.html')) res.setHeader('Cache-Control', 'no-cache');
+ },
+ })
+);
+
+// 5) history 璺敱鍏滃簳锛坔ash 妯″紡涓嶄細璧板埌杩欙級
+// app.get('*', (req, res, next) => {
+// if (req.path.startsWith('/api') || req.path.startsWith('/upload')) return next();
+// res.sendFile(path.join(DIST, 'index.html'), (err) => err && next(err));
+// });
+app.use((req, res, next) => {
+ if (req.path.startsWith('/api') || req.path.startsWith('/upload')) return next();
+ res.sendFile(path.join(DIST, 'index.html'), (err) => err && next(err));
+});
+
+const server = app.listen(PORT, '0.0.0.0', () => {
+ console.log(`[frontend] http://0.0.0.0:${PORT} -> backend ${BACKEND}`);
+});
+
+// WebSocket 鍗囩骇
+server.on('upgrade', socketProxy.upgrade);
+
+process.on('unhandledRejection', (r) => console.error('[unhandledRejection]', r && r.message));
+process.on('uncaughtException', (e) => console.error('[uncaughtException]', e && e.message));
\ No newline at end of file
diff --git a/src/modules/base/config.ts b/src/modules/base/config.ts
index cac5e6f..76e3186 100644
--- a/src/modules/base/config.ts
+++ b/src/modules/base/config.ts
@@ -3,6 +3,7 @@
import { config } from '/@/config';
import { t } from '/@/plugins/i18n';
import './static/css/index.scss';
+import './static/css/mobile.scss';
export default (): ModuleConfig => {
return {
diff --git a/src/modules/base/pages/error/components/error-page.vue b/src/modules/base/pages/error/components/error-page.vue
index bfb7527..3315cb1 100644
--- a/src/modules/base/pages/error/components/error-page.vue
+++ b/src/modules/base/pages/error/components/error-page.vue
@@ -137,4 +137,22 @@
}
}
}
+
+@media only screen and (max-width: 768px) {
+ .error-page {
+ overflow: auto;
+
+ &__code {
+ font-size: 72px;
+ margin-top: 0;
+ }
+
+ &__btns {
+ flex-wrap: wrap;
+ justify-content: center;
+ gap: 10px;
+ padding: 0 16px;
+ }
+ }
+}
</style>
diff --git a/src/modules/base/pages/login/index.vue b/src/modules/base/pages/login/index.vue
index 2a235b8..5a7afd4 100644
--- a/src/modules/base/pages/login/index.vue
+++ b/src/modules/base/pages/login/index.vue
@@ -304,4 +304,36 @@
}
}
}
+
+@media screen and (max-width: 768px) {
+ .page-login {
+ overflow: auto;
+ align-items: flex-start;
+
+ .bg {
+ opacity: 0.25;
+ }
+
+ .box {
+ position: relative;
+ height: auto;
+ min-height: 100%;
+ padding: 48px 20px calc(36px + env(safe-area-inset-bottom));
+ box-sizing: border-box;
+
+ .logo span {
+ font-size: 26px;
+ letter-spacing: 1px;
+ }
+
+ .desc {
+ margin-bottom: 28px;
+ }
+
+ .form {
+ width: min(360px, 100%);
+ }
+ }
+ }
+}
</style>
diff --git a/src/modules/base/pages/main/components/amenu.vue b/src/modules/base/pages/main/components/amenu.vue
index b34000d..f35a988 100644
--- a/src/modules/base/pages/main/components/amenu.vue
+++ b/src/modules/base/pages/main/components/amenu.vue
@@ -148,4 +148,16 @@
margin-left: 8px;
}
}
+
+@media only screen and (max-width: 768px) {
+ .a-menu {
+ min-width: 0;
+ overflow-x: auto;
+
+ &__item {
+ flex-shrink: 0;
+ padding: 0 10px;
+ }
+ }
+}
</style>
diff --git a/src/modules/base/pages/main/components/process.vue b/src/modules/base/pages/main/components/process.vue
index cf82f72..98746c0 100644
--- a/src/modules/base/pages/main/components/process.vue
+++ b/src/modules/base/pages/main/components/process.vue
@@ -276,4 +276,18 @@
}
}
}
+
+@media only screen and (max-width: 768px) {
+ .app-process {
+ padding-left: 6px;
+ padding-right: 6px;
+
+ &__item .close {
+ margin-left: 8px;
+ margin-right: -2px;
+ width: 16px;
+ opacity: 1;
+ }
+ }
+}
</style>
diff --git a/src/modules/base/pages/main/components/topbar.vue b/src/modules/base/pages/main/components/topbar.vue
index 5559d13..a26db38 100644
--- a/src/modules/base/pages/main/components/topbar.vue
+++ b/src/modules/base/pages/main/components/topbar.vue
@@ -188,6 +188,54 @@
}
}
}
+
+@media only screen and (max-width: 768px) {
+ .app-topbar {
+ padding-top: env(safe-area-inset-top);
+ padding-right: 6px;
+ height: calc(46px + env(safe-area-inset-top));
+ min-width: 0;
+
+ .flex1 {
+ min-width: 8px;
+ }
+
+ &__tools {
+ flex-shrink: 0;
+ margin-right: 4px;
+
+ & > li {
+ margin-left: 6px;
+ }
+ }
+
+ &__user {
+ flex-shrink: 0;
+ padding-left: 4px;
+
+ :deep(.el-text) {
+ display: none;
+ }
+ }
+
+ :deep(.route-nav) {
+ min-width: 0;
+ max-width: 46vw;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ :deep(.a-menu) {
+ min-width: 0;
+ overflow-x: auto;
+ }
+
+ :deep(.cl-comm__icon) {
+ width: 32px;
+ height: 32px;
+ }
+ }
+}
</style>
<style lang="scss">
diff --git a/src/modules/base/pages/main/components/views.vue b/src/modules/base/pages/main/components/views.vue
index 0ae0219..50bd056 100644
--- a/src/modules/base/pages/main/components/views.vue
+++ b/src/modules/base/pages/main/components/views.vue
@@ -96,4 +96,14 @@
opacity: 1;
}
}
+
+@media only screen and (max-width: 768px) {
+ .app-views {
+ overflow-x: hidden;
+ overflow-y: auto;
+ -webkit-overflow-scrolling: touch;
+ margin: 0 8px calc(8px + env(safe-area-inset-bottom)) 8px;
+ width: calc(100% - 16px);
+ }
+}
</style>
diff --git a/src/modules/base/pages/main/index.vue b/src/modules/base/pages/main/index.vue
index e078958..620da61 100644
--- a/src/modules/base/pages/main/index.vue
+++ b/src/modules/base/pages/main/index.vue
@@ -67,10 +67,15 @@
}
@media only screen and (max-width: 768px) {
+ position: relative;
+
.app-layout__left {
position: absolute;
left: 0;
+ top: 0;
+ width: min(280px, 86vw);
z-index: 9999;
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
transition:
transform 0.3s cubic-bezier(0.7, 0.3, 0.1, 1),
box-shadow 0.3s cubic-bezier(0.7, 0.3, 0.1, 1);
@@ -78,6 +83,7 @@
.app-layout__right {
width: 100%;
+ min-width: 0;
}
&.is-collapse {
diff --git a/src/modules/base/static/css/index.scss b/src/modules/base/static/css/index.scss
index e31abc7..30f9ca5 100644
--- a/src/modules/base/static/css/index.scss
+++ b/src/modules/base/static/css/index.scss
@@ -1,6 +1,8 @@
#app {
height: 100vh;
- width: 100vw;
+ height: 100dvh;
+ width: 100%;
+ max-width: 100vw;
overflow: hidden;
}
diff --git a/src/modules/base/static/css/mobile.scss b/src/modules/base/static/css/mobile.scss
new file mode 100644
index 0000000..8034af8
--- /dev/null
+++ b/src/modules/base/static/css/mobile.scss
@@ -0,0 +1,253 @@
+/* 鎵嬫満娴忚鍣細鍙湪绐勫睆鐢熸晥锛屾闈㈢鏍峰紡淇濇寔鍘熸牱 */
+@media only screen and (max-width: 768px) {
+ html,
+ body {
+ -webkit-text-size-adjust: 100%;
+ }
+
+ .el-scrollbar__wrap {
+ -webkit-overflow-scrolling: touch;
+ }
+
+ /* 閬垮厤 iOS 鑱氱劍杈撳叆妗嗘椂鑷姩鏀惧ぇ椤甸潰 */
+ .el-form .el-input__inner,
+ .el-form .el-textarea__inner,
+ .el-form .el-select__wrapper,
+ .el-form .el-input__wrapper input {
+ font-size: 16px;
+ }
+
+ .el-dialog:not(.is-fullscreen) {
+ width: calc(100vw - 24px) !important;
+ max-width: calc(100vw - 24px);
+ margin: 12px auto !important;
+ }
+
+ .el-drawer {
+ width: min(100vw, 420px) !important;
+ max-width: 100vw;
+ }
+
+ .el-dialog__body,
+ .cl-dialog .el-dialog__body {
+ max-height: calc(100dvh - 140px);
+ overflow: auto;
+ }
+
+ .cl-search,
+ .cl-form,
+ .el-dialog,
+ .el-drawer {
+ .el-form--inline {
+ .el-form-item {
+ display: flex;
+ margin-right: 0;
+ width: 100%;
+ }
+
+ .el-form-item__content {
+ flex: 1;
+ min-width: 0;
+ }
+ }
+
+ .el-date-editor.el-input,
+ .el-date-editor--daterange,
+ .el-date-editor--datetimerange,
+ .el-select,
+ .el-cascader,
+ .el-input-number {
+ width: 100% !important;
+ max-width: 100%;
+ box-sizing: border-box;
+ }
+ }
+
+ .cl-form .el-col,
+ .el-dialog .el-form .el-col,
+ .cl-search .el-col {
+ flex: 0 0 100%;
+ max-width: 100%;
+ }
+
+ .cl-search,
+ .cl-search-key,
+ .cl-search-key__wrap,
+ .cl-filter {
+ width: 100%;
+ max-width: 100%;
+ }
+
+ .cl-filter {
+ margin-left: 0;
+ margin-right: 0;
+ }
+
+ .cl-pagination.el-pagination {
+ flex-wrap: wrap;
+ justify-content: center;
+ row-gap: 8px;
+ padding-bottom: 4px;
+ }
+
+ .el-pagination__sizes,
+ .el-pagination__jump {
+ display: none !important;
+ }
+
+ .cl-table,
+ .el-table {
+ max-width: 100%;
+ }
+
+ .el-table .cell {
+ word-break: break-word;
+ }
+
+ .el-message-box {
+ width: calc(100vw - 32px) !important;
+ }
+
+ .el-picker__popper,
+ .el-select__popper {
+ max-width: calc(100vw - 16px);
+ }
+
+ .el-date-range-picker {
+ width: calc(100vw - 16px) !important;
+ max-width: calc(100vw - 16px);
+
+ .el-picker-panel__body {
+ min-width: 0 !important;
+ display: flex;
+ flex-direction: column;
+ }
+
+ .el-date-range-picker__content {
+ width: 100%;
+ padding: 8px;
+ }
+ }
+
+ .el-dropdown__popper,
+ .el-popover.el-popper {
+ max-width: calc(100vw - 16px);
+ }
+
+ /* 鎵�鏈変笟鍔¢〉锛氶檺鍒跺湪灞忓箷鍐咃紝鍐呭鍖鸿嚜宸辨粴鍔� */
+ .app-views,
+ .app-views > * {
+ max-width: 100%;
+ min-width: 0;
+ }
+
+ .cl-crud {
+ max-width: 100%;
+ }
+
+ .cl-crud > .cl-row {
+ flex-wrap: wrap;
+ row-gap: 8px;
+ max-width: 100%;
+ }
+
+ .cl-crud > .cl-row > * {
+ max-width: 100%;
+ }
+
+ .cl-crud > .cl-row > .cl-flex1 {
+ flex: 1 1 100%;
+ width: 100%;
+ height: 0;
+ margin: 0;
+ }
+
+ .cl-filter {
+ flex: 1 1 100%;
+ width: 100%;
+ max-width: 100%;
+ margin: 0;
+ box-sizing: border-box;
+
+ .el-select,
+ .el-date-editor,
+ .el-input {
+ flex: 1;
+ width: 100% !important;
+ min-width: 0 !important;
+ }
+ }
+
+ .cl-adv-search,
+ .cl-search.is-inline,
+ .cl-search-key {
+ flex: 1 1 100%;
+ }
+
+ .el-table {
+ width: 100% !important;
+ }
+
+ .el-table__header-wrapper,
+ .el-table__body-wrapper,
+ .el-scrollbar__wrap {
+ max-width: 100%;
+ }
+
+ .el-descriptions__label,
+ .el-descriptions__content {
+ word-break: break-word;
+ }
+
+ .el-tabs__nav-scroll {
+ overflow-x: auto;
+ }
+
+ .el-dialog:not(.is-fullscreen),
+ .cl-dialog:not(.is-fullscreen) {
+ max-height: calc(100dvh - 24px);
+ }
+
+ .cl-dialog__container,
+ .cl-dialog .el-scrollbar {
+ max-height: calc(100dvh - 132px) !important;
+ }
+
+ .w-e-toolbar,
+ .cl-editor-wang {
+ max-width: 100%;
+ overflow-x: auto;
+ }
+
+ .cl-view-group__right .head .title {
+ max-width: calc(100vw - 120px);
+ padding: 0 36px;
+ text-overflow: ellipsis;
+ }
+
+ .error-page__code {
+ font-size: 72px;
+ }
+
+ .plugins__header {
+ flex-wrap: wrap;
+ gap: 8px;
+
+ .search {
+ width: 100% !important;
+ }
+ }
+
+ .cl-upload-space-inner__header {
+ flex-wrap: wrap;
+ height: auto;
+ min-height: 50px;
+ padding: 8px 10px;
+ gap: 8px;
+ }
+
+ .cl-upload-space-inner__file-item {
+ width: calc(50% - 10px) !important;
+ padding-top: calc(50% - 10px) !important;
+ }
+}
diff --git a/src/modules/ezuikit/components/ezuikit-player.vue b/src/modules/ezuikit/components/ezuikit-player.vue
index ed546e9..5cc934d 100644
--- a/src/modules/ezuikit/components/ezuikit-player.vue
+++ b/src/modules/ezuikit/components/ezuikit-player.vue
@@ -171,4 +171,9 @@
padding: 0px;
background: #000;
}
+
+/* 鎵嬫満鎵╁睍鍖洪噷鐨勫渾褰簯鍙般�係DK 鐢� deepmerge 鍚堝苟閰嶇疆鏃舵暟缁勫悎骞讹紝鍗曢潬鍒犳帀 controls 閲岀殑 ptz 鍘讳笉鎺� */
+.ez-player-card :deep(.ez-mobile-ptz) {
+ display: none;
+}
</style>
\ No newline at end of file
diff --git a/src/modules/maps/components/map-board.vue b/src/modules/maps/components/map-board.vue
index 68b7a76..4266880 100644
--- a/src/modules/maps/components/map-board.vue
+++ b/src/modules/maps/components/map-board.vue
@@ -134,4 +134,29 @@
width: 100%;
height: 100%;
}
+
+@media (max-width: 992px) {
+ .map-board {
+ flex-direction: column;
+ height: 100%;
+ overflow: auto;
+ }
+
+ .map-board__side {
+ width: 100%;
+ max-height: 240px;
+ }
+
+ .map-board__map {
+ flex: none;
+ width: 100%;
+ height: 56vh;
+ min-height: 320px;
+ }
+
+ .map-board__panel {
+ width: 100%;
+ max-height: none;
+ }
+}
</style>
diff --git a/src/modules/monitor/views/cameras.vue b/src/modules/monitor/views/cameras.vue
index 94372c4..23ecd10 100644
--- a/src/modules/monitor/views/cameras.vue
+++ b/src/modules/monitor/views/cameras.vue
@@ -257,4 +257,24 @@
border-color: #555 !important;
color: #888 !important;
}
+
+@media (max-width: 768px) {
+ .camera-page {
+ padding: 8px;
+ }
+
+ .scroll-viewport {
+ margin: 0 6px;
+ }
+
+ .player-card {
+ width: min(280px, calc(100vw - 96px));
+ height: 240px;
+ }
+
+ .arrow {
+ width: 28px;
+ height: 64px;
+ }
+}
</style>
\ No newline at end of file
diff --git a/src/modules/monitor/views/device.vue b/src/modules/monitor/views/device.vue
index c2dd1c9..3b91628 100644
--- a/src/modules/monitor/views/device.vue
+++ b/src/modules/monitor/views/device.vue
@@ -117,4 +117,26 @@
font-weight: 500;
}
}
+
+@media (max-width: 768px) {
+ .monitor-page {
+ flex-direction: column;
+ overflow: auto;
+ }
+
+ .left-tree {
+ width: 100%;
+ height: 220px;
+ flex-shrink: 0;
+ }
+
+ .right-player {
+ height: auto;
+ min-height: 360px;
+ }
+
+ .player-grid {
+ grid-template-columns: 1fr !important;
+ }
+}
</style>
\ No newline at end of file
diff --git a/src/modules/operation/views/traderecord.vue b/src/modules/operation/views/traderecord.vue
index a22605f..c178640 100644
--- a/src/modules/operation/views/traderecord.vue
+++ b/src/modules/operation/views/traderecord.vue
@@ -8,6 +8,9 @@
<!-- 鍒犻櫎鎸夐挳 -->
<cl-multi-delete-btn />
<cl-flex1 />
+ <cl-filter label="浜ゆ槗鏃堕棿">
+ <cl-date-picker type="daterange" />
+ </cl-filter>
<cl-import-btn tips="瀵煎叆寰俊浜ゆ槗璁板綍" :on-config="onConfig" :on-submit="onSubmit" />
<!-- 鏉′欢鎼滅储 -->
<cl-search ref="Search" />
diff --git a/src/modules/operation/views/wastesale.vue b/src/modules/operation/views/wastesale.vue
index dd787cc..83867a0 100644
--- a/src/modules/operation/views/wastesale.vue
+++ b/src/modules/operation/views/wastesale.vue
@@ -8,6 +8,9 @@
<!-- 鍒犻櫎鎸夐挳 -->
<cl-multi-delete-btn />
<cl-flex1 />
+ <cl-filter label="鏃ユ湡鏃堕棿">
+ <cl-date-picker type="daterange" />
+ </cl-filter>
<!-- 鏉′欢鎼滅储 -->
<cl-search ref="Search" />
</cl-row>
@@ -260,12 +263,14 @@
service: service.operation.wastesale
},
(app) => {
- service.basicdata.wastetype.page({ isRecyclable: 1, size: 1000 }).then((res) => {
- garbageTypeOptions.value = (res.list || []).map((item: any) => ({
- label: item.name,
- value: item.code,
- price: item.price,
- }));
+ service.basicdata.wastetype.page({ isRecyclable: 1, status: 1, size: 1000 }).then((res) => {
+ garbageTypeOptions.value = (res.list || [])
+ .filter((item: any) => item.status === 1)
+ .map((item: any) => ({
+ label: item.name,
+ value: item.code,
+ price: item.price,
+ }));
});
app.refresh();
}
diff --git a/src/modules/push/views/auditlog.vue b/src/modules/push/views/auditlog.vue
index 089b90b..71cc0e7 100644
--- a/src/modules/push/views/auditlog.vue
+++ b/src/modules/push/views/auditlog.vue
@@ -8,6 +8,9 @@
<!-- 鍒犻櫎鎸夐挳 -->
<cl-multi-delete-btn />
<cl-flex1 />
+ <cl-filter label="鏃ュ織鏃堕棿">
+ <cl-date-picker type="daterange" />
+ </cl-filter>
<!-- 鏉′欢鎼滅储 -->
<cl-search ref="Search" />
</cl-row>
diff --git a/src/modules/push/views/cameragps.vue b/src/modules/push/views/cameragps.vue
index 7ec61ae..f005332 100644
--- a/src/modules/push/views/cameragps.vue
+++ b/src/modules/push/views/cameragps.vue
@@ -7,9 +7,12 @@
<cl-add-btn />
<!-- 鍒犻櫎鎸夐挳 -->
<cl-multi-delete-btn />
- <cl-flex1 />
- <!-- 鏉′欢鎼滅储 -->
- <cl-search ref="Search" />
+ <cl-flex1 />
+ <cl-filter label="娑堟伅鍒涘缓鏃堕棿">
+ <cl-date-picker type="daterange" />
+ </cl-filter>
+ <!-- 鏉′欢鎼滅储 -->
+ <cl-search ref="Search" />
</cl-row>
<cl-row>
diff --git a/src/modules/push/views/compressionweight.vue b/src/modules/push/views/compressionweight.vue
index 3fba788..ebba0dd 100644
--- a/src/modules/push/views/compressionweight.vue
+++ b/src/modules/push/views/compressionweight.vue
@@ -8,6 +8,9 @@
<!-- 鍒犻櫎鎸夐挳 -->
<cl-multi-delete-btn />
<cl-flex1 />
+ <cl-filter label="涓婁紶鏃堕棿">
+ <cl-date-picker type="daterange" />
+ </cl-filter>
<!-- 鏉′欢鎼滅储 -->
<cl-search ref="Search" />
</cl-row>
diff --git a/src/modules/push/views/devicealarm.vue b/src/modules/push/views/devicealarm.vue
index 94b5b7f..02b5a22 100644
--- a/src/modules/push/views/devicealarm.vue
+++ b/src/modules/push/views/devicealarm.vue
@@ -8,6 +8,9 @@
<!-- 鍒犻櫎鎸夐挳 -->
<cl-multi-delete-btn />
<cl-flex1 />
+ <cl-filter label="鎶ヨ鏃堕棿鎴�">
+ <cl-date-picker type="daterange" />
+ </cl-filter>
<!-- 鏉′欢鎼滅储 -->
<cl-search ref="Search" />
</cl-row>
diff --git a/src/modules/push/views/deviceonoff.vue b/src/modules/push/views/deviceonoff.vue
index 73f5ae0..f755f4c 100644
--- a/src/modules/push/views/deviceonoff.vue
+++ b/src/modules/push/views/deviceonoff.vue
@@ -7,9 +7,12 @@
<cl-add-btn />
<!-- 鍒犻櫎鎸夐挳 -->
<cl-multi-delete-btn />
- <cl-flex1 />
- <!-- 鏉′欢鎼滅储 -->
- <cl-search ref="Search" />
+ <cl-flex1 />
+ <cl-filter label="娑堟伅鏃堕棿">
+ <cl-date-picker type="daterange" />
+ </cl-filter>
+ <!-- 鏉′欢鎼滅储 -->
+ <cl-search ref="Search" />
</cl-row>
<cl-row>
diff --git a/src/modules/push/views/siteweight.vue b/src/modules/push/views/siteweight.vue
index 03a8430..e8c5024 100644
--- a/src/modules/push/views/siteweight.vue
+++ b/src/modules/push/views/siteweight.vue
@@ -8,6 +8,9 @@
<!-- 鍒犻櫎鎸夐挳 -->
<cl-multi-delete-btn />
<cl-flex1 />
+ <cl-filter label="涓婁紶鏃堕棿">
+ <cl-date-picker type="daterange" />
+ </cl-filter>
<!-- 鏉′欢鎼滅储 -->
<cl-search ref="Search" />
</cl-row>
@@ -192,11 +195,13 @@
service: service.push.siteweight,
},
(app) => {
- service.basicdata.wastetype.list().then((res) => {
- garbageTypeOptions.value = (res || []).map((item: any) => ({
- label: item.name,
- value: item.code,
- }));
+ service.basicdata.wastetype.list({ status: 1 }).then((res) => {
+ garbageTypeOptions.value = (res || [])
+ .filter((item: any) => item.status === 1)
+ .map((item: any) => ({
+ label: item.name,
+ value: item.code,
+ }));
});
app.refresh();
},
diff --git a/src/modules/push/views/vehiclegps.vue b/src/modules/push/views/vehiclegps.vue
index c90a20f..eee4a55 100644
--- a/src/modules/push/views/vehiclegps.vue
+++ b/src/modules/push/views/vehiclegps.vue
@@ -7,9 +7,12 @@
<cl-add-btn />
<!-- 鍒犻櫎鎸夐挳 -->
<cl-multi-delete-btn />
- <cl-flex1 />
- <!-- 鏉′欢鎼滅储 -->
- <cl-search ref="Search" />
+ <cl-flex1 />
+ <cl-filter label="GPS瀹氫綅鏃堕棿">
+ <cl-date-picker type="daterange" />
+ </cl-filter>
+ <!-- 鏉′欢鎼滅储 -->
+ <cl-search ref="Search" />
</cl-row>
<cl-row>
diff --git a/src/modules/push/views/weight.vue b/src/modules/push/views/weight.vue
index 2581a4e..06bc4b7 100644
--- a/src/modules/push/views/weight.vue
+++ b/src/modules/push/views/weight.vue
@@ -8,6 +8,9 @@
<!-- 鍒犻櫎鎸夐挳 -->
<cl-multi-delete-btn />
<cl-flex1 />
+ <cl-filter label="涓婁紶鏃堕棿">
+ <cl-date-picker type="daterange" />
+ </cl-filter>
<!-- 鏉′欢鎼滅储 -->
<cl-search ref="Search" />
</cl-row>
@@ -33,12 +36,15 @@
name: "push-weight",
});
+import { ref } from "vue";
import { useCrud, useTable, useUpsert, useSearch } from "@cool-vue/crud";
import { useCool } from "/@/cool";
import { useI18n } from "vue-i18n";
const { service } = useCool();
const { t } = useI18n();
+
+const garbageTypeOptions = ref<{ label: string; value: string }[]>([]);
// cl-upsert
const Upsert = useUpsert({
@@ -98,6 +104,7 @@
component: { name: "cl-date-text" },
},
{ label: t("鍨冨溇绫诲瀷"), prop: "garbageType", minWidth: 120 },
+ { label: t("鍨冨溇鍒嗙被"), prop: "garbageName", minWidth: 140 },
{
label: t("鍨冨溇閲嶉噺"),
prop: "weight",
@@ -129,7 +136,34 @@
});
// cl-search
-const Search = useSearch();
+const Search = useSearch({
+ items: [
+ {
+ prop: "deviceNo",
+ component: {
+ name: "el-input",
+ props: {
+ placeholder: t("鎼滅储璁惧鍙�"),
+ clearable: true,
+ },
+ style: { width: "150px" },
+ },
+ },
+ {
+ prop: "garbageType",
+ component: {
+ name: "el-select",
+ props: {
+ placeholder: t("鍨冨溇绫诲瀷"),
+ filterable: true,
+ clearable: true,
+ },
+ options: garbageTypeOptions,
+ style: { width: "180px" },
+ },
+ },
+ ],
+});
// cl-crud
const Crud = useCrud(
@@ -137,6 +171,14 @@
service: service.push.weight,
},
(app) => {
+ service.basicdata.wastetype.list({ status: 1 }).then((res) => {
+ garbageTypeOptions.value = (res || [])
+ .filter((item: any) => item.status === 1)
+ .map((item: any) => ({
+ label: item.name,
+ value: item.code,
+ }));
+ });
app.refresh();
},
);
diff --git a/src/modules/report/components/panel-card.vue b/src/modules/report/components/panel-card.vue
index 0dae349..1165550 100644
--- a/src/modules/report/components/panel-card.vue
+++ b/src/modules/report/components/panel-card.vue
@@ -73,4 +73,25 @@
padding: 8px 8px 12px;
}
}
+
+@media (max-width: 768px) {
+ .panel-card {
+ min-height: 220px;
+
+ &__header {
+ flex-wrap: wrap;
+ align-items: flex-start;
+ padding: 12px 12px 0;
+ }
+
+ &__title {
+ flex-wrap: wrap;
+ }
+
+ &__extra {
+ width: 100%;
+ overflow-x: auto;
+ }
+ }
+}
</style>
diff --git a/src/modules/report/components/screen-map-panel.vue b/src/modules/report/components/screen-map-panel.vue
index 4a7969c..b86dd28 100755
--- a/src/modules/report/components/screen-map-panel.vue
+++ b/src/modules/report/components/screen-map-panel.vue
@@ -253,6 +253,18 @@
}
}
+@media (max-width: 768px) {
+ .map-panel__bar,
+ .map-panel__legend {
+ flex-wrap: wrap;
+ gap: 8px;
+ }
+
+ .map-panel__map {
+ min-height: 280px;
+ }
+}
+
@keyframes map-pulse {
0%,
100% {
diff --git a/src/modules/report/components/screen-shell.vue b/src/modules/report/components/screen-shell.vue
index 23d0b88..117b227 100644
--- a/src/modules/report/components/screen-shell.vue
+++ b/src/modules/report/components/screen-shell.vue
@@ -62,15 +62,11 @@
const current = computed(() => SCREEN_NAV.find(e => e.key === currentKey.value));
-/** 濮嬬粓鐣欏湪棣栭〉璺緞锛岀敤 ?page= 鍒囨崲 pageMap锛岄伩鍏嶈烦鍒� /overview 涓㈡帀瀵艰埅澹� */
+/** 濮嬬粓鐣欏湪棣栭〉璺緞锛岀敤 ?page= 鍒囨崲銆傞粯璁ら〉鏄湴鍥撅紝overview 涔熷繀椤诲甫 page锛屽惁鍒欎細琚В鏋愬洖 map */
function go(key: ScreenKey) {
if (key === currentKey.value) return;
const query = { ...route.query } as Record<string, any>;
- if (key === 'overview') {
- delete query.page;
- } else {
- query.page = key;
- }
+ query.page = key;
router.replace({ path: SCREEN_HOME_PATH, query });
}
@@ -285,4 +281,38 @@
gap: 10px;
flex-shrink: 0;
}
+
+@media (max-width: 992px) {
+ .green-screen__header {
+ flex-wrap: wrap;
+ align-items: flex-start;
+ gap: 8px;
+ }
+
+ .brand {
+ min-width: 0;
+ flex: 1 1 auto;
+ }
+
+ .nav {
+ order: 3;
+ flex: 1 1 100%;
+ }
+
+ .tools {
+ max-width: 100%;
+ overflow-x: auto;
+ }
+}
+
+@media (max-width: 768px) {
+ .green-screen {
+ min-height: 0;
+ height: 100%;
+ }
+
+ .brand__title {
+ font-size: 16px;
+ }
+}
</style>
diff --git a/src/modules/report/data/screen-demo.ts b/src/modules/report/data/screen-demo.ts
deleted file mode 100644
index 097ccf2..0000000
--- a/src/modules/report/data/screen-demo.ts
+++ /dev/null
@@ -1,210 +0,0 @@
-import type { ScreenData, TimeRange } from './screen';
-import { ITEM_COLORS, WASTE_COLORS, buildScreenAxis, structureScreen } from './screen-structure';
-
-function wave(len: number, base: number, amp: number, seed = 0) {
- return Array.from({ length: len }, (_, i) => {
- const v = base + amp * Math.sin((i + seed) * 0.85) + amp * 0.35 * Math.cos((i + seed) * 0.4);
- return Math.max(0, Math.round(v * 10) / 10);
- });
-}
-
-function intWave(len: number, base: number, amp: number, seed = 0) {
- return wave(len, base, amp, seed).map(v => Math.round(v));
-}
-
-function scaleByRange(range: TimeRange) {
- const map: Record<TimeRange, number> = {
- today: 0.08,
- week: 0.28,
- month: 1,
- quarter: 2.8,
- year: 1
- };
- return map[range] ?? 1;
-}
-
-function buildRank(name: string, org: string | undefined, people: number, weight: number, points: number) {
- return {
- name,
- org,
- weight: Math.round(weight * 10) / 10,
- people,
- rate: 0,
- points: Math.round(points),
- carbon: Math.round(weight * 10) / 10,
- size: people,
- weightPerCapita: Math.round((weight / people) * 100) / 100,
- pointPerCapita: Math.round((points / people) * 10) / 10
- };
-}
-
-/** 楗辨弧婕旂ず鏁版嵁锛屽彛寰勪笌鍚庣缁撴瀯涓�鑷� */
-export function demoScreen(range: TimeRange = 'month'): ScreenData {
- const base = structureScreen(range);
- const axis = base.axis.length ? base.axis : buildScreenAxis(range);
- const s = scaleByRange(range);
-
- const periodWeightTon = Math.round(18.6 * s * 100) / 100;
- const recyclableTon = Math.round(7.9 * s * 100) / 100;
- const periodCarbonTon = Math.round(2.14 * s * 100) / 100;
- const periodValue = Math.round(12800 * s);
- const totalWeightTon = 126.8;
- const totalCarbonTon = 14.6;
- const totalParticipants = 3842;
- const totalPoints = 96500;
-
- const wasteWeights = [4200, 3100, 980, 420, 2860].map(v => Math.round(v * s));
- const wasteCounts = [860, 720, 96, 38, 540].map(v => Math.round(v * s));
- const wasteMix = base.wasteMix.map((item, i) => ({
- ...item,
- weight: wasteWeights[i],
- count: wasteCounts[i],
- value: i === 0 ? periodValue : 0,
- color: WASTE_COLORS[item.code || ''] || item.color
- }));
-
- const recycleWeights = [1820, 960, 540, 680, 320, 410, 270].map(v => Math.round(v * s));
- const recycleValues = [4200, 2100, 1800, 960, 480, 3200, 180].map(v => Math.round(v * s));
- const recycleCarbons = recycleWeights.map(w => Math.round(w * 0.42 * 10) / 10);
- const recycleItems = base.recycleItems.map((item, i) => ({
- ...item,
- weight: recycleWeights[i],
- value: recycleValues[i],
- carbon: recycleCarbons[i],
- color: ITEM_COLORS[i]
- }));
-
- const trendWeight = wave(axis.length, 620 * s, 180 * s, 1);
- const trendValue = intWave(axis.length, 420 * s, 120 * s, 2);
- const trendCarbon = wave(axis.length, 860 * s, 220 * s, 3);
-
- const yearCarbon = [0.8, 0.9, 1.1, 1.3, 1.5, 1.8, 2.0, 2.2, 1.9, 1.6, 1.2, 0.9];
-
- const deptRank = [
- buildRank('鐜绉戝涓庡伐绋嬪闄�', undefined, 486, 2860, 12800),
- buildRank('鏉愭枡绉戝涓庡伐绋嬪闄�', undefined, 412, 2410, 10600),
- buildRank('缁忔祹绠$悊瀛﹂櫌', undefined, 368, 1980, 9200),
- buildRank('璁$畻鏈哄闄�', undefined, 352, 1760, 8800),
- buildRank('澶栧浗璇闄�', undefined, 286, 1420, 6400),
- buildRank('鍦熸湪宸ョ▼瀛﹂櫌', undefined, 248, 1180, 5200),
- buildRank('鐢熷懡绉戝瀛﹂櫌', undefined, 216, 960, 4600),
- buildRank('椹厠鎬濅富涔夊闄�', undefined, 168, 720, 3200)
- ];
-
- const classRank = [
- buildRank('鐜2201', '鐜绉戝涓庡伐绋嬪闄�', 68, 420, 1860),
- buildRank('鏉愭枡2102', '鏉愭枡绉戝涓庡伐绋嬪闄�', 62, 386, 1720),
- buildRank('璁$2303', '璁$畻鏈哄闄�', 58, 352, 1580),
- buildRank('缁忕2204', '缁忔祹绠$悊瀛﹂櫌', 54, 318, 1460),
- buildRank('鍦熸湪2101', '鍦熸湪宸ョ▼瀛﹂櫌', 48, 286, 1280),
- buildRank('澶栬2202', '澶栧浗璇闄�', 44, 248, 1120),
- buildRank('鐢熺2301', '鐢熷懡绉戝瀛﹂櫌', 40, 216, 980),
- buildRank('鐜伐2103', '鐜绉戝涓庡伐绋嬪闄�', 36, 198, 860)
- ];
-
- const majorRank = [
- buildRank('鐜宸ョ▼', undefined, 286, 1680, 7600),
- buildRank('鏉愭枡鍖栧', undefined, 248, 1420, 6400),
- buildRank('杞欢宸ョ▼', undefined, 236, 1280, 5800),
- buildRank('宸ュ晢绠$悊', undefined, 218, 1160, 5200),
- buildRank('鑻辫', undefined, 186, 960, 4200),
- buildRank('鍦熸湪宸ョ▼', undefined, 168, 860, 3800),
- buildRank('鐢熺墿鎶�鏈�', undefined, 142, 720, 3200),
- buildRank('鐜绉戝', undefined, 128, 640, 2800)
- ];
-
- const issued = Math.round(186000 * Math.max(s, 0.2));
- const transfer = Math.round(issued * 0.12);
- const donate = Math.round(issued * 0.08);
- const mall = Math.round(issued * 0.46);
- const balance = totalPoints;
-
- const orderAxis = base.ordersByType.axis;
- const ordersByType = {
- axis: orderAxis,
- 鐜板満鍥炴敹: intWave(orderAxis.length, 18 * s, 8 * s, 4),
- 棰勭害涓婇棬: intWave(orderAxis.length, 12 * s, 5 * s, 5),
- 澶у睆鎶曢��: intWave(orderAxis.length, 26 * s, 10 * s, 6),
- 娲诲姩鍥炴敹: intWave(orderAxis.length, 8 * s, 4 * s, 7)
- };
-
- return {
- ...base,
- axis,
- kpis: {
- todayWeightKg: Math.round(286.5 * Math.max(s, 0.15) * 10) / 10,
- periodWeightTon,
- resourceRate: 42.3,
- periodValue,
- periodCarbonTon,
- totalWeightTon,
- totalParticipants,
- totalPoints,
- recyclableTon,
- bulkTon: Math.round(1.8 * s * 100) / 100,
- elecTon: Math.round(0.96 * s * 100) / 100,
- fabricTon: Math.round(1.24 * s * 100) / 100,
- yearCarbonTon: 18.6,
- monthCarbonTon: periodCarbonTon,
- totalCarbonTon,
- greenActions: Math.round(8620 * Math.max(s, 0.2)),
- newParticipants: Math.round(286 * s),
- participateRate: 31.6,
- pointsIssued: issued,
- pointsConsumed: Math.round(issued * 0.54),
- pointsBalance: balance,
- sorterOnline: 12,
- sorterTotal: 16,
- vehicleOnline: 5,
- vehicleTotal: 7,
- siteOnline: 18,
- siteTotal: 22,
- todayOrders: Math.round(46 * Math.max(s, 0.2)),
- todayAppointments: Math.round(28 * Math.max(s, 0.2)),
- pendingAppointments: Math.round(6 * Math.max(s, 0.2)),
- alerts: 2,
- healthAlerts: 1
- },
- wasteMix,
- recycleItems,
- trend: {
- weight: trendWeight,
- value: trendValue,
- carbon: trendCarbon
- },
- yearCarbon,
- deptRank,
- classRank,
- majorRank,
- pointFlow: { issued, transfer, donate, mall, balance },
- participateTrend: intWave(axis.length, 86 * s, 28 * s, 8),
- deliverTrend: intWave(axis.length, 168 * s, 42 * s, 9),
- ordersByType,
- appointmentFlow: [
- { name: '棰勭害', value: Math.round(18 * Math.max(s, 0.2)) },
- { name: '鎺ュ崟', value: Math.round(14 * Math.max(s, 0.2)) },
- { name: '瀹屾垚', value: Math.round(11 * Math.max(s, 0.2)) }
- ],
- sorterStatus: [
- { name: '宸ヤ綔涓�', value: 12, color: '#22c55e' },
- { name: '浼戞伅', value: 2, color: '#f59e0b' },
- { name: '寮傚父', value: 1, color: '#ef4444' },
- { name: '绂荤嚎', value: 1, color: '#94a3b8' }
- ],
- vehicles: [
- { no: '娌狝路8K126', km: 86.4, idle: 12, overspeed: 0, status: '鍦ㄧ嚎' },
- { no: '娌狝路1R441', km: 24.3, idle: 0, overspeed: 0, status: '绂荤嚎' }
- ],
- sites: [
- { name: '瀛︾敓鍏瘬涓�鍙风珯', weight: 286.5, online: true },
- { name: '鍥句功棣嗗洖鏀剁偣', weight: 248.2, online: true },
- { name: '绗竴椋熷爞鏀堕泦鐐�', weight: 216.8, online: true },
- { name: '浣撹偛棣嗗洖鏀剁珯', weight: 186.4, online: true },
- { name: '琛屾斂妤兼敹闆嗙偣', weight: 162.6, online: true },
- { name: '瀹為獙妤糂鍖�', weight: 148.2, online: true },
- { name: '鐮旂┒鐢熷叕瀵撶珯', weight: 126.8, online: false },
- { name: '鍗楅棬涓存椂鐐�', weight: 98.4, online: true }
- ],
- unavailable: []
- };
-}
diff --git a/src/modules/report/data/screen-merge.ts b/src/modules/report/data/screen-merge.ts
index 3f76e64..b820412 100644
--- a/src/modules/report/data/screen-merge.ts
+++ b/src/modules/report/data/screen-merge.ts
@@ -1,12 +1,5 @@
import type { ScreenData, TimeRange } from './screen';
-import { demoScreen } from './screen-demo';
-import {
- FieldTracker,
- KPI_GROUPS,
- groupHasLive,
- resolveDataMode,
- type ScreenDataMode
-} from './screen-field-meta';
+import { FieldTracker, resolveDataMode, type ScreenDataMode } from './screen-field-meta';
import { structureScreen } from './screen-structure';
export type { ScreenDataMode };
@@ -18,271 +11,120 @@
liveFields: string[];
}
-function sum(nums: number[]) {
- return nums.reduce((a, b) => a + (Number(b) || 0), 0);
+function num(v: unknown, fallback = 0) {
+ const n = Number(v);
+ return Number.isFinite(n) ? n : fallback;
}
-function hasPositive(nums: number[]) {
- return nums.some(v => Number(v) > 0);
+function alignSeries(source: number[] | undefined, len: number) {
+ const values = (source || []).map(v => num(v));
+ if (!values.length) return Array.from({ length: len }, () => 0);
+ if (values.length === len) return values;
+ if (values.length > len) return values.slice(values.length - len);
+ return [...Array.from({ length: len - values.length }, () => 0), ...values];
}
-function hasRankData(list: any[]) {
- return list.length > 0 && list.some(e => Number(e?.people) > 0 || Number(e?.weight) > 0);
-}
-
-function pickKpis(
- live: Record<string, number> | undefined,
- demo: Record<string, number>,
- ctx: FieldTracker
-) {
- const out = { ...demo };
- if (!live) {
- Object.values(KPI_GROUPS)
- .flat()
- .forEach(key => ctx.markDemo(`kpis.${key}`));
- return out;
- }
-
- for (const [group, keys] of Object.entries(KPI_GROUPS)) {
- if (groupHasLive(keys, live)) {
- keys.forEach(key => {
- const v = Number(live[key]);
- out[key] = Number.isFinite(v) ? v : demo[key];
- ctx.markLive(`kpis.${key}`);
- });
- } else {
- keys.forEach(key => ctx.markDemo(`kpis.${key}`));
- }
- }
- return out;
-}
-
-function pickArray<T>(
- field: string,
- live: T[] | undefined,
- demo: T[],
- ctx: FieldTracker,
- valid: (v: T[]) => boolean
-) {
- if (live && valid(live)) {
- ctx.markLive(field);
- return live;
- }
- ctx.markDemo(field);
- return demo;
-}
-
-function pickTrend(
- field: string,
- live: { weight: number[]; value: number[]; carbon: number[] } | undefined,
- demo: ScreenData['trend'],
- axis: string[],
- ctx: FieldTracker
-) {
- const valid =
- live &&
- live.weight?.length &&
- (sum(live.weight) > 0 || sum(live.value) > 0 || sum(live.carbon) > 0);
- if (valid) {
- ctx.markLive(field);
- return {
- weight: alignSeries(live!.weight, axis.length, live!.weight[live!.weight.length - 1] || 0),
- value: alignSeries(live!.value, axis.length, live!.value[live!.value.length - 1] || 0),
- carbon: alignSeries(live!.carbon, axis.length, live!.carbon[live!.carbon.length - 1] || 0)
- };
- }
- ctx.markDemo(field);
- return alignTrend(demo, axis.length);
-}
-
-function alignSeries(source: number[], len: number, fill = 0) {
- if (!source?.length) return Array.from({ length: len }, () => fill);
- if (source.length === len) return [...source];
- if (source.length > len) return source.slice(source.length - len);
- return [...Array.from({ length: len - source.length }, () => fill), ...source];
-}
-
-function alignTrend(trend: ScreenData['trend'], len: number) {
- return {
- weight: alignSeries(trend.weight, len),
- value: alignSeries(trend.value, len),
- carbon: alignSeries(trend.carbon, len)
- };
-}
-
-function pickWasteMix(
- live: ScreenData['wasteMix'] | undefined,
- demo: ScreenData['wasteMix'],
- ctx: FieldTracker
-) {
- if (
- live?.length &&
- live.some(e => Number(e.weight) > 0 || Number(e.count) > 0 || Number(e.value) > 0)
- ) {
- ctx.markLive('wasteMix');
- return live.map((item, i) => ({
- ...demo[i],
- ...item,
- color: item.color || demo[i]?.color
- }));
- }
- ctx.markDemo('wasteMix');
- return demo;
-}
-
-function pickRecycleItems(
- live: ScreenData['recycleItems'] | undefined,
- demo: ScreenData['recycleItems'],
- ctx: FieldTracker
-) {
- if (live?.length && live.some(e => Number(e.weight) > 0 || Number(e.value) > 0 || Number(e.carbon) > 0)) {
- ctx.markLive('recycleItems');
- return live.map((item, i) => ({
- ...demo[i],
- ...item,
- color: item.color || demo[i]?.color
- }));
- }
- ctx.markDemo('recycleItems');
- return demo;
-}
-
-function pickPointFlow(
- live: ScreenData['pointFlow'] | undefined,
- demo: ScreenData['pointFlow'],
- ctx: FieldTracker
-) {
- const out = { ...demo };
- if (!live) {
- ctx.markDemo('pointFlow');
- (['issued', 'transfer', 'donate', 'mall', 'balance'] as const).forEach(key =>
- ctx.markDemo(`pointFlow.${key}`)
- );
- return out;
- }
-
- let hasLive = false;
- (['issued', 'transfer', 'donate', 'mall', 'balance'] as const).forEach(key => {
- if (Number(live[key]) > 0) {
- out[key] = live[key];
- ctx.markLive(`pointFlow.${key}`);
- hasLive = true;
- } else {
- ctx.markDemo(`pointFlow.${key}`);
- }
- });
- if (hasLive) ctx.markLive('pointFlow');
- else ctx.markDemo('pointFlow');
- return out;
-}
-
-function pickOrdersByType(
- live: ScreenData['ordersByType'] | undefined,
- demo: ScreenData['ordersByType'],
- ctx: FieldTracker
-) {
- const keys = ['鐜板満鍥炴敹', '棰勭害涓婇棬', '澶у睆鎶曢��', '娲诲姩鍥炴敹'] as const;
- const liveValid = live?.axis?.length && keys.some(k => hasPositive(live[k] || []));
- if (liveValid) {
- ctx.markLive('ordersByType');
- return live!;
- }
- ctx.markDemo('ordersByType');
- return demo;
-}
-
-function pickAppointmentFlow(
- live: ScreenData['appointmentFlow'] | undefined,
- demo: ScreenData['appointmentFlow'],
- ctx: FieldTracker
-) {
- if (live?.length && live.some(e => Number(e.value) > 0)) {
- ctx.markLive('appointmentFlow');
- return live;
- }
- ctx.markDemo('appointmentFlow');
- return demo;
-}
-
-function pickSorterStatus(
- live: ScreenData['sorterStatus'] | undefined,
- demo: ScreenData['sorterStatus'],
- ctx: FieldTracker
-) {
- if (live?.length && sum(live.map(e => Number(e.value))) > 0) {
- ctx.markLive('sorterStatus');
- return live;
- }
- ctx.markDemo('sorterStatus');
- return demo;
-}
-
-function pickAxis(
- live: ScreenData | null | undefined,
- demo: ScreenData,
- structure: ScreenData,
- ctx: FieldTracker
-) {
- const useLiveAxis =
- live?.axis?.length &&
- (sum(live.trend?.weight || []) > 0 ||
- sum(live.participateTrend || []) > 0 ||
- sum(live.deliverTrend || []) > 0 ||
- live.axis.length > 1);
- if (useLiveAxis) {
- ctx.markLive('axis');
- return live!.axis;
- }
- ctx.markDemo('axis');
- return demo.axis.length ? demo.axis : structure.axis;
-}
-
-/** 缁撴瀯 + 婕旂ず + 鐪熷疄鏁版嵁鎸夊瓧娈�/鍒嗙粍鍚堝苟 */
+/** 鐢ㄦ帴鍙g粨鏋滆鐩栭浂鍊肩粨鏋勩�傜己瀛楁淇濇寔 0 鎴栫┖鍒楄〃锛屼笉鍐嶅洖钀藉埌婕旂ず鏁版嵁銆� */
export function resolveScreenData(live: ScreenData | null | undefined, range: TimeRange): ResolvedScreenData {
- const structure = structureScreen(range);
- const demo = demoScreen(range);
+ const base = structureScreen(range);
const ctx = new FieldTracker();
- const axis = pickAxis(live, demo, structure, ctx);
- const kpis = pickKpis(live?.kpis, demo.kpis, ctx);
- const wasteMix = pickWasteMix(live?.wasteMix, demo.wasteMix, ctx);
- const recycleItems = pickRecycleItems(live?.recycleItems, demo.recycleItems, ctx);
- const trend = pickTrend('trend', live?.trend, demo.trend, axis, ctx);
-
- let yearCarbon = demo.yearCarbon;
- if (live?.yearCarbon?.length && sum(live.yearCarbon) > 0) {
- yearCarbon = live.yearCarbon;
- ctx.markLive('yearCarbon');
- } else {
- ctx.markDemo('yearCarbon');
+ if (!live) {
+ return {
+ data: base,
+ mode: 'live',
+ demoFields: [],
+ liveFields: []
+ };
}
- const deptRank = pickArray('deptRank', live?.deptRank, demo.deptRank, ctx, hasRankData);
- const classRank = pickArray('classRank', live?.classRank, demo.classRank, ctx, hasRankData);
- const majorRank = pickArray('majorRank', live?.majorRank, demo.majorRank, ctx, hasRankData);
- const pointFlow = pickPointFlow(live?.pointFlow, demo.pointFlow, ctx);
+ const axis = live.axis?.length ? live.axis : base.axis;
+ ctx.markLive('axis');
- let participateTrend = alignSeries(demo.participateTrend, axis.length);
- if (live?.participateTrend?.length && sum(live.participateTrend) > 0) {
- participateTrend = alignSeries(live.participateTrend, axis.length);
- ctx.markLive('participateTrend');
- } else {
- ctx.markDemo('participateTrend');
- }
+ const kpis = { ...base.kpis };
+ Object.keys(kpis).forEach(key => {
+ if (live.kpis && live.kpis[key] != null) {
+ kpis[key] = num(live.kpis[key]);
+ }
+ ctx.markLive(`kpis.${key}`);
+ });
- let deliverTrend = alignSeries(demo.deliverTrend, axis.length);
- if (live?.deliverTrend?.length && sum(live.deliverTrend) > 0) {
- deliverTrend = alignSeries(live.deliverTrend, axis.length);
- ctx.markLive('deliverTrend');
- } else {
- ctx.markDemo('deliverTrend');
- }
+ const wasteMix = live.wasteMix?.length
+ ? live.wasteMix.map((item, i) => ({
+ ...base.wasteMix[i],
+ ...item,
+ weight: num(item.weight),
+ value: num(item.value),
+ count: num(item.count),
+ color: item.color || base.wasteMix[i]?.color
+ }))
+ : base.wasteMix;
+ ctx.markLive('wasteMix');
- const ordersByType = pickOrdersByType(live?.ordersByType, demo.ordersByType, ctx);
- const appointmentFlow = pickAppointmentFlow(live?.appointmentFlow, demo.appointmentFlow, ctx);
- const sorterStatus = pickSorterStatus(live?.sorterStatus, demo.sorterStatus, ctx);
- const vehicles = pickArray('vehicles', live?.vehicles, demo.vehicles, ctx, v => v.length > 0);
- const sites = pickArray('sites', live?.sites, demo.sites, ctx, v => v.length > 0);
+ const recycleItems = live.recycleItems?.length
+ ? live.recycleItems.map((item, i) => ({
+ ...base.recycleItems[i],
+ ...item,
+ weight: num(item.weight),
+ value: num(item.value),
+ carbon: num(item.carbon),
+ color: item.color || base.recycleItems[i]?.color
+ }))
+ : base.recycleItems;
+ ctx.markLive('recycleItems');
+
+ const trend = {
+ weight: alignSeries(live.trend?.weight, axis.length),
+ value: alignSeries(live.trend?.value, axis.length),
+ carbon: alignSeries(live.trend?.carbon, axis.length)
+ };
+ ctx.markLive('trend');
+
+ const yearCarbon = live.yearCarbon?.length
+ ? alignSeries(live.yearCarbon, 12)
+ : base.yearCarbon;
+ ctx.markLive('yearCarbon');
+
+ const deptRank = Array.isArray(live.deptRank) ? live.deptRank : [];
+ const classRank = Array.isArray(live.classRank) ? live.classRank : [];
+ const majorRank = Array.isArray(live.majorRank) ? live.majorRank : [];
+ ctx.markLive('deptRank');
+ ctx.markLive('classRank');
+ ctx.markLive('majorRank');
+
+ const pointFlow = {
+ issued: num(live.pointFlow?.issued),
+ transfer: num(live.pointFlow?.transfer),
+ donate: num(live.pointFlow?.donate),
+ mall: num(live.pointFlow?.mall),
+ balance: num(live.pointFlow?.balance)
+ };
+ ctx.markLive('pointFlow');
+
+ const participateTrend = alignSeries(live.participateTrend, axis.length);
+ const deliverTrend = alignSeries(live.deliverTrend, axis.length);
+ ctx.markLive('participateTrend');
+ ctx.markLive('deliverTrend');
+
+ const ordersByType = live.ordersByType?.axis?.length
+ ? {
+ axis: live.ordersByType.axis,
+ 鐜板満鍥炴敹: alignSeries(live.ordersByType.鐜板満鍥炴敹, live.ordersByType.axis.length),
+ 棰勭害涓婇棬: alignSeries(live.ordersByType.棰勭害涓婇棬, live.ordersByType.axis.length),
+ 澶у睆鎶曢��: alignSeries(live.ordersByType.澶у睆鎶曢��, live.ordersByType.axis.length),
+ 娲诲姩鍥炴敹: alignSeries(live.ordersByType.娲诲姩鍥炴敹, live.ordersByType.axis.length)
+ }
+ : base.ordersByType;
+ ctx.markLive('ordersByType');
+
+ const appointmentFlow = live.appointmentFlow?.length ? live.appointmentFlow : base.appointmentFlow;
+ const sorterStatus = live.sorterStatus?.length ? live.sorterStatus : base.sorterStatus;
+ const vehicles = Array.isArray(live.vehicles) ? live.vehicles : [];
+ const sites = Array.isArray(live.sites) ? live.sites : [];
+ ctx.markLive('appointmentFlow');
+ ctx.markLive('sorterStatus');
+ ctx.markLive('vehicles');
+ ctx.markLive('sites');
const data: ScreenData = {
range,
@@ -303,21 +145,20 @@
sorterStatus,
vehicles,
sites,
- unavailable: live?.unavailable || []
+ unavailable: live.unavailable || []
};
return {
data,
mode: resolveDataMode(live, ctx),
- demoFields: ctx.listDemo(),
+ demoFields: [],
liveFields: ctx.listLive()
};
}
-/** 鎺ュ彛澶辫触鎴栨棤 live 鏁版嵁鏃剁殑鍒濆灞曠ず */
+/** 鎺ュ彛灏氭湭杩斿洖鏃跺厛灞曠ず闆跺�硷紝閬垮厤鍏堥棯鍑烘紨绀烘暟瀛� */
export function initialScreenData(range: TimeRange = 'month') {
return resolveScreenData(null, range);
}
export { structureScreen, buildScreenAxis } from './screen-structure';
-export { demoScreen } from './screen-demo';
diff --git a/src/modules/report/hooks/use-screen.ts b/src/modules/report/hooks/use-screen.ts
index 0b7dc34..bababc0 100644
--- a/src/modules/report/hooks/use-screen.ts
+++ b/src/modules/report/hooks/use-screen.ts
@@ -103,7 +103,6 @@
} catch (e: any) {
applyResolved(resolveScreenData(null, sharedTimeRange.value));
const msg = e?.message || '';
- // 棣栭〉闈欓粯闄嶇骇鍒版紨绀烘暟鎹紝涓嶅睍绀虹櫥褰�/鏉冮檺绫婚敊璇枃妗�
if (!/鐧诲綍澶辨晥|鏃犳潈闄�/.test(msg)) {
loadError.value = msg || '椹鹃┒鑸辨帴鍙h皟鐢ㄥけ璐�';
}
@@ -124,7 +123,7 @@
return { load, loading, loadError, dataMode };
}
-/** 棣栭〉涓嶅睍绀恒�屾紨绀恒�嶆爣璇嗭紝搴曞眰浠嶅彲闈欓粯浣跨敤婕旂ず鏁版嵁濉厖 */
+/** 棣栭〉鍙睍绀烘帴鍙f眹鎬荤粨鏋滐紝涓嶅啀鐢ㄦ紨绀烘暟鎹~鍏� */
export function useScreenFieldSource() {
const { dataMode, demoFields } = useScreenData();
diff --git a/src/modules/report/views/dailydepartment.vue b/src/modules/report/views/dailydepartment.vue
index 3fcedab..77a879a 100644
--- a/src/modules/report/views/dailydepartment.vue
+++ b/src/modules/report/views/dailydepartment.vue
@@ -8,6 +8,9 @@
<!-- 鍒犻櫎鎸夐挳 -->
<!--cl-multi-delete-btn /-->
<cl-flex1 />
+ <cl-filter label="鏃ユ湡">
+ <cl-date-picker type="daterange" />
+ </cl-filter>
<!-- 鏉′欢鎼滅储 -->
<cl-search ref="Search" />
</cl-row>
@@ -504,7 +507,15 @@
});
// cl-search
-const Search = useSearch();
+function hideDateSearch({ exposed }: { exposed: any }) {
+ const items = exposed.config?.items as { prop?: string }[] | undefined;
+ const index = items?.findIndex(e => e.prop === "date") ?? -1;
+ if (index >= 0) items?.splice(index, 1);
+}
+
+const Search = useSearch({
+ plugins: [hideDateSearch]
+});
// cl-crud
const Crud = useCrud(
diff --git a/src/modules/report/views/dailysite.vue b/src/modules/report/views/dailysite.vue
index 19a0d3b..424856a 100644
--- a/src/modules/report/views/dailysite.vue
+++ b/src/modules/report/views/dailysite.vue
@@ -8,6 +8,9 @@
<!-- 鍒犻櫎鎸夐挳 -->
<!--cl-multi-delete-btn /-->
<cl-flex1 />
+ <cl-filter label="鏃ユ湡">
+ <cl-date-picker type="daterange" />
+ </cl-filter>
<!-- 鏉′欢鎼滅储 -->
<cl-search ref="Search" />
</cl-row>
@@ -508,7 +511,15 @@
});
// cl-search
-const Search = useSearch();
+function hideDateSearch({ exposed }: { exposed: any }) {
+ const items = exposed.config?.items as { prop?: string }[] | undefined;
+ const index = items?.findIndex(e => e.prop === "date") ?? -1;
+ if (index >= 0) items?.splice(index, 1);
+}
+
+const Search = useSearch({
+ plugins: [hideDateSearch]
+});
// cl-crud
const Crud = useCrud(
diff --git a/src/modules/report/views/dailyvehicle.vue b/src/modules/report/views/dailyvehicle.vue
index 063aefd..fe6c49e 100644
--- a/src/modules/report/views/dailyvehicle.vue
+++ b/src/modules/report/views/dailyvehicle.vue
@@ -8,6 +8,9 @@
<!-- 鍒犻櫎鎸夐挳 -->
<!--cl-multi-delete-btn /-->
<cl-flex1 />
+ <cl-filter label="鏁版嵁鏃ユ湡">
+ <cl-date-picker type="daterange" />
+ </cl-filter>
<!-- 鏉′欢鎼滅储 -->
<cl-search ref="Search" />
</cl-row>
@@ -262,7 +265,15 @@
});
// cl-search
-const Search = useSearch();
+function hideDateSearch({ exposed }: { exposed: any }) {
+ const items = exposed.config?.items as { prop?: string }[] | undefined;
+ const index = items?.findIndex(e => e.prop === "date") ?? -1;
+ if (index >= 0) items?.splice(index, 1);
+}
+
+const Search = useSearch({
+ plugins: [hideDateSearch]
+});
// cl-crud
const Crud = useCrud(
diff --git a/src/modules/report/views/joblog.vue b/src/modules/report/views/joblog.vue
index 15d4d1b..70be24a 100644
--- a/src/modules/report/views/joblog.vue
+++ b/src/modules/report/views/joblog.vue
@@ -8,6 +8,9 @@
<!-- 鍒犻櫎鎸夐挳 -->
<!--cl-multi-delete-btn /-->
<cl-flex1 />
+ <cl-filter label="鏃ユ湡">
+ <cl-date-picker type="daterange" />
+ </cl-filter>
<!-- 鏉′欢鎼滅储 -->
<cl-search ref="Search" />
</cl-row>
@@ -173,7 +176,15 @@
});
// cl-search
-const Search = useSearch();
+function hideDateSearch({ exposed }: { exposed: any }) {
+ const items = exposed.config?.items as { prop?: string }[] | undefined;
+ const index = items?.findIndex(e => e.prop === "dataDate") ?? -1;
+ if (index >= 0) items?.splice(index, 1);
+}
+
+const Search = useSearch({
+ plugins: [hideDateSearch]
+});
// cl-crud
const Crud = useCrud(
diff --git a/src/modules/report/views/screen/carbon.vue b/src/modules/report/views/screen/carbon.vue
index afd9980..3121ae7 100644
--- a/src/modules/report/views/screen/carbon.vue
+++ b/src/modules/report/views/screen/carbon.vue
@@ -1,6 +1,6 @@
<template>
<div class="screen-page">
- <div class="kpi-grid" style="--kpi-cols: 6">
+ <div class="kpi-grid" style="--kpi-cols: 5">
<kpi-card v-for="item in kpis" :key="item.label" v-bind="item" />
</div>
@@ -45,16 +45,20 @@
import { computed } from 'vue';
import KpiCard from '../../components/kpi-card.vue';
import PanelCard from '../../components/panel-card.vue';
+import { TIME_RANGE_OPTIONS } from '../../data/screen';
import { useChartTheme, useScreenData, useScreenFieldSource } from '../../hooks/use-screen';
const { data, timeRange } = useScreenData();
const { isDemoSection } = useScreenFieldSource();
const { textColor, mutedColor, splitColor, primary, baseGrid, axisStyle, tooltip } = useChartTheme();
+const rangeLabel = computed(
+ () => TIME_RANGE_OPTIONS.find(e => e.value === timeRange.value)?.label || '鏈尯闂�'
+);
+
const kpis = computed(() => [
{ field: 'kpis.totalCarbonTon', label: '绱纰冲噺鎺�', value: data.value.kpis.totalCarbonTon, suffix: '鍚–O鈧俥', fixed: 1 },
- { field: 'kpis.yearCarbonTon', label: '鏈勾搴︾⒊鍑忔帓', value: data.value.kpis.yearCarbonTon, suffix: '鍚–O鈧俥', fixed: 1 },
- { field: 'kpis.periodCarbonTon', label: '鏈尯闂寸⒊鍑忔帓', value: data.value.kpis.periodCarbonTon, suffix: '鍚–O鈧俥', fixed: 2 },
+ { field: 'kpis.periodCarbonTon', label: `${rangeLabel.value}纰冲噺鎺抈, value: data.value.kpis.periodCarbonTon, suffix: '鍚–O鈧俥', fixed: 2 },
{ field: 'kpis.totalWeightTon', label: '绱璧勬簮鍥炴敹', value: data.value.kpis.totalWeightTon, suffix: '鍚�', fixed: 1 },
{ field: 'kpis.totalParticipants', label: '绱鍙備笌甯堢敓', value: data.value.kpis.totalParticipants, suffix: '浜�', fixed: 0 },
{ field: 'kpis.greenActions', label: '绱鐜繚琛屼负', value: data.value.kpis.greenActions, suffix: '娆�', fixed: 0 }
diff --git a/src/modules/report/views/screen/map.vue b/src/modules/report/views/screen/map.vue
index cd966e8..9d6faaa 100755
--- a/src/modules/report/views/screen/map.vue
+++ b/src/modules/report/views/screen/map.vue
@@ -1,7 +1,7 @@
<template>
<div class="screen-page dash">
<!-- KPI 鎸囨爣鏉� -->
- <div class="kpi-grid" style="--kpi-cols: 8">
+ <div class="kpi-grid" style="--kpi-cols: 7">
<kpi-card v-for="item in kpis" :key="item.label" v-bind="item" />
</div>
@@ -57,7 +57,7 @@
<template #extra>
<cl-select-button v-model="itemMetric" :options="itemOptions" small />
</template>
- <v-chart :option="itemOption" autoresize class="chart" />
+ <v-chart :option="itemOption" autoresize class="chart chart--items" />
</panel-card>
</div>
</div>
@@ -84,9 +84,10 @@
import PanelCard from '../../components/panel-card.vue';
import ScreenMapPanel from '../../components/screen-map-panel.vue';
import CameraMonitor from '../../../monitor/views/cameras.vue';
+import { TIME_RANGE_OPTIONS } from '../../data/screen';
import { useChartTheme, useScreenData, useScreenFieldSource } from '../../hooks/use-screen';
-const { data } = useScreenData();
+const { data, timeRange } = useScreenData();
const { isDemoSection } = useScreenFieldSource();
const { textColor, mutedColor, splitColor, primary, baseGrid, axisStyle, tooltip } = useChartTheme();
@@ -112,10 +113,13 @@
{ label: '纰冲噺鎺�', value: 'carbon' }
];
-/** 椤堕儴 KPI锛氬彇鎬昏鍩熸牳蹇� 8 椤� */
+const rangeLabel = computed(
+ () => TIME_RANGE_OPTIONS.find(e => e.value === timeRange.value)?.label || '鏈尯闂�'
+);
+
+/** 椤堕儴 KPI */
const kpis = computed(() => [
- { field: 'kpis.todayWeightKg', label: '浠婃棩鍥炴敹閲�', value: data.value.kpis.todayWeightKg, suffix: 'kg', fixed: 1 },
- { field: 'kpis.periodWeightTon', label: '鏈尯闂村洖鏀堕噺', value: data.value.kpis.periodWeightTon, suffix: '鍚�', fixed: 2 },
+ { field: 'kpis.periodWeightTon', label: `${rangeLabel.value}鍥炴敹閲廯, value: data.value.kpis.periodWeightTon, suffix: '鍚�', fixed: 2 },
{ field: 'kpis.resourceRate', label: '璧勬簮鍖栫巼', value: data.value.kpis.resourceRate, suffix: '%', fixed: 1 },
{ field: 'kpis.periodValue', label: '鍥炴敹浠峰��', value: data.value.kpis.periodValue, suffix: '鍏�', fixed: 0 },
{ field: 'kpis.periodCarbonTon', label: '纰冲噺鎺�', value: data.value.kpis.periodCarbonTon, suffix: '鍚–O鈧俥', fixed: 2 },
@@ -353,4 +357,65 @@
}
}
}
+
+@media (max-width: 768px) {
+ .dash,
+ .dash-body,
+ .dash-col {
+ height: auto;
+ min-height: 0;
+ overflow: visible;
+ flex: none;
+ }
+
+ .dash :deep(.kpi-grid) {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+
+ .dash-card--flex {
+ flex: none;
+ height: auto;
+ min-height: 0;
+ overflow: visible;
+
+ :deep(.panel-card) {
+ height: auto;
+ min-height: 0;
+ overflow: visible;
+ }
+
+ :deep(.panel-card__body) {
+ flex: none;
+ height: auto;
+ min-height: 0;
+ overflow: visible;
+ }
+ }
+
+ /* 鍦板浘鐢诲竷灞傜骇寰堥珮锛岄檺鍒跺湪涓爮鍐咃紝閬垮厤鐩栦綇涓婁笅涓ゅ潡鍥捐〃 */
+ .dash-card--map {
+ position: relative;
+ z-index: 0;
+ flex: none;
+ height: 480px;
+ min-height: 480px;
+ overflow: hidden;
+ }
+
+ .dash .chart {
+ display: block;
+ height: 260px;
+ min-height: 260px;
+ }
+
+ .dash .chart--items {
+ height: 420px;
+ min-height: 420px;
+ }
+
+ .dash-foot {
+ height: auto;
+ min-height: 300px;
+ }
+}
</style>
\ No newline at end of file
diff --git a/src/modules/report/views/screen/operation.vue b/src/modules/report/views/screen/operation.vue
index a75df31..dc5a267 100644
--- a/src/modules/report/views/screen/operation.vue
+++ b/src/modules/report/views/screen/operation.vue
@@ -323,4 +323,15 @@
}
}
+
+@media (max-width: 768px) {
+ .screen-page .table {
+ overflow-x: auto;
+ }
+
+ .screen-page .table--vehicle :deep(.table__head),
+ .screen-page .table--vehicle .table__row {
+ min-width: 520px;
+ }
+}
</style>
diff --git a/src/modules/report/views/screen/overview.vue b/src/modules/report/views/screen/overview.vue
index c35bd22..8dba391 100644
--- a/src/modules/report/views/screen/overview.vue
+++ b/src/modules/report/views/screen/overview.vue
@@ -1,6 +1,6 @@
<template>
<div class="screen-page">
- <div class="kpi-grid" style="--kpi-cols: 8">
+ <div class="kpi-grid" style="--kpi-cols: 7">
<kpi-card v-for="item in kpis" :key="item.label" v-bind="item" />
</div>
@@ -51,6 +51,7 @@
import KpiCard from '../../components/kpi-card.vue';
import PanelCard from '../../components/panel-card.vue';
import ScreenCameraPreview from '../../components/screen-camera-preview.vue';
+import { TIME_RANGE_OPTIONS } from '../../data/screen';
import { useChartTheme, useScreenData, useScreenFieldSource } from '../../hooks/use-screen';
const { data, timeRange } = useScreenData();
@@ -72,9 +73,12 @@
{ label: '纰冲噺鎺�', value: 'carbon' }
];
+const rangeLabel = computed(
+ () => TIME_RANGE_OPTIONS.find(e => e.value === timeRange.value)?.label || '鏈尯闂�'
+);
+
const kpis = computed(() => [
- { field: 'kpis.todayWeightKg', label: '浠婃棩鍥炴敹閲�', value: data.value.kpis.todayWeightKg, suffix: 'kg', fixed: 1, hint: '瀹炴椂绉伴噸姹囨��' },
- { field: 'kpis.periodWeightTon', label: '鏈尯闂村洖鏀堕噺', value: data.value.kpis.periodWeightTon, suffix: '鍚�', fixed: 2, hint: '褰撳墠鏃堕棿鑼冨洿' },
+ { field: 'kpis.periodWeightTon', label: `${rangeLabel.value}鍥炴敹閲廯, value: data.value.kpis.periodWeightTon, suffix: '鍚�', fixed: 2, hint: '褰撳墠鏃堕棿鑼冨洿' },
{ field: 'kpis.resourceRate', label: '璧勬簮鍖栫巼', value: data.value.kpis.resourceRate, suffix: '%', fixed: 1, hint: '鍙洖鏀剁墿閲嶉噺/鎬婚噸閲忥紝涓嶅惈澶т欢' },
{ field: 'kpis.periodValue', label: '鍥炴敹浠峰��', value: data.value.kpis.periodValue, suffix: '鍏�', fixed: 0, hint: '鏃ヨ〃浼扮畻閿�鍞' },
{ field: 'kpis.periodCarbonTon', label: '纰冲噺鎺�', value: data.value.kpis.periodCarbonTon, suffix: '鍚–O鈧俥', fixed: 2, hint: '鍒嗙被閲嶉噺 脳 纰冲噺鍥犳暟' },
diff --git a/src/modules/report/views/screen/participation.vue b/src/modules/report/views/screen/participation.vue
index 5b839c9..270153c 100644
--- a/src/modules/report/views/screen/participation.vue
+++ b/src/modules/report/views/screen/participation.vue
@@ -69,10 +69,10 @@
import { computed, ref } from 'vue';
import KpiCard from '../../components/kpi-card.vue';
import PanelCard from '../../components/panel-card.vue';
-import { type RankMetric } from '../../data/screen';
+import { TIME_RANGE_OPTIONS, type RankMetric } from '../../data/screen';
import { useChartTheme, useScreenData, useScreenFieldSource } from '../../hooks/use-screen';
-const { data } = useScreenData();
+const { data, timeRange } = useScreenData();
const { isDemoSection } = useScreenFieldSource();
const { textColor, mutedColor, splitColor, primary, baseGrid, axisStyle, tooltip } = useChartTheme();
@@ -99,10 +99,14 @@
{ label: '纰冲噺鎺�', value: 'carbon' }
];
+const rangeLabel = computed(
+ () => TIME_RANGE_OPTIONS.find(e => e.value === timeRange.value)?.label || '鏈尯闂�'
+);
+
const kpis = computed(() => [
{ field: 'kpis.totalParticipants', label: '鍙備笌甯堢敓', value: data.value.kpis.totalParticipants, suffix: '浜�', fixed: 0 },
{ field: 'kpis.participateRate', label: '鍙備笌鐜�', value: data.value.kpis.participateRate, suffix: '%', fixed: 1, hint: '鍙備笌浜烘暟 / 鍙傛暟 student.count.{閮ㄩ棬ID}' },
- { field: 'kpis.newParticipants', label: '鏈尯闂存柊澧炲弬涓�', value: data.value.kpis.newParticipants, suffix: '浜�', fixed: 0, hint: '鍖洪棿鍐呭嚭鐜拌繃鐨勫幓閲嶇敤鎴�' },
+ { field: 'kpis.newParticipants', label: `${rangeLabel.value}鏂板鍙備笌`, value: data.value.kpis.newParticipants, suffix: '浜�', fixed: 0, hint: '鍖洪棿鍐呭嚭鐜拌繃鐨勫幓閲嶇敤鎴�' },
{ field: 'kpis.pointsIssued', label: '纰崇Н鍒嗗彂鏀�', value: data.value.kpis.pointsIssued, suffix: '鍒�', fixed: 0 },
{ field: 'kpis.pointsConsumed', label: '纰崇Н鍒嗘秷璐�', value: data.value.kpis.pointsConsumed, suffix: '鍒�', fixed: 0 },
{ field: 'kpis.pointsBalance', label: '纰崇Н鍒嗕綑棰�', value: data.value.kpis.pointsBalance, suffix: '鍒�', fixed: 0 }
@@ -252,4 +256,10 @@
}
}
}
+
+@media (max-width: 576px) {
+ .screen-page .flow__split {
+ grid-template-columns: 1fr;
+ }
+}
</style>
diff --git a/src/plugins/view/components/group.vue b/src/plugins/view/components/group.vue
index c9991f6..7290912 100644
--- a/src/plugins/view/components/group.vue
+++ b/src/plugins/view/components/group.vue
@@ -680,6 +680,12 @@
}
@media only screen and (max-width: 768px) {
+ .cl-view-group__right .head .title {
+ max-width: calc(100% - 88px);
+ text-overflow: ellipsis;
+ padding: 0 8px;
+ }
+
.cl-view-group__left {
overflow: hidden;
transition: width 0.2s;
--
Gitblit v1.9.1