فهرست منبع

系统重构完成

Huanyi 3 ماه پیش
والد
کامیت
e0fc622a18

+ 1 - 1
apis/setting.js

@@ -10,7 +10,7 @@ import request from '@/utils/request'
  */
 export const getAgreementContent = (type) => {
   return request({
-    url: `/setting/applet/${type}`,
+    url: `/setting/agreement/${type}`,
     method: 'GET'
   })
 }

+ 121 - 0
components/TabBar/index.vue

@@ -0,0 +1,121 @@
+<template>
+  <view class="custom-tabbar">
+    <view 
+      v-for="(item, index) in tabList" 
+      :key="index"
+      class="tab-item"
+      :class="{ active: currentTab === item.name }"
+      @click="handleTabClick(item)"
+    >
+      <image 
+        class="tab-icon" 
+        :src="currentTab === item.name ? item.activeIcon : item.icon"
+        mode="aspectFit"
+      />
+      <text class="tab-text">{{ item.label }}</text>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { computed } from 'vue'
+import { useI18n } from 'vue-i18n'
+
+const { t } = useI18n()
+
+// 定义props
+const props = defineProps({
+  currentTab: {
+    type: String,
+    default: 'home'
+  }
+})
+
+// 底部导航配置
+const tabList = computed(() => [
+  {
+    name: 'home',
+    label: t('common.page.home'),
+    icon: '/static/pages/tabbar/home.png',
+    activeIcon: '/static/pages/tabbar/home-active.png',
+    url: '/pages/home/index'
+  },
+  {
+    name: 'scan',
+    label: t('common.page.scan'),
+    icon: '/static/pages/tabbar/scan.png',
+    activeIcon: '/static/pages/tabbar/scan-active.png',
+    url: '/pages/scan/index'
+  },
+  {
+    name: 'mine',
+    label: t('common.page.mine'),
+    icon: '/static/pages/tabbar/mine.png',
+    activeIcon: '/static/pages/tabbar/mine-active.png',
+    url: '/pages/my/index'
+  }
+])
+
+// 处理tab点击
+const handleTabClick = (item) => {
+  if (props.currentTab === item.name) return
+  
+  // 使用reLaunch跳转,清空页面栈
+  uni.reLaunch({
+    url: item.url
+  })
+}
+</script>
+
+<style lang="scss" scoped>
+.custom-tabbar {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  height: 100rpx;
+  background-color: #ffffff;
+  display: flex;
+  border-top: 1rpx solid #e5e5e5;
+  padding-bottom: env(safe-area-inset-bottom);
+  z-index: 1000;
+  
+  .tab-item {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    padding: 8rpx 0;
+    transition: all 0.3s ease;
+    
+    .tab-icon {
+      width: 48rpx;
+      height: 48rpx;
+      margin-bottom: 4rpx;
+      transition: transform 0.3s ease;
+    }
+    
+    .tab-text {
+      font-size: 20rpx;
+      color: #666666;
+      transition: color 0.3s ease;
+    }
+    
+    &.active {
+      .tab-icon {
+        transform: scale(1.1);
+      }
+      
+      .tab-text {
+        color: #1ec9c9;
+        font-weight: 500;
+      }
+    }
+    
+    &:active {
+      opacity: 0.8;
+    }
+  }
+}
+</style>

BIN
home.png


+ 0 - 81
pages-content/home/index.vue

