<!-- 任务执行提交页面 -->
<template>
  <view class="rw-detail-page" :class="{ 'readonly-mode': isReadOnly }">
    <!-- 提交遮罩层 -->
    <view v-if="isSubmitting" class="submit-overlay">
      <view class="submit-loading">
        <view class="loading-spinner"></view>
        <text class="loading-text">提交中...</text>
      </view>
    </view>
    
    <view v-if="isLoading" class="loading-indicator">加载中...</view>
    <view v-else class="content-wrapper">
      <view class="p-15">
        <!-- 第一部分：任务要求 -->
        <view class="rw-info-section">
          <view class="section-title">任务要求</view>
          
          <!-- 只读模式提示 -->
          <view v-if="isReadOnly" class="readonly-tip">
            <text class="tip-text">📖 只读模式 - 查看已提交的内容</text>
          </view>
          
          <!-- 任务名称 -->
          <view class="info-item">
            <text class="label">任务名称：</text>
            <text class="value title-bold">{{ rw.rwmc }}</text>
          </view>
          
          <!-- 任务描述 -->
          <view v-if="rw.rwms" class="info-item">
            <text class="label">任务描述：</text>
            <text class="value">{{ rw.rwms }}</text>
          </view>
          
          <!-- 任务时间 -->
          <view v-if="rw.rwkstime" class="info-item">
            <text class="label">任务时间：</text>
            <text class="value">{{ rw.rwkstime }}</text>
          </view>
          
          <!-- 附件预览 -->
          <BasicFilePreview 
            v-if="rw.rwfj && rw.fjmx"
            :file-url="rw.rwfj"
            :file-name="rw.fjmx"
            :file-format="getFileFormat(rw.fjmx)"
            class="mt-15"
          />
        </view>
        
        <!-- 第二部分：任务执行 -->
        <view class="rw-execute-section">
          <view class="section-title">任务执行</view>
          <view class="execute-form">
            <BasicForm :schema="schema" v-model="formData" :disabled="isReadOnly">
            </BasicForm>
          </view>
        </view>
      </view>
    </view>
    
    <!-- 提交按钮 - 固定在底部 -->
    <view v-if="!isReadOnly" class="submit-button-fixed">
      <button class="action-button" @click="saveRwZx" :disabled="isSubmitting">
        {{ isSubmitting ? '提交中...' : '提交' }}
      </button>
    </view>
  </view>
</template>

<script lang="ts" setup>
import {ref, reactive} from 'vue';
import {onLoad} from '@dcloudio/uni-app';
import {rwFindInfoByRwId, rwflFindRwlxsByRwId, rwzxExecutedInfoByRwIdAndJsApi, rwzxSaveApi} from "@/api/base/server";
import {useForm} from "@/components/BasicForm/hooks/useForm";
import {navigateBack, showToast} from "@/utils/uniapp";
import {useUserStore} from "@/store/modules/user";
import { ImageVideoUpload, type FileItem, COMPRESS_PRESETS } from "@/components/ImageVideoUpload";
import { attachmentUpload } from "@/api/system/upload";
import BasicFilePreview from "@/components/BasicFile/preview.vue";

interface MessageDetail {
  id: string; // Assuming an ID is passed or can be derived
  title: string;
  desc: string;
  date: string;
  timeAgo: string;
  tagText: string;
  tagType: string;
  likes?: number;
  comments?: number;
  // Add other fields as necessary
}

interface RwInfo {
  id?: string;
  rwmc?: string; // 任务名称
  rwms?: string; // 任务描述
  rwkstime?: string; // 任务开始时间
  rwfj?: string; // 任务附件URL
  fjmx?: string; // 附件名称
  rwlxes?: any[]; // 任务类型列表
  rwzxqds?: any[]; // 任务执行清单
  [key: string]: any; // 允许其他属性
}

const formData: any = ref({})
const messageId = ref<string>('');
const jsId = ref<string>(''); // 教师ID
const executionId = ref<string>(''); // 执行ID
const isReadOnly = ref<boolean>(false); // 只读模式
const isSubmitting = ref<boolean>(false); // 提交状态
const submitTimer = ref<any>(null); // 防抖定时器

