From f4ed2c4a1412f7256614e04e18683ca15a89bb25 Mon Sep 17 00:00:00 2001
From: 祖安之光 <11848914+light-of-zuan@user.noreply.gitee.com>
Date: Wed, 05 Nov 2025 08:58:21 +0800
Subject: [PATCH] 新增

---
 api/review.js                        |   16 
 pages/tabBar/firstPage/firstPage.vue | 1068 +++++++++++++++-------------
 pages/review/signPage.vue            |  388 ++++++++++
 pages.json                           |  102 +-
 common/constant.js                   |    4 
 pages/review/index.vue               |  305 ++++++++
 pages/tabBar/count/count.vue         |   14 
 static/educate.png                   |    0 
 static/review.png                    |    0 
 pages/menuPage/index.vue             |  172 ++++
 pages/tabBar/count/countDetail.vue   |    2 
 pages/index/index.vue                |   18 
 pages/tabBar/current/detail.vue      |   95 ++
 13 files changed, 1,613 insertions(+), 571 deletions(-)

diff --git a/api/review.js b/api/review.js
new file mode 100644
index 0000000..1ec4510
--- /dev/null
+++ b/api/review.js
@@ -0,0 +1,16 @@
+import {service} from '../common/request.js';
+ 
+export function getProjectList(id) {
+  return service({
+		url: '/app/item/review/approvalList?userId=' + id ,
+		method: 'GET'
+	})
+}
+
+export function postSignaure(data) {
+  return service({
+		url: '/app/item/review/approval',
+		method: 'POST',
+		data
+	})
+}
\ No newline at end of file
diff --git a/common/constant.js b/common/constant.js
index 94fdf35..0a686af 100644
--- a/common/constant.js
+++ b/common/constant.js
@@ -2,8 +2,8 @@
 let VUE_APP_BASE_URL= null;
 if (process.env.NODE_ENV == 'development') {
 	// VUE_APP_BASE_URL = 'http://106.15.95.149:8056/api'
-	// VUE_APP_BASE_URL = 'http://192.168.2.30:8056/api'
-	VUE_APP_BASE_URL = 'https://reagent.sinanoaq.cn/exam'
+	VUE_APP_BASE_URL = 'http://192.168.2.28:8056/api'
+	// VUE_APP_BASE_URL = 'https://reagent.sinanoaq.cn/exam'
 }else {
 	// VUE_APP_BASE_URL = 'http://192.168.2.15:8082'
 	// 正式环境
diff --git a/pages.json b/pages.json
index 53eaeba..e3f87a2 100644
--- a/pages.json
+++ b/pages.json
@@ -7,16 +7,37 @@
 			}
 		},
 		{
-		    "path" : "pages/tabBar/firstPage/firstPage",
-			"style" :
-			{
-			    "navigationBarTitleText": "首页"
+			"path": "pages/menuPage/index",
+			"style": {
+				"navigationBarTitleText": "主页面",
+				"navigationStyle": "custom"
 			}
 		},
 		{
-			"path" : "pages/tabBar/firstPage/exam",
-			"style" :
-			{
+			"path": "pages/review/index",
+			"style": {
+				"navigationBarTitleText": "项目审批",
+				"enablePullDownRefresh": false,
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path": "pages/review/signPage",
+			"style": {
+				"navigationBarTitleText": "电子签名"
+			}
+		},
+		{
+			"path": "pages/tabBar/firstPage/firstPage",
+			"style": {
+				"navigationBarTitleText": "首页",
+				"navigationStyle": "custom",
+				"enablePullDownRefresh": false
+			}
+		},
+		{
+			"path": "pages/tabBar/firstPage/exam",
+			"style": {
 				"navigationBarTitleText": "题目内容",
 				"enablePullDownRefresh": false,
 				"app-plus": {
@@ -25,20 +46,18 @@
 			}
 		},
 		{
-		    "path" : "pages/tabBar/count/count",
-		    "style" :                                                                                    
-		    {
-		        "navigationBarTitleText": "我的",
-		        "enablePullDownRefresh": false,
+			"path": "pages/tabBar/count/count",
+			"style": {
+				"navigationBarTitleText": "我的",
+				"enablePullDownRefresh": false,
 				"app-plus": {
 					"scrollIndicator": "none"
 				}
-		    }
+			}
 		},
 		{
-			"path" : "pages/tabBar/count/countDetail",
-			"style" :
-			{
+			"path": "pages/tabBar/count/countDetail",
+			"style": {
 				"navigationBarTitleText": "我的成绩",
 				"enablePullDownRefresh": false,
 				"app-plus": {
@@ -47,9 +66,8 @@
 			}
 		},
 		{
-		    "path" : "pages/tabBar/current/current",
-			"style" :
-			{
+			"path": "pages/tabBar/current/current",
+			"style": {
 				"navigationBarTitleText": "课程",
 				"enablePullDownRefresh": false,
 				"app-plus": {
@@ -58,9 +76,8 @@
 			}
 		},
 		{
-			"path" : "pages/tabBar/current/detail",
-			"style" :
-			{
+			"path": "pages/tabBar/current/detail",
+			"style": {
 				"navigationBarTitleText": "课程详情",
 				"enablePullDownRefresh": false,
 				"app-plus": {
@@ -69,20 +86,18 @@
 			}
 		},
 		{
-		    "path" : "pages/tabBar/wearhouse/wearhouse",
-		    "style" :                                                                                    
-		    {
-			    "navigationBarTitleText": "刷题",
-			    "enablePullDownRefresh": false,
+			"path": "pages/tabBar/wearhouse/wearhouse",
+			"style": {
+				"navigationBarTitleText": "刷题",
+				"enablePullDownRefresh": false,
 				"app-plus": {
 					"scrollIndicator": "none"
 				}
-		    }
+			}
 		},
 		{
-			"path" : "pages/tabBar/wearhouse/questions",
-			"style" :
-			{
+			"path": "pages/tabBar/wearhouse/questions",
+			"style": {
 				"navigationBarTitleText": "题目内容",
 				"enablePullDownRefresh": false,
 				"app-plus": {
@@ -97,16 +112,16 @@
 		"borderStyle": "black",
 		"backgroundColor": "#ffffff",
 		"list": [{
-			"pagePath": "pages/tabBar/firstPage/firstPage",
-			"iconPath": "static/home.png",
-			"selectedIconPath": "static/home_sel.png",
-			"text": "首页"
-		},{
-			"pagePath": "pages/tabBar/current/current",
-			"iconPath": "/static/notice.png",
-			"selectedIconPath": "/static/notice-sel.png",
-			"text": "课程"
-		},{
+				"pagePath": "pages/tabBar/firstPage/firstPage",
+				"iconPath": "static/home.png",
+				"selectedIconPath": "static/home_sel.png",
+				"text": "首页"
+			}, {
+				"pagePath": "pages/tabBar/current/current",
+				"iconPath": "/static/notice.png",
+				"selectedIconPath": "/static/notice-sel.png",
+				"text": "课程"
+			}, {
 				"pagePath": "pages/tabBar/wearhouse/wearhouse",
 				"iconPath": "/static/wearhouse.png",
 				"selectedIconPath": "/static/wearhouse_sel.png",
@@ -117,7 +132,8 @@
 				"iconPath": "/static/my.png",
 				"selectedIconPath": "/static/my_sel.png",
 				"text": "我的"
-			}]
+			}
+		]
 	},
 	"globalStyle": {
 		"navigationBarTextStyle": "black",
@@ -126,4 +142,4 @@
 		"backgroundColor": "#f5f7fa"
 	},
 	"uniIdRouter": {}
-}
+}
\ No newline at end of file
diff --git a/pages/index/index.vue b/pages/index/index.vue
index a3117b9..fef7e9a 100644
--- a/pages/index/index.vue
+++ b/pages/index/index.vue
@@ -4,7 +4,7 @@
     <view class="main">
       <view class="header">
         <view class="titleFirst">
-          你好~<br/>欢迎来到安全教育平台</view>
+          你好~<br/>欢迎来到体系合规化平台</view>
       </view>
       <!-- <view class="form-area"> -->
         <u--form :model="form" ref="uForm" class="form" >
@@ -129,22 +129,18 @@
 				login(data).then(res => {
 					if (res.code === 200) {
 						t.isLogining = false;
-						 //登录成功后
-						 //设置别名
-						// jpushModule.setAlias({
-						// 	'alias': this.phone,
-						// 	'sequence': 1
-						// })
+
 						uni.setStorageSync("name", t.form.username);
 						uni.setStorageSync("pwd", t.form.password);
 						uni.setStorageSync("tk", res.data.token);
 						uni.setStorageSync("uid",res.data.id);
 						uni.setStorageSync('user', res.data);
-						// t.$store.commit('setRoleId', 'user_leader');
-						uni.switchTab({
-							url: '/pages/tabBar/firstPage/firstPage'
+						// uni.switchTab({
+						// 	url: '/pages/tabBar/firstPage/firstPage'
+						// })
+						uni.navigateTo({
+						  url: '/pages/menuPage/index'
 						})
-		// 				}
 					}else{
 						uni.showToast({
 							icon: "none",
diff --git a/pages/menuPage/index.vue b/pages/menuPage/index.vue
new file mode 100644
index 0000000..adc68c4
--- /dev/null
+++ b/pages/menuPage/index.vue
@@ -0,0 +1,172 @@
+<template>
+	<view>
+		<!-- 自定义导航栏 -->
+		<view class="custom-navbar">
+			<view class="navbar-content">
+				<text class="navbar-title">主页面</text>
+			</view>
+		</view>
+		<view class="page-content" :style="{ paddingTop: navbarHeight + 'px' }">
+			<view class="navBtn" @click="toReview()">
+			  <u-image radius="16px" width="140rpx" height="140rpx" :show-loading="true" :src="reviewIcon" mode="aspectFill">
+			  </u-image>
+			  <view class="cardTit">
+			    项目审批
+			  </view>
+			</view>
+			<view class="navBtn" @click="toEducate()">
+			  <u-image radius="16px" width="140rpx" height="140rpx" :show-loading="true" :src="educateIcon" mode="aspectFill">
+			  </u-image>
+			  <view class="cardTit">
+			    安全教育
+			  </view>
+			</view>
+			<view class="loginBtn">
+			  <u-button @click="loginOut" type="primary" text="退出登录" shape="circle"></u-button>
+			</view>
+		</view>
+
+	</view>
+</template>
+
+<script>
+	import VUE_APP_BASE_URL from 'common/constant.js'
+	import {loginOut} from "../../api"
+	import reviewIcon from '../../static/review.png'
+	import educateIcon from '../../static/educate.png'
+	export default {
+		components: {},
+		data() {
+			return {
+				navbarHeight: 0,
+				reviewIcon: reviewIcon,
+				educateIcon: educateIcon
+			}
+
+		},
+		onLoad() {
+			this.getNavbarHeight()
+		},
+		onShow() {
+
+		},
+		created() {
+
+		},
+		mounted() {
+
+		},
+		methods: {
+			getNavbarHeight() {
+				const systemInfo = uni.getSystemInfoSync()
+				const statusBarHeight = systemInfo.statusBarHeight
+				const navbarHeight = 44
+				this.navbarHeight = statusBarHeight + navbarHeight
+			},
+			toReview() {
+				uni.navigateTo({
+					url: '/pages/review/index'
+				})
+			},
+
+			toEducate() {
+				uni.switchTab({
+					url: '/pages/tabBar/firstPage/firstPage'
+				})
+			},
+			loginOut(){
+			  uni.showModal({
+			    title: '提示',
+			    content: '是否确认退出该账号?',
+			    success: async function (res) {
+			      if (res.confirm) {
+			        loginOut().then(res=>{
+			          if(res.code == 200){
+			            uni.showToast({
+			              title: '账户已退出',
+			              duration: 800
+			            })
+			            setTimeout(()=>{
+			              uni.clearStorageSync();
+			              uni.clearStorage();
+			              uni.navigateTo({
+			                url: '/pages/index/index'
+			              })
+			            },800)
+			          }
+			        })
+			      } else if (res.cancel) {
+			        console.log('用户点击取消');
+			      }
+			    }
+			  })
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.custom-navbar {
+		position: fixed;
+		top: 0;
+		left: 0;
+		right: 0;
+		z-index: 999;
+		background: #ffffff;
+
+		.navbar-content {
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			height: 44px;
+			padding-top: var(--status-bar-height);
+		}
+
+		.navbar-title {
+			font-size: 16px;
+			font-weight: bold;
+			color: #333;
+		}
+		
+	}
+	.page-content {
+	  min-height: 100vh;
+	  box-sizing: border-box;
+	  display: flex;
+	  flex-direction: column;
+	  align-items: center;
+	  padding: 0 15px;
+	  .navBtn{
+		  width: 100%;
+		  padding: 15px 30px;
+		  box-sizing: border-box;
+		  margin-top: 15px;
+		  background: #fff;
+		  border-radius: 20rpx;
+		  display: flex;
+		  align-items: center;
+		  box-shadow: 0 10rpx 20rpx rgba(0,0,0,.05);
+		  transition: box-shadow .15s ease !important;
+		  
+		  &:active{
+		    box-shadow: none;
+		  }
+		  
+		  .cardTit{
+		    font-size: 36rpx;
+		    font-weight: bold;
+		    margin-left: 30px;
+		  }
+		  
+	  }
+	  .loginBtn{
+	    width: 100%;
+	    position: fixed;
+	    bottom: 90px;
+	    
+	    ::v-deep .u-button{
+	  	  width: 80%;
+	    }
+	  }
+	}
+</style>
\ No newline at end of file
diff --git a/pages/review/index.vue b/pages/review/index.vue
new file mode 100644
index 0000000..ce9f1a7
--- /dev/null
+++ b/pages/review/index.vue
@@ -0,0 +1,305 @@
+<template>
+	<view>
+		<view class="custom-navbar">
+			<view class="navbar-content">
+				<view class="nav-left" @click="handleBack">
+					<view class="back-btn">
+						<text class="back-text">返回</text>
+					</view>
+				</view>
+				<text class="navbar-title">项目审批</text>
+				<view class="nav-right"></view>
+			</view>
+		</view>
+		<view class="page-content" :style="{ paddingTop: navbarHeight + 'px'}">
+			<view class="card-t">
+				<span class="card-t-l">项目审批</span>
+				<div>
+					<u-tabs :list="examSelect" :current="currentTab" @click="changeState"></u-tabs>
+				</div>
+			</view>
+			<view>
+				<view class="cardList" v-if="projectList && projectList.length>0">
+					<scroll-view scroll-y="true" class="scroll-Y" @scrolltoupper="upper" @scrolltolower="lower"
+						lower-threshold="150" @scroll="scrollView" style="height:100%">
+						<view style="padding: 0 0 20px">
+							<view class="card-i" v-for="(item,index) in projectList" :key="index">
+								<view class="card-line">
+									<view class="card-tit">项目名称</view>
+									<view class="card-cont">{{item.fileName}}</view>
+								</view>
+								<view class="card-line">
+									<view class="card-tit">项目阶段</view>
+									<view class="card-cont">{{item.stage}}</view>
+								</view>
+								<view class="card-line">
+									<u-button text="项目文档" type="primary" @click="viewProject(item)"></u-button>
+									<u-button text="电子签名" type="primary" @click="toSign(item)"></u-button>
+								</view>
+							</view>
+						</view>
+					</scroll-view>
+				</view>
+				<u-empty v-else text="暂无记录" mode="data"></u-empty>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		getProjectList
+	} from '../../api/review.js'
+	import VUE_APP_BASE_URL from "../../common/constant";
+	export default {
+		components: {},
+		data() {
+			return {
+				navbarHeight: 0,
+				currentTab: 0,
+				examSelect: [{
+					name: "待审批"
+				}],
+				projectList: []
+			}
+
+		},
+		onLoad() {
+			//获取手机状态栏高度
+			this.getNavbarHeight()
+			this.getList()
+		},
+		onShow() {
+
+		},
+		created() {},
+		methods: {
+			getNavbarHeight() {
+				const systemInfo = uni.getSystemInfoSync()
+				const statusBarHeight = systemInfo.statusBarHeight
+				const navbarHeight = 44
+				this.navbarHeight = statusBarHeight + navbarHeight
+			},
+
+			handleBack() {
+				uni.navigateTo({
+					url: '/pages/menuPage/index'
+				})
+			},
+			changeState(e) {
+				this.currentTab = e.index
+			},
+			viewProject(item) {
+				wx.showLoading({
+					title: '文件获取中...',
+					mask: true
+				})
+				wx.downloadFile({
+					url: VUE_APP_BASE_URL + '/' + item.filePath,
+					success: function(res) {
+						if (res.statusCode !== 200 || !res.tempFilePath) {
+							wx.hideLoading()
+							uni.showToast({
+								icon: 'none',
+								title: '文件下载失败',
+								duration: 2000
+							})
+							return
+						}
+						var filePath = res.tempFilePath
+						wx.openDocument({
+							filePath: filePath,
+							showMenu: true,
+							success: function(res) {
+								wx.hideLoading()
+							},
+							fail: function(res) {
+								uni.showToast({
+									icon: 'none',
+									duration: 2000,
+									position: 'top',
+									title: `打开文件失败: ${res.errMsg || '未知错误'}`
+								});
+								wx.hideLoading()
+							}
+						})
+					},
+					fail: function(res) {
+						uni.showToast({
+							icon: 'none',
+							duration: 2000,
+							position: 'top',
+							title: `下载失败: ${res.errMsg || '网络错误'}`
+						});
+						wx.hideLoading()
+					}
+				})
+			},
+			toSign(item) {
+				uni.navigateTo({
+					url: `/pages/review/signPage?id=` + encodeURIComponent(JSON.stringify(item.id))
+				})
+			},
+			async getList() {
+				const res = await getProjectList(uni.getStorageSync('uid'))
+				if (res.code == 200) {
+					this.projectList = res.data || []
+				} else {
+					uni.$u.toast(res.message)
+				}
+			},
+			upper(e) {
+				// console.log(e)
+			},
+			lower(e) {
+				//并且让页码+1,调用获取数据的方法获取第二页数据
+				this.classParams.pageNum++
+				if (this.classParams.pageNum > this.totalPage) {
+					uni.$u.toast('已加载全部数据')
+					return
+				}
+				//此处调用自己获取数据列表的方法
+				this.getClass()
+			},
+			scrollView(e) {
+				// console.log(e)
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.custom-navbar {
+		position: fixed;
+		top: 0;
+		left: 0;
+		right: 0;
+		z-index: 999;
+		background: #ffffff;
+
+		.navbar-content {
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			height: 44px;
+			padding-top: var(--status-bar-height);
+		}
+
+		.nav-left {
+			flex-shrink: 0;
+			width: 80px;
+			padding-left: 15px;
+			box-sizing: border-box;
+		}
+
+		.back-btn {
+			display: flex;
+			align-items: center;
+			padding: 8px 12px 8px 0;
+		}
+
+		.back-text {
+			font-size: 16px;
+			color: #333;
+		}
+
+		.navbar-title {
+			flex: 1;
+			font-size: 16px;
+			text-align: center;
+			font-weight: bold;
+			color: #333;
+		}
+
+		.nav-right {
+			flex-shrink: 0;
+			width: 80px;
+		}
+
+
+	}
+
+	.page-content {
+		min-height: calc(100vh - 44px);
+		box-sizing: border-box;
+		padding: 0 15px;
+
+		.card-t {
+			width: 100%;
+			padding: 0 6rpx;
+			box-sizing: border-box;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			margin-bottom: 20rpx;
+
+			.card-t-l {
+				font-size: 36rpx;
+				font-weight: bold;
+			}
+
+			.card-t-r {
+				color: #999;
+				cursor: pointer;
+				font-size: 28rpx;
+			}
+
+			.uni-stat__select {
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				padding: 2rpx 20rpx;
+				border: 1rpx solid #ccc;
+				border-radius: 99rpx;
+				background: #fff;
+				cursor: pointer;
+
+
+				text {
+					color: #999;
+					font-size: 28rpx;
+					margin-right: 6rpx;
+				}
+			}
+		}
+
+		.cardList {
+			width: 100%;
+			height: calc(100vh - 130px);
+			box-sizing: border-box;
+
+			.card-i {
+				width: 100%;
+				background: #fff;
+				border-radius: 20rpx;
+				padding: 15px;
+				margin-bottom: 15px;
+				box-sizing: border-box;
+				box-shadow: 4px 4px 12px rgba(150, 150, 150, .05);
+
+				.card-line {
+					margin-bottom: 15px;
+					display: flex;
+					align-items: flex-start;
+
+					&:last-of-type {
+						margin-bottom: 0;
+					}
+
+					.card-tit {
+						flex-shrink: 0;
+						width: 140rpx;
+					}
+
+					.u-button {
+						margin-right: 30px;
+
+						&:last-of-type {
+							margin-right: 0;
+						}
+					}
+				}
+			}
+		}
+	}
+</style>
\ No newline at end of file
diff --git a/pages/review/signPage.vue b/pages/review/signPage.vue
new file mode 100644
index 0000000..2d2179e
--- /dev/null
+++ b/pages/review/signPage.vue
@@ -0,0 +1,388 @@
+<template>
+	<view class="signature-container">
+		<view class="canvas-container">
+			<canvas canvas-id="signatureCanvas" id="signatureCanvas" class="signature-canvas"
+				@touchstart="handleTouchStart" @touchmove="handleTouchMove" @touchend="handleTouchEnd"
+				disable-scroll></canvas>
+			<view class="toast" v-if="toastVisible">请签写您的名字</view>
+		</view>
+		<view class="controls">
+			<view></view>
+			<view class="btn-group">
+				<button class="btn btn-clear" @tap="clearCanvas" :disabled="uploading">清空</button>
+				<button class="btn btn-confirm" @tap="saveSignature" :disabled="uploading || !hasDrawn">
+					{{ uploading ? '上传中...' : '确定' }}
+				</button>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import VUE_APP_BASE_URL from "../../common/constant";
+	import {
+		postSignaure
+	} from "../../api/review.js"
+	export default {
+		name: 'SignaturePad',
+		data() {
+			return {
+				canvas: null,
+				ctx: null,
+				isDrawing: false,
+				hasDrawn: false,
+				lastX: 0,
+				lastY: 0,
+				toastVisible: true,
+				systemInfo: null,
+				uploading: false,
+				id: null
+			}
+		},
+		onReady() {
+			this.initCanvas();
+		},
+		onLoad(e) {
+			this.getSystemInfo();
+			this.id = e.id && JSON.parse(decodeURIComponent(e.id))
+		},
+		onUnload() {
+			this.cleanup();
+		},
+		methods: {
+			getSystemInfo() {
+				const that = this;
+				wx.getSystemInfo({
+					success(res) {
+						that.systemInfo = res;
+						that.initCanvas();
+					}
+				});
+			},
+
+			initCanvas() {
+				if (!this.systemInfo) return;
+				this.ctx = wx.createCanvasContext('signatureCanvas', this);
+				this.ctx.setLineCap('round');
+				this.ctx.setLineJoin('round');
+				this.ctx.setStrokeStyle('#1A1A1A');
+				this.ctx.setLineWidth(2);
+				this.ctx.setFillStyle('#1A1A1A');
+				this.clearCanvas();
+			},
+
+			handleTouchStart(e) {
+				if (!this.ctx) return;
+
+				const touch = e.touches[0];
+				this.isDrawing = true;
+				[this.lastX, this.lastY] = [touch.x, touch.y];
+				this.drawDot(this.lastX, this.lastY);
+				this.hideToast();
+				this.hasDrawn = true;
+			},
+
+			handleTouchMove(e) {
+				if (!this.isDrawing || !this.ctx) return;
+
+				const touch = e.touches[0];
+				const x = touch.x;
+				const y = touch.y;
+
+				// 绘制线条
+				this.ctx.beginPath();
+				this.ctx.moveTo(this.lastX, this.lastY);
+				this.ctx.lineTo(x, y);
+				this.ctx.stroke();
+				this.ctx.draw(true);
+
+				this.drawDot(x, y);
+
+				[this.lastX, this.lastY] = [x, y];
+			},
+
+			handleTouchEnd() {
+				this.isDrawing = false;
+			},
+
+			drawDot(x, y) {
+				if (!this.ctx) return;
+
+				this.ctx.beginPath();
+				this.ctx.arc(x, y, 1, 0, 2 * Math.PI);
+				this.ctx.fill();
+				this.ctx.draw(true);
+			},
+
+			clearCanvas() {
+				if (!this.ctx) return;
+
+
+				this.ctx.clearRect(0, 0, 1000, 1000);
+				this.ctx.setFillStyle('#F5F7FB');
+				this.ctx.fillRect(0, 0, 1000, 1000);
+				this.ctx.draw(true);
+
+				this.hasDrawn = false;
+				this.showToast();
+			},
+
+			showToast() {
+				this.toastVisible = true;
+			},
+
+			hideToast() {
+				this.toastVisible = false;
+			},
+
+			async saveSignature() {
+				if (!this.hasDrawn) {
+					wx.showToast({
+						title: '您还未签名!',
+						icon: 'none',
+						duration: 2000
+					});
+					return;
+				}
+				if (this.uploading) return;
+				this.uploading = true;
+				try {
+					const tempFilePath = await this.canvasToTempFile();
+					const uploadResult = await this.uploadToServer(tempFilePath);
+					await this.handleUploadSuccess(uploadResult);
+
+				} catch (error) {
+					this.handleUploadError(error);
+				} finally {
+					this.uploading = false;
+				}
+			},
+
+			canvasToTempFile() {
+				return new Promise((resolve, reject) => {
+					wx.canvasToTempFilePath({
+						canvasId: 'signatureCanvas',
+						quality: 1,
+						fileType: 'png',
+						success: (res) => {
+							resolve(res.tempFilePath);
+						},
+						fail: (err) => {
+							reject(new Error('生成图片失败:' + JSON.stringify(err)));
+						}
+					}, this);
+				});
+			},
+
+			uploadToServer(tempFilePath) {
+				return new Promise((resolve, reject) => {
+					wx.uploadFile({
+						url: `${VUE_APP_BASE_URL}/system/common/uploadFile`, // 替换为你的上传接口
+						filePath: tempFilePath,
+						name: 'file',
+						formData: {},
+						header: {
+							'Authorization': uni.getStorageSync('tk'), // 如果有token认证
+							'Content-Type': 'multipart/form-data'
+						},
+						success: (res) => {
+							if (res.statusCode === 200) {
+								try {
+									const data = JSON.parse(res.data);
+									resolve(data);
+								} catch (e) {
+									reject(new Error('解析响应数据失败'));
+								}
+							} else {
+								reject(new Error(`上传失败,状态码:${res.statusCode}`));
+							}
+						},
+						fail: (err) => {
+							reject(new Error('网络请求失败:' + JSON.stringify(err)));
+						}
+					});
+				});
+			},
+
+			async handleUploadSuccess(res) {
+				try {
+					if (!res.data || !res.data.path) {
+						throw new Error('未获取到文件路径');
+					}
+					const filePath = res.data.path;
+					const submitResult = await this.submitSignatureInfo(filePath);
+					this.handleFinalSuccess(submitResult);
+				} catch (error) {
+					throw new Error('提交签名信息失败:' + error.message);
+				}
+			},
+
+			async submitSignatureInfo(path) {
+				const res = await postSignaure({
+					id: this.id,
+					sign: path
+				})
+				if (res.code == 200) {
+					return res
+				} else {
+					reject(new Error(`提交失败,状态码:${res.code}`));
+				}
+			},
+
+			handleFinalSuccess(result) {
+				wx.showToast({
+					title: '签名提交成功',
+					icon: 'success',
+					duration: 2000
+				});
+				setTimeout(() => {
+					// const pages = getCurrentPages();
+					// if (pages.length > 1) {
+					// 	const prevPage = pages[pages.length - 2];
+					// 	if (prevPage) {
+					// 		prevPage.needRefresh = true;
+					// 	}
+					// 	wx.navigateBack({
+					// 		delta: 1,
+					// 		success: () => {
+					// 			console.log('返回成功,页面应该刷新');
+					// 		}
+					// 	});
+					// } else {
+						wx.reLaunch({
+							url: '/pages/review/index'
+						});
+					// }
+				}, 1500);
+			},
+
+			handleUploadError(error) {
+				console.error('上传失败:', error);
+
+				wx.showToast({
+					title: '上传失败,请重试',
+					icon: 'none',
+					duration: 2000
+				});
+			},
+
+			cleanup() {
+				this.ctx = null;
+				this.isDrawing = false;
+			}
+		}
+	}
+</script>
+
+<style scoped>
+	.signature-container {
+		width: 100vw;
+		height: 100vh;
+		display: flex;
+		flex-direction: column;
+		background: #ffffff;
+	}
+
+	.canvas-container {
+		flex: 1;
+		position: relative;
+		background: #F5F7FB;
+		border: 1px solid rgba(0, 0, 0, 0.08);
+		border-radius: 4px;
+		margin: 10px;
+		overflow: hidden;
+	}
+
+	.signature-canvas {
+		width: 100%;
+		height: 100%;
+		background: #F5F7FB;
+	}
+
+	.toast {
+		position: absolute;
+		top: 50%;
+		left: 40%;
+		transform: translate(-50%, -50%);
+		transform: rotate(90deg);
+		font-size: 40rpx;
+		color: rgba(58, 65, 85, 0.4);
+		pointer-events: none;
+		z-index: 100;
+	}
+
+	.controls {
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		padding: 15px 32px;
+		background: #ffffff;
+		border-top: 1px solid #e5e7eb;
+	}
+
+	.btn {
+		padding: 8px 20px;
+		border: none;
+		border-radius: 4px;
+		font-size: 14px;
+		cursor: pointer;
+		transition: all 0.3s ease;
+	}
+
+	.btn-clear {
+		background: rgba(103, 149, 255, 0.2);
+		color: #3670F5;
+		margin-right: 12px;
+	}
+
+	.btn-clear:hover {
+		background: rgba(103, 149, 255, 0.3);
+	}
+
+	.btn-confirm {
+		background: #3670F5;
+		color: #FFFFFF;
+	}
+
+	.btn-confirm:hover {
+		background: #2563eb;
+	}
+
+	.btn-group {
+		display: flex;
+		gap: 10px;
+	}
+
+	/* 微信小程序适配样式 */
+	button {
+		margin: 0;
+		padding: 8px 20px;
+		border-radius: 4px;
+		font-size: 14px;
+	}
+
+	button::after {
+		border: none;
+	}
+
+	/* 横竖屏适配 */
+	@media (orientation: landscape) {
+		.signature-container {
+			flex-direction: column;
+		}
+
+		.canvas-container {
+			height: calc(100vh - 80px);
+		}
+	}
+
+	@media (orientation: portrait) {
+		.signature-container {
+			flex-direction: column;
+		}
+
+		.canvas-container {
+			height: calc(100vh - 120px);
+		}
+	}
+</style>
\ No newline at end of file
diff --git a/pages/tabBar/count/count.vue b/pages/tabBar/count/count.vue
index 8f78d50..402566f 100644
--- a/pages/tabBar/count/count.vue
+++ b/pages/tabBar/count/count.vue
@@ -63,7 +63,11 @@
 			return {
 				page: 'pages/tabBar/count/count',
 				statusBarHeight: '',
-        user: {},
+        user: {
+			name: '',
+			phone: '',
+			company: {},
+		},
         examParams: {
           pageNum: 1,
           pageSize: 10,
@@ -75,11 +79,13 @@
 			
 		},
     created(){
-
+		this.getUserDetail()
     },
+		onShow(){
+			this.getUserDetail()
+		},
 		onLoad() {
 			this.statusBarHeight = uni.getSystemInfoSync()['statusBarHeight'];
-      this.getUserInfo()
 		},
 
 		methods: {
@@ -89,7 +95,7 @@
 				});
 			},
 
-      getUserInfo(){
+      getUserDetail(){
         getUserInfo(uni.getStorageSync('uid')).then(res => {
           if(res.code == 200) {
             this.user = res.data
diff --git a/pages/tabBar/count/countDetail.vue b/pages/tabBar/count/countDetail.vue
index ef8c402..c61c3cd 100644
--- a/pages/tabBar/count/countDetail.vue
+++ b/pages/tabBar/count/countDetail.vue
@@ -21,7 +21,7 @@
 					丨
                   <view>{{item.passed == 0?'不合格':'合格'}}</view>
                 </view>
-				<u-button @tap.stop="reExam(item)" class="re-exam-button" plain type="warning" text="重新考试" shape="circle" size="small"></u-button>
+				<u-button @tap.native.stop="reExam(item)" class="re-exam-button" plain type="warning" text="重新考试" shape="circle" size="small"></u-button>
               </view>
             </view>
           </scroll-view>
diff --git a/pages/tabBar/current/detail.vue b/pages/tabBar/current/detail.vue
index b8807b1..ec9d330 100644
--- a/pages/tabBar/current/detail.vue
+++ b/pages/tabBar/current/detail.vue
@@ -237,22 +237,58 @@
             this.detail = res.data
             this.showDetail = true
             if(this.detail.resourceType == 1){
+				wx.showLoading({
+				  title: '课程获取中...',
+				  mask: true
+				})
               this.$nextTick(() => {
-                // this.videoUrl = this.videoBaseUrl + this.detail.resourcePath
+                if (!this.detail.resourcePath) {
+                  wx.hideLoading()
+                  uni.showToast({
+                	icon: 'none',
+                	title: '文件路径不存在',
+                	duration: 2000
+                  })
+                  return
+                }
                 this.videoUrl = this.detail.resourcePath
                 this.moduleKey++
                 this.$nextTick(() => {
                   if(isClick == true){
+					  wx.hideLoading()
                     uni.createVideoContext('myVideo', this).play();
                   }
+				  wx.hideLoading()
                 })
               })
+			  wx.hideLoading()
             }else{
               const t = this
-              uni.downloadFile({
-                url: this.detail.resourcePath,
-				// url: 'http://106.15.95.149:8056/api/images/20250718/00571736c0c741e895318c2edd8a3f9d.PDF',
+			  wx.showLoading({
+			    title: '课程获取中...',
+				mask: true
+			  })
+				if (!t.detail.resourcePath) {
+				  wx.hideLoading()
+				  uni.showToast({
+					icon: 'none',
+					title: '文件路径不存在',
+					duration: 2000
+				  })
+				  return
+				}
+              wx.downloadFile({
+                url: t.detail.resourcePath,
                 success: function (res) {
+				  if (res.statusCode !== 200 || !res.tempFilePath) {
+					wx.hideLoading()
+					uni.showToast({
+					  icon: 'none',
+					  title: '文件下载失败',
+					  duration: 2000
+					})
+					return
+				  }
                   const data = {
                     chapterId: chapterId,
                     courseId: courseId,
@@ -262,29 +298,60 @@
                   }
                   postNewStudy(data).then(re=>{
                     if(re.code == 200){
-                      this.studyId = re.data
-                      this.handleUpdate(3)
+                      t.studyId = re.data
+                      t.handleUpdate(3)
                     }else{
-                      uni.$u.toast(res.message)
+                      uni.showToast({
+                      	icon: 'none',
+                      	duration: 2000,
+                      	position: 'top',
+                      	title: `${res.message}`
+                      });
                     }
-                  })
+                  }).catch(err => {
+					console.error('学习记录提交失败:', err)
+				  })
                   var filePath = res.tempFilePath
-                  uni.openDocument({
+                  wx.openDocument({
                     filePath: filePath,
                     showMenu: true,
                     success: function (res) {
-                      console.log('打开文档成功');
-                    }
+					  wx.hideLoading()
+                    },
+					fail: function(res){
+						uni.showToast({
+							icon: 'none',
+							duration: 2000,
+							position: 'top',
+							title: `打开文件失败: ${res.errMsg || '未知错误'}`
+						});
+						wx.hideLoading()
+					}
                   })
-                }
+                },
+				fail: function(res){
+					uni.showToast({
+						icon: 'none',
+						duration: 2000,
+						position: 'top',
+						title: `下载失败: ${res.errMsg || '网络错误'}`
+					});
+					wx.hideLoading()
+				}
               })
             }
           }
         }else{
           uni.$u.toast(res.message)
         }
-      })
-
+      }).catch(err => {
+		console.error('获取课程详情失败:', err)
+		uni.showToast({
+		  icon: 'none',
+		  title: '网络请求失败',
+		  duration: 2000
+		})
+	  })
     },
 
     goBack(){
diff --git a/pages/tabBar/firstPage/firstPage.vue b/pages/tabBar/firstPage/firstPage.vue
index 5dac134..615a143 100644
--- a/pages/tabBar/firstPage/firstPage.vue
+++ b/pages/tabBar/firstPage/firstPage.vue
@@ -1,161 +1,195 @@
 <template>
+	<!-- 自定义导航栏 -->
 	<view>
-		<!-- 自定义导航栏 -->
-<!-- 		<view class="navBarBox fix">
-			<view class="statusBar" :style="{ paddingTop: statusBarHeight + 'px' }"></view>
-			<view class="navBar">
-				<view class="barText">首页</view>
+		<view class="custom-navbar">
+			<view class="navbar-content">
+				<view class="nav-left" @click="handleBack">
+					<view class="back-btn">
+						<text class="back-text">返回</text>
+					</view>
+				</view>
+				<text class="navbar-title">安全教育</text>
+				<view class="nav-right"></view>
 			</view>
-		</view> -->
-    <view style="width: 100%;padding: 0 15px;box-sizing: border-box;margin: 20px 0">
-      <u-swiper :list="swiperList" indicatorMode="dot" bgColor="#f5f7fa" circular height="160" indicator previousMargin="30" nextMargin="30"></u-swiper>
-    </view>
-
-    <scroll-view scroll-y="true" class="scroll-Y" @scrolltoupper="upper"
-                 @scrolltolower="lower" lower-threshold="150" @scroll="scrollView" style="height:calc(100vh - 180px)">
-    <view class="m-p-15">
-      <view class="card" style="width:100%">
-        <view class="card-t">
-          <span class="card-t-l">我的线上课程</span>
-          <span class="card-t-r" @click="toCourses">查看全部</span>
-        </view>
-        <view class="card-c" v-if="Array.isArray(classList) && classList.length>0">
-          <view class="card-i" v-for="(item,index) in classList" :key="index">
-            <u-image radius="16px" width="200rpx" height="200rpx" :show-loading="true" :src="getImageUrl(item.course.logo)" mode="aspectFill">
-            </u-image>
-            <!--            <view class="card-i-t">目前已学:{{item.totalProgress}}分钟</view>-->
-            <view class="card-i-r">
-              <view class="card-i-r-t">
-                <view>{{item.phaseName + '-' + item.course.name}}</view>
-                <span style="color: #999;font-size: 12px;display: flex;align-items: center"><u-icon name="account" color="#999" size="18" style="margin-bottom: 0;margin-right: 2px"></u-icon>{{item.createName +'('+ item.createTime +')'}}</span>
-              </view>
-              <view class="card-i-r-b">
-                <u-tag icon="clock" :text="secondsToHms(item.course.period)" type="success" size="mini" shape="circle" plain plainFill></u-tag>
-                <u-button class="study-button" type="primary" text="开始学习" shape="circle" size="small" @click="toStudy(item)"></u-button>
-              </view>
-            </view>
-          </view>
-        </view>
-		<view class="card-c" v-else>
-			<span style="font-size: 28rpx;color: #999;">暂无课程信息</span>
 		</view>
-      </view>
-    </view>
-    <view class="m-p-15">
-      <view class="card" style="width:100%">
-        <view class="card-t">
-          <span class="card-t-l">我的考试</span>
-<!--          <uni-data-select
+		<view class="page-content" :style="{ paddingTop: navbarHeight + 'px' }">
+			<view style="width: 100%;padding: 0 15px;box-sizing: border-box;margin: 20px 0">
+				<u-swiper :list="swiperList" indicatorMode="dot" bgColor="#f5f7fa" circular height="160" indicator
+					previousMargin="30" nextMargin="30"></u-swiper>
+			</view>
+			<scroll-view scroll-y="true" class="scroll-Y" @scrolltoupper="upper" @scrolltolower="lower"
+				lower-threshold="150" @scroll="scrollView" style="height:calc(100vh - 244px)">
+				<view class="m-p-15">
+					<view class="card" style="width:100%">
+						<view class="card-t">
+							<span class="card-t-l">我的线上课程</span>
+							<span class="card-t-r" @click="toCourses">查看全部</span>
+						</view>
+						<view class="card-c" v-if="Array.isArray(classList) && classList.length>0">
+							<view class="card-i" v-for="(item,index) in classList" :key="index">
+								<u-image radius="16px" width="200rpx" height="200rpx" :show-loading="true"
+									:src="getImageUrl(item.course.logo)" mode="aspectFill">
+								</u-image>
+								<!--            <view class="card-i-t">目前已学:{{item.totalProgress}}分钟</view>-->
+								<view class="card-i-r">
+									<view class="card-i-r-t">
+										<view>{{item.phaseName + '-' + item.course.name}}</view>
+										<span
+											style="color: #999;font-size: 12px;display: flex;align-items: center"><u-icon
+												name="account" color="#999" size="18"
+												style="margin-bottom: 0;margin-right: 2px"></u-icon>{{item.createName +'('+ item.createTime +')'}}</span>
+									</view>
+									<view class="card-i-r-b">
+										<u-tag icon="clock" :text="secondsToHms(item.course.period)" type="success"
+											size="mini" shape="circle" plain plainFill></u-tag>
+										<u-button class="study-button" type="primary" text="开始学习" shape="circle"
+											size="small" @click="toStudy(item)"></u-button>
+									</view>
+								</view>
+							</view>
+						</view>
+						<view class="card-c" v-else>
+							<span style="font-size: 28rpx;color: #999;">暂无课程信息</span>
+						</view>
+					</view>
+				</view>
+				<view class="m-p-15">
+					<view class="card" style="width:100%">
+						<view class="card-t">
+							<span class="card-t-l">我的考试</span>
+							<!--          <uni-data-select
               v-model="examParams.state"
               placeholder="完成状态"
               :localdata="examSelect"
               :clear="true"
               @change="changeExam"
           ></uni-data-select> -->
-		  <div>
-<!-- 			  <span @click="showSelect = true" class="uni-stat__select"><text>{{examSelect[0][examParams.state].text}}</text><u-icon name="arrow-down" color="#999" size="14"></u-icon></span>
+							<div>
+								<!-- 			  <span @click="showSelect = true" class="uni-stat__select"><text>{{examSelect[0][examParams.state].text}}</text><u-icon name="arrow-down" color="#999" size="14"></u-icon></span>
 			  <u-picker :show="showSelect" :columns="examSelect" @confirm="confirm" @cancel="showSelect = false" keyName="text"></u-picker> -->
-			  <u-tabs :list="examSelect" :current="currentTab" @click="changeState"></u-tabs>
-		  </div>
-		  
-		  		
-        </view>
-        <view class="card-c card-d" v-if="examList && examList.length>0">
-            <view class="paper-card" v-for="(item,index) in examList" :key="index" @click="toExam(item)">
-              <view class="paper-card-t">
-				  <!-- <span :class="item.state == 0?'blue':item.state == 1?'red':'green'">[{{item.state == 0?'待考试':item.state == 1?'待批阅':'批阅完成'}}]</span> -->
-				  {{item.examPaper.name}}</view>
-              <view class="tag-area">
-				 <u-tag :text="item.examPaper.categoryName" plain size="mini"></u-tag>
-				 <u-tag :text="item.examPaper.limited == 1?'时长:' + item.examPaper.limitTime + '分钟':'不限时'" type="warning" plain size="mini"></u-tag> 
-			  </view>
-              <view class="paper-card-b">
-                <view style="font-size: 12px;margin-top: 5px;color: #999">
-                  <view style="margin-bottom: 2px">创建人:{{item.createName}}</view>
-                  <view>截止日期:{{item.examPaper.deadline.substring(0,10)}}</view>
-                </view>
-<!--                <view class="btn-area" v-if="item.state == 0">
+								<u-tabs :list="examSelect" :current="currentTab" @click="changeState"></u-tabs>
+							</div>
+
+
+						</view>
+						<view class="card-c card-d" v-if="examList && examList.length>0">
+							<view class="paper-card" v-for="(item,index) in examList" :key="index"
+								@click="toExam(item)">
+								<view class="paper-card-t">
+									<!-- <span :class="item.state == 0?'blue':item.state == 1?'red':'green'">[{{item.state == 0?'待考试':item.state == 1?'待批阅':'批阅完成'}}]</span> -->
+									{{item.examPaper.name}}
+								</view>
+								<view class="tag-area">
+									<u-tag :text="item.examPaper.categoryName" plain size="mini"></u-tag>
+									<u-tag
+										:text="item.examPaper.limited == 1?'时长:' + item.examPaper.limitTime + '分钟':'不限时'"
+										type="warning" plain size="mini"></u-tag>
+								</view>
+								<view class="paper-card-b">
+									<view style="font-size: 12px;margin-top: 5px;color: #999">
+										<view style="margin-bottom: 2px">创建人:{{item.createName}}</view>
+										<view>截止日期:{{item.examPaper.deadline.substring(0,10)}}</view>
+									</view>
+									<!--                <view class="btn-area" v-if="item.state == 0">
                   <u-button @click="toExam(item,1)" class="exam-button" type="primary" text="开始考试" shape="circle" size="small"></u-button>
                 </view> -->
-				<view class="btn-area" v-if="item.state == 2">
-					<u-button @tap.stop="reExam(item)" class="exam-button" type="primary" text="重新考试" shape="circle" size="small"></u-button>
-					<!-- <u-button @click="toExam(item,2)" class="re-exam-button" type="primary" text="查看" shape="circle" size="small"></u-button> -->
+									<view class="btn-area" v-if="item.state == 2">
+										<u-button @tap.native.stop="reExam(item)" class="exam-button" type="primary"
+											text="重新考试" shape="circle" size="small"></u-button>
+										<!-- <u-button @click="toExam(item,2)" class="re-exam-button" type="primary" text="查看" shape="circle" size="small"></u-button> -->
+									</view>
+								</view>
+							</view>
+						</view>
+						<view class="card-c card-d" v-else>
+							<u-empty text="该状态暂无记录" mode="data"></u-empty>
+						</view>
+					</view>
 				</view>
-              </view>
-            </view>
-        </view>
-        <view class="card-c card-d" v-else>
-          <u-empty text="该状态暂无记录" mode="data"></u-empty>
-        </view>
-      </view>
-    </view>
 
-    </scroll-view>
+			</scroll-view>
+		</view>
 	</view>
 </template>
 
 <script>
-	import {getClassList, getExamList, getSwiperList} from '../../../api/index.js'
+	import {
+		getClassList,
+		getExamList,
+		getSwiperList
+	} from '../../../api/index.js'
 	import VUE_APP_BASE_URL from 'common/constant.js'
-	import {postEndExam, postAgainExam} from "../../../api/wearhouse";
+	import {
+		postEndExam,
+		postAgainExam
+	} from "../../../api/wearhouse";
 	export default {
-		components:{},
+		components: {},
 		data() {
 			return {
-				showSelect:false,
-        swiperList: [
-          '/static/defaultCover.jpg','/static/defaultCover.jpg','/static/defaultCover.jpg'
-        ],
-		titleList:[
-			{
-				label: '默认排序',
-				value: 1,
-			}
-		],
-        classList: [],
-        examList: [],
-        totalPage: 0,
-		page: 'pages/tabBar/firstPage/firstPage',
-		statusBarHeight: '',
-        classParams:{
-          pageNum: 1,
-          pageSize: 3,
-        },
-        examParams: {
-          pageNum: 1,
-          pageSize: 10,
-          state: 0
-        },
-		currentTab: 0,
-        examSelect: [
-          { name: "待考试" },
-          { name: "批阅完成" }
-        ],
+				navbarHeight: 0,
+				showSelect: false,
+				swiperList: [
+					'/static/defaultCover.jpg', '/static/defaultCover.jpg', '/static/defaultCover.jpg'
+				],
+				titleList: [{
+					label: '默认排序',
+					value: 1,
+				}],
+				classList: [],
+				examList: [],
+				totalPage: 0,
+				page: 'pages/tabBar/firstPage/firstPage',
+				statusBarHeight: '',
+				classParams: {
+					pageNum: 1,
+					pageSize: 3,
+				},
+				examParams: {
+					pageNum: 1,
+					pageSize: 10,
+					state: 0
+				},
+				currentTab: 0,
+				examSelect: [{
+						name: "待考试"
+					},
+					{
+						name: "批阅完成"
+					}
+				],
 				role: '',
-				realname:''
+				realname: ''
 			}
-			
+
 		},
 		onLoad() {
 			//获取手机状态栏高度
-			this.statusBarHeight = uni.getSystemInfoSync()['statusBarHeight'];
-	
-      this.examList = []
-      this.classParams.pageNum = 1
-      this.examParams.pageNum = 1
-      this.getSwiper()
-      this.getClass()
-      this.getExamList()
+			this.getNavbarHeight()
+
+			this.examList = []
+			this.classParams.pageNum = 1
+			this.examParams.pageNum = 1
+			this.getSwiper()
+			this.getClass()
+			this.getExamList()
 		},
-		onShow(){
-			// this.role = uni.getStorageSync('roleName');
-			// this.realname = uni.getStorageSync('user').realName
-      // this.tabBarLists = uni.getStorageSync('tabBarList');
+		onShow() {
 
 		},
-    created(){
-    },
+		created() {},
 		methods: {
+			getNavbarHeight() {
+				const systemInfo = uni.getSystemInfoSync()
+				const statusBarHeight = systemInfo.statusBarHeight
+				const navbarHeight = 44
+				this.navbarHeight = statusBarHeight + navbarHeight
+			},
+			handleBack() {
+				uni.navigateTo({
+					url: '/pages/menuPage/index'
+				})
+			},
 			loginOut() {
 				uni.clearStorageSync();
 				uni.clearStorage();
@@ -164,414 +198,456 @@
 				})
 			},
 
-	  confirm(e) {
-		this.examParams.state = e.value[0].value
-		this.examParams.pageNum = 1
-		this.getExamList()
-		this.showSelect = false
-	  },
+			confirm(e) {
+				this.examParams.state = e.value[0].value
+				this.examParams.pageNum = 1
+				this.getExamList()
+				this.showSelect = false
+			},
 
-		changeState(e){
-			this.currentTab = e.index
-			this.examParams.state = e.index == 0?0:2
-			this.examParams.pageNum = 1
-			this.getExamList()
-		},
+			changeState(e) {
+				this.currentTab = e.index
+				this.examParams.state = e.index == 0 ? 0 : 2
+				this.examParams.pageNum = 1
+				this.getExamList()
+			},
 
-      async getSwiper(){
-        const res = await getSwiperList()
-        if(res.code == 200){
-          let list = res.data.list || []
-          if(list.length>0){
-            this.swiperList = list.map(i=>VUE_APP_BASE_URL + '/api/' + i.imgUrl) || []
-          }
-        }else{
-          uni.$u.toast(res.message)
-        }
-      },
+			async getSwiper() {
+				const res = await getSwiperList()
+				if (res.code == 200) {
+					let list = res.data.list || []
+					if (list.length > 0) {
+						this.swiperList = list.map(i => VUE_APP_BASE_URL + '/api/' + i.imgUrl) || []
+					}
+				} else {
+					uni.$u.toast(res.message)
+				}
+			},
 
-      getClass(){
-        getClassList(this.classParams).then(res => {
-					if(res.code == 200) {
-						if(res.data && res.data.list.length > 0){
+			getClass() {
+				getClassList(this.classParams).then(res => {
+					if (res.code == 200) {
+						if (res.data && res.data.list.length > 0) {
 							this.classList = res.data.list
-						}else {
-              this.classList = []
+						} else {
+							this.classList = []
 						}
-					}else{
+					} else {
 						uni.$u.toast(res.message)
 					}
 				})
 			},
-      getExamList(){
-        getExamList(this.examParams).then(res => {
-          if(res.code == 200) {
-            let list = res.data.list?res.data.list: [];
-            if (res.data.pageNum != 1) {
-              this.examList = this.examList.concat(list)
-            } else {
-              this.examList = res.data.list
-            }
-            this.totalPage = res.data.totalPage
-          }else{
-            uni.$u.toast(res.message)
-          }
-        })
-      },
+			getExamList() {
+				getExamList(this.examParams).then(res => {
+					if (res.code == 200) {
+						let list = res.data.list ? res.data.list : [];
+						if (res.data.pageNum != 1) {
+							this.examList = this.examList.concat(list)
+						} else {
+							this.examList = res.data.list
+						}
+						this.totalPage = res.data.totalPage
+					} else {
+						uni.$u.toast(res.message)
+					}
+				})
+			},
 
-      getImageUrl(logo) {
-        return logo ? VUE_APP_BASE_URL  + '/api/' + logo : '/static/defaultCover.jpg';
-      },
+			getImageUrl(logo) {
+				return logo ? VUE_APP_BASE_URL + '/api/' + logo : '/static/defaultCover.jpg';
+			},
 
-      toStudy(item) {
-        uni.setStorageSync("prevPage", '/pages/tabBar/firstPage/firstPage');
-        uni.navigateTo({
-          url: `/pages/tabBar/current/detail?bank=` + encodeURIComponent(JSON.stringify(item))
-        })
-      },
+			toStudy(item) {
+				uni.setStorageSync("prevPage", '/pages/tabBar/firstPage/firstPage');
+				uni.navigateTo({
+					url: `/pages/tabBar/current/detail?bank=` + encodeURIComponent(JSON.stringify(item))
+				})
+			},
 
-      toExam(item){
-		  console.log(item,'item')
-		  if(item.state == 0 && item.examPaper.deadline){
-			const deadline = item.examPaper.deadline
-			const deadlineTime = new Date(deadline).getTime()
-			const currentTime = new Date().getTime()
-			if (currentTime > deadlineTime) {
-			  uni.$u.toast('已超过考试截止时间,不可重新考试')
-			  return
-			}
-		  }
-        if(item.state == 0){
-          uni.showModal({
-            title: '提示',
-            content: item.examPaper.limited == 1?'该考试限制时长为:' + item.examPaper.limitTime + '分钟,进入后开始计时,计时结束自动交卷,是否继续?':'是否确认考试?',
-            success: function (res) {
-              if (res.confirm) {
-                uni.setStorageSync("prevPage", '/pages/tabBar/firstPage/firstPage');
-                uni.navigateTo({
-                  url: `/pages/tabBar/firstPage/exam?bank=` + encodeURIComponent(JSON.stringify(item)) + `&type=` + encodeURIComponent(JSON.stringify(1))
-                })
-              } else if (res.cancel) {
-                console.log('用户点击取消');
-              }
-            }
-          })
-        }else{
-          uni.setStorageSync("prevPage", '/pages/tabBar/firstPage/firstPage');
-          uni.navigateTo({
-            url: `/pages/tabBar/firstPage/exam?bank=` + encodeURIComponent(JSON.stringify(item)) + `&type=` + encodeURIComponent(JSON.stringify(2))
-          })
-        }
-      },
-	  
-		async reExam(item){
-			const t = this
-			if(item.examPaper.deadline){
-				const deadline = item.examPaper.deadline
-				const deadlineTime = new Date(deadline).getTime()
-				const currentTime = new Date().getTime()
-				if (currentTime > deadlineTime) {
-				  uni.$u.toast('已超过考试截止时间,不可重新考试')
-				  return
+			toExam(item) {
+				if (item.state == 0 && item.examPaper.deadline) {
+					const deadline = item.examPaper.deadline
+					const deadlineTime = new Date(deadline).getTime()
+					const currentTime = new Date().getTime()
+					if (currentTime > deadlineTime) {
+						uni.$u.toast('已超过考试截止时间,不可重新考试')
+						return
+					}
 				}
-			}
-			uni.showModal({
-			  title: '提示',
-			  content: '是否重新考试?',
-			  success: async function (res) {
-			    if (res.confirm) {
-			      const res = await postAgainExam({paperId: item.paperId,studentId: uni.getStorageSync('uid')})
-			      if(res.code == 200){
-			      	uni.$u.toast(res.message)
-					t.currentTab = 0
-					t.examParams.state = 0
-			      	t.examParams.pageNum = 1
-			      	t.getExamList()
-			      }else{
-			      	uni.$u.toast(res.message)
-			      }
-			    } else if (res.cancel) {
-			      console.log('用户点击取消');
-			    }
-			  }
-			})
-		},
+				if (item.state == 0) {
+					uni.showModal({
+						title: '提示',
+						content: item.examPaper.limited == 1 ? '该考试限制时长为:' + item.examPaper.limitTime +
+							'分钟,进入后开始计时,计时结束自动交卷,是否继续?' : '是否确认考试?',
+						success: function(res) {
+							if (res.confirm) {
+								uni.setStorageSync("prevPage", '/pages/tabBar/firstPage/firstPage');
+								uni.navigateTo({
+									url: `/pages/tabBar/firstPage/exam?bank=` + encodeURIComponent(JSON
+										.stringify(item)) + `&type=` + encodeURIComponent(JSON
+										.stringify(1))
+								})
+							} else if (res.cancel) {
+								console.log('用户点击取消');
+							}
+						}
+					})
+				} else {
+					uni.setStorageSync("prevPage", '/pages/tabBar/firstPage/firstPage');
+					uni.navigateTo({
+						url: `/pages/tabBar/firstPage/exam?bank=` + encodeURIComponent(JSON.stringify(item)) +
+							`&type=` + encodeURIComponent(JSON.stringify(2))
+					})
+				}
+			},
 
-      secondsToHms(seconds) {
-        seconds = Number(seconds);
-        const h = Math.floor(seconds / 3600);
-        const m = Math.floor(seconds % 3600 / 60);
-        const s = Math.floor(seconds % 3600 % 60);
+			async reExam(item) {
+				const t = this
+				if (item.examPaper.deadline) {
+					const deadline = item.examPaper.deadline
+					const deadlineTime = new Date(deadline).getTime()
+					const currentTime = new Date().getTime()
+					if (currentTime > deadlineTime) {
+						uni.$u.toast('已超过考试截止时间,不可重新考试')
+						return
+					}
+				}
+				uni.showModal({
+					title: '提示',
+					content: '是否重新考试?',
+					success: async function(res) {
+						if (res.confirm) {
+							const res = await postAgainExam({
+								paperId: item.paperId,
+								studentId: uni.getStorageSync('uid')
+							})
+							if (res.code == 200) {
+								uni.$u.toast(res.message)
+								t.currentTab = 0
+								t.examParams.state = 0
+								t.examParams.pageNum = 1
+								t.getExamList()
+							} else {
+								uni.$u.toast(res.message)
+							}
+						} else if (res.cancel) {
+							console.log('用户点击取消');
+						}
+					}
+				})
+			},
 
-        const hDisplay = h > 0 ? String(h).padStart(2, '0') : '00';
-        const mDisplay = m > 0 ? String(m).padStart(2, '0') : '00';
-        const sDisplay = s > 0 ? String(s).padStart(2, '0') : '00';
-        return `${hDisplay}:${mDisplay}:${sDisplay}`;
-      },
+			secondsToHms(seconds) {
+				seconds = Number(seconds);
+				const h = Math.floor(seconds / 3600);
+				const m = Math.floor(seconds % 3600 / 60);
+				const s = Math.floor(seconds % 3600 % 60);
 
-      upper(e) {
-        // console.log(e)
-      },
-      lower(e) {
-        //并且让页码+1,调用获取数据的方法获取第二页数据
-        this.examParams.pageNum++
-        //此处调用自己获取数据列表的方法
-        if (this.examParams.pageNum > this.totalPage){
-          uni.$u.toast('已加载全部数据')
-          return
-        }
-        this.getExamList()
-      },
-      scrollView(e) {
-        // console.log(e)
-      },
+				const hDisplay = h > 0 ? String(h).padStart(2, '0') : '00';
+				const mDisplay = m > 0 ? String(m).padStart(2, '0') : '00';
+				const sDisplay = s > 0 ? String(s).padStart(2, '0') : '00';
+				return `${hDisplay}:${mDisplay}:${sDisplay}`;
+			},
 
-      toCourses(){
-        uni.switchTab({
-          url: '/pages/tabBar/current/current'
-        })
-      },
+			upper(e) {
+				// console.log(e)
+			},
+			lower(e) {
+				//并且让页码+1,调用获取数据的方法获取第二页数据
+				this.examParams.pageNum++
+				//此处调用自己获取数据列表的方法
+				if (this.examParams.pageNum > this.totalPage) {
+					uni.$u.toast('已加载全部数据')
+					return
+				}
+				this.getExamList()
+			},
+			scrollView(e) {
+				// console.log(e)
+			},
+
+			toCourses() {
+				uni.switchTab({
+					url: '/pages/tabBar/current/current'
+				})
+			},
 
 		}
 	}
-
 </script>
 
-<style lang="scss">
-.navBarBox .navBar {
-	background-color:#fff;
-	  height: 50px;
-	  display: flex;
-	  flex-direction: row;
-	  justify-content: center;
-	  align-items: center;
-  box-shadow: 0 3px 12px rgba(0,0,0,0.05);
-	
-}
-.fix{
-	position: sticky;
-	top: 0;
-	left: 0;
-	right: 0;
-	width: 100%;
-	z-index: 1;
-}
-.barText{
-  /* text-align: center; */
-  font-size: 16px;
-  font-weight: 600;
-  flex: 2;
-  margin-left: 45%;
-}
-.statusBar{
-	background-color:lightgrey;
-}
-.m-p-15{
-  width: 100%;
-  box-sizing: border-box;
-  padding: 0 15px;
-}
-.card{
-  width: 100%;
-  margin-bottom: 40rpx;
+<style lang="scss" scoped>
+	.custom-navbar {
+		position: fixed;
+		top: 0;
+		left: 0;
+		right: 0;
+		z-index: 999;
+		background: #ffffff;
+		border-bottom: 1px solid #f0f0f0;
 
-  .card-t{
-    width: 100%;
-    padding: 0 6rpx;
-    box-sizing: border-box;
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-    margin-bottom: 20rpx;
-
-    .card-t-l{
-      font-size: 36rpx;
-      font-weight: bold;
-    }
-    .card-t-r{
-      color: #999;
-      cursor: pointer;
-	  font-size: 28rpx;
-    }
-    .uni-stat__select{
-		display: flex;
-		align-items: center;
-		justify-content: center;
-		padding: 2rpx 20rpx;
-		border: 1rpx solid #ccc;
-		border-radius: 99rpx;
-		background: #fff;
-		cursor: pointer;
-		
-		
-		text{
-			color: #999;
-			font-size: 28rpx;
-			margin-right: 6rpx;
+		.navbar-content {
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			height: 44px;
+			padding-top: var(--status-bar-height);
 		}
-    }
-  }
 
-  .card-c{
-    background: #fff;
-    border-radius: 20rpx;
-    padding: 15px;
+		.nav-left {
+			flex-shrink: 0;
+			width: 80px;
+			padding-left: 15px;
+			box-sizing: border-box;
+		}
 
-	::v-deep .u-empty{
-	  margin-top: 40rpx !important;
+		.back-btn {
+			display: flex;
+			align-items: center;
+			padding: 8px 12px 8px 0;
+		}
+
+		.back-text {
+			font-size: 16px;
+			color: #000000;
+		}
+
+		.navbar-title {
+			flex: 1;
+			font-size: 16px;
+			text-align: center;
+			font-weight: bold;
+			color: #000000;
+		}
+
+		.nav-right {
+			flex-shrink: 0;
+			width: 80px;
+		}
+
+
 	}
-	
-    .card-i{
-      padding-bottom: 15px;
-      margin-bottom: 15px;
-      border-bottom: 1px solid #f0f0f0;
-      position: relative;
-      display: flex;
-      align-items: flex-start;
-      box-sizing: border-box;
 
-      &:last-of-type{
-        margin-bottom: 0;
-        padding-bottom: 0;
-        border-bottom: none;
-      }
-      .card-i-t{
-        position: absolute;
-        width: 250rpx;
-        height: 30px;
-        border-radius: 8rpx;
-        line-height: 30px;
-        color: #fff;
-        padding: 0 10rpx;
-        box-sizing: border-box;
-        left: 0;
-        bottom: 0;
-        background: rgba(0,0,0,.4);
-      }
-      .card-i-r{
-        width: 100%;
-        height: 200rpx;
-        margin-left: 20rpx;
-        display: flex;
-        flex-direction: column;
-        justify-content: space-between;
-        .card-i-r-t{
-          view{
-            font-size: 36rpx;
-            margin-bottom: 10rpx;
-            font-family: "PingFang SC";
-            font-weight: 800;
-            overflow: hidden;
-            text-overflow: ellipsis;
-            display: -webkit-box;
-            -webkit-line-clamp: 2;
-            -webkit-box-orient: vertical;
-          }
-        }
-        .card-i-r-b{
-          width: 100%;
-          display: flex;
-          align-items: center;
-          justify-content: space-between;
+	.page-content {
+		min-height: calc(100vh - 44px);
+	}
 
-          ::v-deep .u-button{
-            width: 220rpx;
-            margin: 0;
-            box-shadow: 3px 3px 12px rgba(51,133,217,.3), -2px -2px 6px #fff;
-            border: 1px solid rgba(255,255,255,.8);
-          }
-        }
-      }
-    }
-  }
-  .card-d{
-    background: none;
-    padding: 0 0 15px;
-    .paper-card{
-      background: #fff;
-      margin-bottom: 15px;
-      padding: 15px;
-      box-sizing: border-box;
-      position: relative;
-      border-radius: 20rpx;
+	.m-p-15 {
+		width: 100%;
+		box-sizing: border-box;
+		padding: 0 15px;
+	}
 
-      &:last-of-type{
-        margin-bottom: 0;
-      }
+	.card {
+		width: 100%;
+		margin-bottom: 40rpx;
 
-      .paper-card-t{
-        font-size: 36rpx;
-        margin-bottom: 10rpx;
-        font-family: "PingFang SC";
-        font-weight: 800;
-        white-space: nowrap;
-        overflow: hidden;
-        text-overflow: ellipsis;
-
-        .blue{
-          font-size: 32rpx;
-          color: #0f7ff9
-        }
-
-        .green{
-          font-size: 32rpx;
-          color: #5ac725
-        }
-        .red{
-          font-size: 32rpx;
-          color: #f56c6c
-        }
-      }
-
-		.tag-area{
+		.card-t {
 			width: 100%;
-			display: flex;
-			
-			::v-deep .u-tag-wrapper{
-				margin-right: 10rpx;
-			}
-		}
-
-      .paper-card-b{
-        display: flex;
-        align-items: flex-end;
-        justify-content: space-between;
-
-
-		.btn-area{
+			padding: 0 6rpx;
+			box-sizing: border-box;
 			display: flex;
 			align-items: center;
-			
-			::v-deep .u-button{
-				width: 220rpx;
-				margin: 0;
-				box-shadow: 3px 3px 12px rgba(51,133,217,.3), -2px -2px 6px #fff;
-				border: 1px solid rgba(255,255,255,.8);
+			justify-content: space-between;
+			margin-bottom: 20rpx;
+
+			.card-t-l {
+				font-size: 36rpx;
+				font-weight: bold;
 			}
-		}
-		.btn-area2{
-			display: flex;
-			align-items: center;
-			
-			::v-deep .u-button{
-				width: 150rpx;
-				margin: 0;
-				
-				&:last-of-type{
-					box-shadow: 3px 3px 12px rgba(51,133,217,.3), -2px -2px 6px #fff;
-					border: 1px solid rgba(255,255,255,.8);
-					margin-left: 20rpx;
+
+			.card-t-r {
+				color: #999;
+				cursor: pointer;
+				font-size: 28rpx;
+			}
+
+			.uni-stat__select {
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				padding: 2rpx 20rpx;
+				border: 1rpx solid #ccc;
+				border-radius: 99rpx;
+				background: #fff;
+				cursor: pointer;
+
+
+				text {
+					color: #999;
+					font-size: 28rpx;
+					margin-right: 6rpx;
 				}
 			}
 		}
-      }
-    }
-  }
-}
 
-.badge span{
-	text-align: center;
-	width: 100%;
-}
+		.card-c {
+			background: #fff;
+			border-radius: 20rpx;
+			padding: 15px;
 
+			::v-deep .u-empty {
+				margin-top: 40rpx !important;
+			}
+
+			.card-i {
+				padding-bottom: 15px;
+				margin-bottom: 15px;
+				border-bottom: 1px solid #f0f0f0;
+				position: relative;
+				display: flex;
+				align-items: flex-start;
+				box-sizing: border-box;
+
+				&:last-of-type {
+					margin-bottom: 0;
+					padding-bottom: 0;
+					border-bottom: none;
+				}
+
+				.card-i-t {
+					position: absolute;
+					width: 250rpx;
+					height: 30px;
+					border-radius: 8rpx;
+					line-height: 30px;
+					color: #fff;
+					padding: 0 10rpx;
+					box-sizing: border-box;
+					left: 0;
+					bottom: 0;
+					background: rgba(0, 0, 0, .4);
+				}
+
+				.card-i-r {
+					width: 100%;
+					height: 200rpx;
+					margin-left: 20rpx;
+					display: flex;
+					flex-direction: column;
+					justify-content: space-between;
+
+					.card-i-r-t {
+						view {
+							font-size: 36rpx;
+							margin-bottom: 10rpx;
+							font-family: "PingFang SC";
+							font-weight: 800;
+							overflow: hidden;
+							text-overflow: ellipsis;
+							display: -webkit-box;
+							-webkit-line-clamp: 2;
+							-webkit-box-orient: vertical;
+						}
+					}
+
+					.card-i-r-b {
+						width: 100%;
+						display: flex;
+						align-items: center;
+						justify-content: space-between;
+
+						::v-deep .u-button {
+							width: 220rpx;
+							margin: 0;
+							box-shadow: 3px 3px 12px rgba(51, 133, 217, .3), -2px -2px 6px #fff;
+							border: 1px solid rgba(255, 255, 255, .8);
+						}
+					}
+				}
+			}
+		}
+
+		.card-d {
+			background: none;
+			padding: 0 0 15px;
+
+			.paper-card {
+				background: #fff;
+				margin-bottom: 15px;
+				padding: 15px;
+				box-sizing: border-box;
+				position: relative;
+				border-radius: 20rpx;
+
+				&:last-of-type {
+					margin-bottom: 0;
+				}
+
+				.paper-card-t {
+					font-size: 36rpx;
+					margin-bottom: 10rpx;
+					font-family: "PingFang SC";
+					font-weight: 800;
+					white-space: nowrap;
+					overflow: hidden;
+					text-overflow: ellipsis;
+
+					.blue {
+						font-size: 32rpx;
+						color: #0f7ff9
+					}
+
+					.green {
+						font-size: 32rpx;
+						color: #5ac725
+					}
+
+					.red {
+						font-size: 32rpx;
+						color: #f56c6c
+					}
+				}
+
+				.tag-area {
+					width: 100%;
+					display: flex;
+
+					::v-deep .u-tag-wrapper {
+						margin-right: 10rpx;
+					}
+				}
+
+				.paper-card-b {
+					display: flex;
+					align-items: flex-end;
+					justify-content: space-between;
+
+
+					.btn-area {
+						display: flex;
+						align-items: center;
+
+						::v-deep .u-button {
+							width: 220rpx;
+							margin: 0;
+							box-shadow: 3px 3px 12px rgba(51, 133, 217, .3), -2px -2px 6px #fff;
+							border: 1px solid rgba(255, 255, 255, .8);
+						}
+					}
+
+					.btn-area2 {
+						display: flex;
+						align-items: center;
+
+						::v-deep .u-button {
+							width: 150rpx;
+							margin: 0;
+
+							&:last-of-type {
+								box-shadow: 3px 3px 12px rgba(51, 133, 217, .3), -2px -2px 6px #fff;
+								border: 1px solid rgba(255, 255, 255, .8);
+								margin-left: 20rpx;
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+
+	.badge span {
+		text-align: center;
+		width: 100%;
+	}
 </style>
\ No newline at end of file
diff --git a/static/educate.png b/static/educate.png
new file mode 100644
index 0000000..2c7b7ac
--- /dev/null
+++ b/static/educate.png
Binary files differ
diff --git a/static/review.png b/static/review.png
new file mode 100644
index 0000000..547fd8c
--- /dev/null
+++ b/static/review.png
Binary files differ

--
Gitblit v1.9.2