@@ -1,81 +0,0 @@
-<template>
-  <view class="home-page">
-    <!-- 自定义头部 -->
-    <view class="custom-header" :style="{ paddingTop: statusBarHeight + 'px' }">
-      <view class="header-content">
-        <text class="header-title">{{ t('common.page.home') }}</text>
-      </view>
-    </view>
-    
-    <!-- 页面内容 -->
-    <view class="page-body">
-      <text class="placeholder">首页主体内容区域</text>
-    </view>
-  </view>
-</template>
-
-<script setup>
-import { ref, onMounted } from 'vue'
-import { useI18n } from 'vue-i18n'
-
-const { t } = useI18n()
-
-// 状态栏高度
-const statusBarHeight = ref(0)
-
-onMounted(() => {
-  // 获取系统信息
-  const systemInfo = uni.getSystemInfoSync()
-  statusBarHeight.value = systemInfo.statusBarHeight || 0
-  
-  console.log('首页内容组件已加载')
-})
-</script>
-
-<style lang="scss" scoped>
-.home-page {
-  width: 100%;
-  min-height: 100vh;
-  display: flex;
-  flex-direction: column;
-  background: linear-gradient(180deg, #E3F2FD 0%, #F0F7FF 100%);
-  
-  // 自定义头部
-  .custom-header {
-    position: fixed;
-    top: 0;
-    left: 0;
-    right: 0;
-    background-color: #ffffff;
-    border-bottom: 1rpx solid #e5e5e5;
-    z-index: 100;
-    
-    .header-content {
-      height: 88rpx;
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      
-      .header-title {
-        font-size: 32rpx;
-        font-weight: 500;
-        color: #000000;
-      }
-    }
-  }
-  
-  // 页面内容
-  .page-body {
-    flex: 1;
-    padding: 40rpx;
-    margin-top: 88rpx;
-    
-    .placeholder {
-      font-size: 28rpx;
-      color: #999999;
-      text-align: center;
-      margin-top: 200rpx;
-    }
-  }
-}
-</style>

+ 0 - 81
pages-content/scan/index.vue

@@ -1,81 +0,0 @@
-<template>
-  <view class="scan-page">
-    <!-- 自定义头部 -->
-    <view class="custom-header" :style="{ paddingTop: statusBarHeight + 'px' }">
-      <view class="header-content">
-        <text class="header-title">{{ t('common.page.scan') }}</text>
-      </view>
-    </view>
-    
-    <!-- 页面内容 -->
-    <view class="page-body">
-      <text class="placeholder">扫描主体内容区域</text>
-    </view>
-  </view>
-</template>
-
-<script setup>
-import { ref, onMounted } from 'vue'
-import { useI18n } from 'vue-i18n'
-
-const { t } = useI18n()
-
-// 状态栏高度
-const statusBarHeight = ref(0)
-
-onMounted(() => {
-  // 获取系统信息
-  const systemInfo = uni.getSystemInfoSync()
-  statusBarHeight.value = systemInfo.statusBarHeight || 0
-  
-  console.log('扫描内容组件已加载')
-})
-</script>
-
-<style lang="scss" scoped>
-.scan-page {
-  width: 100%;
-  min-height: 100vh;
-  display: flex;
-  flex-direction: column;
-  background: linear-gradient(180deg, #E3F2FD 0%, #F0F7FF 100%);
-  
-  // 自定义头部
-  .custom-header {
-    position: fixed;
-    top: 0;
-    left: 0;
-    right: 0;
-    background-color: #ffffff;
-    border-bottom: 1rpx solid #e5e5e5;
-    z-index: 100;
-    
-    .header-content {
-      height: 88rpx;
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      
-      .header-title {
-        font-size: 32rpx;
-        font-weight: 500;
-        color: #000000;
-      }
-    }
-  }
-  
-  // 页面内容
-  .page-body {
-    flex: 1;
-    padding: 40rpx;
-    margin-top: 88rpx;
-    
-    .placeholder {
-      font-size: 28rpx;
-      color: #999999;
-      text-align: center;
-      margin-top: 200rpx;
-    }
-  }
-}
-</style>

+ 25 - 9
pages.json

@@ -3,39 +3,55 @@
     {
       "path": "pages/login/login",
       "style": {
-        "navigationBarTitleText": "登录",
         "navigationStyle": "custom",
         "enablePullDownRefresh": false
       }
     },
     {
-      "path": "pages/index",
+      "path": "pages/home/index",
       "style": {
         "navigationStyle": "custom",
         "enablePullDownRefresh": false
       }
     },
     {
-      "path": "pages-content/my/aggreement/index",
+      "path": "pages/scan/index",
       "style": {
-        "navigationBarTitleText": "协议说明",
         "navigationStyle": "custom",
         "enablePullDownRefresh": false
       }
     },
     {
-      "path": "pages-content/my/aggreement/detail",
+      "path": "pages/my/index",
+      "style": {
+        "navigationStyle": "custom",
+        "enablePullDownRefresh": false
+      }
+    },
+    {
+      "path": "pages/my/aggreement/index",
+      "style": {
+        "navigationStyle": "custom",
+        "enablePullDownRefresh": false
+      }
+    },
+    {
+      "path": "pages/my/aggreement/detail",
+      "style": {
+        "navigationStyle": "custom",
+        "enablePullDownRefresh": false
+      }
+    },
+    {
+      "path": "pages/my/info/index",
       "style": {
-        "navigationBarTitleText": "协议详情",
         "navigationStyle": "custom",
         "enablePullDownRefresh": false
       }
     }
   ],
   "globalStyle": {
-    "navigationBarTextStyle": "black",
-    "navigationBarTitleText": "智能eTMF系统",
-    "navigationBarBackgroundColor": "#F8F8F8",
+    "navigationStyle": "custom",
     "backgroundColor": "#F8F8F8"
   },
   "uniIdRouter": {}

+ 401 - 0
pages/home/index.vue

@@ -0,0 +1,401 @@
+<template>
+  <view class="home-page">
+    <!-- 顶部渐变背景区域 -->
+    <view class="header-bg" :style="{ paddingTop: statusBarHeight + 'px' }">
+      <view class="header-content">
+        <text class="header-title">智能eTMF小程序</text>
+      </view>
+    </view>
+    
+    <!-- 页面内容 -->
+    <view class="page-content">
+      <!-- 搜索框 -->
+      <view class="search-box">
+        <image class="search-icon" src="/static/pages/home/search.png" mode="aspectFit" />
+        <input 
+          class="search-input" 
+          placeholder="输入要搜索的文档名称"
+          placeholder-class="search-placeholder"
+          v-model="searchKeyword"
+          @confirm="handleSearch"
+        />
+      </view>
+      
+      <!-- 轮播图 -->
+      <view class="banner-section">
+        <swiper 
+          class="banner-swiper" 
+          :indicator-dots="true" 
+          :autoplay="true" 
+          :interval="3000"
+          :duration="500"
+          indicator-color="rgba(255, 255, 255, 0.5)"
+          indicator-active-color="#1ec9c9"
+        >
+          <swiper-item v-for="(item, index) in bannerList" :key="index">
+            <image class="banner-image" :src="item.image" mode="aspectFill" />
+          </swiper-item>
+        </swiper>
+      </view>
+      
+      <!-- 智能扫描卡片 -->
+      <view class="scan-card" @click="handleGoToScan">
+        <view class="scan-icon-wrapper">
+          <image class="scan-icon" src="/static/pages/home/scan-icon.png" mode="aspectFit" />
+        </view>
+        <view class="scan-info">
+          <text class="scan-title">智能扫描</text>
+          <text class="scan-desc">快速的扫描上传文档进行递交文档</text>
+        </view>
+      </view>
+      
+      <!-- 最近文档 -->
+      <view class="recent-section">
+        <view class="section-header">
+          <text class="section-title">最近文档</text>
+          <view class="more-btn" @click="handleViewMore">
+            <text class="more-text">查看更多</text>
+            <text class="more-arrow">›</text>
+          </view>
+        </view>
+        
+        <view class="document-list">
+          <view 
+            v-for="(doc, index) in recentDocuments" 
+            :key="index"
+            class="document-item"
+            @click="handleDocumentClick(doc)"
+          >
+            <image class="doc-thumbnail" :src="doc.thumbnail" mode="aspectFill" />
+            <view class="doc-info">
+              <text class="doc-name">{{ doc.name }}</text>
+              <text class="doc-meta">{{ doc.date }} | 共{{ doc.pages }}页</text>
+            </view>
+          </view>
+        </view>
+      </view>
+    </view>
+    
+    <!-- 底部导航栏 -->
+    <TabBar current-tab="home" />
+  </view>
+</template>
+
+<script setup>
+import { ref, onMounted } from 'vue'
+import { useI18n } from 'vue-i18n'
+import TabBar from '@/components/TabBar/index.vue'
+
+const { t } = useI18n()
+
+// 状态栏高度
+const statusBarHeight = ref(0)
+
+// 搜索关键词
+const searchKeyword = ref('')
+
+// 轮播图数据
+const bannerList = ref([
+  {
+    image: '/static/pages/home/banner1.png'
+  },
+  {
+    image: '/static/pages/home/banner2.png'
+  }
+])
+
+// 最近文档数据
+const recentDocuments = ref([
+  {
+    id: 1,
+    name: 'HFSLKD_SKD_测试文档名称1',
+    date: '2025/11/12 11:12',
+    pages: 5,
+    thumbnail: '/static/pages/home/doc-thumb.png'
+  },
+  {
+    id: 2,
+    name: 'HFSLKD_SKD_测试文档名称1',
+    date: '2025/11/12 11:12',
+    pages: 5,
+    thumbnail: '/static/pages/home/doc-thumb.png'
+  },
+  {
+    id: 3,
+    name: 'HFSLKD_SKD_测试文档名称1',
+    date: '2025/11/12 11:12',
+    pages: 5,
+    thumbnail: '/static/pages/home/doc-thumb.png'
+  },
+  {
+    id: 4,
+    name: 'HFSLKD_SKD_测试文档名称1',
+    date: '2025/11/12 11:12',
+    pages: 5,
+    thumbnail: '/static/pages/home/doc-thumb.png'
+  },
+  {
+    id: 5,
+    name: 'HFSLKD_SKD_测试文档名称1',
+    date: '2025/11/12 11:12',
+    pages: 5,
+    thumbnail: '/static/pages/home/doc-thumb.png'
+  }
+])
+
+onMounted(() => {
+  // 获取系统信息
+  const windowInfo = uni.getWindowInfo()
+  statusBarHeight.value = windowInfo.statusBarHeight || 0
+})
+
+// 搜索
+const handleSearch = () => {
+  if (!searchKeyword.value.trim()) {
+    uni.showToast({
+      title: '请输入搜索关键词',
+      icon: 'none'
+    })
+    return
+  }
+  
+  uni.showToast({
+    title: `搜索: ${searchKeyword.value}`,
+    icon: 'none'
+  })
+  // TODO: 实现搜索功能
+}
+
+// 跳转到扫描页面
+const handleGoToScan = () => {
+  uni.reLaunch({
+    url: '/pages/scan/index'
+  })
+}
+
+// 查看更多文档
+const handleViewMore = () => {
+  uni.showToast({
+    title: '查看更多文档',
+    icon: 'none'
+  })
+  // TODO: 跳转到文档列表页
+}
+
+// 点击文档
+const handleDocumentClick = (doc) => {
+  uni.showToast({
+    title: `打开文档: ${doc.name}`,
+    icon: 'none'
+  })
+  // TODO: 跳转到文档详情页
+}
+</script>
+
+<style lang="scss" scoped>
+.home-page {
+  width: 100%;
+  min-height: 100vh;
+  display: flex;
+  flex-direction: column;
+  background-color: #f5f5f5;
+  padding-bottom: calc(100rpx + env(safe-area-inset-bottom));
+  
+  // 顶部渐变背景
+  .header-bg {
+    background: linear-gradient(180deg, #1ec9c9 0%, #1eb8b8 100%);
+    
+    .header-content {
+      padding: 0 24rpx 16rpx;
+      
+      .header-title {
+        font-size: 32rpx;
+        font-weight: 600;
+        color: #ffffff;
+        display: block;
+        padding: 12rpx 0;
+        line-height: 1.4;
+      }
+    }
+  }
+  
+  // 页面内容
+  .page-content {
+    flex: 1;
+    padding: 0 24rpx 24rpx;
+    margin-top: -12rpx;
+    
+    // 搜索框
+    .search-box {
+      background: #ffffff;
+      border-radius: 16rpx;
+      padding: 20rpx 24rpx;
+      display: flex;
+      align-items: center;
+      margin-bottom: 24rpx;
+      box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
+      
+      .search-icon {
+        width: 32rpx;
+        height: 32rpx;
+        margin-right: 16rpx;
+      }
+      
+      .search-input {
+        flex: 1;
+        font-size: 28rpx;
+        color: #333333;
+      }
+      
+      .search-placeholder {
+        color: #999999;
+      }
+    }
+    
+    // 轮播图
+    .banner-section {
+      margin-bottom: 24rpx;
+      
+      .banner-swiper {
+        width: 100%;
+        height: 280rpx;
+        border-radius: 16rpx;
+        overflow: hidden;
+        
+        .banner-image {
+          width: 100%;
+          height: 100%;
+        }
+      }
+    }
+    
+    // 智能扫描卡片
+    .scan-card {
+      background: #ffffff;
+      border-radius: 16rpx;
+      padding: 32rpx 24rpx;
+      display: flex;
+      align-items: center;
+      margin-bottom: 24rpx;
+      box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
+      
+      &:active {
+        background-color: #f8f8f8;
+      }
+      
+      .scan-icon-wrapper {
+        width: 88rpx;
+        height: 88rpx;
+        background: linear-gradient(135deg, #1ec9c9 0%, #17b3b3 100%);
+        border-radius: 16rpx;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        margin-right: 24rpx;
+        
+        .scan-icon {
+          width: 56rpx;
+          height: 56rpx;
+        }
+      }
+      
+      .scan-info {
+        flex: 1;
+        display: flex;
+        flex-direction: column;
+        gap: 8rpx;
+        
+        .scan-title {
+          font-size: 32rpx;
+          font-weight: 600;
+          color: #333333;
+        }
+        
+        .scan-desc {
+          font-size: 24rpx;
+          color: #999999;
+          line-height: 1.4;
+        }
+      }
+    }
+    
+    // 最近文档
+    .recent-section {
+      .section-header {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        margin-bottom: 24rpx;
+        
+        .section-title {
+          font-size: 32rpx;
+          font-weight: 600;
+          color: #333333;
+        }
+        
+        .more-btn {
+          display: flex;
+          align-items: center;
+          gap: 4rpx;
+          
+          .more-text {
+            font-size: 26rpx;
+            color: #999999;
+          }
+          
+          .more-arrow {
+            font-size: 36rpx;
+            color: #999999;
+            font-weight: 300;
+          }
+        }
+      }
+      
+      .document-list {
+        .document-item {
+          background: #ffffff;
+          border-radius: 16rpx;
+          padding: 24rpx;
+          display: flex;
+          align-items: center;
+          margin-bottom: 16rpx;
+          box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
+          
+          &:active {
+            background-color: #f8f8f8;
+          }
+          
+          .doc-thumbnail {
+            width: 100rpx;
+            height: 120rpx;
+            border-radius: 8rpx;
+            margin-right: 24rpx;
+            background-color: #f0f0f0;
+          }
+          
+          .doc-info {
+            flex: 1;
+            display: flex;
+            flex-direction: column;
+            gap: 12rpx;
+            
+            .doc-name {
+              font-size: 28rpx;
+              font-weight: 500;
+              color: #333333;
+              overflow: hidden;
+              text-overflow: ellipsis;
+              white-space: nowrap;
+            }
+            
+            .doc-meta {
+              font-size: 24rpx;
+              color: #999999;
+            }
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 0 - 143
pages/index.vue

@@ -1,143 +0,0 @@
-<template>
-  <view class="page-container">
-    <!-- 主内容区 -->
-    <view class="main-content">
-      <!-- 首页内容 -->
-      <HomePage v-if="currentTab === 'home'" />
-      
-      <!-- 扫描内容 -->
-      <ScanPage v-else-if="currentTab === 'scan'" />
-      
-      <!-- 我的内容 -->
-      <MyPage v-else-if="currentTab === 'mine'" />
-    </view>
-    
-    <!-- 自定义底部导航栏 -->
-    <view class="custom-tabbar">
-      <view 
-        v-for="(item, index) in tabList" 
-        :key="index"
-        class="tab-item"
-        :class="{ active: currentTab === item.name }"
-        @click="switchTab(item.name)"
-      >
-        <image 
-          class="tab-icon" 
-          :src="currentTab === item.name ? item.activeIcon : item.icon"
-          mode="aspectFit"
-        />
-        <text class="tab-text">{{ item.label }}</text>
-      </view>
-    </view>
-  </view>
-</template>
-
-<script setup>
-import { ref, computed } from 'vue'
-import { useI18n } from 'vue-i18n'
-import HomePage from '../pages-content/home/index.vue'
-import ScanPage from '../pages-content/scan/index.vue'
-import MyPage from '../pages-content/my/index.vue'
-
-const { t } = useI18n()
-
-// 当前激活的tab
-const currentTab = ref('home')
-
-// 底部导航配置
-const tabList = computed(() => [
-  {
-    name: 'home',
-    label: t('common.page.home'),
-    icon: '/static/pages/tabbar/home.png',
-    activeIcon: '/static/pages/tabbar/home-active.png'
-  },
-  {
-    name: 'scan',
-    label: t('common.page.scan'),
-    icon: '/static/pages/tabbar/scan.png',
-    activeIcon: '/static/pages/tabbar/scan-active.png'
-  },
-  {
-    name: 'mine',
-    label: t('common.page.mine'),
-    icon: '/static/pages/tabbar/mine.png',
-    activeIcon: '/static/pages/tabbar/mine-active.png'
-  }
-])
-
-// 切换tab
-const switchTab = (name) => {
-  if (currentTab.value === name) return
-  currentTab.value = name
-}
-</script>
-
-<style lang="scss" scoped>
-.page-container {
-  width: 100%;
-  height: 100vh;
-  display: flex;
-  flex-direction: column;
-  background-color: #f5f5f5;
-}
-
-// 主内容区
-.main-content {
-  flex: 1;
-  overflow-y: auto;
-  padding-bottom: calc(100rpx + env(safe-area-inset-bottom));
-}
-
-// 自定义底部导航栏
-.custom-tabbar {
-  position: fixed;
-  bottom: 0;
-  left: 0;
-  right: 0;
-  height: 100rpx;
-  background-color: #ffffff;
-  display: flex;
-  border-top: 1rpx solid #e5e5e5;
-  padding-bottom: env(safe-area-inset-bottom);
-  z-index: 1000;
-  
-  .tab-item {
-    flex: 1;
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    justify-content: center;
-    padding: 8rpx 0;
-    transition: all 0.3s ease;
-    
-    .tab-icon {
-      width: 48rpx;
-      height: 48rpx;
-      margin-bottom: 4rpx;
-      transition: transform 0.3s ease;
-    }
-    
-    .tab-text {
-      font-size: 20rpx;
-      color: #666666;
-      transition: color 0.3s ease;
-    }
-    
-    &.active {
-      .tab-icon {
-        transform: scale(1.1);
-      }
-      
-      .tab-text {
-        color: #2E7CF6;
-        font-weight: 500;
-      }
-    }
-    
-    &:active {
-      opacity: 0.8;
-    }
-  }
-}
-</style>

+ 6 - 6
pages/login/login.vue

@@ -106,8 +106,8 @@ const languageSwitcherTop = computed(() => {
 
 onMounted(() => {
   // 获取系统信息
-  const systemInfo = uni.getSystemInfoSync()
-  statusBarHeight.value = systemInfo.statusBarHeight || 0
+  const windowInfo = uni.getWindowInfo()
+  statusBarHeight.value = windowInfo.statusBarHeight || 0
 })
 
 // 当前语言名称
@@ -187,14 +187,14 @@ const handleAgreementChange = (e) => {
 // 查看用户协议
 const viewUserAgreement = () => {
   uni.navigateTo({
-    url: '/pages-content/my/aggreement/detail?type=user'
+    url: '/pages/my/aggreement/detail?type=user'
   })
 }
 
 // 查看隐私协议
 const viewPrivacyPolicy = () => {
   uni.navigateTo({
-    url: '/pages-content/my/aggreement/detail?type=privacy'
+    url: '/pages/my/aggreement/detail?type=privacy'
   })
 }
 
@@ -265,8 +265,8 @@ const handleLogin = async () => {
     
     // 登录成功后跳转到首页
     setTimeout(() => {
-      uni.navigateTo({
-        url: '/pages/index'
+      uni.reLaunch({
+        url: '/pages/home/index'
       })
     }, 1500)
     

+ 3 - 3
pages-content/my/aggreement/detail.vue → pages/my/aggreement/detail.vue

@@ -49,8 +49,8 @@ const pageTitle = computed(() => {
 
 onMounted(async () => {
   // 获取系统信息
-  const systemInfo = uni.getSystemInfoSync()
-  statusBarHeight.value = systemInfo.statusBarHeight || 0
+  const windowInfo = uni.getWindowInfo()
+  statusBarHeight.value = windowInfo.statusBarHeight || 0
   
   // 获取页面参数
   const pages = getCurrentPages()
@@ -70,7 +70,7 @@ const handleBack = () => {
     uni.navigateBack()
   } else {
     uni.reLaunch({
-      url: '/pages/index'
+      url: '/pages/home/index'
     })
   }
 }

+ 7 - 7
pages-content/my/aggreement/index.vue → pages/my/aggreement/index.vue

@@ -18,7 +18,7 @@
         <!-- 用户协议 -->
         <view class="list-item" @click="handleUserAgreement">
           <view class="item-left">
-            <image class="item-icon" src="/static/pages-content/my/agreement/user.png" mode="aspectFit" />
+            <image class="item-icon" src="/static/pages/my/agreement/user.png" mode="aspectFit" />
             <view class="item-info">
               <text class="item-title">用户协议</text>
               <text class="item-desc">了解使用本应用的相关条款</text>
@@ -30,7 +30,7 @@
         <!-- 隐私协议 -->
         <view class="list-item" @click="handlePrivacyPolicy">
           <view class="item-left">
-            <image class="item-icon" src="/static/pages-content/my/agreement/privacy.png" mode="aspectFit" />
+            <image class="item-icon" src="/static/pages/my/agreement/privacy.png" mode="aspectFit" />
             <view class="item-info">
               <text class="item-title">隐私政策</text>
               <text class="item-desc">了解我们如何保护您的隐私</text>
@@ -51,8 +51,8 @@ const statusBarHeight = ref(0)
 
 onMounted(() => {
   // 获取系统信息
-  const systemInfo = uni.getSystemInfoSync()
-  statusBarHeight.value = systemInfo.statusBarHeight || 0
+  const windowInfo = uni.getWindowInfo()
+  statusBarHeight.value = windowInfo.statusBarHeight || 0
 })
 
 // 返回上一页
@@ -62,7 +62,7 @@ const handleBack = () => {
     uni.navigateBack()
   } else {
     uni.reLaunch({
-      url: '/pages/index'
+      url: '/pages/home/index'
     })
   }
 }
@@ -70,14 +70,14 @@ const handleBack = () => {
 // 用户协议
 const handleUserAgreement = () => {
   uni.navigateTo({
-    url: '/pages-content/my/aggreement/detail?type=user'
+    url: '/pages/my/aggreement/detail?type=user'
   })
 }
 
 // 隐私协议
 const handlePrivacyPolicy = () => {
   uni.navigateTo({
-    url: '/pages-content/my/aggreement/detail?type=privacy'
+    url: '/pages/my/aggreement/detail?type=privacy'
   })
 }
 </script>

+ 15 - 10
pages-content/my/index.vue → pages/my/index.vue

@@ -40,27 +40,27 @@
         <view class="task-grid">
           <view class="task-item" @click="handleTaskClick('pending')">
             <view class="task-icon-wrapper">
-              <image class="task-icon" src="/static/pages-content/my/task-pending.png" mode="aspectFit" />
+              <image class="task-icon" src="/static/pages/my/task-pending.png" mode="aspectFit" />
               <view v-if="taskCounts.pending > 0" class="task-badge">{{ taskCounts.pending }}</view>
             </view>
             <text class="task-label">待传递</text>
           </view>
           <view class="task-item" @click="handleTaskClick('delivered')">
             <view class="task-icon-wrapper">
-              <image class="task-icon" src="/static/pages-content/my/task-delivered.png" mode="aspectFit" />
+              <image class="task-icon" src="/static/pages/my/task-delivered.png" mode="aspectFit" />
             </view>
             <text class="task-label">已传递</text>
           </view>
           <view class="task-item" @click="handleTaskClick('reviewing')">
             <view class="task-icon-wrapper">
-              <image class="task-icon" src="/static/pages-content/my/task-reviewing.png" mode="aspectFit" />
+              <image class="task-icon" src="/static/pages/my/task-reviewing.png" mode="aspectFit" />
               <view v-if="taskCounts.reviewing > 0" class="task-badge">{{ taskCounts.reviewing }}</view>
             </view>
             <text class="task-label">待审核</text>
           </view>
           <view class="task-item" @click="handleTaskClick('approved')">
             <view class="task-icon-wrapper">
-              <image class="task-icon" src="/static/pages-content/my/task-approved.png" mode="aspectFit" />
+              <image class="task-icon" src="/static/pages/my/task-approved.png" mode="aspectFit" />
             </view>
             <text class="task-label">已审核</text>
           </view>
@@ -71,7 +71,7 @@
       <view class="menu-list">
         <view class="menu-item" @click="handleProtocol">
           <view class="menu-left">
-            <image class="menu-icon" src="/static/pages-content/my/icon-protocol.png" mode="aspectFit" />
+            <image class="menu-icon" src="/static/pages/my/icon-protocol.png" mode="aspectFit" />
             <text class="menu-label">用户协议</text>
           </view>
           <text class="arrow">›</text>
@@ -79,7 +79,7 @@
         
         <view class="menu-item">
           <view class="menu-left">
-            <image class="menu-icon" src="/static/pages-content/my/icon-language.png" mode="aspectFit" />
+            <image class="menu-icon" src="/static/pages/my/icon-language.png" mode="aspectFit" />
             <text class="menu-label">语言切换</text>
           </view>
           <view class="language-switcher" @click="handleLanguageChange">
@@ -91,7 +91,7 @@
         
         <view class="menu-item" @click="handleAbout">
           <view class="menu-left">
-            <image class="menu-icon" src="/static/pages-content/my/icon-about.png" mode="aspectFit" />
+            <image class="menu-icon" src="/static/pages/my/icon-about.png" mode="aspectFit" />
             <text class="menu-label">关于我们</text>
           </view>
           <text class="arrow">›</text>
@@ -103,6 +103,9 @@
         <button class="logout-btn" @click="handleLogout">退出登录</button>
       </view>
     </view>
+    
+    <!-- 底部导航栏 -->
+    <TabBar current-tab="mine" />
   </view>
 </template>
 
@@ -113,6 +116,7 @@ import { useI18n } from 'vue-i18n'
 import { useUserStore } from '@/store/index'
 import { useLocaleStore } from '@/store/locale'
 import { getUserInfo as getUserInfoAPI, logout as logoutAPI } from '@/apis/auth'
+import TabBar from '@/components/TabBar/index.vue'
 
 const { t, locale } = useI18n()
 const userStore = useUserStore()
@@ -167,8 +171,8 @@ const displayPhone = computed(() => {
 
 onMounted(() => {
   // 获取系统信息
-  const systemInfo = uni.getSystemInfoSync()
-  statusBarHeight.value = systemInfo.statusBarHeight || 0
+  const windowInfo = uni.getWindowInfo()
+  statusBarHeight.value = windowInfo.statusBarHeight || 0
   
   // 获取用户信息
   fetchUserInfo()
@@ -231,7 +235,7 @@ const handleTaskClick = (type) => {
 // 协议说明
 const handleProtocol = () => {
   uni.navigateTo({
-    url: '/pages-content/my/aggreement/index'
+    url: '/pages/my/aggreement/index'
   })
 }
 
@@ -317,6 +321,7 @@ const handleLogout = () => {
   width: 100%;
   min-height: 100vh;
   background-color: #f5f5f5;
+  padding-bottom: calc(100rpx + env(safe-area-inset-bottom));
   
   // 顶部渐变背景
   .header-bg {

+ 2 - 2
pages-content/my/info/index.vue → pages/my/info/index.vue

@@ -119,8 +119,8 @@ const genderClass = computed(() => {
 
 onMounted(() => {
   // 获取系统信息
-  const systemInfo = uni.getSystemInfoSync()
-  statusBarHeight.value = systemInfo.statusBarHeight || 0
+  const windowInfo = uni.getWindowInfo()
+  statusBarHeight.value = windowInfo.statusBarHeight || 0
   
   // 获取字典数据
   fetchGenderDict()

+ 308 - 0
pages/scan/index.vue

@@ -0,0 +1,308 @@
+<template>
+  <view class="scan-page">
+    <!-- 顶部导航栏 -->
+    <view class="header-bg" :style="{ paddingTop: statusBarHeight + 'px' }">
+      <view class="header-content">
+        <view class="back-btn" @click="handleBack">
+          <text class="back-icon">‹</text>
+        </view>
+        <text class="header-title">小程序扫描</text>
+        <view class="placeholder"></view>
+      </view>
+    </view>
+    
+    <!-- 扫描区域 -->
+    <view class="scan-area">
+      <camera 
+        device-position="back" 
+        flash="off" 
+        class="camera"
+        @error="handleCameraError"
+      >
+        <!-- 扫描框 -->
+        <view class="scan-frame">
+          <view class="corner corner-tl"></view>
+          <view class="corner corner-tr"></view>
+          <view class="corner corner-bl"></view>
+          <view class="corner corner-br"></view>
+        </view>
+      </camera>
+      
+      <!-- 底部操作按钮 -->
+      <view class="action-buttons">
+        <view class="action-btn" @click="handleSelectImage">
+          <image class="btn-icon" src="/static/pages/scan/image.png" mode="aspectFit" />
+          <text class="btn-text">导入图片</text>
+        </view>
+        
+        <view class="capture-btn" @click="handleCapture">
+          <view class="capture-inner"></view>
+        </view>
+        
+        <view class="action-btn" @click="handleSelectFile">
+          <image class="btn-icon" src="/static/pages/scan/file.png" mode="aspectFit" />
+          <text class="btn-text">导入文档</text>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { ref, onMounted } from 'vue'
+import { useI18n } from 'vue-i18n'
+
+const { t } = useI18n()
+
+// 状态栏高度
+const statusBarHeight = ref(0)
+
+onMounted(() => {
+  // 获取系统信息 - 使用新API
+  const windowInfo = uni.getWindowInfo()
+  statusBarHeight.value = windowInfo.statusBarHeight || 0
+})
+
+// 返回上一页
+const handleBack = () => {
+  // 返回到home页面
+  uni.reLaunch({
+    url: '/pages/home/index'
+  })
+}
+
+// 相机错误处理
+const handleCameraError = (e) => {
+  console.error('相机错误:', e)
+  uni.showToast({
+    title: '相机启动失败',
+    icon: 'none'
+  })
+}
+
+// 拍照
+const handleCapture = () => {
+  const ctx = uni.createCameraContext()
+  ctx.takePhoto({
+    quality: 'high',
+    success: (res) => {
+      console.log('拍照成功:', res.tempImagePath)
+      uni.showToast({
+        title: '拍照成功',
+        icon: 'success'
+      })
+      // TODO: 处理拍照后的图片
+    },
+    fail: (err) => {
+      console.error('拍照失败:', err)
+      uni.showToast({
+        title: '拍照失败',
+        icon: 'none'
+      })
+    }
+  })
+}
+
+// 导入图片
+const handleSelectImage = () => {
+  uni.chooseImage({
+    count: 1,
+    sizeType: ['original', 'compressed'],
+    sourceType: ['album'],
+    success: (res) => {
+      console.log('选择图片成功:', res.tempFilePaths)
+      uni.showToast({
+        title: '图片导入成功',
+        icon: 'success'
+      })
+      // TODO: 处理选择的图片
+    },
+    fail: (err) => {
+      console.error('选择图片失败:', err)
+    }
+  })
+}
+
+// 导入文档
+const handleSelectFile = () => {
+  uni.chooseMessageFile({
+    count: 1,
+    type: 'file',
+    success: (res) => {
+      console.log('选择文件成功:', res.tempFiles)
+      uni.showToast({
+        title: '文档导入成功',
+        icon: 'success'
+      })
+      // TODO: 处理选择的文件
+    },
+    fail: (err) => {
+      console.error('选择文件失败:', err)
+    }
+  })
+}
+</script>
+
+<style lang="scss" scoped>
+.scan-page {
+  width: 100%;
+  height: 100vh;
+  display: flex;
+  flex-direction: column;
+  background-color: #000000;
+  
+  // 顶部导航栏
+  .header-bg {
+    background: linear-gradient(180deg, #1ec9c9 0%, #1eb8b8 100%);
+    position: relative;
+    z-index: 100;
+    
+    .header-content {
+      height: 88rpx;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      padding: 0 24rpx;
+      
+      .back-btn {
+        width: 60rpx;
+        height: 60rpx;
+        display: flex;
+        align-items: center;
+        justify-content: flex-start;
+        
+        .back-icon {
+          font-size: 56rpx;
+          color: #ffffff;
+          font-weight: 300;
+        }
+      }
+      
+      .header-title {
+        flex: 1;
+        text-align: center;
+        font-size: 32rpx;
+        font-weight: 600;
+        color: #ffffff;
+      }
+      
+      .placeholder {
+        width: 60rpx;
+      }
+    }
+  }
+  
+  // 扫描区域
+  .scan-area {
+    flex: 1;
+    position: relative;
+    display: flex;
+    flex-direction: column;
+    
+    .camera {
+      flex: 1;
+      width: 100%;
+      position: relative;
+      
+      // 扫描框
+      .scan-frame {
+        position: absolute;
+        top: 50%;
+        left: 50%;
+        transform: translate(-50%, -50%);
+        width: 500rpx;
+        height: 500rpx;
+        
+        .corner {
+          position: absolute;
+          width: 60rpx;
+          height: 60rpx;
+          border-color: #1ec9c9;
+          border-style: solid;
+          
+          &.corner-tl {
+            top: 0;
+            left: 0;
+            border-width: 6rpx 0 0 6rpx;
+            border-radius: 12rpx 0 0 0;
+          }
+          
+          &.corner-tr {
+            top: 0;
+            right: 0;
+            border-width: 6rpx 6rpx 0 0;
+            border-radius: 0 12rpx 0 0;
+          }
+          
+          &.corner-bl {
+            bottom: 0;
+            left: 0;
+            border-width: 0 0 6rpx 6rpx;
+            border-radius: 0 0 0 12rpx;
+          }
+          
+          &.corner-br {
+            bottom: 0;
+            right: 0;
+            border-width: 0 6rpx 6rpx 0;
+            border-radius: 0 0 12rpx 0;
+          }
+        }
+      }
+    }
+    
+    // 底部操作按钮
+    .action-buttons {
+      position: absolute;
+      bottom: 0;
+      left: 0;
+      right: 0;
+      background: #ffffff;
+      padding: 32rpx 40rpx;
+      padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      
+      .action-btn {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        gap: 12rpx;
+        
+        .btn-icon {
+          width: 48rpx;
+          height: 48rpx;
+        }
+        
+        .btn-text {
+          font-size: 24rpx;
+          color: #666666;
+        }
+      }
+      
+      .capture-btn {
+        width: 120rpx;
+        height: 120rpx;
+        border-radius: 50%;
+        background: #1ec9c9;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        box-shadow: 0 4rpx 16rpx rgba(30, 201, 201, 0.4);
+        
+        &:active {
+          transform: scale(0.95);
+        }
+        
+        .capture-inner {
+          width: 100rpx;
+          height: 100rpx;
+          border-radius: 50%;
+          background: #ffffff;
+        }
+      }
+    }
+  }
+}
+</style>

BIN
scan.png


+ 10 - 0
static/pages/home/banner1.png

@@ -0,0 +1,10 @@
+<svg width="702" height="280" viewBox="0 0 702 280" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <rect width="702" height="280" fill="url(#paint0_linear)"/>
+  <text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle" fill="white" font-size="48" font-weight="bold">轮播图1</text>
+  <defs>
+    <linearGradient id="paint0_linear" x1="0" y1="0" x2="702" y2="280" gradientUnits="userSpaceOnUse">
+      <stop stop-color="#A8E6CF"/>
+      <stop offset="1" stop-color="#7FD8BE"/>
+    </linearGradient>
+  </defs>
+</svg>

+ 10 - 0
static/pages/home/banner2.png

@@ -0,0 +1,10 @@
+<svg width="702" height="280" viewBox="0 0 702 280" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <rect width="702" height="280" fill="url(#paint0_linear)"/>
+  <text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle" fill="white" font-size="48" font-weight="bold">轮播图2</text>
+  <defs>
+    <linearGradient id="paint0_linear" x1="0" y1="0" x2="702" y2="280" gradientUnits="userSpaceOnUse">
+      <stop stop-color="#FFD3A5"/>
+      <stop offset="1" stop-color="#FD6585"/>
+    </linearGradient>
+  </defs>
+</svg>

+ 9 - 0
static/pages/home/doc-thumb.png

@@ -0,0 +1,9 @@
+<svg width="100" height="120" viewBox="0 0 100 120" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <rect width="100" height="120" rx="4" fill="#f0f0f0"/>
+  <rect x="15" y="20" width="70" height="4" rx="2" fill="#cccccc"/>
+  <rect x="15" y="35" width="70" height="4" rx="2" fill="#cccccc"/>
+  <rect x="15" y="50" width="50" height="4" rx="2" fill="#cccccc"/>
+  <rect x="15" y="65" width="60" height="4" rx="2" fill="#cccccc"/>
+  <rect x="15" y="80" width="70" height="4" rx="2" fill="#cccccc"/>
+  <rect x="15" y="95" width="40" height="4" rx="2" fill="#cccccc"/>
+</svg>

+ 5 - 0
static/pages/home/scan-icon.png

@@ -0,0 +1,5 @@
+<svg width="56" height="56" viewBox="0 0 56 56" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <rect x="8" y="8" width="40" height="40" rx="4" stroke="#ffffff" stroke-width="3" fill="none"/>
+  <path d="M8 28H48" stroke="#ffffff" stroke-width="2"/>
+  <circle cx="28" cy="28" r="8" fill="#ffffff"/>
+</svg>

+ 4 - 0
static/pages/home/search.png

@@ -0,0 +1,4 @@
+<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <circle cx="14" cy="14" r="9" stroke="#999999" stroke-width="2" fill="none"/>
+  <line x1="20.5" y1="20.5" x2="27" y2="27" stroke="#999999" stroke-width="2" stroke-linecap="round"/>
+</svg>

+ 0 - 0
static/pages-content/my/aggrement.png → static/pages/my/aggrement.png


+ 0 - 0
static/pages-content/my/agreement/privacy.png → static/pages/my/agreement/privacy.png


+ 0 - 0
static/pages-content/my/agreement/user.png → static/pages/my/agreement/user.png


+ 0 - 0
static/pages-content/my/audit.png → static/pages/my/audit.png


+ 0 - 0
static/pages-content/my/file.png → static/pages/my/file.png


+ 0 - 0
static/pages-content/my/icon-about.png → static/pages/my/icon-about.png


+ 0 - 0
static/pages-content/my/icon-language.png → static/pages/my/icon-language.png


+ 0 - 0
static/pages-content/my/icon-protocol.png → static/pages/my/icon-protocol.png


+ 0 - 0
static/pages-content/my/info.png → static/pages/my/info.png


+ 0 - 0
static/pages-content/my/language.png → static/pages/my/language.png


+ 0 - 0
static/pages-content/my/task-approved.png → static/pages/my/task-approved.png


+ 0 - 0
static/pages-content/my/task-delivered.png → static/pages/my/task-delivered.png


+ 0 - 0
static/pages-content/my/task-pending.png → static/pages/my/task-pending.png


+ 0 - 0
static/pages-content/my/task-reviewing.png → static/pages/my/task-reviewing.png


+ 7 - 0
static/pages/scan/file.png

@@ -0,0 +1,7 @@
+<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <path d="M10 6C8.89543 6 8 6.89543 8 8V40C8 41.1046 8.89543 42 10 42H38C39.1046 42 40 41.1046 40 40V16L28 6H10Z" stroke="#666666" stroke-width="2" fill="none"/>
+  <path d="M28 6V16H40" stroke="#666666" stroke-width="2" fill="none"/>
+  <line x1="16" y1="24" x2="32" y2="24" stroke="#666666" stroke-width="2"/>
+  <line x1="16" y1="30" x2="32" y2="30" stroke="#666666" stroke-width="2"/>
+  <line x1="16" y1="36" x2="26" y2="36" stroke="#666666" stroke-width="2"/>
+</svg>

+ 5 - 0
static/pages/scan/image.png

@@ -0,0 +1,5 @@
+<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <rect x="6" y="6" width="36" height="36" rx="4" stroke="#666666" stroke-width="2" fill="none"/>
+  <circle cx="16" cy="16" r="4" fill="#666666"/>
+  <path d="M6 32L16 22L24 30L32 22L42 32V38C42 40.2091 40.2091 42 38 42H10C7.79086 42 6 40.2091 6 38V32Z" fill="#666666"/>
+</svg>