From 7354f8e5dbb2a3e0612aebf94ad92513a418ea2c Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期四, 21 五月 2026 17:01:53 +0800
Subject: [PATCH] 浪潮 1.安环管理前端四个页面构建开发
---
src/views/safetyManagement/basicInfo/index.vue | 203 +++++++++++++++
src/views/safetyManagement/employeeLearning/index.vue | 165 ++++++++++++
src/views/safetyManagement/trainingManage/index.vue | 135 ++++++++++
src/views/safetyManagement/inspectionReport/index.vue | 233 +++++++++++++++++
4 files changed, 736 insertions(+), 0 deletions(-)
diff --git a/src/views/safetyManagement/basicInfo/index.vue b/src/views/safetyManagement/basicInfo/index.vue
new file mode 100644
index 0000000..ce0160e
--- /dev/null
+++ b/src/views/safetyManagement/basicInfo/index.vue
@@ -0,0 +1,203 @@
+<template>
+ <div class="app-container">
+ <el-tabs v-model="activeTab" type="border-card" @tab-change="handleTabChange">
+ <el-tab-pane label="浜哄憳妗f" name="personnel">
+ <el-form :model="personnelFilters" :inline="true">
+ <el-form-item label="濮撳悕">
+ <el-input v-model="personnelFilters.name" placeholder="璇疯緭鍏ュ鍚�" clearable style="width: 200px" />
+ </el-form-item>
+ <el-form-item label="閮ㄩ棬">
+ <el-input v-model="personnelFilters.dept" placeholder="璇疯緭鍏ラ儴闂�" clearable style="width: 200px" />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="getPersonnelData">鎼滅储</el-button>
+ <el-button @click="resetPersonnelFilters">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+ <div class="table_list">
+ <div class="actions">
+ <el-button type="primary" @click="addPersonnel" icon="Plus">鏂板</el-button>
+ </div>
+ <PIMTable :column="personnelColumns" :tableData="personnelList" :page="personnelPage" @pagination="changePersonnelPage" />
+ </div>
+ </el-tab-pane>
+
+ <el-tab-pane label="璁惧璁炬柦" name="equipment">
+ <el-form :model="equipmentFilters" :inline="true">
+ <el-form-item label="璁惧鍚嶇О">
+ <el-input v-model="equipmentFilters.name" placeholder="璇疯緭鍏ヨ澶囧悕绉�" clearable style="width: 200px" />
+ </el-form-item>
+ <el-form-item label="鎵�灞炲尯鍩�">
+ <el-input v-model="equipmentFilters.area" placeholder="璇疯緭鍏ユ墍灞炲尯鍩�" clearable style="width: 200px" />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="getEquipmentData">鎼滅储</el-button>
+ <el-button @click="resetEquipmentFilters">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+ <div class="table_list">
+ <div class="actions">
+ <el-button type="primary" @click="addEquipment" icon="Plus">鏂板</el-button>
+ </div>
+ <PIMTable :column="equipmentColumns" :tableData="equipmentList" :page="equipmentPage" @pagination="changeEquipmentPage" />
+ </div>
+ </el-tab-pane>
+
+ <el-tab-pane label="浣滀笟鍖哄煙" name="workArea">
+ <el-form :model="areaFilters" :inline="true">
+ <el-form-item label="鍖哄煙鍚嶇О">
+ <el-input v-model="areaFilters.name" placeholder="璇疯緭鍏ュ尯鍩熷悕绉�" clearable style="width: 200px" />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="getAreaData">鎼滅储</el-button>
+ <el-button @click="resetAreaFilters">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+ <div class="table_list">
+ <div class="actions">
+ <el-button type="primary" @click="addArea" icon="Plus">鏂板</el-button>
+ </div>
+ <PIMTable :column="areaColumns" :tableData="areaList" :page="areaPage" @pagination="changeAreaPage" />
+ </div>
+ </el-tab-pane>
+
+ <el-tab-pane label="宀椾綅椋庨櫓" name="risk">
+ <el-form :model="riskFilters" :inline="true">
+ <el-form-item label="椋庨櫓绫诲瀷">
+ <el-input v-model="riskFilters.type" placeholder="璇疯緭鍏ラ闄╃被鍨�" clearable style="width: 200px" />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="getRiskData">鎼滅储</el-button>
+ <el-button @click="resetRiskFilters">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+ <div class="table_list">
+ <div class="actions">
+ <el-button type="primary" @click="addRisk" icon="Plus">鏂板</el-button>
+ </div>
+ <PIMTable :column="riskColumns" :tableData="riskList" :page="riskPage" @pagination="changeRiskPage" />
+ </div>
+ </el-tab-pane>
+
+ <el-tab-pane label="搴旀�ヨ祫婧�" name="emergency">
+ <el-form :model="emergencyFilters" :inline="true">
+ <el-form-item label="璧勬簮鍚嶇О">
+ <el-input v-model="emergencyFilters.name" placeholder="璇疯緭鍏ヨ祫婧愬悕绉�" clearable style="width: 200px" />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="getEmergencyData">鎼滅储</el-button>
+ <el-button @click="resetEmergencyFilters">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+ <div class="table_list">
+ <div class="actions">
+ <el-button type="primary" @click="addEmergency" icon="Plus">鏂板</el-button>
+ </div>
+ <PIMTable :column="emergencyColumns" :tableData="emergencyList" :page="emergencyPage" @pagination="changeEmergencyPage" />
+ </div>
+ </el-tab-pane>
+ </el-tabs>
+ </div>
+</template>
+
+<script setup>
+import { ref, reactive } from "vue";
+import PIMTable from "@/components/PIMTable/PIMTable.vue";
+
+defineOptions({
+ name: "鍩虹淇℃伅绠$悊",
+});
+
+const activeTab = ref("personnel");
+
+// 浜哄憳妗f
+const personnelFilters = reactive({ name: "", dept: "" });
+const personnelList = ref([]);
+const personnelPage = reactive({ current: 1, size: 10, total: 0 });
+const personnelColumns = [
+ { label: "濮撳悕", prop: "name", align: "center" },
+ { label: "閮ㄩ棬", prop: "dept", align: "center" },
+ { label: "宀椾綅", prop: "post", align: "center" },
+ { label: "鑱旂郴鏂瑰紡", prop: "phone", align: "center" },
+ { label: "鍏ヨ亴鏃ユ湡", prop: "entryDate", align: "center" },
+];
+
+// 璁惧璁炬柦
+const equipmentFilters = reactive({ name: "", area: "" });
+const equipmentList = ref([]);
+const equipmentPage = reactive({ current: 1, size: 10, total: 0 });
+const equipmentColumns = [
+ { label: "璁惧鍚嶇О", prop: "name", align: "center" },
+ { label: "瑙勬牸鍨嬪彿", prop: "model", align: "center" },
+ { label: "鎵�灞炲尯鍩�", prop: "area", align: "center" },
+ { label: "鐘舵��", prop: "status", align: "center" },
+];
+
+// 浣滀笟鍖哄煙
+const areaFilters = reactive({ name: "" });
+const areaList = ref([]);
+const areaPage = reactive({ current: 1, size: 10, total: 0 });
+const areaColumns = [
+ { label: "鍖哄煙鍚嶇О", prop: "name", align: "center" },
+ { label: "浣嶇疆", prop: "location", align: "center" },
+ { label: "璐熻矗浜�", prop: "manager", align: "center" },
+];
+
+// 宀椾綅椋庨櫓
+const riskFilters = reactive({ type: "" });
+const riskList = ref([]);
+const riskPage = reactive({ current: 1, size: 10, total: 0 });
+const riskColumns = [
+ { label: "椋庨櫓绫诲瀷", prop: "type", align: "center" },
+ { label: "椋庨櫓绛夌骇", prop: "level", align: "center" },
+ { label: "鎻忚堪", prop: "description", align: "center" },
+];
+
+// 搴旀�ヨ祫婧�
+const emergencyFilters = reactive({ name: "" });
+const emergencyList = ref([]);
+const emergencyPage = reactive({ current: 1, size: 10, total: 0 });
+const emergencyColumns = [
+ { label: "璧勬簮鍚嶇О", prop: "name", align: "center" },
+ { label: "绫诲瀷", prop: "type", align: "center" },
+ { label: "鏁伴噺", prop: "quantity", align: "center" },
+ { label: "瀛樻斁浣嶇疆", prop: "location", align: "center" },
+];
+
+const handleTabChange = () => {
+ // 鍒囨崲tab鏃跺姞杞藉搴旀暟鎹�
+};
+
+const getPersonnelData = () => {};
+const resetPersonnelFilters = () => { personnelFilters.name = ""; personnelFilters.dept = ""; };
+const addPersonnel = () => {};
+const changePersonnelPage = ({ page, limit }) => { personnelPage.current = page; personnelPage.size = limit; };
+
+const getEquipmentData = () => {};
+const resetEquipmentFilters = () => { equipmentFilters.name = ""; equipmentFilters.area = ""; };
+const addEquipment = () => {};
+const changeEquipmentPage = ({ page, limit }) => { equipmentPage.current = page; equipmentPage.size = limit; };
+
+const getAreaData = () => {};
+const resetAreaFilters = () => { areaFilters.name = ""; };
+const addArea = () => {};
+const changeAreaPage = ({ page, limit }) => { areaPage.current = page; areaPage.size = limit; };
+
+const getRiskData = () => {};
+const resetRiskFilters = () => { riskFilters.type = ""; };
+const addRisk = () => {};
+const changeRiskPage = ({ page, limit }) => { riskPage.current = page; riskPage.size = limit; };
+
+const getEmergencyData = () => {};
+const resetEmergencyFilters = () => { emergencyFilters.name = ""; };
+const addEmergency = () => {};
+const changeEmergencyPage = ({ page, limit }) => { emergencyPage.current = page; emergencyPage.size = limit; };
+</script>
+
+<style lang="scss" scoped>
+.actions {
+ margin-bottom: 15px;
+ display: flex;
+ justify-content: flex-end;
+}
+</style>
diff --git a/src/views/safetyManagement/employeeLearning/index.vue b/src/views/safetyManagement/employeeLearning/index.vue
new file mode 100644
index 0000000..2070899
--- /dev/null
+++ b/src/views/safetyManagement/employeeLearning/index.vue
@@ -0,0 +1,165 @@
+<template>
+ <div class="app-container">
+ <el-row :gutter="20">
+ <el-col :span="6">
+ <el-card class="user-card">
+ <div class="user-info">
+ <el-avatar :size="80" :src="userInfo.avatar" />
+ <h3>{{ userInfo.name }}</h3>
+ <p>{{ userInfo.dept }} - {{ userInfo.post }}</p>
+ </div>
+ <el-divider />
+ <div class="stat-item">
+ <span class="label">宸插畬鎴愬煿璁�</span>
+ <span class="value">{{ userInfo.completedTrainings }} 娆�</span>
+ </div>
+ <div class="stat-item">
+ <span class="label">寰呭弬鍔犲煿璁�</span>
+ <span class="value">{{ userInfo.pendingTrainings }} 娆�</span>
+ </div>
+ <div class="stat-item">
+ <span class="label">骞冲潎鑰冩牳鍒嗘暟</span>
+ <span class="value">{{ userInfo.avgScore }} 鍒�</span>
+ </div>
+ </el-card>
+ </el-col>
+
+ <el-col :span="18">
+ <el-tabs v-model="activeTab" type="border-card">
+ <el-tab-pane label="鎴戠殑瀛︿範璁板綍" name="records">
+ <PIMTable :column="recordColumns" :tableData="recordList" :page="recordPage" @pagination="changeRecordPage" />
+ </el-tab-pane>
+
+ <el-tab-pane label="鑰冩牳鎶ュ憡" name="reports">
+ <PIMTable :column="reportColumns" :tableData="reportList" :page="reportPage" @pagination="changeReportPage" />
+ </el-tab-pane>
+
+ <el-tab-pane label="鍦ㄧ嚎娴嬭瘎" name="assessment">
+ <div class="assessment-list">
+ <el-card v-for="item in assessmentList" :key="item.id" class="assessment-card">
+ <div class="assessment-header">
+ <h4>{{ item.title }}</h4>
+ <el-tag :type="item.status === '寰呮祴璇�' ? 'warning' : 'success'">{{ item.status }}</el-tag>
+ </div>
+ <p class="assessment-desc">{{ item.description }}</p>
+ <div class="assessment-footer">
+ <span>鎴鏃堕棿锛歿{ item.deadline }}</span>
+ <el-button type="primary" size="small" :disabled="item.status !== '寰呮祴璇�'" @click="startAssessment(item)">
+ {{ item.status === '寰呮祴璇�' ? '寮�濮嬫祴璇�' : '宸插畬鎴�' }}
+ </el-button>
+ </div>
+ </el-card>
+ </div>
+ </el-tab-pane>
+ </el-tabs>
+ </el-col>
+ </el-row>
+ </div>
+</template>
+
+<script setup>
+import { ref, reactive } from "vue";
+import PIMTable from "@/components/PIMTable/PIMTable.vue";
+
+defineOptions({
+ name: "鍛樺伐瀛︿範",
+});
+
+const activeTab = ref("records");
+
+const userInfo = reactive({
+ name: "寮犱笁",
+ dept: "鐢熶骇閮�",
+ post: "鎿嶄綔宸�",
+ avatar: "",
+ completedTrainings: 12,
+ pendingTrainings: 3,
+ avgScore: 85,
+});
+
+// 瀛︿範璁板綍
+const recordList = ref([]);
+const recordPage = reactive({ current: 1, size: 10, total: 0 });
+const recordColumns = [
+ { label: "鍩硅鍐呭", prop: "content", align: "center" },
+ { label: "鍩硅鏃堕棿", prop: "trainingTime", align: "center" },
+ { label: "鍩硅鏃堕暱", prop: "duration", align: "center" },
+ { label: "鍩硅鏂瑰紡", prop: "method", align: "center" },
+ { label: "瀹屾垚鐘舵��", prop: "status", align: "center" },
+];
+
+// 鑰冩牳鎶ュ憡
+const reportList = ref([]);
+const reportPage = reactive({ current: 1, size: 10, total: 0 });
+const reportColumns = [
+ { label: "鑰冩牳鍚嶇О", prop: "name", align: "center" },
+ { label: "鑰冩牳鏃堕棿", prop: "assessTime", align: "center" },
+ { label: "寰楀垎", prop: "score", align: "center" },
+ { label: "绛夌骇", prop: "grade", align: "center" },
+ { label: "鏄惁鍚堟牸", prop: "qualified", align: "center" },
+];
+
+// 鍦ㄧ嚎娴嬭瘎
+const assessmentList = ref([
+ { id: 1, title: "瀹夊叏鎿嶄綔瑙勭▼娴嬭瘎", description: "鑰冩牳鍛樺伐瀵瑰畨鍏ㄦ搷浣滆绋嬬殑鎺屾彙绋嬪害", deadline: "2026-05-30", status: "寰呮祴璇�" },
+ { id: 2, title: "搴旀�ュ缃兘鍔涙祴璇�", description: "鑰冩牳鍛樺伐搴旀�ュ缃兘鍔�", deadline: "2026-06-15", status: "宸插畬鎴�" },
+]);
+
+const changeRecordPage = ({ page, limit }) => { recordPage.current = page; recordPage.size = limit; };
+const changeReportPage = ({ page, limit }) => { reportPage.current = page; reportPage.size = limit; };
+const startAssessment = (item) => {};
+</script>
+
+<style lang="scss" scoped>
+.user-card {
+ .user-info {
+ text-align: center;
+ h3 {
+ margin: 15px 0 5px;
+ }
+ p {
+ color: #666;
+ font-size: 14px;
+ }
+ }
+ .stat-item {
+ display: flex;
+ justify-content: space-between;
+ padding: 10px 0;
+ .label {
+ color: #666;
+ }
+ .value {
+ font-weight: bold;
+ color: #409eff;
+ }
+ }
+}
+
+.assessment-list {
+ .assessment-card {
+ margin-bottom: 15px;
+ .assessment-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ h4 {
+ margin: 0;
+ }
+ }
+ .assessment-desc {
+ color: #666;
+ margin: 10px 0;
+ }
+ .assessment-footer {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ span {
+ color: #999;
+ font-size: 12px;
+ }
+ }
+ }
+}
+</style>
diff --git a/src/views/safetyManagement/inspectionReport/index.vue b/src/views/safetyManagement/inspectionReport/index.vue
new file mode 100644
index 0000000..91cc4e4
--- /dev/null
+++ b/src/views/safetyManagement/inspectionReport/index.vue
@@ -0,0 +1,233 @@
+<template>
+ <div class="app-container">
+ <el-row :gutter="20" class="stat-cards">
+ <el-col :span="6">
+ <el-card>
+ <div class="stat-item">
+ <div class="stat-icon" style="background: #67c23a;"><el-icon><CircleCheck /></el-icon></div>
+ <div class="stat-info">
+ <span class="stat-value">{{ todayStats.completionRate }}%</span>
+ <span class="stat-label">褰撴棩宸℃瀹屾垚鐜�</span>
+ </div>
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="6">
+ <el-card>
+ <div class="stat-item">
+ <div class="stat-icon" style="background: #409eff;"><el-icon><User /></el-icon></div>
+ <div class="stat-info">
+ <span class="stat-value">{{ todayStats.inspectorCount }}</span>
+ <span class="stat-label">宸℃浜哄憳鏁�</span>
+ </div>
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="6">
+ <el-card>
+ <div class="stat-item">
+ <div class="stat-icon" style="background: #e6a23c;"><el-icon><Warning /></el-icon></div>
+ <div class="stat-info">
+ <span class="stat-value">{{ todayStats.abnormalCount }}</span>
+ <span class="stat-label">寮傚父璁板綍鏁�</span>
+ </div>
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="6">
+ <el-card>
+ <div class="stat-item">
+ <div class="stat-icon" style="background: #f56c6c;"><el-icon><CircleClose /></el-icon></div>
+ <div class="stat-info">
+ <span class="stat-value">{{ todayStats.missedCount }}</span>
+ <span class="stat-label">婕忔璁板綍鏁�</span>
+ </div>
+ </div>
+ </el-card>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="20" class="chart-row">
+ <el-col :span="12">
+ <el-card>
+ <template #header>
+ <span>宸℃浠诲姟鎵ц瓒嬪娍</span>
+ </template>
+ <div ref="trendChartRef" style="height: 300px;"></div>
+ </el-card>
+ </el-col>
+ <el-col :span="12">
+ <el-card>
+ <template #header>
+ <span>宸℃绫诲瀷涓庨鐜囧垎甯�</span>
+ </template>
+ <div ref="typeChartRef" style="height: 300px;"></div>
+ </el-card>
+ </el-col>
+ </el-row>
+
+ <el-card class="table-card">
+ <template #header>
+ <span>宸℃璁板綍鏄庣粏</span>
+ </template>
+ <el-form :model="filters" :inline="true">
+ <el-form-item label="宸℃鏃ユ湡">
+ <el-date-picker v-model="filters.dateRange" type="daterange" range-separator="鑷�" start-placeholder="寮�濮嬫棩鏈�" end-placeholder="缁撴潫鏃ユ湡" value-format="YYYY-MM-DD" />
+ </el-form-item>
+ <el-form-item label="宸℃浜哄憳">
+ <el-input v-model="filters.inspector" placeholder="璇疯緭鍏ュ贰妫�浜哄憳" clearable style="width: 200px" />
+ </el-form-item>
+ <el-form-item label="鐘舵��">
+ <el-select v-model="filters.status" placeholder="璇烽�夋嫨" clearable style="width: 150px">
+ <el-option label="姝e父" value="normal" />
+ <el-option label="寮傚父" value="abnormal" />
+ <el-option label="婕忔" value="missed" />
+ <el-option label="鏈墽琛�" value="unexecuted" />
+ </el-select>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="getData">鎼滅储</el-button>
+ <el-button @click="resetFilters">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+ <PIMTable :column="columns" :tableData="dataList" :page="pagination" @pagination="changePage" />
+ </el-card>
+ </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted } from "vue";
+import PIMTable from "@/components/PIMTable/PIMTable.vue";
+import * as echarts from "echarts";
+
+defineOptions({
+ name: "宸℃鏁版嵁鎶ヨ〃",
+});
+
+const todayStats = reactive({
+ completionRate: 95,
+ inspectorCount: 8,
+ abnormalCount: 2,
+ missedCount: 1,
+});
+
+const filters = reactive({
+ dateRange: [],
+ inspector: "",
+ status: "",
+});
+
+const dataList = ref([]);
+const pagination = reactive({ current: 1, size: 10, total: 0 });
+
+const columns = [
+ { label: "宸℃鏃堕棿", prop: "inspectionTime", align: "center" },
+ { label: "宸℃浜哄憳", prop: "inspector", align: "center" },
+ { label: "宸℃鍖哄煙", prop: "area", align: "center" },
+ { label: "宸℃绫诲瀷", prop: "type", align: "center" },
+ { label: "鐘舵��", prop: "status", align: "center" },
+ { label: "寮傚父鎯呭喌", prop: "abnormalDesc", align: "center" },
+];
+
+const trendChartRef = ref(null);
+const typeChartRef = ref(null);
+
+onMounted(() => {
+ initTrendChart();
+ initTypeChart();
+});
+
+const initTrendChart = () => {
+ const chart = echarts.init(trendChartRef.value);
+ const option = {
+ xAxis: {
+ type: "category",
+ data: ["鍛ㄤ竴", "鍛ㄤ簩", "鍛ㄤ笁", "鍛ㄥ洓", "鍛ㄤ簲", "鍛ㄥ叚", "鍛ㄦ棩"],
+ },
+ yAxis: { type: "value" },
+ series: [
+ { name: "宸插畬鎴�", type: "line", data: [120, 132, 101, 134, 90, 230, 210], smooth: true },
+ { name: "鏈畬鎴�", type: "line", data: [20, 12, 21, 14, 30, 20, 10], smooth: true },
+ ],
+ legend: { data: ["宸插畬鎴�", "鏈畬鎴�"], bottom: 0 },
+ grid: { left: "3%", right: "4%", bottom: "10%", containLabel: true },
+ };
+ chart.setOption(option);
+};
+
+const initTypeChart = () => {
+ const chart = echarts.init(typeChartRef.value);
+ const option = {
+ series: [
+ {
+ type: "pie",
+ radius: ["40%", "70%"],
+ data: [
+ { value: 335, name: "璁惧宸℃" },
+ { value: 310, name: "瀹夊叏宸℃" },
+ { value: 234, name: "鐜宸℃" },
+ { value: 135, name: "娑堥槻宸℃" },
+ ],
+ },
+ ],
+ legend: { orient: "vertical", left: "left" },
+ };
+ chart.setOption(option);
+};
+
+const getData = () => {};
+const resetFilters = () => {
+ filters.dateRange = [];
+ filters.inspector = "";
+ filters.status = "";
+};
+const changePage = ({ page, limit }) => {
+ pagination.current = page;
+ pagination.size = limit;
+};
+</script>
+
+<style lang="scss" scoped>
+.stat-cards {
+ margin-bottom: 20px;
+ .stat-item {
+ display: flex;
+ align-items: center;
+ .stat-icon {
+ width: 60px;
+ height: 60px;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: #fff;
+ font-size: 28px;
+ margin-right: 15px;
+ }
+ .stat-info {
+ display: flex;
+ flex-direction: column;
+ .stat-value {
+ font-size: 24px;
+ font-weight: bold;
+ color: #333;
+ }
+ .stat-label {
+ font-size: 14px;
+ color: #666;
+ margin-top: 5px;
+ }
+ }
+ }
+}
+
+.chart-row {
+ margin-bottom: 20px;
+}
+
+.table-card {
+ :deep(.el-card__header) {
+ font-weight: bold;
+ }
+}
+</style>
diff --git a/src/views/safetyManagement/trainingManage/index.vue b/src/views/safetyManagement/trainingManage/index.vue
new file mode 100644
index 0000000..3c37b2f
--- /dev/null
+++ b/src/views/safetyManagement/trainingManage/index.vue
@@ -0,0 +1,135 @@
+<template>
+ <div class="app-container">
+ <el-tabs v-model="activeTab" type="border-card">
+ <el-tab-pane label="鍩硅璧勬枡" name="materials">
+ <el-form :model="materialFilters" :inline="true">
+ <el-form-item label="璧勬枡鍚嶇О">
+ <el-input v-model="materialFilters.name" placeholder="璇疯緭鍏ヨ祫鏂欏悕绉�" clearable style="width: 200px" />
+ </el-form-item>
+ <el-form-item label="璧勬枡绫诲瀷">
+ <el-select v-model="materialFilters.type" placeholder="璇烽�夋嫨" clearable style="width: 150px">
+ <el-option label="鍒跺害" value="system" />
+ <el-option label="璇句欢" value="courseware" />
+ <el-option label="瑙嗛" value="video" />
+ <el-option label="妗堜緥" value="case" />
+ </el-select>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="getMaterialData">鎼滅储</el-button>
+ <el-button @click="resetMaterialFilters">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+ <div class="table_list">
+ <div class="actions">
+ <el-button type="primary" @click="uploadMaterial" icon="Upload">涓婁紶璧勬枡</el-button>
+ </div>
+ <PIMTable :column="materialColumns" :tableData="materialList" :page="materialPage" @pagination="changeMaterialPage" />
+ </div>
+ </el-tab-pane>
+
+ <el-tab-pane label="鍩硅璁″垝" name="plans">
+ <el-form :model="planFilters" :inline="true">
+ <el-form-item label="璁″垝骞村害">
+ <el-date-picker v-model="planFilters.year" type="year" placeholder="閫夋嫨骞村害" value-format="YYYY" style="width: 150px" />
+ </el-form-item>
+ <el-form-item label="宀椾綅">
+ <el-input v-model="planFilters.post" placeholder="璇疯緭鍏ュ矖浣�" clearable style="width: 200px" />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="getPlanData">鎼滅储</el-button>
+ <el-button @click="resetPlanFilters">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+ <div class="table_list">
+ <div class="actions">
+ <el-button type="primary" @click="addPlan" icon="Plus">鍒跺畾璁″垝</el-button>
+ </div>
+ <PIMTable :column="planColumns" :tableData="planList" :page="planPage" @pagination="changePlanPage" />
+ </div>
+ </el-tab-pane>
+
+ <el-tab-pane label="瀹屾垚璁板綍" name="records">
+ <el-form :model="recordFilters" :inline="true">
+ <el-form-item label="鍛樺伐濮撳悕">
+ <el-input v-model="recordFilters.employeeName" placeholder="璇疯緭鍏ュ憳宸ュ鍚�" clearable style="width: 200px" />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="getRecordData">鎼滅储</el-button>
+ <el-button @click="resetRecordFilters">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+ <div class="table_list">
+ <PIMTable :column="recordColumns" :tableData="recordList" :page="recordPage" @pagination="changeRecordPage" />
+ </div>
+ </el-tab-pane>
+ </el-tabs>
+ </div>
+</template>
+
+<script setup>
+import { ref, reactive } from "vue";
+import PIMTable from "@/components/PIMTable/PIMTable.vue";
+
+defineOptions({
+ name: "鍩硅绠$悊",
+});
+
+const activeTab = ref("materials");
+
+// 鍩硅璧勬枡
+const materialFilters = reactive({ name: "", type: "" });
+const materialList = ref([]);
+const materialPage = reactive({ current: 1, size: 10, total: 0 });
+const materialColumns = [
+ { label: "璧勬枡鍚嶇О", prop: "name", align: "center" },
+ { label: "绫诲瀷", prop: "type", align: "center" },
+ { label: "涓婁紶浜�", prop: "uploader", align: "center" },
+ { label: "涓婁紶鏃堕棿", prop: "uploadTime", align: "center" },
+ { label: "鏂囦欢澶у皬", prop: "fileSize", align: "center" },
+];
+
+// 鍩硅璁″垝
+const planFilters = reactive({ year: "", post: "" });
+const planList = ref([]);
+const planPage = reactive({ current: 1, size: 10, total: 0 });
+const planColumns = [
+ { label: "璁″垝骞村害", prop: "year", align: "center" },
+ { label: "宀椾綅", prop: "post", align: "center" },
+ { label: "灞傜骇", prop: "level", align: "center" },
+ { label: "鍩硅鍐呭", prop: "content", align: "center" },
+ { label: "璁″垝璇炬椂", prop: "hours", align: "center" },
+];
+
+// 瀹屾垚璁板綍
+const recordFilters = reactive({ employeeName: "" });
+const recordList = ref([]);
+const recordPage = reactive({ current: 1, size: 10, total: 0 });
+const recordColumns = [
+ { label: "鍛樺伐濮撳悕", prop: "employeeName", align: "center" },
+ { label: "鍩硅鍐呭", prop: "content", align: "center" },
+ { label: "瀹屾垚鏃堕棿", prop: "completeTime", align: "center" },
+ { label: "鑰冩牳缁撴灉", prop: "result", align: "center" },
+];
+
+const getMaterialData = () => {};
+const resetMaterialFilters = () => { materialFilters.name = ""; materialFilters.type = ""; };
+const uploadMaterial = () => {};
+const changeMaterialPage = ({ page, limit }) => { materialPage.current = page; materialPage.size = limit; };
+
+const getPlanData = () => {};
+const resetPlanFilters = () => { planFilters.year = ""; planFilters.post = ""; };
+const addPlan = () => {};
+const changePlanPage = ({ page, limit }) => { planPage.current = page; planPage.size = limit; };
+
+const getRecordData = () => {};
+const resetRecordFilters = () => { recordFilters.employeeName = ""; };
+const changeRecordPage = ({ page, limit }) => { recordPage.current = page; recordPage.size = limit; };
+</script>
+
+<style lang="scss" scoped>
+.actions {
+ margin-bottom: 15px;
+ display: flex;
+ justify-content: flex-end;
+}
+</style>
--
Gitblit v1.9.3