Ver código fonte

reactor:大屏调整;

zhangchong 1 mês atrás
pai
commit
af1694c0b3

+ 1 - 0
package.json

@@ -10,6 +10,7 @@
     "preview": "vite preview --port 4173"
   },
   "dependencies": {
+    "@dataview/datav-vue3": "^0.0.0-test.1672506674342",
     "@microsoft/signalr": "^8.0.0",
     "axios": "^1.5.1",
     "countup.js": "^2.8.0",

BIN
src/assets/img/snapshot/bg.png


+ 8 - 0
src/router/index.ts

@@ -38,6 +38,14 @@ const routes: Array<RouteRecordRaw> = [
       title: `司法行政执法监督子系统`,
     },
   },
+  {
+    path: "/snapshot",
+    name: "snapshot",
+    component: () => import("@/views/snapshot/index.vue"),
+    meta: {
+      title: `随手拍大屏展示`,
+    },
+  },
   {
     path: "/:pathMatch(.*)",
     name: "notFound",

+ 106 - 0
src/views/snapshot/container.vue

@@ -0,0 +1,106 @@
+<template>
+  <div class="container-box">
+    <div class="container-left">
+      <LeftTop class="container-left-top" :dateArray="dateArray" />
+      <LeftCenter class="container-left-center" :dateArray="dateArray" />
+      <LeftBottom class="container-left-bottom" :dateArray="dateArray" />
+    </div>
+    <div class="container-center">
+      <CenterTop class="container-center-top" :dateArray="dateArray" />
+      <CenterMap class="container-center-map" :dateArray="dateArray" />
+      <CenterFloat class="container-center-float" :dateArray="dateArray" />
+      <CenterBottom class="container-center-bottom" :dateArray="dateArray" />
+    </div>
+    <div class="container-right">
+      <RightTop class="container-right-top" :dateArray="dateArray" />
+      <RightCenter class="container-right-center" :dateArray="dateArray" />
+      <RightBottom class="container-right-bottom" :dateArray="dateArray" />
+    </div>
+  </div>
+</template>
+<script setup lang="ts">
+import LeftTop from "@/views/snapshot/left-top.vue";
+import LeftCenter from "@/views/home/left-center.vue";
+import LeftBottom from "@/views/home/left-bottom.vue";
+import CenterTop from "@/views/home/center-top.vue";
+import CenterMap from "@/views/home/center-map.vue";
+import CenterFloat from "@/views/home/center-float.vue";
+import CenterBottom from "@/views/home/center-bottom.vue";
+import RightTop from "@/views/home/right-top.vue";
+import RightCenter from "@/views/home/right-center.vue";
+import RightBottom from "@/views/home/right-bottom.vue";
+
+const props = defineProps({
+  dateArray: {
+    type: Array,
+    default: () => [],
+  },
+});
+</script>
+<style scoped lang="scss">
+.container-box {
+  width: 100%;
+  display: flex;
+  min-height: calc(100% - 100px);
+  justify-content: space-between;
+  margin-top: 10px;
+
+  .container-left,
+  .container-right {
+    display: flex;
+    flex-direction: column;
+    position: relative;
+    width: 540px;
+    box-sizing: border-box;
+    flex-shrink: 0;
+
+    .container-left-top {
+      height: 350px;
+    }
+
+    .container-left-center {
+      height: 305px;
+    }
+
+    .container-left-bottom {
+      height: 290px;
+    }
+  }
+
+  .container-center-float {
+    position: absolute;
+    top: 300px;
+    left: 520px;
+    z-index: 2;
+  }
+
+  .container-center {
+    flex: 1;
+    margin: 0 24px;
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
+    .center_center-bottom {
+      height: 315px;
+    }
+  }
+
+  .container-right,
+  .container-left {
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    position: relative;
+    width: 540px;
+    box-sizing: border-box;
+    flex-shrink: 0;
+
+    .container-right-top,
+    .container-right-center,
+    .container-right-bottom {
+      height: 300px;
+      overflow: hidden;
+    }
+  }
+}
+</style>

+ 94 - 0
src/views/snapshot/header.vue

@@ -0,0 +1,94 @@
+<template>
+  <div class="d-flex jc-center title_wrap">
+    <div class="time-picker">
+      <!--      <el-date-picker
+        v-model="timeValue"
+        type="daterange"
+        unlink-panels
+        range-separator="至"
+        start-placeholder="开始时间"
+        end-placeholder="结束时间"
+        :shortcuts="shortcuts"
+        :clearable="false"
+        @change="changeDate"
+      />-->
+    </div>
+    <div class="d-flex jc-center">
+      <div class="title">
+        <span class="title-text">{{ title }}</span>
+      </div>
+    </div>
+    <div class="timers">
+      {{ formatDate(now, "YYYY年mm月dd日 HH:MM:SS WWW") }}
+    </div>
+  </div>
+</template>
+<script setup lang="ts">
+import { onMounted, ref } from "vue";
+import dayjs from "dayjs";
+import { shortcuts } from "@/utils/constants";
+import { useNow, useTitle } from "@vueuse/core";
+import { formatDate } from "@/utils/formatTime";
+import { useThemeConfig } from "@/stores/themeConfig";
+import { storeToRefs } from "pinia";
+
+const storesThemeConfig = useThemeConfig();
+const { themeConfig } = storeToRefs(storesThemeConfig);
+
+const emit = defineEmits(["changeDate"]);
+const title = ref("12345政务服务便民热线");
+const now = useNow(); // 获取当前时间
+const timeValue = ref<any>([
+  dayjs().subtract(1, "month").toDate(),
+  dayjs().toDate(),
+]); //默认近一个月
+emit("changeDate", timeValue.value);
+const changeDate = (val: any) => {
+  emit("changeDate", val);
+};
+onMounted(() => {
+  title.value = `${themeConfig.value.cityName}随手拍`;
+  useTitle(title.value);
+});
+</script>
+
+<style scoped lang="scss">
+.title_wrap {
+  height: 60px;
+  background-size: cover;
+  background-position: center center;
+  position: relative;
+
+  .time-picker {
+    position: absolute;
+    left: 30px;
+    top: 40px;
+    font-size: 18px;
+    z-index: 9;
+  }
+
+  .timers {
+    position: absolute;
+    right: 30px;
+    top: 40px;
+    font-size: 18px;
+    display: flex;
+    align-items: center;
+  }
+}
+
+.title {
+  position: relative;
+  text-align: center;
+  height: 90px;
+  line-height: 90px;
+
+  .title-text {
+    font-size: 32px;
+    font-weight: 900;
+    letter-spacing: 2px;
+    width: 100%;
+    color: #fff;
+  }
+}
+</style>

+ 53 - 0
src/views/snapshot/index.vue

@@ -0,0 +1,53 @@
+<template>
+  <scale-screen
+    width="1920"
+    height="1080"
+    :delay="500"
+    :fullScreen="true"
+    :boxStyle="{
+      background: '#03050C',
+      overflow: themeConfig.isScale ? 'hidden' : 'auto',
+    }"
+    :wrapperStyle="wrapperStyle"
+    :autoScale="themeConfig.isScale"
+  >
+    <div class="home-content-wrap">
+      <Headers @changeDate="changeDate" />
+      <Container :dateArray="dateArray" />
+    </div>
+  </scale-screen>
+</template>
+<script setup lang="ts" name="snapshot">
+import { defineAsyncComponent, ref } from "vue";
+import { storeToRefs } from "pinia";
+import { useThemeConfig } from "@/stores/themeConfig";
+
+const ScaleScreen = defineAsyncComponent(
+  () => import("@/components/Scale-screen/index.vue")
+);
+const Headers = defineAsyncComponent(
+  () => import("@/views/snapshot/header.vue")
+);
+const Container = defineAsyncComponent(
+  () => import("@/views/snapshot/container.vue")
+);
+
+const storesThemeConfig = useThemeConfig();
+const { themeConfig } = storeToRefs(storesThemeConfig);
+
+const wrapperStyle = {};
+const dateArray = ref<any[]>([]);
+const changeDate = (date: any[]) => {
+  dateArray.value = date;
+};
+</script>
+
+<style scoped lang="scss">
+.home-content-wrap {
+  width: 100%;
+  height: 100%;
+  box-sizing: border-box;
+  background-image: url("@/assets/img/snapshot/bg.png");
+  background-size: 100% 100%;
+}
+</style>

