已修改5个文件
1147 ■■■■ 文件已修改
src/pages/cooperativeOffice/clientVisit/detail.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/humanResources/attendance/checkin.vue 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/indexItem.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/message.vue 690 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/procurementManagement/invoiceEntry/index.vue 439 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/cooperativeOffice/clientVisit/detail.vue
@@ -288,7 +288,7 @@
          showToast("签到失败,请重试");
        }
      } else {
        const { code } = await clientVisitSignUp(submitData);
        const { code } = await clientVisitSignIn(submitData);
        if (code === 200) {
          showToast("签到成功");
          setTimeout(() => {
src/pages/humanResources/attendance/checkin.vue
@@ -129,7 +129,12 @@
    findTodayPersonalAttendanceRecord({}).then(res => {
      if (res.data) {
        todayRecord.value = res.data;
        noNeedCheckIn.value = false;
        // 检查startAt和endAt是否为空,为空则无需打卡
        if (!todayRecord.value.startAt || !todayRecord.value.endAt) {
          noNeedCheckIn.value = true;
        } else {
          noNeedCheckIn.value = false;
        }
      } else {
        // 页面显示“无需打卡”
        todayRecord.value = {};
src/pages/indexItem.vue
@@ -374,7 +374,14 @@
  const operationType = ref("");
  onLoad(options => {
    if (options.label) {
      operationType.value = options.label;
      // 处理 URL 参数可能包含其他查询参数的情况(如:协同审批?approveType=6)
      // 只提取 label 参数的值,去除可能附加的查询参数
      let labelValue = options.label;
      // 如果 label 包含 ? 符号,只取 ? 之前的部分
      if (labelValue.includes('?')) {
        labelValue = labelValue.split('?')[0];
      }
      operationType.value = labelValue;
      if (operationType.value === "考勤管理") {
        commonItems.value = kaoqin;
      } else if (operationType.value === "会议管理") {
src/pages/message.vue
@@ -30,7 +30,10 @@
            v-for="(item) in messageList"
            :key="item.id"
            class="message-item"
            :class="{ 'unread': !item.read }">
            :class="{
              'unread': !item.read,
              [getApprovalTypeClass(item.noticeTitle)]: true
            }">
        <view class="message-content">
          <view class="message-header">
            <text class="message-title">{{ item.noticeTitle }}</text>
@@ -62,7 +65,8 @@
<script setup>
  import { ref, reactive, onMounted } from "vue";
  import { listNotice, confirmMessage } from "@/api/login.js";
  import { onShow } from "@dcloudio/uni-app";
  import { listNotice, confirmMessage, getNoticeCount } from "@/api/login.js";
  import useUserStore from "@/store/modules/user";
  // 标签页数据
@@ -99,22 +103,191 @@
    return `${Y}-${M}-${D} ${h}:${m}`;
  };
  // 根据标题获取审批类型对应的样式类名
  const getApprovalTypeClass = (title) => {
    if (!title) return 'type-default';
    const titleStr = title.toString().trim();
    if (titleStr.includes('采购审批') || titleStr.includes('采购')) {
      return 'type-purchase';
    } else if (titleStr.includes('报价审批') || titleStr.includes('报价')) {
      return 'type-quotation';
    } else if (titleStr.includes('发货审批') || titleStr.includes('发货')) {
      return 'type-shipment';
    } else if (titleStr.includes('公出') || titleStr.includes('公出管理')) {
      return 'type-business-trip';
    } else if (titleStr.includes('请假') || titleStr.includes('请假管理')) {
      return 'type-leave';
    } else if (titleStr.includes('出差') || titleStr.includes('出差管理')) {
      return 'type-travel';
    } else if (titleStr.includes('报销') || titleStr.includes('报销管理')) {
      return 'type-reimbursement';
    } else if (titleStr.includes('危险作业')) {
      return 'type-dangerous';
    }
    return 'type-default';
  };
  // 根据 noticeTitle 判断跳转页面
  const getJumpPathByTitle = (title, appJumpPath) => {
    if (!title) return null;
    const titleStr = title.toString().trim();
    // 尝试从 appJumpPath 中提取 approveId
    let approveId = null;
    if (appJumpPath) {
      const queryIndex = appJumpPath.indexOf('?');
      if (queryIndex !== -1) {
        const queryString = appJumpPath.substring(queryIndex + 1);
        const params = queryString.split('&');
        params.forEach(param => {
          const [key, value] = param.split('=');
          if (key === 'approveId' && value) {
            approveId = decodeURIComponent(value);
          }
        });
      }
      // 如果没有在查询参数中找到,尝试从路径中提取(如 /pages/xxx/xxx/123)
      if (!approveId) {
        const pathParts = appJumpPath.split('/');
        const lastPart = pathParts[pathParts.length - 1];
        if (lastPart && !lastPart.includes('?') && !lastPart.includes('.')) {
          approveId = lastPart;
        }
      }
    }
    // 根据标题判断审批类型和跳转路径
    if (titleStr.includes('采购审批') || titleStr.includes('采购')) {
      if (approveId) {
        uni.setStorageSync('approveId', approveId);
        uni.setStorageSync('approveType', '5');
        return `/pages/cooperativeOffice/collaborativeApproval/approve?approveType=5`;
      }
      return `/pages/cooperativeOffice/collaborativeApproval/index5`;
    } else if (titleStr.includes('报价审批') || titleStr.includes('报价')) {
      if (approveId) {
        uni.setStorageSync('approveId', approveId);
        uni.setStorageSync('approveType', '6');
        return `/pages/cooperativeOffice/collaborativeApproval/approve?approveType=6`;
      }
      return `/pages/cooperativeOffice/collaborativeApproval/index6`;
    } else if (titleStr.includes('发货审批') || titleStr.includes('发货')) {
      if (approveId) {
        uni.setStorageSync('approveId', approveId);
        uni.setStorageSync('approveType', '7');
        return `/pages/cooperativeOffice/collaborativeApproval/approve?approveType=7`;
      }
      return `/pages/cooperativeOffice/collaborativeApproval/index7`;
    } else if (titleStr.includes('公出') || titleStr.includes('公出管理')) {
      if (approveId) {
        uni.setStorageSync('approveId', approveId);
        uni.setStorageSync('approveType', '1');
        return `/pages/cooperativeOffice/collaborativeApproval/approve?approveType=1`;
      }
      return `/pages/cooperativeOffice/collaborativeApproval/index1`;
    } else if (titleStr.includes('请假') || titleStr.includes('请假管理')) {
      if (approveId) {
        uni.setStorageSync('approveId', approveId);
        uni.setStorageSync('approveType', '2');
        return `/pages/cooperativeOffice/collaborativeApproval/approve?approveType=2`;
      }
      return `/pages/cooperativeOffice/collaborativeApproval/index2`;
    } else if (titleStr.includes('出差') || titleStr.includes('出差管理')) {
      if (approveId) {
        uni.setStorageSync('approveId', approveId);
        uni.setStorageSync('approveType', '3');
        return `/pages/cooperativeOffice/collaborativeApproval/approve?approveType=3`;
      }
      return `/pages/cooperativeOffice/collaborativeApproval/index3`;
    } else if (titleStr.includes('报销') || titleStr.includes('报销管理')) {
      if (approveId) {
        uni.setStorageSync('approveId', approveId);
        uni.setStorageSync('approveType', '4');
        return `/pages/cooperativeOffice/collaborativeApproval/approve?approveType=4`;
      }
      return `/pages/cooperativeOffice/collaborativeApproval/index4`;
    } else if (titleStr.includes('危险作业')) {
      if (approveId) {
        uni.setStorageSync('approveId', approveId);
        uni.setStorageSync('approveType', '8');
        return `/pages/cooperativeOffice/collaborativeApproval/approve?approveType=8`;
      }
      return `/pages/cooperativeOffice/collaborativeApproval/index8`;
    }
    // 如果都不匹配,尝试使用原始的 appJumpPath
    if (appJumpPath) {
      let jumpPath = appJumpPath;
      if (jumpPath.indexOf("/") !== 0) {
        jumpPath = "/" + jumpPath;
      }
      return jumpPath;
    }
    return null;
  };
  // 更新 tab 栏角标
  const updateTabBarBadge = () => {
    if (userId.value) {
      getNoticeCount(userId.value)
        .then(res => {
          const count = res.data || 0;
          // 更新tabbar的角标
          if (count > 0) {
            uni.setTabBarBadge({
              index: 1, // 消息标签页的索引
              text: count.toString(),
            });
          } else {
            uni.removeTabBarBadge({
              index: 1,
            });
          }
        })
        .catch(error => {
          console.error("获取未读消息数量失败:", error);
        });
    }
  };
  // 跳转到详情页
  const goToDetail = item => {
    confirmMessage(item.noticeId, 1).then(res => {
      if (res.code === 200) {
        // uni.showToast({ title: "确认成功", icon: "success" });
        loadMessages(false);
        if (item.appJumpPath) {
          if (item.appJumpPath.indexOf("/") === 0) {
            uni.navigateTo({
              url: item.appJumpPath,
            });
          } else {
            uni.navigateTo({
              url: "/" + item.appJumpPath,
            });
          }
        // 更新 tab 栏角标
        updateTabBarBadge();
        // 根据 noticeTitle 判断跳转页面
        const jumpPath = getJumpPathByTitle(item.noticeTitle, item.appJumpPath);
        if (jumpPath) {
          console.log('跳转路径:', jumpPath);
          console.log('消息标题:', item.noticeTitle);
          console.log('消息数据:', item);
          uni.navigateTo({
            url: jumpPath,
            fail: (err) => {
              console.error('跳转失败:', err);
              uni.showToast({
                title: "跳转失败,请检查路径",
                icon: "none",
              });
            }
          });
        } else {
          console.warn('无法根据标题判断跳转页面:', item.noticeTitle);
          uni.showToast({
            title: "无法跳转,请手动进入",
            icon: "none",
          });
        }
      } else {
        uni.showToast({ title: "确认失败", icon: "none" });
@@ -203,53 +376,71 @@
  onMounted(() => {
    getUserId().then(() => {
      loadMessages();
      // 更新 tab 栏角标
      updateTabBarBadge();
    });
  });
  // 页面显示时也更新角标(从其他页面返回时)
  onShow(() => {
    if (userId.value) {
      updateTabBarBadge();
    }
  });
</script>
<style scoped lang="scss">
  // 全局变量
  $primary-color: #2c7be5;
  $primary-color: #2979ff;
  $primary-light: #4a90e2;
  $success-color: #4cd964;
  $warning-color: #ff9500;
  $danger-color: #ff3b30;
  $text-primary: #333333;
  $text-secondary: #666666;
  $text-tertiary: #999999;
  $bg-color: #f5f7fa;
  $text-primary: #1f2937;
  $text-secondary: #6b7280;
  $text-tertiary: #9ca3af;
  $bg-color: #f9fafb;
  $card-bg: #ffffff;
  $border-color: #e8e8e8;
  $shadow-sm: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
  $border-color: #e5e7eb;
  $shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
  $shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
  $shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
  .message-page {
    min-height: 100vh;
    background-color: $bg-color;
    background: linear-gradient(180deg, #f9fafb 0%, #ffffff 100%);
    padding-bottom: 30rpx;
  }
  /* 标签页容器 */
  .tabs-container {
    background-color: #ffffff;
    margin-bottom: 20rpx;
    box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
    margin-bottom: 12rpx;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
    position: sticky;
    top: 0;
    z-index: 10;
  }
  /* 消息列表 */
  .message-list {
    margin: 0 20rpx 20rpx;
    padding: 0 24rpx 24rpx;
    min-height: 600rpx;
    height: calc(100vh - 200rpx);
    box-sizing: border-box;
  }
  /* 加载状态 */
  .loading-state {
    background-color: $card-bg;
    border-radius: 16rpx;
    border-radius: 20rpx;
    box-shadow: $shadow-sm;
    text-align: center;
    padding: 120rpx 0;
    margin-bottom: 20rpx;
    margin: 0 0 24rpx 0;
    border: 1px solid rgba(0, 0, 0, 0.05);
    width: 100%;
    box-sizing: border-box;
  }
  .loading-text {
@@ -263,70 +454,331 @@
  .message-item {
    display: flex;
    align-items: flex-start;
    background-color: $card-bg;
    border-radius: 16rpx;
    background: linear-gradient(135deg, #ffffff 0%, #fafbfc 100%);
    border-radius: 20rpx;
    box-shadow: $shadow-sm;
    padding: 24rpx;
    margin-bottom: 20rpx;
    margin-right: 40rpx;
    transition: all 0.3s ease;
    padding: 32rpx;
    margin: 0 0 24rpx 0;
    border: 1px solid rgba(0, 0, 0, 0.05);
    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    position: relative;
    overflow: hidden;
    width: 100%;
    box-sizing: border-box;
    &::before {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      width: 6rpx;
      height: 100%;
      background: linear-gradient(180deg, $primary-color 0%, $primary-light 100%);
      opacity: 0;
      transition: opacity 0.3s ease;
    }
  }
  .message-item:hover {
    box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.12);
    transform: translateY(-2rpx);
  .message-item:active {
    transform: scale(0.98);
    box-shadow: $shadow-md;
  }
  .message-item.unread {
    border-left: 4rpx solid $primary-color;
    &::before {
      opacity: 1;
    }
    .message-title {
      font-weight: 700;
    }
    .message-title::before {
      content: '';
      display: inline-block;
      width: 12rpx;
      height: 12rpx;
      border-radius: 50%;
      margin-right: 12rpx;
      vertical-align: middle;
      animation: pulse 2s infinite;
    }
  }
  /* 消息图标 */
  .message-icon {
    margin-right: 20rpx;
    margin-top: 4rpx;
  // 采购审批 - 蓝色
  .message-item.type-purchase.unread {
    background: linear-gradient(135deg, #ffffff 0%, #e3f2fd 100%);
    border: 1px solid rgba(33, 150, 243, 0.2);
    box-shadow: 0 2px 8px rgba(33, 150, 243, 0.15);
    &::before {
      background: linear-gradient(180deg, #2196f3 0%, #1976d2 100%);
    }
    .message-title {
      color: #1976d2;
    }
    .message-title::before {
      background: #1976d2;
    }
    .message-view {
      background: linear-gradient(135deg, #2196f3 0%, #1976d2 100%);
      box-shadow: 0 4rpx 12rpx rgba(33, 150, 243, 0.3);
    }
  }
  // 报价审批 - 绿色
  .message-item.type-quotation.unread {
    background: linear-gradient(135deg, #ffffff 0%, #e8f5e9 100%);
    border: 1px solid rgba(76, 175, 80, 0.2);
    box-shadow: 0 2px 8px rgba(76, 175, 80, 0.15);
    &::before {
      background: linear-gradient(180deg, #4caf50 0%, #388e3c 100%);
    }
    .message-title {
      color: #388e3c;
    }
    .message-title::before {
      background: #388e3c;
    }
    .message-view {
      background: linear-gradient(135deg, #4caf50 0%, #388e3c 100%);
      box-shadow: 0 4rpx 12rpx rgba(76, 175, 80, 0.3);
    }
  }
  // 发货审批 - 橙色
  .message-item.type-shipment.unread {
    background: linear-gradient(135deg, #ffffff 0%, #fff3e0 100%);
    border: 1px solid rgba(255, 152, 0, 0.2);
    box-shadow: 0 2px 8px rgba(255, 152, 0, 0.15);
    &::before {
      background: linear-gradient(180deg, #ff9800 0%, #f57c00 100%);
    }
    .message-title {
      color: #f57c00;
    }
    .message-title::before {
      background: #f57c00;
    }
    .message-view {
      background: linear-gradient(135deg, #ff9800 0%, #f57c00 100%);
      box-shadow: 0 4rpx 12rpx rgba(255, 152, 0, 0.3);
    }
  }
  // 公出管理 - 紫色
  .message-item.type-business-trip.unread {
    background: linear-gradient(135deg, #ffffff 0%, #f3e5f5 100%);
    border: 1px solid rgba(156, 39, 176, 0.2);
    box-shadow: 0 2px 8px rgba(156, 39, 176, 0.15);
    &::before {
      background: linear-gradient(180deg, #9c27b0 0%, #7b1fa2 100%);
    }
    .message-title {
      color: #7b1fa2;
    }
    .message-title::before {
      background: #7b1fa2;
    }
    .message-view {
      background: linear-gradient(135deg, #9c27b0 0%, #7b1fa2 100%);
      box-shadow: 0 4rpx 12rpx rgba(156, 39, 176, 0.3);
    }
  }
  // 请假管理 - 青色
  .message-item.type-leave.unread {
    background: linear-gradient(135deg, #ffffff 0%, #e0f2f1 100%);
    border: 1px solid rgba(0, 150, 136, 0.2);
    box-shadow: 0 2px 8px rgba(0, 150, 136, 0.15);
    &::before {
      background: linear-gradient(180deg, #009688 0%, #00796b 100%);
    }
    .message-title {
      color: #00796b;
    }
    .message-title::before {
      background: #00796b;
    }
    .message-view {
      background: linear-gradient(135deg, #009688 0%, #00796b 100%);
      box-shadow: 0 4rpx 12rpx rgba(0, 150, 136, 0.3);
    }
  }
  // 出差管理 - 红色
  .message-item.type-travel.unread {
    background: linear-gradient(135deg, #ffffff 0%, #ffebee 100%);
    border: 1px solid rgba(244, 67, 54, 0.2);
    box-shadow: 0 2px 8px rgba(244, 67, 54, 0.15);
    &::before {
      background: linear-gradient(180deg, #f44336 0%, #d32f2f 100%);
    }
    .message-title {
      color: #d32f2f;
    }
    .message-title::before {
      background: #d32f2f;
    }
    .message-view {
      background: linear-gradient(135deg, #f44336 0%, #d32f2f 100%);
      box-shadow: 0 4rpx 12rpx rgba(244, 67, 54, 0.3);
    }
  }
  // 报销管理 - 粉色
  .message-item.type-reimbursement.unread {
    background: linear-gradient(135deg, #ffffff 0%, #fce4ec 100%);
    border: 1px solid rgba(233, 30, 99, 0.2);
    box-shadow: 0 2px 8px rgba(233, 30, 99, 0.15);
    &::before {
      background: linear-gradient(180deg, #e91e63 0%, #c2185b 100%);
    }
    .message-title {
      color: #c2185b;
    }
    .message-title::before {
      background: #c2185b;
    }
    .message-view {
      background: linear-gradient(135deg, #e91e63 0%, #c2185b 100%);
      box-shadow: 0 4rpx 12rpx rgba(233, 30, 99, 0.3);
    }
  }
  // 危险作业 - 深红色
  .message-item.type-dangerous.unread {
    background: linear-gradient(135deg, #ffffff 0%, #ffebee 100%);
    border: 1px solid rgba(211, 47, 47, 0.3);
    box-shadow: 0 2px 8px rgba(211, 47, 47, 0.2);
    &::before {
      background: linear-gradient(180deg, #d32f2f 0%, #b71c1c 100%);
    }
    .message-title {
      color: #b71c1c;
    }
    .message-title::before {
      background: #b71c1c;
    }
    .message-view {
      background: linear-gradient(135deg, #d32f2f 0%, #b71c1c 100%);
      box-shadow: 0 4rpx 12rpx rgba(211, 47, 47, 0.4);
    }
  }
  // 默认类型 - 蓝色(原色)
  .message-item.type-default.unread {
    background: linear-gradient(135deg, #ffffff 0%, #f0f7ff 100%);
    border: 1px solid rgba(41, 121, 255, 0.15);
    box-shadow: 0 2px 8px rgba(41, 121, 255, 0.1);
    &::before {
      background: linear-gradient(180deg, $primary-color 0%, $primary-light 100%);
    }
    .message-title {
      color: $primary-color;
    }
    .message-title::before {
      background: $primary-color;
    }
  }
  @keyframes pulse {
    0%, 100% {
      opacity: 1;
      transform: scale(1);
    }
    50% {
      opacity: 0.6;
      transform: scale(1.2);
    }
  }
  /* 消息内容 */
  .message-content {
    flex: 1;
    position: relative;
    z-index: 1;
  }
  /* 消息头部 */
  .message-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 12rpx;
    align-items: flex-start;
    margin-bottom: 16rpx;
    gap: 16rpx;
  }
  .message-title {
    font-size: 16px;
    font-size: 32rpx;
    font-weight: 600;
    color: $text-primary;
    flex: 1;
    margin-right: 20rpx;
    line-height: 1.5;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
  }
  .message-time {
    font-size: 12px;
    font-size: 24rpx;
    color: $text-tertiary;
    white-space: nowrap;
    flex-shrink: 0;
    padding: 4rpx 12rpx;
    background: rgba(0, 0, 0, 0.03);
    border-radius: 12rpx;
  }
  /* 消息描述 */
  .message-desc {
    font-size: 14px;
    font-size: 28rpx;
    color: $text-secondary;
    line-height: 1.4;
    margin-bottom: 16rpx;
    line-height: 1.6;
    margin-bottom: 20rpx;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
    max-height: 2.4em;
  }
  /* 消息底部 */
@@ -334,25 +786,62 @@
    display: flex;
    justify-content: flex-end;
    align-items: center;
    margin-top: 16rpx;
    padding-top: 16rpx;
    border-top: 1px solid rgba(0, 0, 0, 0.05);
  }
  .message-creator {
    font-size: 12px;
    color: $text-tertiary;
  .message-view {
    padding: 12rpx 32rpx;
    background: linear-gradient(135deg, $primary-color 0%, $primary-light 100%);
    color: #ffffff;
    border-radius: 24rpx;
    font-size: 26rpx;
    font-weight: 500;
    box-shadow: 0 4rpx 12rpx rgba(41, 121, 255, 0.3);
    transition: all 0.3s ease;
    position: relative;
    overflow: hidden;
    &::before {
      content: '';
      position: absolute;
      top: 50%;
      left: 50%;
      width: 0;
      height: 0;
      border-radius: 50%;
      background: rgba(255, 255, 255, 0.3);
      transform: translate(-50%, -50%);
      transition: width 0.6s, height 0.6s;
    }
    &:active {
      transform: scale(0.95);
      box-shadow: 0 2rpx 8rpx rgba(41, 121, 255, 0.4);
      &::before {
        width: 300rpx;
        height: 300rpx;
      }
    }
  }
  /* 空状态 */
  .empty-state {
    background-color: $card-bg;
    border-radius: 16rpx;
    background: linear-gradient(135deg, #ffffff 0%, #fafbfc 100%);
    border-radius: 20rpx;
    box-shadow: $shadow-sm;
    text-align: center;
    padding: 160rpx 0;
    margin: 40rpx 0;
    padding: 160rpx 40rpx;
    margin: 60rpx 0 0 0;
    border: 1px solid rgba(0, 0, 0, 0.05);
    width: 100%;
    box-sizing: border-box;
  }
  .empty-text {
    font-size: 14px;
    font-size: 28rpx;
    color: $text-tertiary;
    margin-top: 24rpx;
    font-weight: 500;
@@ -363,44 +852,21 @@
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 30rpx 0;
    margin-top: 10rpx;
  }
  .loading-more-text {
    font-size: 14px;
    color: $text-tertiary;
    margin-left: 10rpx;
  }
  /* 加载更多 */
  .load-more {
    text-align: center;
    padding: 30rpx 0;
    font-size: 14px;
    color: $primary-color;
    font-weight: 500;
    padding: 40rpx 0;
    margin-top: 20rpx;
  }
  .load-more-text {
    display: inline-block;
    padding: 10rpx 30rpx;
    background-color: rgba($primary-color, 0.1);
    border-radius: 20rpx;
    transition: all 0.3s ease;
  }
  .load-more-text:hover {
    background-color: rgba($primary-color, 0.2);
    transform: translateY(-2rpx);
  .loading-more-text {
    font-size: 26rpx;
    color: $text-tertiary;
    margin-left: 12rpx;
  }
  /* 动画效果 */
  @keyframes fadeInUp {
    from {
      opacity: 0;
      transform: translateY(20rpx);
      transform: translateY(30rpx);
    }
    to {
      opacity: 1;
@@ -409,7 +875,11 @@
  }
  .message-item {
    animation: fadeInUp 0.3s ease-out;
    animation: fadeInUp 0.4s cubic-bezier(0.4, 0, 0.2, 1) backwards;
  }
  .message-item:nth-child(1) {
    animation-delay: 0.05s;
  }
  .message-item:nth-child(2) {
@@ -417,18 +887,54 @@
  }
  .message-item:nth-child(3) {
    animation-delay: 0.2s;
    animation-delay: 0.15s;
  }
  .message-item:nth-child(4) {
    animation-delay: 0.3s;
    animation-delay: 0.2s;
  }
  .message-item:nth-child(5) {
    animation-delay: 0.4s;
    animation-delay: 0.25s;
  }
  .message-view {
    float: right;
    color: $primary-color;
  /* 响应式优化 */
  @media (prefers-color-scheme: dark) {
    .message-page {
      background: linear-gradient(180deg, #1f2937 0%, #111827 100%);
    }
    .tabs-container {
      background-color: #1f2937;
      border-bottom: 1px solid rgba(255, 255, 255, 0.1);
    }
    .message-item {
      background: linear-gradient(135deg, #1f2937 0%, #111827 100%);
      border-color: rgba(255, 255, 255, 0.1);
    }
    .message-item.unread {
      background: linear-gradient(135deg, #1f2937 0%, #1e3a5f 100%);
      border-color: rgba(41, 121, 255, 0.3);
    }
    .message-title {
      color: #f3f4f6;
    }
    .message-desc {
      color: #d1d5db;
    }
    .message-time {
      background: rgba(255, 255, 255, 0.1);
      color: #9ca3af;
    }
    .empty-state {
      background: linear-gradient(135deg, #1f2937 0%, #111827 100%);
      border-color: rgba(255, 255, 255, 0.1);
    }
  }
</style>
src/pages/procurementManagement/invoiceEntry/index.vue
@@ -1,240 +1,247 @@
<template>
    <view class="sales-account">
        <!-- 使用通用页面头部组件 -->
        <PageHeader title="来票登记" @back="goBack" />
        <!-- 搜索和筛选区域 -->
        <view class="search-section">
            <view class="search-bar">
                <view class="search-input">
                    <up-input
                        class="search-text"
                        placeholder="请输入采购合同号/供应商名称"
                        v-model="supplierName"
                        @change="getList"
                        clearable
                    />
                </view>
                <view class="filter-button" @click="getList">
                    <up-icon name="search" size="24" color="#999"></up-icon>
                </view>
            </view>
        </view>
        <!-- 采购台账瀑布流 -->
        <view class="ledger-list" v-if="ledgerList.length > 0">
            <view v-for="(item, index) in ledgerList" :key="index">
                <view class="ledger-item">
                    <view class="item-header">
                        <view class="item-left">
                            <view class="document-icon">
                                <up-icon name="file-text" size="16" color="#ffffff"></up-icon>
                            </view>
                            <text class="item-id">{{ item.purchaseContractNumber }}</text>
                        </view>
                    </view>
                    <up-divider></up-divider>
                    <view class="item-details">
                        <view class="detail-row">
                            <text class="detail-label">销售合同号</text>
                            <text class="detail-value">{{ item.salesContractNo }}</text>
                        </view>
                        <view class="detail-row">
                            <text class="detail-label">供应商名称</text>
                            <text class="detail-value">{{ item.supplierName }}</text>
                        </view>
                        <view class="detail-row">
                            <text class="detail-label">项目名称</text>
                            <text class="detail-value">{{ item.projectName }}</text>
                        </view>
                        <view class="detail-row">
                            <text class="detail-label">合同金额(元)</text>
                            <text class="detail-value highlight">{{ item.contractAmount }}</text>
                        </view>
                        <view class="detail-row">
                            <text class="detail-label">已开票金额(元)</text>
                            <text class="detail-value highlight">{{ item.receiptPaymentAmount }}</text>
                        </view>
                        <view class="detail-row">
                            <text class="detail-label">待开票金额(元)</text>
                            <text class="detail-value redlight">{{ item.unReceiptPaymentAmount }}</text>
                        </view>
                    </view>
                    <!-- 操作按钮区域 -->
                    <view class="action-buttons">
                        <u-button
                            type="primary"
                            size="small"
                            @click="handleAddInvoice(item)"
                            class="action-btn"
                            :disabled="item.unReceiptPaymentAmount == 0"
                        >
                            新增开票
                        </u-button>
                        <u-button
                            size="small"
                            @click="handleViewDetail(item)"
                            class="action-btn"
                        >
                            查看详情
                        </u-button>
                    </view>
                </view>
            </view>
        </view>
        <view v-else class="no-data">
            <text>暂无采购台账数据</text>
        </view>
    </view>
  <view class="sales-account">
    <!-- 使用通用页面头部组件 -->
    <PageHeader title="来票登记"
                @back="goBack" />
    <!-- 搜索和筛选区域 -->
    <view class="search-section">
      <view class="search-bar">
        <view class="search-input">
          <up-input class="search-text"
                    placeholder="请输入采购合同号/供应商名称"
                    v-model="supplierName"
                    @change="getList"
                    clearable />
        </view>
        <view class="filter-button"
              @click="getList">
          <up-icon name="search"
                   size="24"
                   color="#999"></up-icon>
        </view>
      </view>
    </view>
    <!-- 采购台账瀑布流 -->
    <view class="ledger-list"
          v-if="ledgerList.length > 0">
      <view v-for="(item, index) in ledgerList"
            :key="index">
        <view class="ledger-item">
          <view class="item-header">
            <view class="item-left">
              <view class="document-icon">
                <up-icon name="file-text"
                         size="16"
                         color="#ffffff"></up-icon>
              </view>
              <text class="item-id">{{ item.purchaseContractNumber }}</text>
            </view>
          </view>
          <up-divider></up-divider>
          <view class="item-details">
            <view class="detail-row">
              <text class="detail-label">销售合同号</text>
              <text class="detail-value">{{ item.salesContractNo }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">供应商名称</text>
              <text class="detail-value">{{ item.supplierName }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">项目名称</text>
              <text class="detail-value">{{ item.projectName }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">合同金额(元)</text>
              <text class="detail-value highlight">{{ item.contractAmount }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">已开票金额(元)</text>
              <text class="detail-value highlight">{{ item.receiptPaymentAmount }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">待开票金额(元)</text>
              <text class="detail-value redlight">{{ item.unReceiptPaymentAmount }}</text>
            </view>
          </view>
          <!-- 操作按钮区域 -->
          <view class="action-buttons">
            <u-button type="primary"
                      size="small"
                      @click="handleAddInvoice(item)"
                      class="action-btn"
                      :disabled="item.unReceiptPaymentAmount == 0">
              新增开票
            </u-button>
            <u-button size="small"
                      @click="handleViewDetail(item)"
                      class="action-btn">
              查看详情
            </u-button>
          </view>
        </view>
      </view>
    </view>
    <view v-else
          class="no-data">
      <text>暂无采购台账数据</text>
    </view>
  </view>
</template>
<script setup>
import { ref } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import useUserStore from "@/store/modules/user";
import {gePurchaseListPage} from "@/api/procurementManagement/invoiceEntry";
const userStore = useUserStore()
  import { ref } from "vue";
  import { onShow } from "@dcloudio/uni-app";
  import useUserStore from "@/store/modules/user";
  import { gePurchaseListPage } from "@/api/procurementManagement/invoiceEntry";
  const userStore = useUserStore();
// 搜索关键词
const supplierName = ref('');
  // 搜索关键词
  const supplierName = ref("");
// 采购台账数据
const ledgerList = ref([]);
  // 采购台账数据
  const ledgerList = ref([]);
// 返回上一页
const goBack = () => {
    uni.navigateBack();
};
// 查询列表
const getList = () => {
    showLoadingToast('加载中...')
    const page = {
        current: -1,
        size: -1
    }
    gePurchaseListPage({...page, supplierName: supplierName.value}).then((res) => {
        ledgerList.value = res.data.records;
        closeToast()
    }).catch(() => {
        closeToast()
    });
};
  // 返回上一页
  const goBack = () => {
    uni.navigateBack();
  };
  // 查询列表
  const getList = () => {
    showLoadingToast("加载中...");
    const page = {
      current: -1,
      size: -1,
    };
    gePurchaseListPage({
      ...page,
      supplierName: supplierName.value,
      approvalStatus: 3,
    })
      .then(res => {
        ledgerList.value = res.data.records;
        closeToast();
      })
      .catch(() => {
        closeToast();
      });
  };
// 显示加载提示
const showLoadingToast = (message) => {
    uni.showLoading({
        title: message,
        mask: true
    });
};
  // 显示加载提示
  const showLoadingToast = message => {
    uni.showLoading({
      title: message,
      mask: true,
    });
  };
// 关闭提示
const closeToast = () => {
    uni.hideLoading();
};
  // 关闭提示
  const closeToast = () => {
    uni.hideLoading();
  };
// 处理新增来票
const handleAddInvoice = (item) => {
    try {
        // 存储选中的合同信息
        uni.setStorageSync('editData', JSON.stringify(item));
        // 跳转到新增来票页面
        uni.navigateTo({
            url: '/pages/procurementManagement/invoiceEntry/add'
        });
    } catch (error) {
        console.error('处理新增来票失败:', error);
        uni.showToast({
            title: '操作失败,请重试',
            icon: 'error'
        });
    }
};
  // 处理新增来票
  const handleAddInvoice = item => {
    try {
      // 存储选中的合同信息
      uni.setStorageSync("editData", JSON.stringify(item));
      // 跳转到新增来票页面
      uni.navigateTo({
        url: "/pages/procurementManagement/invoiceEntry/add",
      });
    } catch (error) {
      console.error("处理新增来票失败:", error);
      uni.showToast({
        title: "操作失败,请重试",
        icon: "error",
      });
    }
  };
// 处理查看详情
const handleViewDetail = (item) => {
    try {
        // 存储数据
        uni.setStorageSync('editData', JSON.stringify(item));
        // 跳转到详情页面
        uni.navigateTo({
            url: '/pages/procurementManagement/invoiceEntry/view'
        });
    } catch (error) {
        console.error('处理查看详情失败:', error);
        uni.showToast({
            title: '操作失败,请重试',
            icon: 'error'
        });
    }
};
  // 处理查看详情
  const handleViewDetail = item => {
    try {
      // 存储数据
      uni.setStorageSync("editData", JSON.stringify(item));
onShow(() => {
    // 页面显示时刷新列表
    getList();
});
      // 跳转到详情页面
      uni.navigateTo({
        url: "/pages/procurementManagement/invoiceEntry/view",
      });
    } catch (error) {
      console.error("处理查看详情失败:", error);
      uni.showToast({
        title: "操作失败,请重试",
        icon: "error",
      });
    }
  };
  onShow(() => {
    // 页面显示时刷新列表
    getList();
  });
</script>
<style scoped lang="scss">
@import '@/styles/procurement-common.scss';
  @import "@/styles/procurement-common.scss";
// 来票登记特有样式
.nav-icon {
    width: 24px;
    height: 24px;
    background: #2979ff;
    border-radius: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
}
  // 来票登记特有样式
  .nav-icon {
    width: 24px;
    height: 24px;
    background: #2979ff;
    border-radius: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
  }
.nav-text {
    font-size: 14px;
    color: #2979ff;
    font-weight: 500;
}
  .nav-text {
    font-size: 14px;
    color: #2979ff;
    font-weight: 500;
  }
.header-center {
    flex: 1;
    display: flex;
    justify-content: center;
    align-items: center;
    position: absolute;
    left: 0;
    right: 0;
    pointer-events: none;
}
  .header-center {
    flex: 1;
    display: flex;
    justify-content: center;
    align-items: center;
    position: absolute;
    left: 0;
    right: 0;
    pointer-events: none;
  }
.page-title {
    font-size: 18px;
    font-weight: 600;
    color: #333;
    pointer-events: auto;
}
  .page-title {
    font-size: 18px;
    font-weight: 600;
    color: #333;
    pointer-events: auto;
  }
.header-right {
    display: flex;
    align-items: center;
}
  .header-right {
    display: flex;
    align-items: center;
  }
.status-bar {
    display: flex;
    align-items: center;
    gap: 4px;
}
  .status-bar {
    display: flex;
    align-items: center;
    gap: 4px;
  }
.signal, .wifi, .battery {
    width: 16px;
    height: 8px;
    background: #333;
    border-radius: 2px;
}
  .signal,
  .wifi,
  .battery {
    width: 16px;
    height: 8px;
    background: #333;
    border-radius: 2px;
  }
.fab-button {
    bottom: 30px; // 与其他页面的 calc(30px + env(safe-area-inset-bottom)) 不同
}
  .fab-button {
    bottom: 30px; // 与其他页面的 calc(30px + env(safe-area-inset-bottom)) 不同
  }
</style>