Merge remote-tracking branch 'origin/dev' into dev

pull/1/head
chenxinying 2024-01-17 10:23:18 +08:00
commit 63be3b2f81
31 changed files with 2565 additions and 49 deletions

148
package-lock.json generated
View File

@ -16,6 +16,8 @@
"axios": "^1.6.3",
"dayjs": "^1.11.10",
"element-plus": "^2.4.4",
"html2canvas": "^1.4.1",
"jspdf": "^2.5.1",
"lodash-es": "^4.17.21",
"mitt": "^3.0.1",
"normalize.css": "^8.0.1",
@ -580,6 +582,17 @@
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/runtime": {
"version": "7.23.8",
"resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.23.8.tgz",
"integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==",
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/template": {
"version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
@ -1305,6 +1318,12 @@
"undici-types": "~5.26.4"
}
},
"node_modules/@types/raf": {
"version": "3.4.3",
"resolved": "https://registry.npmmirror.com/@types/raf/-/raf-3.4.3.tgz",
"integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==",
"optional": true
},
"node_modules/@types/sortablejs": {
"version": "1.15.7",
"resolved": "https://registry.npmmirror.com/@types/sortablejs/-/sortablejs-1.15.7.tgz",
@ -1879,6 +1898,17 @@
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/atob": {
"version": "2.1.2",
"resolved": "https://registry.npmmirror.com/atob/-/atob-2.1.2.tgz",
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
"bin": {
"atob": "bin/atob.js"
},
"engines": {
"node": ">= 4.5.0"
}
},
"node_modules/autoprefixer": {
"version": "10.4.16",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz",
@ -2021,6 +2051,17 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
}
},
"node_modules/btoa": {
"version": "1.2.1",
"resolved": "https://registry.npmmirror.com/btoa/-/btoa-1.2.1.tgz",
"integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==",
"bin": {
"btoa": "bin/btoa.js"
},
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/builtins": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz",
@ -2113,6 +2154,31 @@
}
]
},
"node_modules/canvg": {
"version": "3.0.10",
"resolved": "https://registry.npmmirror.com/canvg/-/canvg-3.0.10.tgz",
"integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==",
"optional": true,
"dependencies": {
"@babel/runtime": "^7.12.5",
"@types/raf": "^3.4.0",
"core-js": "^3.8.3",
"raf": "^3.4.1",
"regenerator-runtime": "^0.13.7",
"rgbcolor": "^1.0.1",
"stackblur-canvas": "^2.0.0",
"svg-pathdata": "^6.0.3"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/canvg/node_modules/regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
"optional": true
},
"node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@ -2218,6 +2284,13 @@
"dev": true,
"peer": true
},
"node_modules/core-js": {
"version": "3.35.0",
"resolved": "https://registry.npmmirror.com/core-js/-/core-js-3.35.0.tgz",
"integrity": "sha512-ntakECeqg81KqMueeGJ79Q5ZgQNR+6eaE8sxGCx62zMbAIj65q+uYvatToew3m6eAGdU4gNZwpZ34NMe4GYswg==",
"hasInstallScript": true,
"optional": true
},
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@ -2354,6 +2427,12 @@
"integrity": "sha512-l32Xp/TLgWb8ReqbVJAFIvXmY7go4nTxxlWiAFyhoQw9RKEOHBZNnyGvJWqDVSPmq3Y9HlM4npqF/T6VMOXhww==",
"deprecated": "dommatrix is no longer maintained. Please use @thednp/dommatrix."
},
"node_modules/dompurify": {
"version": "2.4.7",
"resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-2.4.7.tgz",
"integrity": "sha512-kxxKlPEDa6Nc5WJi+qRgPbOAbgTpSULL+vI3NUXsZMlkJxTqYI9wg5ZTay2sFrdZRWHPWNi+EdAhcJf81WtoMQ==",
"optional": true
},
"node_modules/electron-to-chromium": {
"version": "1.4.617",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.617.tgz",
@ -3124,6 +3203,11 @@
"reusify": "^1.0.4"
}
},
"node_modules/fflate": {
"version": "0.4.8",
"resolved": "https://registry.npmmirror.com/fflate/-/fflate-0.4.8.tgz",
"integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA=="
},
"node_modules/file-entry-cache": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@ -3909,6 +3993,23 @@
"integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==",
"dev": true
},
"node_modules/jspdf": {
"version": "2.5.1",
"resolved": "https://registry.npmmirror.com/jspdf/-/jspdf-2.5.1.tgz",
"integrity": "sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA==",
"dependencies": {
"@babel/runtime": "^7.14.0",
"atob": "^2.1.2",
"btoa": "^1.2.1",
"fflate": "^0.4.8"
},
"optionalDependencies": {
"canvg": "^3.0.6",
"core-js": "^3.6.0",
"dompurify": "^2.2.0",
"html2canvas": "^1.0.0-rc.5"
}
},
"node_modules/keyv": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@ -4386,6 +4487,12 @@
}
}
},
"node_modules/performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
"optional": true
},
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
@ -4627,6 +4734,15 @@
}
]
},
"node_modules/raf": {
"version": "3.4.1",
"resolved": "https://registry.npmmirror.com/raf/-/raf-3.4.1.tgz",
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
"optional": true,
"dependencies": {
"performance-now": "^2.1.0"
}
},
"node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@ -4639,6 +4755,11 @@
"node": ">=8.10.0"
}
},
"node_modules/regenerator-runtime": {
"version": "0.14.1",
"resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
},
"node_modules/regexp.prototype.flags": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz",
@ -4726,6 +4847,15 @@
"node": ">=0.10.0"
}
},
"node_modules/rgbcolor": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/rgbcolor/-/rgbcolor-1.0.1.tgz",
"integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
"optional": true,
"engines": {
"node": ">= 0.8.15"
}
},
"node_modules/rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@ -4936,6 +5066,15 @@
"node": ">=0.10.0"
}
},
"node_modules/stackblur-canvas": {
"version": "2.6.0",
"resolved": "https://registry.npmmirror.com/stackblur-canvas/-/stackblur-canvas-2.6.0.tgz",
"integrity": "sha512-8S1aIA+UoF6erJYnglGPug6MaHYGo1Ot7h5fuXx4fUPvcvQfcdw2o/ppCse63+eZf8PPidSu4v1JnmEVtEDnpg==",
"optional": true,
"engines": {
"node": ">=0.1.14"
}
},
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@ -5062,6 +5201,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/svg-pathdata": {
"version": "6.0.3",
"resolved": "https://registry.npmmirror.com/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
"integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
"optional": true,
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/text-segmentation": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/text-segmentation/-/text-segmentation-1.0.3.tgz",

View File

@ -18,6 +18,8 @@
"axios": "^1.6.3",
"dayjs": "^1.11.10",
"element-plus": "^2.4.4",
"html2canvas": "^1.4.1",
"jspdf": "^2.5.1",
"lodash-es": "^4.17.21",
"mitt": "^3.0.1",
"normalize.css": "^8.0.1",

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

View File

