|
@@ -1,6 +1,11 @@
|
|
|
<script lang="ts" setup>
|
|
<script lang="ts" setup>
|
|
|
import { QhseMonthReportApi } from '@/api/pms/qhse'
|
|
import { QhseMonthReportApi } from '@/api/pms/qhse'
|
|
|
-import type { QhseMonthReportItem, ReportMetricRow } from './types'
|
|
|
|
|
|
|
+import type {
|
|
|
|
|
+ QhseMonthReportItem,
|
|
|
|
|
+ ReportCompanyColumn,
|
|
|
|
|
+ ReportMetricRow,
|
|
|
|
|
+ ReportMetricValue
|
|
|
|
|
+} from './types'
|
|
|
import dayjs from 'dayjs'
|
|
import dayjs from 'dayjs'
|
|
|
|
|
|
|
|
interface Props {
|
|
interface Props {
|
|
@@ -14,6 +19,16 @@ const emits = defineEmits(['update:visible'])
|
|
|
const loading = ref(false)
|
|
const loading = ref(false)
|
|
|
const report = ref<QhseMonthReportItem>()
|
|
const report = ref<QhseMonthReportItem>()
|
|
|
|
|
|
|
|
|
|
+const companyColumns: ReportCompanyColumn[] = [
|
|
|
|
|
+ { key: 'rhxy', label: '瑞恒兴域' },
|
|
|
|
|
+ { key: 'scrd', label: '四川瑞都' },
|
|
|
|
|
+ { key: 'sxty', label: '陕西瑞鹰' },
|
|
|
|
|
+ { key: 'eys', label: '俄油服' },
|
|
|
|
|
+ { key: 'rqny', label: '瑞气能源' },
|
|
|
|
|
+ { key: 'rljs', label: '瑞霖技术' },
|
|
|
|
|
+ { key: 'bjhq', label: '北京总部' }
|
|
|
|
|
+]
|
|
|
|
|
+
|
|
|
const metricRows: ReportMetricRow[] = [
|
|
const metricRows: ReportMetricRow[] = [
|
|
|
{ category: '人工时与里程', label: '员工人数', field: 'employee', unit: '人' },
|
|
{ category: '人工时与里程', label: '员工人数', field: 'employee', unit: '人' },
|
|
|
{ category: '人工时与里程', label: '分包商人数', field: 'subcontractors', unit: '人' },
|
|
{ category: '人工时与里程', label: '分包商人数', field: 'subcontractors', unit: '人' },
|
|
@@ -69,6 +84,56 @@ const firstRowIndexByCategory = computed(() => {
|
|
|
}, {})
|
|
}, {})
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
|
|
+const mockMetricValueMap = computed<Record<string, Record<string, ReportMetricValue>>>(() => ({
|
|
|
|
|
+ employee: { rhxy: 32, scrd: 28, sxty: 25, eys: 18, rqny: 20, rljs: 14, bjhq: 12 },
|
|
|
|
|
+ subcontractors: { rhxy: 15, scrd: 12, sxty: 9, eys: 7, rqny: 6, rljs: 5, bjhq: 0 },
|
|
|
|
|
+ drivingMileage: {
|
|
|
|
|
+ rhxy: 12680.5,
|
|
|
|
|
+ scrd: 11024.2,
|
|
|
|
|
+ sxty: 9480.8,
|
|
|
|
|
+ eys: 6855.6,
|
|
|
|
|
+ rqny: 7742.4,
|
|
|
|
|
+ rljs: 4136.5,
|
|
|
|
|
+ bjhq: 980.2
|
|
|
|
|
+ },
|
|
|
|
|
+ totalManHours: { rhxy: 3824, scrd: 3416, sxty: 2988, eys: 2210, rqny: 2456, rljs: 1768, bjhq: 960 },
|
|
|
|
|
+ withoutAccident: { rhxy: 186, scrd: 186, sxty: 186, eys: 132, rqny: 186, rljs: 186, bjhq: 186 },
|
|
|
|
|
+ fatality: { rhxy: 0, scrd: 0, sxty: 0, eys: 0, rqny: 0, rljs: 0, bjhq: 0 },
|
|
|
|
|
+ injury: { rhxy: 0, scrd: 1, sxty: 0, eys: 0, rqny: 0, rljs: 0, bjhq: 0 },
|
|
|
|
|
+ restrictedCase: { rhxy: 1, scrd: 0, sxty: 0, eys: 0, rqny: 1, rljs: 0, bjhq: 0 },
|
|
|
|
|
+ medicalCase: { rhxy: 1, scrd: 1, sxty: 0, eys: 0, rqny: 0, rljs: 0, bjhq: 0 },
|
|
|
|
|
+ firstAidCase: { rhxy: 2, scrd: 1, sxty: 1, eys: 0, rqny: 1, rljs: 0, bjhq: 0 },
|
|
|
|
|
+ vehicleAccident: { rhxy: 0, scrd: 0, sxty: 0, eys: 1, rqny: 0, rljs: 0, bjhq: 0 },
|
|
|
|
|
+ nearMiss: { rhxy: 3, scrd: 2, sxty: 1, eys: 1, rqny: 2, rljs: 1, bjhq: 0 },
|
|
|
|
|
+ spill: { rhxy: 0, scrd: 0, sxty: 0, eys: 0, rqny: 1, rljs: 0, bjhq: 0 },
|
|
|
|
|
+ lifeSavingRules: { rhxy: 0, scrd: 1, sxty: 0, eys: 0, rqny: 0, rljs: 0, bjhq: 0 },
|
|
|
|
|
+ toolboxTalk: { rhxy: 28, scrd: 24, sxty: 22, eys: 18, rqny: 20, rljs: 16, bjhq: 6 },
|
|
|
|
|
+ committeeMeeting: { rhxy: 1, scrd: 1, sxty: 1, eys: 1, rqny: 1, rljs: 1, bjhq: 1 },
|
|
|
|
|
+ monthlyMeeting: { rhxy: 1, scrd: 1, sxty: 1, eys: 1, rqny: 1, rljs: 1, bjhq: 1 },
|
|
|
|
|
+ companyHazard: { rhxy: 6, scrd: 5, sxty: 4, eys: 3, rqny: 4, rljs: 2, bjhq: 1 },
|
|
|
|
|
+ qhseInspection: { rhxy: 10, scrd: 9, sxty: 8, eys: 6, rqny: 7, rljs: 5, bjhq: 3 },
|
|
|
|
|
+ socCards: { rhxy: 42, scrd: 38, sxty: 31, eys: 22, rqny: 27, rljs: 18, bjhq: 12 },
|
|
|
|
|
+ ptwAudit: { rhxy: 18, scrd: 15, sxty: 13, eys: 8, rqny: 9, rljs: 6, bjhq: 2 },
|
|
|
|
|
+ jsa: { rhxy: 21, scrd: 18, sxty: 16, eys: 10, rqny: 12, rljs: 8, bjhq: 3 },
|
|
|
|
|
+ drills: { rhxy: 2, scrd: 2, sxty: 1, eys: 1, rqny: 1, rljs: 1, bjhq: 1 },
|
|
|
|
|
+ training: { rhxy: 5, scrd: 4, sxty: 4, eys: 3, rqny: 3, rljs: 2, bjhq: 2 },
|
|
|
|
|
+ participantsTraining: { rhxy: 96, scrd: 82, sxty: 74, eys: 48, rqny: 56, rljs: 35, bjhq: 24 },
|
|
|
|
|
+ trainingsHours: { rhxy: 64, scrd: 56, sxty: 48, eys: 32, rqny: 36, rljs: 24, bjhq: 16 },
|
|
|
|
|
+ waterConsumption: { rhxy: 82.5, scrd: 74.2, sxty: 65.8, eys: 48.6, rqny: 53.4, rljs: 31.8, bjhq: 12.2 },
|
|
|
|
|
+ dieselConsumption: { rhxy: 2680, scrd: 2410, sxty: 2085, eys: 1530, rqny: 1695, rljs: 980, bjhq: 220 },
|
|
|
|
|
+ electricityConsumption: { rhxy: 4250, scrd: 3980, sxty: 3650, eys: 2420, rqny: 2860, rljs: 1680, bjhq: 920 },
|
|
|
|
|
+ naturalGasConsumption: { rhxy: 1260, scrd: 1140, sxty: 980, eys: 660, rqny: 720, rljs: 450, bjhq: 180 },
|
|
|
|
|
+ remark: {
|
|
|
|
|
+ rhxy: '现场管理平稳',
|
|
|
|
|
+ scrd: '专项培训已完成',
|
|
|
|
|
+ sxty: '持续推进隐患整改',
|
|
|
|
|
+ eys: '强化车辆安全检查',
|
|
|
|
|
+ rqny: '开展环保专项复盘',
|
|
|
|
|
+ rljs: '重点盯控作业许可',
|
|
|
|
|
+ bjhq: '推进体系宣贯'
|
|
|
|
|
+ }
|
|
|
|
|
+}))
|
|
|
|
|
+
|
|
|
async function loadDetail(id: number) {
|
|
async function loadDetail(id: number) {
|
|
|
loading.value = true
|
|
loading.value = true
|
|
|
try {
|
|
try {
|
|
@@ -96,6 +161,31 @@ function formatDisplayValue(field: keyof QhseMonthReportItem) {
|
|
|
return String(value)
|
|
return String(value)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+function getMetricCompanyValue(field: keyof QhseMonthReportItem, companyKey: string) {
|
|
|
|
|
+ const rowData = mockMetricValueMap.value[String(field)] || {}
|
|
|
|
|
+ const value = rowData[companyKey]
|
|
|
|
|
+
|
|
|
|
|
+ if (value === undefined || value === null || value === '') return '-'
|
|
|
|
|
+ if (typeof value === 'number' && !Number.isInteger(value)) return value.toFixed(2)
|
|
|
|
|
+ return String(value)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function getMetricSummaryValue(field: keyof QhseMonthReportItem) {
|
|
|
|
|
+ const rowData = mockMetricValueMap.value[String(field)] || {}
|
|
|
|
|
+ const values = companyColumns
|
|
|
|
|
+ .map((company) => rowData[company.key])
|
|
|
|
|
+ .filter((value) => value !== undefined && value !== null && value !== '')
|
|
|
|
|
+
|
|
|
|
|
+ if (!values.length) return '-'
|
|
|
|
|
+
|
|
|
|
|
+ if (values.every((value) => typeof value === 'number')) {
|
|
|
|
|
+ const total = values.reduce((sum, value) => sum + Number(value), 0)
|
|
|
|
|
+ return Number.isInteger(total) ? String(total) : total.toFixed(2)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return values.map((value) => String(value)).join(';')
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
watch(
|
|
watch(
|
|
|
() => [props.visible, props.id] as const,
|
|
() => [props.visible, props.id] as const,
|
|
|
([visible, id]) => {
|
|
([visible, id]) => {
|
|
@@ -136,14 +226,9 @@ watch(
|
|
|
<thead>
|
|
<thead>
|
|
|
<tr>
|
|
<tr>
|
|
|
<th class="is-sticky-col">基本信息</th>
|
|
<th class="is-sticky-col">基本信息</th>
|
|
|
|
|
+ <th>指标项</th>
|
|
|
<th>单位</th>
|
|
<th>单位</th>
|
|
|
- <th>瑞恒兴域</th>
|
|
|
|
|
- <th>四川瑞都</th>
|
|
|
|
|
- <th>陕西瑞鹰</th>
|
|
|
|
|
- <th>俄油服</th>
|
|
|
|
|
- <th>瑞气能源</th>
|
|
|
|
|
- <th>瑞霖技术</th>
|
|
|
|
|
- <th>北京总部</th>
|
|
|
|
|
|
|
+ <th v-for="company in companyColumns" :key="company.key">{{ company.label }}</th>
|
|
|
<th>汇总</th>
|
|
<th>汇总</th>
|
|
|
</tr>
|
|
</tr>
|
|
|
</thead>
|
|
</thead>
|
|
@@ -157,7 +242,13 @@ watch(
|
|
|
</th>
|
|
</th>
|
|
|
<th class="is-label">{{ row.label }}</th>
|
|
<th class="is-label">{{ row.label }}</th>
|
|
|
<td>{{ row.unit }}</td>
|
|
<td>{{ row.unit }}</td>
|
|
|
- <td class="is-value">{{ formatDisplayValue(row.field) }}</td>
|
|
|
|
|
|
|
+ <td
|
|
|
|
|
+ v-for="company in companyColumns"
|
|
|
|
|
+ :key="`${row.field}-${company.key}`"
|
|
|
|
|
+ class="is-value">
|
|
|
|
|
+ {{ getMetricCompanyValue(row.field, company.key) }}
|
|
|
|
|
+ </td>
|
|
|
|
|
+ <td class="is-summary">{{ getMetricSummaryValue(row.field) }}</td>
|
|
|
</tr>
|
|
</tr>
|
|
|
</tbody>
|
|
</tbody>
|
|
|
</table>
|
|
</table>
|
|
@@ -282,6 +373,12 @@ watch(
|
|
|
color: #0f3f8f;
|
|
color: #0f3f8f;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+.is-summary {
|
|
|
|
|
+ background: #eef4ff !important;
|
|
|
|
|
+ font-weight: 700;
|
|
|
|
|
+ color: #14346b;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
@media (width < 768px) {
|
|
@media (width < 768px) {
|
|
|
.qhse-report-preview {
|
|
.qhse-report-preview {
|
|
|
padding: 12px;
|
|
padding: 12px;
|