Przeglądaj źródła

总览完成灾害预警记录模块

chauncey 1 rok temu
rodzic
commit
6890e2165d

+ 1 - 1
mock/login/routers.ts

@@ -4,7 +4,7 @@ const list = [
   {
     children: [
       {
-        component: '/todo/todo',
+        component: '/disaster/overview/PageOverview',
         id: 1025,
         meta: {
           activeMenu: null,

+ 3 - 0
src/main.ts

@@ -4,6 +4,9 @@ import './main.scss';
 import 'element-plus/dist/index.css';
 import App from './App.vue';
 import { setupElement } from '@/plugins';
+import dayjs from 'dayjs';
+import 'dayjs/locale/zh-cn';
+dayjs.locale('zh-cn');
 
 async function bootstrap() {
   const app = createApp(App);

+ 230 - 0
src/views/disaster/overview/PageOverview.vue

@@ -0,0 +1,230 @@
+<template>
+  <div class="overview-container">
+    <header class="overview-container__header"> </header>
+    <main class="overview-container__main">
+      <section class="left-info-section">
+        <div class="today-weather">
+          <header class="today-weather__header">
+            <div class="banner">
+              <div class="line"></div>
+              <span class="title">今日天气</span>
+            </div>
+            <div class="location-and-time">
+              <span>上海市</span>
+              <div class="time">
+                <span>{{ currentDate }}</span>
+                <span>{{ currentWeek }}</span>
+                <span>{{ currentTime }}</span>
+              </div>
+            </div>
+          </header>
+          <div class="info-box"> </div>
+        </div>
+        <div class="left-info-section__bottom-box">
+          <div class="disaster-warning-record">
+            <header class="disaster-warning-record__header">
+              <div class="banner">
+                <div class="line"></div>
+                <span class="title">灾害预警记录</span>
+              </div>
+            </header>
+            <main class="disaster-warning-record__main">
+              <DisasterWarning />
+            </main>
+          </div>
+          <div class="bottom-box--right-item">
+            <div class="disaster-loss-and-loss-record">
+              <header class="disaster-loss-and-loss-record__header">
+                <div class="banner">
+                  <div class="line"></div>
+                  <span class="title">灾害检查及损失记录</span>
+                </div>
+              </header>
+            </div>
+            <div class="defensive-notice-and-regulation">
+              <header class="defensive-notice-and-regulation__header">
+                <div class="banner">
+                  <div class="line"></div>
+                  <span class="title">防御通知和规定</span>
+                </div>
+              </header>
+            </div>
+          </div>
+        </div>
+      </section>
+      <section class="right-info-section">
+        <header class="right-info-section__header">
+          <div class="banner">
+            <div class="line"></div>
+            <span class="title">重点区域视频监控</span>
+          </div>
+        </header>
+      </section>
+    </main>
+  </div>
+</template>
+
+<script setup lang="ts">
+  import { ref, onMounted, onUnmounted } from 'vue';
+  import DisasterWarning from './src/components/DisasterWarning.vue';
+  import dayjs from 'dayjs';
+
+  const currentDate = ref('');
+  const currentWeek = ref('');
+  const currentTime = ref('');
+
+  // 更新时间函数
+  const updateDateTime = () => {
+    const now = dayjs();
+    currentDate.value = now.format('MM月DD日');
+    currentWeek.value = `星期${now.format('dd').slice(-1)}`;
+    currentTime.value = now.format('HH:mm:ss');
+  };
+
+  let timer: NodeJS.Timeout;
+
+  onMounted(() => {
+    updateDateTime();
+    timer = setInterval(updateDateTime, 1000);
+  });
+
+  onUnmounted(() => {
+    clearInterval(timer);
+  });
+</script>
+
+<style scoped lang="scss">
+  .banner {
+    display: flex;
+    align-items: center;
+    gap: 15cpx;
+    .line {
+      width: 3cpx;
+      height: 16cpx;
+      background-color: $primary-color;
+    }
+    .title {
+      font-size: 16cpx;
+      font-weight: 600;
+      color: $text-color;
+    }
+  }
+  .overview-container {
+    @include flex-center;
+    flex-direction: column;
+    gap: 10cpx;
+    width: 100%;
+    height: 100%;
+    background-color: $background-color;
+    &__header {
+      width: 100%;
+      height: 40cpx;
+      border-radius: 8cpx;
+      background-color: #fff1b8;
+    }
+    &__main {
+      @include flex-center;
+      gap: 10cpx;
+      width: 100%;
+      flex: 1;
+    }
+  }
+  .left-info-section,
+  .right-info-section {
+    height: 100%;
+  }
+  .left-info-section {
+    display: flex;
+    flex-direction: column;
+    gap: 10cpx;
+    flex: 1;
+    &__bottom-box {
+      display: flex;
+      gap: 10cpx;
+      width: 100%;
+      flex: 1;
+    }
+  }
+  .disaster-warning-record,
+  .disaster-loss-and-loss-record,
+  .defensive-notice-and-regulation,
+  .right-info-section {
+    display: flex;
+    flex-direction: column;
+    gap: 25cpx;
+    padding-top: 20cpx;
+    background-color: $white-color;
+    &__main {
+      width: 100%;
+      flex: 1;
+    }
+  }
+  .disaster-warning-record {
+    width: 448cpx;
+    height: 100%;
+    &__main {
+      padding-left: 26cpx;
+    }
+  }
+  .disaster-loss-and-loss-record {
+    width: 100%;
+    height: 397cpx;
+  }
+  .defensive-notice-and-regulation {
+    width: 100%;
+    flex: 1;
+  }
+  .bottom-box--right-item {
+    display: flex;
+    flex-direction: column;
+    gap: 10cpx;
+    flex: 1;
+    height: 100%;
+  }
+  .right-info-section {
+    width: 406cpx;
+  }
+  .today-weather {
+    position: relative;
+    width: 100%;
+    height: 267cpx;
+    padding-top: 12cpx;
+    border-radius: 4cpx;
+    background: linear-gradient(90deg, #7ea7fe 0%, #a4cdc9 100%);
+    &__header {
+      display: flex;
+      align-items: center;
+      gap: 48cpx;
+      color: $text-color;
+      font-weight: 500;
+      font-size: 16cpx;
+    }
+  }
+  .info-box {
+    position: absolute;
+    right: 26cpx;
+    bottom: 11cpx;
+    width: 653cpx;
+    height: 191cpx;
+    &::after {
+      content: '';
+      position: absolute;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+      background-color: rgba($white-color, 0.2);
+      backdrop-filter: blur(10px);
+      border-radius: 4cpx;
+    }
+  }
+  .location-and-time {
+    display: flex;
+    align-items: center;
+    gap: 20cpx;
+    .time {
+      display: flex;
+      gap: 5cpx;
+    }
+  }
+</style>

+ 46 - 0
src/views/disaster/overview/src/components/DisasterWarning.vue

@@ -0,0 +1,46 @@
+<template>
+  <div class="tabs-container">
+    <el-tabs v-model="activeName">
+      <el-tab-pane label="本周" name="week" />
+      <el-tab-pane label="本月" name="month" />
+      <el-tab-pane label="季度" name="quarter" />
+      <el-tab-pane label="年度" name="year" />
+    </el-tabs>
+    <main class="tabs-container__main">
+      <component :is="dynamicComponent" />
+    </main>
+  </div>
+</template>
+
+<script lang="ts" setup>
+  import { ref, computed, defineAsyncComponent } from 'vue';
+  const activeName = ref('week');
+  const dynamicComponent = computed(() => {
+    switch (activeName.value) {
+      case 'week':
+        return defineAsyncComponent(() => import('./WeekRecord.vue'));
+      case 'month':
+        return defineAsyncComponent(() => import('./MonthRecord.vue'));
+      case 'quarter':
+        return defineAsyncComponent(() => import('./QuarterRecord.vue'));
+      case 'year':
+        return defineAsyncComponent(() => import('./YearRecord.vue'));
+      default:
+        return defineAsyncComponent(() => import('./WeekRecord.vue'));
+    }
+  });
+</script>
+
+<style lang="scss" scoped>
+  .tabs-container {
+    display: flex;
+    flex-direction: column;
+    width: 100%;
+    height: 100%;
+    &__main {
+      width: 100%;
+      flex: 1;
+      overflow: hidden;
+    }
+  }
+</style>

+ 15 - 0
src/views/disaster/overview/src/components/MonthRecord.vue

@@ -0,0 +1,15 @@
+<template>
+  <div class="record-container">
+    <RecordItem :data="data" />
+  </div>
+</template>
+
+<script lang="ts" setup>
+  import { ref } from 'vue';
+  import RecordItem from './RecordItem.vue';
+  const data = ref([]);
+</script>
+
+<style lang="scss" scoped>
+  @use '../styles/record.scss' as *;
+</style>

+ 71 - 0
src/views/disaster/overview/src/components/QuarterRecord.vue

@@ -0,0 +1,71 @@
+<template>
+  <div class="collapse-record-container">
+    <el-collapse v-model="activeName" accordion>
+      <el-collapse-item title="第一季度" name="1">
+        <RecordItem :data="data1" />
+      </el-collapse-item>
+      <el-collapse-item title="第二季度" name="2">
+        <RecordItem :data="data2" />
+      </el-collapse-item>
+      <el-collapse-item title="第三季度" name="3">
+        <RecordItem :data="data3" />
+      </el-collapse-item>
+      <el-collapse-item title="第四季度" name="4">
+        <RecordItem :data="data4" />
+      </el-collapse-item>
+    </el-collapse>
+  </div>
+</template>
+
+<script lang="ts" setup>
+  import { ref } from 'vue';
+  const activeName = ref('');
+  import RecordItem from './RecordItem.vue';
+  const data1 = ref([]);
+  const data2 = ref([
+    {
+      id: 1,
+      title: 'title-2-quarter-1',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-2-1',
+    },
+    {
+      id: 2,
+      title: 'title-2-quarter-2',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-2-2',
+    },
+  ]);
+  const data3 = ref([
+    {
+      id: 3,
+      title: 'title-3-quarter-1',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-3-1',
+    },
+    {
+      id: 4,
+      title: 'title-3-quarter-2',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-3-2',
+    },
+    {
+      id: 5,
+      title: 'title-3-quarter-3',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-3-3',
+    },
+  ]);
+  const data4 = ref([
+    {
+      id: 6,
+      title: 'title-4-quarter-1',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-4-1',
+    },
+  ]);
+</script>
+
+<style lang="scss" scoped>
+  @use '../styles/collapse-record.scss' as *;
+</style>

+ 92 - 0
src/views/disaster/overview/src/components/RecordItem.vue

@@ -0,0 +1,92 @@
+<template>
+  <div class="record-item-container">
+    <template v-if="data.length > 0">
+      <div class="record-item" v-for="item in data" :key="item.id">
+        <section class="record-item__left-section"></section>
+        <section class="record-item__right-section">
+          <span class="record-item__title">{{ item.title }}</span>
+          <div class="record-item__footer">
+            <span>{{ item.time }}</span>
+            <span>{{ item.department }}</span>
+          </div>
+        </section>
+      </div>
+    </template>
+    <template v-else>
+      <div class="empty-container">
+        <img :src="Empty" />
+        <span>暂无数据</span>
+      </div>
+    </template>
+  </div>
+</template>
+<script lang="ts" setup>
+  interface recordData {
+    id: number;
+    title: string;
+    time: string;
+    department: string;
+  }
+  defineProps<{
+    data: recordData[];
+  }>();
+  import Empty from 'assets/images/empty@1X.png';
+</script>
+
+<style lang="scss" scoped>
+  .record-item-container {
+    display: flex;
+    flex-direction: column;
+    gap: 20cpx;
+    width: 100%;
+    height: 100%;
+  }
+  .record-item {
+    display: flex;
+    gap: 12cpx;
+    height: 90cpx;
+    &__left-section {
+      width: 90cpx;
+      height: inherit;
+      background: linear-gradient(90deg, #7ea7fe 0%, #a4cdc9 100%);
+    }
+    &__right-section {
+      display: flex;
+      flex-direction: column;
+      justify-content: space-between;
+      gap: 12cpx;
+      flex: 1;
+      height: 100%;
+      padding-bottom: 6cpx;
+      color: $text-color;
+    }
+    &__title {
+      width: 100%;
+      font-size: 16cpx;
+      font-weight: 600;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+    }
+    &__footer {
+      display: flex;
+      flex-direction: column;
+      gap: 2cpx;
+      font-size: 12cpx;
+      font-weight: 500;
+      color: rgba($text-color, 0.45);
+    }
+  }
+  .empty-container {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    flex-direction: column;
+    gap: 5cpx;
+    width: 100%;
+    height: 100%;
+    img {
+      width: 100%;
+    }
+  }
+</style>

+ 76 - 0
src/views/disaster/overview/src/components/WeekRecord.vue

@@ -0,0 +1,76 @@
+<template>
+  <div class="record-container">
+    <RecordItem :data="data" />
+  </div>
+</template>
+
+<script lang="ts" setup>
+  import { ref } from 'vue';
+  import RecordItem from './RecordItem.vue';
+  const data = ref([
+    {
+      id: 1,
+      title: 'title-week-1',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-1',
+    },
+    {
+      id: 2,
+      title: 'title-week-2',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-2',
+    },
+    {
+      id: 3,
+      title: 'title-week-3',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-3',
+    },
+    {
+      id: 4,
+      title: 'title-week-4',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-4',
+    },
+    {
+      id: 5,
+      title: 'title-week-5',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-5',
+    },
+    {
+      id: 6,
+      title: 'title-week-6',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-6',
+    },
+    {
+      id: 7,
+      title: 'title-week-7',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-7',
+    },
+    {
+      id: 8,
+      title: 'title-week-8',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-8',
+    },
+    {
+      id: 9,
+      title: 'title-week-9',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-9',
+    },
+    {
+      id: 10,
+      title: 'title-week-10',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-10',
+    },
+  ]);
+</script>
+
+<style lang="scss" scoped>
+  @use '../styles/record.scss' as *;
+</style>

+ 84 - 0
src/views/disaster/overview/src/components/YearRecord.vue

@@ -0,0 +1,84 @@
+<template>
+  <div class="collapse-record-container">
+    <el-collapse v-model="activeName" accordion>
+      <el-collapse-item title="2023年" name="1">
+        <RecordItem :data="data1" />
+      </el-collapse-item>
+      <el-collapse-item title="2024年" name="2">
+        <RecordItem :data="data2" />
+      </el-collapse-item>
+      <el-collapse-item title="2025年" name="3">
+        <RecordItem :data="data3" />
+      </el-collapse-item>
+    </el-collapse>
+  </div>
+</template>
+
+<script lang="ts" setup>
+  import { ref } from 'vue';
+  const activeName = ref('');
+  import RecordItem from './RecordItem.vue';
+  const data1 = ref([
+    {
+      id: 1,
+      title: 'title-2023-year-1',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-2023-1',
+    },
+  ]);
+  const data2 = ref([]);
+  const data3 = ref([
+    {
+      id: 1,
+      title: 'title-2025-year-1',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-2025-1',
+    },
+    {
+      id: 2,
+      title: 'title-2025-year-2',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-2025-2',
+    },
+    {
+      id: 3,
+      title: 'title-2025-year-3',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-2025-3',
+    },
+    {
+      id: 4,
+      title: 'title-2025-year-4',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-2025-4',
+    },
+    {
+      id: 5,
+      title: 'title-2025-year-5',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-2025-5',
+    },
+    {
+      id: 6,
+      title: 'title-2025-year-6',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-2025-6',
+    },
+    {
+      id: 7,
+      title: 'title-2025-year-7',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-2025-7',
+    },
+    {
+      id: 8,
+      title: 'title-2025-year-8',
+      time: '2017-10-31 23:12:00',
+      department: 'XXX-部门-2025-8',
+    },
+  ]);
+</script>
+
+<style lang="scss" scoped>
+  @use '../styles/collapse-record.scss' as *;
+</style>

+ 28 - 0
src/views/disaster/overview/src/styles/collapse-record.scss

@@ -0,0 +1,28 @@
+@use '@/styles/variables.scss' as *;
+.collapse-record-container {
+  width: 100%;
+  height: 100%;
+  padding-right: 26cpx;
+  max-height: calc(100vh - 580cpx);
+  overflow-y: auto;
+}
+.el-collapse {
+  display: flex;
+  flex-direction: column;
+  gap: 16cpx;
+}
+:deep(.el-collapse-item button) {
+  background-color: rgba($primary-color, 0.1);
+  padding: 0 16cpx;
+  border-radius: 4cpx;
+}
+:deep(.el-collapse-item__content) {
+  display: flex;
+  flex-direction: column;
+  gap: 20cpx;
+  padding-top: 20cpx;
+  padding-bottom: 0;
+}
+:deep(.el-collapse) {
+  --el-collapse-border-color: transparent !important;
+}

+ 7 - 0
src/views/disaster/overview/src/styles/record.scss

@@ -0,0 +1,7 @@
+@use '@/styles/variables.scss' as *;
+.record-container {
+  width: 100%;
+  height: 100%;
+  max-height: calc(100vh - 580cpx);
+  overflow-y: auto;
+}