@ -568,6 +568,69 @@ export default [
},
],
},
{
path: "/continuous_improvement/risk_analysis",
meta: { title: "风险分析", isSubMenu: false },
component: "continuous_improvement/risk_analysis/index",
},
{
path: "/continuous_improvement/enterprise_report",
meta: { title: "企业报告", isSubMenu: false },
component: "continuous_improvement/enterprise_report/index",
},
{
path: "/continuous_improvement/risk_analysis_record",
meta: { title: "风险分析记录", isSubMenu: false },
component: "continuous_improvement/risk_analysis_record/index",
},
],
},
{
path: "/statistical_analysis",
redirect: "/statistical_analysis/hazard_statistics",
meta: { title: "统计分析", model: MODEL["1"] },
component: "children",
children: [
{
path: "/statistical_analysis/hazard_statistics",
meta: { title: "隐患统计", isSubMenu: false },
component: "statistical_analysis/hazard_statistics/index",
},
{
path: "/statistical_analysis/detection_situation",
meta: { title: "员工日常检测情况", isSubMenu: false },
component: "children",
children: [
{
path: "",
component: "statistical_analysis/detection_situation/index",
},
{
path: "/statistical_analysis/detection_situation/print",
meta: {
title: "打印",
activeMenu: "/statistical_analysis/detection_situation",
},
component: "statistical_analysis/detection_situation/print",
},
],
},
{
path: "/statistical_analysis/usage_situation",
meta: { title: "员工使用情况分析", isSubMenu: false },
component: "statistical_analysis/usage_situation/index",
},
{
path: "/statistical_analysis/inventory_statistics_month",
meta: { title: "员工清单检查统计(月)", isSubMenu: false },
component: "children",
children: [
{
path: "",
component: "statistical_analysis/inventory_statistics_month/index",
},
],
},
],
},
{

View File

@ -83,6 +83,13 @@ export const layoutFnGetRiskLevel = async () => {
});
return ref(resData.list);
};
// 风险成因
export const layoutFnGetRiskCauses = async () => {
const resData = await getLevels({
DICTIONARIES_ID: "1bacbc4c1f6544718519c0d470dfeb62",
});
return ref(resData.list);
};
// 部门级别
export const layoutFnGetDepartmentLevel = async () => {
const resData = await getLevels({

View File

@ -1,5 +1,5 @@
<template>
<el-form ref="formRef" :rules="rules" :model="form" label-width="240px">
<el-form ref="formRef" :rules="defineRules" :model="form" label-width="240px">
<el-row>
<el-col :span="24" v-if="!infoIsEmpty">
<el-form-item label="管控部门" prop="DEPTNAME">
@ -204,6 +204,7 @@
</el-form-item>
</el-col>
</template>
<slot />
</el-row>
</el-form>
</template>
@ -241,10 +242,14 @@ const props = defineProps({
type: Boolean,
default: false,
},
rules: {
type: Object,
default: () => ({}),
},
});
const emits = defineEmits(["update:form"]);
const form = useVModel(props, "form", emits);
const rules = {
const defineRules = {
USER_ID: [{ required: true, message: "管控责任人不能为空", trigger: "blur" }],
RISK_DESCR: [
{ required: true, message: "存在风险不能为空", trigger: "blur" },
@ -285,6 +290,7 @@ const rules = {
IDENTIFICATION_ID: [
{ required: true, message: "辨识部位不能为空", trigger: "change" },
],
...props.rules,
};
const formRef = ref(null);
const infoIsEmpty = ref(isEmpty(props.info));
@ -317,6 +323,9 @@ watch(
([LIKELIHOOD, EXPOSURE, CONSEQUENCE]) => {
if (!LIKELIHOOD || !EXPOSURE || !CONSEQUENCE) return;
fnGetLevelName(LIKELIHOOD, EXPOSURE, CONSEQUENCE);
},
{
immediate: true,
}
);
const fnGetUnitList = async () => {

View File

@ -0,0 +1,84 @@
<template>
<el-descriptions :column="2" border>
<el-descriptions-item label="风险单元">
{{ info.RISKUNITNAME }}
</el-descriptions-item>
<el-descriptions-item label="辨识部位">
{{ info.PARTSNAME }}
</el-descriptions-item>
<el-descriptions-item label="存在风险" :span="2">
{{ info.RISK_DESCR }}
</el-descriptions-item>
<el-descriptions-item label="事故发生的可能性">
<span v-if="info.LIKELIHOOD === 10"></span>
<span v-else-if="info.LIKELIHOOD === 6">相当可能</span>
<span v-else-if="info.LIKELIHOOD === 3">可能但不经常</span>
<span v-else-if="info.LIKELIHOOD === 1">可能性小完全意外</span>
<span v-else-if="info.LIKELIHOOD === 0.5">很不可能可以设想</span>
<span v-else-if="info.LIKELIHOOD === 0.2">极不可能</span>
<span v-else-if="info.LIKELIHOOD === 0.1">实际不可能</span>
</el-descriptions-item>
<el-descriptions-item label="分值">
{{ info.LIKELIHOOD }}
</el-descriptions-item>
<el-descriptions-item label="人员暴露于危险环境中的频繁程度">
<span v-if="info.EXPOSURE === 10"></span>
<span v-else-if="info.EXPOSURE === 6">每天工作时间内暴露</span>
<span v-else-if="info.EXPOSURE === 3">每周一次或偶然暴露</span>
<span v-else-if="info.EXPOSURE === 2">每月一次暴露完全意外</span>
<span v-else-if="info.EXPOSURE === 1">每年几次暴露</span>
<span v-else-if="info.EXPOSURE === 0.5">非常罕见暴露</span>
</el-descriptions-item>
<el-descriptions-item label="分值">
{{ info.EXPOSURE }}
</el-descriptions-item>
<el-descriptions-item label="一旦发生事故可能造成的后果">
<span v-if="info.CONSEQUENCE === 100">10</span>
<span v-else-if="info.CONSEQUENCE === 40">39人死亡</span>
<span v-else-if="info.CONSEQUENCE === 15">12人死亡</span>
<span v-else-if="info.CONSEQUENCE === 7">严重</span>
<span v-else-if="info.CONSEQUENCE === 3">重大伤残</span>
<span v-else-if="info.CONSEQUENCE === 1">引人注意</span>
</el-descriptions-item>
<el-descriptions-item label="分值">
{{ info.CONSEQUENCE }}
</el-descriptions-item>
<el-descriptions-item label="风险分级">
{{ info.DNAME5 }}
</el-descriptions-item>
<el-descriptions-item label="总分值">
{{ info.DANGER }}
</el-descriptions-item>
<el-descriptions-item label="管控措施" :span="2">
{{ info.MEASURES }}
</el-descriptions-item>
<el-descriptions-item label="管控部门">
{{ info.DEPT_NAME_ALL }}
</el-descriptions-item>
<el-descriptions-item label="管控责任人">
{{ info.USER_ID }}
</el-descriptions-item>
<el-descriptions-item label="事故类型" :span="2">
{{ info.ACCIDENTS_NAME }}
</el-descriptions-item>
<el-descriptions-item label="应急处置措施" :span="2">
{{ info.EME_MEASURES }}
</el-descriptions-item>
<slot />
</el-descriptions>
</template>
<script setup>
defineOptions({
name: "LayoutRiskView",
});
defineProps({
info: {
type: Object,
required: true,
default: () => ({}),
},
});
</script>
<style scoped lang="scss"></style>

View File

@ -14,6 +14,7 @@
:show-summary="showSummary"
:summary-method="summaryMethod"
:span-method="spanMethod"
:default-expand-all="defaultExpandAll"
@row-click="rowClick"
@row-dblclick="rowDblclick"
>
@ -79,6 +80,10 @@ const props = defineProps({
type: Boolean,
default: false,
},
defaultExpandAll: {
type: Boolean,
default: false,
},
rowKey: {
type: [String, Function],
},

View File

@ -0,0 +1,34 @@
import { post } from "@/request/axios.js";
export const setHazardAnalysisSubmit = (params) =>
post("/riskpointanalysis/add", params); // 隐患分析提交
export const getRiskAnalysisList = (params) =>
post("/riskpointanalysis/list", params); // 风险分析列表
export const setRiskAnalysisRepulse = (params) =>
post("/riskpointanalysis/delete", params); // 风险分析打回
export const setRiskAnalysisAdopt = (params) =>
post("/riskpointanalysis/apply", params); // 风险分析通过
export const getRiskAnalysisRecordList = (params) =>
post("/riskpoint/getLogs", params); // 风险分析记录列表
export const getRiskAnalysisRecordView = (params) =>
post("/riskpointanalysis/getInfo", params); // 风险分析记录查看
// 企业报告 start
export const getEnterpriseReport1 = (params) =>
post("/corpinfo/getDiagnosis", params);
export const getEnterpriseReport2 = (params) =>
post("/jobEvaluation/counlistPaget?showCount=1000&currentPage=1", params);
export const getEnterpriseReport3 = (params) =>
post("/studytask/list?showCount=100&currentPage=1", params);
export const getEnterpriseReport4 = (params) =>
post("/confinedspace/getDiagnosis", params);
export const getEnterpriseReport5 = (params) =>
post("/performanceexamine_dept/listAll", params);
export const getEnterpriseReport6 = (params) =>
post("/performanceexamine_user/listAll", params);
export const getEnterpriseReportConclusion = (params) =>
post("/corpadvice/listAll", params); // 企业报告结论
export const setEnterpriseReportConclusionEdit = (params) =>
post("/corpadvice/edit", params); // 企业报告结论编辑
export const setEnterpriseReportConclusionAdd = (params) =>
post("/corpadvice/add", params); // 企业报告结论新增
// 企业报告 end

View File

@ -0,0 +1,10 @@
import { post } from "@/request/axios.js";
export const getHazardStatisticsList = (params) =>
post("/statistics/gostatistics", params); // 隐患统计列表
export const getDetectionSituationList = (params) =>
post("/jobEvaluation/counlistPaget", params); // 员工日常检测情况列表
export const getDetectionSituationListTime = (params) =>
post("/liststatistics/getTimeAstrict", params); // 员工日常检测情况列表时间
export const getUsageSituationList = (params) =>
post("/liststatistics/checkSituation", params); // 员工使用情况分析列表

View File

@ -0,0 +1,76 @@
<template>
<el-dialog v-model="visible" title="请填写结论建议" :on-close="fnClose">
<div>
<el-input
v-model="advice"
type="textarea"
:autosize="{
minRows: 3,
}"
placeholder="这里输入意见..."
/>
</div>
<template #footer>
<el-button @click="fnClose"> </el-button>
<el-button type="primary" @click="fnSubmit"> </el-button>
</template>
</el-dialog>
</template>
<script setup>
import { useVModels } from "@vueuse/core";
import { debounce } from "throttle-debounce";
import {
setEnterpriseReportConclusionAdd,
setEnterpriseReportConclusionEdit,
} from "@/request/continuous_improvement.js";
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
advice: {
type: String,
required: true,
default: "",
},
corpAdvice: {
type: Object,
required: true,
default: () => ({}),
},
month: {
type: String,
required: true,
default: "",
},
});
const emits = defineEmits(["update:visible", "update:advice", "submit"]);
const { visible, advice } = useVModels(props, emits);
const fnClose = () => {
visible.value = false;
};
const fnSubmit = debounce(
1000,
async () => {
if (props.corpAdvice.CORPADVICE_ID) {
await setEnterpriseReportConclusionEdit({
...props.corpAdvice,
ADVICE: advice.value,
});
} else {
await setEnterpriseReportConclusionAdd({
ADVICE_DATE: props.month,
ADVICE: advice.value,
});
}
fnClose();
emits("submit");
},
{ atBegin: true }
);
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,76 @@
<template>
<el-drawer v-model="visible" title="查看其他诊断书">
<el-row>
<el-col
v-for="(item, index) in dateList"
:key="index"
:span="6"
:offset="1"
>
<div
style="
text-align: center;
cursor: pointer;
margin-top: 10px;
border-radius: 10px;
"
:style="{
background: adviceDate?.includes(item)
? 'var(--el-border-color)'
: 'var(--el-fill-color-light)',
}"
@click="fnCheck(item)"
>
<div
style="
color: var(--el-text-color-regular);
padding: 10px 0;
border-radius: 10px;
"
:style="{
background: item === month ? 'var(--el-color-primary)' : '',
}"
>
{{ item }}
</div>
</div>
</el-col>
</el-row>
</el-drawer>
</template>
<script setup>
import { useVModels } from "@vueuse/core";
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
dateList: {
type: Array,
required: true,
default: () => [],
},
adviceDate: {
type: Array,
required: true,
default: () => [],
},
month: {
type: String,
required: true,
default: "",
},
});
const emits = defineEmits(["update:visible", "update:month", "check"]);
const { visible, month } = useVModels(props, emits);
const fnCheck = (item) => {
visible.value = false;
month.value = item;
emits("check");
};
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,889 @@
<template>
<layout-card>
<div class="pdf-page">
<div name="pdf-box" class="pdf-cover">
<div class="top">
<h1>{{ data.cpd.CORP_NAME }}</h1>
<h1>秦安双重预防机制建设平台</h1>
<h1>体系运行报告</h1>
</div>
<div class="bot">
<h1>{{ data.cpd.CORP_NAME }}</h1>
<h1>{{ dayjs(startDate).format("YYYY年MM月") }}</h1>
</div>
</div>
<div class="pdf-print">
<!-- TODO PDF导出分页截断"-->
<el-button type="primary" @click="fnPDFPrinting">PDF</el-button>
</div>
<div name="pdf-box" class="pdf-content">
<h1>1.概述</h1>
<p>
{{ data.cpd.CORP_NAME }}公司统一社会信用代码为{{
data.cpd.CODE
}}公司地址{{ data.cpd.COMPANY_AREA }}所属行业{{
data.cpd.CORP_TYPE_NAME
}}主要负责人{{ data.cpd.LR_NAME }}
</p>
<p>
本体系运行报告的数据来源于{{
data.cpd.CORP_NAME
}}秦安双重预防机制建设平台相关数据如企业信息风险管控隐患排查隐患治理教育培训高危作业管理等均取自数据库实际数据
</p>
<p>
本体系运行报告的数据统计时间范围{{
dayjs(startDate).format("YYYY年MM月DD日")
}}-{{ dayjs(lastDate).format("YYYY年MM月DD日") }}
</p>
<h1>2.风险管控</h1>
<h4>2.1 风险点单元</h4>
<p>
截至到{{ dayjs(lastDate).format("YYYY年MM月DD日") }}公司共建立{{
data.riskpd.unit_count
}}个风险点单元
</p>
<h4>2.2 辨识部位</h4>
<p>
截至到{{ dayjs(lastDate).format("YYYY年MM月DD日") }}公司共辨识了{{
data.riskpd.id_count
}}个辨识部位
</p>
<h4>2.3 风险管控信息台账</h4>
<p>
截至到{{ dayjs(lastDate).format("YYYY年MM月DD日") }}公司建立了{{
data.riskpd.risk_count
}}个风险管控信息台账其中重大风险{{ data.riskpd.a_count }}
较大风险{{ data.riskpd.b_count }}一般风险{{
data.riskpd.c_count
}}低风险{{ data.riskpd.d_count }}
</p>
</div>
<div name="pdf-box" class="pdf-content">
<h1>3.隐患排查</h1>
<h4>3.1清单管理</h4>
<p>
截至到{{ dayjs(lastDate).format("YYYY年MM月DD日") }}公司共建立{{
data.lists.length
}}个隐患排查清单其中日常隐患排查清单{{ data.listType0001 }}
综合性隐患排查清单{{ data.listType0002 }}季节性隐患排查清单{{
data.listType0004
}}节假日隐患排查清单{{
data.listType0005
}}专业性隐患排查清单{{ data.listType0003 }}
</p>
<p>
{{ dayjs(startDate).format("YYYY年MM月DD日") }}-{{
dayjs(lastDate).format("YYYY年MM月DD日")
}}公司新建了{{ data.monthlist.length }}个排查清单详细情况如下:
</p>
<table>
<thead>
<tr>
<td width="60" align="center">序号</td>
<td>清单类型</td>
<td>清单名称</td>
<td>清单负责人</td>
<td>清单建立时间</td>
<td>清单排查周期</td>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in data.lists" :key="index">
<td align="center">{{ index + 1 }}</td>
<td>{{ typeMap[item.TYPE] }}</td>
<td>{{ item.NAME }}</td>
<td>{{ item.USER_NAME }}</td>
<td>{{ dayjs(item.CREATTIME).format("YYYY年MM月DD日") }}</td>
<td>{{ periodMap[item.PERIOD] }}</td>
</tr>
<tr v-if="data.lists.length === 0">
<td colspan="6" align="center">暂无数据</td>
</tr>
</tbody>
</table>
<h4>3.2清单排查情况</h4>
<p>
{{ dayjs(startDate).format("YYYY年MM月DD日") }}-{{
dayjs(lastDate).format("YYYY年MM月DD日")
}}公司已建立清单用户详细排查情况见表1
</p>
<table>
<thead>
<tr>
<td width="60" align="center">序号</td>
<td>部门</td>
<td>岗位</td>
<td>姓名</td>
<td>负责的清单数</td>
<td>应排查清单的次数</td>
<td>实际排查次数</td>
<td>排查率</td>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in data.checkList" :key="index">
<td align="center">{{ index + 1 }}</td>
<td>{{ item.DEPARTNAME_ALL }}</td>
<td>{{ item.POSTNAME }}</td>
<td>{{ item.USERNAME }}</td>
<td>{{ item.listCount }}</td>
<td>{{ item.staCount }}</td>
<td>{{ item.cheCount }}</td>
<td>{{ item.percent }}</td>
</tr>
<tr v-if="data.checkList.length === 0">
<td colspan="8" align="center">暂无数据</td>
</tr>
</tbody>
</table>
<h4>3.3隐患治理情况</h4>
<p>
{{ dayjs(startDate).format("YYYY年MM月DD日") }}-{{
dayjs(lastDate).format("YYYY年MM月DD日")
}}公司共发现隐患{{ data.hdlist.length }} 其中重大隐患{{
data.zd_count
}}一般隐患{{ data.yb_count }}其中待整改{{
data.dzg_count
}}待验收{{ data.dys_count }}已验收{{
data.yys_count
}}已超期{{ data.cq_count }}
</p>
<p class="pdf-subtitle">隐患治理情况见表2</p>
<table>
<thead>
<tr>
<td width="60" align="center">序号</td>
<td width="120" align="center">隐患发现时间</td>
<td width="80" align="center">检查人</td>
<td width="80">检查部门</td>
<td width="80">问题描述</td>
<td>整改措施</td>
<td width="80">整改情况</td>
<td width="100">整改前照片</td>
<td width="100">整改后照片</td>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in data.hdlist" :key="index">
<td align="center">{{ index + 1 }}</td>
<td>{{ item.CREATTIME }}</td>
<td>{{ item.USER_NAME }}</td>
<td>{{ item.DEPARTMENT_NAME }}</td>
<td>{{ item.HIDDENDESCR }}</td>
<td>{{ item.RECTIFYDESCR }}</td>
<td v-if="item.STATE === '-1'"></td>
<td v-if="item.STATE === '1'">
{{
item.HIDDENLEVEL === "hiddenLevel0001" ? "待整改" : "整改中"
}}
</td>
<td v-if="item.STATE === '2'"></td>
<td v-if="item.STATE === '3'"></td>
<td v-if="item.STATE === '4'"></td>
<td>
<viewer :images="[VITE_FILE_URL + item.HD_IMGS]">
<img
v-if="item.HD_IMGS"
:src="VITE_FILE_URL + item.HD_IMGS"
alt=""
/>
</viewer>
</td>
<td>
<viewer :images="[VITE_FILE_URL + item.ZG_IMGS]">
<img
v-if="item.ZG_IMGS"
:src="VITE_FILE_URL + item.ZG_IMGS"
alt=""
/>
</viewer>
</td>
</tr>
<tr v-if="data.hdlist.length === 0">
<td colspan="9" align="center">暂无数据</td>
</tr>
</tbody>
</table>
</div>
<div name="pdf-box" class="pdf-content">
<h1>4.风险分析记录</h1>
<p>改进信息显示风险辨识台账更新记录</p>
<table>
<tr>
<td align="center">风险点单元</td>
<td align="center">辨识部位</td>
<td align="center">改进类型</td>
<td align="center">持续改进</td>
<td align="center">存在风险</td>
<td align="center">管控措施</td>
</tr>
<tr v-for="(item, index) in data.riskLog" :key="index">
<td align="center" rowspan="2" v-if="index % 2 === 0">
{{ item.risk_unit_name }}
</td>
<td rowspan="2" v-if="index % 2 === 0">{{ item.parts_name }}</td>
<td rowspan="2" v-if="index % 2 === 0">{{ item.is_new }}</td>
<td>{{ item.label }}</td>
<td>{{ item.risk_descr }}</td>
<td>{{ item.measures }}</td>
</tr>
<tr v-if="data.riskLog.length === 0">
<td colspan="6" align="center">暂无数据</td>
</tr>
</table>
</div>
<div name="pdf-box" class="pdf-content">
<h1>5.教育培训情况</h1>
<h4>5.1教育培训</h4>
<p>
{{ dayjs(startDate).format("YYYY年MM月DD日") }}-{{
dayjs(lastDate).format("YYYY年MM月DD日")
}}公司共完成建立{{ data.studypd.curriculum_count }}课程 完成建立{{
data.studypd.paper_count
}}试卷完成建立{{
data.studypd.task_count
}}次学习任务岗位培训类型分别为{{
data.post_type_name_arr.join("")
}}培训时间{{ data.sum_classhour }}分钟 共有{{
data.study_student_count
}}名学员参与平台教育培训考核通过{{
data.study_pass_count
}}通过率{{ data.study_pass_rate || 0 }}%
</p>
<table>
<thead>
<tr>
<td width="60" align="center">序号</td>
<td>课程名称</td>
<td>培训类型</td>
<td>任务学时分钟</td>
<td>学员人数</td>
<td>任务状态</td>
<td>应考人数</td>
<td>参考人数/合格人数</td>
<td>通过率</td>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in data.studylist" :key="index">
<td align="center">{{ index + 1 }}</td>
<td>{{ item.STUDY_NAME }}</td>
<td>{{ item.train_type_name }}</td>
<td>{{ item.SUM_CLASSHOUR }}</td>
<td>{{ item.userCount }}</td>
<td v-if="item.PEIXUE_START_TIME > dayjs().format('YYYY-MM-DD')">
未开始
</td>
<td
v-else-if="
item.PEIXUE_START_TIME <= dayjs().format('YYYY-MM-DD') &&
item.PEIXUE_END_TIME >= dayjs().format('YYYY-MM-DD')
"
>
进行中
</td>
<td
v-else-if="item.PEIXUE_END_TIME <= dayjs().format('YYYY-MM-DD')"
>
已结束
</td>
<td>{{ item.userCount }}</td>
<td>{{ item.cj }}/{{ item.hg }}</td>
<td>
{{ item.cj === 0 ? 0 : ((item.hg / item.cj) * 100).toFixed(2) }}
</td>
</tr>
</tbody>
<tr v-if="data.studylist.length === 0">
<td colspan="9" align="center">暂无数据</td>
</tr>
</table>
<h4>5.2档案建立情况</h4>
<p>
{{ dayjs(startDate).format("YYYY年MM月DD日") }}-{{
dayjs(lastDate).format("YYYY年MM月DD日")
}}公司共完成建立个人档案{{ data.ztask_count }} 一期一档{{
data.studypd.task_count
}}
</p>
</div>
<div name="pdf-box" class="pdf-content">
<h1>6.特殊作业管理</h1>
<p>
{{ dayjs(startDate).format("YYYY年MM月DD日") }}-{{
dayjs(lastDate).format("YYYY年MM月DD日")
}}公司共新建{{ data.eight_count }}项特殊作业审批 已存档{{
data.eight_pass_count
}}项审批数据其中受限空间作业{{
data.eightlist?.[2]?.pass_count || 0
}}断路作业{{ data.eightlist?.[4]?.pass_count || 0 }}
盲板抽堵作业{{ data.eightlist?.[0]?.pass_count || 0 }}动土作业{{
data.eightlist?.[1]?.pass_count || 0
}}高处作业{{ data.eightlist?.[5]?.pass_count || 0 }}
吊装作业{{ data.eightlist?.[6]?.pass_count || 0 }}临时用电作业{{
data.eightlist?.[3]?.pass_count || 0
}}动火作业{{ data.eightlist?.[7]?.pass_count || 0 }}
</p>
</div>
<div name="pdf-box" class="pdf-content">
<h1>7.绩效考核</h1>
<p>
{{ dayjs(startDate).format("YYYY年MM月DD日") }}-{{
dayjs(lastDate).format("YYYY年MM月DD日")
}}公司绩效考核详细情况如下
</p>
<h4>7.1 部门考核</h4>
<table>
<thead>
<tr>
<td width="60" align="center">序号</td>
<td>部门</td>
<td>发现隐患</td>
<td>隐患整改</td>
<td>检查得分</td>
<td>培训得分</td>
<td>风险辨识完善得分</td>
<td>考核日期</td>
<td>考核等级</td>
<td>合计</td>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in data.deptPeList" :key="index">
<td align="center">{{ index + 1 }}</td>
<td>{{ item.DEPT_NAME_ALL }}</td>
<td>{{ item.SCORE1 }}</td>
<td>{{ item.SCORE2 }}</td>
<td>{{ item.SCORE3 }}</td>
<td>{{ item.SCORE4 }}</td>
<td>{{ item.SCORE5 }}</td>
<td>{{ month }}</td>
<td>
{{
computeLevel(
item.SCORE1 +
item.SCORE2 +
item.SCORE3 +
item.SCORE4 +
item.SCORE5
)
}}
</td>
<td>
{{
item.SCORE1 +
item.SCORE2 +
item.SCORE3 +
item.SCORE4 +
item.SCORE5
}}
</td>
</tr>
<tr v-if="data.deptPeList.length === 0">
<td colspan="10" align="center">暂无数据</td>
</tr>
</tbody>
</table>
<h4>7.2 人员考核</h4>
<table>
<thead>
<tr>
<td width="60" align="center">序号</td>
<td>部门</td>
<td>人员</td>
<td>发现隐患</td>
<td>隐患整改</td>
<td>检查得分</td>
<td>培训得分</td>
<td>风险辨识完善得分</td>
<td>考核日期</td>
<td>考核等级</td>
<td>合计</td>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in data.userPeList" :key="index">
<td align="center">{{ index + 1 }}</td>
<td>{{ item.DEPT_NAME_ALL }}</td>
<td>{{ item.USER_NAME }}</td>
<td>{{ item.SCORE1 }}</td>
<td>{{ item.SCORE2 }}</td>
<td>{{ item.SCORE3 }}</td>
<td>{{ item.SCORE4 }}</td>
<td>{{ item.SCORE5 }}</td>
<td>{{ showDate }}</td>
<td>
{{
computeLevel(
item.SCORE1 +
item.SCORE2 +
item.SCORE3 +
item.SCORE4 +
item.SCORE5
)
}}
</td>
<td>
{{
item.SCORE1 +
item.SCORE2 +
item.SCORE3 +
item.SCORE4 +
item.SCORE5
}}
</td>
</tr>
<tr v-if="data.userPeList.length === 0">
<td colspan="11" align="center">暂无数据</td>
</tr>
</tbody>
</table>
</div>
<div name="pdf-box" class="pdf-content">
<h1>8.结论建议</h1>
<p>
{{ data.corp_advice.ADVICE }}
</p>
</div>
</div>
<div class="tc mt-10">
<el-button type="primary" @click="fnConclusion"></el-button>
</div>
<div class="fixed_right" @click="data.otherVisible = true">
查看其它诊断书
</div>
<conclusion
v-model:visible="data.conclusionDialog.visible"
v-model:advice="data.conclusionDialog.advice"
:corp-advice="data.corp_advice"
:month="month"
@submit="fnGetConclusion"
/>
<other
v-model:visible="data.otherVisible"
v-model:month="month"
:advice-date="data.corp_advice_all"
:date-list="dateList"
@check="fnGetData"
/>
</layout-card>
</template>
<script setup>
import {
getEnterpriseReport1,
getEnterpriseReport2,
getEnterpriseReport3,
getEnterpriseReport4,
getEnterpriseReport5,
getEnterpriseReport6,
getEnterpriseReportConclusion,
} from "@/request/continuous_improvement.js";
import { reactive, ref, watchEffect } from "vue";
import dayjs from "dayjs";
import Conclusion from "./components/conclusion.vue";
import Other from "./components/other.vue";
import { ElLoading } from "element-plus";
import html2Canvas from "html2canvas";
import JsPDF from "jspdf";
let loading;
const VITE_FILE_URL = import.meta.env.VITE_FILE_URL;
const typeMap = {
listType0001: "日常隐患排查清单",
listType0002: "综合隐患排查清单",
listType0003: "专业隐患排查清单",
listType0004: "季节性隐患排查清单",
listType0005: "节假日隐患排查清单",
};
const periodMap = {
checkPeriod0001: "每日",
checkPeriod0002: "每周",
checkPeriod0003: "每旬",
checkPeriod0004: "每月",
checkPeriod0005: "每季",
checkPeriod0006: "每年",
checkPeriod0007: "半年",
};
const dateList = ref([]);
const month = ref("");
const startDate = ref("");
const lastDate = ref("");
const color = ref("unset");
const border_color = ref("var(--el-border-color-lighter)");
const data = reactive({
cpd: {},
riskpd: {},
lists: [],
monthlist: [],
hdlist: [],
studypd: {},
riskLog: [],
listType0001: 0,
listType0002: 0,
listType0003: 0,
listType0004: 0,
listType0005: 0,
yb_count: 0,
zd_count: 0,
dzg_count: 0,
dys_count: 0,
yys_count: 0,
cq_count: 0,
checkList: [],
studylist: [],
study_student_count: 0,
sum_classhour: 0,
study_pass_count: 0,
ztask_count: 0,
post_type_name_arr: [],
study_pass_rate: 0,
eightlist: [],
eight_count: 0,
eight_pass_count: 0,
deptPeList: [],
userPeList: [],
corp_advice: {},
corp_advice_all: [],
conclusionDialog: {
visible: false,
advice: "",
},
otherVisible: false,
});
watchEffect(() => {
startDate.value = dayjs(month.value).startOf("month").format("YYYY-MM-DD");
lastDate.value = dayjs(month.value).endOf("month").format("YYYY-MM-DD");
});
const fnGetDateList = () => {
let tempDate = "2022-06";
dateList.value.push(dayjs(tempDate).format("YYYY-MM"));
while (dayjs().diff(dayjs(tempDate), "month") > 0) {
tempDate = dayjs(tempDate).add(1, "month");
dateList.value.push(dayjs(tempDate).format("YYYY-MM"));
}
month.value = dateList.value[dateList.value.length - 1];
};
fnGetDateList();
const fnGetConclusion = async () => {
const resData = await getEnterpriseReportConclusion({ MONTH: month.value });
const resDataAll = await getEnterpriseReportConclusion();
data.corp_advice = resData.varList[0] || {
ADVICE:
"公司安全生产情况良好,需继续依据相关标准积极开展风险分级管控和隐患排查治理体系建设,根据公司目前的安全管理情况,须加强隐患排查、隐患整改等方面的安全管理,提高公司的安全管理水平,防止和减少生产安全事故的发生。",
};
data.corp_advice_all = resDataAll.varList.map((item) => item.ADVICE_DATE);
};
fnGetConclusion();
const computeLevel = (total) => {
if (total >= 75) return "一级";
else if (total >= 50) return "二级";
else if (total >= 25) return "三级";
else return "四级";
};
const fnGetData1 = async () => {
const resData = await getEnterpriseReport1({ MONTH: month.value });
data.cpd = resData.cpd;
data.riskpd = resData.riskpd;
data.lists = resData.lists;
data.monthlist = resData.monthlist;
data.hdlist = resData.hdlist;
data.studypd = resData.studypd;
data.riskLog = resData.riskLog;
data.lists.forEach((item) => {
if (item.TYPE === "listType0001") data.listType0001++;
else if (item.TYPE === "listType0002") data.listType0002++;
else if (item.TYPE === "listType0003") data.listType0003++;
else if (item.TYPE === "listType0004") data.listType0004++;
else if (item.TYPE === "listType0005") data.listType0005++;
});
data.hdlist.forEach((item) => {
if (item.HIDDENLEVEL === "hiddenLevel0001") data.yb_count++;
else data.zd_count++;
if (item.STATE === "1") data.dzg_count++;
else if (item.STATE === "2" || item.STATE === "3") data.dys_count++;
else if (item.STATE === "4") data.yys_count++;
else if (item.STATE === "-1") data.cq_count++;
});
};
const fnGetData2 = async () => {
const resData = await getEnterpriseReport2({
STARTTIME: startDate.value,
ENDTIME: lastDate.value,
});
data.checkList = resData.varList;
};
const fnGetData3 = async () => {
const resData = await getEnterpriseReport3({ MONTH: month.value });
data.studylist = resData.varList;
const post_type_name_set = new Set();
data.study_student_count = 0;
data.sum_classhour = 0;
data.study_pass_count = 0;
data.ztask_count = 0;
data.studylist.forEach((item) => {
post_type_name_set.add(item.post_type_name);
data.sum_classhour += item.SUM_CLASSHOUR;
data.study_student_count += item.cj;
data.study_pass_count += item.hg;
data.ztask_count += item.userCount;
});
if (post_type_name_set.size > 0) {
data.post_type_name_arr = Array.from(post_type_name_set);
}
if (data.study_student_count > 0) {
data.study_pass_rate = (
(data.study_pass_count / data.study_student_count) *
100
).toFixed(2);
}
};
const fnGetData4 = async () => {
const resData = await getEnterpriseReport4({ MONTH: month.value });
data.eightlist = resData.eightlist;
data.eight_count = 0;
data.eight_pass_count = 0;
data.eightlist.forEach((item) => {
data.eight_count += +item.count;
data.eight_pass_count += +item.pass_count || 0;
});
};
const fnGetData5 = async () => {
const resData = await getEnterpriseReport5({ MONTH: month.value });
data.deptPeList = resData.varList;
};
const fnGetData6 = async () => {
const resData = await getEnterpriseReport6({ MONTH: month.value });
data.userPeList = resData.varList;
};
const fnGetData = async () => {
await fnGetData1();
await fnGetData2();
await fnGetData3();
await fnGetData4();
await fnGetData5();
await fnGetData6();
};
fnGetData();
const fnConclusion = () => {
data.conclusionDialog.visible = true;
data.conclusionDialog.advice = data.corp_advice.ADVICE;
};
const fnPDFPrinting = () => {
loading = ElLoading.service({
lock: true,
text: "正在生成,请稍候...",
background: "rgba(0, 0, 0, 0.5)",
});
color.value = "#000";
border_color.value = "#000";
const elements = document.querySelectorAll('div[name="pdf-box"]');
fnHtmlToPdf("企业诊断报告", elements);
};
const fnHtmlToPdf = (filename, els) => {
const pdf = new JsPDF("", "pt", "a4");
const flagArr = [];
for (let i = 0, len = els.length; i < len; i++) {
flagArr.push(0);
}
runself(0);
function runself(index) {
const html = els[index];
const contentWidth = html.clientWidth; //
const contentHeight = html.clientHeight; //
let leftHeight = contentHeight;
const pageHeight = (contentWidth / 592.28) * 841.89;
let position = 0;
const canvas = document.createElement("canvas");
const scale = 2; // 2
canvas.width = contentWidth * scale; // &&
canvas.height = contentHeight * scale;
canvas.getContext("2d").scale(scale, scale);
const opts = {
// scale: scale,
canvas,
width: contentWidth,
height: contentHeight,
useCORS: true,
allowTaint: true,
};
html2Canvas(html, opts)
.then((canvas) => {
const pageData = canvas.toDataURL("image/jpeg", 1.0); // 0 - 1
const imgWidth = 555.28;
const imgHeight = (imgWidth / contentWidth) * contentHeight;
// pdf.addImage(pageData, 'JPEG', )
if (leftHeight < pageHeight) {
pdf.addImage(pageData, "JPEG", 20, 0, imgWidth, imgHeight);
} else {
while (leftHeight > 0) {
// arg3-->;arg4-->;arg5-->;arg6-->
pdf.addImage(pageData, "JPEG", 20, position, imgWidth, imgHeight);
leftHeight -= pageHeight;
position -= 841.89;
//
if (leftHeight > 0) {
pdf.addPage();
}
}
}
if (index < els.length - 1) {
pdf.addPage();
}
return 1;
})
.then((item) => {
flagArr[index] = item;
if (flagArr.every((f) => f === 1)) {
pdf.save(filename);
}
index++;
if (index < els.length) {
runself(index);
} else {
color.value = "unset";
border_color.value = "var(--el-border-color-lighter)";
loading.close();
}
});
}
};
</script>
<style scoped lang="scss">
.pdf-page {
width: 1100px;
border: 1px solid var(--el-border-color);
padding: 20px;
position: relative;
color: v-bind(color);
.pdf-print {
float: right;
}
.pdf-cover {
top: -1523px;
position: absolute;
width: 100%;
height: 1497px;
background: #fff url("/src/assets/images/print/cover-bg.png") no-repeat 0
bottom;
background-size: 100% 630px;
.top {
padding-top: 400px;
h1 {
font-size: 34px;
text-align: center;
}
}
.bot {
padding-top: 700px;
h1 {
font-size: 18px;
text-align: center;
}
}
}
.pdf-content {
position: relative;
.pdf-subtitle {
text-align: center;
text-indent: 0;
margin-bottom: 1em;
font-weight: bold;
}
h1 {
font-size: 20px;
}
h4 {
font-size: 16px;
text-indent: 34px;
}
p {
text-indent: 34px;
margin: 0 0 0.2em;
line-height: 1.6;
}
}
}
img {
width: 100px;
height: 100px;
}
table {
border-collapse: collapse;
width: 100%;
td {
border: 1px solid v-bind(border_color);
padding: 8px 12px;
font-size: 14px;
}
.title {
background: var(--el-fill-color-light);
width: 200px;
text-align: center;
}
}
p,
h1,
h2,
h3,
h4,
h5,
h6 {
margin-bottom: 1em;
margin-top: 1em;
}
.fixed_right {
position: fixed;
right: -29px;
top: 50%;
transform: translate(-50%, -50%);
color: #ffffff;
clip-path: polygon(
100% 0%,
100% 0%,
100% 0%,
100% 100%,
100% 100%,
100% 100%,
65% 85%,
65% 17%
);
width: 100px;
writing-mode: tb-rl;
padding: 50px 10px 50px 0;
background-color: var(--el-color-primary);
cursor: pointer;
font-size: 14px;
}
</style>

View File

@ -0,0 +1,76 @@
<template>
<el-dialog v-model="visible" title="分析" :before-close="fnClose">
<layout-risk-add v-model:form="form" :rules="rules" ref="riskAddRef">
<el-col :span="24">
<el-form-item label="是否生成新风险因素" prop="IS_NEW">
<el-radio-group v-model="form.IS_NEW" disabled>
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</layout-risk-add>
<template #footer>
<el-button @click="fnClose"></el-button>
<el-button type="primary" @click="fnSubmit"> </el-button>
</template>
</el-dialog>
</template>
<script setup>
import { useVModels } from "@vueuse/core";
import { debounce } from "throttle-debounce";
import { ElMessage } from "element-plus";
import LayoutRiskAdd from "@/components/risk_add/index.vue";
import { ref, watch } from "vue";
import { setHazardAnalysisSubmit } from "@/request/continuous_improvement.js";
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
form: {
type: Object,
required: true,
default: () => ({}),
},
});
const emits = defineEmits(["update:visible", "update:form", "get-data"]);
const { visible, form } = useVModels(props, emits);
const rules = {
IS_NEW: [{ required: true, message: "请选择", trigger: "change" }],
};
const riskAddRef = ref(null);
const fnClose = () => {
riskAddRef.value.reset();
visible.value = false;
};
const fnSubmit = debounce(
1000,
async () => {
await riskAddRef.value.formValidate();
await setHazardAnalysisSubmit({
STATUS: 0,
ACCIDENTS: form.value.ACCIDENTS.join(","),
ACCIDENTS_NAME: riskAddRef.value.accidentsName(),
...form.value,
});
ElMessage.success("操作成功");
fnClose();
emits("get-data");
},
{ atBegin: true }
);
watch(
() => props.form.IDENTIFICATION_ID,
(newValue, oldValue) => {
if (oldValue) {
form.value.IS_NEW = 1;
}
}
);
</script>
<style scoped lang="scss"></style>

