feat: 从甘肃完整复制过来,下一步在改内容

This commit is contained in:
2026-01-16 14:35:57 +08:00
parent 5f291c4ffb
commit 9236ef0280
2037 changed files with 563859 additions and 0 deletions

View File

@ -0,0 +1,135 @@
<template>
<div class="industry-center-container">
<!-- <div class="title">行业预警中心</div> -->
<div class="industry-center-header">
<div class="tab-container">
<el-tabs v-model="activeTab" type="card" @tab-click="onTabClick">
<el-tab-pane :label="item.label" :name="item.value" v-for="(item, i) in tabList" :key="i" />
</el-tabs>
</div>
<el-select style="width: 230px;" v-model="yearValue" placeholder="请选择年份">
<el-option v-for="item in yearList" :key="item" :label="item" :value="item" />
</el-select>
<el-button style="margin-left: 15px;" v-if="activeTab !== 'synthesis'" type="primary"
@click="onDownLoad">下载预警信息</el-button>
<el-button style="margin-left: 15px;" type="primary"
@click="configShow">{{activeTab === 'synthesis' ? '配置' : '查看配置'}}</el-button>
</div>
<div class="industry-center-content">
<div class="right-content">
<ThresholdAndSpecial ref="thresholdAndSpecialRef"
v-if="activeTab === 'threshold' || activeTab === 'special'" :yearValue="yearValue" />
<Synthesis ref="synthesisRef" v-if="activeTab === 'synthesis'" :yearValue="yearValue" />
</div>
</div>
<specialTable v-if="isShowSpecialTableTable" @close="isShowSpecialTableTable = false" />
<ThresholdTable v-if="isShowThresholdTable" @close="isShowThresholdTable = false" />
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import ThresholdAndSpecial from './tabsCom/ThresholdAndSpecial.vue'
import Synthesis from './tabsCom/Synthesis.vue'
import specialTable from './tabsCom/specialTable.vue'
import ThresholdTable from './tabsCom/ThresholdTable.vue'
const yearList = ref([])
const yearValue = ref(new Date().getFullYear())
const activeTab = ref('synthesis')
const thresholdAndSpecialRef = ref()
const synthesisRef = ref()
const isShowSpecialTableTable = ref(false)
const isShowThresholdTable = ref(false)
const tabList = ref([
{ label: '综合预警', value: 'synthesis' },
{ label: '阈值预警', value: 'threshold' },
{ label: '专项预警', value: 'special' },
])
const onTabClick = (tab) => {
console.log(tab)
}
const onDownLoad = () => {
console.log('下载。。')
if (typeof thresholdAndSpecialRef.value?.onDownLoad === 'function') {
thresholdAndSpecialRef.value.onDownLoad()
}
}
const configShow = () => {
console.log('配置。。')
if (activeTab.value === 'special') {
isShowSpecialTableTable.value = true
}
if (activeTab.value === 'threshold') {
isShowThresholdTable.value = true
}
}
onMounted(() => {
yearList.value = Array.from({ length: 10 }, (_, index) => new Date().getFullYear() - index)
})
</script>
<style lang="scss" scoped>
@import "@/views/dutyBook/jgryandzz/talentPool/tabContainer.scss";
/**tab-container.部分样式在 上面tabContainer.scss 文件中 */
.tab-container {
margin-left: 5px;
}
.industry-center-container {
width: 100%;
height: calc(100vh - 140px);
}
.industry-center-header {
display: flex;
// padding: 5px 10px;
align-items: center;
background-color: #fff;
}
.industry-center-content {
display: flex;
width: 100%;
height: calc(100vh - 182px);
// margin-top: 10px;
}
.left-tab {
width: 70px;
.left-tab-item {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
width: 100%;
height: 160px;
cursor: pointer;
background-color: #fff;
color: #000;
border-bottom: 1px solid var(--el-table-border-color);
.left-tab-item-img {
width: 50px;
height: 50px;
margin-bottom: 10px;
}
&.active {
background-color: var(--el-color-primary);
}
}
}
.right-content {
// width: calc(100% - 70px);
height: 100%;
}
</style>

View File

@ -0,0 +1,168 @@
<template>
<div class="synthesis-container">
<div class="synthesis-left">
<div class="synthesis-left-top">
<div class="synthesis-left-top-container">
<div class="synthesis-left-top-left">
<div>行业预警得分</div>
<div>
单位排行榜
</div>
</div>
<div class="synthesis-left-top-right">
<el-image style="width: 100px; height: 100%" :src="require('@/assets/images/jcgl_bj.png')"
fit="cover"></el-image>
</div>
</div>
</div>
<div class="synthesis-left-content">
<div class="synthesis-left-content-title">
<span class="col-1">
排序
</span>
<span class="col-2">
名称
</span>
<span class="col-3">
分数
</span>
</div>
<div class="synthesis-left-content-list">
<div v-for="(item, index) in 99" :key="index" class="synthesis-left-content-item">
<span class="rank-col-1">
<span class="rank-col-1-num">
{{ (index + 1) < 10 ? '0' + (index + 1) : (index + 1) }} </span>
</span>
<span class="rank-col-2">
甘肃兰州
</span>
<span class="rank-col-3">
99.99
</span>
</div>
</div>
</div>
</div>
<div class="synthesis-right">
<div class="synthesis-right-top">
<ScoreGlobe style="width: calc(50% - 5px);margin-right: 10px;" />
<LineChart style="width: calc(50% - 5px);" />
</div>
<SynthesisTable style="margin-top: 10px;" />
</div>
</div>
</template>
<script setup>
import ScoreGlobe from './synthesisCom/ScoreGlobe.vue';
import LineChart from './synthesisCom/lineChart.vue'
import SynthesisTable from './synthesisCom/synthesisTable.vue'
</script>
<style lang="scss" scoped>
.synthesis-container {
width: 100%;
height: 100%;
// background-color: #fff;
display: flex;
.synthesis-left {
width: 380px;
height: 100%;
margin-right: 10px;
.synthesis-left-content {
height: calc(100% - 100px);
padding: 10px;
font-weight: bolder;
color: #000;
background-color: #fff;
.synthesis-left-content-title {
display: flex;
border-radius: 2px;
background-color: #f0f0f0;
.col-1 {
display: inline-block;
width: 100px;
text-align: center;
padding: 6px 10px;
}
.col-2 {
display: inline-block;
// width: 180px;
flex: 1;
text-align: center;
padding: 6px 10px;
}
.col-3 {
display: inline-block;
width: 100px;
text-align: center;
padding: 6px 10px;
}
}
.synthesis-left-content-list {
height: calc(100% - 30px);
overflow: auto;
.synthesis-left-content-item {
display: flex;
border-bottom: 1px solid #ededee;
.rank-col-1 {
display: inline-block;
width: 100px;
text-align: center;
padding: 6px 10px;
.rank-col-1-num {
display: inline-block;
width: 22px;
height: 22px;
text-align: center;
line-height: 22px;
border-radius: 50%;
color: #fff;
background-color: var(--el-color-primary);
}
}
.rank-col-2 {
display: inline-block;
flex: 1;
// width: 180px;
text-align: center;
padding: 6px 10px;
}
.rank-col-3 {
display: inline-block;
width: 100px;
text-align: center;
padding: 6px 10px;
color: var(--el-color-primary);
}
}
}
}
}
.synthesis-right {
flex: 1;
padding-top: 10px;
.synthesis-right-top {
display: flex;
height: 280px;
width: 100%;
}
}
}
</style>

View File

