| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div> |
| | | <span class="search_title">å¹è®åç§°ï¼</span> |
| | | <el-input v-model="searchForm.name" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥å¹è®åç§°æç´¢" |
| | | @change="handleQuery" |
| | | clearable |
| | | :prefix-icon="Search" /> |
| | | <span class="search_title ml10">å¹è®ç±»åï¼</span> |
| | | <el-select v-model="searchForm.type" |
| | | clearable |
| | | @change="handleQuery" |
| | | style="width: 240px"> |
| | | <el-option v-for="item in knowledgeTypeOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" /> |
| | | </el-select> |
| | | <el-button type="primary" |
| | | @click="handleQuery" |
| | | style="margin-left: 10px"> |
| | | æç´¢ |
| | | </el-button> |
| | | </div> |
| | | <div> |
| | | <el-button type="primary" |
| | | @click="openForm('add')">æ°å¢å¹è®</el-button> |
| | | <el-button type="danger" |
| | | plain |
| | | @click="handleDelete">å é¤</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <PIMTable rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination" |
| | | :total="page.total" |
| | | :rowClassName="getRowClass"></PIMTable> |
| | | </div> |
| | | <!-- æ°å¢/ç¼è¾ç¥è¯å¼¹çª --> |
| | | <el-dialog v-model="dialogVisible" |
| | | :title="dialogTitle" |
| | | width="800px" |
| | | :close-on-click-modal="false"> |
| | | <el-form ref="formRef" |
| | | :model="form" |
| | | :rules="rules" |
| | | label-width="120px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å¹è®æ¥æ" |
| | | prop="trainingDate"> |
| | | <el-date-picker style="width: 100%" |
| | | v-model="form.trainingDate" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="date" |
| | | placeholder="è¯·éæ©" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="课ç¨ç¼å·" |
| | | prop="courseCode"> |
| | | <el-input v-model="form.courseCode" |
| | | disabled |
| | | placeholder="èªå¨çæ" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å¼å§æ¶é´" |
| | | prop="openingTime"> |
| | | <el-time-picker v-model="form.openingTime" |
| | | placeholder="è¯·éæ©" |
| | | value-format="HH:mm:ss" |
| | | format="HH:mm:ss" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç»ææ¶é´" |
| | | prop="endTime"> |
| | | <el-time-picker v-model="form.endTime" |
| | | placeholder="è¯·éæ©" |
| | | value-format="HH:mm:ss" |
| | | format="HH:mm:ss" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å¹è®ç®æ " |
| | | prop="trainingObjectives"> |
| | | <el-input v-model="form.trainingObjectives" |
| | | placeholder="请è¾å
¥å¹è®ç®æ " /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="åå 对象" |
| | | prop="participants"> |
| | | <el-input v-model="form.participants" |
| | | placeholder="请è¾å
¥åå 对象" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å¹è®å
容" |
| | | prop="trainingContent"> |
| | | <el-input v-model="form.trainingContent" |
| | | placeholder="请è¾å
¥å¹è®å
容" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å¹è®è®²å¸" |
| | | prop="trainingLecturer"> |
| | | <el-input v-model="form.trainingLecturer" |
| | | placeholder="请è¾å
¥å¹è®è®²å¸" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="课ç¨å¦å" |
| | | prop="projectCredits"> |
| | | <el-input v-model="form.projectCredits" |
| | | placeholder="请è¾å
¥è¯¾ç¨å¦å" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å¹è®æ¹å¼" |
| | | prop="trainingMode"> |
| | | <el-select v-model="form.trainingMode" |
| | | placeholder="è¯·éæ©å¹è®æ¹å¼" |
| | | clearable> |
| | | <el-option v-for="item in trainingModeOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å¹è®å°ç¹" |
| | | prop="placeTraining"> |
| | | <el-input v-model="form.placeTraining" |
| | | placeholder="请è¾å
¥å¹è®å°ç¹" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="课æ¶" |
| | | prop="classHour"> |
| | | <el-input v-model="form.classHour" |
| | | type="number" |
| | | min="0" |
| | | placeholder="请è¾å
¥è¯¾æ¶" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" |
| | | @click="submitForm">ç¡®å®</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- æ¥çç¥è¯è¯¦æ
å¼¹çª --> |
| | | <el-dialog v-model="viewDialogVisible" |
| | | title="å¹è®è¯¦æ
" |
| | | width="900px" |
| | | :close-on-click-modal="false"> |
| | | <div class="knowledge-detail"> |
| | | <el-descriptions :column="2" |
| | | border> |
| | | <el-descriptions-item label="å¹è®åç§°" |
| | | :span="2"> |
| | | <span class="detail-title">{{ currentKnowledge.name }}</span> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="å¹è®ç¼ç "> |
| | | {{ currentKnowledge.code }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="å¹è®ç±»å"> |
| | | <el-tag type="info"> |
| | | <!-- {{ getTypeLabel(currentKnowledge.type) }} --> |
| | | </el-tag> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="æå¨ä½ç½®"> |
| | | {{ currentKnowledge.location }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="ç®¡æ§æªæ½"> |
| | | {{ currentKnowledge.controlMeasures }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="åºåæ°é"> |
| | | {{ currentKnowledge.stockQty }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="管æ§è´£ä»»äºº"> |
| | | {{ currentKnowledge.principalUserId }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="责任人èç³»çµè¯"> |
| | | {{ currentKnowledge.principalMobile }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="é£é©ç级"> |
| | | <el-tag :type="getTypeTagType(currentKnowledge.riskLevel)"> |
| | | {{ currentKnowledge.riskLevel }} |
| | | </el-tag> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="è§æ ¼ / é£é©æè¿°"> |
| | | {{ currentKnowledge.specInfo }} |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | </div> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="viewDialogVisible = false">å
³é</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- éä»¶åè¡¨å¼¹çª --> |
| | | <FileListDialog ref="fileListRef" |
| | | v-model="fileListDialogVisible" |
| | | :show-upload-button="true" |
| | | :show-delete-button="true" |
| | | :upload-method="handleUpload" |
| | | :delete-method="handleFileDelete" |
| | | title="éä»¶å表" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import FileListDialog from "@/components/Dialog/FileListDialog.vue"; |
| | | import { |
| | | onMounted, |
| | | ref, |
| | | reactive, |
| | | toRefs, |
| | | getCurrentInstance, |
| | | computed, |
| | | } from "vue"; |
| | | import request from "@/utils/request"; |
| | | import { getToken } from "@/utils/auth"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import PIMTable from "@/components/PIMTable/PIMTable.vue"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import { |
| | | safeTrainingListPage, |
| | | safeTrainingAdd, |
| | | safeTrainingExport, |
| | | safeTrainingDel, |
| | | safeTrainingFileListPage, |
| | | safeTrainingFileAdd, |
| | | safeTrainingFileDel, |
| | | } from "@/api/safeProduction/safetyTrainingAssessment.js"; |
| | | |
| | | // 表åéªè¯è§å |
| | | const rules = { |
| | | trainingDate: [ |
| | | { required: true, message: "è¯·éæ©å¹è®æ¥æ", trigger: "change" }, |
| | | ], |
| | | openingTime: [ |
| | | { required: true, message: "è¯·éæ©å¼å§æ¶é´", trigger: "change" }, |
| | | ], |
| | | endTime: [{ required: true, message: "è¯·éæ©ç»ææ¶é´", trigger: "change" }], |
| | | trainingContent: [ |
| | | { required: true, message: "请è¾å
¥å¹è®å
容", trigger: "blur" }, |
| | | ], |
| | | trainingLecturer: [ |
| | | { required: true, message: "请è¾å
¥å¹è®è®²å¸", trigger: "blur" }, |
| | | ], |
| | | classHour: [{ required: true, message: "请è¾å
¥è¯¾æ¶", trigger: "blur" }], |
| | | }; |
| | | |
| | | // ååºå¼æ°æ® |
| | | const data = reactive({ |
| | | searchForm: { |
| | | name: "", |
| | | type: "", |
| | | }, |
| | | tableLoading: false, |
| | | page: { |
| | | current: 1, |
| | | size: 20, |
| | | total: 0, |
| | | }, |
| | | tableData: [], |
| | | selectedIds: [], |
| | | form: { |
| | | courseCode: "", // 课ç¨ç¼å· |
| | | trainingDate: "", // å¹è®æ¥æ |
| | | openingTime: "", // å¼å§æ¶é´ |
| | | endTime: "", // ç»ææ¶é´ |
| | | trainingObjectives: "", // å¹è®ç®æ |
| | | participants: "", // åå 对象 |
| | | trainingContent: "", // å¹è®å
容 |
| | | trainingLecturer: "", // å¹è®è®²å¸ |
| | | projectCredits: "", // 项ç®å¦å |
| | | trainingMode: "", // å¹è®æ¹å¼ |
| | | placeTraining: "", // å¹è®å°ç¹ |
| | | classHour: "", // è¯¾æ¶ |
| | | }, |
| | | dialogVisible: false, |
| | | dialogTitle: "", |
| | | dialogType: "add", |
| | | viewDialogVisible: false, |
| | | currentKnowledge: {}, |
| | | }); |
| | | |
| | | const { |
| | | searchForm, |
| | | tableLoading, |
| | | page, |
| | | tableData, |
| | | selectedIds, |
| | | form, |
| | | dialogVisible, |
| | | dialogTitle, |
| | | dialogType, |
| | | viewDialogVisible, |
| | | currentKnowledge, |
| | | } = toRefs(data); |
| | | const { proxy } = getCurrentInstance(); |
| | | const { safe_training_methods } = proxy.useDict("safe_training_methods"); |
| | | const trainingModeOptions = computed(() => safe_training_methods?.value || []); |
| | | const getTrainingModeLabel = val => { |
| | | const item = trainingModeOptions.value.find( |
| | | i => String(i.value) === String(val) |
| | | ); |
| | | return item ? item.label : val; |
| | | }; |
| | | // 表åå¼ç¨ |
| | | const formRef = ref(); |
| | | const riskLevelOptions = ref([ |
| | | { value: "ä½é£é©", label: "ä½é£é©" }, |
| | | { value: "ä¸è¬é£é©", label: "ä¸è¬é£é©" }, |
| | | { value: "è¾å¤§é£é©", label: "è¾å¤§é£é©" }, |
| | | { value: "é大é£é©", label: "é大é£é©" }, |
| | | ]); |
| | | |
| | | // è¡¨æ ¼åé
ç½® |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "课ç¨ç¼å·", |
| | | prop: "courseCode", |
| | | showOverflowTooltip: true, |
| | | }, |
| | | { |
| | | label: "å¹è®æ¥æ", |
| | | prop: "trainingDate", |
| | | showOverflowTooltip: true, |
| | | }, |
| | | { |
| | | label: "å¼å§æ¶é´", |
| | | prop: "openingTime", |
| | | showOverflowTooltip: true, |
| | | }, |
| | | { |
| | | label: "ç»ææ¶é´", |
| | | prop: "endTime", |
| | | showOverflowTooltip: true, |
| | | }, |
| | | { |
| | | label: "å¹è®ç®æ ", |
| | | prop: "trainingObjectives", |
| | | showOverflowTooltip: true, |
| | | }, |
| | | { |
| | | label: "åå 对象", |
| | | prop: "participants", |
| | | showOverflowTooltip: true, |
| | | }, |
| | | { |
| | | label: "å¹è®å
容", |
| | | prop: "trainingContent", |
| | | showOverflowTooltip: true, |
| | | }, |
| | | { |
| | | label: "å¹è®è®²å¸", |
| | | prop: "trainingLecturer", |
| | | showOverflowTooltip: true, |
| | | }, |
| | | { |
| | | label: "项ç®å¦å", |
| | | prop: "projectCredits", |
| | | showOverflowTooltip: true, |
| | | }, |
| | | { |
| | | label: "å¹è®æ¹å¼", |
| | | prop: "trainingMode", |
| | | showOverflowTooltip: true, |
| | | formatData: params => { |
| | | return getTrainingModeLabel(params); |
| | | }, |
| | | }, |
| | | { |
| | | label: "å¹è®å°ç¹", |
| | | prop: "placeTraining", |
| | | showOverflowTooltip: true, |
| | | }, |
| | | { |
| | | label: "课æ¶", |
| | | prop: "classHour", |
| | | showOverflowTooltip: true, |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | | fixed: "right", |
| | | width: 200, |
| | | operation: [ |
| | | { |
| | | name: "ç¼è¾", |
| | | type: "text", |
| | | clickFun: row => { |
| | | openForm("edit", row); |
| | | }, |
| | | }, |
| | | { |
| | | name: "导åº", |
| | | type: "danger", |
| | | clickFun: row => { |
| | | exportKnowledge(row); |
| | | }, |
| | | }, |
| | | { |
| | | name: "éä»¶", |
| | | type: "danger", |
| | | clickFun: row => { |
| | | downLoadFile(row); |
| | | }, |
| | | }, |
| | | // { |
| | | // name: "æ¥ç", |
| | | // type: "text", |
| | | // clickFun: row => { |
| | | // viewKnowledge(row); |
| | | // }, |
| | | // }, |
| | | ], |
| | | }, |
| | | ]); |
| | | const userList = ref([]); |
| | | // çå½å¨æ |
| | | onMounted(() => { |
| | | getList(); |
| | | startAutoRefresh(); |
| | | userListNoPage().then(res => { |
| | | userList.value = res.data; |
| | | }); |
| | | }); |
| | | |
| | | // å¤çç¨æ·éæ©åå |
| | | const handleUserChange = userId => { |
| | | const selectedUser = userList.value.find(user => user.userId === userId); |
| | | if (selectedUser) { |
| | | form.value.principalUser = selectedUser.nickName; |
| | | form.value.principalMobile = selectedUser.phonenumber; |
| | | } |
| | | }; |
| | | /** |
| | | * ä¸è½½æä»¶ |
| | | * |
| | | * @param row ä¸è½½æä»¶çç¸å
³ä¿¡æ¯å¯¹è±¡ |
| | | */ |
| | | const fileListRef = ref(null); |
| | | const fileListDialogVisible = ref(false); |
| | | const currentFileRow = ref(null); |
| | | const downLoadFile = row => { |
| | | currentFileRow.value = row; |
| | | safeTrainingFileListPage({ safeTrainingId: row.id }).then(res => { |
| | | if (fileListRef.value) { |
| | | fileListRef.value.open(res.data.records); |
| | | } |
| | | }); |
| | | }; |
| | | // ä¸ä¼ éä»¶ |
| | | const handleUpload = async () => { |
| | | if (!currentFileRow.value) { |
| | | proxy.$modal.msgWarning("请å
éæ©æ°æ®"); |
| | | return null; |
| | | } |
| | | |
| | | return new Promise(resolve => { |
| | | // å建ä¸ä¸ªéèçæä»¶è¾å
¥å
ç´ |
| | | const input = document.createElement("input"); |
| | | input.type = "file"; |
| | | input.style.display = "none"; |
| | | input.onchange = async e => { |
| | | const file = e.target.files[0]; |
| | | if (!file) { |
| | | resolve(null); |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | // ä½¿ç¨ FormData ä¸ä¼ æä»¶ |
| | | const formData = new FormData(); |
| | | formData.append("file", file); |
| | | |
| | | const uploadRes = await request({ |
| | | url: "/file/upload", |
| | | method: "post", |
| | | data: formData, |
| | | headers: { |
| | | "Content-Type": "multipart/form-data", |
| | | Authorization: `Bearer ${getToken()}`, |
| | | }, |
| | | }); |
| | | |
| | | if (uploadRes.code === 200) { |
| | | // ä¿åéä»¶ä¿¡æ¯ |
| | | const fileData = { |
| | | safeTrainingId: currentFileRow.value.id, |
| | | name: uploadRes.data.originalName || file.name, |
| | | url: uploadRes.data.tempPath || uploadRes.data.url, |
| | | }; |
| | | |
| | | const saveRes = await safeTrainingFileAdd(fileData); |
| | | if (saveRes.code === 200) { |
| | | proxy.$modal.msgSuccess("æä»¶ä¸ä¼ æå"); |
| | | // éæ°å è½½æä»¶å表 |
| | | const listRes = await safeTrainingFileListPage({ |
| | | safeTrainingId: currentFileRow.value.id, |
| | | }); |
| | | if (listRes.code === 200 && fileListRef.value) { |
| | | const fileList = (listRes.data?.records || []).map(item => ({ |
| | | name: item.name, |
| | | url: item.url, |
| | | id: item.id, |
| | | ...item, |
| | | })); |
| | | fileListRef.value.setList(fileList); |
| | | } |
| | | // è¿åæ°æä»¶ä¿¡æ¯ |
| | | resolve({ |
| | | name: fileData.name, |
| | | url: fileData.url, |
| | | id: saveRes.data?.id, |
| | | }); |
| | | } else { |
| | | proxy.$modal.msgError(saveRes.msg || "æä»¶ä¿å失败"); |
| | | resolve(null); |
| | | } |
| | | } else { |
| | | proxy.$modal.msgError(uploadRes.msg || "æä»¶ä¸ä¼ 失败"); |
| | | resolve(null); |
| | | } |
| | | } catch (error) { |
| | | proxy.$modal.msgError("æä»¶ä¸ä¼ 失败"); |
| | | resolve(null); |
| | | } finally { |
| | | document.body.removeChild(input); |
| | | } |
| | | }; |
| | | |
| | | document.body.appendChild(input); |
| | | input.click(); |
| | | }); |
| | | }; |
| | | // å é¤éä»¶ |
| | | const handleFileDelete = async row => { |
| | | try { |
| | | const res = await safeTrainingFileDel([row.id]); |
| | | if (res.code === 200) { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | // éæ°å è½½æä»¶å表 |
| | | if (currentFileRow.value && fileListRef.value) { |
| | | const listRes = await safeTrainingFileListPage({ |
| | | safeTrainingId: currentFileRow.value.id, |
| | | }); |
| | | if (listRes.code === 200) { |
| | | const fileList = (listRes.data?.records || []).map(item => ({ |
| | | name: item.name, |
| | | url: item.url, |
| | | id: item.id, |
| | | ...item, |
| | | })); |
| | | fileListRef.value.setList(fileList); |
| | | } |
| | | } |
| | | return true; // è¿å true 表示å 餿åï¼ç»ä»¶ä¼æ´æ°å表 |
| | | } else { |
| | | proxy.$modal.msgError(res.msg || "å é¤å¤±è´¥"); |
| | | return false; |
| | | } |
| | | } catch (error) { |
| | | proxy.$modal.msgError("å é¤å¤±è´¥"); |
| | | return false; |
| | | } |
| | | }; |
| | | |
| | | // å¼å§èªå¨å·æ° |
| | | const startAutoRefresh = () => { |
| | | setInterval(() => { |
| | | getList(); |
| | | }, 600000); // 10åéå·æ°ä¸æ¬¡ (10 * 60 * 1000 = 600000ms) |
| | | }; |
| | | |
| | | // æ¥è¯¢æ°æ® |
| | | const handleQuery = () => { |
| | | page.value.current = 1; |
| | | getList(); |
| | | }; |
| | | const exportKnowledge = row => { |
| | | safeTrainingExport(row) |
| | | .then(res => { |
| | | // å建Blob对象 |
| | | const blob = new Blob([res], { |
| | | type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", |
| | | }); |
| | | // å建ä¸è½½é¾æ¥ |
| | | const url = window.URL.createObjectURL(blob); |
| | | const link = document.createElement("a"); |
| | | link.href = url; |
| | | link.download = `å¹è®è®°å½_${row.courseCode}.xlsx`; |
| | | |
| | | // 模æç¹å»ä¸è½½ |
| | | document.body.appendChild(link); |
| | | link.click(); |
| | | |
| | | // æ¸
ç临æ¶å¯¹è±¡ |
| | | setTimeout(() => { |
| | | document.body.removeChild(link); |
| | | window.URL.revokeObjectURL(url); |
| | | }, 100); |
| | | |
| | | ElMessage.success("å¯¼åºæå"); |
| | | }) |
| | | .catch(err => { |
| | | console.error("导åºå¤±è´¥:", err); |
| | | ElMessage.error("导åºå¤±è´¥ï¼è¯·éè¯"); |
| | | }); |
| | | }; |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | safeTrainingListPage({ ...page.value, ...searchForm.value }) |
| | | .then(res => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | page.value.total = res.data.total; |
| | | }) |
| | | .catch(err => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | // å页å¤ç |
| | | const pagination = obj => { |
| | | page.value.current = obj.page; |
| | | page.value.size = obj.limit; |
| | | handleQuery(); |
| | | }; |
| | | |
| | | // éæ©ååå¤ç |
| | | const handleSelectionChange = selection => { |
| | | selectedIds.value = selection.map(item => item.id); |
| | | }; |
| | | |
| | | // æå¼è¡¨å |
| | | const openForm = (type, row = null) => { |
| | | dialogType.value = type; |
| | | if (type === "add") { |
| | | dialogTitle.value = "æ°å¢å¹è®"; |
| | | // é置表å |
| | | Object.assign(form.value, { |
| | | courseCode: "", // 课ç¨ç¼å· |
| | | trainingDate: "", // å¹è®æ¥æ |
| | | openingTime: "", // å¼å§æ¶é´ |
| | | endTime: "", // ç»ææ¶é´ |
| | | trainingObjectives: "", // å¹è®ç®æ |
| | | participants: "", // åå 对象 |
| | | trainingContent: "", // å¹è®å
容 |
| | | trainingLecturer: "", // å¹è®è®²å¸ |
| | | projectCredits: "", // 项ç®å¦å |
| | | trainingMode: "", // å¹è®æ¹å¼ |
| | | placeTraining: "", // å¹è®å°ç¹ |
| | | classHour: "", // è¯¾æ¶ |
| | | }); |
| | | } else if (type === "edit" && row) { |
| | | dialogTitle.value = "ç¼è¾å¹è®"; |
| | | Object.assign(form.value, { |
| | | id: row.id, |
| | | courseCode: row.courseCode, // 课ç¨ç¼å· |
| | | trainingDate: row.trainingDate, // å¹è®æ¥æ |
| | | openingTime: row.openingTime, // å¼å§æ¶é´ |
| | | endTime: row.endTime, // ç»ææ¶é´ |
| | | trainingObjectives: row.trainingObjectives, // å¹è®ç®æ |
| | | participants: row.participants, // åå 对象 |
| | | trainingContent: row.trainingContent, // å¹è®å
容 |
| | | trainingLecturer: row.trainingLecturer, // å¹è®è®²å¸ |
| | | projectCredits: row.projectCredits, // 项ç®å¦å |
| | | trainingMode: row.trainingMode, // å¹è®æ¹å¼ |
| | | placeTraining: row.placeTraining, // å¹è®å°ç¹ |
| | | classHour: row.classHour, // è¯¾æ¶ |
| | | }); |
| | | } |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | // æ¥çå¹è®è¯¦æ
|
| | | const viewKnowledge = row => { |
| | | currentKnowledge.value = { ...row }; |
| | | viewDialogVisible.value = true; |
| | | }; |
| | | |
| | | // è·åç±»åæ ç¾ç±»å |
| | | const getTypeTagType = type => { |
| | | const typeMap = { |
| | | è¾å¤§é£é©: "warning", |
| | | ä½é£é©: "info", |
| | | ä¸è¬é£é©: "info", |
| | | é大é£é©: "danger", |
| | | }; |
| | | return typeMap[type] || "info"; |
| | | }; |
| | | |
| | | // è·åæçæ ç¾ç±»å |
| | | const getEfficiencyTagType = efficiency => { |
| | | const typeMap = { |
| | | high: "success", |
| | | medium: "warning", |
| | | low: "info", |
| | | }; |
| | | return typeMap[efficiency] || "info"; |
| | | }; |
| | | |
| | | // è·åæçæ ç¾ææ¬ |
| | | const getEfficiencyLabel = efficiency => { |
| | | const efficiencyMap = { |
| | | high: "æ¾èæå", |
| | | medium: "ä¸è¬æå", |
| | | low: "轻微æå", |
| | | }; |
| | | return efficiencyMap[efficiency] || efficiency; |
| | | }; |
| | | |
| | | // è·åæçæåç¾åæ¯ |
| | | const getEfficiencyScore = efficiency => { |
| | | const scoreMap = { |
| | | high: 40, |
| | | medium: 25, |
| | | low: 15, |
| | | }; |
| | | return scoreMap[efficiency] || 0; |
| | | }; |
| | | |
| | | // è·åå¹³åèçæ¶é´ |
| | | const getTimeSaved = efficiency => { |
| | | const timeMap = { |
| | | high: "2-3天", |
| | | medium: "1-2天", |
| | | low: "0.5-1天", |
| | | }; |
| | | return timeMap[efficiency] || "æªç¥"; |
| | | }; |
| | | |
| | | /** |
| | | * è·åè¡ç±»åï¼ç¨äºå¤æé£é©ç级æ¯å¦ä¸ºé大é£é© |
| | | * @param row è¡æ°æ® |
| | | * @returns ç±»å |
| | | */ |
| | | const getRowClass = ({ row }) => { |
| | | if (row.riskLevel === "é大é£é©") { |
| | | return "danger-row"; |
| | | } |
| | | return ""; |
| | | }; |
| | | |
| | | // æäº¤å¹è®è¡¨å |
| | | const submitForm = async () => { |
| | | try { |
| | | await formRef.value.validate(); |
| | | if (dialogType.value === "add") { |
| | | // æ°å¢å¹è®å°è´¦ |
| | | safeTrainingAdd({ ...form.value }) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("æ·»å æå"); |
| | | dialogVisible.value = false; |
| | | getList(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | } else { |
| | | // æ´æ°å¹è®å°è´¦ |
| | | safeTrainingAdd({ ...form.value }) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("æ´æ°æå"); |
| | | dialogVisible.value = false; |
| | | getList(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | } |
| | | } catch (error) { |
| | | console.error("表åéªè¯å¤±è´¥:", error); |
| | | } |
| | | }; |
| | | |
| | | // å é¤å¹è® |
| | | const handleDelete = () => { |
| | | if (selectedIds.value.length === 0) { |
| | | ElMessage.warning("è¯·éæ©è¦å é¤çå¹è®"); |
| | | return; |
| | | } |
| | | |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "å é¤", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | // console.log(selectedIds.value); |
| | | safeTrainingDel(selectedIds.value).then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("å 餿å"); |
| | | selectedIds.value = []; |
| | | getList(); |
| | | } |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | // ç¨æ·åæ¶ |
| | | }); |
| | | }; |
| | | |
| | | const getKnowledgeTypeTagType = val => { |
| | | const item = knowledgeTypeOptions.value.find( |
| | | i => String(i.value) === String(val) |
| | | ); |
| | | return item?.elTagType || "info"; |
| | | }; |
| | | const handleExport = () => { |
| | | proxy.download( |
| | | "/knowledgeBase/export", |
| | | { ...searchForm.value }, |
| | | "ç¥è¯åº.xlsx" |
| | | ); |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .auto-refresh-info { |
| | | margin-bottom: 15px; |
| | | } |
| | | |
| | | .auto-refresh-info .el-alert { |
| | | border-radius: 8px; |
| | | } |
| | | |
| | | .dialog-footer { |
| | | text-align: right; |
| | | } |
| | | |
| | | .knowledge-detail { |
| | | padding: 20px 0; |
| | | } |
| | | |
| | | .detail-title { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | } |
| | | |
| | | .detail-section { |
| | | margin-top: 24px; |
| | | } |
| | | |
| | | .detail-section h4 { |
| | | margin: 0 0 12px 0; |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | border-left: 4px solid #409eff; |
| | | padding-left: 12px; |
| | | } |
| | | |
| | | .detail-content { |
| | | background: #f8f9fa; |
| | | padding: 16px; |
| | | border-radius: 6px; |
| | | line-height: 1.6; |
| | | color: #606266; |
| | | white-space: pre-wrap; |
| | | } |
| | | |
| | | .key-points { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .usage-stats { |
| | | margin-top: 16px; |
| | | } |
| | | |
| | | .stat-item { |
| | | text-align: center; |
| | | padding: 20px; |
| | | background: #f8f9fa; |
| | | border-radius: 8px; |
| | | } |
| | | |
| | | .stat-number { |
| | | font-size: 24px; |
| | | font-weight: bold; |
| | | color: #409eff; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .stat-label { |
| | | font-size: 14px; |
| | | color: #909399; |
| | | } |
| | | |
| | | :deep(.danger-row td) { |
| | | color: #e95a66 !important; |
| | | } |
| | | </style> |