+ 462 - 0
src/views/snapshot/left-top.vue

@@ -0,0 +1,462 @@
+<template>
+  <div class="left-top">
+    <BorderBox1 class="container"> Content </BorderBox1>
+    <div class="flex w-full tab">
+      <span :class="{ active: active === '0' }" @click="active = '0'"
+        >工单统计</span
+      >
+      <span
+        :class="{ active: active === '2' }"
+        @click="active = '2'"
+        v-if="['ZiGong', 'LuZhou'].includes(themeConfig.appScope)"
+        >二次办理统计</span
+      >
+      <span :class="{ active: active === '1' }" @click="active = '1'"
+        >知识库统计</span
+      >
+    </div>
+    <div
+      v-if="active === '0'"
+      class="flex flex-wrap left-top-content-order"
+      v-loading="loading"
+    >
+      <div class="flex left-top-content-item">
+        <img src="@/assets/img/home/done_order.png" alt="" />
+        <div class="left-top-content-item-text">
+          <div class="left-top-content-item-text-title">办结工单</div>
+          <div class="left-top-content-item-text-num">
+            <b>
+              <CountUp :endVal="state.order.completionCount" :duration="2" />
+            </b>
+            件
+          </div>
+          <div class="left-top-content-item-text-rate">
+            办结率:{{ state.order.completionRate }}%
+          </div>
+        </div>
+      </div>
+      <div class="flex left-top-content-item">
+        <img src="@/assets/img/home/wait_order.png" alt="" />
+        <div class="left-top-content-item-text">
+          <div class="left-top-content-item-text-title">待受理工单</div>
+          <div class="left-top-content-item-text-num">
+            <b>
+              <CountUp :endVal="state.order.haveToAcceptCount" :duration="2" />
+            </b>
+            件
+          </div>
+          <div class="left-top-content-item-text-rate">
+            待受理率:{{ state.order.haveToAcceptRate }}%
+          </div>
+        </div>
+      </div>
+      <div class="flex left-top-content-item">
+        <img src="@/assets/img/home/ex_order.png" alt="" />
+        <div class="left-top-content-item-text">
+          <div class="left-top-content-item-text-title">超期工单</div>
+          <div class="left-top-content-item-text-num">
+            <b>
+              <CountUp :endVal="state.order.overTimeCount" :duration="2" />
+            </b>
+            件
+          </div>
+          <div class="left-top-content-item-text-rate">
+            超期率:{{ state.order.overTimeRate }}%
+          </div>
+        </div>
+      </div>
+      <div class="flex left-top-content-item">
+        <img src="@/assets/img/home/delay_order.png" alt="" />
+        <div class="left-top-content-item-text">
+          <div class="left-top-content-item-text-title">延期工单</div>
+          <div class="left-top-content-item-text-num">
+            <b>
+              <CountUp :endVal="state.order.delayCount" :duration="2" />
+            </b>
+            件
+          </div>
+          <div class="left-top-content-item-text-rate">
+            延期率:{{ state.order.delayRate }}%
+          </div>
+        </div>
+      </div>
+      <div class="flex left-top-content-item">
+        <img src="@/assets/img/home/my_order.png" alt="" />
+        <div class="left-top-content-item-text">
+          <div class="left-top-content-item-text-title">满意工单</div>
+          <div class="left-top-content-item-text-num">
+            <b>
+              <CountUp :endVal="state.order.satisfiedCount" :duration="2" />
+            </b>
+            件
+          </div>
+          <div class="left-top-content-item-text-rate">
+            总满意率:{{ state.order.satisfiedRate }}%
+          </div>
+        </div>
+      </div>
+      <div class="flex left-top-content-item">
+        <img src="@/assets/img/home/provice_order.png" alt="" />
+        <div class="left-top-content-item-text">
+          <div class="left-top-content-item-text-title">省工单</div>
+          <div class="left-top-content-item-text-num">
+            <b>
+              <CountUp :endVal="state.order.provinceOrderCount" :duration="2" />
+            </b>
+            件
+          </div>
+          <div class="left-top-content-item-text-rate">
+            已办结:{{ state.order.provinceOrderCompletionCount }}件
+          </div>
+        </div>
+      </div>
+    </div>
+    <div
+      v-if="active === '1'"
+      class="flex flex-wrap left-top-content-knowledge"
+      v-loading="loading"
+    >
+      <div class="flex left-top-content-item">
+        <img src="@/assets/img/home/knowledge_add.png" alt="" />
+        <div class="left-top-content-item-text">
+          <div class="left-top-content-item-text-title">本月新增知识数量</div>
+          <div class="left-top-content-item-text-num">
+            <b>
+              <CountUp :endVal="state.knowledge.todayAddCount" :duration="2" />
+            </b>
+            条
+          </div>
+        </div>
+      </div>
+      <div class="flex left-top-content-item">
+        <img src="@/assets/img/home/knowledge_update.png" alt="" />
+        <div class="left-top-content-item-text">
+          <div class="left-top-content-item-text-title">本月更新知识数</div>
+          <div class="left-top-content-item-text-num">
+            <b>
+              <CountUp
+                :endVal="state.knowledge.thisMonthModifyCount"
+                :duration="2"
+              />
+            </b>
+            条
+          </div>
+        </div>
+      </div>
+      <div class="flex left-top-content-item">
+        <img src="@/assets/img/home/knowledge_read.png" alt="" />
+        <div class="left-top-content-item-text">
+          <div class="left-top-content-item-text-title">今日知识阅读量</div>
+          <div class="left-top-content-item-text-num">
+            <b>
+              <CountUp :endVal="state.knowledge.todayReadCount" :duration="2" />
+            </b>
+            条
+          </div>
+        </div>
+      </div>
+      <div class="flex left-top-content-item">
+        <img src="@/assets/img/home/knowledge_total.png" alt="" />
+        <div class="left-top-content-item-text">
+          <div class="left-top-content-item-text-title">知识总数</div>
+          <div class="left-top-content-item-text-num">
+            <b>
+              <CountUp :endVal="state.knowledge.knowledgeCount" :duration="2" />
+            </b>
+            条
+          </div>
+        </div>
+      </div>
+    </div>
+    <div
+      v-if="active === '2'"
+      class="flex flex-wrap left-top-content-knowledge"
+      v-loading="loading"
+    >
+      <div class="flex left-top-content-item">
+        <img src="@/assets/img/home/done_order.png" alt="" />
+        <div class="left-top-content-item-text">
+          <div class="left-top-content-item-text-title">二次办理工单</div>
+          <div class="left-top-content-item-text-num">
+            <b>
+              <CountUp
+                :endVal="state.secondHandling.orderCount"
+                :duration="2"
+              />
+            </b>
+            件
+          </div>
+        </div>
+      </div>
+      <div class="flex left-top-content-item">
+        <img src="@/assets/img/home/knowledge_update.png" alt="" />
+        <div class="left-top-content-item-text">
+          <div class="left-top-content-item-text-title">二次办理超期</div>
+          <div class="left-top-content-item-text-num">
+            <b>
+              <CountUp
+                :endVal="state.secondHandling.orderOverdueCount"
+                :duration="2"
+              />
+            </b>
+            件
+          </div>
+        </div>
+      </div>
+      <div class="flex left-top-content-item">
+        <img src="@/assets/img/home/knowledge_read.png" alt="" />
+        <div class="left-top-content-item-text">
+          <div class="left-top-content-item-text-title">
+            二次办理即将超期工单
+          </div>
+          <div class="left-top-content-item-text-num">
+            <b>
+              <CountUp
+                :endVal="state.secondHandling.orderSoonOverdueCount"
+                :duration="2"
+              />
+            </b>
+            件
+          </div>
+        </div>
+      </div>
+      <div class="flex left-top-content-item">
+        <img src="@/assets/img/home/knowledge_total.png" alt="" />
+        <div class="left-top-content-item-text">
+          <div class="left-top-content-item-text-title">二次办理满意度</div>
+          <div class="left-top-content-item-text-num">
+            <b>
+              {{ state.secondHandling.satisfactionRate }}
+            </b>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script setup lang="ts">
+import { defineAsyncComponent, onMounted, reactive, ref, watch } from "vue";
+import { knowledge, workOrder, secondHandling } from "@/api/home";
+import dayjs from "dayjs";
+import { useThemeConfig } from "@/stores/themeConfig";
+import { storeToRefs } from "pinia";
+
+import { BorderBox1 } from "@dataview/datav-vue3";
+
+const CountUp = defineAsyncComponent(
+  () => import("@/components/Count-up/index.vue")
+);
+
+const storesThemeConfig = useThemeConfig();
+const { themeConfig } = storeToRefs(storesThemeConfig);
+
+const active = ref("0");
+const props = defineProps({
+  dateArray: {
+    type: Array,
+    default: () => [],
+  },
+});
+const loading = ref(false);
+const date = ref([]);
+watch(
+  () => props.dateArray,
+  (val: any) => {
+    date.value = val;
+  },
+  { immediate: true }
+);
+
+watch(
+  () => props.dateArray,
+  (val: any) => {
+    getWorkOrder();
+    if (["ZiGong"].includes(themeConfig.value.appScope)) {
+      getSecondHandling();
+    }
+  }
+);
+const state = reactive({
+  order: {
+    completionCount: 0,
+    completionRate: 0,
+    haveToAcceptCount: 0,
+    haveToAcceptRate: 0,
+    overTimeCount: 0,
+    overTimeRate: 0,
+    delayCount: 0,
+    delayRate: 0,
+    satisfiedCount: 0,
+    satisfiedRate: 0,
+    provinceOrderCount: 0,
+    provinceOrderCompletionCount: 0,
+  },
+  knowledge: {
+    todayAddCount: 0,
+    thisMonthModifyCount: 0,
+    todayReadCount: 0,
+    knowledgeCount: 0,
+  },
+  secondHandling: {
+    orderCount: 0,
+    orderOverdueCount: 0,
+    orderSoonOverdueCount: 0,
+    satisfactionRate: "0%",
+  },
+});
+// 获取工单统计
+const getWorkOrder = async () => {
+  loading.value = true;
+  try {
+    const { result } = await workOrder({
+      StartTime: dayjs(date.value[0]).format("YYYY-MM-DD"),
+      EndTime: dayjs(date.value[1]).format("YYYY-MM-DD"),
+    });
+    state.order = result;
+    loading.value = false;
+  } catch (e) {
+    console.log(e);
+    loading.value = false;
+  }
+};
+// 获取知识库统计
+const getKnowledge = async () => {
+  loading.value = true;
+  try {
+    const { result } = await knowledge();
+    state.knowledge = result;
+    loading.value = false;
+  } catch (e) {
+    console.log(e);
+    loading.value = false;
+  }
+};
+// 获取二次办理统计
+const getSecondHandling = async () => {
+  loading.value = true;
+  try {
+    const { result } = await secondHandling({
+      StartTime: dayjs(date.value[0]).format("YYYY-MM-DD"),
+      EndTime: dayjs(date.value[1]).format("YYYY-MM-DD"),
+    });
+    state.secondHandling = result;
+    loading.value = false;
+  } catch (e) {
+    console.log(e);
+    loading.value = false;
+  }
+};
+onMounted(() => {
+  getWorkOrder();
+  getKnowledge();
+  if (["ZiGong"].includes(themeConfig.value.appScope)) {
+    getSecondHandling();
+  }
+});
+</script>
+<style scoped lang="scss">
+.left-top {
+  padding: 0 30px;
+  .container {
+    width: 500px;
+    height: 200px;
+  }
+
+  .tab {
+    span {
+      cursor: pointer;
+      flex: 1;
+      height: 50px;
+      text-align: center;
+      line-height: 50px;
+      font-size: 16px;
+
+      margin-right: 20px;
+      background: url("@/assets/img/home/tab_bg.png") no-repeat;
+      background-size: 100% 100%;
+
+      &:last-child {
+        margin-right: 0;
+      }
+
+      &.active {
+        color: #fff;
+        font-size: 18px;
+        font-weight: bold;
+        position: relative;
+
+        &:after {
+          content: "";
+          display: block;
+          width: 50%;
+          height: 30px;
+          background: linear-gradient(
+            to right,
+            rgba(255, 255, 255, 0.2),
+            rgba(255, 255, 255, 0.1)
+          );
+          border-radius: 20px;
+          position: absolute;
+          top: 20%;
+          left: 25%;
+        }
+      }
+    }
+  }
+
+  &-content {
+    &-order {
+      justify-content: space-between;
+      margin-top: 20px;
+    }
+
+    &-knowledge {
+      justify-content: space-between;
+      margin-top: 40px;
+    }
+
+    &-item {
+      width: 50%;
+      margin-bottom: 15px;
+
+      &:last-child {
+        margin-right: 0;
+        margin-bottom: 0;
+      }
+
+      img {
+        width: 50px;
+        height: 50px;
+      }
+
+      &-text {
+        margin-left: 10px;
+
+        &-title {
+          font-size: 16px;
+          color: #aaafaf;
+          white-space: nowrap;
+        }
+
+        &-num {
+          color: #aaafaf;
+
+          b {
+            font-size: 30px;
+            color: #fff;
+          }
+        }
+
+        &-rate {
+          font-size: 12px;
+          color: #fff;
+        }
+      }
+    }
+  }
+
+  .count-up-wrap {
+    display: inline-block;
+  }
+}
+</style>

Diferenças do arquivo suprimidas por serem muito extensas
+ 465 - 287
yarn.lock


Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff