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() {
const filteredByPermission = this.DASHBOARD_MODULES_MAP.filter(module =>
this.quanxians.includes(module.value)
);
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;
});
}
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>