const messageDetail = ref<MessageDetail | null>({
  id: 'todo1',
  title: '教务通知 (待办)',
  desc: '学校召开期初教学准备会议暨首次教学工作例会. 会议强调了新学期的教学重点和要求，请各位老师认真准备。',
  date: '2025-02-17',
  timeAgo: '8 mins 前',
  tagText: '通知',
  tagType: 'notice',
  likes: 6,
  comments: 12
});
const isLoading = ref(false);
const rwflx: any = ref([])
const rw = ref<RwInfo>({})
const schema = ref<FormsSchema[]>([])
const {getUser} = useUserStore()

async function saveRwZx() {
  // 防抖处理
  if (isSubmitting.value) {
    console.log('正在提交中，请勿重复点击');
    return;
  }
  
  // 清除之前的定时器
  if (submitTimer.value) {
    clearTimeout(submitTimer.value);
  }
  
  // 设置防抖延迟
  submitTimer.value = setTimeout(async () => {
    await performSubmit();
  }, 300);
}

async function performSubmit() {
  if (isSubmitting.value) {
    return;
  }
  
  isSubmitting.value = true;
  
  try {
    const result = [];
    for (let i = 0; i < rwflx.value.length; i++) {
    const fieldId = rwflx.value[i].id;
    let fieldValue = formData.value[fieldId];
    
    // 处理上传类型的任务
    let fileNames = '';
    if (rwflx.value[i].rwfl == "sctp" || rwflx.value[i].rwfl == "scsp" || rwflx.value[i].rwfl == "scwd") {
      // 收集上传文件的URL和文件名
      const fileUrls = [];
      const names = [];
      
      if (rwflx.value[i].rwfl == "sctp") {
        // 图片上传
        const images = formData.value[`${fieldId}_imageList`] || [];
        images.forEach((img: any) => {
          if (img.url) {
            fileUrls.push(img.url);
            names.push(img.name || img.url.split('/').pop() || 'image.jpg');
          }
        });
      } else if (rwflx.value[i].rwfl == "scsp") {
        // 视频上传
        const videos = formData.value[`${fieldId}_videoList`] || [];
        videos.forEach((video: any) => {
          if (video.url) {
            fileUrls.push(video.url);
            names.push(video.name || video.url.split('/').pop() || 'video.mp4');
          }
        });
      } else if (rwflx.value[i].rwfl == "scwd") {
        // 文档上传
        const files = formData.value[`${fieldId}_fileList`] || [];
        files.forEach((file: any) => {
          if (file.url) {
            fileUrls.push(file.url);
            names.push(file.name || file.url.split('/').pop() || 'document');
          }
        });
      }
      
      fieldValue = fileUrls.join(',');
      fileNames = names.join(',');
    }
    
    
    // 验证必填项 - 针对上传类型使用不同的判断方式
    if (rwflx.value[i].rwbs) {
      let isEmpty = false;
      
      if (rwflx.value[i].rwfl == "sctp" || rwflx.value[i].rwfl == "scsp" || rwflx.value[i].rwfl == "scwd") {
        // 上传类型的验证：检查是否有上传的文件
        if (rwflx.value[i].rwfl == "sctp") {
          const images = formData.value[`${fieldId}_imageList`] || [];
          isEmpty = images.length === 0;
        } else if (rwflx.value[i].rwfl == "scsp") {
          const videos = formData.value[`${fieldId}_videoList`] || [];
          isEmpty = videos.length === 0;
        } else if (rwflx.value[i].rwfl == "scwd") {
          const files = formData.value[`${fieldId}_fileList`] || [];
          isEmpty = files.length === 0;
        }
      } else {
        // 非上传类型的验证：检查字段值是否为空
        isEmpty = !fieldValue || fieldValue == "";
      }
      
      if (isEmpty) {
        showToast("请填写必填项!")
        isSubmitting.value = false;
        return;
      }
    }
    // 查找对应的执行记录ID
    const existingRecord = rwzxqds.value.find(item => item.rwlxId === fieldId);
    const recordId = existingRecord ? existingRecord.id : undefined;
    
    result.push({
      id: recordId, // 如果有现有记录则保留ID，否则为undefined（新增）
      rwlxId: fieldId,
      rwzxqdtx: fieldValue,
      wjmc: fileNames || undefined, // 文件名，只有上传类型才有
    })
  }
  await rwzxSaveApi({
    id: executionId.value, // 执行记录ID，如果有的话就是更新，没有就是新增
    rwId: rw.value.id, // 任务ID
    rwzxfzr: jsId.value || getUser.id, // 执行人（教师ID）
    mobile: getUser.mobile, // 手机号
    rwzxqdDtos: result // 执行清单
  })
  showToast("操作成功!");
  
  // 发送刷新事件
  uni.$emit('refreshTaskExecution');
  
  // 延迟一下再跳转，让用户看到成功提示
  setTimeout(() => {
    // 返回到任务执行页面
    uni.navigateBack();
  }, 1500);
  
  } catch (error) {
    console.error('提交失败:', error);
    showToast("提交失败，请重试");
  } finally {
    isSubmitting.value = false;
  }
}