View File

@ -124,11 +124,18 @@
>
查看
</el-button>
<el-button type="primary" text link> 分析 </el-button>
<el-button type="primary" text link @click="fnAnalysis(row)">
分析
</el-button>
</template>
</el-table-column>
</layout-table>
</layout-card>
<analysis
v-model:visible="data.analysisDialog.visible"
v-model:form="data.analysisDialog.form"
@get-data="fnResetPaginationTransfer"
/>
</div>
</template>
@ -139,6 +146,9 @@ import useListData from "@/assets/js/useListData.js";
import LayoutDepartment from "@/components/department/index.vue";
import { getHiddenDangerList } from "@/request/hidden_danger_government.js";
import { layoutFnGetHazardLevel } from "@/assets/js/data_dictionary.js";
import { nextTick, reactive } from "vue";
import Analysis from "./components/analysis.vue";
import { getRiskControlLedgerView } from "@/request/risk_control.js";
const stateList = [
{ NAME: "未整改", ID: "1" },
@ -152,6 +162,27 @@ const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getHiddenDangerList, {
otherParams: { STATE: 4, DISPOSESTATE: "-1", ANALYSIS: 1 },
});
const data = reactive({
analysisDialog: {
visible: false,
form: {
DEPARTMENT_ID: "",
USER_ID: "",
RISK_UNIT_ID: "",
IDENTIFICATION_ID: "",
RISK_DESCR: "",
LIKELIHOOD: "",
EXPOSURE: "",
CONSEQUENCE: "",
LEVEL_NAME: "",
DANGER: "",
MEASURES: "",
ACCIDENTS: [],
EME_MEASURES: "",
IS_NEW: 1,
},
},
});
const fnGetDataTransfer = () => {
fnGetData({
STARTTIME: searchForm.value.dates?.[0],
@ -167,6 +198,24 @@ const fnResetPaginationTransfer = () => {
});
};
const hazardLevelList = await layoutFnGetHazardLevel();
const fnAnalysis = async ({
HIDDEN_ID,
RISKPOINT_ID,
HIDDENDESCR,
RECTIFYDESCR,
}) => {
data.analysisDialog.visible = true;
await nextTick();
if (RISKPOINT_ID) {
const resData = await getRiskControlLedgerView({ RISKPOINT_ID });
resData.pd.IS_NEW = 0;
data.analysisDialog.form = resData.pd;
data.analysisDialog.form.ACCIDENTS = resData.pd.ACCIDENTS.split(",");
data.analysisDialog.form.RISK_DESCR += HIDDENDESCR;
data.analysisDialog.form.MEASURES += RECTIFYDESCR;
}
data.analysisDialog.form.HIDDEN_ID = HIDDEN_ID;
};
</script>
<style scoped></style>

View File

@ -0,0 +1,83 @@
<template>
<el-dialog v-model="visible" title="分析" :on-close="fnClose">
<layout-risk-view :info="info">
<el-descriptions-item label="是否生成新风险因素" :span="2">
{{ info.IS_NEW === 1 ? "是" : "否" }}
</el-descriptions-item>
<el-descriptions-item label="风险成因" :span="2">
<el-select v-model="riskCauses" placeholder="请选择">
<el-option
v-for="item in riskCausesList"
:key="item.DICTIONARIES_ID"
:label="item.NAME"
:value="item.DICTIONARIES_ID"
/>
</el-select>
</el-descriptions-item>
</layout-risk-view>
<template #footer>
<el-button type="primary" @click="fnSubmit(1)"></el-button>
<el-button type="danger" @click="fnSubmit(0)"></el-button>
<el-button @click="fnClose"></el-button>
</template>
</el-dialog>
</template>
<script setup>
import { useVModel } from "@vueuse/core";
import { ref } from "vue";
import { layoutFnGetRiskCauses } from "@/assets/js/data_dictionary.js";
import { debounce } from "throttle-debounce";
import {
setRiskAnalysisAdopt,
setRiskAnalysisRepulse,
} from "@/request/continuous_improvement.js";
import { ElMessage } from "element-plus";
import LayoutRiskView from "@/components/risk_view/index.vue";
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
info: {
type: Object,
required: true,
default: () => ({}),
},
});
const emits = defineEmits(["update:visible", "get-data"]);
const visible = useVModel(props, "visible", emits);
const riskCauses = ref("");
const riskCausesList = await layoutFnGetRiskCauses();
const fnClose = () => {
visible.value = false;
riskCauses.value = "";
};
const fnSubmit = debounce(
1000,
async (STATUS) => {
if (STATUS === 0) {
await setRiskAnalysisRepulse({
RISKPOINT_ANALYSIS_ID: props.info.RISKPOINT_ANALYSIS_ID,
});
} else {
if (!riskCauses.value) {
ElMessage.warning("风险成因未选择");
return;
}
await setRiskAnalysisAdopt({
RISKPOINT_ANALYSIS_ID: props.info.RISKPOINT_ANALYSIS_ID,
RISK_CAUSES: riskCauses.value,
});
}
ElMessage.success("操作成功");
fnClose();
emits("get-data");
},
{ atBegin: true }
);
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,189 @@
<template>
<div>
<el-card>
<el-form
:model="searchForm"
label-width="100px"
@submit.prevent="fnResetPaginationTransfer"
>
<el-row>
<el-col :span="6">
<el-form-item label="关键字" prop="KEYWORDS">
<el-input v-model="searchForm.KEYWORDS" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="风险分级" prop="LEVELID">
<el-select v-model="searchForm.LEVELID">
<el-option
v-for="item in riskClassificationList"
:key="item.BIANMA"
:label="item.NAME"
:value="item.BIANMA"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="部门" prop="DEPTIDS">
<layout-department
v-model="searchForm.DEPTIDS"
multiple
show-checkbox
collapse-tags
root-disabled="Y"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="事故类型">
<el-select v-model="searchForm.BIANMA" multiple>
<el-option
v-for="item in accidentTypeList"
:key="item.BIANMA"
:label="item.NAME"
:value="item.BIANMA"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="管控责任人" prop="gkzrName">
<el-input v-model="searchForm.gkzrName" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="是否审核" prop="STATUS">
<el-select v-model="searchForm.STATUS">
<el-option label="未审核" value="0" />
<el-option label="已审核" value="1" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label-width="10px">
<el-button type="primary" native-type="submit">搜索</el-button>
<el-button native-type="reset" @click="fnResetPaginationTransfer">
重置
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<layout-card>
<layout-table
:data="list"
@get-data="fnGetDataTransfer"
v-model:pagination="pagination"
>
<el-table-column label="序号" width="60">
<template #default="{ $index }">
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column prop="DEPT_NAME_ALL" label="管控部门" width="250" />
<el-table-column
prop="RISKUNITNAME"
label="风险点(单元)"
width="250"
/>
<el-table-column prop="PARTSNAME" label="辨识部位" width="250" />
<el-table-column prop="LEVELID" label="风险分级" width="120">
<template v-slot="{ row }">
<span v-if="row.LEVELID === 'levelD'" class="text-blue">
低风险/D级
</span>
<span v-else-if="row.LEVELID === 'levelC'" class="text-yellow">
一般风险/C级
</span>
<span v-else-if="row.LEVELID === 'levelB'" class="text-orange">
较大风险/B级
</span>
<span v-else-if="row.LEVELID === 'levelA'" class="text-red">
重大风险/A级
</span>
</template>
</el-table-column>
<el-table-column prop="ACCIDENTS_NAME" label="事故类型" />
<el-table-column prop="USER_ID" label="管控责任人" width="100" />
<el-table-column prop="STATUS" label="状态" width="90">
<template v-slot="{ row }">
{{ row.STATUS === 1 ? "已审核" : "未审核" }}
</template>
</el-table-column>
<el-table-column label="操作" width="100">
<template #default="{ row }">
<el-button
v-if="row.STATUS === 0"
type="primary"
text
link
@click="fnAnalysis(row)"
>
分析
</el-button>
</template>
</el-table-column>
</layout-table>
</layout-card>
<analysis
v-model:visible="data.analysisDialog.visible"
:info="data.analysisDialog.info"
@get-data="fnResetPaginationTransfer"
/>
</div>
</template>
<script setup>
import { serialNumber } from "@/assets/js/utils";
import useListData from "@/assets/js/useListData.js";
import LayoutDepartment from "@/components/department/index.vue";
import {
layoutFnGetAccidentType,
layoutFnGetRiskClassification,
} from "@/assets/js/data_dictionary.js";
import { reactive } from "vue";
import { getRiskAnalysisList } from "@/request/continuous_improvement.js";
import { useUserStore } from "@/pinia/user.js";
import { ElMessageBox } from "element-plus";
import { cloneDeep } from "lodash-es";
import Analysis from "./components/analysis.vue";
const userStore = useUserStore();
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getRiskAnalysisList);
const data = reactive({
analysisDialog: {
visible: false,
info: {},
},
});
const fnGetDataTransfer = () => {
fnGetData({
DEPTIDS: searchForm.value.DEPTIDS?.join(","),
BIANMA: searchForm.value.BIANMA?.join(","),
});
};
const fnResetPaginationTransfer = () => {
fnResetPagination({
DEPTIDS: searchForm.value.DEPTIDS?.join(","),
BIANMA: searchForm.value.BIANMA?.join(","),
});
};
const riskClassificationList = await layoutFnGetRiskClassification();
const accidentTypeList = await layoutFnGetAccidentType();
const fnAnalysis = (row) => {
if (
userStore.getUserInfo.ISMAIN === "1" ||
userStore.getUserInfo.IS_SAFETY === 1
) {
data.analysisDialog.visible = true;
data.analysisDialog.info = cloneDeep(row);
} else {
ElMessageBox.alert("您无权进行此项操作");
}
};
</script>
<style scoped></style>

