|
@@ -0,0 +1,348 @@
|
|
|
+<template>
|
|
|
+ <van-cell-group inset class="mobile-stats">
|
|
|
+ <van-cell title="今日事件统计" :border="false">
|
|
|
+ <template #extra>
|
|
|
+ <van-tag plain type="primary">{{ formatTime }}</van-tag>
|
|
|
+ </template>
|
|
|
+ </van-cell>
|
|
|
+
|
|
|
+ <van-grid :border="false" :column-num="2">
|
|
|
+ <van-grid-item>
|
|
|
+ <div class="stat-card total">
|
|
|
+ <div class="value">{{ stats.total }}</div>
|
|
|
+ <div class="label">事件总数</div>
|
|
|
+ <van-icon name="todo-list-o" size="16" />
|
|
|
+ </div>
|
|
|
+ </van-grid-item>
|
|
|
+
|
|
|
+ <van-grid-item>
|
|
|
+ <div class="stat-card success">
|
|
|
+ <div class="value">{{ stats.completed }}</div>
|
|
|
+ <div class="label">已完成</div>
|
|
|
+ <div style="display: flex; justify-content: center">
|
|
|
+ <van-tag
|
|
|
+ round
|
|
|
+ type="success"
|
|
|
+ style="
|
|
|
+ width: 80px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ "
|
|
|
+ >
|
|
|
+ {{ getPercentage(stats.completed) }}%
|
|
|
+ </van-tag>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </van-grid-item>
|
|
|
+
|
|
|
+ <van-grid-item>
|
|
|
+ <div class="stat-card danger">
|
|
|
+ <div class="value">{{ stats.pending }}</div>
|
|
|
+ <div class="label">未处理</div>
|
|
|
+ <div style="display: flex; justify-content: center">
|
|
|
+ <van-tag
|
|
|
+ round
|
|
|
+ type="danger"
|
|
|
+ style="
|
|
|
+ width: 80px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <van-icon name="warning-o" /> {{ getPercentage(stats.pending) }}%
|
|
|
+ </van-tag>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </van-grid-item>
|
|
|
+
|
|
|
+ <van-grid-item>
|
|
|
+ <div class="stat-card warning">
|
|
|
+ <div class="value">{{ stats.processing }}</div>
|
|
|
+ <div class="label">处理中</div>
|
|
|
+ <div style="display: flex; justify-content: center">
|
|
|
+ <van-tag
|
|
|
+ round
|
|
|
+ type="warning"
|
|
|
+ style="
|
|
|
+ width: 80px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <van-icon name="clock-o" /> {{ getPercentage(stats.processing) }}%
|
|
|
+ </van-tag>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </van-grid-item>
|
|
|
+ </van-grid>
|
|
|
+
|
|
|
+ <div class="refresh-area">
|
|
|
+ <van-button round size="small" :loading="loading" @click="refreshData">
|
|
|
+ <template #icon>
|
|
|
+ <van-icon name="replay" />
|
|
|
+ </template>
|
|
|
+ 刷新数据
|
|
|
+ </van-button>
|
|
|
+ </div>
|
|
|
+ </van-cell-group>
|
|
|
+ <div class="change-container">
|
|
|
+ <div class="duty-card">
|
|
|
+ <el-table :data="dataList" border table-layout="auto">
|
|
|
+ <el-table-column label="事件编号" prop="data5" align="center" />
|
|
|
+ <el-table-column label="事件" prop="data1" align="center" />
|
|
|
+ <el-table-column label="发生时间" prop="data2" align="center" />
|
|
|
+ <el-table-column label="事件类型" prop="data2" align="center" />
|
|
|
+ <el-table-column label="紧急程度" prop="data6" align="center" />
|
|
|
+ <el-table-column label="状态" prop="data4" align="center" />
|
|
|
+ <el-table-column label="负责人" prop="data7" align="center" />
|
|
|
+ <el-table-column label="剩余响应时限" prop="data8" align="center" />
|
|
|
+ <el-table-column label="操作" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <div
|
|
|
+ v-if="scope.row.data4 === '待处理'"
|
|
|
+ class="btn"
|
|
|
+ style="color: #1d92ff"
|
|
|
+ @click="showDetails(scope.row)"
|
|
|
+ >
|
|
|
+ 处理并报送
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <van-popup v-model:show="showPicker">
|
|
|
+ <van-form @submit="onSubmit">
|
|
|
+ <div class="van-doc-block__title">事件处理</div>
|
|
|
+ <van-cell-group inset>
|
|
|
+ <van-field
|
|
|
+ v-model="form.name"
|
|
|
+ label="处理人"
|
|
|
+ placeholder="请输入处理人姓名"
|
|
|
+ />
|
|
|
+ </van-cell-group>
|
|
|
+ <div class="popup-footer">
|
|
|
+ <van-button class="cancel-btn" @click="handleCancel"
|
|
|
+ >取 消</van-button
|
|
|
+ >
|
|
|
+ <van-button type="primary" native-type="submit" class="confirm-btn"
|
|
|
+ >确 定</van-button
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </van-form>
|
|
|
+ </van-popup>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import { ref, computed, onMounted } from "vue";
|
|
|
+import { Toast } from "vant";
|
|
|
+import { ElTable, ElTableColumn } from "element-plus";
|
|
|
+
|
|
|
+const loading = ref(false);
|
|
|
+const showPicker = ref(false);
|
|
|
+const form = ref({
|
|
|
+ name: ""
|
|
|
+});
|
|
|
+const stats = ref({
|
|
|
+ total: 0,
|
|
|
+ pending: 0,
|
|
|
+ processing: 0,
|
|
|
+ completed: 0
|
|
|
+});
|
|
|
+
|
|
|
+const showDetails = () => {
|
|
|
+ showPicker.value = true;
|
|
|
+};
|
|
|
+const handleCancel = () => {
|
|
|
+ form.value.name = "";
|
|
|
+ showPicker.value = false;
|
|
|
+};
|
|
|
+// 获取当前时间
|
|
|
+const formatTime = computed(() => {
|
|
|
+ return new Date().toLocaleTimeString("zh-CN", {
|
|
|
+ hour: "2-digit",
|
|
|
+ minute: "2-digit"
|
|
|
+ });
|
|
|
+});
|
|
|
+
|
|
|
+// 计算百分比
|
|
|
+const getPercentage = value => {
|
|
|
+ if (stats.value.total === 0) return 0;
|
|
|
+ return Math.round((value / stats.value.total) * 100);
|
|
|
+};
|
|
|
+
|
|
|
+// 模拟数据获取
|
|
|
+const fetchData = () => {
|
|
|
+ loading.value = true;
|
|
|
+ // 模拟API请求延迟
|
|
|
+ setTimeout(() => {
|
|
|
+ stats.value = {
|
|
|
+ total: 42 + Math.floor(Math.random() * 5),
|
|
|
+ pending: Math.max(0, 8 + Math.floor(Math.random() * 3) - 1),
|
|
|
+ processing: 12 + Math.floor(Math.random() * 4) - 2,
|
|
|
+ completed: 22 + Math.floor(Math.random() * 3)
|
|
|
+ };
|
|
|
+ loading.value = false;
|
|
|
+ Toast.success("数据已更新");
|
|
|
+ }, 800);
|
|
|
+};
|
|
|
+
|
|
|
+// 手动刷新
|
|
|
+const refreshData = () => {
|
|
|
+ fetchData();
|
|
|
+};
|
|
|
+
|
|
|
+const dataList = ref([
|
|
|
+ {
|
|
|
+ data1: "网络安全攻击",
|
|
|
+ data2: "2025-4-14",
|
|
|
+ data3: "紧急",
|
|
|
+ data4: "待处理",
|
|
|
+ data5: "1020495",
|
|
|
+ data6: "网络攻击",
|
|
|
+ data7: "张三",
|
|
|
+ data8: "8小时"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ data1: "电力系统故障",
|
|
|
+ data2: "2025-4-14",
|
|
|
+ data3: "高",
|
|
|
+ data4: "处理中",
|
|
|
+ data5: "1020495",
|
|
|
+ data6: "电力故障",
|
|
|
+ data7: "张三",
|
|
|
+ data8: "8小时"
|
|
|
+ }
|
|
|
+]);
|
|
|
+
|
|
|
+// 初始化加载
|
|
|
+onMounted(fetchData);
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+.change-container {
|
|
|
+ .duty-card {
|
|
|
+ margin-left: 10px;
|
|
|
+ margin-right: 10px;
|
|
|
+ margin-top: 16px;
|
|
|
+ //width: 100%;
|
|
|
+ background-color: #fff;
|
|
|
+ border-radius: 4px;
|
|
|
+ &:first-child {
|
|
|
+ margin-top: 0;
|
|
|
+ }
|
|
|
+ .duty-header {
|
|
|
+ padding: 10px;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: bold;
|
|
|
+ border-bottom: 1px solid #f0f1f1;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ .add-text {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #2c81ff;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .duty-content {
|
|
|
+ padding: 10px;
|
|
|
+ .duty-item {
|
|
|
+ padding: 3px 0;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: flex-start;
|
|
|
+ font-size: 14px;
|
|
|
+ .item-left {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ .icon {
|
|
|
+ display: inline-block;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .duty-item2 {
|
|
|
+ padding: 5px;
|
|
|
+ font-size: 14px;
|
|
|
+ background-color: #f2f2f2;
|
|
|
+ border-radius: 4px;
|
|
|
+ margin-top: 10px;
|
|
|
+ &:first-child {
|
|
|
+ margin-top: 0;
|
|
|
+ }
|
|
|
+ .text1 {
|
|
|
+ font-size: 12px;
|
|
|
+ color: rgba(0, 0, 0, 0.45);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.mobile-stats {
|
|
|
+ margin: 12px;
|
|
|
+ border-radius: 12px;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+/* 统计卡片通用样式 */
|
|
|
+.stat-card {
|
|
|
+ //padding: 12px;
|
|
|
+ width: 150px;
|
|
|
+ border-radius: 8px;
|
|
|
+ text-align: center;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+
|
|
|
+/* 各状态卡片颜色 */
|
|
|
+.stat-card.total {
|
|
|
+ background-color: #f0f9ff;
|
|
|
+}
|
|
|
+.stat-card.success {
|
|
|
+ background-color: #f6ffed;
|
|
|
+}
|
|
|
+.stat-card.danger {
|
|
|
+ background-color: #fff2f0;
|
|
|
+}
|
|
|
+.stat-card.warning {
|
|
|
+ background-color: #fffbe6;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-card .value {
|
|
|
+ font-size: 24px;
|
|
|
+ font-weight: bold;
|
|
|
+ line-height: 1.2;
|
|
|
+ margin-bottom: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-card .label {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #666;
|
|
|
+ margin-bottom: 6px;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-card :deep(.van-tag) {
|
|
|
+ margin-top: 4px;
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 刷新区域 */
|
|
|
+.refresh-area {
|
|
|
+ text-align: center;
|
|
|
+ padding: 8px 0;
|
|
|
+}
|
|
|
+
|
|
|
+///* 移动端适配 */
|
|
|
+//@media (max-width: 320px) {
|
|
|
+// .stat-card .value {
|
|
|
+// font-size: 20px;
|
|
|
+// }
|
|
|
+//}
|
|
|
+</style>
|