|
|
@@ -0,0 +1,1558 @@
|
|
|
+<template>
|
|
|
+ <view class="page-container">
|
|
|
+ <!-- 顶部导航 -->
|
|
|
+ <u-navbar :title="navTitle" :border-bottom="false" bg-color="#3c9cff" title-color="#fff">
|
|
|
+ <view slot="left" @click="goBack">
|
|
|
+ <u-icon name="arrow-left" color="#fff" size="22"></u-icon>
|
|
|
+ </view>
|
|
|
+ </u-navbar>
|
|
|
+
|
|
|
+ <!-- 加载状态 -->
|
|
|
+ <u-loading-page :loading="pageLoading" loading-text="加载中..."></u-loading-page>
|
|
|
+
|
|
|
+ <!-- 表单内容 -->
|
|
|
+ <view v-if="!pageLoading" class="form-container">
|
|
|
+ <u-form ref="formRef" :model="formData" :rules="rules" label-width="140">
|
|
|
+ <!-- 基本信息 -->
|
|
|
+ <view class="form-section">
|
|
|
+ <text class="section-title">基本信息</text>
|
|
|
+
|
|
|
+ <u-form-item label="检查标题" prop="checkTitle" required>
|
|
|
+ <u-input v-model="formData.checkTitle" placeholder="请输入检查标题" />
|
|
|
+ </u-form-item>
|
|
|
+
|
|
|
+ <u-form-item label="检查日期" prop="checkDate" required>
|
|
|
+ <u-datetime-picker
|
|
|
+ :show="showDatePicker"
|
|
|
+ v-model="checkDateValue"
|
|
|
+ mode="datetime"
|
|
|
+ @confirm="handleDateConfirm"
|
|
|
+ @cancel="showDatePicker = false"
|
|
|
+ ></u-datetime-picker>
|
|
|
+ <view @click="showDatePicker = true">
|
|
|
+ <u-input
|
|
|
+ v-model="checkDateDisplay"
|
|
|
+ placeholder="请选择检查日期"
|
|
|
+ readonly
|
|
|
+ suffix-icon="calendar-fill"
|
|
|
+ suffix-icon-style="color: #909399"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </u-form-item>
|
|
|
+
|
|
|
+ <u-form-item label="检查类型" prop="checkType" required>
|
|
|
+ <u-picker
|
|
|
+ :show="showCheckTypePicker"
|
|
|
+ :columns="checkTypeColumns"
|
|
|
+ @confirm="handleCheckTypeConfirm"
|
|
|
+ @cancel="showCheckTypePicker = false"
|
|
|
+ ></u-picker>
|
|
|
+ <view @click="showCheckTypePicker = true">
|
|
|
+ <u-input
|
|
|
+ v-model="checkTypeDisplay"
|
|
|
+ placeholder="请选择检查类型"
|
|
|
+ readonly
|
|
|
+ suffix-icon="arrow-down-fill"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </u-form-item>
|
|
|
+
|
|
|
+ <u-form-item label="检查级别" prop="checkLevel" required>
|
|
|
+ <u-picker
|
|
|
+ :show="showCheckLevelPicker"
|
|
|
+ :columns="checkLevelColumns"
|
|
|
+ @confirm="handleCheckLevelConfirm"
|
|
|
+ @cancel="showCheckLevelPicker = false"
|
|
|
+ ></u-picker>
|
|
|
+ <view @click="showCheckLevelPicker = true">
|
|
|
+ <u-input
|
|
|
+ v-model="checkLevelDisplay"
|
|
|
+ placeholder="请选择检查级别"
|
|
|
+ readonly
|
|
|
+ suffix-icon="arrow-down-fill"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </u-form-item>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 位置信息 -->
|
|
|
+ <view class="form-section">
|
|
|
+ <text class="section-title">位置信息</text>
|
|
|
+
|
|
|
+ <u-form-item label="校区" prop="campusId" required>
|
|
|
+ <u-picker
|
|
|
+ :show="showCampusPicker"
|
|
|
+ :columns="campusColumns"
|
|
|
+ @confirm="handleCampusConfirm"
|
|
|
+ @cancel="showCampusPicker = false"
|
|
|
+ ></u-picker>
|
|
|
+ <view @click="showCampusPicker = true">
|
|
|
+ <u-input
|
|
|
+ v-model="formData.campusName"
|
|
|
+ placeholder="请选择校区"
|
|
|
+ readonly
|
|
|
+ suffix-icon="arrow-down-fill"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </u-form-item>
|
|
|
+
|
|
|
+ <u-form-item label="宿舍区" prop="areaId" required>
|
|
|
+ <u-picker
|
|
|
+ :show="showAreaPicker"
|
|
|
+ :columns="areaColumns"
|
|
|
+ @confirm="handleAreaConfirm"
|
|
|
+ @cancel="showAreaPicker = false"
|
|
|
+ ></u-picker>
|
|
|
+ <view @click="showAreaPicker = true">
|
|
|
+ <u-input
|
|
|
+ v-model="formData.areaName"
|
|
|
+ placeholder="请选择宿舍区"
|
|
|
+ readonly
|
|
|
+ suffix-icon="arrow-down-fill"
|
|
|
+ :disabled="!formData.campusId"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </u-form-item>
|
|
|
+
|
|
|
+ <u-form-item label="宿舍楼" prop="buildingId" required>
|
|
|
+ <u-picker
|
|
|
+ :show="showBuildingPicker"
|
|
|
+ :columns="buildingColumns"
|
|
|
+ @confirm="handleBuildingConfirm"
|
|
|
+ @cancel="showBuildingPicker = false"
|
|
|
+ ></u-picker>
|
|
|
+ <view @click="showBuildingPicker = true">
|
|
|
+ <u-input
|
|
|
+ v-model="formData.buildingName"
|
|
|
+ placeholder="请选择宿舍楼"
|
|
|
+ readonly
|
|
|
+ suffix-icon="arrow-down-fill"
|
|
|
+ :disabled="!formData.areaId"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </u-form-item>
|
|
|
+
|
|
|
+ <u-form-item label="房间" prop="roomId" required>
|
|
|
+ <u-picker
|
|
|
+ :show="showRoomPicker"
|
|
|
+ :columns="roomColumns"
|
|
|
+ @confirm="handleRoomConfirm"
|
|
|
+ @cancel="showRoomPicker = false"
|
|
|
+ ></u-picker>
|
|
|
+ <view @click="showRoomPicker = true">
|
|
|
+ <u-input
|
|
|
+ v-model="formData.roomName"
|
|
|
+ placeholder="请选择房间"
|
|
|
+ readonly
|
|
|
+ suffix-icon="arrow-down-fill"
|
|
|
+ :disabled="!formData.buildingId"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </u-form-item>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 检查结果 -->
|
|
|
+ <view class="form-section">
|
|
|
+ <text class="section-title">检查结果</text>
|
|
|
+
|
|
|
+ <u-form-item label="宿舍总分" prop="totalScore">
|
|
|
+ <u-input
|
|
|
+ v-model="formData.totalScore"
|
|
|
+ type="number"
|
|
|
+ placeholder="请输入宿舍总分(0-100分)"
|
|
|
+ @input="handleTotalScoreChange"
|
|
|
+ />
|
|
|
+ </u-form-item>
|
|
|
+
|
|
|
+ <u-form-item label="卫生等级" prop="hygieneGrade" required>
|
|
|
+ <u-picker
|
|
|
+ :show="showHygieneGradePicker"
|
|
|
+ :columns="hygieneGradeColumns"
|
|
|
+ @confirm="handleHygieneGradeConfirm"
|
|
|
+ @cancel="showHygieneGradePicker = false"
|
|
|
+ ></u-picker>
|
|
|
+ <view @click="showHygieneGradePicker = true">
|
|
|
+ <u-input
|
|
|
+ v-model="hygieneGradeDisplay"
|
|
|
+ placeholder="请选择卫生等级"
|
|
|
+ readonly
|
|
|
+ suffix-icon="arrow-down-fill"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </u-form-item>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 检查员信息 -->
|
|
|
+ <view class="form-section">
|
|
|
+ <text class="section-title">检查员信息</text>
|
|
|
+
|
|
|
+ <u-form-item label="检查员" prop="checkerName" required>
|
|
|
+ <u-input v-model="formData.checkerName" placeholder="请输入检查员姓名" />
|
|
|
+ </u-form-item>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 房间学生信息 -->
|
|
|
+ <view v-if="formData.roomId && roomStudents.length > 0" class="form-section">
|
|
|
+ <text class="section-title">房间学生信息</text>
|
|
|
+
|
|
|
+ <view class="student-list">
|
|
|
+ <view
|
|
|
+ v-for="(student, index) in roomStudents"
|
|
|
+ :key="index"
|
|
|
+ class="student-item"
|
|
|
+ >
|
|
|
+ <view class="student-header">
|
|
|
+ <text class="student-name">{{ student.studentName }}</text>
|
|
|
+ <text class="student-no">{{ student.studentNo }}</text>
|
|
|
+ <text class="student-bed">{{ student.bedName }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="student-form">
|
|
|
+ <view class="form-row">
|
|
|
+ <view class="form-col">
|
|
|
+ <text class="form-label">个人得分</text>
|
|
|
+ <u-input
|
|
|
+ v-model="student.student_score"
|
|
|
+ type="number"
|
|
|
+ placeholder="0-100分"
|
|
|
+ @input="handleStudentScoreChange(student)"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <view class="form-col">
|
|
|
+ <text class="form-label">出勤状态</text>
|
|
|
+ <u-picker
|
|
|
+ :show="student.showAttendancePicker"
|
|
|
+ :columns="attendanceStatusColumns"
|
|
|
+ @confirm="(e) => handleAttendanceConfirm(e, student)"
|
|
|
+ @cancel="student.showAttendancePicker = false"
|
|
|
+ ></u-picker>
|
|
|
+ <view @click="student.showAttendancePicker = true">
|
|
|
+ <u-input
|
|
|
+ :value="
|
|
|
+ getAttendanceDisplay(student.attendance_status)
|
|
|
+ "
|
|
|
+ placeholder="请选择"
|
|
|
+ readonly
|
|
|
+ suffix-icon="arrow-down-fill"
|
|
|
+ size="small"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="form-row">
|
|
|
+ <view class="form-col">
|
|
|
+ <text class="form-label">学生评级</text>
|
|
|
+ <u-picker
|
|
|
+ :show="student.showGradePicker"
|
|
|
+ :columns="hygieneGradeColumns"
|
|
|
+ @confirm="(e) => handleStudentGradeConfirm(e, student)"
|
|
|
+ @cancel="student.showGradePicker = false"
|
|
|
+ ></u-picker>
|
|
|
+ <view @click="student.showGradePicker = true">
|
|
|
+ <u-input
|
|
|
+ :value="getGradeDisplay(student.student_grade)"
|
|
|
+ placeholder="请选择"
|
|
|
+ readonly
|
|
|
+ suffix-icon="arrow-down-fill"
|
|
|
+ size="small"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 附件上传 -->
|
|
|
+ <view class="form-section">
|
|
|
+ <text class="section-title">附件上传</text>
|
|
|
+
|
|
|
+ <!-- 图片附件 -->
|
|
|
+ <view class="attachment-section">
|
|
|
+ <text class="attachment-title">图片附件</text>
|
|
|
+ <view class="image-upload-container">
|
|
|
+ <view class="image-list">
|
|
|
+ <view
|
|
|
+ v-for="(image, index) in imageList"
|
|
|
+ :key="index"
|
|
|
+ class="image-item"
|
|
|
+ >
|
|
|
+ <image
|
|
|
+ :src="image.url"
|
|
|
+ mode="aspectFill"
|
|
|
+ class="image-preview"
|
|
|
+ @click="previewImage(index)"
|
|
|
+ />
|
|
|
+ <view class="image-actions">
|
|
|
+ <u-icon
|
|
|
+ name="trash"
|
|
|
+ size="16"
|
|
|
+ color="#f56c6c"
|
|
|
+ @click="removeImage(index)"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view
|
|
|
+ v-if="imageList.length < 9"
|
|
|
+ class="image-upload-btn"
|
|
|
+ @click="chooseImage"
|
|
|
+ >
|
|
|
+ <u-icon name="plus" size="32" color="#909399" />
|
|
|
+ <text class="upload-text">上传图片</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 文档附件 -->
|
|
|
+ <view class="attachment-section">
|
|
|
+ <text class="attachment-title">文档附件</text>
|
|
|
+ <view class="document-upload-container">
|
|
|
+ <view class="document-list">
|
|
|
+ <view
|
|
|
+ v-for="(doc, index) in documentList"
|
|
|
+ :key="index"
|
|
|
+ class="document-item"
|
|
|
+ >
|
|
|
+ <view class="document-info">
|
|
|
+ <u-icon name="file-text" size="24" color="#3c9cff" />
|
|
|
+ <text class="document-name">{{ doc.name }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="document-actions">
|
|
|
+ <u-icon
|
|
|
+ name="download"
|
|
|
+ size="16"
|
|
|
+ color="#52c41a"
|
|
|
+ @click="downloadDocument(doc)"
|
|
|
+ />
|
|
|
+ <u-icon
|
|
|
+ name="trash"
|
|
|
+ size="16"
|
|
|
+ color="#f56c6c"
|
|
|
+ @click="removeDocument(index)"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="document-upload-btn" @click="chooseDocument">
|
|
|
+ <u-icon name="folder-plus" size="20" color="#3c9cff" />
|
|
|
+ <text class="upload-text">选择文档</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 备注信息 -->
|
|
|
+ <view class="form-section">
|
|
|
+ <text class="section-title">备注信息</text>
|
|
|
+
|
|
|
+ <u-form-item label="检查总结" prop="checkSummary">
|
|
|
+ <u-textarea
|
|
|
+ v-model="formData.checkSummary"
|
|
|
+ placeholder="请输入检查总结"
|
|
|
+ :maxlength="500"
|
|
|
+ count
|
|
|
+ :height="120"
|
|
|
+ />
|
|
|
+ </u-form-item>
|
|
|
+
|
|
|
+ <u-form-item label="整改建议" prop="improvementSuggestions">
|
|
|
+ <u-textarea
|
|
|
+ v-model="formData.improvementSuggestions"
|
|
|
+ placeholder="请输入整改建议"
|
|
|
+ :maxlength="500"
|
|
|
+ count
|
|
|
+ :height="120"
|
|
|
+ />
|
|
|
+ </u-form-item>
|
|
|
+
|
|
|
+ <u-form-item label="检查备注" prop="checkRemarks">
|
|
|
+ <u-textarea
|
|
|
+ v-model="formData.checkRemarks"
|
|
|
+ placeholder="请输入检查备注"
|
|
|
+ :maxlength="500"
|
|
|
+ count
|
|
|
+ :height="120"
|
|
|
+ />
|
|
|
+ </u-form-item>
|
|
|
+ </view>
|
|
|
+ </u-form>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 底部操作按钮 -->
|
|
|
+ <view class="bottom-actions">
|
|
|
+ <u-button type="info" @click="goBack" style="margin-right: 20rpx">取消</u-button>
|
|
|
+ <u-button type="primary" @click="handleSubmit" :loading="submitLoading">保存</u-button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { request, smartUploadFile } from '@/common/request.js';
|
|
|
+import { getDict, getDictLabel } from '@/common/dict.js';
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: 'DormHygieneCheckAdd',
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ pageLoading: false,
|
|
|
+ submitLoading: false,
|
|
|
+
|
|
|
+ // 页面参数
|
|
|
+ pageType: 'add', // add | update
|
|
|
+ checkId: null,
|
|
|
+
|
|
|
+ // 表单数据
|
|
|
+ formData: {
|
|
|
+ id: undefined,
|
|
|
+ checkTitle: '',
|
|
|
+ checkDate: '',
|
|
|
+ checkerId: undefined,
|
|
|
+ checkerName: '',
|
|
|
+ checkType: '1',
|
|
|
+ checkLevel: '1',
|
|
|
+ roomId: undefined,
|
|
|
+ roomCode: undefined,
|
|
|
+ roomName: undefined,
|
|
|
+ buildingId: undefined,
|
|
|
+ buildingName: undefined,
|
|
|
+ areaId: undefined,
|
|
|
+ areaName: undefined,
|
|
|
+ campusId: undefined,
|
|
|
+ campusName: undefined,
|
|
|
+ totalScore: undefined,
|
|
|
+ hygieneGrade: 'A',
|
|
|
+ attachmentIds: undefined,
|
|
|
+ checkSummary: undefined,
|
|
|
+ improvementSuggestions: undefined,
|
|
|
+ checkRemarks: undefined,
|
|
|
+ },
|
|
|
+
|
|
|
+ // 表单验证规则
|
|
|
+ rules: {
|
|
|
+ checkTitle: [{ required: true, message: '请输入检查标题', trigger: 'blur' }],
|
|
|
+ checkDate: [{ required: true, message: '请选择检查日期', trigger: 'change' }],
|
|
|
+ checkerName: [{ required: true, message: '请输入检查员姓名', trigger: 'blur' }],
|
|
|
+ campusId: [{ required: true, message: '请选择校区', trigger: 'change' }],
|
|
|
+ areaId: [{ required: true, message: '请选择宿舍区', trigger: 'change' }],
|
|
|
+ buildingId: [{ required: true, message: '请选择宿舍楼', trigger: 'change' }],
|
|
|
+ roomId: [{ required: true, message: '请选择房间', trigger: 'change' }],
|
|
|
+ checkType: [{ required: true, message: '请选择检查类型', trigger: 'change' }],
|
|
|
+ checkLevel: [{ required: true, message: '请选择检查级别', trigger: 'change' }],
|
|
|
+ hygieneGrade: [{ required: true, message: '请选择卫生等级', trigger: 'change' }],
|
|
|
+ },
|
|
|
+
|
|
|
+ // 时间选择器
|
|
|
+ showDatePicker: false,
|
|
|
+ checkDateValue: '',
|
|
|
+ checkDateDisplay: '',
|
|
|
+
|
|
|
+ // 级联选择器数据
|
|
|
+ campusOptions: [],
|
|
|
+ areaOptions: [],
|
|
|
+ buildingOptions: [],
|
|
|
+ roomOptions: [],
|
|
|
+
|
|
|
+ // 级联选择器显示状态
|
|
|
+ showCampusPicker: false,
|
|
|
+ showAreaPicker: false,
|
|
|
+ showBuildingPicker: false,
|
|
|
+ showRoomPicker: false,
|
|
|
+
|
|
|
+ // 字典选择器显示状态
|
|
|
+ showCheckTypePicker: false,
|
|
|
+ showCheckLevelPicker: false,
|
|
|
+ showHygieneGradePicker: false,
|
|
|
+
|
|
|
+ // 字典数据
|
|
|
+ xg_dorm_hygiene_check_type: [],
|
|
|
+ xg_dorm_hygiene_check_level: [],
|
|
|
+ xg_dorm_hygiene_grade: [],
|
|
|
+ xg_student_attendance_status: [],
|
|
|
+
|
|
|
+ // 房间学生信息
|
|
|
+ roomStudents: [],
|
|
|
+
|
|
|
+ // 附件数据
|
|
|
+ imageList: [],
|
|
|
+ documentList: [],
|
|
|
+ };
|
|
|
+ },
|
|
|
+
|
|
|
+ computed: {
|
|
|
+ navTitle() {
|
|
|
+ return this.pageType === 'add' ? '新增检查' : '修改检查';
|
|
|
+ },
|
|
|
+
|
|
|
+ // 级联选择器数据转换
|
|
|
+ campusColumns() {
|
|
|
+ return [this.campusOptions.map((item) => ({ text: item.campusName, value: item.id }))];
|
|
|
+ },
|
|
|
+
|
|
|
+ areaColumns() {
|
|
|
+ return [this.areaOptions.map((item) => ({ text: item.areaName, value: item.id }))];
|
|
|
+ },
|
|
|
+
|
|
|
+ buildingColumns() {
|
|
|
+ return [
|
|
|
+ this.buildingOptions.map((item) => ({ text: item.buildingName, value: item.id })),
|
|
|
+ ];
|
|
|
+ },
|
|
|
+
|
|
|
+ roomColumns() {
|
|
|
+ return [this.roomOptions.map((item) => ({ text: item.roomName, value: item.id }))];
|
|
|
+ },
|
|
|
+
|
|
|
+ // 字典选择器数据转换
|
|
|
+ checkTypeColumns() {
|
|
|
+ return [
|
|
|
+ this.xg_dorm_hygiene_check_type.map((item) => ({
|
|
|
+ text: item.label,
|
|
|
+ value: item.value,
|
|
|
+ })),
|
|
|
+ ];
|
|
|
+ },
|
|
|
+
|
|
|
+ checkLevelColumns() {
|
|
|
+ return [
|
|
|
+ this.xg_dorm_hygiene_check_level.map((item) => ({
|
|
|
+ text: item.label,
|
|
|
+ value: item.value,
|
|
|
+ })),
|
|
|
+ ];
|
|
|
+ },
|
|
|
+
|
|
|
+ hygieneGradeColumns() {
|
|
|
+ return [
|
|
|
+ this.xg_dorm_hygiene_grade.map((item) => ({ text: item.label, value: item.value })),
|
|
|
+ ];
|
|
|
+ },
|
|
|
+
|
|
|
+ attendanceStatusColumns() {
|
|
|
+ return [
|
|
|
+ this.xg_student_attendance_status.map((item) => ({
|
|
|
+ text: item.label,
|
|
|
+ value: item.value,
|
|
|
+ })),
|
|
|
+ ];
|
|
|
+ },
|
|
|
+
|
|
|
+ // 显示字段
|
|
|
+ checkTypeDisplay() {
|
|
|
+ const item = this.xg_dorm_hygiene_check_type.find(
|
|
|
+ (d) => d.value === this.formData.checkType,
|
|
|
+ );
|
|
|
+ return item ? item.label : '';
|
|
|
+ },
|
|
|
+
|
|
|
+ checkLevelDisplay() {
|
|
|
+ const item = this.xg_dorm_hygiene_check_level.find(
|
|
|
+ (d) => d.value === this.formData.checkLevel,
|
|
|
+ );
|
|
|
+ return item ? item.label : '';
|
|
|
+ },
|
|
|
+
|
|
|
+ hygieneGradeDisplay() {
|
|
|
+ const item = this.xg_dorm_hygiene_grade.find(
|
|
|
+ (d) => d.value === this.formData.hygieneGrade,
|
|
|
+ );
|
|
|
+ return item ? item.label : '';
|
|
|
+ },
|
|
|
+ },
|
|
|
+
|
|
|
+ async onLoad(options) {
|
|
|
+ console.log('页面参数:', options);
|
|
|
+
|
|
|
+ this.pageType = options.type || 'add';
|
|
|
+ this.checkId = options.id;
|
|
|
+
|
|
|
+ await this.initPage();
|
|
|
+ },
|
|
|
+
|
|
|
+ methods: {
|
|
|
+ // 初始化页面
|
|
|
+ async initPage() {
|
|
|
+ this.pageLoading = true;
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 加载字典数据
|
|
|
+ await this.loadDictionaries();
|
|
|
+ // 加载级联选择器数据
|
|
|
+ await this.loadCampusOptions();
|
|
|
+ // 设置默认值
|
|
|
+ this.setDefaultValues();
|
|
|
+
|
|
|
+ // 编辑模式加载数据
|
|
|
+ if (this.pageType === 'update' && this.checkId) {
|
|
|
+ await this.loadCheckData();
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('初始化页面失败:', error);
|
|
|
+ uni.showToast({
|
|
|
+ title: '页面初始化失败',
|
|
|
+ icon: 'none',
|
|
|
+ });
|
|
|
+ } finally {
|
|
|
+ this.pageLoading = false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 加载字典数据
|
|
|
+ async loadDictionaries() {
|
|
|
+ try {
|
|
|
+ const dictTypes = [
|
|
|
+ 'xg_dorm_hygiene_check_type',
|
|
|
+ 'xg_dorm_hygiene_check_level',
|
|
|
+ 'xg_dorm_hygiene_grade',
|
|
|
+ 'xg_student_attendance_status',
|
|
|
+ ];
|
|
|
+
|
|
|
+ const results = await Promise.all(dictTypes.map((type) => getDict(type)));
|
|
|
+
|
|
|
+ this.xg_dorm_hygiene_check_type = results[0] || [];
|
|
|
+ this.xg_dorm_hygiene_check_level = results[1] || [];
|
|
|
+ this.xg_dorm_hygiene_grade = results[2] || [];
|
|
|
+ this.xg_student_attendance_status = results[3] || [];
|
|
|
+
|
|
|
+ console.log('字典数据加载完成');
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载字典数据失败:', error);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 设置默认值
|
|
|
+ setDefaultValues() {
|
|
|
+ const now = new Date();
|
|
|
+ this.checkDateValue = now.getTime();
|
|
|
+ this.checkDateDisplay = this.formatDateTime(now);
|
|
|
+ this.formData.checkDate = this.formatDateTime(now);
|
|
|
+
|
|
|
+ // 设置默认检查标题
|
|
|
+ const dateStr = now.toISOString().slice(0, 10).replace(/-/g, '');
|
|
|
+ this.formData.checkTitle = `${dateStr}宿舍卫生检查`;
|
|
|
+
|
|
|
+ // 获取当前用户信息
|
|
|
+ this.getCurrentUserInfo();
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取当前用户信息
|
|
|
+ async getCurrentUserInfo() {
|
|
|
+ try {
|
|
|
+ const res = await request({
|
|
|
+ url: '/system/user/getInfo',
|
|
|
+ method: 'GET',
|
|
|
+ });
|
|
|
+
|
|
|
+ if (res && res.code === 200 && res.data && res.data.user) {
|
|
|
+ const user = res.data.user;
|
|
|
+ this.formData.checkerId = user.userId;
|
|
|
+ this.formData.checkerName = user.nickName || user.userName;
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.warn('获取用户信息失败:', error);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 加载检查数据(编辑模式)
|
|
|
+ async loadCheckData() {
|
|
|
+ try {
|
|
|
+ const res = await request({
|
|
|
+ url: `/dormHygieneCheck/dormHygieneCheck/${this.checkId}`,
|
|
|
+ method: 'GET',
|
|
|
+ });
|
|
|
+
|
|
|
+ if (res && res.code === 200 && res.data) {
|
|
|
+ Object.assign(this.formData, res.data);
|
|
|
+
|
|
|
+ // 设置时间显示
|
|
|
+ if (this.formData.checkDate) {
|
|
|
+ const date = new Date(this.formData.checkDate);
|
|
|
+ this.checkDateValue = date.getTime();
|
|
|
+ this.checkDateDisplay = this.formatDateTime(date);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 加载级联数据
|
|
|
+ await this.loadCascadeData();
|
|
|
+ // 加载房间学生数据
|
|
|
+ await this.loadRoomStudents();
|
|
|
+ // 加载附件数据
|
|
|
+ await this.loadAttachmentData();
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载检查数据失败:', error);
|
|
|
+ uni.showToast({
|
|
|
+ title: '加载数据失败',
|
|
|
+ icon: 'none',
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 加载级联数据
|
|
|
+ async loadCascadeData() {
|
|
|
+ try {
|
|
|
+ const tasks = [];
|
|
|
+
|
|
|
+ if (this.formData.campusId) {
|
|
|
+ tasks.push(this.loadAreaOptions(this.formData.campusId));
|
|
|
+ }
|
|
|
+ if (this.formData.areaId) {
|
|
|
+ tasks.push(this.loadBuildingOptions(this.formData.areaId));
|
|
|
+ }
|
|
|
+ if (this.formData.buildingId) {
|
|
|
+ tasks.push(this.loadRoomOptions(this.formData.buildingId));
|
|
|
+ }
|
|
|
+
|
|
|
+ await Promise.all(tasks);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载级联数据失败:', error);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 加载校区选项
|
|
|
+ async loadCampusOptions() {
|
|
|
+ try {
|
|
|
+ const res = await request({
|
|
|
+ url: '/xqxx/dormCampus/list',
|
|
|
+ method: 'GET',
|
|
|
+ });
|
|
|
+ this.campusOptions = res.rows || [];
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载校区选项失败:', error);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 加载宿舍区选项
|
|
|
+ async loadAreaOptions(campusId) {
|
|
|
+ try {
|
|
|
+ const res = await request({
|
|
|
+ url: '/ssqxx/dormArea/list',
|
|
|
+ method: 'GET',
|
|
|
+ params: { campusId },
|
|
|
+ });
|
|
|
+ this.areaOptions = res.rows || [];
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载宿舍区选项失败:', error);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 加载宿舍楼选项
|
|
|
+ async loadBuildingOptions(areaId) {
|
|
|
+ try {
|
|
|
+ const res = await request({
|
|
|
+ url: '/sslxx/dormBuilding/list',
|
|
|
+ method: 'GET',
|
|
|
+ params: { areaId },
|
|
|
+ });
|
|
|
+ this.buildingOptions = res.rows || [];
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载宿舍楼选项失败:', error);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 加载房间选项
|
|
|
+ async loadRoomOptions(buildingId) {
|
|
|
+ try {
|
|
|
+ const res = await request({
|
|
|
+ url: '/xgss/dormRoom/list',
|
|
|
+ method: 'GET',
|
|
|
+ params: { buildingId },
|
|
|
+ });
|
|
|
+ this.roomOptions = res.rows || [];
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载房间选项失败:', error);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 加载房间学生信息
|
|
|
+ async loadRoomStudents() {
|
|
|
+ if (!this.formData.roomId) {
|
|
|
+ this.roomStudents = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 如果是编辑模式,先尝试获取历史评分数据
|
|
|
+ if (this.pageType === 'update' && this.formData.id) {
|
|
|
+ const studentScoresRes = await request({
|
|
|
+ url: `/dormHygieneStudentScore/dormHygieneStudentScore/getByCheckId/${this.formData.id}`,
|
|
|
+ method: 'GET',
|
|
|
+ });
|
|
|
+
|
|
|
+ if (
|
|
|
+ studentScoresRes.code === 200 &&
|
|
|
+ studentScoresRes.data &&
|
|
|
+ studentScoresRes.data.length > 0
|
|
|
+ ) {
|
|
|
+ this.roomStudents = studentScoresRes.data.map((item) => ({
|
|
|
+ ...item,
|
|
|
+ student_score: item.studentScore || null,
|
|
|
+ attendance_status: item.attendanceStatus || '1',
|
|
|
+ student_grade: item.studentGrade || 'A',
|
|
|
+ showAttendancePicker: false,
|
|
|
+ showGradePicker: false,
|
|
|
+ }));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取房间学生基础数据
|
|
|
+ const res = await request({
|
|
|
+ url: '/dormBedStudent/dormBedStudent/getRoomStudents',
|
|
|
+ method: 'GET',
|
|
|
+ params: { roomId: this.formData.roomId },
|
|
|
+ });
|
|
|
+
|
|
|
+ if (res.code === 200 && res.data) {
|
|
|
+ this.roomStudents = res.data.map((item) => ({
|
|
|
+ ...item,
|
|
|
+ student_score: null,
|
|
|
+ attendance_status: '1',
|
|
|
+ student_grade: 'A',
|
|
|
+ showAttendancePicker: false,
|
|
|
+ showGradePicker: false,
|
|
|
+ }));
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载房间学生信息失败:', error);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 加载附件数据
|
|
|
+ async loadAttachmentData() {
|
|
|
+ if (!this.formData.attachmentIds) {
|
|
|
+ this.imageList = [];
|
|
|
+ this.documentList = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ const ossIds = this.formData.attachmentIds.split(',').filter((id) => id.trim());
|
|
|
+ if (ossIds.length === 0) return;
|
|
|
+
|
|
|
+ const res = await request({
|
|
|
+ url: `/resource/oss/listByIds/${ossIds.join(',')}`,
|
|
|
+ method: 'GET',
|
|
|
+ });
|
|
|
+
|
|
|
+ if (res.code === 200 && res.data) {
|
|
|
+ const images = [];
|
|
|
+ const documents = [];
|
|
|
+
|
|
|
+ res.data.forEach((item) => {
|
|
|
+ const isImage = /\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(item.originalName);
|
|
|
+ if (isImage) {
|
|
|
+ images.push({
|
|
|
+ url: item.url,
|
|
|
+ ossId: item.ossId,
|
|
|
+ name: item.originalName,
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ documents.push({
|
|
|
+ url: item.url,
|
|
|
+ ossId: item.ossId,
|
|
|
+ name: item.originalName,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ this.imageList = images;
|
|
|
+ this.documentList = documents;
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载附件数据失败:', error);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 时间选择确认
|
|
|
+ handleDateConfirm(e) {
|
|
|
+ this.checkDateValue = e.value;
|
|
|
+ const date = new Date(e.value);
|
|
|
+ this.checkDateDisplay = this.formatDateTime(date);
|
|
|
+ this.formData.checkDate = this.formatDateTime(date);
|
|
|
+ this.showDatePicker = false;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 校区选择确认
|
|
|
+ async handleCampusConfirm(e) {
|
|
|
+ const campus = this.campusOptions.find((item) => item.id === e.value[0]);
|
|
|
+ if (campus) {
|
|
|
+ this.formData.campusId = campus.id;
|
|
|
+ this.formData.campusName = campus.campusName;
|
|
|
+
|
|
|
+ // 清空下级选项
|
|
|
+ this.clearSubOptions('campus');
|
|
|
+ await this.loadAreaOptions(campus.id);
|
|
|
+ }
|
|
|
+ this.showCampusPicker = false;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 宿舍区选择确认
|
|
|
+ async handleAreaConfirm(e) {
|
|
|
+ const area = this.areaOptions.find((item) => item.id === e.value[0]);
|
|
|
+ if (area) {
|
|
|
+ this.formData.areaId = area.id;
|
|
|
+ this.formData.areaName = area.areaName;
|
|
|
+
|
|
|
+ // 清空下级选项
|
|
|
+ this.clearSubOptions('area');
|
|
|
+ await this.loadBuildingOptions(area.id);
|
|
|
+ }
|
|
|
+ this.showAreaPicker = false;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 宿舍楼选择确认
|
|
|
+ async handleBuildingConfirm(e) {
|
|
|
+ const building = this.buildingOptions.find((item) => item.id === e.value[0]);
|
|
|
+ if (building) {
|
|
|
+ this.formData.buildingId = building.id;
|
|
|
+ this.formData.buildingName = building.buildingName;
|
|
|
+
|
|
|
+ // 清空下级选项
|
|
|
+ this.clearSubOptions('building');
|
|
|
+ await this.loadRoomOptions(building.id);
|
|
|
+ }
|
|
|
+ this.showBuildingPicker = false;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 房间选择确认
|
|
|
+ async handleRoomConfirm(e) {
|
|
|
+ const room = this.roomOptions.find((item) => item.id === e.value[0]);
|
|
|
+ if (room) {
|
|
|
+ this.formData.roomId = room.id;
|
|
|
+ this.formData.roomName = room.roomName;
|
|
|
+ this.formData.roomCode = room.roomCode || room.roomName;
|
|
|
+
|
|
|
+ // 加载房间学生信息
|
|
|
+ await this.loadRoomStudents();
|
|
|
+ }
|
|
|
+ this.showRoomPicker = false;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 清空下级选项
|
|
|
+ clearSubOptions(level) {
|
|
|
+ switch (level) {
|
|
|
+ case 'campus':
|
|
|
+ this.formData.areaId = undefined;
|
|
|
+ this.formData.areaName = undefined;
|
|
|
+ this.areaOptions = [];
|
|
|
+ case 'area':
|
|
|
+ this.formData.buildingId = undefined;
|
|
|
+ this.formData.buildingName = undefined;
|
|
|
+ this.buildingOptions = [];
|
|
|
+ case 'building':
|
|
|
+ this.formData.roomId = undefined;
|
|
|
+ this.formData.roomName = undefined;
|
|
|
+ this.formData.roomCode = undefined;
|
|
|
+ this.roomOptions = [];
|
|
|
+ this.roomStudents = [];
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 检查类型选择确认
|
|
|
+ handleCheckTypeConfirm(e) {
|
|
|
+ this.formData.checkType = e.value[0];
|
|
|
+ this.showCheckTypePicker = false;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 检查级别选择确认
|
|
|
+ handleCheckLevelConfirm(e) {
|
|
|
+ this.formData.checkLevel = e.value[0];
|
|
|
+ this.showCheckLevelPicker = false;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 卫生等级选择确认
|
|
|
+ handleHygieneGradeConfirm(e) {
|
|
|
+ this.formData.hygieneGrade = e.value[0];
|
|
|
+
|
|
|
+ // 自动为所有学生设置相同评级
|
|
|
+ if (this.roomStudents.length > 0) {
|
|
|
+ this.roomStudents.forEach((student) => {
|
|
|
+ student.student_grade = e.value[0];
|
|
|
+ });
|
|
|
+
|
|
|
+ const gradeItem = this.xg_dorm_hygiene_grade.find((d) => d.value === e.value[0]);
|
|
|
+ if (gradeItem) {
|
|
|
+ uni.showToast({
|
|
|
+ title: `已为${this.roomStudents.length}名学生设置评级:${gradeItem.label}`,
|
|
|
+ icon: 'none',
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ this.showHygieneGradePicker = false;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 总分变化处理
|
|
|
+ handleTotalScoreChange() {
|
|
|
+ const score = parseFloat(this.formData.totalScore);
|
|
|
+ if (!isNaN(score) && score >= 0 && score <= 100 && this.roomStudents.length > 0) {
|
|
|
+ this.roomStudents.forEach((student) => {
|
|
|
+ student.student_score = score;
|
|
|
+ });
|
|
|
+
|
|
|
+ uni.showToast({
|
|
|
+ title: `已为${this.roomStudents.length}名学生设置个人得分:${score}分`,
|
|
|
+ icon: 'none',
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 学生分数变化处理
|
|
|
+ handleStudentScoreChange(student) {
|
|
|
+ const score = parseFloat(student.student_score);
|
|
|
+ if (!isNaN(score) && (score < 0 || score > 100)) {
|
|
|
+ uni.showToast({
|
|
|
+ title: '个人得分必须在0-100分之间',
|
|
|
+ icon: 'none',
|
|
|
+ });
|
|
|
+ student.student_score = null;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 出勤状态选择确认
|
|
|
+ handleAttendanceConfirm(e, student) {
|
|
|
+ student.attendance_status = e.value[0];
|
|
|
+ student.showAttendancePicker = false;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 学生评级选择确认
|
|
|
+ handleStudentGradeConfirm(e, student) {
|
|
|
+ student.student_grade = e.value[0];
|
|
|
+ student.showGradePicker = false;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取出勤状态显示文本
|
|
|
+ getAttendanceDisplay(value) {
|
|
|
+ const item = this.xg_student_attendance_status.find((d) => d.value === value);
|
|
|
+ return item ? item.label : '';
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取评级显示文本
|
|
|
+ getGradeDisplay(value) {
|
|
|
+ const item = this.xg_dorm_hygiene_grade.find((d) => d.value === value);
|
|
|
+ return item ? item.label : '';
|
|
|
+ },
|
|
|
+
|
|
|
+ // 选择图片
|
|
|
+ chooseImage() {
|
|
|
+ uni.chooseImage({
|
|
|
+ count: 9 - this.imageList.length,
|
|
|
+ sizeType: ['compressed'],
|
|
|
+ sourceType: ['album', 'camera'],
|
|
|
+ success: (res) => {
|
|
|
+ res.tempFilePaths.forEach((path) => {
|
|
|
+ this.uploadFile(path, true);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 选择文档
|
|
|
+ chooseDocument() {
|
|
|
+ // H5环境下的文件选择
|
|
|
+ // #ifdef H5
|
|
|
+ const input = document.createElement('input');
|
|
|
+ input.type = 'file';
|
|
|
+ input.accept = '.pdf,.doc,.docx,.txt,.xls,.xlsx';
|
|
|
+ input.onchange = (e) => {
|
|
|
+ const files = e.target.files;
|
|
|
+ for (let i = 0; i < files.length; i++) {
|
|
|
+ this.uploadFile(files[i], false);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ input.click();
|
|
|
+ // #endif
|
|
|
+
|
|
|
+ // 非H5环境提示
|
|
|
+ // #ifndef H5
|
|
|
+ uni.showToast({
|
|
|
+ title: '该功能仅在H5环境下支持',
|
|
|
+ icon: 'none',
|
|
|
+ });
|
|
|
+ // #endif
|
|
|
+ },
|
|
|
+
|
|
|
+ // 文件上传
|
|
|
+ async uploadFile(fileOrPath, isImage) {
|
|
|
+ const formData = {
|
|
|
+ bizType: 'dorm_hygiene_check_attachment',
|
|
|
+ };
|
|
|
+
|
|
|
+ try {
|
|
|
+ uni.showLoading({ title: '上传中...' });
|
|
|
+
|
|
|
+ const res = await smartUploadFile('/resource/oss/upload', fileOrPath, formData);
|
|
|
+
|
|
|
+ if (res.code === 200) {
|
|
|
+ const fileData = {
|
|
|
+ url: res.data.url,
|
|
|
+ ossId: res.data.ossId,
|
|
|
+ name: res.data.originalName || '未知文件',
|
|
|
+ };
|
|
|
+
|
|
|
+ if (isImage) {
|
|
|
+ this.imageList.push(fileData);
|
|
|
+ } else {
|
|
|
+ this.documentList.push(fileData);
|
|
|
+ }
|
|
|
+
|
|
|
+ uni.showToast({
|
|
|
+ title: '上传成功',
|
|
|
+ icon: 'success',
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ throw new Error(res.msg || '上传失败');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('文件上传失败:', error);
|
|
|
+ uni.showToast({
|
|
|
+ title: error.message || '上传失败',
|
|
|
+ icon: 'none',
|
|
|
+ });
|
|
|
+ } finally {
|
|
|
+ uni.hideLoading();
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 预览图片
|
|
|
+ previewImage(index) {
|
|
|
+ const urls = this.imageList.map((item) => item.url);
|
|
|
+ uni.previewImage({
|
|
|
+ current: index,
|
|
|
+ urls: urls,
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 删除图片
|
|
|
+ removeImage(index) {
|
|
|
+ this.imageList.splice(index, 1);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 下载文档
|
|
|
+ async downloadDocument(doc) {
|
|
|
+ try {
|
|
|
+ // H5环境下载
|
|
|
+ // #ifdef H5
|
|
|
+ const link = document.createElement('a');
|
|
|
+ link.href = doc.url;
|
|
|
+ link.download = doc.name;
|
|
|
+ link.click();
|
|
|
+ // #endif
|
|
|
+
|
|
|
+ // 非H5环境
|
|
|
+ // #ifndef H5
|
|
|
+ uni.downloadFile({
|
|
|
+ url: doc.url,
|
|
|
+ success: (res) => {
|
|
|
+ if (res.statusCode === 200) {
|
|
|
+ uni.openDocument({
|
|
|
+ filePath: res.tempFilePath,
|
|
|
+ success: () => {
|
|
|
+ console.log('打开文档成功');
|
|
|
+ },
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ });
|
|
|
+ // #endif
|
|
|
+ } catch (error) {
|
|
|
+ console.error('下载文档失败:', error);
|
|
|
+ uni.showToast({
|
|
|
+ title: '下载失败',
|
|
|
+ icon: 'none',
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 删除文档
|
|
|
+ removeDocument(index) {
|
|
|
+ this.documentList.splice(index, 1);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 格式化日期时间
|
|
|
+ formatDateTime(date) {
|
|
|
+ const year = date.getFullYear();
|
|
|
+ const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
|
+ const day = String(date.getDate()).padStart(2, '0');
|
|
|
+ const hours = String(date.getHours()).padStart(2, '0');
|
|
|
+ const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
|
+ const seconds = String(date.getSeconds()).padStart(2, '0');
|
|
|
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 表单提交
|
|
|
+ async handleSubmit() {
|
|
|
+ try {
|
|
|
+ // 表单验证
|
|
|
+ const valid = await this.$refs.formRef.validate();
|
|
|
+ if (!valid) return;
|
|
|
+
|
|
|
+ this.submitLoading = true;
|
|
|
+
|
|
|
+ // 处理附件ID
|
|
|
+ const allAttachments = [...this.imageList, ...this.documentList];
|
|
|
+ this.formData.attachmentIds = allAttachments.map((item) => item.ossId).join(',');
|
|
|
+
|
|
|
+ // 处理学生评分数据
|
|
|
+ const studentScores = this.roomStudents.map((student) => ({
|
|
|
+ id: student.id, // 编辑时包含ID
|
|
|
+ studentId: student.studentId,
|
|
|
+ studentName: student.studentName,
|
|
|
+ studentNo: student.studentNo,
|
|
|
+ className: student.className,
|
|
|
+ majorName: student.majorName,
|
|
|
+ collegeName: student.collegeName,
|
|
|
+ bedId: student.bedId,
|
|
|
+ bedCode: student.bedName,
|
|
|
+ studentScore: student.student_score ? Number(student.student_score) : undefined,
|
|
|
+ attendanceStatus: student.attendance_status,
|
|
|
+ studentGrade: student.student_grade,
|
|
|
+ isResponsiblePerson: student.isResponsiblePerson
|
|
|
+ ? Number(student.isResponsiblePerson)
|
|
|
+ : 0,
|
|
|
+ scoreRemarks: student.scoreRemarks || '',
|
|
|
+ improvementNotes: student.improvementNotes || '',
|
|
|
+ }));
|
|
|
+
|
|
|
+ // 构建提交数据
|
|
|
+ const submitData = {
|
|
|
+ ...this.formData,
|
|
|
+ studentScores: studentScores,
|
|
|
+ };
|
|
|
+
|
|
|
+ console.log('提交数据:', submitData);
|
|
|
+
|
|
|
+ // 调用API
|
|
|
+ const url =
|
|
|
+ this.pageType === 'add'
|
|
|
+ ? '/dormHygieneCheck/dormHygieneCheck'
|
|
|
+ : `/dormHygieneCheck/dormHygieneCheck`;
|
|
|
+
|
|
|
+ const res = await request({
|
|
|
+ url: url,
|
|
|
+ method: this.pageType === 'add' ? 'POST' : 'PUT',
|
|
|
+ data: submitData,
|
|
|
+ });
|
|
|
+
|
|
|
+ if (res && res.code === 200) {
|
|
|
+ uni.showToast({
|
|
|
+ title: '保存成功',
|
|
|
+ icon: 'success',
|
|
|
+ });
|
|
|
+
|
|
|
+ // 发送刷新事件
|
|
|
+ uni.$emit('refreshCheckList');
|
|
|
+
|
|
|
+ // 返回上一页
|
|
|
+ setTimeout(() => {
|
|
|
+ uni.navigateBack();
|
|
|
+ }, 1500);
|
|
|
+ } else {
|
|
|
+ throw new Error(res?.msg || '保存失败');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('提交失败:', error);
|
|
|
+ uni.showToast({
|
|
|
+ title: error.message || '保存失败',
|
|
|
+ icon: 'none',
|
|
|
+ });
|
|
|
+ } finally {
|
|
|
+ this.submitLoading = false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 返回上一页
|
|
|
+ goBack() {
|
|
|
+ uni.navigateBack();
|
|
|
+ },
|
|
|
+ },
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.page-container {
|
|
|
+ min-height: 100vh;
|
|
|
+ background-color: #f5f6fa;
|
|
|
+ padding-bottom: 120rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.form-container {
|
|
|
+ padding: 20rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.form-section {
|
|
|
+ background-color: #ffffff;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ padding: 32rpx;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
|
|
+}
|
|
|
+
|
|
|
+.section-title {
|
|
|
+ font-size: 32rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #303133;
|
|
|
+ margin-bottom: 32rpx;
|
|
|
+ padding-bottom: 16rpx;
|
|
|
+ border-bottom: 2rpx solid #e4e7ed;
|
|
|
+ display: block;
|
|
|
+}
|
|
|
+
|
|
|
+// 学生信息样式
|
|
|
+.student-list {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 24rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.student-item {
|
|
|
+ background-color: #f8f9fa;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ padding: 24rpx;
|
|
|
+ border: 1px solid #e9ecef;
|
|
|
+}
|
|
|
+
|
|
|
+.student-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 16rpx;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+ padding-bottom: 16rpx;
|
|
|
+ border-bottom: 1px solid #e9ecef;
|
|
|
+}
|
|
|
+
|
|
|
+.student-name {
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #303133;
|
|
|
+}
|
|
|
+
|
|
|
+.student-no {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #606266;
|
|
|
+ background-color: #e9ecef;
|
|
|
+ padding: 4rpx 8rpx;
|
|
|
+ border-radius: 4rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.student-bed {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #909399;
|
|
|
+ background-color: #f0f0f0;
|
|
|
+ padding: 4rpx 8rpx;
|
|
|
+ border-radius: 4rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.student-form {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 16rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.form-row {
|
|
|
+ display: flex;
|
|
|
+ gap: 20rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.form-col {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 8rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.form-label {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #606266;
|
|
|
+ margin-bottom: 8rpx;
|
|
|
+}
|
|
|
+
|
|
|
+// 附件样式
|
|
|
+.attachment-section {
|
|
|
+ margin-bottom: 32rpx;
|
|
|
+
|
|
|
+ &:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.attachment-title {
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #303133;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+ display: block;
|
|
|
+}
|
|
|
+
|
|
|
+// 图片上传样式
|
|
|
+.image-upload-container {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.image-list {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(3, 1fr);
|
|
|
+ gap: 16rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.image-item {
|
|
|
+ position: relative;
|
|
|
+ width: 100%;
|
|
|
+ aspect-ratio: 1;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.image-preview {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ border-radius: 12rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.image-actions {
|
|
|
+ position: absolute;
|
|
|
+ top: 8rpx;
|
|
|
+ right: 8rpx;
|
|
|
+ background-color: rgba(0, 0, 0, 0.5);
|
|
|
+ border-radius: 50%;
|
|
|
+ width: 48rpx;
|
|
|
+ height: 48rpx;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+
|
|
|
+.image-upload-btn {
|
|
|
+ width: 100%;
|
|
|
+ aspect-ratio: 1;
|
|
|
+ border: 2rpx dashed #d9d9d9;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ gap: 8rpx;
|
|
|
+ background-color: #fafafa;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-text {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #909399;
|
|
|
+}
|
|
|
+
|
|
|
+// 文档上传样式
|
|
|
+.document-upload-container {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.document-list {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 16rpx;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.document-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 16rpx;
|
|
|
+ background-color: #f8f9fa;
|
|
|
+ border-radius: 8rpx;
|
|
|
+ border: 1px solid #e9ecef;
|
|
|
+}
|
|
|
+
|
|
|
+.document-info {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 12rpx;
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.document-name {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #303133;
|
|
|
+ flex: 1;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+
|
|
|
+.document-actions {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 16rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.document-upload-btn {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ gap: 12rpx;
|
|
|
+ padding: 24rpx;
|
|
|
+ border: 2rpx dashed #d9d9d9;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ background-color: #fafafa;
|
|
|
+}
|
|
|
+
|
|
|
+// 底部操作按钮
|
|
|
+.bottom-actions {
|
|
|
+ position: fixed;
|
|
|
+ bottom: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ padding: 20rpx;
|
|
|
+ background-color: #ffffff;
|
|
|
+ border-top: 1px solid #e4e7ed;
|
|
|
+ display: flex;
|
|
|
+ gap: 20rpx;
|
|
|
+ z-index: 999;
|
|
|
+}
|
|
|
+
|
|
|
+.bottom-actions .u-button {
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+
|
|
|
+// 响应式设计
|
|
|
+@media (max-width: 375px) {
|
|
|
+ .form-container {
|
|
|
+ padding: 16rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .form-section {
|
|
|
+ padding: 24rpx;
|
|
|
+ margin-bottom: 16rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .student-item {
|
|
|
+ padding: 20rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .form-row {
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 16rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .image-list {
|
|
|
+ grid-template-columns: repeat(2, 1fr);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// uview组件样式调整
|
|
|
+::v-deep .u-form-item {
|
|
|
+ margin-bottom: 32rpx;
|
|
|
+}
|
|
|
+
|
|
|
+::v-deep .u-input {
|
|
|
+ font-size: 28rpx;
|
|
|
+}
|
|
|
+
|
|
|
+::v-deep .u-textarea {
|
|
|
+ font-size: 28rpx;
|
|
|
+}
|
|
|
+
|
|
|
+::v-deep .u-button {
|
|
|
+ border-radius: 12rpx;
|
|
|
+}
|
|
|
+</style>
|