xwt
2025-10-30 4a9c0f7ddb5eae77b1f833bd2223e33fe6bb2918
pages/QC/XJ/Add.vue
@@ -79,13 +79,15 @@
            <table>
              <thead>
                <tr>
                  <th width="20%" style="text-align: center;">检验项目</th>
                  <th width="8%" style="text-align: center;">序号</th>
                  <th width="17%" style="text-align: center;">检验项目</th>
                  <th width="50%" style="text-align: center;">检验描述</th>
                  <th width="15%" style="text-align: center;">记录(点击)</th>
                </tr>
              </thead>
              <tbody>
                <tr v-for="(item, index) in tableData" :key="index">
                  <td style="text-align: center;">{{ item.forder || (index + 1) }}</td>
                  <td>{{ item.projName }}</td>
                  <td>
                    <view v-if="item.result=='合格'" class="watermark approved">
@@ -119,9 +121,15 @@
         
         <!-- 已有单据的操作按钮 -->
         <button class="action-btn secondary" v-if="!isUpdate && !isShowTable" @click="toImage">上传/查看图片</button>
       <button class="action-btn secondary" v-if="!isUpdate && !isShowTable" @click="fetchDrawingNumber(formData.itemNo)">
          调取PLM图纸
       </button>
       <button class="action-btn secondary" v-if="!isUpdate && !isShowTable" @click="getBom">
          Bom用料清单
       </button>
         <button class="action-btn secondary" v-if="!isUpdate && !isShowTable" @click="viewAttachmentInfo">查看附件信息</button>
         <button class="action-btn danger" v-if="!isUpdate && !formData.fcheckResu && !isShowTable && formData.fsubmit !== 1" @click="removeXJ">删除单据</button>
         <button class="action-btn danger" v-if="!isUpdate && !formData.fcheckResu && !isShowTable && formData.fsubmit !== 1" @click="showDeleteConfirmDialog">删除单据</button>
         <button class="action-btn warning" v-if="!isUpdate && !isShowTable && formData.fsubmit !== 1" @click="saveRemarks">添加不合格描述</button>
         
         <!-- 检验项目管理按钮 -->
@@ -268,6 +276,61 @@
          </div>
        </view>
      </view>
     <view class="barcode">
        <u-modal :show="itemShow" title="物料明细" @confirm="drawingConfirm" @cancel="itemCancel"
           showCancelButton :z-index="1000">
           <uni-table border stripe emptyText="暂无更多数据" style="margin-left: 5px;margin-right: 5px;height: 400px;max-height: 60vh;overflow-y: auto;">
              <uni-tr>
                 <uni-th align="center">料号</uni-th>
                 <uni-th align="center" width="90">名称</uni-th>
                 <uni-th align="center" width="90">规格型号</uni-th>
                 <uni-th align="center" width="150">调取PLM图纸</uni-th>
              </uni-tr>
              <uni-tr v-for="(item,index) in (drawing || [])" style="height: 100px;">
                 <uni-td align="center">{{item.itemNo}}</uni-td>
                 <uni-td align="center" >
                    <div >{{item.itemName}}</div>
                 </uni-td>
                 <uni-td align="center" >
                    <div>{{item.itemModel}}</div>
                 </uni-td>
                 <uni-td align="center" class="click-wd">
                    <div @click="fetchDrawingNumber(item.itemNo)">调取图纸</div>
                 </uni-td>
              </uni-tr>
           </uni-table>
        </u-modal>
     </view>
     <view class="barcode">
        <u-modal :show="drawingShow" title="图纸明细" @confirm="drawingConfirm" @cancel="drawingCancel"
           showCancelButton :z-index="1000">
           <uni-table border stripe emptyText="暂无更多数据" style="margin-left: 5px;margin-right: 5px;height: 400px;max-height: 60vh;overflow-y: auto;">
              <uni-tr>
                 <uni-th align="center">相关文档</uni-th>
                 <uni-th align="center" width="90">有无关联PDF文件</uni-th>
                 <uni-th align="center" width="90">能否打开文件</uni-th>
                 <uni-th align="center" width="150">操作(点击)</uni-th>
              </uni-tr>
              <uni-tr v-for="(item,index) in (drawing || [])" style="height: 100px;">
                 <uni-td align="center">{{item.fName}}</uni-td>
                 <uni-td align="center" style="font-size:25px;">
                    <div v-if="item.fRelevantObject==' '" style="color: #E47470;">×</div>
                    <div style="color: #90BA87;" v-else>√</div>
                 </uni-td>
                 <uni-td align="center" style="font-size:25px;">
                    <div v-if="item.isSupported || item.fRelevantObject!=' '" style="color: #90BA87;">√</div>
                    <div style="color: #E47470;" v-else>×</div>
                 </uni-td>
                 <uni-td align="center" class="click-wd">
                    <div @click="openDrawings(item)">打开文档</div>
                 </uni-td>
              </uni-tr>
           </uni-table>
        </u-modal>
     </view>
      <!-- 文件预览弹窗 -->
      <view v-if="showFilePreviewPopup" class="overlay">