// 获取文件格式
const getFileFormat = (fileName: string) => {
  if (!fileName) return '';
  const parts = fileName.split('.');
  return parts.length > 1 ? parts[parts.length - 1].toLowerCase() : '';
};

const rwzxqds = ref<any[]>([])
onLoad(async (options: any) => {
  console.log('页面加载参数:', options);
  
  let taskId = '';
  
  // 从全局存储中获取参数数据
  const storedParams = uni.getStorageSync('taskSubmitData');
  
  if (storedParams) {
    try {
      taskId = storedParams.id;
      jsId.value = storedParams.jsId || '';
      executionId.value = storedParams.executionId || '';
      isReadOnly.value = storedParams.isReadOnly || false;
      console.log('从全局存储解析参数成功:', { taskId, jsId: jsId.value, executionId: executionId.value, isReadOnly: isReadOnly.value });
      
      // 清除存储的参数数据
      uni.removeStorageSync('taskSubmitData');
    } catch (error) {
      console.error('解析全局存储参数失败:', error);
      taskId = options.id || '';
    }
  } else {
    // 兼容原有的URL参数方式（向后兼容）
    if (options && options.params) {
      try {
        const params = JSON.parse(decodeURIComponent(options.params));
        taskId = params.id;
        jsId.value = params.jsId || '';
        executionId.value = params.executionId || '';
        isReadOnly.value = params.isReadOnly || false;
        console.log('解析URL参数成功:', { taskId, jsId: jsId.value, executionId: executionId.value, isReadOnly: isReadOnly.value });
      } catch (error) {
        console.error('解析URL参数失败:', error);
        taskId = options.id || '';
      }
    } else if (options && options.id) {
      taskId = options.id;
    }
  }
  
  if (taskId) {
    const {result} = await rwFindInfoByRwId({
      rwId: taskId
    });
    rwflx.value = result.rwlxes;
    rw.value = result;
    for (let i = 0; i < rwflx.value.length; i++) {
      // 处理上传类型的任务
      if (rwflx.value[i].rwfl == "sctp" || rwflx.value[i].rwfl == "scsp" || rwflx.value[i].rwfl == "scwd") {
        // 初始化表单数据
        const fieldId = rwflx.value[i].id;
        if (rwflx.value[i].rwfl == "sctp") {
          formData.value[`${fieldId}_imageList`] = [];
        } else if (rwflx.value[i].rwfl == "scsp") {
          formData.value[`${fieldId}_videoList`] = [];
        } else if (rwflx.value[i].rwfl == "scwd") {
          formData.value[`${fieldId}_fileList`] = [];
        }
        // 根据任务类型配置上传组件
        let componentConfig = {};
        
        if (rwflx.value[i].rwfl == "sctp") {
          // 上传图片
          componentConfig = {
            component: "ImageVideoUpload",
            componentProps: {
              enableImage: true,
              enableVideo: false,
              enableFile: false,
              maxImageCount: 30,
              uploadApi: attachmentUpload,
              compressConfig: COMPRESS_PRESETS.medium,
              imageList: formData.value[`${fieldId}_imageList`] || []
            }
          };
        } else if (rwflx.value[i].rwfl == "scsp") {
          // 上传视频
          componentConfig = {
            component: "ImageVideoUpload",
            componentProps: {
              enableImage: false,
              enableVideo: true,
              enableFile: false,
              maxVideoCount: 30,
              uploadApi: attachmentUpload,
              compressConfig: COMPRESS_PRESETS.medium,
              videoList: formData.value[`${fieldId}_videoList`] || []
            }
          };
        } else if (rwflx.value[i].rwfl == "scwd") {
          // 上传文档
          componentConfig = {
            component: "ImageVideoUpload",
            componentProps: {
              enableImage: false,
              enableVideo: false,
              enableFile: true,
              maxFileCount: 30,
              allowedFileTypes: ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'mp3', 'wav', 'zip', 'rar'],
              uploadApi: attachmentUpload,
              compressConfig: COMPRESS_PRESETS.medium,
              fileList: formData.value[`${fieldId}_fileList`] || []
            }
          };
        }
        
        // 对于上传类型，使用特殊的字段名
        const schemaField = rwflx.value[i].rwfl === "sctp" ? `${rwflx.value[i].id}_imageList` :
                           rwflx.value[i].rwfl === "scsp" ? `${rwflx.value[i].id}_videoList` :
                           rwflx.value[i].rwfl === "scwd" ? `${rwflx.value[i].id}_fileList` :
                           `${rwflx.value[i].id}`;
        
        schema.value.push({
          field: schemaField,
          label: `${rwflx.value[i].rwbt}`,
          required: rwflx.value[i].rwbs && !isReadOnly.value, // 只读模式下不要求必填
          itemProps: {
            labelPosition: "top",
          },
          ...componentConfig,
          componentProps: {
            ...componentConfig.componentProps,
            disabled: isReadOnly.value // 禁用上传组件
          }
        })
      } else if (rwflx.value[i].rwfl == "fwb") {
        // 富文本类型 - 使用富文本编辑器
        schema.value.push({
          field: `${rwflx.value[i].id}`,
          label: `${rwflx.value[i].rwbt}`,
          component: "BasicEditor",  // 使用富文本编辑器组件
          required: rwflx.value[i].rwbs && !isReadOnly.value, // 只读模式下不要求必填
          itemProps: {
            labelPosition: "top",
          },
          componentProps: {
            placeholder: isReadOnly.value ? "" : "请输入富文本内容，支持插入图片",
            disabled: isReadOnly.value // 禁用编辑器
          },
        })
      } else if (rwflx.value[i].rwfl == "text") {
        // 普通文本类型 - 使用 BasicInput
        schema.value.push({
          field: `${rwflx.value[i].id}`,
          label: `${rwflx.value[i].rwbt}`,
          component: "BasicInput",
          required: rwflx.value[i].rwbs && !isReadOnly.value, // 只读模式下不要求必填
          itemProps: {
            labelPosition: "top",
          },
          componentProps: {
            type: "textarea",
            placeholder: isReadOnly.value ? "" : "请输入内容",
            disabled: isReadOnly.value // 禁用文本输入
          },
        })
      } else if (rwflx.value[i].rwfl == "dxsx" || rwflx.value[i].rwfl == "dxxz") {
        // 同时支持中文分号（；）和英文分号（;）分割选项
        let options = rwflx.value[i].remark.split(/[；;]/);
        let range = [];
        for (let j = 0; j < options.length; j++) {
          range.push({
            name: options[j]
          });
        }
        schema.value.push({
          field: `${rwflx.value[i].id}`,
          label: `${rwflx.value[i].rwbt}`,
          component: "BasicPicker",
          required: rwflx.value[i].rwbs && !isReadOnly.value, // 只读模式下不要求必填
          itemProps: {
            labelPosition: "top",
          },
          componentProps: {
            range: range,
            rangeKey: "name",
            savaKey: "name",
            disabled: isReadOnly.value // 禁用选择器
          },
        })
      }
    }
    
    
    const res = await rwzxExecutedInfoByRwIdAndJsApi({
      rwId: taskId,
      jsId: jsId.value || getUser.id // 使用传入的jsId，如果没有则使用当前用户ID
    });
    if (res && res.result && res.result.length) {
      rwzxqds.value = res.result;
      const showData = {};
      
      for (let i = 0; i < rwzxqds.value.length; i++) {
        const record = rwzxqds.value[i];
        const rwlxId = record.rwlxId;
        const rwzxqdtx = record.rwzxqdtx;
        
        // 查找对应的任务类型
        const taskType = rwflx.value.find(item => item.id === rwlxId);
        
        if (taskType) {
          if (taskType.rwfl === "sctp") {
            // 图片上传类型 - 解析URL和文件名并创建图片对象
            if (rwzxqdtx) {
              const urls = rwzxqdtx.split(',').filter(Boolean);
              const names = record.wjmc ? record.wjmc.split(',').filter(Boolean) : [];
              const images = urls.map((url, index) => ({
                url: url.trim(),
                name: names[index] || url.split('/').pop() || 'image.jpg',
                tempPath: undefined
              }));
              showData[`${rwlxId}_imageList`] = images;
            }
          } else if (taskType.rwfl === "scsp") {
            // 视频上传类型
            if (rwzxqdtx) {
              const urls = rwzxqdtx.split(',').filter(Boolean);
              const names = record.wjmc ? record.wjmc.split(',').filter(Boolean) : [];
              const videos = urls.map((url, index) => ({
                url: url.trim(),
                name: names[index] || url.split('/').pop() || 'video.mp4',
                tempPath: undefined
              }));
              showData[`${rwlxId}_videoList`] = videos;
            }
          } else if (taskType.rwfl === "scwd") {
            // 文档上传类型
            if (rwzxqdtx) {
              const urls = rwzxqdtx.split(',').filter(Boolean);
              const names = record.wjmc ? record.wjmc.split(',').filter(Boolean) : [];
              const files = urls.map((url, index) => ({
                url: url.trim(),
                name: names[index] || url.split('/').pop() || 'document',
                tempPath: undefined,
                type: 'document',
                extension: url.split('.').pop() || ''
              }));
              showData[`${rwlxId}_fileList`] = files;
            }
          } else {
            // 文本等其他类型
            showData[rwlxId] = rwzxqdtx;
          }
        }
      }
      
      // 合并已保存的数据，而不是完全覆盖
      formData.value = { ...formData.value, ...showData };
      
      // 更新 schema 中上传组件的初始值
      for (let i = 0; i < schema.value.length; i++) {
        const schemaItem = schema.value[i];
        if (schemaItem.component === "ImageVideoUpload" && schemaItem.field) {
          const fieldName = schemaItem.field;
          
          if (fieldName.includes('_imageList') && formData.value[fieldName]) {
            schemaItem.componentProps.imageList = formData.value[fieldName];
          } else if (fieldName.includes('_videoList') && formData.value[fieldName]) {
            schemaItem.componentProps.videoList = formData.value[fieldName];
          } else if (fieldName.includes('_fileList') && formData.value[fieldName]) {
            schemaItem.componentProps.fileList = formData.value[fieldName];
          }
        }
      }
      
      // 调试：输出回显数据
      console.log('数据回显 - showData:', showData);
      console.log('数据回显 - formData.value:', formData.value);
      console.log('更新后的 schema:', schema.value);
      
      // 调试：输出文件名处理情况
      console.log('文件名处理 - rwzxqds.value:', rwzxqds.value);
    }
  } else {
    console.error('Message ID/Data is missing!');
    uni.showToast({title: '加载失败，缺少信息', icon: 'none'});
  }
});
</script>

