SOURCE

console 命令行工具 X clear

                    
>
console
<!DOCTYPE html>
<html lang="zh-CN">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>响应式工作台</title>
	<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
  <script src="https://unpkg.com/element-ui/lib/index.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.6/Sortable.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vuedraggable@2.24.3/dist/vuedraggable.umd.min.js"></script>
	<style>
		.dashboard-container {
			padding: 20px;
			max-width: 1800px;
			margin: 0 auto;
		}

		.dashboard-grid {
			display: grid;
			grid-template-columns: repeat(2, 1fr);
			gap: 20px;
		}

		.dashboard-module {
			background: #fff;
			border-radius: 4px;
			box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
			padding: 20px;
			min-height: 200px;
			display: flex;
			align-items: center;
			justify-content: center;
			font-size: 18px;
			color: #666;
		}

		.module-title {
			font-weight: bold;
			margin-bottom: 15px;
			font-size: 16px;
			color: #333;
		}

		.module-content {
			width: 100%;
		}

		.drag-handle {
			cursor: move;
			margin-right: 10px;
			color: #909399;
		}

		.module-item {
			display: flex;
			align-items: center;
			padding: 10px 0;
			border-bottom: 1px solid #ebeef5;
		}

		.module-item:last-child {
			border-bottom: none;
		}

		.module-item-content {
			flex: 1;
			display: flex;
			align-items: center;
		}

		@media (max-width: 768px) {
			.dashboard-grid {
				grid-template-columns: 1fr;
			}
		}
	</style>
</head>