@@ -307,6 +370,32 @@
          <div class="file-preview-actions">
            <button v-if="previewType !== 'text'" class="file-preview-btn download-btn" @click="downloadPreviewFile">📥 下载文件</button>
            <button class="file-preview-btn close-btn" @click="closeFilePreview">关闭</button>
          </div>
        </view>
      </view>
      <!-- 删除确认弹窗 -->
      <view v-if="showDeleteConfirm" class="overlay">
        <view class="popup delete-confirm-popup">
          <h3 class="delete-confirm-title">⚠️ 确认删除</h3>
          <div class="delete-confirm-divider"></div>
          <div class="delete-confirm-content">
            <view class="delete-warning-icon">🗑️</view>
            <view class="delete-warning-text">您确定要删除此检验单吗?</view>
            <view class="delete-warning-detail">删除后将无法恢复,请谨慎操作!</view>
            <view class="delete-countdown">
              <view class="countdown-text">确认按钮将在 <text class="countdown-number">{{ deleteCountdown }}</text> 秒后可用</view>
              <view class="countdown-progress">
                <view class="countdown-bar" :style="{ width: countdownProgress + '%' }"></view>
              </view>
            </view>
          </div>
          <div class="delete-confirm-actions">
            <button class="delete-confirm-btn cancel-btn" @click="cancelDelete">取消</button>
            <button class="delete-confirm-btn confirm-btn"
              :disabled="deleteCountdown > 0"
              :class="{ 'disabled': deleteCountdown > 0 }"
              @click="confirmDelete">确认删除</button>
          </div>
        </view>
      </view>
@@ -356,10 +445,16 @@
        lineNo: "",
  
        tableData: [],
        drawing: [],
  
        isSubmit: true,
      isSubmit: true,
  
        isUpdate: true,
      isUpdate: true,
      isShowTable: false,
      drawingShow: false,
      itemShow: false,
  
        remarks: "",
        remarksPopup: false,
@@ -379,7 +474,13 @@
        previewTitle: '',
        previewContent: '',
        previewType: '',
        previewFileUrl: ''
        previewFileUrl: '',
        // 删除确认相关数据
        showDeleteConfirm: false,
        deleteCountdown: 5,
        countdownProgress: 0,
        deleteTimer: null
      };
    },
