luogang hai 3 meses
pai
achega
18b1563c38

+ 29 - 0
plus-ui-ts/.gitignore

@@ -0,0 +1,29 @@
+.DS_Store
+.history
+node_modules/
+dist/
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+**/*.log
+
+tests/**/coverage/
+tests/e2e/reports
+selenium-debug.log
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.local
+
+package-lock.json
+yarn.lock
+pnpm-lock.yaml
+
+# 编译生成的文件
+auto-imports.d.ts
+components.d.ts

+ 2 - 1
plus-ui-ts/index.html

@@ -6,7 +6,8 @@
     <meta name="renderer" content="webkit" />
     <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
     <link rel="icon" href="/favicon.ico" />
-    <title>RuoYi-Vue-Plus多租户管理系统</title>
+    <script type="text/javascript" src="https://api.map.baidu.com/api?v=1.0&type=webgl&ak=KumIikHq4H2BQnbRrxMktUaS4peySWGD"></script>
+    <title>交通事件管理系统</title>
     <!--[if lt IE 11
       ]><script>
         window.location.href = '/html/ie.html';

+ 10 - 1
plus-ui-ts/package.json

@@ -24,17 +24,26 @@
     "@highlightjs/vue-plugin": "2.1.0",
     "@vueup/vue-quill": "1.2.0",
     "@vueuse/core": "13.1.0",
+    "@wangeditor/editor": "^5.1.23",
+    "@wangeditor/editor-for-vue": "^5.1.12",
     "animate.css": "4.1.1",
     "await-to-js": "3.0.0",
     "axios": "1.8.4",
     "crypto-js": "4.2.0",
+    "dplayer": "^1.27.1",
     "echarts": "5.6.0",
     "element-plus": "2.9.8",
-    "file-saver": "2.0.5",
+    "element-resize-detector": "^1.2.4",
+    "file-saver": "^2.0.5",
     "highlight.js": "11.9.0",
+    "html-docx-js": "^0.3.1",
+    "html-docx-js-typescript": "^0.1.5",
+    "html2canvas": "^1.4.1",
+    "html2image-pdf-word": "^1.0.4",
     "image-conversion": "2.1.1",
     "js-cookie": "3.0.5",
     "jsencrypt": "3.3.2",
+    "jspdf": "^2.5.2",
     "nprogress": "0.2.0",
     "pinia": "3.0.2",
     "screenfull": "6.0.2",

BIN=BIN
plus-ui-ts/src/assets/images/demo.mp4


+ 20 - 0
plus-ui-ts/src/assets/images/monitor.svg