<style scoped lang="scss">
.rw-detail-page {
  background-color: #f4f5f7;
  min-height: 100vh;
  padding-bottom: 80px; // 为底部按钮留出空间
  box-sizing: border-box;
}

.loading-indicator {
  text-align: center;
  color: #999;
  padding: 40px 15px;
  font-size: 14px;
}

.content-wrapper {
  .p-15 {
    padding: 15px;
  }
  
  .mt-15 {
    margin-top: 15px;
  }
}

// 第一部分：任务要求
.rw-info-section {
  margin-bottom: 20px;
  padding: 15px;
  background: #fff;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  
  .section-title {
    font-size: 16px;
    font-weight: bold;
    margin-bottom: 15px;
    color: #333;
    border-bottom: 2px solid #007aff;
    padding-bottom: 5px;
  }
  
  .readonly-tip {
    margin-bottom: 15px;
    padding: 8px 12px;
    background-color: #e6f7ff;
    border: 1px solid #91d5ff;
    border-radius: 4px;
    
    .tip-text {
      font-size: 12px;
      color: #1890ff;
    }
  }
  
  .info-item {
    display: flex;
    margin-bottom: 15px;
    
    &:last-child {
      margin-bottom: 0;
    }
    
    .label {
      width: 80px;
      color: #666;
      font-size: 14px;
      flex-shrink: 0;
    }
    
    .value {
      flex: 1;
      color: #333;
      font-size: 14px;
      word-break: break-word;
      
      &.title-bold {
        font-weight: bold;
        font-size: 16px;
      }
    }
  }
}