@ -0,0 +1,179 @@
<template>
<div class="threshold-container">
<div class="top">
<div class="mapleft">
<!-- 地图 -->
<div class="tabBox">
<!-- <BigMap /> -->
</div>
</div>
<div class="mapright">
<div class="title">
<img src="@/assets/map/yujing.png" alt="">
<span class="ml5">预警图标</span>
</div>
<div>
<ul>
<li v-for="it in yjzblist" :key="it" class="libox">
<div style="width: 78%;">
<div class="name">{{ it.name }}</div>
<div class="num">{{ it.num }}</div>
</div>
<div class="iconmg">
<img src="@/assets/map/yujing.png" alt="">
</div>
</li>
</ul>
</div>
</div>
</div>
<div class="btom">
<ul class="one">
<li v-for="item in list" :key="item" class="ont_li">
<span style="font-size: 15px;font-weight: 600;">{{ item.title }}</span>
<div v-for="it in item.lists" :key="it" class="mt10 boxss">
<span class="coubox">{{ it.name }}</span><span class="szbox">{{ it.num }}</span>
</div>
</li>
</ul>
</div>
</div>
</template>
<script setup>
// 引入
import { onMounted, ref, onBeforeUnmount } from "vue";
// import BigMap from "@/components/Map/yjMap.vue";
import * as MOSTY from "@/components/MyComponents/index";
import { useRouter } from "vue-router";
const router = useRouter();
import { useStore } from "vuex";
const store = useStore();
const yjzblist = ref([
{ name: '安全工程师岗位聘任比率', num: '6.93%' },
{ name: '专职驾驶员体检率', num: '2.93%' },
{ name: '电工体检率', num: '6.93%' },
{ name: '安全协议签订率', num: '6.93%' },
{ name: '相关方资质符合率', num: '6.93%' },
{ name: '使用超过8年车辆占比', num: '6.93%' },
{ name: '较大风险(橙区)现状风险单元数量', num: '6.93%' },
{ name: '隐患按期整改率', num: '6.93%' },
])
const list = ref([
{ title: '安全管理队伍', lists: [{ name: '安全管理人员数占比', num: '1.67%' }] },
{ title: '建筑物', lists: [{ name: '安全管理人员数占比', num: '1.67%' }, { name: '安全管理人员数占比', num: '1.67%' }] },
{ title: '职业健康', lists: [{ name: '安全管理人员数占比', num: '1.67%' }] },
{ title: '道路交通', lists: [{ name: '安全管理人员数占比', num: '1.67%' }] },
])
onMounted(() => {
});
</script>
<style lang="scss" scoped>
.threshold-container {
background: #f0f3fa;
}
.top {
height: calc(100vh - 359px);
display: flex;
}
.mapleft {
width: 58%;
.tabBox {
height: calc(100vh - 359px);
}
}
.mapright {
width: 42%;
padding: 10px;
background-color: #fff;
.title {
font-size: 18px;
color: #000;
}
ul {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
}
}
.libox {
width: 215px;
display: flex;
justify-content: space-between;
background: rgba(243, 198, 183, 0.5607843137);
padding: 10px;
margin: 8px;
.name {
font-size: 14px;
color: #000;
}
.num {
font-size: 20px;
color: red;
}
.iconmg {
>img {
height: 31px;
}
}
}
.one {
display: flex;
justify-content: start;
.ont_li {
padding: 10px;
margin: 10px;
background: #ffffff7a;
color: #000;
height: 159px;
}
}
.coubox {
display: inline-block;
width: 60%;
overflow: hidden; // 溢出隐藏
white-space: nowrap; // 强制一行
text-overflow: ellipsis; // 文字溢出显示省略号
}
.szbox {
color: var(--el-color-primary);
font-size: 15px;
font-weight: 600;
}
.boxss {
display: flex;
justify-content: space-between;
background: linear-gradient(378deg, #a8e3f5 0%, #c7ebf13d 100%);
padding: 5px;
}
</style>

View File

@ -0,0 +1,286 @@
<template>
<!-- <div class="synthesis-conf-container"> -->
<el-dialog v-model="dialogVisible" title="配置" width="85vw" :before-close="close">
<div class="synthesis-conf-content">
<el-table :data="tableData" height="calc(100vh - 250px)" border @selection-change="selectionChange"
:span-method="arraySpanMethod">
<el-table-column type="index" width="55" label="序号" />
<el-table-column prop="warningModule" label="预警模块" width="180"></el-table-column>
<el-table-column prop="warningIndex" label="预警指标" width="180"></el-table-column>
<el-table-column prop="indexRule" label="指标规则" width="300"></el-table-column>
<el-table-column prop="thresholdDefaultConfig" label="阈值默认配置" width="150"></el-table-column>
<el-table-column prop="threshold" label="阈值" width="100">
<template #default="scope">
<span>{{ scope.row.threshold }}%</span>
</template>
</el-table-column>
</el-table>
</div>
<template #footer>
<!-- <el-button type="primary" @click="ok">保存</el-button> -->
<el-button @click="close">关闭</el-button>
</template>
</el-dialog>
<!-- </div> -->
</template>
<script setup>
import { ref } from 'vue';
const dialogVisible = ref(true);
const emit = defineEmits(['ok', 'close']);
const tableData = [
{
"warningModule": "综合管理",
"warningIndex": "安全管理机构设置比率",
"indexRule": "独立设置安全管理机构单位数量/应独立设置安全管理机构数量*100%",
"thresholdDefaultConfig": "低于(不含)",
"threshold": 85
},
{
"warningModule": "综合管理",
"warningIndex": "安全生产标准化达标率",
"indexRule": "安全生产标准化达标单位数量/安全生产标准化应达标单位数量*100%",
"thresholdDefaultConfig": "低于(不含)",
"threshold": 80
},
{
"warningModule": "综合管理",
"warningIndex": "安全工程师岗位设置比率",
"indexRule": "设置安全工程师岗位单位数量/应设置安全工程师岗位单位数量*100%",
"thresholdDefaultConfig": "低于(不含)",
"threshold": 85
},
{
"warningModule": "安全管理队伍",
"warningIndex": "安全工程师岗位聘任比率",
"indexRule": "评聘安全工程师人数/专职安全管理人员数量*100%",
"thresholdDefaultConfig": "低于(不含)",
"threshold": 12
},
{
"warningModule": "安全管理队伍",
"warningIndex": "安全管理人员数占比",
"indexRule": "专职安全管理人员数量/从业人员总数*100%",
"thresholdDefaultConfig": "低于(不含)",
"threshold": 1
},
{
"warningModule": "",
"warningIndex": "高层民用建筑可燃外墙保温材料性能占比",
"indexRule": "高层民用建筑可燃外墙保温材料性能建筑数量/高层民用建筑总量*100%",
"thresholdDefaultConfig": "高于(不含)",
"threshold": 0
},
{
"warningModule": "",
"warningIndex": "高层民用建筑易燃外墙保温材料性能占比",
"indexRule": "高层民用建筑易燃外墙保温材料性能建筑数量/高层民用建筑总量*100%",
"thresholdDefaultConfig": "高于(不含)",
"threshold": 0
},
{
"warningModule": "",
"warningIndex": "联合工房易燃外墙保温材料性能占比",
"indexRule": "联合工房建筑易燃外墙保温材料性能建筑数量/联合工房建筑总量*100%",
"thresholdDefaultConfig": "高于(不含)",
"threshold": 0
},
{
"warningModule": "",
"warningIndex": "高层民用建筑消火栓系统设置比率",
"indexRule": "高层民用建筑设置消火栓系统建筑数量/高层民用建筑总数量*100%",
"thresholdDefaultConfig": "低于(不含)",
"threshold": 0
},
{
"warningModule": "",
"warningIndex": "高层民用建筑火灾自动报警系统设置比率",
"indexRule": "高层民用建筑设置火灾自动报警系统建筑数量/高层民用建筑总数量*100%",
"thresholdDefaultConfig": "低于(不含)",
"threshold": 0
},
{
"warningModule": "",
"warningIndex": "高层民用建筑自动灭火系统设置比率",
"indexRule": "高层民用建筑设置自动灭火系统建筑数量/高层民用建筑总数量*100%",
"thresholdDefaultConfig": "低于(不含)",
"threshold": 0
},
{
"warningModule": "",
"warningIndex": "联合工房消火栓系统设置比率",
"indexRule": "联合工房建筑设置消火栓系统建筑数量/联合工房建筑总数量*100%",
"thresholdDefaultConfig": "低于(不含)",
"threshold": 0
},
{
"warningModule": "",
"warningIndex": "联合工房火灾自动报警系统设置比率",
"indexRule": "联合工房建筑设置火灾自动报警系统建筑数量/联合工房建筑总数量*100%",
"thresholdDefaultConfig": "低于(不含)",
"threshold": 0
},
{
"warningModule": "仓储安全",
"warningIndex": "仓储消防设施设置比率",
"indexRule": "配置消火栓系统或火灾自动报警系统或自动灭火系统的(条件同分母)仓库数量/占地面积大于1500平方米或者总建筑面积大于3000平方米的单层库或多层库的仓库数量+立体库的仓库数量)*100%",
"thresholdDefaultConfig": "低于(不含)",
"threshold": 23
},
{
"warningModule": "职业健康和劳动保护",
"warningIndex": "专职驾驶员体检率",
"indexRule": "专职驾驶员特种作业人员体检数/驾驶员总数量*100%",
"thresholdDefaultConfig": "低于(不含)",
"threshold": 100
},
{
"warningModule": "职业健康和劳动保护",
"warningIndex": "电工体检率",
"indexRule": "电工特种作业人员体检数/电工总人数*100%",
"thresholdDefaultConfig": "低于(不含)",
"threshold": 100
},
{
"warningModule": "职业健康和劳动保护",
"warningIndex": "压力容器操作工体检率",
"indexRule": "压力容器操作工特种作业人员体检数/压力容器操作工总人数*100%",
"thresholdDefaultConfig": "低于(不含)",
"threshold": 100
},
{
"warningModule": "相关方",
"warningIndex": "安全协议签订率",
"indexRule": "签订安全协议相关数量/重点相关方总数量*100%",
"thresholdDefaultConfig": "低于(不含)",
"threshold": 100
},
{
"warningModule": "相关方",
"warningIndex": "相关方资质符合率",
"indexRule": "具备相应单位资质相关方数量/重点相关方总数量*100%",
"thresholdDefaultConfig": "低于(不含)",
"threshold": 100
},
{
"warningModule": "道路交通",
"warningIndex": "使用超过8年车辆占比",
"indexRule": "使用超过8年车辆数量/机动车辆总数*100%",
"thresholdDefaultConfig": "高于(不含)",
"threshold": 27
},
{
"warningModule": "道路交通",
"warningIndex": "使用超过30万公里车辆占比",
"indexRule": "使用超过30万公里车辆数量/机动车辆总数*100%",
"thresholdDefaultConfig": "高于(不含)",
"threshold": 27
},
{
"warningModule": "风险管控",
"warningIndex": "较大风险(橙区)现状风险单元数量(个)",
"indexRule": "较大风险(橙区)现状风险单元数量(个)",
"thresholdDefaultConfig": "高于(不含)",
"threshold": 0
},
{
"warningModule": "风险管控",
"warningIndex": "重大风险(红区)现状风险单元数量(个)",
"indexRule": "重大风险(红区)现状风险单元数量(个)",
"thresholdDefaultConfig": "高于(不含)",
"threshold": 0
},
{
"warningModule": "隐患治理",
"warningIndex": "隐患按期整改率",
"indexRule": "在整改期限小于等于统计周期最后一自然日内,隐患状态为\"已完成\"的隐患数量/整改期限小于等于统计周期最后一自然日的隐患数量*100%",
"thresholdDefaultConfig": "低于(不含)",
"threshold": 90
},
{
"warningModule": "隐患治理",
"warningIndex": "重大隐患占比",
"indexRule": "重大隐患数量/隐患总数*100%",
"thresholdDefaultConfig": "高于(不含)",
"threshold": 1
},
{
"warningModule": "事故事件",
"warningIndex": "交通事故万车死亡率",
"indexRule": "事故类型为\"道路交通机动车辆伤害”的死亡人数/车辆总数*10000",
"thresholdDefaultConfig": "高于(不含)",
"threshold": 1.38
},
{
"warningModule": "事故事件",
"warningIndex": "千人生产安全事故死亡率",
"indexRule": "事故类型为非\"道路交通机动车辆伤害”死亡人数/单位从业人数*1000",
"thresholdDefaultConfig": "高于(不含)",
"threshold": 0.01244
}
];
const form = ref({});
const ok = () => {
emit('ok');
};
/** 是否可选 */
const selectable = () => {
return true;
}
const selectionChange = (selection) => {
console.log('selectionChange', selection);
}
const arraySpanMethod = ({ row, column, rowIndex, columnIndex }) => {
// 第一列,,向下合并
if (columnIndex === 1) {
// 综合管理 合并3个 。对比excel序号少2个(因为列表序号从0开始而excel序号从2开始)
if (rowIndex === 0) return [3, 1]
if (rowIndex > 0 && rowIndex < 3) return [0, 0]
// 安全管理队伍 合并2个
if (rowIndex === 3) return [2, 1]
if (rowIndex > 3 && rowIndex < 5) return [0, 0]
// 无名菜单 (建筑) 合并 8个
if (rowIndex === 5) return [8, 1]
if (rowIndex > 5 && rowIndex < 13) return [0, 0]
// 仓储安全 合并 1个
if (rowIndex === 13) return [1, 1]
// 职业健康和劳动保护 合并 3个
if (rowIndex === 14) return [3, 1]
if (rowIndex > 14 && rowIndex < 17) return [0, 0]
// 相关方 合并 2个
if (rowIndex === 17) return [2, 1]
if (rowIndex > 17 && rowIndex < 19) return [0, 0]
// 道路交通 合并 2个
if (rowIndex === 19) return [2, 1]
if (rowIndex > 19 && rowIndex < 21) return [0, 0]
// 风险管控 合并 2个
if (rowIndex === 21) return [2, 1]
if (rowIndex > 21 && rowIndex < 23) return [0, 0]
// 隐患治理 合并 2个
if (rowIndex === 23) return [2, 1]
if (rowIndex > 23 && rowIndex < 25) return [0, 0]
// 事故事件 合并 2个
if (rowIndex === 25) return [2, 1]
if (rowIndex > 25 && rowIndex < 27) return [0, 0]
}
return [1, 1]
}
const close = () => {
emit('close');
};
// /** 设置table数据 */
// const setTable = ()=>{
// tableData.value = []
// }
</script>
<style lang="scss" scoped>
// .synthesis-conf-container {
// width: 100%;
// height: 100%;
// }</style>

View File

@ -0,0 +1,303 @@
<template>
<!-- <div class="synthesis-conf-container"> -->
<el-dialog v-model="dialogVisible" title="配置" width="85vw" :before-close="close">
<div class="synthesis-conf-content">
<el-table :data="tableData" height="calc(100vh - 250px)" border @selection-change="selectionChange"
:span-method="arraySpanMethod">
<el-table-column type="index" width="55" />
<el-table-column prop="warningProject" label="预警项目"></el-table-column>
<el-table-column prop="warningElement" label="预警要素"></el-table-column>
<el-table-column prop="warningThreshold" label="预警阈值"></el-table-column>
<el-table-column prop="warningLevel" label="预警等级"></el-table-column>
<el-table-column prop="businessModule" label="业务模块"></el-table-column>
<el-table-column prop="indicatorName" label="指标名称"></el-table-column>
<el-table-column prop="displayForm" label="显示形式"></el-table-column>
</el-table>
</div>
<template #footer>
<!-- <el-button type="primary" @click="ok">保存</el-button> -->
<el-button @click="close">关闭</el-button>
</template>
</el-dialog>
<!-- </div> -->
</template>
<script setup>
import { ref } from 'vue';
const dialogVisible = ref(true);
const emit = defineEmits(['ok', 'close']);
const tableData = [
{
warningProject: "风险单元预警",
warningElement: "风险单元",
warningThreshold: "出现红区风险单元(固有风险除外)",
warningLevel: "红",
businessModule: "14风险分级管控",
indicatorName: "不同级别现状风险单元数量",
displayForm: "风险单元"
},
{
warningProject: "风险单元预警",
warningElement: "风险单元",
warningThreshold: "出现橙区风险单元(固有风险除外)",
warningLevel: "橙",
businessModule: "14风险分级管控",
indicatorName: "不同级别现状风险单元数量",
displayForm: "风险单元"
},
{
warningProject: "风险单元预警",
warningElement: "重大隐患数量",
warningThreshold: "重大隐患数量≧2",
warningLevel: "红",
businessModule: "15隐患排查治理",
indicatorName: "重大隐患数量",
displayForm: "重大隐患数量"
},
{
warningProject: "风险单元预警",
warningElement: "重大隐患数量",
warningThreshold: "出现重大隐患",
warningLevel: "橙",
businessModule: "15隐患排查治理",
indicatorName: "重大隐患数量",
displayForm: "重大隐患数量"
},
{
warningProject: "风险单元预警",
warningElement: "同类别隐患占隐患总数",
warningThreshold: "同类别隐患占隐患总数超过70%",
warningLevel: "红",
businessModule: "15隐患排查治理",
indicatorName: "各隐患类别数量占比",
displayForm: "同类隐患占比"
},
{
warningProject: "风险单元预警",
warningElement: "同类别隐患占隐患总数",
warningThreshold: "同类别隐患占隐患总数超过60%",
warningLevel: "橙",
businessModule: "15隐患排查治理",
indicatorName: "各隐患类别数量占比",
displayForm: "同类隐患占比"
},
{
warningProject: "风险单元预警",
warningElement: "同类别隐患占隐患总数",
warningThreshold: "同类别隐患占隐患总数超过50%",
warningLevel: "黄",
businessModule: "15隐患排查治理",
indicatorName: "各隐患类别数量占比",
displayForm: "同类隐患占比"
},
{
warningProject: "风险单元预警",
warningElement: "隐患整改",
warningThreshold: "隐患按期整改率低于60%",
warningLevel: "红",
businessModule: "15隐患排查治理",
indicatorName: "隐患按期整改率",
displayForm: "隐患按期整改率"
},
{
warningProject: "风险单元预警",
warningElement: "隐患整改",
warningThreshold: "隐患按期整改率低于70%",
warningLevel: "橙",
businessModule: "15隐患排查治理",
indicatorName: "隐患按期整改率",
displayForm: "隐患按期整改率"
},
{
warningProject: "风险单元预警",
warningElement: "隐患整改",
warningThreshold: "隐患按期整改率低于80%",
warningLevel: "黄",
businessModule: "15隐患排查治理",
indicatorName: "隐患按期整改率",
displayForm: "隐患按期整改率"
},
{
warningProject: "事故预警",
warningElement: "事故事件",
warningThreshold: "发生死亡1人以上或重伤3人以上或直接经济损失100万以上的安全事故",
warningLevel: "红",
businessModule: "17事故事件",
indicatorName: "一般事故-3数量、一般事故-2数量、一般事故-1数量",
displayForm: "事故事件"
},
{
warningProject: "事故预警",
warningElement: "事故事件",
warningThreshold: "发生重伤1-2人或直接经济损失50万-100万的安全事故",
warningLevel: "橙",
businessModule: "17事故事件",
indicatorName: "一般事故-3数量、一般事故-2数量、一般事故-1数量",
displayForm: "事故事件"
},
{
warningProject: "事故预警",
warningElement: "事故事件",
warningThreshold: "发生轻伤3人及以上或直接经济损失10万-50万的安全事故",
warningLevel: "黄",
businessModule: "17事故事件",
indicatorName: "一般事故-3数量、一般事故-2数量、一般事故-1数量",
displayForm: "事故事件"
},
{
warningProject: "其他预警",
warningElement: "安全管理机构人员配置率",
warningThreshold: "配置率低于50%",
warningLevel: "红",
businessModule: "1综合管理",
indicatorName: "安全管理机构人员配置率",
displayForm: "安全管理机构人员配置率"
},
{
warningProject: "其他预警",
warningElement: "安全管理机构人员配置率",
warningThreshold: "配置率低于60%",
warningLevel: "橙",
businessModule: "1综合管理",
indicatorName: "安全管理机构人员配置率",
displayForm: "安全管理机构人员配置率"
},
{
warningProject: "其他预警",
warningElement: "安全管理机构人员配置率",
warningThreshold: "配置率低于70%",
warningLevel: "黄",
businessModule: "1综合管理",
indicatorName: "安全管理机构人员配置率",
displayForm: "安全管理机构人员配置率"
},
{
warningProject: "其他预警",
warningElement: "安全工程师评聘比例",
warningThreshold: "评聘比例低于5%",
warningLevel: "红",
businessModule: "2安全管理队伍",
indicatorName: "安全管理队伍安全工程师聘任率",
displayForm: "安全工程师评聘"
},
{
warningProject: "其他预警",
warningElement: "安全工程师评聘比例",
warningThreshold: "评聘比例低于10%",
warningLevel: "橙",
businessModule: "2安全管理队伍",
indicatorName: "安全管理队伍安全工程师聘任率",
displayForm: "安全工程师评聘"
},
{
warningProject: "其他预警",
warningElement: "安全工程师评聘比例",
warningThreshold: "评聘比例低于15%",
warningLevel: "黄",
businessModule: "2安全管理队伍",
indicatorName: "安全管理队伍安全工程师聘任率",
displayForm: "安全工程师评聘"
},
{
warningProject: "其他预警",
warningElement: "主要负责人安全培训符合学时要求≥12学时占比",
warningThreshold: "符合学时要求≥12学时的企业主要负责人占比低于60%",
warningLevel: "红",
businessModule: "3安全教育培训",
indicatorName: "主要负责人安全培训学时达标率",
displayForm: "主要负责人安全培训"
},
{
warningProject: "其他预警",
warningElement: "主要负责人安全培训符合学时要求≥12学时占比",
warningThreshold: "符合学时要求≥12学时的企业主要负责人占比低于80%",
warningLevel: "橙",
businessModule: "3安全教育培训",
indicatorName: "主要负责人安全培训学时达标率",
displayForm: "主要负责人安全培训"
},
{
warningProject: "其他预警",
warningElement: "主要负责人安全培训符合学时要求≥12学时占比",
warningThreshold: "符合学时要求≥12学时的企业主要负责人占比低于100%",
warningLevel: "黄",
businessModule: "3安全教育培训",
indicatorName: "主要负责人安全培训学时达标率",
displayForm: "主要负责人安全培训"
}
];
const form = ref({});
const ok = () => {
emit('ok');
};
/** 是否可选 */
const selectable = () => {
return true;
}
const selectionChange = (selection) => {
console.log('selectionChange', selection);
}
const arraySpanMethod = ({ row, column, rowIndex, columnIndex }) => {
// 第一列,第二列相同项,向下合并
if (columnIndex === 1) {
// 安全责任年度对比excel序号少2个(因为列表序号从0开始而excel序号从2开始)
if (rowIndex === 0) return [2, 1]
if (rowIndex === 1) return [0, 0]
// 未知?
if (rowIndex === 2) return [8, 1]
if (rowIndex > 2 && rowIndex < 10) return [0, 0]
// 事故预警
if (rowIndex === 10) return [3, 1]
if (rowIndex > 10 && rowIndex < 13) return [0, 0]
// 其他预警
if (rowIndex === 13) return [9, 1]
if (rowIndex > 13 && rowIndex < 22) return [0, 0]
}
if (columnIndex === 2) {
// 风险单元
if (rowIndex === 0) return [2, 1]
if (rowIndex > 0 && rowIndex < 2) return [0, 0]
// 重大隐患 合并2个
if (rowIndex === 2) return [2, 1]
if (rowIndex > 2 && rowIndex < 4) return [0, 0]
// 同类别隐患占隐患总数 合并3个
if (rowIndex === 4) return [3, 1]
if (rowIndex > 4 && rowIndex < 7) return [0, 0]
// 隐患整改 合并3个
if (rowIndex === 7) return [3, 1]
if (rowIndex > 7 && rowIndex < 10) return [0, 0]
// 事故事件 合并3个
if (rowIndex === 10) return [3, 1]
if (rowIndex > 10 && rowIndex < 13) return [0, 0]
// 安全管理机构人员配置率 合并3个
if (rowIndex === 13) return [3, 1]
if (rowIndex > 13 && rowIndex < 16) return [0, 0]
// 安全工程师评聘比例 合并3个
if (rowIndex === 16) return [3, 1]
if (rowIndex > 16 && rowIndex < 19) return [0, 0]
// 主要负责人安全培训符合学时要求≥12学时占比 合并3个
if (rowIndex === 19) return [3, 1]
if (rowIndex > 19 && rowIndex < 22) return [0, 0]
}
return [1, 1]
}
const close = () => {
emit('close');
};
// /** 设置table数据 */
// const setTable = ()=>{
// tableData.value = []
// }
</script>
<style lang="scss" scoped>
// .synthesis-conf-container {
// width: 100%;
// height: 100%;
// }</style>

View File

@ -0,0 +1,147 @@
<template>
<div class="score-globe-container">
<MOSTY.Assort title="甘肃省烟草行业预警得分"></MOSTY.Assort>
<div class="score-globe-content">
<div class="score-globe">
<div id="waveChart" class="liquidfill"></div>
</div>
<div class="score-globe-detail">
<div v-for="(item, index) in globeDetailList" :key="index" class="score-globe-item">
<span class="score-globe-item-title">
{{ item.name }} ({{ item.bracket }})
</span>
<span class="score-globe-item-value">
{{ item.value }}
</span>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import * as echarts from 'echarts'
import * as MOSTY from "@/components/MyComponents/index";
import 'echarts-liquidfill';
const globeDetailList = ref(
[
{
name: '安全责任',
value: 99.99,
bracket: 100
},
{
name: '双层预防',
value: 99.99,
bracket: 100
},
{
name: '培训教育',
value: 99.99,
bracket: 100
},
{
name: '应急管理',
value: 99.99,
bracket: 100
},
{
name: '重点领域',
value: 99.99,
bracket: 100
},
{
name: '事故事件',
value: 99.99,
bracket: '扣分项目'
}
]
);
/**
* @description 设置波浪图
*/
const setWaveChart = (value) => {
const cssText = document.documentElement.style.cssText;
const color = cssText.match(/--el-color-primary: (.*);/)[1] || '#007457';
const chart = echarts.init(document.getElementById('waveChart'));
const option = {
series: [
{
type: 'liquidFill',
// 水波图的配置
data: [value], // 设置水位值为0到1之间
radius: '90%', // 设置图的大小
color: [color],
outline: {
borderDistance: 0, // 外边框距离
itemStyle: {
borderWidth: 2, // 外边框宽度
borderColor: color // 外边框颜色
}
},
backgroundStyle: {
color: '#fff' // 背景色
},
label: {
show: false
}
},
],
};
chart.setOption(option);
}
onMounted(() => {
setWaveChart(0.22);
})
</script>
<style lang="scss" scoped>
.score-globe-container {
// width: calc(50% - 10px);
height: 100%;
padding: 0 10px 10px;
background-color: #fff;
}
.score-globe-content {
display: flex;
align-items: center;
}
.score-globe {
width: 200px;
height: 200px;
.liquidfill {
width: 100%;
height: 100%;
}
}
.score-globe-detail {
display: flex;
justify-content: center;
width: calc(100% - 200px);
flex-wrap: wrap;
color: #000;
.score-globe-item {
font-weight: bolder;
padding: 1.8%;
.score-globe-item-title {
display: inline-block;
width: 10.5em;
}
.score-globe-item-value {
display: inline-block;
min-width: 5em;
color: var(--el-color-primary);
}
}
}
</style>

View File

@ -0,0 +1,62 @@
<template>
<div class="line-chart-container">
<MOSTY.Assort style="margin-left: 10px;" title="甘肃省烟草行业预警得分"></MOSTY.Assort>
<div id="lineChart" class="line-chart"></div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import * as echarts from 'echarts';
import * as MOSTY from "@/components/MyComponents/index";
const setLineChart = (dataList, timeList) => {
const chart = echarts.init(document.getElementById('lineChart'));
let option2 = {
// title: {
// text: '贵州烟草专卖(公司)总得分趋势情况',
// left: 'center'
// },
xAxis: {
type: 'category',
data: timeList
},
yAxis: {
type: 'value'
},
series: [{
data: dataList,
type: 'line',
areaStyle: {
color: '#24CCB8',
opacity: 0.4
},
lineStyle: {
color: '#24CCB8'
},
itemStyle: {
normal: {
color: '#24CCB8', // 连接点的颜色
}
},
}]
}
chart.setOption(option2);
}
onMounted(() => {
setLineChart([100, 90, 80, 70, 60, 50, 40, 30, 20, 10], ['2024-01', '2024-02', '2024-03', '2024-04', '2024-05', '2024-06', '2024-07', '2024-08', '2024-09', '2024-10']);
})
</script>
<style lang="scss" scoped>
.line-chart-container {
width: 100%;
height: 100%;
background-color: #fff;
}
.line-chart {
width: 100%;
height: calc(100% - 40px);
}
</style>

View File

@ -0,0 +1,465 @@
<template>
<!-- <div class="synthesis-conf-container"> -->
<el-dialog v-model="dialogVisible" title="配置" width="85vw" :before-close="close">
<div class="synthesis-conf-content">
<el-table :data="tableData" height="calc(100vh - 250px)" border @selection-change="selectionChange"
:span-method="arraySpanMethod">
<el-table-column type="index" width="55" />
<el-table-column prop="projectName" label="评估项目"></el-table-column>
<el-table-column prop="warningKey" label="预警要素"></el-table-column>
<el-table-column type="selection" :selectable="selectable" width="55" />
<el-table-column prop="indexName" label="指标名称"></el-table-column>
<el-table-column prop="rule" label="规则">
<template #default="{ row }">
<div class="rule-content" v-html="row.rule"></div>
</template>
</el-table-column>
<el-table-column prop="weightValue" label="权重">
<template #default="{ row }">
<el-input v-model="row.weightValue" />
</template>
</el-table-column>
<el-table-column prop="scoreRule" label="评分规则">
<template #default="{ row }">
<div class="score-rule-content" v-html="row.scoreRule"></div>
</template>
</el-table-column>
<el-table-column v-if="false" prop="cycle" label="取值周期">
</el-table-column>
</el-table>
</div>
<template #footer>
<el-button type="primary" @click="ok">保存</el-button>
<el-button @click="close">关闭</el-button>
</template>
</el-dialog>
<!-- </div> -->
</template>
<script setup>
import { ref, getCurrentInstance } from 'vue';
const dialogVisible = ref(true);
const { proxy } = getCurrentInstance();
const emit = defineEmits(['ok', 'close']);
const tableData = ref([
{
projectName: '安全责任(年度)',
warningKey: '安全生产标准化',
indexName: '安全生产标准化达标率',
rule: '安全生产标准化达标企业总数/应达标单位总数*100%<br/>(统计口径:各卷烟工厂、复烤厂、薄片厂、市局(公司)及醋纤企业的单位总数)',
weightValue: '2',
scoreRule: '比率*权重',
cycle: '搜索当前年度时,展示上一年搜索历史年度时,展示当前年',
index: 2
},
{
projectName: '安全责任(年度)',
warningKey: '机构队伍',
indexName: '安全管理机构设置比率',
rule: '安全管理机构设置数量/应独立设置安全管理机构单位总数*100%<br/>统计口径:省级公司本部、卷烟工厂、复烤厂、薄片厂、市局 (公司) 及醋纤企业的单位总数',
weightValue: '5',
scoreRule: '比率*权重',
cycle: '搜索当前年度时,展示上一年搜索历史年度时,展示当前年',
index: 3
},
{
projectName: '安全责任(年度)',
warningKey: '机构队伍',
indexName: '安全管理机构人员配置率',
rule: '配置人数/编制人数*100%',
weightValue: '5',
scoreRule: '比率*权重',
cycle: '搜索当前年度时,展示上一年搜索历史年度时,展示当前年',
index: 4
},
{
projectName: '安全责任(年度)',
warningKey: '机构队伍',
indexName: '安全管理人员数占比',
rule: '专职安全管理人员数/行业在册职工和劳动派遣者总数*100%',
weightValue: '4',
scoreRule: '占比≥1%得4分1%>占比≥0.9%等3分0.9%>占比≥0.8%等2分0.8%>占比≥0.7%等1分低于0.7%得0分',
cycle: '搜索当前年度时,展示上一年搜索历史年度时,展示当前年',
index: 5
},
{
projectName: '安全责任(年度)',
warningKey: '机构队伍',
indexName: '注册安全(消防)工程师占比',
rule: '从事专职安全管理岗位注册安全(消防)工程师/专职安全管理人员数量*100%',
weightValue: '3',
scoreRule: '工业占比≥50%得3分50%>占比≥30%得 2分 30%>占比≥10% 的1分10%>占比 得0分商业占比≥25%得3分25%>占比≥20%得 2分20%>占比≥10% 的1分10%>占比 得0分',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示第四季度',
index: 6
},
{
projectName: '安全责任(年度)',
warningKey: '机构队伍',
indexName: '安全工程师应聘比率',
rule: '已聘任安全工程师单位总数/应聘任安全工程师单位总数*100%(统计口径为:省级公司本部(不含中烟实业本级)、卷烟工厂(不包含雪茄厂),复烤厂、市局(公司)及醋纤企业的单位总数)',
weightValue: '2',
scoreRule: '比率*权重',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示第四季度',
index: 7
},
{
projectName: '安全责任(年度)',
warningKey: '安委会会议',
indexName: '安委会会议频次',
rule: '安委会会议次数每年省级公司至少1次、下属企业至少2次',
weightValue: '5',
scoreRule: '省级公司缺少次数扣1分/次、下属企业缺少次数扣0.5分/次',
cycle: '搜索当前年度时,展示上一年搜索历史年度时,展示当前年',
index: 8
},
{
projectName: '教育培训(半年)',
warningKey: '培训学时',
indexName: '企业主要负责人培训总学时',
rule: '符合学时要求≥12学时的企业主要负责人/企业主要负责人数量*100%',
weightValue: '3',
scoreRule: '比率*权重',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示下半年',
index: 9
},
{
projectName: '教育培训(半年)',
warningKey: '培训学时',
indexName: '安全分管领导(安全总监)培训总学时',
rule: '符合学时要求≥12学时的安全分管领导安全总监/安全分管领导(安全总监)数量*100%',
weightValue: '3',
scoreRule: '比率*权重',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示下半年',
index: 10
},
{
projectName: '教育培训(半年)',
warningKey: '培训学时',
indexName: '专职安全管理人员人均培训学时',
rule: '专职安全管理人员人均培训学时/专职安全管理人员应培训学时12学时*100%',
weightValue: '3',
scoreRule: '比率*权重',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示下半年',
index: 11
},
{
projectName: '教育培训(半年)',
warningKey: '培训学时',
indexName: '新员工人均培训学时',
rule: '新员工人均培训学时/新员工应培训学时24学时*100%',
weightValue: '3',
scoreRule: '比率*权重',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示下半年',
index: 12
},
{
projectName: '重点领域',
warningKey: '工程建设项目“三同时”(半年)',
indexName: '建设项目“三同时”符合率',
rule: '可研、设计、验收阶段“三同时”资料均上传的已竣工验收项目数量/已竣工验收项目总数量*100%',
weightValue: '5',
scoreRule: '比率*权重 <br/>1.都在建,无建设项目,为满分 <br/> 2有在建的有竣工验收的分子分母只计算竣工验收的',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示下半年',
index: 13
},
{
projectName: '重点领域',
warningKey: '消防安全(半年)',
indexName: '易燃可燃外墙保温材料建筑物占比',
rule: '(易燃外墙保温材料的建筑物数量+可燃外墙保温材料的建筑物数量) /总建筑物数量*100%',
weightValue: '4',
scoreRule: '比率*权重(没有建筑得满分)',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示下半年',
index: 14
},
{
projectName: '重点领域',
warningKey: '消防安全(半年)',
indexName: '高层民用建筑消防设施符合率',
rule: '同时配置消火栓系统、火灾自动报警系统、自动灭火系统的高层民用建筑数量/高层民用建筑总数量*100%',
weightValue: '1',
scoreRule: '比率*权重(没有建筑得满分)',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示下半年',
index: 15
},
{
projectName: '重点领域',
warningKey: '消防安全(半年)',
indexName: '联合工房消防设施符合率',
rule: '同时配置消火栓系统、火灾自动报警系统的联合工房数量/联合工房总数量*100%',
weightValue: '1',
scoreRule: '比率*权重(没有建筑得满分)',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示下半年',
index: 16
},
{
projectName: '重点领域',
warningKey: '消防安全(半年)',
indexName: '仓储消防设施符合率',
rule: '配置消火栓系统或火灾自动报警系统或自动灭火系统的(条件同分母)仓库数量/占地面积大于1500平方米或者总建筑面积大于3000平方米的单层库或多层库的仓库数量+立体库的仓库数量)*100%',
weightValue: '1',
scoreRule: '比率*权重(没有仓储得满分)',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示下半年',
index: 17
},
{
projectName: '重点领域',
warningKey: '消防安全(半年)',
indexName: '消控室持证人员配置率',
rule: '四级/中级工以上(人)/消控室值班人员(人)*100%',
weightValue: '1',
scoreRule: '比率*权重',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示下半年',
index: 18
},
{
projectName: '重点领域',
warningKey: '职业健康(季度)',
indexName: '职业危害因素超标点位率',
rule: '超标点位数量/检测点位数量*100%',
weightValue: '4',
scoreRule: '(1-比率)*权重',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示第四季度',
index: 19
},
{
projectName: '重点领域',
warningKey: '职业健康(季度)',
indexName: '职业病确诊人数',
rule: '职业病确认人数',
weightValue: '4',
scoreRule: '扣1分/人',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示第四季度',
index: 20
},
{
projectName: '重点领域',
warningKey: '危险化学品(季度)',
indexName: '“两重一大”危险化学品',
rule: '构成重大危险源数量',
weightValue: '4',
scoreRule: '扣0.1分/品种',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示第四季度',
index: 21
},
{
projectName: '重点领域',
warningKey: '相关方(季度)',
indexName: '重点相关方资质符合率',
rule: '具备相应的的单位资质相关方数量/重点相关方总数量*100%',
weightValue: '5',
scoreRule: '比例*权重',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示第四季度',
index: 22
},
{
projectName: '重点领域',
warningKey: '相关方(季度)',
indexName: '重点相关方安全协议签订率',
rule: '签订安全协议相关数量/重点相关方总数量*100%',
weightValue: '5',
scoreRule: '比例*权重',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示第四季度',
index: 23
},
{
projectName: '重点领域',
warningKey: '道路交通(季度)',
indexName: '超过8年或30万公里的车辆占比',
rule: '使用超过8年或使用超过30万公里的非已报废车辆数量/非已报废机动车辆总数*100%',
weightValue: '1',
scoreRule: '(1-比率)*权重',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示第四季度',
index: 24
},
{
projectName: '重点领域',
warningKey: '道路交通(季度)',
indexName: '车辆定位系统安装占比',
rule: '安装定位系统的自有物流运输车辆及自有通勤非已报废车辆数量/自有物流运输车辆及自有通勤非已报废车辆总数*100%',
weightValue: '1',
scoreRule: '比例*权重',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示第四季度',
index: 25
},
{
projectName: '重点领域',
warningKey: '道路交通(季度)',
indexName: '车辆影像雷达安装占比',
rule: '安装倒车影像且安装全车雷达的自有物流运输车辆及自有通勤非已报废车辆数量/自有物流运输车辆及自有通勤非已报废车辆总数*100%',
weightValue: '1',
scoreRule: '比例*权重',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示第四季度',
index: 26
},
{
projectName: '重点领域',
warningKey: '道路交通(季度)',
indexName: '车载监控系统安装占比',
rule: '安装驾驶行为监控预警的自有物流运输车辆及自有通勤非已报废车辆数量/自有物流运输车辆及自有通勤非已报废车辆总数*100%',
weightValue: '1',
scoreRule: '比例*权重',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示第四季度',
index: 27
},
{
projectName: '双重预防',
warningKey: '风险管理(半年)',
indexName: '橙区及以上现状风险单元数量(半年)',
rule: '现状风险单元出现红、橙风险的数量',
weightValue: '6',
scoreRule: '扣-0.1分/个',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示下半年',
index: 28
},
{
projectName: '双重预防',
warningKey: '隐患管理(季度)',
indexName: '主要负责人参与排查次数',
rule: '主要负责人参与的隐患排查次数',
weightValue: '3',
scoreRule: '省级单位≥1缺一次扣0.5分下属单位≥1季度缺一次扣0.5分。',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示第四季度',
index: 29
},
{
projectName: '双重预防',
warningKey: '隐患管理(季度)',
indexName: '隐患按期整改率',
rule: '按期已整改隐患数量/到期应整改隐患数量*100%',
weightValue: '6',
scoreRule: '比例*权重',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示第四季度',
index: 30
},
{
projectName: '双重预防',
warningKey: '隐患管理(季度)',
indexName: '重大隐患数量',
rule: '隐患类别为“重大隐患”的非已整改完成的隐患数量',
weightValue: '6',
scoreRule: '-1分/个',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示第四季度',
index: 31
},
{
projectName: '应急管理',
warningKey: '应急管理(季度)',
indexName: '应急预案演练覆盖率',
rule: '统计周期内发生演练的专项应急预案和现场处置方案数量之和/专项和现场应急预案总数*100%',
weightValue: '1',
scoreRule: '比例*权重',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示第四季度',
index: 32
},
{
projectName: '应急管理',
warningKey: '应急管理(季度)',
indexName: '应急演练评估覆盖率',
rule: '应急演练评估总次数/应急演练总次数*100%',
weightValue: '1',
scoreRule: '比例*权重',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示第四季度',
index: 33
},
{
projectName: '事故事件',
warningKey: '事故事件',
indexName: '事故发生次数',
rule: '事故台账填报次数',
weightValue: '',
scoreRule: '一般事故轻伤3人及以上或直接经济损失10万-50万扣2分/起<br/>重伤1-2人或直接经济损失50万-100万扣5分/起<br/>死亡1-2人或重伤3-9人或直接经济损失100万-1000万扣10分/起<br/>较大及以上事故死亡3人及以上重伤10人及以上直接经济损失1000万及以上扣20分/起',
cycle: '搜索当前年度时,展示上周期搜索历史年度时,展示第四季度',
index: 34
}
]);
const form = ref({});
const ok = () => {
emit('ok');
};
/** 是否可选 */
const selectable = () => {
return true;
}
const selectionChange = (selection) => {
console.log('selectionChange', selection);
}
const arraySpanMethod = ({ row, column, rowIndex, columnIndex }) => {
// 第一列,第二列相同项,向下合并
if (columnIndex === 1) {
// 安全责任年度对比excel序号少2个(因为列表序号从0开始而excel序号从2开始)
if (rowIndex === 0) return [7, 1]
if (rowIndex > 0 && rowIndex < 7) return [0, 0]
// 教育培训(半年)序号
if (rowIndex === 7) return [4, 1]
if (rowIndex > 7 && rowIndex < 11) return [0, 0]
// 重点领域
if (rowIndex === 11) return [15, 1]
if (rowIndex > 11 && rowIndex < 26) return [0, 0]
// 双重预防
if (rowIndex === 26) return [4, 1]
if (rowIndex > 26 && rowIndex < 30) return [0, 0]
// 应急管理
if (rowIndex === 30) return [2, 1]
if (rowIndex > 30 && rowIndex < 32) return [0, 0]
}
if (columnIndex === 2) {
// 机构队伍
if (rowIndex === 1) return [5, 1]
if (rowIndex > 1 && rowIndex < 6) return [0, 0]
// 培训学时 合并4个
if (rowIndex === 7) return [4, 1]
if (rowIndex > 7 && rowIndex < 11) return [0, 0]
// 工程建设项目“三同时”(半年)不合并
if (rowIndex === 11) return [1, 1]
// 消防安全 半年合并5个
if (rowIndex === 12) return [5, 1]
if (rowIndex > 12 && rowIndex < 17) return [0, 0]
// 职业健康(季度) 合并2个
if (rowIndex === 17) return [2, 1]
if (rowIndex > 17 && rowIndex < 19) return [0, 0]
// 危险化学品(季度) 1个
if (rowIndex === 19) return [1, 1]
// 相关方(季度) 合并2个
if (rowIndex === 20) return [2, 1]
if (rowIndex > 20 && rowIndex < 22) return [0, 0]
// 道路交通(季度) 合并4个
if (rowIndex === 22) return [4, 1]
if (rowIndex > 22 && rowIndex < 26) return [0, 0]
// 风险管理(半年) 1个
if (rowIndex === 26) return [1, 1]
// 隐患管理(季度) 合并3个
if (rowIndex === 27) return [3, 1]
if (rowIndex > 27 && rowIndex < 30) return [0, 0]
// 应急管理 合并2个
if (rowIndex === 30) return [2, 1]
if (rowIndex > 30 && rowIndex < 32) return [0, 0]
}
return [1, 1]
}
const close = () => {
proxy.$modal.confirm('离开会丢失页面中修改的内容,确认离开吗?')
.then(() => {
emit('close');
})
.catch(() => {
// catch error
})
};
// /** 设置table数据 */
// const setTable = ()=>{
// tableData.value = []
// }
</script>
<style lang="scss" scoped>
// .synthesis-conf-container {
// width: 100%;
// height: 100%;
// }</style>

View File

@ -0,0 +1,52 @@
<template>
<div class="synthesis-table-container">
<div class="synthesis-table-header">
<MOSTY.Assort title="甘肃省烟预警指标明细"></MOSTY.Assort>
<el-button type="primary" @click="handleConfig">配置</el-button>
</div>
<el-table :data="tableData" style="width: 100%;">
<el-table-column prop="name" label="评估项目" />
<el-table-column prop="value" label="预警" />
<el-table-column prop="score" label="指标名称" />
<el-table-column prop="score" label="得分" />
</el-table>
<SynthesisConf v-if="isShowConf" @ok="configOk" @close="configClose" />
</div>
</template>
<script setup>
import * as MOSTY from "@/components/MyComponents/index";
import SynthesisConf from './synthesisConf.vue';
import { ref } from 'vue';
const isShowConf = ref(false);
const tableData = ref([
{ name: '评估项目', value: '预警', score: '指标名称', score: '得分' },
{ name: '评估项目', value: '预警', score: '指标名称', score: '得分' },
{ name: '评估项目', value: '预警', score: '指标名称', score: '得分' },
{ name: '评估项目', value: '预警', score: '指标名称', score: '得分' },
]);
const handleConfig = () => {
console.log('配置');
isShowConf.value = true;
};
const configOk = () => {
isShowConf.value = false;
};
const configClose = () => {
isShowConf.value = false;
};
</script>
<style lang="scss" scoped>
.synthesis-table-container {
width: 100%;
height: 100%;
padding: 0 10px 10px;
background-color: #fff;
.synthesis-table-header {
display: flex;
align-items: center;
}
}
</style>

View File

@ -0,0 +1,107 @@
<template>
<div>
<PageTitle :title="pageTitle">
<el-button type="primary" @click="submit(ruleFormRef)"><el-icon>
<DocumentChecked />
</el-icon>保存</el-button>
<el-button @click="black"><el-icon>
<DocumentDelete />
</el-icon>关闭</el-button>
</PageTitle>
<div class="formBox">
<el-form ref="ruleFormRef" :model="data.formData" :rules="rules" label-width="120px" class="demo-ruleForm"
status-icon :inline="true" label-position="top">
<el-row :gutter="80">
<el-col :span="18">
<el-form-item label="岗位名称" prop="gwmc">
<el-input v-model="data.formData.gwmc" placeholder="请输入岗位名称" style="width: 100%"></el-input>
</el-form-item>
</el-col>
<el-col :span="18">
<el-form-item label="适用范围" prop="syfw">
<el-select v-model="data.formData.syfw" placeholder="请选择适用范围" style="width: 100%">
<el-option v-for="item in GWSYFY" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</div>
</template>
<script setup>
import {
reactive,
ref,
watchEffect,
getCurrentInstance,
watch,
nextTick
} from "vue";
import PageTitle from "@/components/PageTitle/PageTitle.vue";
import * as rule from "@/utils/rules.js";
const { proxy } = getCurrentInstance();
const { GWSYFY } = proxy.$dict("GWSYFY");
const props = defineProps({
editObj: {
type: Object,
default: () => { }
}
});
const emit = defineEmits("changePage");
const ruleFormRef = ref();
let pageTitle = ref("添加考核登记");
const data = reactive({
formData: {
gwmc: "", //考核岗位名称
gwfl: "", //岗位分类
syfw: "" //适用范围
}
});
const rules = reactive({
});
// 保存
const submit = async (formEl) => {
if (!formEl) return;
await formEl.validate((valid, fields) => {
if (valid) {
}
});
};
const black = () => {
proxy.$modal.confirm('离开会丢失页面中修改的内容,确认离开吗?')
.then(() => {
emit("changePage", "Main");
})
.catch(() => {
// catch error
})
};
watchEffect(() => {
if (props.editObj) {
data.formData = JSON.parse(JSON.stringify(props.editObj));
}
});
</script>
<style lang="scss" scoped>
::v-deep .el-cascader,
::v-deep .el-select {
width: 100%;
}
.formBox {
padding: 30px 120px;
background-color: #fff;
height: 750px;
}
</style>

View File

@ -0,0 +1,296 @@
<template>
<div class="usermanage">
<!-- 组织机构信息 -->
<div class="right">
<div class="title">
<span>
<span class="left10">岗位类型</span><dict-tag :options="KHLX" :value="data.fromObj.grade" :tag="false"
color="red" />
<span class="left10">考核岗位</span><span style="color: red;">{{ data.fromObj.name }}</span>
<span class="left10">适用范围</span><dict-tag :options="GWSYFY" :value="data.fromObj.assignLv" :tag="false"
color="red" />
</span>
<span>当前已分配 </span>
<span style="margin-right: 20px;">
<span class="score" style="color: green;font-size: 25px;font-weight: 900;"> {{ total }} </span>
</span>
<span>未分配分数 </span>
<span style="margin-right: 50px;"><span class="score" style="color: red;font-size: 25px;font-weight: 900;">
{{ 100 - total < 0 ? 0 : 100 - total }} </span> </span>
<el-button @click="black">关闭</el-button>
<el-button type="primary" v-if="data.config.saveBtnShow" @click="submit()">保存</el-button>
</div>
<el-form :disabled="!data.config.saveBtnShow">
<div class="bottom" style="color: #000;">
<div>
<table border="1" cellpadding="15" cellSpacing="0" style="border-color: green;width: 100%;">
<thead>
<tr>
<th style="width: 10%;text-align: center; font-weight: bold;color: #000;">评价项目</th>
<th style="width: 5%;text-align: center; font-weight: bold;color: #000;" align="center"></th>
<th style="width: 10%;text-align: center; font-weight: bold;color: #000;" align="center">评价要素</th>
<th style="width: 20%;text-align: center; font-weight: bold;color: #000;" align="center">评价内容</th>
<th style="width:20%;text-align: center; font-weight: bold;color: #000;" align="center">评价规则</th>
<th style="width: 10%;text-align: center; font-weight: bold;color: #000;" align="center">评价分值</th>
</tr>
</thead>
<tbody>
<tr v-for="item in list" :key="item.id">
<td v-if="item.parentname" :rowspan="item.rowspan"
style="vertical-align: middle;font-weight: bold;color: #000;" align="center">{{
item.parentname }}
</td>
<td class="uucheck" align="center">
<div class="checkbox icheck-success">
<el-checkbox v-model="item.checked" size="large" />
</div>
</td>
<td :style="{ color: item.checked ? '#333' : '#999' }" align="center">{{ item.name }}</td>
<td :style="{ color: item.checked ? '#333' : '#999' }">{{ item.appraiseContent }}</td>
<td :style="{ color: item.checked ? '#333' : '#999' }">
{{ item.note }}
<span v-if="item.configflag == 'Y'">(
<span style="font-weight: bold;">配置</span>
<span v-if="item.p1name" style="margin-left: 8px;">
{{ item.p1name }}
<el-input type="number" :min="0" v-model="item.p1" style="width: 120px;"
@blur="inputNumber(item, $event.target.value, 'p1')" />
</span>
<span v-if="item.p2name" style="margin-left: 8px;">
{{ item.p2name }}
<el-input type="number" :min="0" v-model="item.p2" style="width: 120px;"
@blur="inputNumber(item, $event.target.value, 'p2')" />
</span>
<span v-if="item.p3name" style="margin-left: 8px;">
{{ item.p3name }}
<el-input type="number" :min="0" v-model="item.p3" style="width: 120px;"
@blur="inputNumber(item, $event.target.value, 'p3')" />
</span>
)</span>
</td>
<td v-if="item.scoreflag == 'N' && item.parentname != null" :rowspan="item.rowspan"
style="text-align: center;vertical-align: middle;">
10
</td>
<td v-if="item.scoreflag == 'F' && item.parentname != null" :rowspan="item.rowspan"
style="text-align: center;vertical-align: middle;">
一票否决
</td>
<td v-if="item.scoreflag == 'K' && item.parentname != null" :rowspan="item.rowspan"
style="text-align: center;vertical-align: middle;">
</td>
<td v-if="item.pscoreflag != 'N' && item.pscoreflag != 'F' && item.pscoreflag != 'K'" align="center"
style="text-align: center;">
<div class="spinner" :style="{ display: item.checked ? 'block' : 'none' }">
<div style="display: flex;align-items: center;justify-content: center;">
<el-button plain @click="down(item)">-</el-button>
<el-input type="number" :min="0" :max="100" v-model="item.modelScore" style="width: 60px;"
@blur="inputNumber(item, $event.target.value, 'modelScore')" />
<el-button plain @click="item.modelScore += 1">+</el-button>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</el-form>
</div>
</div>
</template>
<style lang="scss" scoped>
.usermanage {
.right {
height: calc(100%);
width: calc(100%);
padding: 0 10px;
box-sizing: border-box;
.bottom {
max-height: calc(100vh - 200px);
overflow: auto;
width: 100%;
}
.title {
color: black;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
line-height: 50px;
width: 100%;
text-align: center;
font-size: 18px;
.left10 {
margin-left: 10px;
}
>span {
.score {
margin: 0 10px;
}
>div {
display: inline-block;
}
}
}
}
}
</style>
<script setup>
import { reactive, ref, watchEffect, getCurrentInstance, computed } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { getApi, postApi } from "@/api/tobAcco_api.js";
const { proxy } = getCurrentInstance();
const { KHLX, GWSYFY } = proxy.$dict("KHLX", "GWSYFY");
const emit = defineEmits("changePage");
const props = defineProps({
editObj: {
type: Object,
default: () => { }
}
});
const data = reactive({
fromObj: {},
});
// 列表数据
const list = ref([])
// 计算总分
const total = computed(() => {
let count = 0;
let pidmp = {};
for (let index in list.value) {
if (!list.value[index].checked) continue;
let pid = list.value[index].pid;
pidmp[pid] = 'Y';
let tmpscore = list.value[index].modelScore;
if (tmpscore != null && tmpscore != '') {
if (parseInt(tmpscore)) {
count += parseInt(tmpscore);
}
} else {
list.value[index].modelScore = 0;
}
}
for (let index in list.value) {
if (list.value[index].parentname != null) {
if (pidmp[list.value[index].pid] != null) {
list.value[index].color = { color: '#333' }
} else {
list.value[index].color = { color: '#ccc' }
}
}
}
return count;
});
// 填写分数
const inputNumber = (item, value, column) => {
if (value != null && value != '' && value != NaN) {
item[column] = parseInt(value.replace(/[^\d]/g, ''));
if (item[column] == "") {
item[column] = 0;
}
} else {
item[column] = 0;
}
}
// 减分
const down = (item) => {
item.modelScore -= 1;
if (item.modelScore < 0) {
item.modelScore = 0;
}
}
// 获取配置项列表详情
const getTableData = (id) => {
getApi({}, "/mosty-jcgl/station/modelInfo?id=" + id).then(
(res) => {
let tList = res.list;
if (res && res.list.length > 0) {
let parentChirdens = {};
let parentList = [];
let ulist = [];
for (let index in tList) {
let pid = tList[index].pid;
if (pid == "0") {
parentList.push(tList[index]);
} else {
if (parentChirdens[pid] == null) {
parentChirdens[pid] = [];
}
parentChirdens[pid].push(tList[index]);
}
}
for (let index in parentList) {
let uItem = parentList[index];
// 父级
let pid = uItem.id.replace(res.citycode, '');
if (parentChirdens[pid] != null) {
let temparr = parentChirdens[pid];
for (let ind in temparr) {
if (ind == 0) {
temparr[0].parentname = uItem.name;
temparr[0].rowspan = temparr.length;
temparr[0].scoreflag = uItem.scoreflag;
}
temparr[ind].pscoreflag = uItem.scoreflag;
}
ulist = ulist.concat(temparr);
}
}
list.value = ulist;
}
}
);
}
// 返回
const black = () => {
proxy.$modal.confirm('离开会丢失页面中修改的内容,确认离开吗?')
.then(() => {
emit("changePage", "Main");
})
.catch(() => {
// catch error
})
};
// 保存
const submit = async () => {
let params = {
id: data.config.id,
itemList: list.value
}
ElMessageBox.confirm("确定保存当前修改?", "提示").then(() => {
postApi(params, `/mosty-jcgl/station/saveInfo`).then(() => {
ElMessage.success("保存成功");
}
);
});
};
//获取详情
function getMain(id) {
if (id) {
getApi({ id: id }, "/mosty-jcgl/station/getStationInfo").then(
(res) => {
if (res) {
data.fromObj = res;
}
}
);
}
}
watchEffect(() => {
if (props.editObj) {
data.config = props.editObj;
}
getMain(data.config.id);
getTableData(data.config.id);
});
</script>

View File

@ -0,0 +1,224 @@
<template>
<MOSTY.PageTree :pageTitle="'风险评估模型'" :isShowLeftTree="false">
<template #serach>
<el-divider />
<MOSTY.Search :searchArr="searchArr" @submit="onSearch">
<el-button @click="addInfo"><el-icon size="small">
<Plus />
</el-icon>新增</el-button>
</MOSTY.Search>
</template>
<template #table>
<section :style="{ height: totalHeight }">
<MOSTY.Table :table-columns="data.tableColumn" :tableData="data.tableData" :tableloading="tableloading"
:isSelect="false" :isSort="true" :tableConfiger="data.tableConfiger" :actionsW="300" style="width: 100%;">
<template #grade="{ row }">
<dict-tag v-if="row.grade" :options="KHLX" :value="row.grade" :tag="false" />
<span v-else></span>
</template>
<template #assignLv="{ row }">
<dict-tag v-if="row.assignLv" :options="GWSYFY" :value="row.assignLv" :tag="false" />
<span v-else></span>
</template>
<!-- 操作 -->
<template #actions="{ row }">
<span class="operedit" @click="editInfo(row)"
v-if="row.xtCityCode == ssdept.ssdwid.substring(0, 4)"><el-icon>
<Setting />
</el-icon>设置考核模型</span>
<span class="operesee" @click="showInfo(row)"><el-icon>
<Compass />
</el-icon>查看</span>
<el-popconfirm v-if="row.xtCityCode == ssdept.ssdwid.substring(0, 4)" confirm-button-text="是"
cancel-button-text="" icon-color="red" title="确定要删除?" @confirm="handledelete(row)">
<template #reference>
<span span class="operdel" size="small">
<el-icon>
<Delete />
</el-icon>
删除</span>
</template>
</el-popconfirm>
</template>
</MOSTY.Table>
</section>
<div class="fenye">
<MOSTY.Pages :pageConfiger="pageConfiger" @changeNo="handleCurrentChange" @changeSize="handleSizeChange" />
</div>
</template>
</MOSTY.PageTree>
<el-dialog v-model="dialogVisible" title="添加岗位配置" width="900px" :before-close="handleClose">
<el-form class="mosty-from-wrap" ref="elform" label-width="130px" :model="fromObj" :inline="true" :rules="rules">
<el-form-item label="岗位名称:">
<el-input v-model="fromObj.name" clearable style="width: 250px" />
</el-form-item>
<el-form-item label="适用范围:">
<el-select style="width: 250px" v-model="fromObj.assignLv" placeholder="请选择适用范围">
<el-option v-for="item in GWSYFY" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button type="primary" @click="submitry"> <el-icon>
<DocumentChecked />
</el-icon>保存 </el-button>
<el-button @click="handleClose"><el-icon>
<DocumentDelete />
</el-icon>关闭</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup>
import * as MOSTY from "@/components/MyComponents/index";
import { getApi, postApi } from "@/api/tobAcco_api.js";
import { ElMessage } from "element-plus";
import { getItem } from "@/utils/storage";
import { reactive, onMounted, ref, getCurrentInstance } from "vue";
const emit = defineEmits("changePage", "getobj");
const ssdept = getItem("deptId");
const { proxy } = getCurrentInstance();
const { KHLX, GWSYFY } = proxy.$dict("KHLX", "GWSYFY");
// 树的展开与折叠
const searchArr = reactive([
{
showType: "select",
prop: "grade",
options: KHLX,
placeholder: "请选择岗位类型"
}
]);
const dialogVisible = ref(false);
const fromObj = ref({});
const tableloading = ref(false);
const totalHeight = ref()
const listQuery = reactive({
pageCurrent: 1,
pageSize: 20,
grade: ''
});
const data = reactive({
searchObj: {},
tableData: [],
tableColumn: [
{
title: "评估项目名称",
prop: "name"
},
{
title: "预警要素",
prop: "grade",
width: '150',
slot: true
},
{
title: "指标描述",
prop: "assignLv",
slot: true
},
{
title: "操作",
prop: "actions",
width: '250',
slot: true
}
],
tableConfiger: {
showIndex: false,
loading: false
},
pageConfiger: {
pageSize: 20,
pageCurrent: 1,
total: 0
}
});
const rgBoxWid = ref("calc(100% )");
// 查询数据
const onSearch = (obj) => {
listQuery.grade = obj.grade;
listQuery.year = obj.year;
listQuery.pageCurrent = 1;
getTableData();
};
function getTableData() {
tableloading.value = true;
getApi(listQuery, `/mosty-jcgl/station/queryStationByGrade`).then((res) => {
if (res) {
data.tableData = res;
tableloading.value = false;
data.pageConfiger.total = res.total;
} else {
data.tableData = [];
tableloading.value = false;
}
}).finally(() => {
tableloading.value = false;
});
}
function handleClose(params) {
proxy.$modal.confirm('离开会丢失页面中修改的内容,确认离开吗?')
.then(() => {
dialogVisible.value = true;
})
.catch(() => {
// catch error
})
}
//新增
const addInfo = () => {
fromObj.value = {};
dialogVisible.value = true;
};
const submitry = () => {
let params = {
assignLv: fromObj.value.assignLv,
grade: listQuery.grade,
name: fromObj.value.name
};
postApi(params, "/mosty-jcgl/station/addStationOne")
.then(() => {
ElMessage.success("新增成功");
dialogVisible.value = false;
getTableData();
})
.catch((err) => {
});
};
// 查看考核模型
const showInfo = (row) => {
let arr = {
title: "查看考核模型",
saveBtnShow: false,
id: row.id ? row.id : null
};
emit("changePage", "Khmx", arr);
}
// 设置考核模型
const editInfo = (row) => {
let arr = {
title: "设置考核模型",
saveBtnShow: true,
id: row.id ? row.id : null
};
emit("changePage", "Khmx", arr);
};
//删除
const handledelete = (row) => {
postApi({}, "/mosty-jcgl/station/del/" + row.id
).then(() => {
ElMessage.success("删除成功");
getTableData();
});
};
onMounted(() => {
totalHeight.value = `calc(100vh - 330px)`
getTableData();
});
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,30 @@
<template>
<div>
<Main v-if="showPage === 'Main'" @changePage="changePage"></Main>
<AddOrEdite v-else-if="showPage === 'AddOrEdite'" @changePage="changePage" :editObj="editObj.editObj">
</AddOrEdite>
<Khmx v-else-if="showPage === 'Khmx'" @changePage="changePage" :editObj="editObj.editObj"></Khmx>
</div>
</template>
<script setup>
import Main from "./Main/index.vue";
import AddOrEdite from "./AddOrEdite/index.vue";
import Khmx from "./Khmx/index.vue";
import { reactive, ref } from "vue";
let showPage = ref('Main')
let editObj = reactive({
editObj: null
})
const changePage = (val, obj) => {
if (obj) {
editObj.editObj = obj
} else {
editObj.editObj = null
}
showPage.value = val
}
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,254 @@
<template>
<!-- <div class="synthesis-container"> -->
<div class="synthesis-left">
<div class="synthesis-left-top">
<div class="synthesis-left-top-container">
<div class="synthesis-left-top-left">
<div>行业安全生产得分</div>
<div>
单位排行榜
</div>
</div>
<!-- <div class="synthesis-left-top-right">
<el-image style="width: 100px; height: 100%" :src="require('@/assets/images/jcgl_bj.png')"
fit="cover"></el-image>
</div> -->
</div>
</div>
<div v-if="orgLevel == '2'" class="tab-container">
<el-tabs v-model="activeTab" type="card" @tab-click="onTabClick">
<el-tab-pane :label="item.label" :name="item.value" v-for="(item, i) in tabList" :key="i" />
</el-tabs>
</div>
<div class="synthesis-left-content" :class="{ 'is-city': orgLevel == '2' }">
<div class="synthesis-left-content-title">
<span class="col-1">
排序
</span>
<span class="col-2">
名称
</span>
<span class="col-3">
分数
</span>
</div>
<div class="synthesis-left-content-list">
<div v-for="(item, index) in tableData" :key="index" class="synthesis-left-content-item">
<span class="rank-col-1">
<span class="rank-col-1-num" :class="{ 'col-1': index == 0, 'col-2': index == 1, 'col-3': index == 2 }">
{{ (index + 1) < 10 ? '0' + (index + 1) : (index + 1) }} </span>
</span>
<span class="rank-col-2">
{{ item.orgName }}
</span>
<span class="rank-col-3">
{{ new Big(item.rankingSumScore || 0).round(2).toString() }}
</span>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, defineProps, defineExpose } from 'vue'
import { getApi } from "@/api/tobAcco_api.js"
import { getItem, setItem } from "@/utils/storage"
import Big from "@/utils/big.js"
const props = defineProps({
year: {
type: [Number, String],
}
})
const tableData = ref([])
const activeTab = ref('1');
/** 账号级别 1省 2市 3县 4县 */
const orgLevel = ref(getItem("deptId").orgLevel?.[0])
const tabList = ref([
{ label: '市级', value: '1' },
{ label: '县级', value: '0' },
])
/**
* 获取表格数据
*/
const getTableDetail = () => {
/** 是否市级 */
let isCity
if (orgLevel.value == '1') { // 省级一定是市级
isCity = true
} else if (orgLevel.value == '2') { // 市级 可以选“市”或者“县”
isCity = activeTab.value == '1' ? true : false
} else { // 其他级别一定是县级
isCity = false
}
getApi({ year: props.year, isCity: isCity }, "/mosty-jcgl/rankScore/getCityScoreRank").then((res) => {
if (Array.isArray(res)) {
tableData.value = Array.isArray(res) ? res : []
} else {
tableData.value = []
}
})
}
const onTabClick = () => {
getTableDetail()
}
onMounted(() => {
getTableDetail()
})
defineExpose({
getTableDetail
})
//
</script>
<style lang="scss" scoped>
@import "@/views/dutyBook/jgryandzz/talentPool/tabContainer.scss";
.tab-container {
margin-top: 5px;
background-color: #fff;
}
.synthesis-left {
width: 320px;
height: 100%;
margin-right: 10px;
flex-shrink: 0;
.synthesis-left-top {
background-color: var(--el-color-primary);
height: 80px;
padding: 10px;
.synthesis-left-top-container {
display: flex;
justify-content: space-between;
.synthesis-left-top-left {
// padding: 20px;
font-size: 20px;
font-weight: bolder;
font-style: italic;
}
.synthesis-left-top-right {
width: 100px;
height: 100px;
}
}
}
.synthesis-left-content {
height: calc(100% - 85px);
padding: 10px;
font-weight: bolder;
color: #000;
background-color: #fff;
&.is-city {
height: calc(100% - 85px - 45px);
}
.synthesis-left-content-title {
display: flex;
border-radius: 2px;
background-color: #f0f0f0;
.col-1 {
display: inline-block;
width: 50px;
text-align: center;
padding: 6px 10px;
}
.col-2 {
display: inline-block;
// width: 180px;
flex: 1;
text-align: center;
padding: 6px 10px;
}
.col-3 {
display: inline-block;
width: 100px;
text-align: center;
padding: 6px 10px;
}
}
.synthesis-left-content-list {
height: calc(100% - 30px);
overflow: auto;
.synthesis-left-content-item {
display: flex;
border-bottom: 1px solid #ededee;
.rank-col-1 {
display: inline-block;
width: 20px;
text-align: center;
padding: 6px 10px;
.rank-col-1-num {
display: inline-block;
width: 22px;
height: 22px;
text-align: center;
line-height: 22px;
border-radius: 50%;
color: #fff;
background-color: var(--el-color-primary);
&.col-1 {
background-color: #f4a90c;
}
&.col-2 {
background-color: #8ba4b0;
}
&.col-3 {
background-color: #e2a254;
}
}
}
// 名称
.rank-col-2 {
display: inline-block;
flex: 1;
// width: 180px;
text-align: center;
padding: 6px 0px 6px 15px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.rank-col-3 {
display: inline-block;
width: 50px;
text-align: center;
padding: 6px 5px;
color: var(--el-color-primary);
}
}
}
}
}
.synthesis-right {
flex: 1;
padding-top: 10px;
.synthesis-right-top {
display: flex;
height: 280px;
width: 100%;
}
}
</style>

View File

@ -0,0 +1,188 @@
<template>
<div class="water-polo-container">
<div class="warningTitle">甘肃省烟草专卖局(公司)安全生产得分(总分100分)</div>
<div class="warningCent">
<div ref="waterPolo" class="liquidfill-container"></div>
<div class="warningCentInfo">
<div class="warningCentInfoItem" v-for="(item, index) in dataArr" :key="index">
<div class="warningCentInfoTitle">
<el-icon color="#0b6c51">
<Burger />
</el-icon>
<span>{{ item.moduleName }}{{ item.sumCount || 0 }}</span>
</div>
<span :style="{ color: item.moduleName.indexOf('扣分') !== -1 ? '#e72828' : '#0b6c51' }">
{{ item.sumScore }}</span>
</div>
</div>
</div>
</div>
</template>
<script setup>
import * as MOSTY from "@/components/MyComponents/index"
import * as echarts from "echarts"
import "echarts-liquidfill"
import { ref, onMounted, defineExpose, defineProps } from "vue"
import { getApi, postApi, } from "@/api/tobAcco_api.js";
import Big from "@/utils/big.js"
// const proxy = getCurrentInstance()
// const { D_BZ_ZHYJ } = proxy.$dict("D_BZ_ZHYJ");
const props = defineProps({
year: {
type: [Number, String],
}
})
/** 水球dom */
const waterPolo = ref(null)
const formData = ref({
/** 总得分 */
totalScore: 0,
})
/** 模块得分
* - moduleName 模块名称
* - sumScore 得分
* - sumCount 数量
* */
const dataArr = ref([])
const chart = ref(null)
/**
* 初始化综合评分
*/
const initializeComprehensiveRating = () => {
const data = [0]
const dom = waterPolo.value
if (!dom) return
chart.value = echarts.init(dom)
chart.value.setOption({
series: [{
radius: "80%", // 半径大小,可以是百分比或像素值
center: ["50%", "50%"], // 中心位置
type: "liquidFill",
data: data,
backgroundStyle: {
color: "#fff" // 背景颜色
},
label: {
color: "#0b6c51", // 文字颜色
fontSize: 34, // 字体大小
normal: { // 百分比正常样式
textStyle: { // 百分比正常样式字体
fontSize: 34, // 百分比正常样式字体大小
color: '#0b6c51'
},
formatter: function (param) { // 百分比正常样式字体格式
return param.value * 100 + '分'; // 百分比正常样式字体格式
}
}
},
outline: {
itemStyle: {
borderColor: "#0b6c51" // 外圈颜色
}
},
color: ["#0b6c51"] // 水波颜色
}]
})
}
const setLiquidFill = (value) => {
if (!chart.value) return
chart.value.setOption({
series: [{
data: [value]
}]
})
}
/**
* 获取表格数据
*/
const getDetail = () => {
getApi({ year: props.year }, "/mosty-jcgl/scoreItem/getScoreSummary").then((res) => {
res = res || {}
formData.value = {
totalScore: res.totalScore || 0,
}
dataArr.value = Array.isArray(res.modules) ? res.modules : []
dataArr.value = dataArr.value.map((item) => {
return {
...item,
moduleName: typeof item.moduleName === 'string' ? item.moduleName : '',
sumScore: new Big(item.sumScore || 0).round(2),
sumCount: item.sumCount || 0
}
})
// 设置水球
setLiquidFill(new Big(formData.value.totalScore).div(100).round(2).toNumber())
})
}
onMounted(() => {
getDetail()
initializeComprehensiveRating()
})
/** 刷新数据 by年变化 */
const refresh = () => {
getDetail()
}
defineExpose({
refresh
})
</script>
<style scoped lang="scss">
.warningCent {
height: calc(100% - 18px);
display: flex;
align-items: center;
justify-content: center;
.liquidfill-container {
width: 170px;
height: 100%;
}
.warningCentInfo {
width: calc(100% - 170px);
height: 100%;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
color: #0b6c51;
font-size: 13px;
box-sizing: border-box;
padding: 20px 0;
.warningCentInfoItem {
width: 50%;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 10px;
.warningCentInfoTitle {
color: #0a0909;
display: flex;
align-items: center;
span {
margin-left: 8px;
}
}
}
}
}
.warningTitle {
font-size: 18px;
line-height: 18px;
color: #03130e;
padding-left: 20px;
border-left: 4px solid #0b6c51;
}
</style>

View File

@ -0,0 +1,295 @@
<template>
<div>
<div class="warning-header">
<div class="warning-title">预警中心统计</div>
<div>
<el-date-picker v-model="yearStr" type="year" format="YYYY" value-format="YYYY"
:disabled-date="disabledDate"></el-date-picker>
<el-button style="margin-left: 10px;" type="primary" size="mini" @click="search(yearStr)">查询</el-button>
</div>
</div>
<div class="warning-container">
<rank ref="rankRef" :year="yearStr" />
<div class="right-content">
<div class="warningStatisticsTitle">
<!-- 水球安全生产得分 -->
<waterPolo ref="waterPoloRef" class="right-head-polo-line-echart" :year="yearStr" />
<!-- 折线图 -->
<div class="right-head-polo-line-echart">
<div class="warningTitle">甘肃省烟草专卖局(公司)总得分趋势情况</div>
<div class="trendDistribution" id="trendDistribution"></div>
</div>
</div>
<!-- 详细表格 -->
<div class="table_list">
<div class="warningTitle">甘肃省烟草专卖局(公司)安全生产得分(总分100分)</div>
</div>
<div class="table-container">
<el-table :data="tableData" :span-method="handleSpan" border style="width: 100%;" height="100%">
<el-table-column prop="moduleName" label="评估项目"></el-table-column>
<el-table-column prop="itemName" label="预警要素"></el-table-column>
<el-table-column prop="agencyName" label="指标名称"></el-table-column>
<el-table-column prop="score" label="得分"></el-table-column>
</el-table>
</div>
</div>
</div>
</div>
</template>
<script setup>
import * as MOSTY from "@/components/MyComponents/index"
import * as echarts from "echarts"
import "echarts-liquidfill"
import { ref, onMounted } from "vue"
import { getApi, postApi } from "@/api/tobAcco_api.js";
import rank from "./com/rank.vue"
import waterPolo from './com/waterPolo.vue'
const yearStr = ref((new Date().getFullYear()).toString())
const tableData = ref([])
const rankRef = ref(null)
const waterPoloRef = ref(null)
const search = (val) => {
if (rankRef.value) rankRef.value.getTableDetail(val)
if (waterPoloRef.value) waterPoloRef.value.refresh(val)
getTableDetail()
}
const handleSpan = ({ row, column, rowIndex, columnIndex }) => {
if (columnIndex === 0) { // 处理“评估项目”列
if (row.moduleRowSpan > 0) {
return [row.moduleRowSpan, 1];
} else {
return [0, 0]; // 非首行隐藏
}
} else if (columnIndex === 1) { // 处理“预警要素”列
if (row.itemRowSpan > 0) {
return [row.itemRowSpan, 1];
} else {
return [0, 0];
}
}
return [1, 1]; // 其他列不合并
}
const disabledDate = (time) => {
return time.getFullYear() > new Date().getFullYear() || time.getFullYear() < 2010
}
/**
* 初始化趋势分布
*/
const initializeTrendDistributionLineChart = () => {
let chartDom = document.getElementById("trendDistribution")
let myChart = echarts.init(chartDom)
let option
option = {
grid: {
top: "20px",
left: "40px",
right: "10px",
bottom: "30px"
},
xAxis: {
type: "category",
data: ["一月", "二月", "三月", "四月", "五月", "六月", "七月"]
},
yAxis: {
splitLine: {
lineStyle: {
color: "#565050",
width: 0.1
}
},
type: "value"
},
series: [
{
data: [150, 230, 224, 218, 135, 147, 260],
type: "line",
areaStyle: {
color: "rgba(21,107,84,0.09)"
},
smooth: true,
color: "#0b6c51"
}
]
}
option && myChart.setOption(option)
}
const processData = (originalData) => {
const flatData = [];
originalData.forEach(module => {
const moduleName = module.moduleName;
// 计算该模块总行数(所有指标数量之和)
const moduleRowCount = module.items.reduce((sum, item) => sum + item.agencys.length, 0);
let moduleRowIndex = 0; // 记录当前模块内的行索引
module.items.forEach(item => {
const itemName = item.itemName;
const itemRowCount = item.agencys.length; // 当前预警要素的行数
item.agencys.forEach((agency, agencyIndex) => {
flatData.push({
moduleName,
moduleRowSpan: moduleRowIndex === 0 ? moduleRowCount : 0, // 模块首行设置合并行数
itemName,
itemRowSpan: agencyIndex === 0 ? itemRowCount : 0, // 预警要素首行设置合并行数
agencyName: agency.agencyName,
score: agency.score
});
moduleRowIndex++;
});
});
});
return flatData;
}
/**
* 获取表格数据
*/
const getTableDetail = () => {
getApi({ year: yearStr.value }, "/mosty-jcgl/scoreDetail/getScoreDetailList").then((res) => {
if (Array.isArray(res)) {
tableData.value = processData(res)
} else {
tableData.value = []
}
})
}
onMounted(() => {
initializeTrendDistributionLineChart()
search()
// getTableDetail()
// if (rankRef.value) rankRef.value.getTableDetail(val)
// if (waterPoloRef.value) waterPoloRef.value.refresh(val)
})
</script>
<style scoped lang="scss">
.warning-header {
display: flex;
justify-content: space-between;
align-items: center;
background-color: #fff;
padding-right: 10px;
}
.warning-title {
display: flex;
justify-content: space-between;
align-items: center;
height: 39px;
padding-left: 20px;
line-height: 39px;
font-size: 18px;
color: var(--el-color-primary);
background-color: #fff;
}
.warning-container {
display: flex;
height: calc(100vh - 170px);
.right-content {
width: calc(100% - 330px);
height: calc(100vh - 180px);
// height: calc(100vh - 140px);
// padding: 10px;
// background-color: #fff;
// overflow-y: auto;
// box-sizing: border-box;
}
}
.warningStatisticsTitle {
display: flex;
align-items: center;
justify-content: space-between;
background: #faf6f6;
padding: 10px;
.right-head-polo-line-echart {
width: calc((100% - 10px) / 2);
box-sizing: border-box;
background: #fff;
padding: 10px;
height: 200px;
.trendDistribution {
height: calc(100% - 18px);
width: 100%;
}
// .warningCent {
// height: calc(100% - 18px);
// display: flex;
// align-items: center;
// justify-content: center;
// .liquidfill-container {
// width: 170px;
// height: 100%;
// }
// .warningCentInfo {
// width: calc(100% - 170px);
// height: 100%;
// display: flex;
// flex-wrap: wrap; align-items: center;
// justify-content: space-between;
// color: #0b6c51;
// font-size: 13px;
// box-sizing: border-box;
// padding: 20px 0;
// .warningCentInfoItem {
// width: 50%;
// display: flex;
// align-items: center;
// justify-content: space-between;
// padding: 0 10px;
// .warningCentInfoTitle {
// color: #0a0909;
// display: flex;
// align-items: center;
// span {
// margin-left: 8px;
// }
// }
// }
// }
// }
}
}
.warningTitle {
font-size: 18px;
line-height: 18px;
color: #03130e;
padding-left: 20px;
border-left: 4px solid #0b6c51;
}
.table_list {
padding: 10px;
background-color: #fff;
}
.table-container {
padding: 0 10px 11px;
background: #fff;
height: calc(100% - 250px);
}
</style>