@@ -0,0 +1,20 @@
+<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 32 36.2722168" class="design-iconfont">
+  <defs>
+    <clipPath id="hhrtwp33j__29f44cr7ya">
+      <rect x="9" y="8" width="16" height="16" rx="0"/>
+    </clipPath>
+  </defs>
+  <g fill-rule="evenodd">
+    <path d="M16,36.2722C17.1428,36.2722,18.2575,31.8802,19.3325,31.6525C26.5695,30.1192,32,23.6938,32,16C32,7.16344,24.8366,0,16,0C7.16344,0,0,7.16344,0,16C0,23.7698,5.53827,30.246,12.8825,31.6965C13.8908,31.8956,14.9332,36.2722,16,36.2722Z" fill="#FFF"/>
+    <path d="M16,36.2722C17.1428,36.2722,18.2575,31.8802,19.3325,31.6525C26.5695,30.1192,32,23.6938,32,16C32,7.16344,24.8366,0,16,0C7.16344,0,0,7.16344,0,16C0,23.7698,5.53827,30.246,12.8825,31.6965C13.8908,31.8956,14.9332,36.2722,16,36.2722ZM16.0532,34.9775Q16.0402,34.9972,16.0277,35.0157L16.0239,35.0096Q15.7826,34.6213,15.2671,33.5102Q14.0604,30.9098,13.0763,30.7154Q7.86932,29.6871,4.45635,25.579Q1,21.4186,0.999999,16Q1,9.7868,5.3934,5.3934Q9.78679,1,16,0.999999Q22.2132,1,26.6066,5.3934Q31,9.78679,31,16Q31,21.3631,27.6068,25.5025Q24.2589,29.5866,19.1252,30.6742Q18.1356,30.8838,16.866,33.461Q16.3125,34.5845,16.0532,34.9775Z" fill="#DBDBDB"/>
+  </g>
+  <path fill="#ED7646" d="M16 3A13 13 0 1 0 16 29A13 13 0 1 0 16 3Z"/>
+  <g fill-rule="evenodd">
+    <path d="M16,36.2722C17.1428,36.2722,18.2575,31.8802,19.3325,31.6525C26.5695,30.1192,32,23.6938,32,16C32,7.16344,24.8366,0,16,0C7.16344,0,0,7.16344,0,16C0,23.7698,5.53827,30.246,12.8825,31.6965C13.8908,31.8956,14.9332,36.2722,16,36.2722Z" fill="#FFF"/>
+    <path d="M16,36.2722C17.1428,36.2722,18.2575,31.8802,19.3325,31.6525C26.5695,30.1192,32,23.6938,32,16C32,7.16344,24.8366,0,16,0C7.16344,0,0,7.16344,0,16C0,23.7698,5.53827,30.246,12.8825,31.6965C13.8908,31.8956,14.9332,36.2722,16,36.2722ZM16.0532,34.9775Q16.0402,34.9972,16.0277,35.0157L16.0239,35.0096Q15.7826,34.6213,15.2671,33.5102Q14.0604,30.9098,13.0763,30.7154Q7.86932,29.6871,4.45635,25.579Q1,21.4186,0.999999,16Q1,9.7868,5.3934,5.3934Q9.78679,1,16,0.999999Q22.2132,1,26.6066,5.3934Q31,9.78679,31,16Q31,21.3631,27.6068,25.5025Q24.2589,29.5866,19.1252,30.6742Q18.1356,30.8838,16.866,33.461Q16.3125,34.5845,16.0532,34.9775Z" fill="#DBDBDB"/>
+  </g>
+  <path fill="#7E57DC" d="M16 3A13 13 0 1 0 16 29A13 13 0 1 0 16 3Z"/>
+  <g clip-path="url(#hhrtwp33j__29f44cr7ya)">
+    <path d="M12.35,18.700048828125L10.65,18.700048828125L10.65,16.550048828125L9,16.250048828125L9,23.150048828125L10.65,22.600048828125L10.65,20.200048828125L13.3,20.200048828125L14.75,18.250048828125L12.85,17.250048828125L12.35,18.700048828125ZM20.95,19.150048828125L24.8,16.700048828125L12.8,8.800048828125L11.4,8.800048828125L9.5,11.800048828125L9.5,12.800048828125L20.05,19.200048828125L20.95,19.200048828125L20.95,19.150048828125ZM19.5,19.650048828125L10.4,13.750048828125L9.45,14.750048828125L20,21.150048828125L20.95,21.150048828125L21.45,20.650048828125L21.95,19.200048828125C21.95,19.200048828125,20.55,20.200048828125,20.5,20.200048828125C19.95,19.850048828125,19.5,19.650048828125,19.5,19.650048828125Z" fill="#FFF" style="mix-blend-mode:passthrough"/>
+  </g>
+</svg>

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 3 - 0
plus-ui-ts/src/assets/images/report.svg


+ 3 - 0
plus-ui-ts/src/assets/images/title.svg

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 16" class="design-iconfont">
+  <path d="M0.571429,6.99886C0.255837,6.99886,0,6.74302,0,6.42743L0,1.571429C0,1.255837,0.255837,1,0.571429,1L15.4286,1C15.7442,1,16,1.255837,16,1.571429L16,6.42743C16,6.74302,15.7442,6.99886,15.4286,6.99886L0.571429,6.99886ZM1.4297,3.85824C1.43033,4.33137,1.81372,4.71476,2.28684,4.71538L5.14399,4.71538C5.61737,4.71538,6.00113,4.3316300000000005,6.00113,3.85824C6.00113,3.38486,5.61737,3.0011,5.14399,3.0011L2.28684,3.0011C2.05952,3.0008,1.84138,3.09081,1.68042,3.25134C1.51946,3.41187,1.42886,3.62977,1.42856,3.8571L1.4297,3.85824ZM0.571429,14.7142C0.255837,14.7142,0,14.4584,0,14.1428L0,9.28566C0,8.97007,0.255837,8.71423,0.571429,8.71423L15.4286,8.71423C15.7442,8.71423,16,8.97007,16,9.28566L16,14.1428C16,14.4584,15.7442,14.7142,15.4286,14.7142L0.571429,14.7142ZM1.4297,11.5703C1.4294,11.7977,1.51961,12.0159,1.68042,12.1767C1.84123,12.3375,2.05942,12.4277,2.28684,12.4274L5.14399,12.4274C5.61737,12.4274,6.00113,12.0437,6.00113,11.5703C6.00113,11.0969,5.61737,10.71314,5.14399,10.71314L2.28684,10.71314C2.05923,10.71253,1.84074,10.8026,1.67968,10.96345C1.51862,11.1243,1.42825,11.3427,1.42856,11.5703L1.4297,11.5703Z" fill-rule="evenodd" fill="#308CFF"/>
+</svg>