View File

@ -0,0 +1,37 @@
<template>
<el-dialog v-model="visible" title="查看">
<layout-risk-view :info="info">
<el-descriptions-item label="是否生成新风险因素" :span="2">
{{ info.IS_NEW === 1 ? "是" : "否" }}
</el-descriptions-item>
<el-descriptions-item label="风险成因" :span="2">
{{ info.RISK_CAUSES }}
</el-descriptions-item>
</layout-risk-view>
<template #footer>
<el-button @click="visible = false">关闭</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { useVModel } from "@vueuse/core";
import LayoutRiskView from "@/components/risk_view/index.vue";
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
info: {
type: Object,
required: true,
default: () => ({}),
},
});
const emits = defineEmits(["update:visible"]);
const visible = useVModel(props, "visible", emits);
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,165 @@
<template>
<div>
<el-card>
<el-form
:model="searchForm"
label-width="100px"
@submit.prevent="fnResetPagination"
>
<el-row>
<el-col :span="6">
<el-form-item label="关键字" prop="KEYWORDS">
<el-input v-model="searchForm.KEYWORDS" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="风险点" prop="RISK_UNIT_ID">
<el-select
v-model="searchForm.RISK_UNIT_ID"
@change="fnGetPartsList"
>
<el-option
v-for="item in data.unitList"
:key="item.RISKUNIT_ID"
:label="item.DEPT_NAME + '-' + item.RISKUNITNAME"
:value="item.RISKUNIT_ID"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="辨识部位" prop="IDENTIFICATION_ID">
<el-select v-model="searchForm.IDENTIFICATION_ID">
<el-option
v-for="item in data.partsList"
:key="item.IDENTIFICATIONPARTS_ID"
:label="item.PARTSNAME"
:value="item.IDENTIFICATIONPARTS_ID"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label-width="10px">
<el-button type="primary" native-type="submit">搜索</el-button>
<el-button native-type="reset" @click="fnResetPagination">
重置
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<layout-card>
<layout-table
:data="list"
@get-data="fnGetData"
v-model:pagination="pagination"
:span-method="fnSpanMethod"
>
<el-table-column
fixed
prop="risk_unit_name"
label="风险点(单元)"
width="200px"
/>
<el-table-column prop="parts_name" label="辨识部位" width="200px" />
<el-table-column prop="is_new" label="改进类型" width="80" />
<el-table-column prop="label" label="持续改进" width="100" />
<el-table-column
prop="risk_causes_name"
label="风险成因"
width="150px"
/>
<el-table-column prop="risk_descr" label="存在风险" width="500px" />
<el-table-column prop="dname5" label="风险等级" width="100" />
<el-table-column prop="measures" label="管控措施" width="500px" />
<el-table-column prop="accidents_name" label="事故类型" width="300px" />
<el-table-column prop="dept_name_all" label="责任部门" width="150px" />
<el-table-column label="责任人" width="150px">
<template v-slot="{ row }">
{{ row.dept_user_name ? row.dept_user_name : row.user_id }}
</template>
</el-table-column>
<el-table-column prop="creat_time" label="分析时间" width="150px" />
<el-table-column prop="creator_name" label="分析人员" width="150px" />
<el-table-column prop="inspector_name" label="审批人员" width="150px" />
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
<el-button type="primary" text link @click="fnView(row)">
查看最新信息
</el-button>
</template>
</el-table-column>
</layout-table>
</layout-card>
<view-info
v-model:visible="data.viewDialog.visible"
:info="data.viewDialog.info"
/>
</div>
</template>
<script setup>
import useListData from "@/assets/js/useListData.js";
import { reactive } from "vue";
import {
getRiskAnalysisRecordList,
getRiskAnalysisRecordView,
} from "@/request/continuous_improvement.js";
import {
getIdentifyingPartsListAll,
getRiskPointListAllById,
} from "@/request/risk_control.js";
import ViewInfo from "./components/view.vue";
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getRiskAnalysisRecordList, { key: "list" });
const data = reactive({
unitList: [],
partsList: [],
viewDialog: {
visible: false,
info: {},
},
});
const fnGetUnitList = async () => {
const resData = await getRiskPointListAllById({
DEPARTMENT_ID: "",
});
data.unitList = resData.unitList;
};
const fnGetPartsList = async () => {
searchForm.value.IDENTIFICATION_ID = "";
const resData = await getIdentifyingPartsListAll({
RISK_UNIT_ID: searchForm.value.RISK_UNIT_ID,
});
data.partsList = resData.partsList;
};
fnGetUnitList();
const fnView = async (row) => {
const resData = await getRiskAnalysisRecordView({
RISKPOINT_ANALYSIS_ID: row.riskpoint_analysis_id,
});
data.viewDialog.visible = true;
data.viewDialog.info = resData.form;
};
const fnSpanMethod = ({ rowIndex, columnIndex }) => {
const arr = [0, 1, 2, 14];
if (arr.includes(columnIndex)) {
if (rowIndex % 2 === 0) {
return {
rowspan: 2,
colspan: 1,
};
} else {
return {
rowspan: 0,
colspan: 0,
};
}
}
};
</script>
<style scoped></style>

