From b8da78824e4c67632abb65302f01ccf74d5a1096 Mon Sep 17 00:00:00 2001
From: zouyu <2723363702@qq.com>
Date: 星期二, 26 五月 2026 18:45:51 +0800
Subject: [PATCH] 浪潮对接:芯导-安环管理系统,配置调整
---
src/views/safetyManagement/trainingManage/index.vue | 892 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 861 insertions(+), 31 deletions(-)
diff --git a/src/views/safetyManagement/trainingManage/index.vue b/src/views/safetyManagement/trainingManage/index.vue
index 3c37b2f..873f862 100644
--- a/src/views/safetyManagement/trainingManage/index.vue
+++ b/src/views/safetyManagement/trainingManage/index.vue
@@ -1,6 +1,6 @@
<template>
<div class="app-container">
- <el-tabs v-model="activeTab" type="border-card">
+ <el-tabs v-model="activeTab" type="border-card" @tab-change="handleTabChange">
<el-tab-pane label="鍩硅璧勬枡" name="materials">
<el-form :model="materialFilters" :inline="true">
<el-form-item label="璧勬枡鍚嶇О">
@@ -8,10 +8,17 @@
</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-option label="PDF" value="PDF" />
+ <el-option label="鍒跺害" value="鍒跺害" />
+ <el-option label="璇句欢" value="璇句欢" />
+ <el-option label="瑙嗛" value="瑙嗛" />
+ <el-option label="妗堜緥" value="妗堜緥" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="鐘舵��">
+ <el-select v-model="materialFilters.status" placeholder="璇烽�夋嫨" clearable style="width: 150px">
+ <el-option label="鍚敤" :value="1" />
+ <el-option label="鍋滅敤" :value="0" />
</el-select>
</el-form-item>
<el-form-item>
@@ -21,9 +28,9 @@
</el-form>
<div class="table_list">
<div class="actions">
- <el-button type="primary" @click="uploadMaterial" icon="Upload">涓婁紶璧勬枡</el-button>
+ <el-button type="primary" @click="openMaterialDialog" icon="Upload">涓婁紶璧勬枡</el-button>
</div>
- <PIMTable :column="materialColumns" :tableData="materialList" :page="materialPage" @pagination="changeMaterialPage" />
+ <PIMTable :column="materialColumns" :tableData="materialList" :page="materialPage" @pagination="changeMaterialPage" :tableLoading="materialLoading" />
</div>
</el-tab-pane>
@@ -35,6 +42,20 @@
<el-form-item label="宀椾綅">
<el-input v-model="planFilters.post" placeholder="璇疯緭鍏ュ矖浣�" clearable style="width: 200px" />
</el-form-item>
+ <el-form-item label="鍩硅绛夌骇">
+ <el-select v-model="planFilters.level" placeholder="璇烽�夋嫨" clearable style="width: 150px">
+ <el-option label="涓�绾�" value="涓�绾�" />
+ <el-option label="浜岀骇" value="浜岀骇" />
+ <el-option label="涓夌骇" value="涓夌骇" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="鐘舵��">
+ <el-select v-model="planFilters.status" placeholder="璇烽�夋嫨" clearable style="width: 150px">
+ <el-option label="寰呮墽琛�" :value="0" />
+ <el-option label="鎵ц涓�" :value="1" />
+ <el-option label="宸插畬鎴�" :value="2" />
+ </el-select>
+ </el-form-item>
<el-form-item>
<el-button type="primary" @click="getPlanData">鎼滅储</el-button>
<el-button @click="resetPlanFilters">閲嶇疆</el-button>
@@ -42,9 +63,9 @@
</el-form>
<div class="table_list">
<div class="actions">
- <el-button type="primary" @click="addPlan" icon="Plus">鍒跺畾璁″垝</el-button>
+ <el-button type="primary" @click="openPlanDialog" icon="Plus">鍒跺畾璁″垝</el-button>
</div>
- <PIMTable :column="planColumns" :tableData="planList" :page="planPage" @pagination="changePlanPage" />
+ <PIMTable :column="planColumns" :tableData="planList" :page="planPage" @pagination="changePlanPage" :tableLoading="planLoading" />
</div>
</el-tab-pane>
@@ -53,22 +74,232 @@
<el-form-item label="鍛樺伐濮撳悕">
<el-input v-model="recordFilters.employeeName" placeholder="璇疯緭鍏ュ憳宸ュ鍚�" clearable style="width: 200px" />
</el-form-item>
+ <el-form-item label="鐘舵��">
+ <el-select v-model="recordFilters.status" placeholder="璇烽�夋嫨" clearable style="width: 150px">
+ <el-option label="宸插畬鎴�" :value="1" />
+ <el-option label="鏈畬鎴�" :value="0" />
+ </el-select>
+ </el-form-item>
<el-form-item>
<el-button type="primary" @click="getRecordData">鎼滅储</el-button>
<el-button @click="resetRecordFilters">閲嶇疆</el-button>
+ <el-button type="primary" @click="openRecordDialog" icon="Plus">鏂板</el-button>
+ <el-button type="success" @click="exportRecords" icon="Download">瀵煎嚭</el-button>
</el-form-item>
</el-form>
<div class="table_list">
- <PIMTable :column="recordColumns" :tableData="recordList" :page="recordPage" @pagination="changeRecordPage" />
+ <PIMTable :column="recordColumns" :tableData="recordList" :page="recordPage" @pagination="changeRecordPage" :tableLoading="recordLoading" />
</div>
</el-tab-pane>
</el-tabs>
+
+ <!-- 鍩硅璧勬枡寮圭獥 -->
+ <el-dialog :title="materialDialog.title" v-model="materialDialog.visible" width="600px" append-to-body>
+ <el-form ref="materialFormRef" :model="materialForm" :rules="materialRules" label-width="100px">
+ <el-form-item label="璧勬枡鍚嶇О" prop="name">
+ <el-input v-model="materialForm.name" placeholder="璇疯緭鍏ヨ祫鏂欏悕绉�" />
+ </el-form-item>
+ <el-form-item label="璧勬枡绫诲瀷" prop="type">
+ <el-select v-model="materialForm.type" placeholder="璇烽�夋嫨璧勬枡绫诲瀷" style="width: 100%">
+ <el-option label="PDF" value="PDF" />
+ <el-option label="鍒跺害" value="鍒跺害" />
+ <el-option label="璇句欢" value="璇句欢" />
+ <el-option label="瑙嗛" value="瑙嗛" />
+ <el-option label="妗堜緥" value="妗堜緥" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="鏂囦欢涓婁紶" prop="fileUrl" v-if="!materialForm.id">
+ <el-upload
+ ref="uploadRef"
+ action="/dev-api/common/upload"
+ :headers="uploadHeaders"
+ :on-success="handleUploadSuccess"
+ :on-error="handleUploadError"
+ :before-upload="beforeUpload"
+ :limit="1"
+ >
+ <el-button type="primary">閫夋嫨鏂囦欢</el-button>
+ <template #tip>
+ <div class="el-upload__tip">鏀寔 PDF銆乄ord銆佽棰戠瓑鏍煎紡</div>
+ </template>
+ </el-upload>
+ </el-form-item>
+ <el-form-item label="鏂囦欢澶у皬" prop="fileSize" v-if="materialForm.fileSize">
+ <el-input v-model="materialForm.fileSize" disabled />
+ </el-form-item>
+ <el-form-item label="鐘舵��" prop="status">
+ <el-radio-group v-model="materialForm.status">
+ <el-radio :value="1">鍚敤</el-radio>
+ <el-radio :value="0">鍋滅敤</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ <el-form-item label="澶囨敞" prop="remark">
+ <el-input v-model="materialForm.remark" type="textarea" :rows="3" placeholder="璇疯緭鍏ュ娉�" />
+ </el-form-item>
+ </el-form>
+ <template #footer>
+ <el-button @click="materialDialog.visible = false">鍙� 娑�</el-button>
+ <el-button type="primary" @click="submitMaterialForm" :loading="materialDialog.loading">纭� 瀹�</el-button>
+ </template>
+ </el-dialog>
+
+ <!-- 鍩硅璁″垝寮圭獥 -->
+ <el-dialog :title="planDialog.title" v-model="planDialog.visible" width="700px" append-to-body>
+ <el-form ref="planFormRef" :model="planForm" :rules="planRules" label-width="100px">
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="璁″垝骞村害" prop="year">
+ <el-date-picker v-model="planForm.year" type="year" placeholder="閫夋嫨骞村害" value-format="YYYY" style="width: 100%" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="閫傜敤宀椾綅" prop="post">
+ <el-input v-model="planForm.post" placeholder="璇疯緭鍏ラ�傜敤宀椾綅" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="鍩硅绛夌骇" prop="level">
+ <el-select v-model="planForm.level" placeholder="璇烽�夋嫨鍩硅绛夌骇" style="width: 100%">
+ <el-option label="涓�绾�" value="涓�绾�" />
+ <el-option label="浜岀骇" value="浜岀骇" />
+ <el-option label="涓夌骇" value="涓夌骇" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="璁″垝璇炬椂" prop="hours">
+ <el-input-number v-model="planForm.hours" :min="1" style="width: 100%" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-form-item label="鍩硅鍐呭" prop="content">
+ <el-input v-model="planForm.content" type="textarea" :rows="3" placeholder="璇疯緭鍏ュ煿璁唴瀹�" />
+ </el-form-item>
+ <el-form-item label="鍩硅璧勬枡" prop="materialIds">
+ <el-select v-model="planForm.materialIds" multiple placeholder="璇烽�夋嫨鍩硅璧勬枡" style="width: 100%">
+ <el-option v-for="item in materialOptions" :key="item.id" :label="item.name" :value="item.id" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="鐘舵��" prop="status">
+ <el-radio-group v-model="planForm.status">
+ <el-radio :value="0">寰呮墽琛�</el-radio>
+ <el-radio :value="1">鎵ц涓�</el-radio>
+ <el-radio :value="2">宸插畬鎴�</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ <el-form-item label="澶囨敞" prop="remark">
+ <el-input v-model="planForm.remark" type="textarea" :rows="3" placeholder="璇疯緭鍏ュ娉�" />
+ </el-form-item>
+ </el-form>
+ <template #footer>
+ <el-button @click="planDialog.visible = false">鍙� 娑�</el-button>
+ <el-button type="primary" @click="submitPlanForm" :loading="planDialog.loading">纭� 瀹�</el-button>
+ </template>
+ </el-dialog>
+
+ <!-- 瀹屾垚璁板綍寮圭獥 -->
+ <el-dialog :title="recordDialog.title" v-model="recordDialog.visible" width="700px" append-to-body>
+ <el-form ref="recordFormRef" :model="recordForm" :rules="recordRules" label-width="100px">
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="鍩硅璁″垝" prop="planId">
+ <el-select v-model="recordForm.planId" placeholder="璇烽�夋嫨鍩硅璁″垝" style="width: 100%" @change="handlePlanChange">
+ <el-option v-for="item in planOptions" :key="item.id" :label="item.content" :value="item.id" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鍛樺伐濮撳悕" prop="employeeId">
+ <el-select v-model="recordForm.employeeId" placeholder="璇烽�夋嫨鍛樺伐" style="width: 100%" @change="handleEmployeeChange">
+ <el-option v-for="item in employeeOptions" :key="item.userId" :label="item.userName" :value="item.userId" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="瀹屾垚鏃堕棿" prop="completeTime">
+ <el-date-picker v-model="recordForm.completeTime" type="datetime" placeholder="閫夋嫨瀹屾垚鏃堕棿" value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="瀛︿範鏃堕暱" prop="duration">
+ <el-input-number v-model="recordForm.duration" :min="0" :precision="1" style="width: 100%" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="鍩硅鏂瑰紡" prop="method">
+ <el-select v-model="recordForm.method" placeholder="璇烽�夋嫨鍩硅鏂瑰紡" style="width: 100%">
+ <el-option label="绾夸笅鎺堣" value="绾夸笅鎺堣" />
+ <el-option label="绾夸笂瀛︿範" value="绾夸笂瀛︿範" />
+ <el-option label="瀹炴搷婕旂粌" value="瀹炴搷婕旂粌" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鑰冩牳鍒嗘暟" prop="score">
+ <el-input-number v-model="recordForm.score" :min="0" :max="100" style="width: 100%" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="鑰冩牳缁撴灉" prop="result">
+ <el-select v-model="recordForm.result" placeholder="璇烽�夋嫨鑰冩牳缁撴灉" style="width: 100%">
+ <el-option label="閫氳繃" value="閫氳繃" />
+ <el-option label="鏈�氳繃" value="鏈�氳繃" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鐘舵��" prop="status">
+ <el-radio-group v-model="recordForm.status">
+ <el-radio :value="1">宸插畬鎴�</el-radio>
+ <el-radio :value="0">鏈畬鎴�</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-form-item label="澶囨敞" prop="remark">
+ <el-input v-model="recordForm.remark" type="textarea" :rows="3" placeholder="璇疯緭鍏ュ娉�" />
+ </el-form-item>
+ </el-form>
+ <template #footer>
+ <el-button @click="recordDialog.visible = false">鍙� 娑�</el-button>
+ <el-button type="primary" @click="submitRecordForm" :loading="recordDialog.loading">纭� 瀹�</el-button>
+ </template>
+ </el-dialog>
</div>
</template>
<script setup>
-import { ref, reactive } from "vue";
+import { ref, reactive, onMounted } from "vue";
import PIMTable from "@/components/PIMTable/PIMTable.vue";
+import {
+ getMaterialList,
+ uploadMaterial as uploadMaterialApi,
+ updateMaterial,
+ deleteMaterial,
+ getMaterialDetail,
+ getPlanList,
+ addPlan as addPlanApi,
+ updatePlan,
+ deletePlan,
+ getPlanDetail,
+ getRecordList,
+ addRecord as addRecordApi,
+ updateRecord,
+ deleteRecord,
+ getRecordDetail,
+ exportRecord
+} from "@/api/safetyManagement/trainingManage.js";
+import { listUser } from "@/api/system/user";
+import { getToken } from "@/utils/auth";
+import { ElMessage, ElMessageBox } from "element-plus";
defineOptions({
name: "鍩硅绠$悊",
@@ -76,54 +307,653 @@
const activeTab = ref("materials");
-// 鍩硅璧勬枡
-const materialFilters = reactive({ name: "", type: "" });
+// ==================== 鍩硅璧勬枡 ====================
+const materialFilters = reactive({ name: "", type: "", status: null });
const materialList = ref([]);
const materialPage = reactive({ current: 1, size: 10, total: 0 });
+const materialLoading = ref(false);
const materialColumns = [
{ label: "璧勬枡鍚嶇О", prop: "name", align: "center" },
- { label: "绫诲瀷", prop: "type", align: "center" },
+ {
+ label: "绫诲瀷",
+ prop: "type",
+ align: "center",
+ dataType: "tag",
+ formatType: () => "primary",
+ formatData: (val) => val || '-'
+ },
{ label: "涓婁紶浜�", prop: "uploader", align: "center" },
{ label: "涓婁紶鏃堕棿", prop: "uploadTime", align: "center" },
{ label: "鏂囦欢澶у皬", prop: "fileSize", align: "center" },
+ {
+ label: "鐘舵��",
+ prop: "status",
+ align: "center",
+ dataType: "tag",
+ formatType: (val) => (val === 1 ? "success" : "info"),
+ formatData: (val) => (val === 1 ? "鍚敤" : "鍋滅敤")
+ },
+ {
+ label: "鎿嶄綔",
+ prop: "action",
+ align: "center",
+ dataType: "action",
+ operation: [
+ { name: "缂栬緫", type: "text", clickFun: (row) => handleEditMaterial(row) },
+ { name: "涓嬭浇", type: "text", clickFun: (row) => handleDownload(row) },
+ { name: "鍒犻櫎", type: "text", clickFun: (row) => handleDeleteMaterial(row) }
+ ]
+ }
];
-// 鍩硅璁″垝
-const planFilters = reactive({ year: "", post: "" });
+const materialDialog = reactive({ visible: false, title: "", loading: false });
+const materialFormRef = ref(null);
+const uploadRef = ref(null);
+const materialForm = reactive({
+ id: null,
+ name: "",
+ type: "",
+ fileUrl: "",
+ fileSize: "",
+ status: 1,
+ remark: ""
+});
+const materialRules = {
+ name: [{ required: true, message: "璇疯緭鍏ヨ祫鏂欏悕绉�", trigger: "blur" }],
+ type: [{ required: true, message: "璇烽�夋嫨璧勬枡绫诲瀷", trigger: "change" }]
+};
+
+const uploadHeaders = reactive({
+ Authorization: "Bearer " + getToken()
+});
+
+// ==================== 鍩硅璁″垝 ====================
+const planFilters = reactive({ year: "", post: "", level: "", status: null });
const planList = ref([]);
const planPage = reactive({ current: 1, size: 10, total: 0 });
+const planLoading = ref(false);
const planColumns = [
{ label: "璁″垝骞村害", prop: "year", align: "center" },
{ label: "宀椾綅", prop: "post", align: "center" },
- { label: "灞傜骇", prop: "level", align: "center" },
+ { label: "鍩硅绛夌骇", prop: "level", align: "center" },
{ label: "鍩硅鍐呭", prop: "content", align: "center" },
{ label: "璁″垝璇炬椂", prop: "hours", align: "center" },
+ {
+ label: "鐘舵��",
+ prop: "status",
+ align: "center",
+ dataType: "tag",
+ formatType: (val) => {
+ if (val === 0) return 'info';
+ if (val === 1) return 'warning';
+ return 'success';
+ },
+ formatData: (val) => {
+ const statusMap = { 0: '寰呮墽琛�', 1: '鎵ц涓�', 2: '宸插畬鎴�' };
+ return statusMap[val] || val;
+ }
+ },
+ {
+ label: "鎿嶄綔",
+ prop: "action",
+ align: "center",
+ dataType: "action",
+ operation: [
+ { name: "缂栬緫", type: "text", clickFun: (row) => handleEditPlan(row) },
+ { name: "鍒犻櫎", type: "text", clickFun: (row) => handleDeletePlan(row) }
+ ]
+ }
];
-// 瀹屾垚璁板綍
-const recordFilters = reactive({ employeeName: "" });
+const planDialog = reactive({ visible: false, title: "", loading: false });
+const planFormRef = ref(null);
+const planForm = reactive({
+ id: null,
+ year: "",
+ post: "",
+ level: "",
+ content: "",
+ hours: 1,
+ materialIds: [],
+ status: 0,
+ remark: ""
+});
+const planRules = {
+ year: [{ required: true, message: "璇烽�夋嫨璁″垝骞村害", trigger: "change" }],
+ post: [{ required: true, message: "璇疯緭鍏ラ�傜敤宀椾綅", trigger: "blur" }],
+ level: [{ required: true, message: "璇烽�夋嫨鍩硅绛夌骇", trigger: "change" }],
+ content: [{ required: true, message: "璇疯緭鍏ュ煿璁唴瀹�", trigger: "blur" }],
+ hours: [{ required: true, message: "璇疯緭鍏ヨ鍒掕鏃�", trigger: "blur" }]
+};
+const materialOptions = ref([]);
+
+// ==================== 瀹屾垚璁板綍 ====================
+const recordFilters = reactive({ employeeName: "", status: null });
const recordList = ref([]);
const recordPage = reactive({ current: 1, size: 10, total: 0 });
+const recordLoading = ref(false);
const recordColumns = [
{ label: "鍛樺伐濮撳悕", prop: "employeeName", align: "center" },
{ label: "鍩硅鍐呭", prop: "content", align: "center" },
{ label: "瀹屾垚鏃堕棿", prop: "completeTime", align: "center" },
- { label: "鑰冩牳缁撴灉", prop: "result", align: "center" },
+ { label: "瀛︿範鏃堕暱", prop: "duration", align: "center" },
+ { label: "鍩硅鏂瑰紡", prop: "method", align: "center" },
+ { label: "鍒嗘暟", prop: "score", align: "center" },
+ {
+ label: "鑰冩牳缁撴灉",
+ prop: "result",
+ align: "center",
+ dataType: "tag",
+ formatType: (val) => {
+ if (val === '浼樼' || val === '閫氳繃') return 'success';
+ if (val === '鑹ソ') return 'primary';
+ if (val === '鍚堟牸') return 'warning';
+ return 'danger';
+ },
+ formatData: (val) => val || '-'
+ },
+ {
+ label: "鎿嶄綔",
+ prop: "action",
+ align: "center",
+ dataType: "action",
+ operation: [
+ { name: "缂栬緫", type: "text", clickFun: (row) => handleEditRecord(row) },
+ { name: "鍒犻櫎", type: "text", clickFun: (row) => handleDeleteRecord(row) }
+ ]
+ }
];
-const getMaterialData = () => {};
-const resetMaterialFilters = () => { materialFilters.name = ""; materialFilters.type = ""; };
-const uploadMaterial = () => {};
-const changeMaterialPage = ({ page, limit }) => { materialPage.current = page; materialPage.size = limit; };
+const recordDialog = reactive({ visible: false, title: "", loading: false });
+const recordFormRef = ref(null);
+const recordForm = reactive({
+ id: null,
+ planId: null,
+ employeeId: null,
+ employeeName: "",
+ content: "",
+ completeTime: "",
+ duration: 0,
+ method: "",
+ score: 0,
+ result: "",
+ status: 1,
+ remark: ""
+});
+const recordRules = {
+ planId: [{ required: true, message: "璇烽�夋嫨鍩硅璁″垝", trigger: "change" }],
+ employeeId: [{ required: true, message: "璇烽�夋嫨鍛樺伐", trigger: "change" }],
+ completeTime: [{ required: true, message: "璇烽�夋嫨瀹屾垚鏃堕棿", trigger: "change" }]
+};
+const planOptions = ref([]);
+const employeeOptions = ref([]);
-const getPlanData = () => {};
-const resetPlanFilters = () => { planFilters.year = ""; planFilters.post = ""; };
-const addPlan = () => {};
-const changePlanPage = ({ page, limit }) => { planPage.current = page; planPage.size = limit; };
+// ==================== 閫氱敤鏂规硶 ====================
+const loadData = () => {
+ switch (activeTab.value) {
+ case 'materials':
+ getMaterialData();
+ break;
+ case 'plans':
+ getPlanData();
+ break;
+ case 'records':
+ getRecordData();
+ break;
+ }
+};
-const getRecordData = () => {};
-const resetRecordFilters = () => { recordFilters.employeeName = ""; };
-const changeRecordPage = ({ page, limit }) => { recordPage.current = page; recordPage.size = limit; };
+const handleTabChange = () => {
+ loadData();
+};
+
+// ==================== 鍩硅璧勬枡鏂规硶 ====================
+const getMaterialData = async () => {
+ materialLoading.value = true;
+ try {
+ const res = await getMaterialList({
+ pageNum: materialPage.current,
+ pageSize: materialPage.size,
+ ...materialFilters
+ });
+ if (res.code === 200) {
+ materialList.value = res.data.records || res.data.rows || [];
+ materialPage.total = res.data.total || 0;
+ }
+ } catch (error) {
+ ElMessage.error('鑾峰彇鍩硅璧勬枡澶辫触');
+ } finally {
+ materialLoading.value = false;
+ }
+};
+
+const resetMaterialFilters = () => {
+ materialFilters.name = "";
+ materialFilters.type = "";
+ materialFilters.status = null;
+ materialPage.current = 1;
+ getMaterialData();
+};
+
+const changeMaterialPage = ({ page, limit }) => {
+ materialPage.current = page;
+ materialPage.size = limit;
+ getMaterialData();
+};
+
+const resetMaterialForm = () => {
+ materialForm.id = null;
+ materialForm.name = "";
+ materialForm.type = "";
+ materialForm.fileUrl = "";
+ materialForm.fileSize = "";
+ materialForm.status = 1;
+ materialForm.remark = "";
+ if (uploadRef.value) {
+ uploadRef.value.clearFiles();
+ }
+};
+
+const openMaterialDialog = () => {
+ resetMaterialForm();
+ materialDialog.title = "涓婁紶鍩硅璧勬枡";
+ materialDialog.visible = true;
+};
+
+const handleEditMaterial = async (row) => {
+ resetMaterialForm();
+ try {
+ const res = await getMaterialDetail(row.id);
+ if (res.code === 200) {
+ Object.assign(materialForm, res.data);
+ materialDialog.title = "缂栬緫鍩硅璧勬枡";
+ materialDialog.visible = true;
+ }
+ } catch (error) {
+ ElMessage.error('鑾峰彇璧勬枡璇︽儏澶辫触');
+ }
+};
+
+const handleUploadSuccess = (response) => {
+ if (response.code === 200) {
+ materialForm.fileUrl = response.url;
+ materialForm.fileSize = formatFileSize(response.file?.size || 0);
+ ElMessage.success('鏂囦欢涓婁紶鎴愬姛');
+ } else {
+ ElMessage.error(response.msg || '涓婁紶澶辫触');
+ }
+};
+
+const handleUploadError = () => {
+ ElMessage.error('鏂囦欢涓婁紶澶辫触');
+};
+
+const beforeUpload = (file) => {
+ const maxSize = 50 * 1024 * 1024; // 50MB
+ if (file.size > maxSize) {
+ ElMessage.error('鏂囦欢澶у皬涓嶈兘瓒呰繃 50MB');
+ return false;
+ }
+ return true;
+};
+
+const formatFileSize = (size) => {
+ if (size < 1024) return size + ' B';
+ if (size < 1024 * 1024) return (size / 1024).toFixed(2) + ' KB';
+ if (size < 1024 * 1024 * 1024) return (size / (1024 * 1024)).toFixed(2) + ' MB';
+ return (size / (1024 * 1024 * 1024)).toFixed(2) + ' GB';
+};
+
+const submitMaterialForm = async () => {
+ const valid = await materialFormRef.value.validate().catch(() => false);
+ if (!valid) return;
+
+ if (!materialForm.id && !materialForm.fileUrl) {
+ ElMessage.error('璇蜂笂浼犳枃浠�');
+ return;
+ }
+
+ materialDialog.loading = true;
+ try {
+ const api = materialForm.id ? updateMaterial : uploadMaterialApi;
+ const res = await api(materialForm);
+ if (res.code === 200) {
+ ElMessage.success(materialForm.id ? '淇敼鎴愬姛' : '涓婁紶鎴愬姛');
+ materialDialog.visible = false;
+ getMaterialData();
+ }
+ } catch (error) {
+ ElMessage.error(materialForm.id ? '淇敼澶辫触' : '涓婁紶澶辫触');
+ } finally {
+ materialDialog.loading = false;
+ }
+};
+
+const handleDownload = (row) => {
+ if (row.fileUrl) {
+ // 澶勭悊URL鏍煎紡闂
+ let url = row.fileUrl;
+ // 淇绫讳技 http://host:portupload/ 鐨勯敊璇牸寮�
+ url = url.replace(/^(http:\/\/[^/]+:\d+)(upload\/)/, '$1/$2');
+ // 濡傛灉涓嶆槸瀹屾暣URL锛屾坊鍔犲墠缂�
+ if (!url.startsWith('http')) {
+ url = '/dev-api/' + url.replace(/^\//, '');
+ }
+ window.open(url, '_blank');
+ } else {
+ ElMessage.warning('鏂囦欢鍦板潃涓嶅瓨鍦�');
+ }
+};
+
+const handleDeleteMaterial = (row) => {
+ ElMessageBox.confirm(`纭鍒犻櫎璧勬枡 "${row.name}" 鍚楋紵`, "鎻愮ず", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning"
+ }).then(async () => {
+ try {
+ const res = await deleteMaterial(row.id);
+ if (res.code === 200) {
+ ElMessage.success("鍒犻櫎鎴愬姛");
+ getMaterialData();
+ }
+ } catch (error) {
+ ElMessage.error("鍒犻櫎澶辫触");
+ }
+ });
+};
+
+// ==================== 鍩硅璁″垝鏂规硶 ====================
+const getPlanData = async () => {
+ planLoading.value = true;
+ try {
+ const res = await getPlanList({
+ pageNum: planPage.current,
+ pageSize: planPage.size,
+ ...planFilters
+ });
+ if (res.code === 200) {
+ planList.value = res.data.records || res.data.rows || [];
+ planPage.total = res.data.total || 0;
+ }
+ } catch (error) {
+ ElMessage.error('鑾峰彇鍩硅璁″垝澶辫触');
+ } finally {
+ planLoading.value = false;
+ }
+};
+
+const resetPlanFilters = () => {
+ planFilters.year = "";
+ planFilters.post = "";
+ planFilters.level = "";
+ planFilters.status = null;
+ planPage.current = 1;
+ getPlanData();
+};
+
+const changePlanPage = ({ page, limit }) => {
+ planPage.current = page;
+ planPage.size = limit;
+ getPlanData();
+};
+
+const loadMaterialOptions = async () => {
+ try {
+ const res = await getMaterialList({ pageNum: 1, pageSize: 1000 });
+ if (res.code === 200) {
+ materialOptions.value = res.data.records || res.data.rows || [];
+ }
+ } catch (error) {
+ console.error('鍔犺浇鍩硅璧勬枡閫夐」澶辫触', error);
+ }
+};
+
+const resetPlanForm = () => {
+ planForm.id = null;
+ planForm.year = "";
+ planForm.post = "";
+ planForm.level = "";
+ planForm.content = "";
+ planForm.hours = 1;
+ planForm.materialIds = [];
+ planForm.status = 0;
+ planForm.remark = "";
+};
+
+const openPlanDialog = () => {
+ resetPlanForm();
+ loadMaterialOptions();
+ planDialog.title = "鍒跺畾鍩硅璁″垝";
+ planDialog.visible = true;
+};
+
+const handleEditPlan = async (row) => {
+ resetPlanForm();
+ loadMaterialOptions();
+ try {
+ const res = await getPlanDetail(row.id);
+ if (res.code === 200) {
+ Object.assign(planForm, res.data);
+ // 灏� materialIds 瀛楃涓茶浆鎹负鏁扮粍
+ if (planForm.materialIds && typeof planForm.materialIds === 'string') {
+ planForm.materialIds = planForm.materialIds.split(',').map(id => parseInt(id));
+ }
+ planDialog.title = "缂栬緫鍩硅璁″垝";
+ planDialog.visible = true;
+ }
+ } catch (error) {
+ ElMessage.error('鑾峰彇璁″垝璇︽儏澶辫触');
+ }
+};
+
+const submitPlanForm = async () => {
+ const valid = await planFormRef.value.validate().catch(() => false);
+ if (!valid) return;
+
+ planDialog.loading = true;
+ try {
+ const submitData = { ...planForm };
+ // 灏� materialIds 鏁扮粍杞崲涓洪�楀彿鍒嗛殧鐨勫瓧绗︿覆
+ if (Array.isArray(submitData.materialIds)) {
+ submitData.materialIds = submitData.materialIds.join(',');
+ }
+ const api = planForm.id ? updatePlan : addPlanApi;
+ const res = await api(submitData);
+ if (res.code === 200) {
+ ElMessage.success(planForm.id ? '淇敼鎴愬姛' : '鏂板鎴愬姛');
+ planDialog.visible = false;
+ getPlanData();
+ }
+ } catch (error) {
+ ElMessage.error(planForm.id ? '淇敼澶辫触' : '鏂板澶辫触');
+ } finally {
+ planDialog.loading = false;
+ }
+};
+
+const handleDeletePlan = (row) => {
+ ElMessageBox.confirm(`纭鍒犻櫎璇ュ煿璁鍒掑悧锛焋, "鎻愮ず", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning"
+ }).then(async () => {
+ try {
+ const res = await deletePlan(row.id);
+ if (res.code === 200) {
+ ElMessage.success("鍒犻櫎鎴愬姛");
+ getPlanData();
+ }
+ } catch (error) {
+ ElMessage.error("鍒犻櫎澶辫触");
+ }
+ });
+};
+
+// ==================== 瀹屾垚璁板綍鏂规硶 ====================
+const getRecordData = async () => {
+ recordLoading.value = true;
+ try {
+ const res = await getRecordList({
+ pageNum: recordPage.current,
+ pageSize: recordPage.size,
+ ...recordFilters
+ });
+ if (res.code === 200) {
+ recordList.value = res.data.records || res.data.rows || [];
+ recordPage.total = res.data.total || 0;
+ }
+ } catch (error) {
+ ElMessage.error('鑾峰彇瀹屾垚璁板綍澶辫触');
+ } finally {
+ recordLoading.value = false;
+ }
+};
+
+const resetRecordFilters = () => {
+ recordFilters.employeeName = "";
+ recordFilters.status = null;
+ recordPage.current = 1;
+ getRecordData();
+};
+
+const changeRecordPage = ({ page, limit }) => {
+ recordPage.current = page;
+ recordPage.size = limit;
+ getRecordData();
+};
+
+const exportRecords = async () => {
+ try {
+ const res = await exportRecord(recordFilters);
+ // 澶勭悊鏂囦欢涓嬭浇
+ const blob = new Blob([res]);
+ const link = document.createElement('a');
+ link.href = URL.createObjectURL(blob);
+ link.download = '鍩硅瀹屾垚璁板綍.xlsx';
+ link.click();
+ ElMessage.success('瀵煎嚭鎴愬姛');
+ } catch (error) {
+ ElMessage.error('瀵煎嚭澶辫触');
+ }
+};
+
+// 瀹屾垚璁板綍琛ㄥ崟鏂规硶
+const resetRecordForm = () => {
+ recordForm.id = null;
+ recordForm.planId = null;
+ recordForm.employeeId = null;
+ recordForm.employeeName = "";
+ recordForm.content = "";
+ recordForm.completeTime = "";
+ recordForm.duration = 0;
+ recordForm.method = "";
+ recordForm.score = 0;
+ recordForm.result = "";
+ recordForm.status = 1;
+ recordForm.remark = "";
+};
+
+// 鍔犺浇鍩硅璁″垝閫夐」
+const loadPlanOptions = async () => {
+ try {
+ const res = await getPlanList({ pageNum: 1, pageSize: 1000 });
+ if (res.code === 200) {
+ planOptions.value = res.data.records || res.data.rows || [];
+ }
+ } catch (error) {
+ console.error('鍔犺浇鍩硅璁″垝澶辫触', error);
+ }
+};
+
+// 鍔犺浇鍛樺伐閫夐」锛堜粠鐢ㄦ埛绠$悊鑾峰彇锛�
+const loadEmployeeOptions = async () => {
+ try {
+ const res = await listUser({ pageNum: 1, pageSize: 1000 });
+ // 鐢ㄦ埛绠$悊鎺ュ彛鐩存帴杩斿洖 rows锛屾病鏈� code 瀛楁
+ employeeOptions.value = res.rows || [];
+ } catch (error) {
+ console.error('鍔犺浇鍛樺伐鍒楄〃澶辫触', error);
+ }
+};
+
+const handlePlanChange = (val) => {
+ const selectedPlan = planOptions.value.find(item => item.id === val);
+ if (selectedPlan) {
+ recordForm.content = selectedPlan.content;
+ }
+};
+
+const handleEmployeeChange = (val) => {
+ const selectedEmployee = employeeOptions.value.find(item => item.userId === val);
+ if (selectedEmployee) {
+ recordForm.employeeName = selectedEmployee.userName;
+ }
+};
+
+const openRecordDialog = () => {
+ resetRecordForm();
+ loadPlanOptions();
+ loadEmployeeOptions();
+ recordDialog.title = "鏂板瀹屾垚璁板綍";
+ recordDialog.visible = true;
+};
+
+const handleEditRecord = async (row) => {
+ resetRecordForm();
+ try {
+ const res = await getRecordDetail(row.id);
+ if (res.code === 200) {
+ Object.assign(recordForm, res.data);
+ recordDialog.title = "缂栬緫瀹屾垚璁板綍";
+ recordDialog.visible = true;
+ }
+ } catch (error) {
+ ElMessage.error('鑾峰彇璁板綍璇︽儏澶辫触');
+ }
+};
+
+const submitRecordForm = async () => {
+ const valid = await recordFormRef.value.validate().catch(() => false);
+ if (!valid) return;
+
+ recordDialog.loading = true;
+ try {
+ const api = recordForm.id ? updateRecord : addRecordApi;
+ const res = await api(recordForm);
+ if (res.code === 200) {
+ ElMessage.success(recordForm.id ? '淇敼鎴愬姛' : '鏂板鎴愬姛');
+ recordDialog.visible = false;
+ getRecordData();
+ }
+ } catch (error) {
+ ElMessage.error(recordForm.id ? '淇敼澶辫触' : '鏂板澶辫触');
+ } finally {
+ recordDialog.loading = false;
+ }
+};
+
+const handleDeleteRecord = (row) => {
+ ElMessageBox.confirm(`纭鍒犻櫎璇ュ畬鎴愯褰曞悧锛焋, "鎻愮ず", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning"
+ }).then(async () => {
+ try {
+ const res = await deleteRecord(row.id);
+ if (res.code === 200) {
+ ElMessage.success("鍒犻櫎鎴愬姛");
+ getRecordData();
+ }
+ } catch (error) {
+ ElMessage.error("鍒犻櫎澶辫触");
+ }
+ });
+};
+
+onMounted(() => {
+ getMaterialData();
+});
</script>
<style lang="scss" scoped>
--
Gitblit v1.9.3