index.vue 6.88 KB
<template>
  <view class="page-container">
    <!-- 顶部固定区域:Tabs + 搜索框 -->
    <view class="top-fixed">
      <!-- uView Tabs 标签 -->
      <u-tabs
          v-model="activeTab"
          :list="tabList"
          :is-scroll="false"
          :activeStyle="{
            color: '#3c9cff',
            fontWeight: 'bold',
            transform: 'scale(1.05)'
        }"
          :inactiveStyle="{
            color: '#606266',
            transform: 'scale(1)'
        }"
          font-size="28rpx"
          @change="handleTabChange"
      ></u-tabs>

      <!-- 道路名称搜索框 -->
      <u-search
          v-model="searchValue"
          placeholder="请输入道路名称"
          bg-color="#f5f5f5"
          border-radius="8rpx"
          :clearabled="true"
          @search="handleSearch"
          @clear="handleSearchClear"
          maxlength="50"
          style="margin: 10rpx 20rpx 0"
      ></u-search>
    </view>

    <!-- z-paging 分页列表 -->
    <z-paging
        v-model="planList"
        :page-size="pageSize"
        :total="total"
        @query="loadData"
        :scroll-top-reset-type="1"
        :top="160"
        bg-color="#f8f8f8"
    >
      <!-- 计划卡片列表 -->
      <view class="card-list">
        <view class="plan-card" v-for="(item, index) in planList" :key="index">
          <view class="card-content">
            <!-- 道路名称 -->
            <view class="row-item">
              <text class="label">道路名称:</text>
              <text class="value">{{ item.roadName }}</text>
            </view>
            <!-- 所属街道 -->
            <view class="row-item">
              <text class="label">所属街道:</text>
              <text class="value">{{ item.street }}</text>
            </view>
            <!-- 养护级别 + 计划明细按钮 -->
            <view class="row-item flex-between">
              <view>
                <text class="label">养护级别:</text>
                <text class="value">{{ item.maintainLevel }}</text>
              </view>
              <text class="detail-btn" @click="gotoDetail(item)">计划明细</text>
            </view>
            <!-- 计划类型 -->
            <view class="row-item">
              <text class="label">计划类型:</text>
              <text class="value">{{ item.planType }}</text>
            </view>
            <!-- 计划时间 -->
            <view class="row-item">
              <text class="label">计划时间:</text>
              <text class="value">{{ item.planTime }}</text>
            </view>
          </view>
        </view>
      </view>

      <!-- 空数据占位 -->
      <template #empty>
        <view class="empty-wrap">
          <text class="empty-text">暂无相关计划数据</text>
        </view>
      </template>
    </z-paging>
  </view>
</template>

<script setup>
import { ref, reactive, onMounted } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
// Tabs 配置
const tabList = ref([
  {name: '待完成', id: 'pending'},
  {name: '已失效', id: 'invalid'},
  {name: '已完成', id: 'completed'}
]);
const activeTab = ref('pending'); // 当前激活的Tab
// 搜索相关
const searchValue = ref(''); // 搜索框值
// 分页相关
const pageNo = ref(1); // 当前页码
const pageSize = ref(10); // 每页条数
const total = ref(100); // 总记录数(模拟大量数据)
const planList = ref([]); // 计划列表数据
// Tab切换事件(清空搜索条件)
const handleTabChange = () => {
  // 清空搜索框
  searchValue.value = '';
  // 重置分页
  pageNo.value = 1;
  // 重新加载数据
  loadData(true);
};
// 搜索事件
const handleSearch = () => {
  pageNo.value = 1;
  loadData(true);
};
// 清空搜索框
const handleSearchClear = () => {
  pageNo.value = 1;
  loadData(true);
};
// 生成模拟数据
const generateMockData = (page) => {
  const mockList = [];
  const tabMap = {
    pending: '待完成',
    invalid: '已失效',
    completed: '已完成'
  };
  const maintainLevels = ['一级养护', '二级养护', '三级养护'];
  const planTypes = ['日常养护', '专项养护', '应急养护'];
  const streets = ['西长安街街道', '东城区东华门街道', '朝阳区望京街道', '海淀区中关村街道', '丰台区马家堡街道'];
  const roadNames = [
    '长安街', '王府井大街', '中关村南大街', '朝阳北路', '建国路',
    '复兴路', '西直门外大街', '广渠路', '阜成门外大街', '安定门东大街'
  ];
  // 生成当前页数据
  for (let i = 0; i < 35; i++) {
    const idx = (page - 1) * pageSize.value + i;
    mockList.push({
      id: idx + 1,
      roadName: `${roadNames[idx % roadNames.length]}${idx + 1}段`,
      street: streets[Math.floor(Math.random() * streets.length)],
      maintainLevel: maintainLevels[Math.floor(Math.random() * maintainLevels.length)],
      planType: planTypes[Math.floor(Math.random() * planTypes.length)],
      planTime: `2025-${Math.floor(Math.random() * 12) + 1}-${Math.floor(Math.random() * 28) + 1} 至 2025-${Math.floor(Math.random() * 12) + 1}-${Math.floor(Math.random() * 28) + 1}`,
      status: tabMap[activeTab.value]
    });
  }
  return mockList;
};
// 加载数据(z-paging 核心方法)
const loadData = (isRefresh = false) => {
  // 模拟接口请求延迟
  setTimeout(() => {
    const newData = generateMockData(pageNo.value);
    if (isRefresh) {
      planList.value = newData; // 刷新:替换数据
    } else {
      planList.value = [...planList.value, ...newData]; // 加载更多:追加数据
    }
  }, 500);
};
// 跳转到计划明细页面
const gotoDetail = (item) => {
  uni.navigateTo({
    url: `/pages/plan-detail/index?id=${item.id}&status=${activeTab.value}`
  });
};
// 页面加载初始化
onLoad(() => {
  loadData(true);
});
</script>

<style scoped lang="scss">
.page-container {
  min-height: 100vh;
  background-color: #f8f8f8;
}

/* 顶部固定区域 */
.top-fixed {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 999;
  background-color: #fff;
  padding-bottom: 10rpx;
  box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
}

/* 计划卡片样式 */
.card-list {
  padding: 170rpx 20rpx 20rpx;
}

.plan-card {
  background-color: #fff;
  border-radius: 12rpx;
  padding: 20rpx;
  margin-bottom: 15rpx;
  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.03);
}

.card-content {
  display: flex;
  flex-direction: column;
  gap: 12rpx;
}

.row-item {
  display: flex;
  align-items: center;
  font-size: 28rpx;
  line-height: 1.5;
}

.flex-between {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.label {
  color: #999;
  width: 140rpx;
  flex-shrink: 0;
}

.value {
  color: #333;
  flex: 1;
}

.detail-btn {
  color: #1989fa;
  font-size: 26rpx;
  padding: 0 10rpx;
}

/* 空数据样式 */
.empty-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 100rpx 0;
}

.empty-text {
  font-size: 28rpx;
  color: #999;
}
</style>