// 第二部分：任务执行
.rw-execute-section {
  margin-bottom: 20px;
  padding: 15px;
  background: #fff;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  
  .section-title {
    font-size: 16px;
    font-weight: bold;
    margin-bottom: 15px;
    color: #333;
    border-bottom: 2px solid #007aff;
    padding-bottom: 5px;
  }
  
  .execute-form {
    padding-top: 5px;
  }
}

// 提交按钮 - 固定在底部
.submit-button-fixed {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 15px;
  background-color: #fff;
  box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
  z-index: 10;
  border-top: 1px solid #eee;
  
  .action-button {
    width: 100%;
    height: 44px;
    line-height: 44px;
    font-size: 16px;
    font-weight: 500;
    border-radius: 8px;
    background-color: #409eff;
    color: #ffffff;
    border: none;
    
    &:active:not(:disabled) {
      background-color: #3a8ee6;
      transform: translateY(1px);
    }
    
    &:disabled {
      background-color: #d9d9d9 !important;
      color: #999 !important;
      cursor: not-allowed;
      opacity: 0.6;
    }
  }
}

// 为输入框添加基本边框
:deep(.uni-input),
:deep(.uni-textarea) {
  width: 100% !important;
  min-height: 35px !important;
  font-size: 13px !important;
  border: 1px #CCCCCC solid !important;
  border-radius: 3px !important;
  padding: 8px 12px !important;
  box-sizing: border-box !important;
}