<body>
	<div id="app">
		<div class="dashboard-container">
			<el-button type="primary" @click="showModuleDialog">模块配置</el-button>

			<div class="dashboard-grid">
				<div v-for="module in visibleModules" :key="module.components" class="dashboard-module" :data-module="module.components">
					<div class="module-content">
						<div class="module-title">{{ module.name }}</div>
						<div>这是 {{ module.name }} 的内容区域</div>
					</div>
				</div>
			</div>

			<el-dialog title="模块配置" :visible.sync="moduleDialogVisible" width="600px">
				<div>
					<el-alert title="拖拽可以调整模块顺序,开关控制模块显示/隐藏" type="info" show-icon style="margin-bottom: 20px;"></el-alert>

					<draggable v-model="moduleList" handle=".drag-handle" @end="onDragEnd">
						<transition-group>
							<div v-for="module in moduleList" :key="module.components" class="module-item">
								<div class="module-item-content">
									<i class="el-icon-rank drag-handle"></i>
                  <span style="flex: 1;">{{ module.name }}</span>
                  <el-switch 
                    v-model="module.check" 
                    @change="handleModuleChange(module)"
                  ></el-switch>
                </div>
              </div>
            </transition-group>
          </draggable>
        </div>
      </el-dialog>
    </div>
  </div>

  
  <script>
      new Vue({
  el: '#app',
  components: {
    draggable: window.vuedraggable
  },
  data() {
    return {
      DASHBOARD_MODULES_MAP: [
        {name:"客诉工单统计",value:"dashboard:workOrderStatistics",disabled:false,check:true,components:"modulesBlock1"},
        {name:"投诉率统计",value:"dashboard:workOrderComplaintRate",disabled:false,check:true,components:"modulesBlock2"},
        {name:"二次投诉统计",value:"dashboard:workOrderSecondComplaintRate",disabled:false,check:true,components:"modulesBlock3"},
        {name:"客诉处理环节结单时间占比",value:"dashboard:workOrderFinishedRate",disabled:false,check:true,components:"modulesBlock4"},
        {name:"周期统计",value:"dashboard:workOrderCycleRate",disabled:false,check:true,components:"modulesBlock5"},
        {name:"本月前十省份产品故障工单数统计",value:"dashboard:workOrderProvinceRate",disabled:false,check:true,components:"modulesBlock6"},
        {name:"本月前十产品故障工单数统计",value:"dashboard:workOrderProductRate",disabled:false,check:true,components:"modulesBlock7"},
        {name:"作业统计",value:"dashboard:job",disabled:false,check:true,components:"modulesBlock8"},
        {name:"调试完工统计",value:"dashboard:complete",disabled:false,check:true,components:"modulesBlock9"},
        {name:"电梯完工统计",value:"dashboard:closing",disabled:false,check:true,components:"modulesBlock10"},
        {name:"电梯统计(外品牌)",value:"dashboard:hta",disabled:false,check:true,components:"modulesBlock11"},
        {name:"电梯统计(CL-MEU)",value:"dashboard:clmeu",disabled:false,check:true,components:"modulesBlock12"},
        {name:"电梯统计(IOT-WL)",value:"dashboard:lotwl",disabled:false,check:true,components:"modulesBlock13"},
        {name:"电梯终端在线率(近三十天)",value:"dashboard:onlineRateOfElevator",disabled:false,check:true,components:"modulesBlock14"},
        {name:"调验得分统计",value:"dashboard:debugScore",disabled:false,check:true,components:"modulesBlock15"},
        {name:"直签项目管理",value:"dashboard:subscribe",disabled:false,check:true,components:"modulesBlock16"},
        {name:"调试项目管理",value:"dashboard:debug",disabled:false,check:true,components:"modulesBlock17"},
        {name:"故障中心",value:"dashboard:fault",disabled:false,check:true,components:"modulesBlock18"},
        {name:"即将到期合同",value:"dashboard:contract",disabled:false,check:true,components:"modulesBlock19"},
        {name:"地图",value:"dashboard:map",disabled:false,check:true,components:"modulesBlock20"}
      ],
      quanxians: [
        'dashboard:job',
        'dashboard:clmeu',
        'dashboard:lotwl',
        'dashboard:fault',
        'dashboard:publish',
        'dashboard:contract',
        'dashboard:map',
        'globalRealTimeMsg:urgentrepair',
        'globalRealTimeMsg:fault',
        'globalRealTimeMsg:maintenanceFinish',
        'globalRealTimeMsg:urgentrepairFinish',
        'dashboard:subscribe',
        'dashboard:subscribe-total',
        'dashboard:debug',
        'dashboard:closing',
        'dashboard:subscribe-onEvidence',
        'dashboard:subscribe-completeExceed',
        'dashboard:subscribe-exceedEvidence',
        'dashboard:subscribe-yearEvidence',
        'dashboard:subscribe-monthEvidence',
        'dashboard:subscribe-catalogue',
        'dashboard:subscribe-suspend',
        'dashboard:subscribe-cancelContract',
        'dashboard:subscribe-enclosure',
        'dashboard:subscribe-check',
        'dashboard:subscribe-installPrepare',
        'dashboard:subscribe-installationPhase',
        'dashboard:subscribe-debugPhase',
        'dashboard:subscribe-acceptancePhase',
        'dashboard:subscribe-closingPhase',
        'dashboard:onlineRateOfElevator',
        'dashboard:debugScore',
        'dashboard:workOrderStatistics',
        'dashboard:workOrderComplaintRate',
        'dashboard:workOrderSecondComplaintRate',
        'dashboard:workOrderFinishedRate',
        'dashboard:workOrderProvinceRate',
        'dashboard:workOrderProductRate',
        'dashboard:workOrderCycleRate'
      ],
      moduleDialogVisible: false,
      moduleList: [],
      originalModuleList: []
    }
  },
  computed: {
    visibleModules() {
      // 1. 根据权限过滤模块
      const filteredByPermission = this.DASHBOARD_MODULES_MAP.filter(module => 
        this.quanxians.includes(module.value)
      );
      
      // 2. 根据本地存储的配置过滤模块
      const savedConfig = this.getSavedModuleConfig();
      if (savedConfig && savedConfig['grcloud-dashboard']) {
        const savedComponents = savedConfig['grcloud-dashboard'];
        
        return filteredByPermission.filter(module => {
          const savedModule = this.moduleList.find(m => m.components === module.components);
          return savedModule ? savedModule.check : module.check;
        }).sort((a, b) => {
          const indexA = savedComponents.indexOf(a.components);
          const indexB = savedComponents.indexOf(b.components);
          
          if (indexA === -1) return 1;
          if (indexB === -1) return -1;
          return indexA - indexB;
        });
      }
      
      // 3. 默认返回根据权限过滤且check为true的模块
      return filteredByPermission.filter(module => module.check);
    }
  },
  created() {
    this.initModuleList();
  },
  methods: {
    initModuleList() {
      const savedConfig = this.getSavedModuleConfig();
      
      if (savedConfig && savedConfig['grcloud-dashboard']) {
        const savedComponents = savedConfig['grcloud-dashboard'];
        
        this.moduleList = this.DASHBOARD_MODULES_MAP.map(module => {
          const savedModuleIndex = savedComponents.indexOf(module.components);
          return {
            ...module,
            check: savedModuleIndex !== -1
          };
        }).sort((a, b) => {
          const indexA = savedComponents.indexOf(a.components);
          const indexB = savedComponents.indexOf(b.components);
          
          if (indexA === -1 && indexB === -1) return 0;
          if (indexA === -1) return 1;
          if (indexB === -1) return -1;
          return indexA - indexB;
        });
      } else {
        this.moduleList = [...this.DASHBOARD_MODULES_MAP];
      }
      
      this.originalModuleList = [...this.moduleList];
    },
    showModuleDialog() {
      this.moduleDialogVisible = true;
    },
    handleModuleChange(module) {
      // 实时更新模块状态
      const index = this.moduleList.findIndex(m => m.components === module.components);
      if (index !== -1) {
        this.moduleList.splice(index, 1, module);
      }
    },
    onDragEnd() {
      // 拖拽结束,实时更新顺序
      this.saveModuleConfig();
    },
    saveModuleConfig() {
      const config = {
        'grcloud-dashboard': this.moduleList
          .filter(module => module.check)
          .map(module => module.components)
      };
      
      localStorage.setItem('dashboard-modules-config', JSON.stringify(config));
      this.$message.success('模块配置保存成功');
      this.initModuleList();
    },
    getSavedModuleConfig() {
      const configStr = localStorage.getItem('dashboard-modules-config');
      try {
        return configStr ? JSON.parse(configStr) : null;
      } catch (e) {
        return null;
      }
    }
  }
});
  </script>
</body>
</html>