+ 17 - 4
plus-ui-ts/src/assets/styles/element-ui.scss

@@ -65,24 +65,34 @@
 .el-overlay {
   overflow: hidden;
 
-  .el-overlay-dialog {
+ .el-overlay-dialog {
     display: flex;
     align-items: center;
     justify-content: center;
     width: 100%;
     height: 100%;
-
     .el-dialog {
-      margin: 0 auto !important;
+      // margin: 0 auto !important;
+      padding: 0;
 
       .el-dialog__body {
         padding: 15px !important;
       }
       .el-dialog__header {
-        padding: 16px 16px 8px 16px;
+        padding: 8px 16px;
+        background: #fafafa;
         box-sizing: border-box;
         border-bottom: 1px solid var(--brder-color);
         margin-right: 0;
+        border-radius: 6px 6px 0 0;
+        .el-dialog__title {
+          font-size: 14px;
+          font-weight: 500;
+        }
+      }
+      .el-dialog__footer {
+        padding: 16px;
+        text-align: center;
       }
     }
   }
@@ -151,3 +161,6 @@
 .el-message-box .el-message-box__message {
   word-break: break-word;
 }
+.el-form-item__label {
+  font-weight: 400!important;
+}

+ 4 - 4
plus-ui-ts/src/assets/styles/ruoyi.scss

@@ -76,9 +76,9 @@ h6 {
 .el-form .el-form-item__label {
   font-weight: 700;
 }
-.el-dialog:not(.is-fullscreen) {
-  margin-top: 6vh !important;
-}
+// .el-dialog:not(.is-fullscreen) {
+//   margin-top: 6vh !important;
+// }
 
 .el-dialog.scrollbar .el-dialog__body {
   overflow: auto;
@@ -188,7 +188,7 @@ h6 {
 }
 
 .el-card__header {
-  padding: 14px 15px 7px !important;
+  padding: 14px 20px 14px !important;
   min-height: 40px;
 }
 

+ 83 - 0
plus-ui-ts/src/components/BaseChart/index.vue

@@ -0,0 +1,83 @@
+<template>
+  <div ref="chart" :style="style"></div>
+</template>
+
+<script lang="ts" setup>
+import * as echarts from 'echarts'
+import elementResizeDetectorMaker from 'element-resize-detector'
+
+const props = defineProps({
+  // 图表的宽度
+  width: {
+    type: String,
+    default: '600px'
+  },
+  // 图表的高度
+  height: {
+    type: String,
+    default: '400px'
+  },
+  // 图表的配置
+  option: {
+    type: Object,
+    required: true
+  }
+})
+
+const chart = shallowRef<any>()
+
+const style = computed(() => ({
+  width: props.width,
+  height: props.height
+}))
+
+// 初始化图表
+const initChart = () => {
+  // setTimeout(() => {
+  if (!chartInstance.value) {
+    chartInstance.value = echarts.init(chart.value)
+  }
+  chartInstance.value.clear();
+  props.option && chartInstance.value.setOption(props.option, true)
+
+  // }, 1000)
+
+}
+
+// 处理图表容器大小变化
+const handleResize = () => {
+  const erd = elementResizeDetectorMaker()
+  // 监听图表容器的大小变化
+  erd.listenTo(chart.value, () => {
+    // 改变图表尺寸
+    chartInstance.value?.resize()
+  })
+}
+
+const chartInstance = shallowRef<any>()
+
+watch(
+  () => props.option,
+  () => {
+    initChart()
+  },
+  { deep: true }
+)
+
+onMounted(() => {
+  initChart()
+  handleResize()
+})
+
+onBeforeUnmount(() => {
+  if (chartInstance.value) {
+    // 销毁图表实例
+    chartInstance.value.dispose()
+    chartInstance.value = null
+  }
+})
+</script>
+
+<style lang="scss" scoped>
+/* 你可以在这里定义样式 */
+</style>

+ 2 - 2
plus-ui-ts/src/layout/components/AppMain.vue

@@ -57,7 +57,7 @@ function addIframe() {
 <style lang="scss" scoped>
 .app-main {
   /* 50= navbar  50  */
-  min-height: calc(100vh - 50px);
+  height: calc(100vh - 50px);
   width: 100%;
   position: relative;
   overflow: hidden;
@@ -70,7 +70,7 @@ function addIframe() {
 .hasTagsView {
   .app-main {
     /* 84 = navbar + tags-view = 50 + 34 */
-    min-height: calc(100vh - 84px);
+    height: calc(100vh - 84px);
   }
 
   .fixed-header + .app-main {

+ 661 - 51
plus-ui-ts/src/views/index.vue

@@ -1,80 +1,690 @@
 <template>
-  <div class="app-container home">
-    <el-row :gutter="20">
-      <el-col :sm="24" :lg="12" style="padding-left: 20px">
-        <h2>交通事件管理系统</h2>
-      </el-col>
-    </el-row>
-    <el-divider />
+  <div class="home">
+    <div class="map" id="map"></div>
+    <div class="left-part">
+      <el-card>
+        <template #header>
+          <div class="custom-title">
+            <img src="@/assets/images/title.svg" />
+            <span>本月</span>
+          </div>
+        </template>
+        <div class="custom-card">
+          <div class="card-item">
+            <span>147</span>
+            <span>所有数量</span>
+          </div>
+          <div class="card-item">
+            <span>147</span>
+            <span>已解决</span>
+          </div>
+          <div class="card-item">
+            <span>147</span>
+            <span>未解决</span>
+          </div>
+          <div class="card-item">
+            <span>147</span>
+            <span>已上报</span>
+          </div>
+        </div>
+      </el-card>
+      <el-card style="margin-top: 10px">
+        <template #header>
+          <div class="custom-title">
+            <img src="@/assets/images/title.svg" />
+            <span>本周</span>
+          </div>
+        </template>
+        <div class="custom-card week-card">
+          <div class="card-item">
+            <span>147</span>
+            <span>所有数量</span>
+          </div>
+          <div class="card-item">
+            <span>147</span>
+            <span>已解决</span>
+          </div>
+          <div class="card-item">
+            <span>147</span>
+            <span>未解决</span>
+          </div>
+          <div class="card-item">
+            <span>147</span>
+            <span>已上报</span>
+          </div>
+        </div>
+      </el-card>
+      <el-card style="margin-top: 10px">
+        <template #header>
+          <div class="custom-title">
+            <img src="@/assets/images/title.svg" />
+            <span>当天</span>
+          </div>
+        </template>
+        <div class="custom-card day-card">
+          <div class="card-item">
+            <span>147</span>
+            <span>所有数量</span>
+          </div>
+          <div class="card-item">
+            <span>147</span>
+            <span>已解决</span>
+          </div>
+          <div class="card-item">
+            <span>147</span>
+            <span>未解决</span>
+          </div>
+          <div class="card-item">
+            <span>147</span>
+            <span>已上报</span>
+          </div>
+        </div>
+      </el-card>
+      <el-card style="margin-top: 10px">
+        <template #header>
+          <div class="custom-title">
+            <img src="@/assets/images/title.svg" />
+            <span>统计分析</span>
+          </div>
+        </template>
+        <BaseChart width="100%" height="230px" :option="pieOptions" />
+      </el-card>
+    </div>
+    <div class="right-part">
+      <div class="event-title">
+        <div>
+          <el-select style="width: 100px" v-model="queryParams.level" clearable placeholder="事件等级">
+            <el-option v-for="dict in event_level" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
+          </el-select>
+          <el-select style="width: 100px; margin-left: 10px" v-model="queryParams.level" clearable placeholder="事件类型">
+            <el-option v-for="dict in event_level" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
+          </el-select>
+          <el-date-picker
+            v-model="queryParams.dateRange"
+            style="margin-left: 10px"
+            type="daterange"
+            unlink-panels
+            range-separator="~"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            :shortcuts="shortcuts"
+          />
+        </div>
+        <div style="margin-top: 10px">
+          <el-input v-model="queryParams.addr" style="width: 210px" placeholder="输入地点关键词" :suffix-icon="Search" />
+          <div style="margin-left: 10px">
+            <el-button color="#3CBBED" style="color: #fff">查询</el-button>
+            <el-button>重置</el-button>
+          </div>
+        </div>
+      </div>
+      <div class="event-list">
+        <el-table :data="tableData" :show-header="false" :border="false" style="width: 100%; --el-table-border-color: none">
+          <el-table-column prop="level" />
+          <el-table-column prop="type" />
+          <el-table-column prop="addr" show-overflow-tooltip />
+          <el-table-column prop="date" />
+          <el-table-column width="60">
+            <template #default="{ row }">
+              <el-button link type="primary" @click="showDetails(row)">查看</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+      <div class="event-footer">
+        <el-pagination background layout="prev, pager, next" :total="1000" />
+      </div>
+    </div>
+    <el-dialog v-model="dialog.visible" :title="dialog.title" width="1000px" top="0">
+      <el-form ref="addFormRef" :model="form" label-position="top" label-width="90px" label-suffix=":">
+        <el-row :gutter="20">
+          <el-col :span="8">
+            <el-form-item label="事件ID" prop="handler" :rules="[{ required: true, message: '请输入', trigger: 'blur' }]">
+              <el-input v-model="form.handler" placeholder="请输入" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="事件类型" prop="handleWay">
+              <el-select v-model="form.level" clearable placeholder="请选择">
+                <el-option v-for="dict in event_level" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="发生时间" prop="handleContent">
+              <el-date-picker style="width: 100%" v-model="form.value1" type="date" placeholder="请选择" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="事件等级" prop="handleWay">
+              <el-select v-model="form.level" clearable placeholder="请选择">
+                <el-option v-for="dict in event_level" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="桩号" prop="handleWay">
+              <el-input v-model="form.handler" placeholder="请输入" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="地点描述" prop="handleWay">
+              <el-input v-model="form.handler" type="textarea" placeholder="请输入" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div class="event-media">
+        <div class="event-media-title">现场画面</div>
+        <div class="event-media-content">
+          <div class="imgs">
+            <el-image :src="imgUrl" show-progress :preview-src-list="imgList" fit="cover" />
+            <el-image :src="imgUrl" show-progress :preview-src-list="imgList" fit="cover" />
+          </div>
+        </div>
+      </div>
+      <div class="event-media" style="margin-top: 10px">
+        <div class="event-media-title">现场视频</div>
+        <div class="event-media-content">
+          <div class="videos">
+            <div id="dplayer1"></div>
+            <div id="dplayer2"></div>
+            <div id="dplayer3"></div>
+            <div id="dplayer4"></div>
+          </div>
+        </div>
+      </div>
+      <div class="report-btn">
+        <img @click="generateReport" src="@/assets/images/report.svg" alt="" />
+      </div>
+      <template v-if="showReport">
+        <div class="report-editor">
+          <div class="report-title">报告内容:</div>
+          <div style="border: 1px solid #d9d9d9; margin-top: 10px">
+            <Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" mode="default" />
+            <Editor style="height: 500px; overflow-y: hidden" v-model="valueHtml" :defaultConfig="editorConfig" @onCreated="handleCreated" />
+          </div>
+        </div>
+        <div style="margin-top: 20px">
+          <div class="report-title">格式选择:</div>
+          <el-select style="width: 300px; margin-top: 10px" v-model="fileType" clearable placeholder="请选择">
+            <el-option label="pdf" :value="1"></el-option>
+            <el-option label="word" :value="2"></el-option>
+            <el-option label="图片" :value="3"></el-option>
+          </el-select>
+        </div>
+        <div>
+          <el-button color="#2AB55C" style="color: #fff; margin-top: 20px; margin-bottom: 30px" @click="htmlToPdfFn">导出报告</el-button>
+        </div>
+      </template>
+      <!-- <template #footer>
+        <div class="dialog-footer">
+        </div>
+      </template> -->
+    </el-dialog>
   </div>
 </template>
+<script lang="ts" setup>
+import { Search, Location } from '@element-plus/icons-vue';
+import BaseChart from '@/components/BaseChart/index.vue';
+import monitorIcon from '@/assets/images/monitor.svg';
+import DPlayer from 'dplayer';
+import '@wangeditor/editor/dist/css/style.css'; // 引入 css
+import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
+import { exportAsPdf, exportAsWord, exportAsImage } from 'html2image-pdf-word';
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const bdmap = ref(null);
+const marks = ref([
+  {
+    longitude: 118.84651017058795,
+    latitude: 32.03286965957209
+  },
+  {
+    longitude: 118.87381865809128,
+    latitude: 32.050866853291296
+  },
+  {
+    longitude: 118.88459832421101,
+    latitude: 32.01094988629638
+  }
+]);
+const { event_level } = toRefs<any>(proxy?.useDict('event_level'));
+const editorRef = shallowRef();
+const toolbarConfig = {};
+const editorConfig = { placeholder: '请输入内容...' };
+// 内容 HTML
+const valueHtml = ref('<p>hello</p>');
+const handleCreated = (editor) => {
+  console.log('created', editor);
+  editorRef.value = editor; // 记录 editor 实例,重要!
+};
+const fileType = ref(1);
+const showReport = ref(false);
+const htmlToPdfFn = async () => {
+  const dom: any = document.querySelector('.w-e-text-container');
+  const filename = '报告';
+  const type = fileType.value;
+  switch (type) {
+    case 1:
+      await exportAsPdf(dom, filename);
+      break;
+    case 2:
+      await exportAsWord(dom, filename);
+      break;
+    case 3:
+      await exportAsImage(dom, filename);
+      break;
+  }
+};
 
-<script setup name="Index" lang="ts">
-const goTarget = (url: string) => {
-  window.open(url, '__blank');
+const queryParams = ref({
+  level: undefined,
+  dateRange: undefined,
+  addr: undefined
+});
+const dialog = reactive({
+  visible: false,
+  title: '事件详情'
+});
+const form = reactive({});
+const shortcuts = [
+  {
+    text: '最近一周',
+    value: () => {
+      const end = new Date();
+      const start = new Date();
+      start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
+      return [start, end];
+    }
+  },
+  {
+    text: '最近一个月',
+    value: () => {
+      const end = new Date();
+      const start = new Date();
+      start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
+      return [start, end];
+    }
+  },
+  {
+    text: '最近三个月',
+    value: () => {
+      const end = new Date();
+      const start = new Date();
+      start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
+      return [start, end];
+    }
+  }
+];
+const pieOptions = computed(() => {
+  const options = {
+    tooltip: {
+      trigger: 'item'
+    },
+    legend: {
+      orient: 'horizontal',
+      left: 'center',
+      itemWidth: 15,
+      itemHeight: 8,
+      itemGap: 10
+    },
+    series: [
+      {
+        type: 'pie',
+        radius: '50%',
+        radius: ['40%', '80%'],
+        center: ['50%', '60%'],
+        data: [
+          {
+            value: 40,
+            name: '已解决',
+            itemStyle: {
+              color: '#FAC858'
+            }
+          },
+          {
+            value: 17,
+            name: '未解决',
+            itemStyle: {
+              color: '#93BEFF'
+            }
+          },
+          {
+            value: 15,
+            name: '已上报',
+            itemStyle: {
+              color: '#507AFC'
+            }
+          }
+        ],
+        labelLine: {
+          show: false
+        },
+        label: {
+          show: false,
+          position: 'center'
+        }
+      }
+    ]
+  };
+  return options;
+});
+const tableData = [
+  {
+    date: '2016-05-03',
+    level: '严重',
+    addr: '地点',
+    type: '交通事故'
+  },
+  {
+    date: '2016-05-03',
+    level: '严重',
+    addr: '地点',
+    type: '交通事故'
+  },
+  {
+    date: '2016-05-03',
+    level: '严重',
+    addr: '地点',
+    type: '交通事故'
+  }
+];
+const imgUrl = new URL(`@/assets/images/profile.jpg`, import.meta.url).href;
+const imgList = [new URL(`@/assets/images/profile.jpg`, import.meta.url).href, new URL(`@/assets/images/profile.jpg`, import.meta.url).href];
+onMounted(() => {
+  const map = new BMapGL.Map('map'); // 创建地图实例
+  const point = new BMapGL.Point(118.879999, 32.016216); // 创建点坐标
+  map.centerAndZoom(point, 14);
+  map.enableScrollWheelZoom(true);
+  bdmap.value = map;
+  map.addEventListener('click', function (e) {
+    const { lng, lat } = e.latlng;
+    console.log(e.latlng);
+  });
+  showMarks();
+});
+onBeforeUnmount(() => {
+  const editor = editorRef.value;
+  if (editor == null) return;
+  editor.destroy();
+});
+const showMarks = () => {
+  bdmap.value.clearOverlays();
+  marks.value.forEach((item) => {
+    const pt = new BMapGL.Point(Number(item.longitude), Number(item.latitude));
+    const icon = new BMapGL.Icon(monitorIcon, new BMapGL.Size(30, 30));
+    const marker = new BMapGL.Marker(pt, { icon });
+    bdmap.value.addOverlay(marker);
+  });
+};
+const showDetails = () => {
+  showReport.value = false;
+  dialog.visible = true;
+  nextTick(() => {
+    const dp = new DPlayer({
+      container: document.getElementById('dplayer1'),
+      video: {
+        url: new URL(`@/assets/images/demo.mp4`, import.meta.url).href
+      }
+    });
+    const dp2 = new DPlayer({
+      container: document.getElementById('dplayer2'),
+      video: {
+        url: new URL(`@/assets/images/demo.mp4`, import.meta.url).href
+      }
+    });
+    const dp3 = new DPlayer({
+      container: document.getElementById('dplayer3'),
+      video: {
+        url: new URL(`@/assets/images/demo.mp4`, import.meta.url).href
+      }
+    });
+    const dp4 = new DPlayer({
+      container: document.getElementById('dplayer4'),
+      video: {
+        url: new URL(`@/assets/images/demo.mp4`, import.meta.url).href
+      }
+    });
+  });
+};
+const generateReport = () => {
+  showReport.value = true;
+  proxy?.$modal.msgSuccess('报告生成成功');
 };
 </script>
-
 <style lang="scss" scoped>
 .home {
-  blockquote {
-    padding: 10px 20px;
-    margin: 0 0 20px;
-    font-size: 17.5px;
-    border-left: 5px solid #eee;
+  height: 100%;
+  background-color: #f0f2f5;
+  position: relative;
+
+  .left-part {
+    position: absolute;
+    width: 300px;
+    top: 10px;
+    left: 20px;
+    z-index: 10;
+  }
+
+  .right-part {
+    position: absolute;
+    background: #fff;
+    border-radius: 4px;
+    top: 10px;
+    width: 550px;
+    right: 20px;
+    bottom: 10px;
+    z-index: 10;
+    box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12);
+    display: flex;
+    flex-direction: column;
   }
-  hr {
-    margin-top: 20px;
-    margin-bottom: 20px;
-    border: 0;
-    border-top: 1px solid #eee;
+}
+
+.custom-title {
+  display: flex;
+  align-items: center;
+  color: #000000;
+  font-size: 16px;
+
+  img {
+    height: 16px;
+    margin-right: 5px;
   }
-  .col-item {
-    margin-bottom: 20px;
+}
+
+.custom-card {
+  display: flex;
+  justify-content: space-between;
+
+  .card-item {
+    display: flex;
+    width: 22.5%;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    height: 71px;
+    background: #e3eefe;
+    color: #2d5794;
+    border-radius: 4.8px;
+
+    span:first-child {
+      flex: 1;
+      font-size: 22px;
+      margin-top: 10px;
+    }
+
+    span:last-child {
+      width: 80%;
+      text-align: center;
+      height: 26px;
+      line-height: 26px;
+      border-top: 0.6px solid #d0dff4;
+      font-size: 10px;
+    }
   }
+}
+
+.week-card {
+  .card-item {
+    background: #fef4e3;
+
+    span:first-child {
+      color: #7c5b22;
+    }
 
-  ul {
-    padding: 0;
-    margin: 0;
+    span:last-child {
+      border-color: #eddbbc;
+      color: #8c692e;
+    }
   }
+}
+
+.day-card {
+  .card-item {
+    background: #e3fef0;
 
-  font-family: 'open sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
-  font-size: 13px;
-  color: #676a6c;
-  overflow-x: hidden;
+    span:first-child {
+      color: #248647;
+    }
 
-  ul {
-    list-style-type: none;
+    span:last-child {
+      border-color: #ade7cd;
+      color: #238546;
+    }
   }
+}
+
+.map {
+  width: 100%;
+  height: 100%;
+}
+
+.event-title {
+  flex-shrink: 0;
+  padding: 10px;
+  background: linear-gradient(180deg, #ffffff 0%, #f5f5f5 100%);
+  border-radius: 4px 4px 0 0;
 
-  h4 {
-    margin-top: 0px;
+  > div {
+    display: flex;
+    align-items: center;
+
+    > .el-select {
+      flex-shrink: 0;
+    }
   }
+}
+
+.event-list {
+  flex: 1;
+  overflow-y: auto;
 
-  h2 {
-    margin-top: 10px;
-    font-size: 26px;
-    font-weight: 100;
+  :deep() {
+    .el-table__cell {
+      border: none;
+    }
   }
+}
 
-  p {
-    margin-top: 10px;
+.event-footer {
+  height: 60px;
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+  padding-right: 20px;
 
-    b {
-      font-weight: 700;
+  :deep() {
+    .el-pagination.is-background .btn-next,
+    .el-pagination.is-background .btn-prev,
+    .el-pagination.is-background .el-pager li {
+      background: transparent;
+      border: 1px solid #00000026;
+      color: #000000a6;
     }
+
+    .el-pagination.is-background .is-active {
+      background: #1890ff !important;
+      border: none !important;
+      color: #fff !important;
+      font-weight: normal;
+    }
+  }
+}
+
+.event-media {
+  border: 1px solid #f0f0f0;
+
+  &-title {
+    background: #fbfbfb;
+    padding: 10px;
+    font-size: 14px;
+    color: #000000;
   }
 
-  .update-log {
-    ol {
-      display: block;
-      list-style-type: decimal;
-      margin-block-start: 1em;
-      margin-block-end: 1em;
-      margin-inline-start: 0;
-      margin-inline-end: 0;
-      padding-inline-start: 40px;
+  &-content {
+    padding: 20px;
+
+    .imgs {
+      display: flex;
+      flex-wrap: wrap;
+
+      .el-image {
+        height: 100px;
+        width: 100px;
+        margin-right: 10px;
+        border-radius: 4px;
+        margin-top: 10px;
+      }
     }
+
+    .videos {
+      display: flex;
+      flex-wrap: wrap;
+
+      div {
+        height: 200px;
+        width: 32%;
+        border-radius: 4px;
+        margin-right: 10px;
+        margin-top: 10px;
+      }
+    }
+  }
+}
+
+.report-btn {
+  text-align: center;
+  margin-top: 20px;
+
+  img {
+    height: 62px;
+    cursor: pointer;
   }
 }
+.hidden-report {
+  position: absolute;
+  visibility: hidden;
+  left: -9999px;
+  top: -9999px;
+  width: max-content;
+  height: max-content;
+  display: inline-block;
+  contain: layout;
+}
+
+.report-content {
+  width: 800px;
+  height: auto;
+  padding: 20px;
+  background-color: #fff;
+  border: 1px solid #eee;
+}
+.report-editor {
+  margin-top: 20px;
+}
+.report-title {
+  color: #5d5d5dd9;
+  font-size: 14px;
+}
 </style>

+ 2 - 2
plus-ui-ts/vite/plugins/index.ts

@@ -1,5 +1,5 @@
 import vue from '@vitejs/plugin-vue';
-import vueDevTools from 'vite-plugin-vue-devtools';
+// import vueDevTools from 'vite-plugin-vue-devtools';
 
 import createUnoCss from './unocss';
 import createAutoImport from './auto-import';
@@ -13,7 +13,7 @@ import path from 'path';
 export default (viteEnv: any, isBuild = false): [] => {
   const vitePlugins: any = [];
   vitePlugins.push(vue());
-  vitePlugins.push(vueDevTools());
+  // vitePlugins.push(vueDevTools());
   vitePlugins.push(createUnoCss());
   vitePlugins.push(createAutoImport(path));
   vitePlugins.push(createComponents(path));

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio