From 03e1f933ce9771a7cdacddbff5be7186ba1d4718 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期四, 05 二月 2026 17:29:02 +0800
Subject: [PATCH] 安全培训考核更正名字错字

---
 src/pages/safeProduction/safetyTrainingAssessment/record.vue |  546 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 546 insertions(+), 0 deletions(-)

diff --git a/src/pages/safeProduction/safetyTrainingAssessment/record.vue b/src/pages/safeProduction/safetyTrainingAssessment/record.vue
new file mode 100644
index 0000000..825b7d6
--- /dev/null
+++ b/src/pages/safeProduction/safetyTrainingAssessment/record.vue
@@ -0,0 +1,546 @@
+<template>
+  <view class="training-record">
+    <!-- 浣跨敤閫氱敤椤甸潰澶撮儴缁勪欢 -->
+    <PageHeader title="鍩硅璁板綍"
+                @back="goBack" />
+    <!-- 鎼滅储鍜岀瓫閫夊尯鍩� -->
+    <view class="search-section">
+      <view class="search-bar">
+        <view class="search-input">
+          <up-input class="search-text"
+                    placeholder="浜哄憳鍚嶇О鎼滅储"
+                    v-model="searchForm.searchText"
+                    @change="searchName"
+                    clearable />
+        </view>
+        <view class="filter-button"
+              @click="searchName">
+          <u-icon name="search"
+                  size="24"
+                  color="#999"></u-icon>
+        </view>
+      </view>
+    </view>
+    <!-- 浜哄憳鍗$墖鍒楄〃 -->
+    <view class="user-card-list"
+          v-if="userList.length > 0">
+      <view v-for="(user, index) in userList"
+            :key="index"
+            class="user-card">
+        <!-- 鍗$墖澶撮儴 -->
+        <view class="card-header"
+              @click="toggleUserCard(index)">
+          <view class="header-left">
+            <text class="user-name">{{ user.nickName }}</text>
+            <text class="user-dept">鎵�灞烇細{{ user.deptNames || '-' }}</text>
+            <text class="user-dept">鑱旂郴鏂瑰紡锛歿{ user.phonenumber || '-' }}</text>
+            <!-- 鍩硅缁熻淇℃伅 -->
+          </view>
+          <u-icon :name="expandedUsers[index] ? 'arrow-up' : 'arrow-down'"
+                  size="20"
+                  color="#999"></u-icon>
+        </view>
+        <!-- 鍗$墖鍐呭锛堟姌鍙犻儴鍒嗭級 -->
+        <view class="card-content"
+              v-if="expandedUsers[index]">
+          <!-- 骞翠唤绛涢�� -->
+          <view class="year-filter-section">
+            <!-- <text class="filter-label">骞翠唤绛涢��</text> -->
+            <view class="year-options">
+              <u-tag v-for="year in yearOptions"
+                     :key="year"
+                     :text="year"
+                     :type="userYearFilters[user.userId] === year.toString() ? 'primary' : 'info'"
+                     @click="() => {
+                       userYearFilters[user.userId] = year.toString();
+                       filterUserCourses(user.userId);
+                     }"
+                     :class="{ active: userYearFilters[user.userId] === year.toString() }"
+                     style="margin-right: 8px; margin-bottom: 8px;"></u-tag>
+            </view>
+          </view>
+          <!-- 鍩硅璇剧▼鍒楄〃 -->
+          <view class="course-list"
+                v-if="userCourses[user.userId] && userCourses[user.userId].length > 0">
+            <view class="user-stats"
+                  v-if="userStats[user.userId]">
+              <text class="stat-item">鍩硅娆℃暟: {{ userStats[user.userId].total }}</text>
+              <text class="stat-item success">鍚堟牸: {{ userStats[user.userId].qualified }}</text>
+              <text class="stat-item danger">涓嶅悎鏍�: {{ userStats[user.userId].unqualified }}</text>
+            </view>
+            <view v-for="(course, courseIndex) in userCourses[user.userId]"
+                  :key="courseIndex">
+              <view class="course-item"
+                    v-if="userYearFilters[user.userId] === '鍏ㄩ儴' || course.trainingDate.includes(userYearFilters[user.userId])">
+                <view class="course-header">
+                  <text class="course-date">{{ course.trainingDate || '-' }}</text>
+                  <u-tag :type="course.examinationResults === '鍚堟牸' ? 'success' : 'error'">
+                    {{ course.examinationResults || '-' }}
+                  </u-tag>
+                </view>
+                <view class="course-info">
+                  <text class="info-label">鍩硅鍐呭锛�</text>
+                  <text class="info-value">{{ course.trainingContent || '-' }}</text>
+                </view>
+                <view class="course-info">
+                  <text class="info-label">鍩硅璇炬椂锛�</text>
+                  <text class="info-value">{{ course.classHour || '-' }}</text>
+                </view>
+              </view>
+            </view>
+            <!-- 绛涢�夊悗鏃犳暟鎹� -->
+            <view v-if="userYearFilters[user.userId] === '鍏ㄩ儴' ? userCourses[user.userId].length === 0 : userCourses[user.userId].filter(c => c.trainingDate.includes(userYearFilters[user.userId])).length === 0"
+                  class="empty-course">
+              <text class="empty-text">{{ userYearFilters[user.userId] === '鍏ㄩ儴' ? '鏆傛棤鍩硅璁板綍' : '璇ュ勾浠芥殏鏃犲煿璁褰�' }}</text>
+            </view>
+          </view>
+          <!-- 绌虹姸鎬� -->
+          <view v-else
+                class="empty-course">
+            <text class="empty-text">鏆傛棤鍩硅璁板綍</text>
+          </view>
+        </view>
+        <!-- 瀵煎嚭鎸夐挳 -->
+        <!-- <view class="course-export">
+          <u-button type="primary"
+                    size="small"
+                    @click="exportUserRecord(user.userId)">瀵煎嚭璁板綍</u-button>
+        </view> -->
+      </view>
+    </view>
+    <view v-else
+          class="empty-state">
+      <up-icon name="people"
+               size="64"
+               color="#c0c4cc"></up-icon>
+      <text class="empty-text">鏆傛棤浜哄憳鏁版嵁</text>
+    </view>
+    <!-- 绌虹姸鎬� -->
+    <!-- 骞翠唤閫夋嫨鍣� -->
+    <up-datetime-picker :show="yearPickerVisible"
+                        mode="year"
+                        @confirm="handleYearConfirm"
+                        @cancel="yearPickerVisible = false"
+                        title="閫夋嫨骞翠唤" />
+  </view>
+</template>
+
+<script setup>
+  import { ref, onMounted, reactive } from "vue";
+  import { onShow } from "@dcloudio/uni-app";
+  import PageHeader from "@/components/PageHeader.vue";
+  import { safeTrainingDetailListPage } from "@/api/safeProduction/safetyTrainingAssessment";
+  import { userListNoPage } from "@/api/system/user.js";
+  import { getToken } from "@/utils/auth";
+  import config from "@/config";
+
+  // 椤甸潰鐘舵��
+  const userList = ref([]);
+  const userCourses = ref({}); // 瀛樺偍姣忎釜鐢ㄦ埛鐨勫煿璁绋�
+  const userStats = ref({}); // 瀛樺偍姣忎釜鐢ㄦ埛鐨勫煿璁粺璁′俊鎭�
+  const expandedUsers = ref([]); // 鎺у埗鐢ㄦ埛鍗$墖灞曞紑鐘舵��
+  const loading = ref(false);
+  const courseLoading = ref({}); // 鎺у埗姣忎釜鐢ㄦ埛鐨勮绋嬪姞杞界姸鎬�
+  const userYearFilters = ref({}); // 瀛樺偍姣忎釜鐢ㄦ埛鐨勫勾浠界瓫閫夋潯浠�
+  const yearOptions = ref([]); // 骞翠唤閫夐」锛堜粖骞村拰杩囧幓涓夊勾锛�
+
+  // 鎼滅储琛ㄥ崟
+  const searchForm = reactive({
+    searchText: "",
+    invoiceDate: "",
+  });
+
+  // 骞翠唤閫夋嫨鍣ㄧ姸鎬�
+  const yearPickerVisible = ref(false);
+
+  // 杩斿洖涓婁竴椤�
+  const goBack = () => {
+    uni.navigateBack();
+  };
+
+  // 鐢熸垚骞翠唤閫夐」
+  const generateYearOptions = () => {
+    const currentYear = new Date().getFullYear();
+    const options = [];
+    // 娣诲姞"鍏ㄩ儴"閫夐」
+    options.push("鍏ㄩ儴");
+    for (let i = 0; i < 4; i++) {
+      options.push(currentYear - i);
+    }
+    yearOptions.value = options;
+  };
+
+  // 鎼滅储浜哄憳鍚嶇О
+  const searchName = () => {
+    getUserList();
+  };
+
+  // 鏄剧ず骞翠唤閫夋嫨鍣�
+  const showYearPicker = () => {
+    yearPickerVisible.value = true;
+  };
+
+  // 澶勭悊骞翠唤閫夋嫨纭
+  const handleYearConfirm = e => {
+    searchForm.invoiceDate = e.value;
+    yearPickerVisible.value = false;
+  };
+
+  // 鎸夊勾浠芥悳绱�
+  const searchDate = () => {
+    // 閬嶅巻鎵�鏈夊睍寮�鐨勭敤鎴峰崱鐗囷紝閲嶆柊鍔犺浇鍩硅璁板綍
+    userList.value.forEach((user, index) => {
+      if (expandedUsers.value[index]) {
+        getUserCourses(user.userId, index);
+      }
+    });
+  };
+
+  // 鑾峰彇浜哄憳鍒楄〃
+  const getUserList = () => {
+    loading.value = true;
+    userListNoPage()
+      .then(res => {
+        loading.value = false;
+        if (res.data && res.data.length > 0) {
+          let users = res.data;
+          // 濡傛灉鏈夋悳绱㈠叧閿瘝锛岃繘琛岀瓫閫�
+          if (searchForm.searchText) {
+            users = users.filter(user =>
+              user.nickName.includes(searchForm.searchText)
+            );
+          }
+          userList.value = users;
+          // 鍒濆鍖栨墍鏈夊崱鐗囦负鏀惰捣鐘舵��
+          expandedUsers.value = new Array(userList.value.length).fill(false);
+        } else {
+          userList.value = [];
+          expandedUsers.value = [];
+        }
+      })
+      .catch(() => {
+        loading.value = false;
+        uni.showToast({ title: "鑾峰彇浜哄憳鍒楄〃澶辫触", icon: "none" });
+      });
+  };
+
+  // 鍒囨崲鐢ㄦ埛鍗$墖灞曞紑鐘舵��
+  const toggleUserCard = index => {
+    const user = userList.value[index];
+    expandedUsers.value[index] = !expandedUsers.value[index];
+
+    // 濡傛灉灞曞紑鍗$墖锛屽姞杞藉煿璁褰�
+    if (expandedUsers.value[index]) {
+      // 鍒濆鍖栧勾浠界瓫閫夋潯浠朵负"鍏ㄩ儴"
+      userYearFilters.value[user.userId] = "鍏ㄩ儴";
+      getUserCourses(user.userId, index);
+    }
+  };
+
+  // 绛涢�夌敤鎴峰煿璁绋�
+  const filterUserCourses = userId => {
+    if (!userYearFilters.value[userId]) return;
+    console.log("userYearFilters", userYearFilters.value);
+    const year = userYearFilters.value[userId];
+    const allCourses = userCourses.value[userId] || [];
+
+    // 绛涢�夋寚瀹氬勾浠界殑鍩硅璁板綍
+    let filteredCourses = allCourses;
+    if (year !== "鍏ㄩ儴") {
+      filteredCourses = allCourses.filter(
+        course => course.trainingDate && course.trainingDate.includes(year)
+      );
+    }
+    console.log("filteredCourses", filteredCourses);
+
+    // 鏇存柊缁熻淇℃伅
+    const total = filteredCourses.length;
+    const qualified = filteredCourses.filter(
+      course => course.examinationResults === "鍚堟牸"
+    ).length;
+    const unqualified = filteredCourses.filter(
+      course => course.examinationResults === "涓嶅悎鏍�"
+    ).length;
+    userStats.value[userId] = {
+      total,
+      qualified,
+      unqualified,
+    };
+  };
+
+  // 鑾峰彇鐢ㄦ埛鍩硅璇剧▼
+  const getUserCourses = (userId, index) => {
+    courseLoading.value[userId] = true;
+
+    const params = {
+      userId,
+      // 濡傛灉鏈夊勾浠界瓫閫夛紝娣诲姞骞翠唤鍙傛暟
+      // 杩欓噷闇�瑕佹牴鎹悗绔帴鍙g殑瀹為檯鍙傛暟鍚嶈繘琛岃皟鏁�
+    };
+
+    safeTrainingDetailListPage(params)
+      .then(res => {
+        courseLoading.value[userId] = false;
+        if (res.data && res.data.records) {
+          let courses = res.data.records;
+          // 濡傛灉鏈夊勾浠界瓫閫夛紝杩涜绛涢��
+          if (searchForm.invoiceDate) {
+            const year = searchForm.invoiceDate.substring(0, 4);
+            courses = courses.filter(
+              course => course.trainingDate && course.trainingDate.includes(year)
+            );
+          }
+          userCourses.value[userId] = courses;
+
+          // 璁$畻鍩硅缁熻淇℃伅
+          const total = courses.length;
+          const qualified = courses.filter(
+            course => course.examinationResults === "鍚堟牸"
+          ).length;
+          const unqualified = courses.filter(
+            course => course.examinationResults === "涓嶅悎鏍�"
+          ).length;
+
+          userStats.value[userId] = {
+            total,
+            qualified,
+            unqualified,
+          };
+        } else {
+          userCourses.value[userId] = [];
+          userStats.value[userId] = {
+            total: 0,
+            qualified: 0,
+            unqualified: 0,
+          };
+        }
+      })
+      .catch(() => {
+        courseLoading.value[userId] = false;
+        uni.showToast({ title: "鑾峰彇鍩硅璁板綍澶辫触", icon: "none" });
+      });
+  };
+
+  // 椤甸潰鍔犺浇
+  onMounted(() => {
+    // 鐢熸垚骞翠唤閫夐」
+    generateYearOptions();
+    getUserList();
+  });
+
+  // 椤甸潰鏄剧ず鏃跺埛鏂�
+  onShow(() => {
+    // 鍙互鍦ㄨ繖閲屾坊鍔犲埛鏂伴�昏緫
+  });
+</script>
+
+<style scoped lang="scss">
+  @import "../../../styles/sales-common.scss";
+  .training-record {
+    min-height: 100vh;
+    background: #f8f9fa;
+    padding-bottom: 20px;
+  }
+
+  // 骞翠唤閫夋嫨鍣�
+  .year-picker {
+    flex: 1;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 10px 15px;
+    background: #f8f9fa;
+    border-radius: 4px;
+    margin-right: 10px;
+  }
+
+  .picker-text {
+    font-size: 14px;
+    color: #333;
+  }
+
+  // 浜哄憳鍗$墖鍒楄〃
+  .user-card-list {
+    padding: 10px;
+  }
+
+  // 浜哄憳鍗$墖
+  .user-card {
+    background: #fff;
+    border-radius: 8px;
+    margin-bottom: 12px;
+    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
+    overflow: hidden;
+    border: 1px solid #e8e8e8;
+  }
+
+  // 鍗$墖澶撮儴
+  .card-header {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 16px;
+    background: #f5f7fa;
+    border-bottom: 1px solid #e8e8e8;
+    cursor: pointer;
+  }
+
+  .header-left {
+    display: flex;
+    flex-direction: column;
+  }
+
+  .user-name {
+    font-size: 16px;
+    font-weight: 600;
+    color: #333;
+    margin-bottom: 20rpx;
+  }
+
+  .user-dept {
+    font-size: 14px;
+    color: #666;
+    margin-bottom: 8px;
+  }
+
+  // 鍩硅缁熻淇℃伅
+  .user-stats {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 10px;
+    margin-bottom: 8px;
+  }
+
+  .stat-item {
+    font-size: 12px;
+    color: #555;
+    padding: 5px 10px;
+    background: #f0f2f5;
+    border-radius: 4px;
+    border: 1px solid #e0e0e0;
+    font-weight: 500;
+  }
+
+  .stat-item.success {
+    background: #e6f7ff;
+    color: #1890ff;
+    border-color: #91d5ff;
+  }
+
+  .stat-item.danger {
+    background: #fff1f0;
+    color: #ff4d4f;
+    border-color: #ffccc7;
+  }
+
+  // 骞翠唤绛涢�夊尯鍩�
+  .year-filter-section {
+    margin-bottom: 16px;
+    padding-bottom: 12px;
+    border-bottom: 1px solid #e8e8e8;
+  }
+
+  .filter-label {
+    font-size: 14px;
+    font-weight: 500;
+    color: #333;
+    margin-bottom: 8px;
+    display: block;
+  }
+
+  .year-options {
+    display: flex;
+    flex-wrap: wrap;
+  }
+
+  // 鍗$墖鍐呭
+  .card-content {
+    padding: 16px;
+  }
+
+  // 鍩硅璇剧▼鍒楄〃
+  .course-list {
+    margin-bottom: 16px;
+  }
+
+  // 璇剧▼椤�
+  .course-item {
+    background: #fafafa;
+    border-radius: 6px;
+    padding: 14px;
+    margin-bottom: 12px;
+    border: 1px solid #e8e8e8;
+  }
+
+  // 璇剧▼澶撮儴
+  .course-header {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    margin-bottom: 12px;
+    padding-bottom: 8px;
+    border-bottom: 1px solid #f0f0f0;
+  }
+
+  .course-date {
+    font-size: 14px;
+    font-weight: 600;
+    color: #333;
+  }
+
+  // 璇剧▼淇℃伅
+  .course-info {
+    display: flex;
+    margin-bottom: 8px;
+    align-items: flex-start;
+  }
+
+  .info-label {
+    font-size: 14px;
+    color: #666;
+    width: 80px;
+    flex-shrink: 0;
+  }
+
+  .info-value {
+    font-size: 14px;
+    color: #333;
+    flex: 1;
+    line-height: 1.4;
+  }
+
+  // 璇剧▼瀵煎嚭鎸夐挳
+  .course-export {
+    display: flex;
+    justify-content: flex-end;
+  }
+
+  // 绌虹姸鎬�
+  .empty-state {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    padding: 60px 0;
+  }
+
+  .empty-course {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    padding: 30px 0;
+    color: #999;
+    font-size: 14px;
+  }
+
+  .empty-text {
+    font-size: 14px;
+    color: #999;
+    margin-top: 16px;
+  }
+  :deep(.u-tag--info) {
+    background-color: #c1c3c8;
+    border-width: 1px;
+    border-color: #c1c3c8;
+  }
+</style>
\ No newline at end of file

--
Gitblit v1.9.3