View File

@ -110,44 +110,48 @@
</layout-table>
</div>
<table class="print_use">
<tr>
<th width="55">序号</th>
<th width="125">风险点单元</th>
<th width="100">辨识部位</th>
<th>存在风险</th>
<th width="120">风险分级</th>
<th>检查内容</th>
<th width="100">状态</th>
</tr>
<tr v-for="(item, index) in inspectionList" :key="index">
<td>{{ index + 1 }}</td>
<td>{{ item.RISKUNITNAME }}</td>
<td>{{ item.PARTSNAME }}</td>
<td>{{ item.RISK_DESCR }}</td>
<td>{{ item.LEVEL_NAME }}</td>
<td>{{ item.CHECK_CONTENT }}</td>
<template v-if="item.ISNORMAL === 0">
<template v-if="item.IMGCOUNT > 0">
<thead>
<tr>
<th width="55">序号</th>
<th width="125">风险点单元</th>
<th width="100">辨识部位</th>
<th>存在风险</th>
<th width="120">风险分级</th>
<th>检查内容</th>
<th width="100">状态</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in inspectionList" :key="index">
<td>{{ index + 1 }}</td>
<td>{{ item.RISKUNITNAME }}</td>
<td>{{ item.PARTSNAME }}</td>
<td>{{ item.RISK_DESCR }}</td>
<td>{{ item.LEVEL_NAME }}</td>
<td>{{ item.CHECK_CONTENT }}</td>
<template v-if="item.ISNORMAL === 0">
<template v-if="item.IMGCOUNT > 0">
<td>
<el-button type="primary" text link> 合格 </el-button>
</td>
</template>
<template v-else>
<td>合格</td>
</template>
</template>
<template v-else-if="item.ISNORMAL === 1">
<td>
<el-button type="primary" text link> 合格 </el-button>
<el-button type="primary" text link> 合格 </el-button>
</td>
</template>
<template v-else>
<td>合格</td>
<template v-else-if="item.ISNORMAL === 2">
<td>不涉及</td>
</template>
</template>
<template v-else-if="item.ISNORMAL === 1">
<td>
<el-button type="primary" text link> 不合格 </el-button>
</td>
</template>
<template v-else-if="item.ISNORMAL === 2">
<td>不涉及</td>
</template>
<template v-else>
<td>存在未整改隐患</td>
</template>
</tr>
<template v-else>
<td>存在未整改隐患</td>
</template>
</tr>
</tbody>
</table>
<el-divider content-position="left">其他隐患</el-divider>
<div class="print_no_use">
@ -174,14 +178,18 @@
</layout-table>
</div>
<table class="print_use">
<tr>
<th width="55">序号</th>
<th>隐患描述</th>
</tr>
<tr v-for="(item, index) in otherHiddenList" :key="index">
<td>{{ index + 1 }}</td>
<td>{{ item.HIDDENDESCR }}</td>
</tr>
<thead>
<tr>
<th width="55">序号</th>
<th>隐患描述</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in otherHiddenList" :key="index">
<td>{{ index + 1 }}</td>
<td>{{ item.HIDDENDESCR }}</td>
</tr>
</tbody>
</table>
<qualified
v-model:visible="data.qualifiedDialog.visible"

