spring
3 天以前 39724c7cb4801b3863bb0135057e5d300f6670be
Merge branch 'dev_New' of http://114.132.189.42:9002/r/product-inventory-management into dev_New
已添加1个文件
已修改5个文件
913 ■■■■■ 文件已修改
src/api/safeProduction/safetyTrainingAssessment.js 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/measurementEquipment/components/calibrationDia.vue 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/measurementEquipment/components/formDia.vue 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productStructure/Detail/index.vue 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/safeProduction/safetyTrainingAssessment/detail.vue 325 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/safeProduction/safetyTrainingAssessment/index.vue 415 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/safeProduction/safetyTrainingAssessment.js
@@ -67,4 +67,46 @@
        method: 'delete',
        data: ids
    })
}
}
// ç­¾åˆ°
export function safeTrainingSign(query) {
    return request({
        url: '/safeTraining/sign',
        method: 'post',
        data: query
    })
}
// æŸ¥è¯¢è¯¦æƒ…
export function safeTrainingGet(query) {
    return request({
        url: '/safeTraining/getSafeTraining',
        method: 'get',
        params: query
    })
}
// æäº¤
export function safeTrainingSave(query) {
    return request({
        url: '/safeTraining/saveSafeTraining',
        method: 'post',
        data: query
    })
}
export function safeTrainingDetailListPage(query) {
  return request({
    url: "/safeTrainingDetails/page",
    method: "get",
    params: query,
  });
}
// å¯¼å‡º
export function safeTrainingDetailExport(query) {
    return request({
        url: '/safeTrainingDetails/export',
        method: 'post',
        data: query,
        responseType: 'blob'
    })
}
src/views/equipmentManagement/measurementEquipment/components/calibrationDia.vue
@@ -51,11 +51,14 @@
                        </el-form-item>
                    </el-col>
                    <el-col :span="12">
                        <el-form-item label="有效期:" prop="valid">
                        <el-form-item label="有效日期(天):" prop="valid">
                            <el-input
                                v-model="form.valid"
                                placeholder="请输入"
                                type="number"
                                placeholder="请输入有效期天数"
                                clearable
                                :min="1"
                                @input="handleValidInput"
                            >
                                <template #append>日</template>
                            </el-input>
@@ -152,7 +155,32 @@
    rules: {
        code: [{required: true, message: "请输入", trigger: "blur"}],
        name: [{required: true, message: "请输入", trigger: "blur"}],
        valid: [{required: true, message: "请输入", trigger: "blur"}],
        valid: [
            {required: true, message: "请输入", trigger: "blur"},
            {
                validator: (rule, value, callback) => {
                    if (value === '' || value === null || value === undefined) {
                        callback();
                        return;
                    }
                    const numValue = Number(value);
                    if (isNaN(numValue)) {
                        callback(new Error('请输入有效的数字'));
                        return;
                    }
                    if (numValue <= 0) {
                        callback(new Error('只能输入正数'));
                        return;
                    }
                    if (!Number.isInteger(numValue)) {
                        callback(new Error('请输入整数'));
                        return;
                    }
                    callback();
                },
                trigger: 'blur'
            }
        ],
        recordDate: [{required: true, message: "请选择", trigger: "change"}],
        userId: [{required: true, message: "请选择", trigger: "change"}],
        entryDate: [{required: true, message: "请选择", trigger: "change"}],
@@ -233,6 +261,27 @@
    }
}
// å¤„理有效日期输入,只允许正整数
const handleValidInput = (value) => {
    if (value === '' || value === null || value === undefined) {
        form.value.valid = '';
        return;
    }
    // è½¬æ¢ä¸ºå­—符串并移除所有非数字字符(包括负号、小数点等)
    const numStr = String(value).replace(/[^0-9]/g, '');
    if (numStr === '') {
        form.value.valid = '';
        return;
    }
    const numValue = parseInt(numStr, 10);
    // ç¡®ä¿æ˜¯æ­£æ•´æ•°ï¼ˆå¤§äºŽ0)
    if (numValue > 0 && !isNaN(numValue)) {
        form.value.valid = numValue;
    } else {
        form.value.valid = '';
    }
}
const submitForm = () => {
    proxy.$refs["formRef"].validate(valid => {
        if (valid) {
src/views/equipmentManagement/measurementEquipment/components/formDia.vue
@@ -74,8 +74,11 @@
            <el-form-item label="有效日期(天):" prop="valid">
              <el-input
                  v-model="form.valid"
                  type="number"
                  placeholder="请输入有效期天数"
                  clearable
                  :min="1"
                  @input="handleValidInput"
              >
              <template #append>日</template>
              </el-input>
@@ -192,7 +195,32 @@
    instationLocation: [{required: true, message: "请输入", trigger: "blur"}],
    mostDate: [{required: true, message: "请选择", trigger: "change"}],
    cycle: [{required: true, message: "请选择", trigger: "blur"}],
    valid: [{required: true, message: "请输入", trigger: "blur"}],
    valid: [
      {required: true, message: "请输入", trigger: "blur"},
      {
        validator: (rule, value, callback) => {
          if (value === '' || value === null || value === undefined) {
            callback();
            return;
          }
          const numValue = Number(value);
          if (isNaN(numValue)) {
            callback(new Error('请输入有效的数字'));
            return;
          }
          if (numValue <= 0) {
            callback(new Error('只能输入正数'));
            return;
          }
          if (!Number.isInteger(numValue)) {
            callback(new Error('请输入整数'));
            return;
          }
          callback();
        },
        trigger: 'blur'
      }
    ],
    unit: [{required: true, message: "请输入", trigger: "blur"}],
    }
})
@@ -254,6 +282,27 @@
    }
}
// å¤„理有效日期输入,只允许正整数
const handleValidInput = (value) => {
    if (value === '' || value === null || value === undefined) {
        form.value.valid = '';
        return;
    }
    // è½¬æ¢ä¸ºå­—符串并移除所有非数字字符(包括负号、小数点等)
    const numStr = String(value).replace(/[^0-9]/g, '');
    if (numStr === '') {
        form.value.valid = '';
        return;
    }
    const numValue = parseInt(numStr, 10);
    // ç¡®ä¿æ˜¯æ­£æ•´æ•°ï¼ˆå¤§äºŽ0)
    if (numValue > 0 && !isNaN(numValue)) {
        form.value.valid = numValue;
    } else {
        form.value.valid = '';
    }
}
const submitForm = () => {
    proxy.$refs["formRef"].validate(valid => {
        if (valid) {
src/views/productionManagement/productStructure/Detail/index.vue
@@ -115,7 +115,7 @@
                    <el-input v-model="row.unit"
                              placeholder="请输入单位"
                              clearable
                               :disabled="!dataValue.isEdit || dataValue.dataList.some(item => (item as any).tempId === row.tempId)" />
                              :disabled="!dataValue.isEdit || dataValue.dataList.some(item => (item as any).tempId === row.tempId)" />
                  </el-form-item>
                </template>
              </el-table-column>
@@ -264,15 +264,20 @@
    const productData = row[0];
    //  æœ€å¤–层组件中,与当前产品相同的产品只能有一个
    const isTopLevel = dataValue.dataList.some(item => (item as any).tempId === dataValue.currentRowName);
    const isTopLevel = dataValue.dataList.some(
      item => (item as any).tempId === dataValue.currentRowName
    );
    if (isTopLevel) {
      if (productData.productName === tableData[0].productName &&
        productData.model === tableData[0].model) {
      if (
        productData.productName === tableData[0].productName &&
        productData.model === tableData[0].model
      ) {
        //  æŸ¥æ‰¾æ˜¯å¦å·²ç»æœ‰å…¶ä»–顶层行已经是这个产品
        const hasOther = dataValue.dataList.some(item =>
          (item as any).tempId !== dataValue.currentRowName &&
          (item as any).productName === tableData[0].productName &&
          (item as any).model === tableData[0].model
        const hasOther = dataValue.dataList.some(
          item =>
            (item as any).tempId !== dataValue.currentRowName &&
            (item as any).productName === tableData[0].productName &&
            (item as any).model === tableData[0].model
        );
        if (hasOther) {
          ElMessage.warning("最外层和当前产品一样的一级只能有一个");
@@ -390,7 +395,7 @@
    }
  };
  const removeItem = (tempId:string) => {
  const removeItem = (tempId: string) => {
    // å…ˆå°è¯•从顶层删除
    const topIndex = dataValue.dataList.findIndex(item => item.tempId === tempId);
    if (topIndex !== -1) {
src/views/safeProduction/safetyTrainingAssessment/detail.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,325 @@
<template>
  <div class="app-container">
    <PageHeader content="培训记录">
    </PageHeader>
    <div class="search_form">
      <div class="search_item">
        <span class="search_title">人员名称:</span>
        <el-input v-model="searchForm.searchText"
                  style="width: 240px"
                  placeholder="输入客户名称搜索"
                  @change="searchName"
                  clearable
                  prefix-icon="Search" />
        <el-button type="primary"
                   @click="searchName"
                   style="margin-left: 10px">搜索</el-button>
      </div>
      <div class="search_item">
        <span class="search_title">年份:</span>
        <el-date-picker v-model="searchForm.invoiceDate"
                        type="year"
                        @change="searchDate"
                        placeholder="选择年">
        </el-date-picker>
        <el-button type="primary"
                   @click="searchDate"
                   style="margin-left: 10px">搜索</el-button>
        <el-button type="primary"
                   @click="exportData"
                   style="margin-left: 20px;margin-right: 20px">导出</el-button>
      </div>
    </div>
    <div style="display: flex">
      <div class="table_list">
        <el-table :data="tableData"
                  border
                  v-loading="tableLoading"
                  :row-key="(row) => row.id"
                  @row-click="rowClickMethod"
                  height="calc(100vh - 18.5em)">
          <el-table-column align="center"
                           label="序号"
                           type="index"
                           width="60" />
          <el-table-column label="名称"
                           prop="nickName"
                           show-overflow-tooltip
                           width="200" />
          <el-table-column label="所属部门"
                           prop="deptNames"
                           show-overflow-tooltip
                           width="200" />
          <el-table-column label="联系方式"
                           prop="phonenumber"
                           show-overflow-tooltip
                           width="200" />
          <!-- <el-table-column label="email"
                           prop="email"
                           show-overflow-tooltip
                           width="200" /> -->
          <!-- <el-table-column label="应收金额(元)"
                           prop="unReceiptPaymentAmount"
                           show-overflow-tooltip
                           width="200">
            <template #default="{ row, column }">
              <el-text type="danger">
                {{ formattedNumber(row, column, row.unReceiptPaymentAmount) }}
              </el-text>
            </template>
          </el-table-column> -->
        </el-table>
        <pagination v-show="total > 0"
                    :total="total"
                    layout="total, sizes, prev, pager, next, jumper"
                    :page="page.current"
                    :limit="page.size"
                    @pagination="paginationChange" />
      </div>
      <div class="table_list">
        <el-table :data="receiptRecord"
                  border
                  :row-key="(row) => row.id"
                  height="calc(100vh - 18.5em)">
          <el-table-column align="center"
                           label="序号"
                           type="index"
                           width="60" />
          <el-table-column label="培训日期"
                           prop="trainingDate"
                           show-overflow-tooltip />
          <el-table-column label="培训内容"
                           prop="trainingContent"
                           show-overflow-tooltip />
          <el-table-column label="培训课时"
                           prop="classHour"
                           show-overflow-tooltip />
          <el-table-column label="考核结果"
                           prop="examinationResults"
                           show-overflow-tooltip>
            <template #default="{ row }">
              <el-tag :type="row.examinationResults === '合格' ? 'success' : 'danger'">
                {{ row.examinationResults }}
              </el-tag>
            </template>
          </el-table-column>
        </el-table>
      </div>
    </div>
  </div>
</template>
<script setup>
  import { onMounted, ref } from "vue";
  import { invoiceLedgerSalesAccount } from "@/api/salesManagement/invoiceLedger.js";
  import { customerInteractions } from "@/api/salesManagement/receiptPayment.js";
  import Pagination from "@/components/PIMTable/Pagination.vue";
  import {
    safeTrainingDetailListPage,
    safeTrainingDetailExport,
  } from "@/api/safeProduction/safetyTrainingAssessment.js";
  import { userListNoPage } from "@/api/system/user.js";
  const { proxy } = getCurrentInstance();
  const tableData = ref([]);
  const receiptRecord = ref([]);
  const tableLoading = ref(false);
  const page = reactive({
    current: 1,
    size: 100,
  });
  const recordPage = reactive({
    current: 1,
    size: 100,
  });
  const total = ref(0);
  const recordTotal = ref(0);
  const data = reactive({
    searchForm: {
      searchText: "",
      invoiceDate: "",
    },
  });
  const customerId = ref("");
  const { searchForm } = toRefs(data);
  const originReceiptRecord = ref([]);
  // æŸ¥è¯¢åˆ—表
  /** æœç´¢æŒ‰é’®æ“ä½œ */
  const handleQuery = () => {
    page.current = 1;
    getList();
  };
  const paginationChange = obj => {
    page.current = obj.page;
    page.size = obj.limit;
    getList();
  };
  const tableDataCopy = ref([]);
  const getList = () => {
    tableLoading.value = true;
    userListNoPage({}).then(res => {
      console.log("res", res.data);
      tableData.value = res.data;
      tableDataCopy.value = res.data;
      if (tableData.value.length > 0) {
        customerId.value = tableData.value[0].userId;
        receiptPaymentList(customerId.value);
        tableLoading.value = false;
      }
    });
  };
  const exportData = () => {
    safeTrainingDetailExport({
      userId: customerId.value,
    })
      .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 = `记录详情_${tableData.value[0].nickName}.docx`;
        // æ¨¡æ‹Ÿç‚¹å‡»ä¸‹è½½
        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 formattedNumber = (row, column, cellValue) => {
    return parseFloat(cellValue).toFixed(2);
  };
  // ä¸»è¡¨åˆè®¡æ–¹æ³•
  const summarizeMainTable = param => {
    return proxy.summarizeTable(
      param,
      ["invoiceTotal", "receiptPaymentAmount", "unReceiptPaymentAmount"],
      {
        ticketsNum: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
        futureTickets: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
      }
    );
  };
  // å­è¡¨åˆè®¡æ–¹æ³•
  const summarizeMainTable1 = param => {
    var summarizeTable = proxy.summarizeTable(
      param,
      ["invoiceAmount", "receiptAmount", "unReceiptAmount"],
      {
        ticketsNum: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
        futureTickets: { noDecimal: true }, // ä¸ä¿ç•™å°æ•°
      }
    );
    // å–最后一行数据;
    if (receiptRecord.value?.length > 0) {
      const index = tableData.value.findIndex(
        item => item.id == customerId.value
      );
      summarizeTable[summarizeTable.length - 1] =
        tableData.value[index].unReceiptPaymentAmount.toFixed(2);
    } else {
      summarizeTable[summarizeTable.length - 1] = 0.0;
    }
    return summarizeTable;
  };
  const goBack = () => {
    proxy.$router.push({
      path: "/safeProduction/safetyTrainingAssessment",
    });
  };
  const searchName = () => {
    tableData.value = tableDataCopy.value;
    if (searchForm.value.searchText) {
      tableData.value = tableData.value.filter(item =>
        item.nickName.includes(searchForm.value.searchText)
      );
      customerId.value = tableData.value[0].userId;
    }
    receiptPaymentList(customerId.value);
  };
  const dateFormat = (date, format = "yyyy-MM-dd") => {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");
    return format.replace("yyyy", year).replace("MM", month).replace("dd", day);
  };
  const searchDate = () => {
    receiptRecord.value = originReceiptRecordCopy.value;
    console.log("searchForm.value.invoiceDate", searchForm.value.invoiceDate);
    if (searchForm.value.invoiceDate) {
      const year = dateFormat(searchForm.value.invoiceDate, "yyyy");
      receiptRecord.value = receiptRecord.value.filter(item => {
        console.log("item.trainingDate", item.trainingDate);
        return item.trainingDate.includes(year);
      });
    }
  };
  const originReceiptRecordCopy = ref([]);
  const receiptPaymentList = id => {
    const param = {
      userId: id,
    };
    console.log("param", param);
    safeTrainingDetailListPage(param).then(res => {
      originReceiptRecord.value = res.data.records;
      handlePagination({ page: 1, limit: recordPage.size });
      recordTotal.value = res.data.length;
    });
  };
  // æ±‡æ¬¾è®°å½•列表分页
  const recordPaginationChange = pagination => {
    handlePagination(pagination);
  };
  const rowClickMethod = row => {
    customerId.value = row.userId;
    receiptPaymentList(customerId.value);
  };
  const handlePagination = ({ page, limit }) => {
    recordPage.current = page;
    recordPage.size = limit;
    const start = (page - 1) * limit;
    const end = start + limit;
    receiptRecord.value = originReceiptRecord.value.slice(start, end);
    originReceiptRecordCopy.value = originReceiptRecord.value.slice(start, end);
  };
  onMounted(() => {
    getList();
  });
</script>
<style scoped lang="scss">
  .table_list {
    width: 50%;
  }
  .search_back {
    cursor: pointer;
    color: #0f497e;
  }
  .search_item {
    width: 50%;
    display: flex;
    align-items: center;
    justify-content: flex-start;
    margin-right: 20px;
  }
</style>
src/views/safeProduction/safetyTrainingAssessment/index.vue
@@ -2,23 +2,14 @@
  <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>
        <span class="search_title">培训日期:</span>
        <el-date-picker v-model="searchForm.trainingDate"
                        value-format="YYYY-MM-DD"
                        format="YYYY-MM-DD"
                        @change="handleQuery"
                        type="date"
                        placeholder="请选择"
                        clearable />
        <el-button type="primary"
                   @click="handleQuery"
                   style="margin-left: 10px">
@@ -28,12 +19,24 @@
      <div>
        <el-button type="primary"
                   @click="openForm('add')">新增培训</el-button>
        <el-button type="primary"
                   @click="opendetail">培训记录</el-button>
        <el-button type="danger"
                   plain
                   @click="handleDelete">删除</el-button>
      </div>
    </div>
    <div class="table_list">
      <el-tabs v-model="searchForm.state"
               @tab-click="tabhandleQuery">
        <el-tab-pane label="未开始"
                     :name="0"></el-tab-pane>
        <el-tab-pane label="进行中"
                     :name="1"></el-tab-pane>
        <el-tab-pane label="已结束"
                     :name="2"></el-tab-pane>
      </el-tabs>
      <!-- state    çŠ¶æ€(0:未开始1:进行中;2:已结束)     -->
      <PIMTable rowKey="id"
                :column="tableColumn"
                :tableData="tableData"
@@ -135,6 +138,8 @@
            <el-form-item label="课程学分"
                          prop="projectCredits">
              <el-input v-model="form.projectCredits"
                        type="number"
                        min="0"
                        placeholder="请输入课程学分" />
            </el-form-item>
          </el-col>
@@ -181,51 +186,164 @@
    </el-dialog>
    <!-- æŸ¥çœ‹çŸ¥è¯†è¯¦æƒ…弹窗 -->
    <el-dialog v-model="viewDialogVisible"
               title="培训详情"
               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-descriptions size="mini"
                         style="margin-left: 60px;"
                         :column="3">
          <el-descriptions-item label="课程编号:">{{ currentKnowledge.courseCode }}</el-descriptions-item>
          <el-descriptions-item label="培训内容:">{{ currentKnowledge.trainingContent }}</el-descriptions-item>
          <el-descriptions-item label="状态:">
            <el-tag :type="currentKnowledge.status === 0 ? 'success' : (currentKnowledge.status === 1 ? 'success' : 'info')">
              {{ currentKnowledge.status === 0 ? '未开始' : (currentKnowledge.status === 1 ? '进行中' : '已结束') }}
            </el-tag>
          </el-descriptions-item>
          <el-descriptions-item label="所在位置">
            {{ currentKnowledge.location }}
          <el-descriptions-item label="培训讲师:">
            {{ currentKnowledge.trainingLecturer }}
          </el-descriptions-item>
          <el-descriptions-item label="管控措施">
            {{ currentKnowledge.controlMeasures }}
          <el-descriptions-item label="培训开始时间:">
            {{ currentKnowledge.trainingDate + ' ' + currentKnowledge.openingTime }}
          </el-descriptions-item>
          <el-descriptions-item label="库存数量">
            {{ currentKnowledge.stockQty }}
          <el-descriptions-item label="培训结束时间:">
            {{ currentKnowledge.trainingDate + ' ' + currentKnowledge.endTime }}
          </el-descriptions-item>
          <el-descriptions-item label="管控责任人">
            {{ currentKnowledge.principalUserId }}
          <el-descriptions-item label="培训目标:">
            {{ currentKnowledge.trainingObjectives }}
          </el-descriptions-item>
          <el-descriptions-item label="责任人联系电话">
            {{ currentKnowledge.principalMobile }}
          <el-descriptions-item label="参加对象:">
            {{ currentKnowledge.participants }}
          </el-descriptions-item>
          <el-descriptions-item label="风险等级">
            <el-tag :type="getTypeTagType(currentKnowledge.riskLevel)">
              {{ currentKnowledge.riskLevel }}
          <el-descriptions-item label="培训方式:">
            <el-tag type="primary">
              {{ getTrainingModeLabel(currentKnowledge.trainingMode) }}
            </el-tag>
          </el-descriptions-item>
          <el-descriptions-item label="规格 / é£Žé™©æè¿°">
            {{ currentKnowledge.specInfo }}
          <el-descriptions-item label="培训地点:">
            {{ currentKnowledge.placeTraining }}
          </el-descriptions-item>
          <el-descriptions-item label="课时:">
            {{ currentKnowledge.classHour }}
          </el-descriptions-item>
          <el-descriptions-item label="课程学分:">
            {{ currentKnowledge.projectCredits }}
          </el-descriptions-item>
          <el-descriptions-item label="报名人数:">
            {{ currentKnowledge.nums }}
          </el-descriptions-item>
          <el-descriptions-item label="附件列表:">
            <el-button type="primary"
                       size="small"
                       @click="downLoadFile(endform)">附件列表</el-button>
          </el-descriptions-item>
        </el-descriptions>
        <el-divider style="margin: 20px 0;" />
        <el-form ref="formRef"
                 :model="form"
                 :rules="rules"
                 label-width="130px">
          <el-row :gutter="20">
            <el-col :span="12">
              <el-form-item label="评价人:"
                            prop="courseCode">
                <el-input v-model="endform.assessmentUserName"
                          disabled
                          placeholder="请选择评价人" />
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="评价时间:"
                            prop="trainingDate">
                <el-date-picker style="width: 100%"
                                disabled
                                v-model="endform.assessmentDate"
                                value-format="YYYY-MM-DD"
                                format="YYYY-MM-DD"
                                type="date"
                                placeholder="请选择"
                                clearable />
              </el-form-item>
            </el-col>
          </el-row>
          <el-row :gutter="20">
            <el-col :span="12">
              <el-form-item label="考核方式:"
                            prop="assessmentMethod">
                <el-input v-model="endform.assessmentMethod"
                          placeholder="请选择考核方式" />
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="本次课程综合评价:"
                            prop="comprehensiveAssessment">
                <el-input v-model="endform.comprehensiveAssessment"
                          placeholder="请输入本次课程综合评价" />
              </el-form-item>
            </el-col>
          </el-row>
          <el-form-item label="培训摘要:"
                        prop="trainingAbstract">
            <el-input v-model="endform.trainingAbstract"
                      type="textarea"
                      :rows="2"
                      placeholder="请输入培训摘要" />
          </el-form-item>
          <!-- <el-row :gutter="30">
            <el-col :span="24">
              <el-form-item label="附件材料:"
                            prop="remark">
                <el-upload v-model:file-list="fileList"
                           :action="upload.url"
                           multiple
                           ref="fileUpload"
                           auto-upload
                           :headers="upload.headers"
                           :before-upload="handleBeforeUpload"
                           :on-error="handleUploadError"
                           :on-success="handleUploadSuccess"
                           :on-remove="handleRemove">
                  <el-button type="primary"
                             v-if="operationType !== 'view'">上传</el-button>
                  <template #tip
                            v-if="operationType !== 'view'">
                    <div class="el-upload__tip">
                      æ–‡ä»¶æ ¼å¼æ”¯æŒ
                      doc,docx,xls,xlsx,ppt,pptx,pdf,txt,xml,jpg,jpeg,png,gif,bmp,rar,zip,7z
                    </div>
                  </template>
                </el-upload>
              </el-form-item>
            </el-col>
          </el-row> -->
        </el-form>
        <el-table style="margin-top: 20px;"
                  :data="endform.safeTrainingDetailsDtoList"
                  border
                  fit
                  highlight-current-row>
          <el-table-column prop="nickName"
                           label="姓名" />
          <el-table-column prop="phonenumber"
                           label="电话号码" />
          <el-table-column prop="examinationResults"
                           label="考核结果">
            <template #default="scope">
              <el-select v-model="scope.row.examinationResults"
                         placeholder="请选择考核结果">
                <el-option label="合格"
                           value="合格" />
                <el-option label="不合格"
                           value="不合格" />
              </el-select>
            </template>
          </el-table-column>
        </el-table>
      </div>
      <template #footer>
        <span class="dialog-footer">
          <el-button type="primary"
                     @click="submitForm2">提交</el-button>
          <el-button @click="viewDialogVisible = false">关闭</el-button>
        </span>
      </template>
@@ -265,7 +383,13 @@
    safeTrainingFileListPage,
    safeTrainingFileAdd,
    safeTrainingFileDel,
    safeTrainingSign,
    safeTrainingGet,
    safeTrainingSave,
  } from "@/api/safeProduction/safetyTrainingAssessment.js";
  import useUserStore from "@/store/modules/user";
  import dayjs from "dayjs";
  const userStore = useUserStore();
  // è¡¨å•验证规则
  const rules = {
@@ -284,12 +408,17 @@
    ],
    classHour: [{ required: true, message: "请输入课时", trigger: "blur" }],
  };
  const upload = reactive({
    // ä¸Šä¼ çš„地址
    url: import.meta.env.VITE_APP_BASE_API + "/file/upload",
    // è®¾ç½®ä¸Šä¼ çš„请求头部
    headers: { Authorization: "Bearer " + getToken() },
  });
  // å“åº”式数据
  const data = reactive({
    searchForm: {
      name: "",
      type: "",
      trainingDate: "",
      state: 0,
    },
    tableLoading: false,
    page: {
@@ -342,6 +471,13 @@
    );
    return item ? item.label : val;
  };
  // åˆ‡æ¢tab查询
  const tabhandleQuery = val => {
    searchForm.value.state = val.paneName;
    console.log(searchForm.value.state, "searchForm.value.state");
    handleQuery();
  };
  // è¡¨å•引用
  const formRef = ref();
  const riskLevelOptions = ref([
@@ -351,56 +487,69 @@
    { value: "重大风险", label: "重大风险" },
  ]);
  const fileList = ref([]);
  // è¡¨æ ¼åˆ—配置
  const tableColumn = ref([
    {
      label: "课程编号",
      prop: "courseCode",
      width: 150,
      showOverflowTooltip: true,
    },
    {
      label: "培训日期",
      prop: "trainingDate",
      width: 120,
      showOverflowTooltip: true,
    },
    {
      label: "开始时间",
      prop: "openingTime",
      width: 120,
      showOverflowTooltip: true,
    },
    {
      label: "结束时间",
      prop: "endTime",
      width: 120,
      showOverflowTooltip: true,
    },
    {
      label: "培训目标",
      prop: "trainingObjectives",
      width: 200,
      showOverflowTooltip: true,
    },
    {
      label: "参加对象",
      prop: "participants",
      width: 200,
      showOverflowTooltip: true,
    },
    {
      label: "培训内容",
      prop: "trainingContent",
      width: 200,
      showOverflowTooltip: true,
    },
    {
      label: "培训讲师",
      prop: "trainingLecturer",
      width: 200,
      showOverflowTooltip: true,
    },
    {
      label: "项目学分",
      prop: "projectCredits",
      width: 120,
      showOverflowTooltip: true,
    },
    {
      label: "培训方式",
      prop: "trainingMode",
      width: 120,
      showOverflowTooltip: true,
      formatData: params => {
        return getTrainingModeLabel(params);
@@ -409,11 +558,19 @@
    {
      label: "培训地点",
      prop: "placeTraining",
      width: 200,
      showOverflowTooltip: true,
    },
    {
      label: "课时",
      prop: "classHour",
      width: 120,
      showOverflowTooltip: true,
    },
    {
      label: "报名人数",
      prop: "nums",
      width: 120,
      showOverflowTooltip: true,
    },
    {
@@ -421,27 +578,47 @@
      label: "操作",
      align: "center",
      fixed: "right",
      width: 200,
      width: 300,
      operation: [
        {
          name: "签到",
          type: "text",
          disabled: row => row.state !== 1,
          clickFun: row => {
            signIn(row);
          },
        },
        {
          name: "编辑",
          type: "text",
          disabled: row => row.state !== 0,
          clickFun: row => {
            openForm("edit", row);
          },
        },
        {
          name: "导出",
          type: "danger",
          type: "text",
          clickFun: row => {
            exportKnowledge(row);
          },
          color: "#C49000",
        },
        {
          name: "附件",
          type: "danger",
          type: "text",
          clickFun: row => {
            downLoadFile(row);
          },
          color: "#007AFF",
        },
        {
          name: "结果明细",
          type: "text",
          // disabled: row => row.state !== 2,
          clickFun: row => {
            viewResultDetail(row);
          },
        },
        // {
@@ -457,12 +634,133 @@
  const userList = ref([]);
  // ç”Ÿå‘½å‘¨æœŸ
  onMounted(() => {
    getCurrentFactoryName();
    getList();
    startAutoRefresh();
    userListNoPage().then(res => {
      userList.value = res.data;
    });
  });
  const endform = ref({
    assessmentUserId: "", //评价人
    assessmentUserName: "", //评价人姓名
    assessmentMethod: "", //考核方式
    assessmentDate: "", //评价时间
    comprehensiveAssessment: "", //综合评价
    trainingAbstract: "", //培训摘要
    safeTrainingFileList: [], //培训附件
    safeTrainingDetailsDtoList: [], //考核结果详情
  });
  const operationType = ref("edit");
  const viewResultDetail = row => {
    // fileList.value = [];
    operationType.value = "edit";
    safeTrainingGet({ id: row.id }).then(res => {
      if (res.code === 200) {
        console.log(res.data, "res.data");
        currentKnowledge.value = JSON.parse(JSON.stringify(res.data));
        currentKnowledge.value.nums = row.nums;
        viewDialogVisible.value = true;
        endform.value = { ...res.data };
        endform.value.assessmentUserName = endform.value.assessmentUserName
          ? endform.value.assessmentUserName
          : currentUserName.value;
        endform.value.assessmentUserId = endform.value.assessmentUserId
          ? endform.value.assessmentUserId
          : currentUserId.value;
        endform.value.assessmentDate = dayjs().format("YYYY-MM-DD");
      } else {
        proxy.$modal.msgError(res.msg || "查询详情失败");
      }
    });
  };
  // ä¸Šä¼ å‰æ ¡æ£€
  function handleBeforeUpload(file) {
    proxy.$modal.loading("正在上传文件,请稍候...");
    return true;
  }
  // ä¸Šä¼ å¤±è´¥
  function handleUploadError(err) {
    proxy.$modal.msgError("上传文件失败");
    proxy.$modal.closeLoading();
  }
  // ä¸Šä¼ æˆåŠŸå›žè°ƒ
  function handleUploadSuccess(res, file, uploadFiles) {
    proxy.$modal.closeLoading();
    if (res.code === 200) {
      // ç¡®ä¿ tempFileIds å­˜åœ¨ä¸”为数组
      if (!endform.value.safeTrainingFileList) {
        endform.value.safeTrainingFileList = [];
      }
      endform.value.safeTrainingFileList.push({
        id: res.data.tempId,
        fileName: res.data.originalName,
        url: res.data.tempPath,
        safeTrainingId: currentKnowledge.value.id,
      });
      proxy.$modal.msgSuccess("上传成功");
    } else {
      proxy.$modal.msgError(res.msg);
      proxy.$refs.fileUpload.handleRemove(file);
    }
  }
  // ç§»é™¤æ–‡ä»¶
  function handleRemove(file) {
    if (operationType.value === "edit") {
      let index = endform.value.safeTrainingFileList.findIndex(
        item => item.fileName === file.name
      );
      if (index !== -1) {
        endform.value.safeTrainingFileList.splice(index, 1);
      }
    }
  }
  const submitForm2 = () => {
    endform.value.safeTrainingDetailsDtoList.forEach((item, index) => {
      if (!item.examinationResults) {
        proxy.$modal.msgError(`请选择${item.nickName}的考核结果`);
        return;
      }
    });
    console.log(endform.value, "endform.value");
    proxy.$modal.loading("正在提交,请稍候...");
    safeTrainingSave(endform.value).then(res => {
      proxy.$modal.closeLoading();
      if (res.code === 200) {
        proxy.$modal.msgSuccess("提交成功");
        getList();
        viewDialogVisible.value = false;
      } else {
        proxy.$modal.msgError(res.msg || "提交失败");
      }
    });
  };
  const opendetail = row => {
    proxy.$router.push({
      path: "/safeProduction/safetyTrainingAssessmentDetail",
    });
  };
  const signIn = row => {
    ElMessageBox.confirm("确认签到吗?", "提示", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning",
    }).then(() => {
      safeTrainingSign({
        safeTrainingId: row.id,
        userId: currentUserId.value,
      }).then(res => {
        if (res.code === 200) {
          proxy.$modal.msgSuccess("签到成功");
          getList();
        } else {
          proxy.$modal.msgError(res.msg || "签到失败");
        }
      });
    });
  };
  // å¤„理用户选择变化
  const handleUserChange = userId => {
@@ -627,7 +925,7 @@
        const url = window.URL.createObjectURL(blob);
        const link = document.createElement("a");
        link.href = url;
        link.download = `培训记录_${row.courseCode}.xlsx`;
        link.download = `培训记录_${row.courseCode}.docx`;
        // æ¨¡æ‹Ÿç‚¹å‡»ä¸‹è½½
        document.body.appendChild(link);
@@ -670,6 +968,13 @@
  const handleSelectionChange = selection => {
    selectedIds.value = selection.map(item => item.id);
  };
  const currentUserId = ref("");
  const currentUserName = ref("");
  const getCurrentFactoryName = async () => {
    let res = await userStore.getInfo();
    currentUserId.value = res.user.userId;
    currentUserName.value = res.user.nickName;
  };
  // æ‰“开表单
  const openForm = (type, row = null) => {
@@ -710,12 +1015,6 @@
      });
    }
    dialogVisible.value = true;
  };
  // æŸ¥çœ‹åŸ¹è®­è¯¦æƒ…
  const viewKnowledge = row => {
    currentKnowledge.value = { ...row };
    viewDialogVisible.value = true;
  };
  // èŽ·å–ç±»åž‹æ ‡ç­¾ç±»åž‹