@@ -453,6 +554,53 @@
        } else {
          return '检验项目详情';
        }
      },
      // 显示删除确认弹窗
      showDeleteConfirmDialog() {
        this.showDeleteConfirm = true;
        this.deleteCountdown = 5;
        this.countdownProgress = 0;
        this.startDeleteCountdown();
      },
      // 开始倒计时
      startDeleteCountdown() {
        this.deleteTimer = setInterval(() => {
          this.deleteCountdown--;
          this.countdownProgress = ((5 - this.deleteCountdown) / 5) * 100;
          if (this.deleteCountdown <= 0) {
            clearInterval(this.deleteTimer);
            this.deleteTimer = null;
          }
        }, 1000);
      },
      // 取消删除
      cancelDelete() {
        this.showDeleteConfirm = false;
        if (this.deleteTimer) {
          clearInterval(this.deleteTimer);
          this.deleteTimer = null;
        }
        this.deleteCountdown = 5;
        this.countdownProgress = 0;
      },
      // 确认删除
      confirmDelete() {
        if (this.deleteCountdown > 0) {
          return;
        }
        this.showDeleteConfirm = false;
        if (this.deleteTimer) {
          clearInterval(this.deleteTimer);
          this.deleteTimer = null;
        }
        this.removeXJ();
      },
      
      removeXJ() {
@@ -709,16 +857,10 @@
                 pid: this.formData.id
               }
             }).then(res1 => {
               let tableData = res1.data.tbBillList
               //当已检验个数都不为空时按照检测结构排序
               let tableData = res1.data.tbBillList;
               // 按FORDER序号排序
               tableData.sort((a, b) => {
                 if (a.result === '未完成' && b.result === '合格') {
                   return -1;
                 } else if (a.result === '合格' && b.result === '未完成') {
                   return 1;
                 } else {
                   return 0;
                 }
                 return (a.forder || 0) - (b.forder || 0);
               });
               this.tableData = tableData;
               if (this.tableData.length === 0) {
@@ -1037,6 +1179,318 @@
          }
        });
      },
     drawingConfirm() {
        this.drawingShow = false
        this.imageShow = false
        this.productionShow = false
        this.itemShow=false
     },
     drawingCancel() {
        this.drawingShow = false
        this.imageShow = false
        this.productionShow = false
           // const item = '83040700101'
           const item = this.formData.billNo;
           console.log(this.formData.billNo );
           console.log('daa001:', item);
           console.log('ItemNo:', this.formData.itemNo);
           const url = this.$store.state.serverInfo.serverAPI + "/LLJ/getWomdab";
           // 或者如果路径不同,请使用正确的端点
           // const url = "http://192.168.0.100:10054/api/getWomdab"
           let _this = this;
           uni.request({
               url: url,
               method: 'POST',
               header: {
                   'Content-Type': 'application/json'
               },
               data: {
                     daa001: item,  // 根据DTO属性名传递
                     ItemNo: this.formData.itemNo   // 注意大小写匹配
               },
               success: (response) => {
                   console.log(response);
                   console.log("-------------------------------------");
                   // 根据后端返回的数据结构进行调整
                   if (response.data.status === 1) {
                       // 状态为1表示没有数据
                       _this.drawing = [];
                   } else if (response.data.status === 0) {
                       // 状态为0表示成功
                       if (response.data.data && response.data.data.tbBillList) {
                           _this.drawing = response.data.data.tbBillList;
                           // 遍历数据,判断文件后缀并添加字段
                           _this.drawing.forEach((file) => {
                               // 获取文件名的后缀
                               const fileExtension = file.fName ? file.fName.split('.').pop().toLowerCase() : '';
                               // 定义支持的文件类型
                               const supportedExtensions = ['jpg', 'pdf', 'xlsx', 'doc', 'docx', 'xls'];
                               // 判断是否支持该文件类型
                               file.isSupported = supportedExtensions.includes(fileExtension);
                           });
                       } else {
                           _this.drawing = [];
                       }
                   } else {
                       // 其他状态码处理
                       _this.drawing = [];
                       uni.showToast({
                           title: response.data.message || '请求失败',
                           icon: 'none'
                       });
                   }
               },
               fail: (error) => {
                   uni.showToast({
                       title: '请求图纸链接失败',
                       icon: 'none'
                   });
                   console.error('请求失败:', error);
               }
           });
     },
     itemCancel() {
        this.itemShow=false
     },
     fetchDrawingNumber(itemNo) {
        // const item = '83040700101'
        const item = itemNo;
        console.log(itemNo)
        // console.log(item)
        const url = this.$store.state.serverInfo.serverAPI +"/PLM/RetrieveDrawings?ItemNo=" + item
        // const item = '5.06.04.4002';
        // const url = "http://192.168.0.100:10054/api/PLM/RetrieveDrawings?ItemNo=" + item
        let _this = this;
        uni.request({
           url: url,
           method: 'POST',
           success: (response) => {
              console.log(response)
              if (response.data.data == '返回结果为空') {
                 _this.drawing = []
              } else {
                 _this.drawing = response.data.data
                 // 遍历数据,判断文件后缀并添加字段
                 _this.drawing.forEach((file) => {
                    // 获取文件名的后缀
                    const fileExtension = file.fName.split('.').pop()
                       .toLowerCase();
                    // 定义支持的文件类型
                    const supportedExtensions = ['jpg', 'pdf', 'xlsx', 'doc',
                       'docx',
                       'xls'
                    ];
                    // 判断是否支持该文件类型
                    file.isSupported = supportedExtensions.includes(fileExtension);
                 });
              }
           },
           fail: (error) => {
              uni.showToast({
                 title: '请求图纸链接失败',
                 icon: 'none'
              });
           }
        });
        this.drawingShow = true
     },
     getBom(){
        // const item = '83040700101'
        const item = this.formData.billNo;
        console.log(this.formData.billNo );
        console.log('daa001:', item);
        console.log('ItemNo:', this.formData.itemNo);
        const url = this.$store.state.serverInfo.serverAPI + "/LLJ/getWomdab";
        // 或者如果路径不同,请使用正确的端点
        // const url = "http://192.168.0.100:10054/api/getWomdab"
        let _this = this;
        uni.request({
            url: url,
            method: 'POST',
            header: {
                'Content-Type': 'application/json'
            },
            data: {
                  daa001: item,  // 根据DTO属性名传递
                  ItemNo: this.formData.itemNo   // 注意大小写匹配
            },
            success: (response) => {
                console.log(response);
                console.log("-------------------------------------");
                // 根据后端返回的数据结构进行调整
                if (response.data.status === 1) {
                    // 状态为1表示没有数据
                    _this.drawing = [];
                    uni.showToast({
                        title: response.data.message || '该检验单未上传附件信息',
                        icon: 'none'
                    });
                } else if (response.data.status === 0) {
                    // 状态为0表示成功
                    if (response.data.data && response.data.data.tbBillList) {
                        _this.drawing = response.data.data.tbBillList;
                        // 遍历数据,判断文件后缀并添加字段
                        _this.drawing.forEach((file) => {
                            // 获取文件名的后缀
                            const fileExtension = file.fName ? file.fName.split('.').pop().toLowerCase() : '';
                            // 定义支持的文件类型
                            const supportedExtensions = ['jpg', 'pdf', 'xlsx', 'doc', 'docx', 'xls'];
                            // 判断是否支持该文件类型
                            file.isSupported = supportedExtensions.includes(fileExtension);
                        });
                    } else {
                        _this.drawing = [];
                    }
                } else {
                    // 其他状态码处理
                    _this.drawing = [];
                    uni.showToast({
                        title: response.data.message || '请求失败',
                        icon: 'none'
                    });
                }
            },
            fail: (error) => {
                uni.showToast({
                    title: '请求图纸链接失败',
                    icon: 'none'
                });
                console.error('请求失败:', error);
            }
        });
        this.itemShow = true
     },
     //图纸相关文档
     openDrawings(item) {
       console.log("jkjoi", item)
       if (item.fRelevantObject.length > 2) {
        // 生成请求URL(简化编码逻辑)
        const encodedName = encodeURIComponent(item.fName);
        const url = this.$store.state.serverInfo.serverAPI+`/PLM/OpenDrawingsGet?fileId=${item.fRelevantObject}&fName=${encodedName}`;
        console.log('请求URL:', url);
        const now = new Date();
        const timestamp = [
          now.getFullYear(),
          String(now.getMonth() + 1).padStart(2, '0'),
          String(now.getDate()).padStart(2, '0'),
          String(now.getHours()).padStart(2, '0'),
          String(now.getMinutes()).padStart(2, '0'),
          String(now.getSeconds()).padStart(2, '0')
        ].join('');
        // 生成新文件名(基础名_时间戳.后缀)
        this.fileName = `${item.fName}_${timestamp}.pdf`;
        console.log('新文件名:', this.fileName);
        uni.downloadFile({
           url: url,
           success: (res) => {
              console.log(res);
              let fileName = this.fileName;
              let fileExt = fileName.split('.').pop();
              // let newFilePath = "_doc/uniapp_temp_1742877118745/download" + "/" + fileName;
              // console.log('newFilePath', newFilePath)
              if (fileExt === 'xls' || fileExt === 'xlsx' || fileExt === 'pdf'|| fileExt === 'jpg'|| fileExt === 'png') {
                 plus.io.resolveLocalFileSystemURL(res.tempFilePath, (entry) => {
                         // 获取文件所在的目录
                         entry.getParent((parentEntry) => {
                           let newFileName = this.fileName; // 新的文件名
                           // 移动并重命名文件
                           entry.moveTo(
                             parentEntry,
                             newFileName,
                             (newEntry) => {
                               console.log('重命名成功:', newEntry.fullPath);
                               // 打开 Excel 文件
                               plus.runtime.openFile(newEntry.fullPath, {}, (e) => {
                                 console.error('无法打开 Excel 文件:', e);
                               });
                            // let pages = getCurrentPages();
                            // let beforePage = pages[pages.length - 2];
                            // uni.navigateBack({
                            //    delta: 1, //返回的页面数,如果为1表示返回上一页
                            //    success: (event) => {
                            //       beforePage.$vm.reload()
                            //    }
                            // });
                             },
                             (err) => {
                               console.error('重命名失败:', err);
                             }
                           );
                         }, (err) => {
                           console.error('获取父目录失败:', err);
                         });
                       }, (err) => {
                         console.error('获取文件失败:', err);
                       });
              } else {
                 console.error('文件格式不匹配:', fileExt);
                 uni.showToast({
                    title: '文件格式不支持',
                    icon: 'none'
                 });
              }
           }
        })
        uni.request({
           url: url,
           method: 'POST',
           responseType: 'arraybuffer',
           success: (response) => {
              console.log(response.data)
              if (!response) {
                 uni.showToast({
                    title: "协议预览失败",
                    duration: 2000
                 });
              }
           },
           fail: (error) => {
              console.log(error)
              uni.showToast({
                 title: '请求预览链接失败',
                 icon: 'none'
              });
           }
        });
     }
       else
       {
        uni.showToast({
           title: '请求预览链接失败',
           icon: 'none'
        });
       }
     },
      
      previewOfficeFile(url, fileName) {
        this.previewTitle = fileName;
@@ -1080,7 +1534,8 @@
  <style scoped>
  /* 基础样式 */
  .container {
    padding: 10px;
    padding: 20px;
    padding-bottom: 120px; /* 为固定按钮留出更多空间,避免遮盖检验项目 */
    background-color: #f5f7fa;
    min-height: 100vh;
  }
@@ -1186,41 +1641,44 @@
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    margin: 25px 0;
  }
  .inspection-table table {
    width: 100%;
    border-collapse: collapse;
  }
  .inspection-table th {
    background-color: #f8f9fa;
    color: #34495e;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: white;
    padding: 12px 15px;
    font-weight: bold;
    text-align: left;
    border: 1px solid #ddd;
    text-align: center;
    border: none;
  }
  .inspection-table td {
    padding: 12px 15px;
    text-align: left;
    border: 1px solid #ddd;
    border: none;
    vertical-align: middle;
  }
  .inspection-table tr:nth-child(even) {
    background-color: #f9f9f9;
  }
  .inspection-table tr:hover {
    background-color: #f1f5f9;
    transform: translateY(-1px);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  }
  
  /* 水印样式 */
  .watermark {
    position: absolute;
    font-size: 40px;
    font-size: 32px;
    font-weight: bold;
    opacity: 1;
    opacity: 0.8;
    z-index: 1;
    pointer-events: none;
    transform: rotate(-15deg);
@@ -1230,15 +1688,15 @@
    left: 50%;
    transform: translate(-50%, -50%) rotate(-15deg);
  }
  .watermark.approved {
    color: #2ecc71;
  }
  .watermark.rejected {
    color: #e74c3c;
  }
  .watermark.pending {
    color: #f39c12;
  }