View File

@ -343,7 +343,7 @@ const fnGetData = async () => {
data.form = resData.pd;
data.form.dates = [resData.pd.START_DATE, resData.pd.END_DATE];
data.list = resData.varList;
data.listAll = resData.varList;
data.listAll = [...resData.varList];
};
fnGetData();
const fnGetInspectionItems = async () => {
@ -389,7 +389,7 @@ const fnGetDataFilter = () => {
item.USERNAME?.indexOf(keyword) > -1
);
} else {
data.list = data.listAll;
data.list = [...data.listAll];
}
fnTableSelection();
};

View File

@ -476,7 +476,7 @@ watch(
}
);
const fnChoice = (item) => {
data.RECTIFYDESCR = item.RECTIFYDESCR;
data.form.RECTIFYDESCR = item.RECTIFYDESCR;
};
const fnSubmit = debounce(
1000,

View File

@ -8,7 +8,7 @@
>
<el-row>
<el-col :span="6">
<el-form-item label="关键字搜索" prop="KEYWORDS">
<el-form-item label="关键字" prop="KEYWORDS">
<el-input v-model="searchForm.KEYWORDS" />
</el-form-item>
</el-col>

View File

@ -0,0 +1,122 @@
<template>
<div>
<el-card>
<el-form
:model="searchForm"
label-width="70px"
@submit.prevent="fnResetPaginationTransfer"
>
<el-row>
<el-col :span="6">
<el-form-item label="关键字" prop="KEYWORDS">
<el-input
v-model="searchForm.KEYWORDS"
placeholder="请输入关键字"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="部门" prop="DEPTIDS">
<layout-department
v-model="searchForm.DEPTIDS"
multiple
show-checkbox
collapse-tags
root-disabled="Y"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="时间" prop="dates">
<el-date-picker
v-model="searchForm.dates"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
/>
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label-width="10px">
<el-button type="primary" native-type="submit">搜索</el-button>
<el-button native-type="reset" @click="fnResetPaginationTransfer">
重置
</el-button>
</el-form-item>
</el-col>
<el-col :span="2">
<el-form-item label-width="10px" class="end">
<el-button
@click="
router.push({
path: '/statistical_analysis/detection_situation/print',
query: {
STARTTIME: searchForm.dates?.[0],
ENDTIME: searchForm.dates?.[1],
DEPTIDS: searchForm.DEPTIDS?.join(','),
},
})
"
>
打印
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<layout-card>
<layout-table :data="list" :show-pagination="false">
<el-table-column label="序号" width="70">
<template v-slot="{ $index }">
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column prop="DEPARTNAME_ALL" label="部门" />
<el-table-column prop="POSTNAME" label="岗位" />
<el-table-column prop="USERNAME" label="姓名" />
<el-table-column prop="listCount" label="负责清单数" />
<el-table-column prop="staCount" label="应检查清单次数" />
<el-table-column prop="cheCount" label="实际检查次数" />
<el-table-column prop="percent" label="检查率" />
</layout-table>
</layout-card>
</div>
</template>
<script setup>
import LayoutDepartment from "@/components/department/index.vue";
import { serialNumber } from "@/assets/js/utils.js";
import useListData from "@/assets/js/useListData.js";
import {
getDetectionSituationList,
getDetectionSituationListTime,
} from "@/request/statistical_analysis.js";
import { useRouter } from "vue-router";
const router = useRouter();
const { list, searchForm, pagination, fnResetPagination } = useListData(
getDetectionSituationList,
{
immediate: false,
}
);
const fnResetPaginationTransfer = () => {
fnResetPagination({
STARTTIME: searchForm.value.dates?.[0],
ENDTIME: searchForm.value.dates?.[1],
DEPTIDS: searchForm.value.DEPTIDS?.join(","),
});
};
const fnGetData = async () => {
const resData = await getDetectionSituationListTime();
searchForm.value.dates = [resData.pd.MINTIME, resData.pd.MAXTIME];
fnResetPaginationTransfer();
};
fnGetData();
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,62 @@
<template>
<layout-card>
<div id="printContent">
<el-divider content-position="left">员工日常检测情况</el-divider>
<div class="print_no_use">
<layout-table :data="list" :show-pagination="false">
<el-table-column label="序号" width="70" type="index" />
<el-table-column prop="DEPARTNAME_ALL" label="部门" />
<el-table-column prop="POSTNAME" label="岗位" />
<el-table-column prop="USERNAME" label="姓名" />
<el-table-column prop="listCount" label="负责清单数" />
<el-table-column prop="staCount" label="应检查清单次数" />
<el-table-column prop="cheCount" label="实际检查次数" />
<el-table-column prop="percent" label="检查率" />
</layout-table>
</div>
<table class="print_use">
<thead>
<tr>
<th width="55">序号</th>
<th>部门</th>
<th>岗位</th>
<th>姓名</th>
<th>负责清单数</th>
<th>应检查清单次数</th>
<th>实际检查次数</th>
<th>检查率</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in list" :key="index">
<td>{{ index + 1 }}</td>
<td>{{ item.DEPARTNAME_ALL }}</td>
<td>{{ item.POSTNAME }}</td>
<td>{{ item.USERNAME }}</td>
<td>{{ item.listCount }}</td>
<td>{{ item.staCount }}</td>
<td>{{ item.cheCount }}</td>
<td>{{ item.percent }}</td>
</tr>
</tbody>
</table>
</div>
<div class="tc mt-10">
<el-button type="primary" v-print="'#printContent'"></el-button>
</div>
</layout-card>
</template>
<script setup>
import useListData from "@/assets/js/useListData.js";
import { getDetectionSituationList } from "@/request/statistical_analysis.js";
import { useRoute } from "vue-router";
const route = useRoute();
const { STARTTIME, ENDTIME, DEPTIDS } = route.query;
const { list } = useListData(getDetectionSituationList, {
otherParams: { showCount: 10000, STARTTIME, ENDTIME, DEPTIDS },
});
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,184 @@
<template>
<div>
<el-card>
<el-form
:model="searchForm"
label-width="100px"
@submit.prevent="fnGetDataTransfer"
>
<el-row>
<el-col :span="5">
<el-form-item label="隐患级别" prop="checkedCities">
<el-checkbox-group
v-model="searchForm.checkedCities"
:disabled="searchForm.statecheckedCities.length > 0"
>
<el-checkbox
v-for="item in hazardLevelList"
:label="item"
:key="item.BIANMA"
>
{{ item.NAME }}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item label="隐患状态" prop="statecheckedCities">
<el-checkbox-group
v-model="searchForm.statecheckedCities"
:disabled="searchForm.checkedCities.length > 0"
>
<el-checkbox
v-for="item in hazardStateList"
:label="item"
:key="item.id"
>
{{ item.name }}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="5">
<el-form-item label="部门" prop="checkedIds">
<layout-department
v-model="searchForm.checkedIds"
show-checkbox
multiple
collapse-tags
root-disabled="Y"
@update:model-value="fnDepartmentChange"
/>
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item label="发现日期" prop="dates">
<el-date-picker
v-model="searchForm.dates"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label-width="10px">
<el-button type="primary" native-type="submit">搜索</el-button>
<el-button
native-type="reset"
@click="
list = [];
resultList = [];
"
>
重置
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<layout-card v-if="list.length > 0">
<layout-table
:data="list"
row-key="DEPARTMENT_ID"
:show-pagination="false"
default-expand-all
>
<el-table-column label="序号" type="index" />
<template v-for="item in resultList" :key="item.dataItem">
<el-table-column
:show-overflow-tooltip="true"
:prop="item.dataItem"
:label="item.dataName"
/>
</template>
</layout-table>
</layout-card>
</div>
</template>
<script setup>
import useListData from "@/assets/js/useListData.js";
import { getHazardStatisticsList } from "@/request/statistical_analysis.js";
import { layoutFnGetHazardLevel } from "@/assets/js/data_dictionary.js";
import layoutDepartment from "@/components/department/index.vue";
import { ref } from "vue";
import { ElMessage } from "element-plus";
import { useUserStore } from "@/pinia/user.js";
const hazardStateList = [
{ id: "1", name: "未整改" },
{ id: "3", name: "待验收" },
{ id: "4", name: "已验收" },
{ id: "-1", name: "已过期" },
];
const userStore = useUserStore();
const resultList = ref([]);
const { list, searchForm, fnGetData } = useListData(getHazardStatisticsList, {
otherParams: {
DISPOSESTATE: "2",
},
usePagination: false,
immediate: false,
defaultSearchForm: {
checkedCities: [],
statecheckedCities: [],
hiddentypecheckedCities: [],
checkedIds: [],
dates: [],
},
callbackFn: (list, resData) => {
resultList.value = resData.retultlist;
},
});
const hazardLevelList = await layoutFnGetHazardLevel();
const fnGetDataTransfer = () => {
if (
searchForm.value.checkedCities?.length > 0 ||
searchForm.value.statecheckedCities?.length > 0
) {
fnGetData({
STARTTIME: searchForm.value.dates[0],
ENDTIME: searchForm.value.dates[1],
checkedCities: JSON.stringify(searchForm.value.checkedCities),
statecheckedCities: JSON.stringify(searchForm.value.statecheckedCities),
hiddentypecheckedCities: JSON.stringify(
searchForm.value.hiddentypecheckedCities
),
checkedIds: JSON.stringify(searchForm.value.checkedIds),
});
} else {
ElMessage.warning("请选择统计项");
}
};
const fnDepartmentChange = () => {
const DEPARTMENT_ID = userStore.getUserInfo.DEPARTMENT_ID;
if (
searchForm.value.checkedIds.length === 1 &&
searchForm.value.checkedIds[0] === DEPARTMENT_ID
) {
searchForm.value.checkedIds = [];
return;
}
if (searchForm.value.checkedIds.length > 0) {
if (searchForm.value.checkedIds.includes(DEPARTMENT_ID)) return;
searchForm.value.checkedIds.unshift(DEPARTMENT_ID);
}
};
</script>
<style scoped lang="scss">
:deep {
.el-table__row {
.el-table__cell:nth-child(2) {
text-align: left !important;
}
}
}
</style>

View File

@ -0,0 +1,138 @@
<template>
<div>
<el-card>
<el-form
:model="searchForm"
label-width="70px"
@submit.prevent="fnResetPaginationTransfer"
>
<el-row>
<el-col :span="5">
<el-form-item label="姓名" prop="KEYWORDS">
<el-input
v-model="searchForm.KEYWORDS"
placeholder="请输入关键字"
/>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="部门" prop="DEPTIDS">
<layout-department
v-model="searchForm.DEPTIDS"
multiple
show-checkbox
collapse-tags
root-disabled="Y"
/>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="时间" prop="TIME">
<el-date-picker
v-model="searchForm.TIME"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
type="date"
placeholder="选择查询日期"
/>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="登录情况" label-width="80px">
<el-select v-model="searchForm.STATE">
<el-option label="已登录" value="1" />
<el-option label="未登录" value="2" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label-width="10px">
<el-button type="primary" native-type="submit">搜索</el-button>
<el-button native-type="reset" @click="fnResetPaginationTransfer">
重置
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<layout-card>
<div class="mb-10" style="display: flex">
<div>
部门共有<span class="text-red"> {{ list.length }} </span>
</div>
<div>
登录<span class="text-red"> {{ loginNum }} </span>
</div>
<div>
登录率<span class="text-red"> {{ achieving }}% </span>
</div>
<div>
共有清单<span class="text-red"> {{ listNoCheckNum }} </span>
</div>
<div>
已检查<span class="text-red"> {{ listCheckedNum }} </span>
</div>
<div>
检查率<span class="text-red"> {{ checkTheRate }}% </span>
</div>
</div>
<layout-table :data="list" :show-pagination="false">
<el-table-column label="序号" width="70">
<template v-slot="{ $index }">
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column prop="DEPARTMENTNAME_ALL" label="部门" />
<el-table-column prop="POSTNAME" label="岗位" />
<el-table-column prop="USERNAME" label="姓名" />
<el-table-column prop="NOTEXAMINEDNUM" label="待排查清单数" />
<el-table-column prop="INSPECTEDNUM" label="已排查清单数" />
<el-table-column prop="PERCENT" label="排查率" />
<el-table-column label="登录情况">
<template v-slot="{ row }">
{{ row.ISLOGIN > 0 ? "已登录" : "未登录" }}
</template>
</el-table-column>
</layout-table>
</layout-card>
</div>
</template>
<script setup>
import LayoutDepartment from "@/components/department/index.vue";
import { serialNumber } from "@/assets/js/utils.js";
import useListData from "@/assets/js/useListData.js";
import { getUsageSituationList } from "@/request/statistical_analysis.js";
import { ref } from "vue";
import dayjs from "dayjs";
const loginNum = ref(0);
const achieving = ref(0);
const listNoCheckNum = ref(0);
const listCheckedNum = ref(0);
const checkTheRate = ref(0);
const { list, searchForm, pagination, fnResetPagination } = useListData(
getUsageSituationList,
{
defaultSearchForm: {
TIME: dayjs().format("YYYY-MM-DD"),
},
usePagination: false,
callbackFn: (list, resData) => {
achieving.value = resData.achieving;
checkTheRate.value = resData.checkTheRate;
listCheckedNum.value = resData.listCheckedNum;
listNoCheckNum.value = resData.listNoCheckNum;
loginNum.value = resData.loginNum;
},
}
);
const fnResetPaginationTransfer = () => {
fnResetPagination({
DEPTIDS: searchForm.value.DEPTIDS?.join(","),
});
};
</script>
<style scoped lang="scss"></style>