:deep(input),
:deep(textarea) {
  width: 100% !important;
  min-height: 35px !important;
  font-size: 13px !important;
  border: 1px #CCCCCC solid !important;
  border-radius: 3px !important;
  padding: 8px 12px !important;
  box-sizing: border-box !important;
}

// 为 BasicForm 中的 label 添加样式
:deep(.basic-form) {
  .form-label,
  .label,
  .uni-form-item__label {
    width: 100% !important;
    white-space: normal !important;
    word-break: break-word !important;
    font-size: 15px !important;
    font-weight: bold !important;
    color: #333 !important;
    text-align: left !important;
    display: block !important;
    line-height: 1.4 !important;
    max-width: 100% !important;
    overflow-wrap: break-word !important;
  }
}

// 直接针对包含标签文本的 view 元素
:deep(view) {
  white-space: normal !important;
  word-break: normal !important;
  overflow-wrap: break-word !important;
}

// 只读模式样式
.readonly-mode {
  :deep(input),
  :deep(textarea),
  :deep(.uni-input),
  :deep(.uni-textarea) {
    background-color: #f5f5f5 !important;
    color: #666 !important;
    cursor: not-allowed !important;
  }
  
  :deep(.upload-container),
  :deep(.picker-container) {
    opacity: 0.6;
    pointer-events: none;
  }
}

// 提交遮罩层样式
.submit-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9999;
}

.submit-loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background-color: #fff;
  padding: 30px;
  border-radius: 12px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
}

.loading-spinner {
  width: 40px;
  height: 40px;
  border: 3px solid #f3f3f3;
  border-top: 3px solid #409eff;
  border-radius: 50%;
  animation: spin 1s linear infinite;
  margin-bottom: 16px;
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

.loading-text {
  font-size: 16px;
  color: #333;
  font-weight: 500;
}
</style>