@@ -1252,10 +1710,11 @@
  }
  
  /* 调整表格单元格 */
  .inspection-table td:nth-child(2) {
  .inspection-table td:nth-child(3) {
    position: relative;
    overflow: hidden;
    padding: 0;
    min-height: 80px;
  }
  
  .record-btn {
@@ -1276,55 +1735,111 @@
  
  /* 操作按钮 */
  .action-buttons {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    background-color: white;
    border-top: 1px solid #e9ecef;
    padding: 12px;
    box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
    z-index: 1000;
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-bottom: 20px;
    flex-wrap: wrap;
    gap: 8px;
    justify-content: center;
    align-items: center;
  }
  
  .action-btn {
    padding: 12px 20px;
    background-color: #ecf0f1;
    color: #34495e;
    padding: 12px 15px;
    border: none;
    border-radius: 6px;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.2s;
    font-size: 12px;
    font-weight: 500;
    transition: all 0.3s ease;
    text-align: center;
    min-height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    white-space: nowrap;
    flex-shrink: 0;
    min-width: 80px;
    max-width: 120px;
    flex: 1;
  }
  .action-btn:hover {
    background-color: #d5dbdb;
    transform: translateY(-1px);
  }
  .action-btn.primary {
    background-color: #3498db;
    color: white;
    color: #fff;
  }
  .action-btn.primary:hover {
    background-color: #2980b9;
  }
  .action-btn.secondary {
    background-color: #95a5a6;
    color: white;
    background-color: #ecf0f1;
    color: #34495e;
  }
  .action-btn.secondary:hover {
    background-color: #d5dbdb;
  }
  .action-btn.danger {
    background-color: #e74c3c;
    color: white;
    color: #fff;
  }
  .action-btn.danger:hover {
    background-color: #c0392b;
  }
  .action-btn.warning {
    background-color: #f39c12;
    color: white;
    color: #fff;
  }
  .action-btn.warning:hover {
    background-color: #e67e22;
  }
  .action-btn.success {
    background-color: #2ecc71;
    color: white;
    color: #fff;
  }
  .action-btn.success:hover {
    background-color: #27ae60;
  }
  .action-btn.info {
    background-color: #17a2b8;
    color: white;
    color: #fff;
  }
  .action-btn.info:hover {
    background-color: #138496;
  }
  
  .action-btn.small {
    padding: 6px 12px;
    padding: 10px 12px;
    font-size: 12px;
    min-height: 44px;
    white-space: nowrap;
    flex-shrink: 0;
    min-width: 80px;
    max-width: 120px;
  }
  
  /* 弹出框样式 */
@@ -1945,12 +2460,37 @@
  /* 响应式设计 */
  @media (max-width: 768px) {
    .container {
      padding-bottom: 120px; /* 为固定按钮留出空间,避免遮盖检验项目 */
    }
    .info-grid {
      grid-template-columns: 1fr;
    }
    
    .action-buttons {
      flex-direction: column;
      flex-direction: row;
      align-items: center;
      justify-content: center;
      padding: 8px;
      gap: 6px;
    }
    .action-btn {
      min-width: 70px;
      max-width: 100px;
      padding: 8px 10px;
      font-size: 11px;
      min-height: 40px;
      flex: 1;
    }
    .action-btn.small {
      min-width: 70px;
      max-width: 100px;
      padding: 8px 10px;
      font-size: 11px;
      min-height: 40px;
    }
    
    /* 附件弹窗响应式 */
@@ -2007,9 +2547,7 @@
    .attachment-icon {
      font-size: 20px;
    }
  }
  @media (max-width: 480px) {
    .attachment-popup-content {
      padding: 16px;
    }
@@ -2034,4 +2572,145 @@
      font-size: 28px;
    }
  }
  /* 删除确认弹窗样式 */
  .delete-confirm-popup {
    width: 90vw;
    max-width: 400px;
    max-height: 70vh;
    display: flex;
    flex-direction: column;
  }
  .delete-confirm-title {
    font-size: 20px;
    font-weight: 700;
    color: #e74c3c;
    margin-bottom: 8px;
    text-align: center;
    letter-spacing: 1px;
  }
  .delete-confirm-divider {
    height: 2px;
    background: linear-gradient(90deg, #e74c3c 0%, #c0392b 100%);
    margin-bottom: 20px;
  }
  .delete-confirm-content {
    text-align: center;
    margin-bottom: 20px;
  }
  .delete-warning-icon {
    font-size: 48px;
    margin-bottom: 16px;
    animation: shake 0.5s ease-in-out infinite alternate;
  }
  @keyframes shake {
    0% { transform: translateX(-2px); }
    100% { transform: translateX(2px); }
  }
  .delete-warning-text {
    font-size: 18px;
    font-weight: 600;
    color: #2c3e50;
    margin-bottom: 8px;
  }
  .delete-warning-detail {
    font-size: 14px;
    color: #7f8c8d;
    margin-bottom: 20px;
    line-height: 1.4;
  }
  .delete-countdown {
    background: #f8f9fa;
    border-radius: 8px;
    padding: 16px;
    margin: 16px 0;
    border: 1px solid #e9ecef;
  }
  .countdown-text {
    font-size: 14px;
    color: #495057;
    margin-bottom: 8px;
    text-align: center;
  }
  .countdown-number {
    font-weight: 700;
    color: #e74c3c;
    font-size: 16px;
  }
  .countdown-progress {
    width: 100%;
    height: 6px;
    background: #e9ecef;
    border-radius: 3px;
    overflow: hidden;
  }
  .countdown-bar {
    height: 100%;
    background: linear-gradient(90deg, #e74c3c, #c0392b);
    border-radius: 3px;
    transition: width 1s ease;
  }
  .delete-confirm-actions {
    display: flex;
    gap: 12px;
    justify-content: center;
  }
  .delete-confirm-btn {
    padding: 12px 24px;
    border: none;
    border-radius: 8px;
    font-size: 16px;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.3s ease;
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 120px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  }
  .delete-confirm-btn.cancel-btn {
    background: linear-gradient(135deg, #95a5a6, #7f8c8d);
    color: white;
  }
  .delete-confirm-btn.cancel-btn:hover {
    background: linear-gradient(135deg, #7f8c8d, #6c7b7d);
    transform: translateY(-1px);
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
  }
  .delete-confirm-btn.confirm-btn {
    background: linear-gradient(135deg, #e74c3c, #c0392b);
    color: white;
  }
  .delete-confirm-btn.confirm-btn:hover:not(.disabled) {
    background: linear-gradient(135deg, #c0392b, #a93226);
    transform: translateY(-1px);
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
  }
  .delete-confirm-btn.disabled {
    background: #bdc3c7;
    color: #7f8c8d;
    cursor: not-allowed;
    transform: none;
    box-shadow: none;
  }
  </style>